summaryrefslogtreecommitdiff
path: root/external/libmariadb
diff options
context:
space:
mode:
authorLionel Elie Mamane <lionel@mamane.lu>2013-10-19 16:28:37 +0200
committerLionel Elie Mamane <lionel@mamane.lu>2013-10-19 23:03:01 +0200
commit96953171bf0503a89611b7c518668f749fe14425 (patch)
tree170d5897d0e67b8f3c807eb2bfda27e5c5cf612d /external/libmariadb
parenteb007bb6d8d8b97941260784c3a8469c0800d3d3 (diff)
update libmariadb to bzr revision 101
Change-Id: I98b7442aa9843f206549ad7c5a2ae141b70b1542
Diffstat (limited to 'external/libmariadb')
-rw-r--r--external/libmariadb/README16
-rw-r--r--external/libmariadb/StaticLibrary_mariadb.mk170
-rw-r--r--external/libmariadb/UnpackedTarball_mariadb.mk8
-rw-r--r--external/libmariadb/configs/linux_my_config.h87
-rw-r--r--external/libmariadb/configs/mysql_version.h10
-rw-r--r--external/libmariadb/mariadb-msvc.patch.14
-rw-r--r--external/libmariadb/mariadb-static-inline.patch11
-rw-r--r--external/libmariadb/mariadb-thread.patch12
-rw-r--r--external/libmariadb/mariadb-trunk-101.patch (renamed from external/libmariadb/mariadb-trunk-40.patch)97845
9 files changed, 94256 insertions, 3907 deletions
diff --git a/external/libmariadb/README b/external/libmariadb/README
new file mode 100644
index 000000000000..03a1138b47f8
--- /dev/null
+++ b/external/libmariadb/README
@@ -0,0 +1,16 @@
+Update to new upstream bzr snapshot:
+
+Don't use 'bzr diff', it will not put renames in the diff in a way
+that patch understands.
+
+bzr -Ossl.cert_reqs=none branch lp:mariadb-native-client
+mv mariadb-native-client mariadb-native-client.trunk
+cp -R mariadb-native-client.trunk mariadb-native-client.release
+cd mariadb-native-client.release
+bzr revert -r mariadb-native-client-1.0.0
+cd ..
+diff -x .bzr -u --recursive -N mariadb-native-client.release/ mariadb-native-client.trunk/ > /path/to/libreoffice_tree/libmariadb/mariadb-trunk-NNN.patch
+sed -i -e 's@^\([+-]\{3\} \)mariadb-native-client.\(trunk\|release\)/@\1mariadb/@' /path/to/libreoffice_tree/libmariadb/mariadb-trunk-NNN.patch
+dos2unix -f /path/to/libreoffice_tree/libmariadb/mariadb-trunk-NNN.patch
+
+regenerate configs \ No newline at end of file
diff --git a/external/libmariadb/StaticLibrary_mariadb.mk b/external/libmariadb/StaticLibrary_mariadb.mk
index 1174c9717d82..b0434a4a06d9 100644
--- a/external/libmariadb/StaticLibrary_mariadb.mk
+++ b/external/libmariadb/StaticLibrary_mariadb.mk
@@ -21,94 +21,92 @@ $(eval $(call gb_StaticLibrary_set_include,mariadblib,\
# This is needed for MSVC 2008: it somehow finds a dlopen somewhere
# but the static library then contains unreferenced symbols.
# This macro enables a re-definition to native Win32 APIs in my_global.h.
-$(eval $(call gb_StaticLibrary_add_cflags,mariadblib,-DHAVE_DLOPEN))
+## TODO missing enable: -DHAVE_OPENSSL -D HAVE_COMPRESS
+## (but then need to add "-lssl -lcrypto -lz" to mysqlcppconn linking)
+$(eval $(call gb_StaticLibrary_add_cflags,mariadblib,-DHAVE_DLOPEN -D ENABLED_LOCAL_INFILE -D LIBMARIADB -D THREAD -DSQLITE_ENABLE_COLUMN_METADATA=1))
$(eval $(call gb_StaticLibrary_add_generated_cobjects,mariadblib,\
- UnpackedTarball/mariadb/libmysql/array \
- UnpackedTarball/mariadb/libmysql/bchange \
- UnpackedTarball/mariadb/libmysql/bmove \
- UnpackedTarball/mariadb/libmysql/bmove_upp \
- UnpackedTarball/mariadb/libmysql/charset \
- UnpackedTarball/mariadb/libmysql/client_plugin \
- UnpackedTarball/mariadb/libmysql/dbug \
- UnpackedTarball/mariadb/libmysql/default \
- UnpackedTarball/mariadb/libmysql/errmsg \
- UnpackedTarball/mariadb/libmysql/errors \
- UnpackedTarball/mariadb/libmysql/getopt \
- UnpackedTarball/mariadb/libmysql/getopt1 \
- UnpackedTarball/mariadb/libmysql/get_password \
- UnpackedTarball/mariadb/libmysql/int2str \
- UnpackedTarball/mariadb/libmysql/is_prefix \
- UnpackedTarball/mariadb/libmysql/libmysql \
- UnpackedTarball/mariadb/libmysql/list \
- UnpackedTarball/mariadb/libmysql/llstr \
- UnpackedTarball/mariadb/libmysql/longlong2str \
- UnpackedTarball/mariadb/libmysql/mf_dirname \
- UnpackedTarball/mariadb/libmysql/mf_fn_ext \
- UnpackedTarball/mariadb/libmysql/mf_format \
- UnpackedTarball/mariadb/libmysql/mf_loadpath \
- UnpackedTarball/mariadb/libmysql/mf_pack \
- UnpackedTarball/mariadb/libmysql/mf_path \
- UnpackedTarball/mariadb/libmysql/mf_tempfile \
- UnpackedTarball/mariadb/libmysql/mf_unixpath \
- UnpackedTarball/mariadb/libmysql/mf_wcomp \
- UnpackedTarball/mariadb/libmysql/mulalloc \
- UnpackedTarball/mariadb/libmysql/my_alloc \
- UnpackedTarball/mariadb/libmysql/my_auth \
- UnpackedTarball/mariadb/libmysql/my_charset \
- UnpackedTarball/mariadb/libmysql/my_compress \
- UnpackedTarball/mariadb/libmysql/my_create \
- UnpackedTarball/mariadb/libmysql/my_delete \
- UnpackedTarball/mariadb/libmysql/my_div \
- UnpackedTarball/mariadb/libmysql/my_error \
- UnpackedTarball/mariadb/libmysql/my_fopen \
- UnpackedTarball/mariadb/libmysql/my_fstream \
- UnpackedTarball/mariadb/libmysql/my_gethostbyname \
- UnpackedTarball/mariadb/libmysql/my_getwd \
- UnpackedTarball/mariadb/libmysql/my_init \
- UnpackedTarball/mariadb/libmysql/my_lib \
- UnpackedTarball/mariadb/libmysql/my_loaddata \
- UnpackedTarball/mariadb/libmysql/my_malloc \
- UnpackedTarball/mariadb/libmysql/my_messnc \
- UnpackedTarball/mariadb/libmysql/my_net \
- UnpackedTarball/mariadb/libmysql/my_once \
- UnpackedTarball/mariadb/libmysql/my_open \
- UnpackedTarball/mariadb/libmysql/my_port \
- UnpackedTarball/mariadb/libmysql/my_pthread \
- UnpackedTarball/mariadb/libmysql/my_read \
- UnpackedTarball/mariadb/libmysql/my_realloc \
- UnpackedTarball/mariadb/libmysql/my_secure \
- UnpackedTarball/mariadb/libmysql/my_seek \
- UnpackedTarball/mariadb/libmysql/my_static \
- UnpackedTarball/mariadb/libmysql/my_stmt \
- UnpackedTarball/mariadb/libmysql/my_stmt_codec \
- UnpackedTarball/mariadb/libmysql/my_symlink \
- UnpackedTarball/mariadb/libmysql/my_thr_init \
- UnpackedTarball/mariadb/libmysql/my_vsnprintf \
- UnpackedTarball/mariadb/libmysql/my_write \
- UnpackedTarball/mariadb/libmysql/net \
- UnpackedTarball/mariadb/libmysql/password \
- UnpackedTarball/mariadb/libmysql/safemalloc \
- UnpackedTarball/mariadb/libmysql/sha1 \
- UnpackedTarball/mariadb/libmysql/str2int \
- UnpackedTarball/mariadb/libmysql/strcend \
- UnpackedTarball/mariadb/libmysql/strcont \
- UnpackedTarball/mariadb/libmysql/strend \
- UnpackedTarball/mariadb/libmysql/strfill \
- UnpackedTarball/mariadb/libmysql/string \
- UnpackedTarball/mariadb/libmysql/strinstr \
- UnpackedTarball/mariadb/libmysql/strmake \
- UnpackedTarball/mariadb/libmysql/strmov \
- UnpackedTarball/mariadb/libmysql/strnlen \
- UnpackedTarball/mariadb/libmysql/strnmov \
- UnpackedTarball/mariadb/libmysql/strto \
- UnpackedTarball/mariadb/libmysql/strtoll \
- UnpackedTarball/mariadb/libmysql/strtoull \
- UnpackedTarball/mariadb/libmysql/strxmov \
- UnpackedTarball/mariadb/libmysql/strxnmov \
- UnpackedTarball/mariadb/libmysql/thr_mutex \
- UnpackedTarball/mariadb/libmysql/typelib \
- UnpackedTarball/mariadb/libmysql/violite \
+ UnpackedTarball/mariadb/libmariadb/array \
+ UnpackedTarball/mariadb/libmariadb/ma_dyncol \
+ UnpackedTarball/mariadb/libmariadb/bchange \
+ UnpackedTarball/mariadb/libmariadb/bmove \
+ UnpackedTarball/mariadb/libmariadb/bmove_upp \
+ UnpackedTarball/mariadb/libmariadb/my_charset \
+ UnpackedTarball/mariadb/libmariadb/hash \
+ UnpackedTarball/mariadb/libmariadb/violite \
+ UnpackedTarball/mariadb/libmariadb/net \
+ UnpackedTarball/mariadb/libmariadb/charset \
+ UnpackedTarball/mariadb/libmariadb/ma_time \
+ UnpackedTarball/mariadb/libmariadb/dbug \
+ UnpackedTarball/mariadb/libmariadb/default \
+ UnpackedTarball/mariadb/libmariadb/errmsg \
+ UnpackedTarball/mariadb/libmariadb/my_vsnprintf \
+ UnpackedTarball/mariadb/libmariadb/errors \
+ UnpackedTarball/mariadb/libmariadb/getopt1 \
+ UnpackedTarball/mariadb/libmariadb/getopt \
+ UnpackedTarball/mariadb/libmariadb/get_password \
+ UnpackedTarball/mariadb/libmariadb/int2str \
+ UnpackedTarball/mariadb/libmariadb/is_prefix \
+ UnpackedTarball/mariadb/libmariadb/libmariadb \
+ UnpackedTarball/mariadb/libmariadb/list \
+ UnpackedTarball/mariadb/libmariadb/llstr \
+ UnpackedTarball/mariadb/libmariadb/longlong2str \
+ UnpackedTarball/mariadb/libmariadb/mf_dirname \
+ UnpackedTarball/mariadb/libmariadb/mf_fn_ext \
+ UnpackedTarball/mariadb/libmariadb/mf_format \
+ UnpackedTarball/mariadb/libmariadb/mf_loadpath \
+ UnpackedTarball/mariadb/libmariadb/mf_pack \
+ UnpackedTarball/mariadb/libmariadb/mf_path \
+ UnpackedTarball/mariadb/libmariadb/mf_unixpath \
+ UnpackedTarball/mariadb/libmariadb/mf_wcomp \
+ UnpackedTarball/mariadb/libmariadb/mulalloc \
+ UnpackedTarball/mariadb/libmariadb/my_alloc \
+ UnpackedTarball/mariadb/libmariadb/my_compress \
+ UnpackedTarball/mariadb/libmariadb/my_div \
+ UnpackedTarball/mariadb/libmariadb/my_error \
+ UnpackedTarball/mariadb/libmariadb/my_fopen \
+ UnpackedTarball/mariadb/libmariadb/my_fstream \
+ UnpackedTarball/mariadb/libmariadb/my_getwd \
+ UnpackedTarball/mariadb/libmariadb/my_init \
+ UnpackedTarball/mariadb/libmariadb/my_lib \
+ UnpackedTarball/mariadb/libmariadb/my_malloc \
+ UnpackedTarball/mariadb/libmariadb/my_messnc \
+ UnpackedTarball/mariadb/libmariadb/my_net \
+ UnpackedTarball/mariadb/libmariadb/my_once \
+ UnpackedTarball/mariadb/libmariadb/my_open \
+ UnpackedTarball/mariadb/libmariadb/my_port \
+ UnpackedTarball/mariadb/libmariadb/my_pthread \
+ UnpackedTarball/mariadb/libmariadb/my_read \
+ UnpackedTarball/mariadb/libmariadb/my_realloc \
+ UnpackedTarball/mariadb/libmariadb/my_seek \
+ UnpackedTarball/mariadb/libmariadb/my_static \
+ UnpackedTarball/mariadb/libmariadb/my_symlink \
+ UnpackedTarball/mariadb/libmariadb/my_thr_init \
+ UnpackedTarball/mariadb/libmariadb/my_write \
+ UnpackedTarball/mariadb/libmariadb/password \
+ UnpackedTarball/mariadb/libmariadb/str2int \
+ UnpackedTarball/mariadb/libmariadb/strcend \
+ UnpackedTarball/mariadb/libmariadb/strcont \
+ UnpackedTarball/mariadb/libmariadb/strend \
+ UnpackedTarball/mariadb/libmariadb/strfill \
+ UnpackedTarball/mariadb/libmariadb/string \
+ UnpackedTarball/mariadb/libmariadb/strinstr \
+ UnpackedTarball/mariadb/libmariadb/strmake \
+ UnpackedTarball/mariadb/libmariadb/strmov \
+ UnpackedTarball/mariadb/libmariadb/strnmov \
+ UnpackedTarball/mariadb/libmariadb/strtoll \
+ UnpackedTarball/mariadb/libmariadb/strtoull \
+ UnpackedTarball/mariadb/libmariadb/strxmov \
+ UnpackedTarball/mariadb/libmariadb/strxnmov \
+ UnpackedTarball/mariadb/libmariadb/thr_mutex \
+ UnpackedTarball/mariadb/libmariadb/typelib \
+ UnpackedTarball/mariadb/libmariadb/sha1 \
+ UnpackedTarball/mariadb/libmariadb/my_stmt \
+ UnpackedTarball/mariadb/libmariadb/my_loaddata \
+ UnpackedTarball/mariadb/libmariadb/my_stmt_codec \
+ UnpackedTarball/mariadb/libmariadb/client_plugin \
+ UnpackedTarball/mariadb/libmariadb/my_auth \
+ UnpackedTarball/mariadb/libmariadb/ma_secure \
))
# vim: set noet sw=4 ts=4:
diff --git a/external/libmariadb/UnpackedTarball_mariadb.mk b/external/libmariadb/UnpackedTarball_mariadb.mk
index a198440ee917..489477c4ba41 100644
--- a/external/libmariadb/UnpackedTarball_mariadb.mk
+++ b/external/libmariadb/UnpackedTarball_mariadb.mk
@@ -27,15 +27,9 @@ $(eval $(call gb_UnpackedTarball_set_patchlevel,mariadb,1))
# <https://mariadb.atlassian.net/browse/CONC-18> "no external definition of
# non-static inline local_thr_alarm in libmariadb/net.c":
$(eval $(call gb_UnpackedTarball_add_patches,mariadb,\
- external/libmariadb/mariadb-thread.patch \
external/libmariadb/mariadb-swap.patch \
- external/libmariadb/mariadb-trunk-40.patch \
- external/libmariadb/mariadb-static-inline.patch \
+ external/libmariadb/mariadb-trunk-101.patch \
external/libmariadb/mariadb-msvc.patch.1 \
))
-$(eval $(call gb_UnpackedTarball_fix_end_of_line,mariadb,\
- libmysql/libmysql_exports.def \
-))
-
# vim: set noet sw=4 ts=4:
diff --git a/external/libmariadb/configs/linux_my_config.h b/external/libmariadb/configs/linux_my_config.h
index 6007d85676fe..a52a62ce0cdd 100644
--- a/external/libmariadb/configs/linux_my_config.h
+++ b/external/libmariadb/configs/linux_my_config.h
@@ -1,6 +1,4 @@
-#define HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE 1
-
/*
* Include file constants (processed in LibmysqlIncludeFiles.txt 1
*/
@@ -60,7 +58,7 @@
/* #undef HAVE_BFILL */
/* #undef HAVE_BMOVE */
#define HAVE_BZERO 1
-/* #undef HAVE_CLOCK_GETTIME */
+#define HAVE_CLOCK_GETTIME 1
/* #undef HAVE_COMPRESS */
/* #undef HAVE_CRYPT */
#define HAVE_DLERROR 1
@@ -69,7 +67,7 @@
#define HAVE_FCNTL 1
/* #undef HAVE_FCONVERT */
#define HAVE_FDATASYNC 1
-/* #undef HAVE_FESETROUND */
+#define HAVE_FESETROUND 1
#define HAVE_FINITE 1
#define HAVE_FSEEKO 1
#define HAVE_FSYNC 1
@@ -91,7 +89,7 @@
#define HAVE_INITGROUPS 1
#define HAVE_LDIV 1
#define HAVE_LOCALTIME_R 1
-/* #undef HAVE_LOG2 */
+#define HAVE_LOG2 1
#define HAVE_LONGJMP 1
#define HAVE_LSTAT 1
#define HAVE_MADVISE 1
@@ -108,19 +106,19 @@
#define HAVE_POLL 1
#define HAVE_PREAD 1
/* #undef HAVE_PTHREAD_ATTR_CREATE */
-/* #undef HAVE_PTHREAD_ATTR_GETSTACKSIZE */
+#define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1
/* #undef HAVE_PTHREAD_ATTR_SETPRIO */
#define HAVE_PTHREAD_ATTR_SETSCHEDPARAM 1
#define HAVE_PTHREAD_ATTR_SETSCOPE 1
-/* #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE */
+#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
/* #undef HAVE_PTHREAD_CONDATTR_CREATE */
/* #undef HAVE_PTHREAD_INIT */
-/* #undef HAVE_PTHREAD_KEY_DELETE */
-/* #undef HAVE_PTHREAD_KILL */
-/* #undef HAVE_PTHREAD_RWLOCK_RDLOCK */
+#define HAVE_PTHREAD_KEY_DELETE 1
+#define HAVE_PTHREAD_KILL 1
+#define HAVE_PTHREAD_RWLOCK_RDLOCK 1
/* #undef HAVE_PTHREAD_SETPRIO_NP */
#define HAVE_PTHREAD_SETSCHEDPARAM 1
-/* #undef HAVE_PTHREAD_SIGMASK */
+#define HAVE_PTHREAD_SIGMASK 1
/* #undef HAVE_PTHREAD_THREADMASK */
/* #undef HAVE_PTHREAD_YIELD_NP */
#define HAVE_READDIR_R 1
@@ -137,6 +135,7 @@
#define HAVE_SIGWAIT 1
#define HAVE_SLEEP 1
#define HAVE_SNPRINTF 1
+/* #undef HAVE_SQLITE */
#define HAVE_STPCPY 1
#define HAVE_STRERROR 1
/* #undef HAVE_STRLCPY */
@@ -160,127 +159,107 @@
*/
/* Types we may use */
#define SIZEOF_CHAR 1
-#ifdef SIZEOF_CHAR
+#if SIZEOF_CHAR
# define HAVE_CHAR 1
#endif
-#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__)
#define SIZEOF_CHARP 8
-#else
-#define SIZEOF_CHARP 4
-#endif
-#ifdef SIZEOF_CHARP
+#if SIZEOF_CHARP
# define HAVE_CHARP 1
#endif
#define SIZEOF_SHORT 2
-#ifdef SIZEOF_SHORT
+#if SIZEOF_SHORT
# define HAVE_SHORT 1
#endif
#define SIZEOF_INT 4
-#ifdef SIZEOF_INT
+#if SIZEOF_INT
# define HAVE_INT 1
#endif
-#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__)
#define SIZEOF_LONG 8
-#else
-#define SIZEOF_LONG 4
-#endif
-#ifdef SIZEOF_LONG
+#if SIZEOF_LONG
# define HAVE_LONG 1
#endif
#define SIZEOF_LONG_LONG 8
-#ifdef SIZEOF_LONG_LONG
+#if SIZEOF_LONG_LONG
# define HAVE_LONG_LONG 1
#endif
-#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__)
#define SIZEOF_OFF_T 8
-#else
-#define SIZEOF_OFF_T 4
-#endif
-#ifdef SIZEOF_OFF_T
+#if SIZEOF_OFF_T
# define HAVE_OFF_T 1
#endif
#define SIZEOF_SIGSET_T 128
-#ifdef SIZEOF_SIGSET_T
+#if SIZEOF_SIGSET_T
# define HAVE_SIGSET_T 1
#endif
-#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__)
#define SIZEOF_SIZE_T 8
-#else
-#define SIZEOF_SIZE_T 4
-#endif
-#ifdef SIZEOF_SIZE_T
+#if SIZEOF_SIZE_T
# define HAVE_SIZE_T 1
#endif
/* #undef SIZEOF_UCHAR */
-#ifdef SIZEOF_UCHAR
+#if SIZEOF_UCHAR
# define HAVE_UCHAR 1
#endif
#define SIZEOF_UINT 4
-#ifdef SIZEOF_UINT
+#if SIZEOF_UINT
# define HAVE_UINT 1
#endif
-#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__)
#define SIZEOF_ULONG 8
-#else
-#define SIZEOF_ULONG 4
-#endif
-#ifdef SIZEOF_ULONG
+#if SIZEOF_ULONG
# define HAVE_ULONG 1
#endif
/* #undef SIZEOF_INT8 */
-#ifdef SIZEOF_INT8
+#if SIZEOF_INT8
# define HAVE_INT8 1
#endif
/* #undef SIZEOF_UINT8 */
-#ifdef SIZEOF_UINT8
+#if SIZEOF_UINT8
# define HAVE_UINT8 1
#endif
/* #undef SIZEOF_INT16 */
-#ifdef SIZEOF_INT16
+#if SIZEOF_INT16
# define HAVE_INT16 1
#endif
/* #undef SIZEOF_UINT16 */
-#ifdef SIZEOF_UINT16
+#if SIZEOF_UINT16
# define HAVE_UINT16 1
#endif
/* #undef SIZEOF_INT32 */
-#ifdef SIZEOF_INT32
+#if SIZEOF_INT32
# define HAVE_INT32 1
#endif
/* #undef SIZEOF_UINT32 */
-#ifdef SIZEOF_UINT32
+#if SIZEOF_UINT32
# define HAVE_UINT32 1
#endif
/* #undef SIZEOF_U_INT32_T */
-#ifdef SIZEOF_U_INT32_T
+#if SIZEOF_U_INT32_T
# define HAVE_U_INT32_T 1
#endif
/* #undef SIZEOF_INT64 */
-#ifdef SIZEOF_INT64
+#if SIZEOF_INT64
# define HAVE_INT64 1
#endif
/* #undef SIZEOF_UINT64 */
-#ifdef SIZEOF_UINT64
+#if SIZEOF_UINT64
# define HAVE_UINT64 1
#endif
/* #undef SIZEOF_SOCKLEN_T */
-#ifdef SIZEOF_SOCKLEN_T
+#if SIZEOF_SOCKLEN_T
# define HAVE_SOCKLEN_T 1
#endif
@@ -295,3 +274,5 @@
/* #undef HAVE_THREADS */
#define SHAREDIR "share"
#define DEFAULT_CHARSET_HOME "/usr/local"
+#define PLUGINDIR "/usr/local/lib/plugin"
+
diff --git a/external/libmariadb/configs/mysql_version.h b/external/libmariadb/configs/mysql_version.h
index 26120a9ec10a..050e861b7b91 100644
--- a/external/libmariadb/configs/mysql_version.h
+++ b/external/libmariadb/configs/mysql_version.h
@@ -7,15 +7,19 @@
#include <custom_conf.h>
#else
#define PROTOCOL_VERSION 10
-#define MYSQL_CLIENT_VERSION "5.3.2"
-#define MYSQL_SERVER_VERSION "5.3.2"
+#define MYSQL_CLIENT_VERSION "5.5.0"
+#define MYSQL_SERVER_VERSION "5.5.0"
#define MYSQL_SERVER_SUFFIX ""
#define FRM_VER
-#define MYSQL_VERSION_ID 50302
+#define MYSQL_VERSION_ID 50500
#define MYSQL_PORT 3306
#define MYSQL_UNIX_ADDR "/tmp/mysql.sock"
#define MYSQL_CONFIG_NAME "my"
+#define MARIADB_PACKAGE_VERSION "1.1.2"
+#define MARIADB_SYSTEM_TYPE "Linux"
+#define MARIADB_MACHINE_TYPE "x86_64"
+
/* mysqld compile time options */
#ifndef MYSQL_CHARSET
#define MYSQL_CHARSET ""
diff --git a/external/libmariadb/mariadb-msvc.patch.1 b/external/libmariadb/mariadb-msvc.patch.1
index 60fddae793ec..b88f00f8d309 100644
--- a/external/libmariadb/mariadb-msvc.patch.1
+++ b/external/libmariadb/mariadb-msvc.patch.1
@@ -1,5 +1,5 @@
---- mariadb/libmysql/my_pthread.c.orig 2013-04-17 15:45:52.025896770 +0200
-+++ mariadb/libmysql/my_pthread.c 2013-04-17 15:47:32.292895908 +0200
+--- mariadb/libmariadb/my_pthread.c.orig 2013-04-17 15:45:52.025896770 +0200
++++ mariadb/libmariadb/my_pthread.c 2013-04-17 15:47:32.292895908 +0200
@@ -28,6 +28,10 @@
#ifdef _WIN32
diff --git a/external/libmariadb/mariadb-static-inline.patch b/external/libmariadb/mariadb-static-inline.patch
deleted file mode 100644
index c82266b99809..000000000000
--- a/external/libmariadb/mariadb-static-inline.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- mariadb/libmysql/net.c 2013-03-15 21:05:15.551769966 +0100
-+++ mariadb/libmysql/net.c 2013-03-15 21:26:13.543332306 +0100
-@@ -75,7 +75,7 @@
- #define thr_alarm_in_use(A) (*(A))
- #define thr_end_alarm(A)
- #define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
--inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-+static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
- {
- *A=1;
- return 0;
diff --git a/external/libmariadb/mariadb-thread.patch b/external/libmariadb/mariadb-thread.patch
deleted file mode 100644
index 997929f9eb28..000000000000
--- a/external/libmariadb/mariadb-thread.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- mariadb/libmysql/client_plugin.c 2013-03-06 17:06:42.548905989 +0100
-+++ mariadb/libmysql/client_plugin.c 2013-03-06 17:14:29.721588964 +0100
-@@ -175,7 +175,9 @@
- goto err2;
- }
-
-+#ifdef THREAD
- safe_mutex_assert_owner(&LOCK_load_client_plugin);
-+#endif
-
- p->next= plugin_list[plugin->type];
- plugin_list[plugin->type]= p;
diff --git a/external/libmariadb/mariadb-trunk-40.patch b/external/libmariadb/mariadb-trunk-101.patch
index 968a75048ebd..a5a74a519b6b 100644
--- a/external/libmariadb/mariadb-trunk-40.patch
+++ b/external/libmariadb/mariadb-trunk-101.patch
@@ -1,7 +1,780 @@
-=== modified file 'CMakeLists.txt'
---- mariadb/CMakeLists.txt 2012-11-28 21:44:42 +0000
-+++ mariadb/CMakeLists.txt 2013-03-14 21:01:43 +0000
-@@ -1,35 +1,57 @@
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/CheckFunctions.cmake mariadb-native-client.trunk/cmake/CheckFunctions.cmake
+--- mariadb/cmake/CheckFunctions.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/CheckFunctions.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,108 @@
++# This file is included by CMakeLists.txt and
++# checks for various functions.
++# include/my_config.h.in
++# You will find the appropiate defines in
++
++INCLUDE(CheckFunctionExists)
++
++CHECK_FUNCTION_EXISTS (access HAVE_ACCESS)
++CHECK_FUNCTION_EXISTS (aiowait HAVE_AIOWAIT)
++CHECK_FUNCTION_EXISTS (alarm HAVE_ALARM)
++CHECK_FUNCTION_EXISTS (alloca HAVE_ALLOCA)
++CHECK_FUNCTION_EXISTS (bcmp HAVE_BCMP)
++CHECK_FUNCTION_EXISTS (bfill HAVE_BFILL)
++CHECK_FUNCTION_EXISTS (bmove HAVE_BMOVE)
++CHECK_FUNCTION_EXISTS (bzero HAVE_BZERO)
++CHECK_FUNCTION_EXISTS (clock_gettime HAVE_CLOCK_GETTIME)
++CHECK_FUNCTION_EXISTS (compress HAVE_COMPRESS)
++CHECK_FUNCTION_EXISTS (crypt HAVE_CRYPT)
++CHECK_FUNCTION_EXISTS (dlerror HAVE_DLERROR)
++CHECK_FUNCTION_EXISTS (dlopen HAVE_DLOPEN)
++CHECK_FUNCTION_EXISTS (fchmod HAVE_FCHMOD)
++CHECK_FUNCTION_EXISTS (fcntl HAVE_FCNTL)
++CHECK_FUNCTION_EXISTS (fconvert HAVE_FCONVERT)
++CHECK_FUNCTION_EXISTS (fdatasync HAVE_FDATASYNC)
++CHECK_FUNCTION_EXISTS (fesetround HAVE_FESETROUND)
++CHECK_FUNCTION_EXISTS (finite HAVE_FINITE)
++CHECK_FUNCTION_EXISTS (fseeko HAVE_FSEEKO)
++CHECK_FUNCTION_EXISTS (fsync HAVE_FSYNC)
++CHECK_FUNCTION_EXISTS (getaddrinfo HAVE_GETADDRINFO)
++CHECK_FUNCTION_EXISTS (getcwd HAVE_GETCWD)
++CHECK_FUNCTION_EXISTS (gethostbyaddr_r HAVE_GETHOSTBYADDR_R)
++CHECK_FUNCTION_EXISTS (gethostbyname_r HAVE_GETHOSTBYNAME_R)
++CHECK_FUNCTION_EXISTS (gethrtime HAVE_GETHRTIME)
++CHECK_FUNCTION_EXISTS (getnameinfo HAVE_GETNAMEINFO)
++CHECK_FUNCTION_EXISTS (getpagesize HAVE_GETPAGESIZE)
++CHECK_FUNCTION_EXISTS (getpass HAVE_GETPASS)
++CHECK_FUNCTION_EXISTS (getpassphrase HAVE_GETPASSPHRASE)
++CHECK_FUNCTION_EXISTS (getpwnam HAVE_GETPWNAM)
++CHECK_FUNCTION_EXISTS (getpwuid HAVE_GETPWUID)
++CHECK_FUNCTION_EXISTS (getrlimit HAVE_GETRLIMIT)
++CHECK_FUNCTION_EXISTS (getrusage HAVE_GETRUSAGE)
++CHECK_FUNCTION_EXISTS (getwd HAVE_GETWD)
++CHECK_FUNCTION_EXISTS (gmtime_r HAVE_GMTIME_R)
++CHECK_FUNCTION_EXISTS (initgroups HAVE_INITGROUPS)
++CHECK_FUNCTION_EXISTS (ldiv HAVE_LDIV)
++CHECK_FUNCTION_EXISTS (localtime_r HAVE_LOCALTIME_R)
++CHECK_FUNCTION_EXISTS (log2 HAVE_LOG2)
++CHECK_FUNCTION_EXISTS (longjmp HAVE_LONGJMP)
++CHECK_FUNCTION_EXISTS (lstat HAVE_LSTAT)
++CHECK_FUNCTION_EXISTS (madvise HAVE_MADVISE)
++CHECK_FUNCTION_EXISTS (mallinfo HAVE_MALLINFO)
++CHECK_FUNCTION_EXISTS (memalign HAVE_MEMALIGN)
++CHECK_FUNCTION_EXISTS (memcpy HAVE_MEMCPY)
++CHECK_FUNCTION_EXISTS (memmove HAVE_MEMMOVE)
++CHECK_FUNCTION_EXISTS (mkstemp HAVE_MKSTEMP)
++CHECK_FUNCTION_EXISTS (mlock HAVE_MLOCK)
++CHECK_FUNCTION_EXISTS (mlockall HAVE_MLOCKALL)
++CHECK_FUNCTION_EXISTS (mmap HAVE_MMAP)
++CHECK_FUNCTION_EXISTS (mmap64 HAVE_MMAP64)
++CHECK_FUNCTION_EXISTS (perror HAVE_PERROR)
++CHECK_FUNCTION_EXISTS (poll HAVE_POLL)
++CHECK_FUNCTION_EXISTS (pread HAVE_PREAD)
++CHECK_FUNCTION_EXISTS (pthread_attr_create HAVE_PTHREAD_ATTR_CREATE)
++CHECK_FUNCTION_EXISTS (pthread_attr_getstacksize HAVE_PTHREAD_ATTR_GETSTACKSIZE)
++CHECK_FUNCTION_EXISTS (pthread_attr_setprio HAVE_PTHREAD_ATTR_SETPRIO)
++CHECK_FUNCTION_EXISTS (pthread_attr_setschedparam HAVE_PTHREAD_ATTR_SETSCHEDPARAM)
++CHECK_FUNCTION_EXISTS (pthread_attr_setscope HAVE_PTHREAD_ATTR_SETSCOPE)
++CHECK_FUNCTION_EXISTS (pthread_attr_setstacksize HAVE_PTHREAD_ATTR_SETSTACKSIZE)
++CHECK_FUNCTION_EXISTS (pthread_condattr_create HAVE_PTHREAD_CONDATTR_CREATE)
++CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT)
++CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE)
++CHECK_FUNCTION_EXISTS (pthread_kill HAVE_PTHREAD_KILL)
++CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK)
++CHECK_FUNCTION_EXISTS (pthread_setprio_np HAVE_PTHREAD_SETPRIO_NP)
++CHECK_FUNCTION_EXISTS (pthread_setschedparam HAVE_PTHREAD_SETSCHEDPARAM)
++CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK)
++CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK)
++CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP)
++CHECK_FUNCTION_EXISTS (readdir_r HAVE_READDIR_R)
++CHECK_FUNCTION_EXISTS (readlink HAVE_READLINK)
++CHECK_FUNCTION_EXISTS (realpath HAVE_REALPATH)
++CHECK_FUNCTION_EXISTS (rename HAVE_RENAME)
++CHECK_FUNCTION_EXISTS (sched_yield HAVE_SCHED_YIELD)
++CHECK_FUNCTION_EXISTS (select HAVE_SELECT)
++CHECK_FUNCTION_EXISTS (setfd HAVE_SETFD)
++CHECK_FUNCTION_EXISTS (setfilepointer HAVE_SETFILEPOINTER)
++CHECK_FUNCTION_EXISTS (sigaction HAVE_SIGACTION)
++CHECK_FUNCTION_EXISTS (sigthreadmask HAVE_SIGTHREADMASK)
++CHECK_FUNCTION_EXISTS (sigwait HAVE_SIGWAIT)
++CHECK_FUNCTION_EXISTS (sleep HAVE_SLEEP)
++CHECK_FUNCTION_EXISTS (snprintf HAVE_SNPRINTF)
++CHECK_FUNCTION_EXISTS (stpcpy HAVE_STPCPY)
++CHECK_FUNCTION_EXISTS (strerror HAVE_STRERROR)
++CHECK_FUNCTION_EXISTS (strlcpy HAVE_STRLCPY)
++CHECK_FUNCTION_EXISTS (strnlen HAVE_STRNLEN)
++CHECK_FUNCTION_EXISTS (strpbrk HAVE_STRPBRK)
++CHECK_FUNCTION_EXISTS (strsep HAVE_STRSEP)
++CHECK_FUNCTION_EXISTS (strstr HAVE_STRSTR)
++CHECK_FUNCTION_EXISTS (strtok_r HAVE_STRTOK_R)
++CHECK_FUNCTION_EXISTS (strtol HAVE_STRTOL)
++CHECK_FUNCTION_EXISTS (strtoll HAVE_STRTOLL)
++CHECK_FUNCTION_EXISTS (strtoul HAVE_STRTOUL)
++CHECK_FUNCTION_EXISTS (strtoull HAVE_STRTOULL)
++CHECK_FUNCTION_EXISTS (tell HAVE_TELL)
++CHECK_FUNCTION_EXISTS (thr_setconcurrency HAVE_THR_SETCONCURRENCY)
++CHECK_FUNCTION_EXISTS (thr_yield HAVE_THR_YIELD)
++CHECK_FUNCTION_EXISTS (vasprintf HAVE_VASPRINTF)
++CHECK_FUNCTION_EXISTS (vsnprintf HAVE_VSNPRINTF)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/CheckIncludeFiles.cmake mariadb-native-client.trunk/cmake/CheckIncludeFiles.cmake
+--- mariadb/cmake/CheckIncludeFiles.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/CheckIncludeFiles.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,68 @@
++# This file is included by CMakeLists.txt and
++# checks for various header files.
++# You will find the appropiate defines in
++# include/my_config.h.in
++
++INCLUDE(CheckIncludeFiles)
++
++CHECK_INCLUDE_FILES (alloca.h HAVE_ALLOCA_H)
++CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H)
++CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H)
++CHECK_INCLUDE_FILES (dirent.h HAVE_DIRENT_H)
++CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H)
++CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H)
++CHECK_INCLUDE_FILES (fcntl.h HAVE_FCNTL_H)
++CHECK_INCLUDE_FILES (fenv.h HAVE_FENV_H)
++CHECK_INCLUDE_FILES (float.h HAVE_FLOAT_H)
++CHECK_INCLUDE_FILES (fpu/control.h HAVE_FPU_CONTROL_H)
++CHECK_INCLUDE_FILES (grp.h HAVE_GRP_H)
++CHECK_INCLUDE_FILES (ieeefp.h HAVE_IEEEFP_H)
++CHECK_INCLUDE_FILES (limits.h HAVE_LIMITS_H)
++CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
++CHECK_INCLUDE_FILES (memory.h HAVE_MEMORY_H)
++CHECK_INCLUDE_FILES (netinet/in.h HAVE_NETINET_IN_H)
++CHECK_INCLUDE_FILES (paths.h HAVE_PATHS_H)
++CHECK_INCLUDE_FILES (pwd.h HAVE_PWD_H)
++CHECK_INCLUDE_FILES (sched.h HAVE_SCHED_H)
++CHECK_INCLUDE_FILES (select.h HAVE_SELECT_H)
++
++CHECK_INCLUDE_FILES (signal.h INCLUDE_SIGNAL)
++IF(INCLUDE_SIGNAL)
++ SET(HAVE_SIGNAL 1)
++ SET(CMAKE_EXTRA_INCLUDE_FILES signal.h)
++ENDIF(INCLUDE_SIGNAL)
++
++CHECK_INCLUDE_FILES (stddef.h HAVE_STDDEF_H)
++
++CHECK_INCLUDE_FILES (stdint.h HAVE_STDINT_H)
++IF(HAVE_STDINT_H)
++ SET(CMAKE_EXTRA_INCLUDE_FILES stdint.h)
++ENDIF(HAVE_STDINT_H)
++
++CHECK_INCLUDE_FILES (stdlib.h HAVE_STDLIB_H)
++CHECK_INCLUDE_FILES (string.h HAVE_STRING_H)
++CHECK_INCLUDE_FILES (strings.h HAVE_STRINGS_H)
++CHECK_INCLUDE_FILES (synch.h HAVE_SYNCH_H)
++CHECK_INCLUDE_FILES (sys/fpu.h HAVE_SYS_FPU_H)
++CHECK_INCLUDE_FILES (sys/ioctl.h HAVE_SYS_IOCTL_H)
++CHECK_INCLUDE_FILES (sys/ipc.h HAVE_SYS_IPC_H)
++CHECK_INCLUDE_FILES (sys/mman.h HAVE_SYS_MMAN_H)
++CHECK_INCLUDE_FILES (sys/prctl.h HAVE_SYS_PRCTL_H)
++CHECK_INCLUDE_FILES (sys/select.h HAVE_SYS_SELECT_H)
++CHECK_INCLUDE_FILES (sys/shm.h HAVE_SYS_SHM_H)
++
++CHECK_INCLUDE_FILES (sys/socket.h HAVE_SYS_SOCKET_H)
++IF(HAVE_SYS_SOCKET_H)
++ SET(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
++ENDIF(HAVE_SYS_SOCKET_H)
++
++CHECK_INCLUDE_FILES (sys/stat.h HAVE_SYS_STAT_H)
++CHECK_INCLUDE_FILES (sys/stream.h HAVE_SYS_STREAM_H)
++CHECK_INCLUDE_FILES (sys/timeb.h HAVE_SYS_TIMEB_H)
++CHECK_INCLUDE_FILES (sys/types.h HAVE_SYS_TYPES_H)
++CHECK_INCLUDE_FILES (sys/un.h HAVE_SYS_UN_H)
++CHECK_INCLUDE_FILES (sysent.h HAVE_SYSENT_H)
++CHECK_INCLUDE_FILES (termio.h HAVE_TERMIO_H)
++CHECK_INCLUDE_FILES (termios.h HAVE_TERMIOS_H)
++CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H)
++CHECK_INCLUDE_FILES (utime.h HAVE_UTIME_H)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/CheckTypes.cmake mariadb-native-client.trunk/cmake/CheckTypes.cmake
+--- mariadb/cmake/CheckTypes.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/CheckTypes.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,106 @@
++# This file is included by CMakeLists.txt and
++# checks for type sizes.
++# You will find the appropiate defines in
++# include/my_config.h.in
++INCLUDE (CheckTypeSize)
++
++SET(CMAKE_EXTRA_INCLUDE_FILES signal.h)
++CHECK_TYPE_SIZE(sigset_t SIZEOF_SIGSET_T)
++CHECK_TYPE_SIZE(char SIZEOF_CHAR)
++CHECK_TYPE_SIZE("char *" SIZEOF_CHARP)
++CHECK_TYPE_SIZE(short SIZEOF_SHORT)
++CHECK_TYPE_SIZE(int SIZEOF_INT)
++CHECK_TYPE_SIZE(long SIZEOF_LONG)
++CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
++SET(CMAKE_EXTRA_INCLUDE_FILES stdio.h)
++CHECK_TYPE_SIZE(size_t SIZEOF_SIZE_T)
++SET(CMAKE_EXTRA_INCLUDE_FILES sys/types.h)
++CHECK_TYPE_SIZE(off_t SIZEOF_OFF_T)
++CHECK_TYPE_SIZE(uchar SIZEOF_UCHAR)
++CHECK_TYPE_SIZE(uint SIZEOF_UINT)
++CHECK_TYPE_SIZE(ulong SIZEOF_ULONG)
++CHECK_TYPE_SIZE(int8 SIZEOF_INT8)
++CHECK_TYPE_SIZE(uint8 SIZEOF_UINT8)
++CHECK_TYPE_SIZE(int16 SIZEOF_INT16)
++CHECK_TYPE_SIZE(uint16 SIZEOF_UINT16)
++CHECK_TYPE_SIZE(int32 SIZEOF_INT32)
++CHECK_TYPE_SIZE(uint32 SIZEOF_UINT32)
++CHECK_TYPE_SIZE(u_int32_t SIZEOF_UINT_32_T)
++CHECK_TYPE_SIZE(int64 SIZEOF_INT64)
++CHECK_TYPE_SIZE(uint64 SIZEOF_UINT64)
++CHECK_TYPE_SIZE(socklen_t SIZEOF_SOCKLEN_T)
++
++#
++# Compile testing
++#
++INCLUDE (CheckCSourceCompiles)
++
++#
++# signal handler
++#
++CHECK_C_SOURCE_COMPILES("
++ #include <signal.h>
++
++ #ifdef signal
++ #undef signal
++ #endif
++
++ #ifdef __cplusplus
++ extern \"C\" void (*signal (int, void (*)(int)))(int);
++ #else
++ void (*signal ()) ();
++ #endif
++
++ int main(int ac, char **av)
++ {
++ }"
++ IS_VOID_SIGNAL)
++
++IF(IS_VOID_SIGNAL)
++ SET(RETSIGTYPE "void")
++ELSE(IS_VOID_SIGNAL)
++ SET(RETSIGTYPE "int")
++ENDIF(IS_VOID_SIGNAL)
++
++#
++# quick sort
++#
++CHECK_C_SOURCE_COMPILES("
++ #include <stdlib.h>
++ #ifdef __cplusplus
++ extern \"C\" void qsort(void *base, size_t nel, size_t width, int (*compar) (const void *, const void *));
++ #else
++ void qsort(void *base, size_t nel, size_t width, int (*compar) (const void *, const void *));
++ #endif
++ int main(int ac, char **av)
++ {
++ }"
++ IS_VOID_QSORT)
++IF(IS_VOID_QSORT)
++ SET(RETQSORTTYPE "void")
++ELSE(IS_VOID_QSORT)
++ SET(RETQSORTTYPE "int")
++ENDIF(IS_VOID_QSORT)
++
++#
++# SOCKET_SIZE
++#
++IF(WIN32)
++ SET(SOCKET_SIZE_TYPE int)
++ELSE(WIN32)
++ FOREACH(CHECK_TYPE "socklen_t" "size_t" "int")
++ IF (NOT SOCKET_SIZE_TYPE)
++ CHECK_C_SOURCE_COMPILES("
++ #include <sys/socket.h>
++ int main(int argc, char **argv)
++ {
++ getsockname(0, 0, (${CHECK_TYPE} *)0);
++ return 0;
++ }"
++ SOCKET_SIZE_FOUND_${CHECK_TYPE})
++ IF(SOCKET_SIZE_FOUND_${CHECK_TYPE})
++ SET(SOCKET_SIZE_TYPE ${CHECK_TYPE})
++ ENDIF(SOCKET_SIZE_FOUND_${CHECK_TYPE})
++ ENDIF (NOT SOCKET_SIZE_TYPE)
++ ENDFOREACH()
++ENDIF(WIN32)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/FindIconv.cmake mariadb-native-client.trunk/cmake/FindIconv.cmake
+--- mariadb/cmake/FindIconv.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/FindIconv.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,52 @@
++# Copyright (c) 2010 Michael Bell <michael.bell@web.de>
++
++if (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
++ # Already in cache, be silent
++ set(ICONV_FIND_QUIETLY TRUE)
++endif (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
++
++find_path(ICONV_INCLUDE_DIR iconv.h)
++
++find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
++
++if (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
++ set (ICONV_FOUND TRUE)
++endif (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
++
++set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
++set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
++
++if (ICONV_FOUND)
++ include(CheckCSourceCompiles)
++ CHECK_C_SOURCE_COMPILES("
++ #include <iconv.h>
++ int main(){
++ iconv_t conv = 0;
++ const char* in = 0;
++ size_t ilen = 0;
++ char* out = 0;
++ size_t olen = 0;
++ iconv(conv, &in, &ilen, &out, &olen);
++ return 0;
++ }
++" ICONV_SECOND_ARGUMENT_IS_CONST )
++endif (ICONV_FOUND)
++
++set (CMAKE_REQUIRED_INCLUDES)
++set (CMAKE_REQUIRED_LIBRARIES)
++
++if (ICONV_FOUND)
++ if (NOT ICONV_FIND_QUIETLY)
++ message (STATUS "Found Iconv: ${ICONV_LIBRARIES}")
++ endif (NOT ICONV_FIND_QUIETLY)
++else (ICONV_FOUND)
++ if (Iconv_FIND_REQUIRED)
++ message (FATAL_ERROR "Could not find Iconv")
++ endif (Iconv_FIND_REQUIRED)
++endif (ICONV_FOUND)
++
++MARK_AS_ADVANCED(
++ ICONV_INCLUDE_DIR
++ ICONV_LIBRARIES
++ ICONV_SECOND_ARGUMENT_IS_CONST
++)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/SearchLibrary.cmake mariadb-native-client.trunk/cmake/SearchLibrary.cmake
+--- mariadb/cmake/SearchLibrary.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/SearchLibrary.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,23 @@
++INCLUDE(CheckFunctionExists)
++INCLUDE(CheckLibraryExists)
++
++FUNCTION(SEARCH_LIBRARY library_name function liblist)
++ IF(${${library_name}})
++ RETURN()
++ ENDIF()
++ CHECK_FUNCTION_EXISTS(${function} HAVE_${function}_IN_LIBC)
++ # check if function is part of libc
++ IF(HAVE_${function}_IN_LIBC)
++ SET(${library_name} "" PARENT_SCOPE)
++ RETURN()
++ ENDIF()
++ FOREACH(lib ${liblist})
++ CHECK_LIBRARY_EXISTS(${lib} ${function} "" HAVE_${function}_IN_${lib})
++ IF(HAVE_${function}_IN_${lib})
++ SET(${library_name} ${lib} PARENT_SCOPE)
++ SET(HAVE_${library_name} 1 PARENT_SCOPE)
++ RETURN()
++ ENDIF()
++ ENDFOREACH()
++ENDFUNCTION()
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/cmake/WindowsCache.cmake mariadb-native-client.trunk/cmake/WindowsCache.cmake
+--- mariadb/cmake/WindowsCache.cmake 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/cmake/WindowsCache.cmake 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,392 @@
++IF(MSVC)
++SET(BFD_H_EXISTS 0 CACHE INTERNAL "")
++SET(HAVE_ACCESS 1 CACHE INTERNAL "")
++SET(HAVE_AIO_H CACHE INTERNAL "")
++SET(HAVE_AIO_READ CACHE INTERNAL "")
++SET(HAVE_ALARM CACHE INTERNAL "")
++SET(HAVE_ALLOCA_H CACHE INTERNAL "")
++SET(HAVE_ARPA_INET_H CACHE INTERNAL "")
++SET(HAVE_ASM_MSR_H CACHE INTERNAL "")
++SET(HAVE_BACKTRACE CACHE INTERNAL "")
++SET(HAVE_BACKTRACE_SYMBOLS CACHE INTERNAL "")
++SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE INTERNAL "")
++SET(HAVE_BFILL CACHE INTERNAL "")
++SET(HAVE_BMOVE CACHE INTERNAL "")
++SET(HAVE_BSD_SIGNALS CACHE INTERNAL "")
++SET(HAVE_BSEARCH 1 CACHE INTERNAL "")
++SET(HAVE_BSS_START CACHE INTERNAL "")
++SET(HAVE_BZERO CACHE INTERNAL "")
++SET(HAVE_CHOWN CACHE INTERNAL "")
++SET(HAVE_CLOCK_GETTIME CACHE INTERNAL "")
++SET(HAVE_COMPRESS CACHE INTERNAL "")
++SET(HAVE_CRYPT CACHE INTERNAL "")
++SET(HAVE_CRYPT_H CACHE INTERNAL "")
++SET(HAVE_CUSERID CACHE INTERNAL "")
++SET(HAVE_CXX_NEW 1 CACHE INTERNAL "")
++SET(HAVE_DECL_MADVISE CACHE INTERNAL "")
++SET(HAVE_DIRECTIO CACHE INTERNAL "")
++SET(HAVE_DIRENT_H CACHE INTERNAL "")
++SET(HAVE_DLERROR CACHE INTERNAL "")
++SET(HAVE_DLFCN_H CACHE INTERNAL "")
++SET(HAVE_DLOPEN CACHE INTERNAL "")
++SET(HAVE_DOPRNT CACHE INTERNAL "")
++SET(HAVE_EXECINFO_H CACHE INTERNAL "")
++SET(HAVE_FCHMOD CACHE INTERNAL "")
++SET(HAVE_FCNTL CACHE INTERNAL "")
++SET(HAVE_FCNTL_H 1 CACHE INTERNAL "")
++SET(HAVE_FCNTL_NONBLOCK CACHE INTERNAL "")
++SET(HAVE_FCONVERT CACHE INTERNAL "")
++SET(HAVE_FDATASYNC CACHE INTERNAL "")
++SET(HAVE_DECL_FDATASYNC CACHE INTERNAL "")
++SET(HAVE_FEDISABLEEXCEPT CACHE INTERNAL "")
++SET(HAVE_FENV_H CACHE INTERNAL "")
++SET(HAVE_FESETROUND CACHE INTERNAL "")
++SET(HAVE_FGETLN CACHE INTERNAL "")
++SET(HAVE_FINITE CACHE INTERNAL "")
++SET(HAVE_FINITE_IN_MATH_H CACHE INTERNAL "")
++SET(HAVE_FLOATINGPOINT_H CACHE INTERNAL "")
++SET(HAVE_FLOAT_H 1 CACHE INTERNAL "")
++SET(HAVE_FLOCKFILE CACHE INTERNAL "")
++SET(HAVE_FNMATCH_H CACHE INTERNAL "")
++SET(HAVE_FPSETMASK CACHE INTERNAL "")
++SET(HAVE_FPU_CONTROL_H CACHE INTERNAL "")
++SET(HAVE_FSEEKO CACHE INTERNAL "")
++SET(HAVE_FSYNC CACHE INTERNAL "")
++SET(HAVE_FTIME 1 CACHE INTERNAL "")
++SET(HAVE_FTRUNCATE CACHE INTERNAL "")
++SET(HAVE_GETADDRINFO 1 CACHE INTERNAL "")
++SET(HAVE_GETCWD 1 CACHE INTERNAL "")
++SET(HAVE_GETHOSTBYADDR_R CACHE INTERNAL "")
++SET(HAVE_GETHRTIME CACHE INTERNAL "")
++SET(HAVE_GETLINE CACHE INTERNAL "")
++SET(HAVE_GETNAMEINFO CACHE INTERNAL "")
++SET(HAVE_GETPAGESIZE CACHE INTERNAL "")
++SET(HAVE_GETPASS CACHE INTERNAL "")
++SET(HAVE_GETPASSPHRASE CACHE INTERNAL "")
++SET(HAVE_GETPWNAM CACHE INTERNAL "")
++SET(HAVE_GETPWUID CACHE INTERNAL "")
++SET(HAVE_GETRLIMIT CACHE INTERNAL "")
++SET(HAVE_GETRUSAGE CACHE INTERNAL "")
++SET(HAVE_GETTIMEOFDAY CACHE INTERNAL "")
++SET(HAVE_GETWD CACHE INTERNAL "")
++SET(HAVE_GMTIME_R CACHE INTERNAL "")
++SET(HAVE_GRP_H CACHE INTERNAL "")
++SET(HAVE_IA64INTRIN_H CACHE INTERNAL "")
++SET(HAVE_IEEEFP_H CACHE INTERNAL "")
++SET(HAVE_INDEX CACHE INTERNAL "")
++SET(HAVE_INITGROUPS CACHE INTERNAL "")
++SET(HAVE_INTTYPES_H CACHE INTERNAL "")
++SET(HAVE_IPPROTO_IPV6 CACHE INTERNAL "")
++SET(HAVE_IPV6 TRUE CACHE INTERNAL "")
++SET(HAVE_IPV6_V6ONLY 1 CACHE INTERNAL "")
++SET(HAVE_ISINF CACHE INTERNAL "")
++SET(HAVE_ISNAN CACHE INTERNAL "")
++SET(HAVE_ISSETUGID CACHE INTERNAL "")
++SET(HAVE_GETUID CACHE INTERNAL "")
++SET(HAVE_GETEUID CACHE INTERNAL "")
++SET(HAVE_GETGID CACHE INTERNAL "")
++SET(HAVE_GETEGID CACHE INTERNAL "")
++SET(HAVE_LANGINFO_H CACHE INTERNAL "")
++SET(HAVE_LDIV 1 CACHE INTERNAL "")
++SET(HAVE_LIMITS_H 1 CACHE INTERNAL "")
++SET(HAVE_LOCALE_H 1 CACHE INTERNAL "")
++SET(HAVE_LOCALTIME_R CACHE INTERNAL "")
++SET(HAVE_LOG2 CACHE INTERNAL "")
++SET(HAVE_LONGJMP 1 CACHE INTERNAL "")
++SET(HAVE_LRAND48 CACHE INTERNAL "")
++SET(HAVE_LSTAT CACHE INTERNAL "")
++SET(HAVE_MADVISE CACHE INTERNAL "")
++SET(HAVE_MALLINFO CACHE INTERNAL "")
++SET(HAVE_MALLOC_H 1 CACHE INTERNAL "")
++SET(HAVE_MEMALIGN CACHE INTERNAL "")
++SET(HAVE_MEMCPY 1 CACHE INTERNAL "")
++SET(HAVE_MEMMOVE 1 CACHE INTERNAL "")
++SET(HAVE_MEMORY_H 1 CACHE INTERNAL "")
++SET(HAVE_MKSTEMP CACHE INTERNAL "")
++SET(HAVE_MLOCK CACHE INTERNAL "")
++SET(HAVE_MLOCKALL CACHE INTERNAL "")
++SET(HAVE_MMAP CACHE INTERNAL "")
++SET(HAVE_MMAP64 CACHE INTERNAL "")
++SET(HAVE_NETDB_H CACHE INTERNAL "")
++SET(HAVE_NETINET_IN6_H CACHE INTERNAL "")
++SET(HAVE_NETINET_IN_H CACHE INTERNAL "")
++SET(HAVE_NL_LANGINFO CACHE INTERNAL "")
++SET(HAVE_PASE_ENVIRONMENT CACHE INTERNAL "")
++SET(HAVE_PATHS_H CACHE INTERNAL "")
++SET(HAVE_PCLOSE CACHE INTERNAL "")
++SET(HAVE_PERROR 1 CACHE INTERNAL "")
++SET(HAVE_PEERCRED CACHE INTERNAL "")
++SET(HAVE_PAM_APPL_H CACHE INTERNAL "")
++SET(HAVE_POLL_H CACHE INTERNAL "")
++SET(HAVE_POPEN CACHE INTERNAL "")
++SET(HAVE_POLL CACHE INTERNAL "")
++SET(HAVE_PORT_CREATE CACHE INTERNAL "")
++SET(HAVE_PORT_H CACHE INTERNAL "")
++SET(HAVE_POSIX_FALLOCATE CACHE INTERNAL "")
++SET(HAVE_POSIX_SIGNALS CACHE INTERNAL "")
++SET(HAVE_PREAD CACHE INTERNAL "")
++SET(HAVE_PRINTSTACK CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_CREATE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_GETSTACKSIZE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_SETSCOPE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_SETSTACKSIZE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_CONDATTR_CREATE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_CONDATTR_SETCLOCK CACHE INTERNAL "")
++SET(HAVE_PTHREAD_INIT CACHE INTERNAL "")
++SET(HAVE_PTHREAD_KEY_DELETE CACHE INTERNAL "")
++SET(HAVE_PTHREAD_RWLOCK_RDLOCK CACHE INTERNAL "")
++SET(HAVE_PTHREAD_SIGMASK CACHE INTERNAL "")
++SET(HAVE_PTHREAD_THREADMASK CACHE INTERNAL "")
++SET(HAVE_PTHREAD_YIELD_NP CACHE INTERNAL "")
++SET(HAVE_PTHREAD_YIELD_ZERO_ARG CACHE INTERNAL "")
++SET(HAVE_PUTENV 1 CACHE INTERNAL "")
++SET(HAVE_PWD_H CACHE INTERNAL "")
++SET(HAVE_RDTSCLL CACHE INTERNAL "")
++SET(HAVE_READDIR_R CACHE INTERNAL "")
++SET(HAVE_READLINK CACHE INTERNAL "")
++SET(HAVE_READ_REAL_TIME CACHE INTERNAL "")
++SET(HAVE_REALPATH CACHE INTERNAL "")
++SET(HAVE_REGCOMP CACHE INTERNAL "")
++SET(HAVE_RENAME 1 CACHE INTERNAL "")
++SET(HAVE_RE_COMP CACHE INTERNAL "")
++SET(HAVE_RINT CACHE INTERNAL "")
++SET(HAVE_RWLOCK_INIT CACHE INTERNAL "")
++SET(HAVE_SCHED_H CACHE INTERNAL "")
++SET(HAVE_SCHED_YIELD CACHE INTERNAL "")
++SET(HAVE_SELECT 1 CACHE INTERNAL "")
++SET(HAVE_SELECT_H CACHE INTERNAL "")
++SET(HAVE_SEMAPHORE_H CACHE INTERNAL "")
++SET(HAVE_SETENV CACHE INTERNAL "")
++SET(HAVE_SETFD CACHE INTERNAL "")
++SET(HAVE_SETLOCALE 1 CACHE INTERNAL "")
++SET(HAVE_SHMAT CACHE INTERNAL "")
++SET(HAVE_SHMCTL CACHE INTERNAL "")
++SET(HAVE_SHMDT CACHE INTERNAL "")
++SET(HAVE_SHMGET CACHE INTERNAL "")
++SET(HAVE_SIGACTION CACHE INTERNAL "")
++SET(HAVE_SIGADDSET CACHE INTERNAL "")
++SET(HAVE_SIGEMPTYSET CACHE INTERNAL "")
++SET(HAVE_SIGHOLD CACHE INTERNAL "")
++SET(HAVE_SIGINT 1 CACHE INTERNAL "")
++SET(HAVE_SIGPIPE CACHE INTERNAL "")
++SET(HAVE_SIGQUIT CACHE INTERNAL "")
++SET(HAVE_SIGSET CACHE INTERNAL "")
++SET(HAVE_SIGTERM 1 CACHE INTERNAL "")
++SET(HAVE_SIGTHREADMASK CACHE INTERNAL "")
++SET(HAVE_SIGWAIT CACHE INTERNAL "")
++SET(HAVE_SIZEOF_BOOL FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_CHAR TRUE CACHE INTERNAL "")
++SET(SIZEOF_CHAR 1 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_CHARP TRUE CACHE INTERNAL "")
++SET(SIZEOF_CHARP ${CMAKE_SIZEOF_VOID_P} CACHE INTERNAL "")
++SET(HAVE_SIZEOF_IN6_ADDR TRUE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_INT TRUE CACHE INTERNAL "")
++SET(SIZEOF_INT 4 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_INT16 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_INT32 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_INT64 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_INT8 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_LONG TRUE CACHE INTERNAL "")
++SET(SIZEOF_LONG 4 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_LONG_LONG TRUE CACHE INTERNAL "")
++SET(SIZEOF_LONG_LONG 8 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_MODE_T FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_OFF_T TRUE CACHE INTERNAL "")
++SET(SIZEOF_OFF_T 4 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_SHORT TRUE CACHE INTERNAL "")
++SET(SIZEOF_SHORT 2 CACHE INTERNAL "")
++SET(HAVE_SIZEOF_SIGSET_T FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_SIZE_T TRUE CACHE INTERNAL "")
++SET(SIZEOF_SIZE_T ${CMAKE_SIZEOF_VOID_P} CACHE INTERNAL "")
++SET(HAVE_SIZEOF_SOCKADDR_IN6 TRUE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_SOCKLEN_T FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UCHAR FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UINT FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UINT16 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UINT32 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UINT64 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_UINT8 FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_ULONG FALSE CACHE INTERNAL "")
++SET(HAVE_SIZEOF_U_INT32_T FALSE CACHE INTERNAL "")
++SET(HAVE_SIZE_OF_SSIZE_T FALSE CACHE INTERNAL "")
++SET(HAVE_SLEEP CACHE INTERNAL "")
++SET(HAVE_SNPRINTF CACHE INTERNAL "")
++SET(HAVE_SOCKADDR_STORAGE_SS_FAMILY 1 CACHE INTERNAL "")
++SET(HAVE_SOLARIS_STYLE_GETHOST CACHE INTERNAL "")
++SET(STACK_DIRECTION -1 CACHE INTERNAL "")
++SET(HAVE_STDARG_H 1 CACHE INTERNAL "")
++SET(HAVE_STDDEF_H 1 CACHE INTERNAL "")
++SET(HAVE_STDINT_H CACHE INTERNAL "")
++SET(HAVE_STDLIB_H 1 CACHE INTERNAL "")
++SET(HAVE_STPCPY CACHE INTERNAL "")
++SET(HAVE_STRCASECMP CACHE INTERNAL "")
++SET(HAVE_STRCOLL 1 CACHE INTERNAL "")
++SET(HAVE_STRDUP 1 CACHE INTERNAL "")
++SET(HAVE_STRERROR 1 CACHE INTERNAL "")
++SET(HAVE_STRINGS_H CACHE INTERNAL "")
++SET(HAVE_STRING_H 1 CACHE INTERNAL "")
++SET(HAVE_STRLCAT CACHE INTERNAL "")
++SET(HAVE_STRLCPY CACHE INTERNAL "")
++SET(HAVE_STRNCASECMP CACHE INTERNAL "")
++SET(HAVE_STRNDUP CACHE INTERNAL "")
++IF(MSVC_VERSION GREATER 1310)
++SET(HAVE_STRNLEN 1 CACHE INTERNAL "")
++ENDIF()
++SET(HAVE_STRPBRK 1 CACHE INTERNAL "")
++SET(HAVE_STRSEP CACHE INTERNAL "")
++SET(HAVE_STRSIGNAL CACHE INTERNAL "")
++SET(HAVE_STRSTR 1 CACHE INTERNAL "")
++SET(HAVE_STRTOK_R CACHE INTERNAL "")
++SET(HAVE_STRTOL 1 CACHE INTERNAL "")
++SET(HAVE_STRTOLL CACHE INTERNAL "")
++SET(HAVE_STRTOUL 1 CACHE INTERNAL "")
++SET(HAVE_STRTOULL CACHE INTERNAL "")
++SET(HAVE_SVR3_SIGNALS CACHE INTERNAL "")
++SET(HAVE_SYNCH_H CACHE INTERNAL "")
++SET(HAVE_SYSENT_H CACHE INTERNAL "")
++SET(HAVE_SYS_CDEFS_H CACHE INTERNAL "")
++SET(HAVE_SYS_DIR_H CACHE INTERNAL "")
++SET(HAVE_SYS_ERRLIST CACHE INTERNAL "")
++SET(HAVE_SYS_FILE_H CACHE INTERNAL "")
++SET(HAVE_SYS_FPU_H CACHE INTERNAL "")
++SET(HAVE_SYS_IOCTL_H CACHE INTERNAL "")
++SET(HAVE_SYS_IPC_H CACHE INTERNAL "")
++SET(HAVE_SYS_MALLOC_H CACHE INTERNAL "")
++SET(HAVE_SYS_MMAN_H CACHE INTERNAL "")
++SET(HAVE_SYS_PARAM_H CACHE INTERNAL "")
++SET(HAVE_SYS_PRCTL_H CACHE INTERNAL "")
++SET(HAVE_SYS_PTEM_H CACHE INTERNAL "")
++SET(HAVE_SYS_PTE_H CACHE INTERNAL "")
++SET(HAVE_SYS_RESOURCE_H CACHE INTERNAL "")
++SET(HAVE_SYS_SELECT_H CACHE INTERNAL "")
++SET(HAVE_SYS_SHM_H CACHE INTERNAL "")
++SET(HAVE_SYS_SOCKIO_H CACHE INTERNAL "")
++SET(HAVE_SYS_SOCKET_H CACHE INTERNAL "")
++SET(HAVE_SYS_STAT_H 1 CACHE INTERNAL "")
++SET(HAVE_SYS_STREAM_H CACHE INTERNAL "")
++SET(HAVE_SYS_TERMCAP_H CACHE INTERNAL "")
++SET(HAVE_SYS_TIMEB_H 1 CACHE INTERNAL "")
++SET(HAVE_SYS_TIMES_H CACHE INTERNAL "")
++SET(HAVE_SYS_TIME_H CACHE INTERNAL "")
++SET(HAVE_SYS_TYPES_H 1 CACHE INTERNAL "")
++SET(HAVE_SYS_UN_H CACHE INTERNAL "")
++SET(HAVE_SYS_UTIME_H 1 CACHE INTERNAL "")
++SET(HAVE_SYS_VADVISE_H CACHE INTERNAL "")
++SET(HAVE_SYS_WAIT_H CACHE INTERNAL "")
++SET(HAVE_TCGETATTR CACHE INTERNAL "")
++SET(HAVE_TELL 1 CACHE INTERNAL "")
++SET(HAVE_TEMPNAM 1 CACHE INTERNAL "")
++SET(HAVE_TERMCAP_H CACHE INTERNAL "")
++SET(HAVE_TERMIOS_H CACHE INTERNAL "")
++SET(HAVE_TERMIO_H CACHE INTERNAL "")
++SET(HAVE_TERM_H CACHE INTERNAL "")
++SET(HAVE_THR_SETCONCURRENCY CACHE INTERNAL "")
++SET(HAVE_THR_YIELD CACHE INTERNAL "")
++SET(HAVE_TIME 1 CACHE INTERNAL "")
++SET(HAVE_TIMES CACHE INTERNAL "")
++SET(HAVE_TIMESPEC_TS_SEC CACHE INTERNAL "")
++SET(HAVE_TIME_H 1 CACHE INTERNAL "")
++SET(HAVE_TZNAME 1 CACHE INTERNAL "")
++SET(HAVE_UNISTD_H CACHE INTERNAL "")
++SET(HAVE_UTIME_H CACHE INTERNAL "")
++SET(HAVE_VALLOC CACHE INTERNAL "")
++SET(HAVE_VARARGS_H 1 CACHE INTERNAL "")
++SET(HAVE_VASPRINTF CACHE INTERNAL "")
++SET(HAVE_VPRINTF 1 CACHE INTERNAL "")
++IF(MSVC_VERSION GREATER 1310)
++SET(HAVE_VSNPRINTF 1 CACHE INTERNAL "")
++ENDIF()
++SET(HAVE_WEAK_SYMBOL CACHE INTERNAL "")
++SET(HAVE_WORDS_BIGENDIAN TRUE CACHE INTERNAL "")
++SET(WORDS_BIGENDIAN CACHE INTERNAL "")
++SET(HAVE__S_IFIFO 1 CACHE INTERNAL "")
++SET(HAVE__S_IREAD 1 CACHE INTERNAL "")
++SET(HAVE__finite 1 CACHE INTERNAL "")
++SET(HAVE__isnan 1 CACHE INTERNAL "")
++SET(HAVE__pclose 1 CACHE INTERNAL "")
++SET(HAVE__popen 1 CACHE INTERNAL "")
++SET(HAVE__snprintf 1 CACHE INTERNAL "")
++SET(HAVE__stricmp 1 CACHE INTERNAL "")
++SET(HAVE__strnicmp 1 CACHE INTERNAL "")
++SET(HAVE__strtoi64 1 CACHE INTERNAL "")
++SET(HAVE__strtoui64 1 CACHE INTERNAL "")
++IF(MSVC_VERSION GREATER 1310)
++ SET(HAVE_strtok_s 1 CACHE INTERNAL "")
++ENDIF()
++SET(STDC_HEADERS CACHE 1 INTERNAL "")
++SET(STRUCT_DIRENT_HAS_D_INO CACHE INTERNAL "")
++SET(STRUCT_DIRENT_HAS_D_INO CACHE INTERNAL "")
++SET(STRUCT_DIRENT_HAS_D_NAMLEN CACHE INTERNAL "")
++SET(TIME_WITH_SYS_TIME CACHE INTERNAL "")
++SET(TIME_T_UNSIGNED 1 CACHE INTERNAL "")
++SET(TIOCSTAT_IN_SYS_IOCTL CACHE INTERNAL "")
++SET(HAVE_S_IROTH CACHE INTERNAL "")
++SET(HAVE_S_IFIFO CACHE INTERNAL "")
++SET(QSORT_TYPE_IS_VOID 1 CACHE INTERNAL "")
++SET(SIGNAL_RETURN_TYPE_IS_VOID 1 CACHE INTERNAL "")
++SET(C_HAS_inline CACHE INTERNAL "")
++SET(C_HAS___inline 1 CACHE INTERNAL "")
++SET(FIONREAD_IN_SYS_IOCTL CACHE INTERNAL "")
++SET(FIONREAD_IN_SYS_FILIO CACHE INTERNAL "")
++SET(GWINSZ_IN_SYS_IOCTL CACHE INTERNAL "")
++SET(HAVE_CXXABI_H CACHE INTERNAL "")
++SET(HAVE_NDIR_H CACHE INTERNAL "")
++SET(HAVE_SYS_NDIR_H CACHE INTERNAL "")
++SET(HAVE_SYS_NDIR_H CACHE INTERNAL "")
++SET(HAVE_ASM_TERMBITS_H CACHE INTERNAL "")
++SET(HAVE_TERMBITS_H CACHE INTERNAL "")
++SET(HAVE_VIS_H CACHE INTERNAL "")
++SET(HAVE_WCHAR_H 1 CACHE INTERNAL "")
++SET(HAVE_WCTYPE_H 1 CACHE INTERNAL "")
++SET(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP CACHE INTERNAL "")
++SET(HAVE_SOCKADDR_IN_SIN_LEN CACHE INTERNAL "")
++SET(HAVE_SOCKADDR_IN6_SIN6_LEN CACHE INTERNAL "")
++SET(HAVE_VALGRIND CACHE INTERNAL "")
++SET(HAVE_EVENT_H CACHE INTERNAL "")
++SET(HAVE_LINUX_UNISTD_H CACHE INTERNAL "")
++SET(HAVE_SYS_UTSNAME_H CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_GETGUARDSIZE CACHE INTERNAL "")
++SET(FIONREAD_IN_SYS_FILIO CACHE INTERNAL "")
++SET(FIONREAD_IN_SYS_IOCTL CACHE INTERNAL "")
++SET(GWINSZ_IN_SYS_IOCTL CACHE INTERNAL "")
++SET(HAVE_ACCESS 1 CACHE INTERNAL "")
++SET(HAVE_AIOWAIT CACHE INTERNAL "")
++SET(HAVE_AIO_H CACHE INTERNAL "")
++SET(HAVE_AIO_READ CACHE INTERNAL "")
++SET(HAVE_ALARM CACHE INTERNAL "")
++SET(HAVE_ALLOCA CACHE INTERNAL "")
++SET(HAVE_ALLOCA_H CACHE INTERNAL "")
++SET(HAVE_ARPA_INET_H CACHE INTERNAL "")
++SET(HAVE_ASM_MSR_H CACHE INTERNAL "")
++SET(HAVE_ASM_TERMBITS_H CACHE INTERNAL "")
++SET(HAVE_BACKTRACE CACHE INTERNAL "")
++SET(HAVE_BACKTRACE_SYMBOLS CACHE INTERNAL "")
++SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE INTERNAL "")
++SET(HAVE_BCMP CACHE INTERNAL "")
++SET(HAVE_BFILL CACHE INTERNAL "")
++SET(HAVE_BMOVE CACHE INTERNAL "")
++SET(HAVE_BSD_SIGNALS CACHE INTERNAL "")
++SET(HAVE_BSEARCH CACHE INTERNAL "")
++SET(HAVE_BSS_START CACHE INTENAL "")
++SET(HAVE_BZERO CACHE INTERNAL "")
++SET(HAVE_CHOWN CACHE INTERNAL "")
++SET(HAVE_CLOCK_GETTIME CACHE INTERNAL "")
++SET(HAVE_COMPRESS CACHE INTERNAL "")
++SET(HAVE_CRYPT CACHE INTERNAL "")
++SET(HAVE_CRYPT_H CACHE INTERNAL "")
++SET(HAVE_CUSERID CACHE INTERNAL "")
++SET(HAVE_CXXABI_H CACHE INTERNAL "")
++SET(HAVE_CXX_NEW CACHE INTERNAL "")
++SET(HAVE_DECL_FDATASYNC CACHE INTERNAL "")
++SET(HAVE_SIGNAL_H 1 CACHE INTERNAL "")
++SET(HAVE_GETHOSTBYNAME_R CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_SETPRIO CACHE INTERNAL "")
++SET(HAVE_PTHREAD_ATTR_SETSCHEDPARAM CACHE INTERNAL "")
++SET(HAVE_PTHREAD_KILL CACHE INTERNAL "")
++SET(HAVE_PTHREAD_SETPRIO_NP CACHE INTERNAL "")
++SET(HAVE_PTHREAD_SETSCHEDPARAM CACHE INTERNAL "")
++SET(HAVE_SETFILEPOINTER CACHE INTERNAL "")
++SET(SIZEOF_U_INT32_T CACHE INTERNAL "")
++SET(IS_VOID_SIGNAL 1 CACHE INTERNAL "")
++SET(IS_VOID_QSORT 1 CACHE INTERNAL "")
++ENDIF()
+diff -x .bzr -u --recursive -N mariadb-native-client.release/CMakeLists.txt mariadb-native-client.trunk/CMakeLists.txt
+--- mariadb/CMakeLists.txt 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -1,26 +1,68 @@
# CMakeLists.txt
@@ -11,8 +784,10 @@
SET(CPACK_PACKAGE_VERSION_MAJOR 1)
-SET(CPACK_PACKAGE_VERSION_MINOR 0)
+-SET(CPACK_PACKAGE_VERSION_PATCH 0)
+SET(CPACK_PACKAGE_VERSION_MINOR 1)
- SET(CPACK_PACKAGE_VERSION_PATCH 0)
++SET(CPACK_PACKAGE_VERSION_PATCH 2)
++SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-# Minimum required version is Cmake 2.6.x
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
@@ -26,37 +801,58 @@
+### Options ###
+IF(NOT WIN32)
+ OPTION(WITH_MYSQLCOMPAT "creates libmysql* symbolic links" ON)
++ OPTION(WITH_OPENSSL "enables SSL support" ON)
++ELSE()
++ OPTION(WITH_OPENSSL "enables SSL support" OFF)
+ENDIF()
+
-+OPTION(WITH_SQLITE "Enables Sqlite support" ON)
++OPTION(WITH_SQLITE "Enables Sqlite support" OFF)
++OPTION(WITH_EXTERNAL_ZLIB "Enables use of external zlib" OFF)
+###############
+
IF(WIN32)
# Speedup system tests
- INCLUDE(${CMAKE_SOURCE_DIR}/WindowsCache.cmake)
+-ENDIF()
+ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/WindowsCache.cmake)
+ IF (MSVC)
-+ FOREACH(flag_var
-+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
-+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
-+ IF(${flag_var} MATCHES "/MD")
-+ STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
-+ ENDIF()
-+ ENDFOREACH(flag_var)
++ SET(CONFIG_TYPES "DEBUG" "RELEASE" "RELWITHDEBINFO")
++ FOREACH(BUILD_TYPE ${CONFIG_TYPES})
++ FOREACH(COMPILER CXX C)
++ SET(COMPILER_FLAGS "${CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE}}")
++ IF (NOT COMPILER_FLAGS STREQUAL "")
++ STRING(REPLACE "/MD" "/MT" COMPILER_FLAGS ${COMPILER_FLAGS})
++ IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
++ SET(COMPILER_FLAGS "${COMPILER_FLAGS} /RTC1 /RTCc")
++ STRING(REPLACE "/Zi" "/ZI" COMPILER_FLAGS ${COMPILER_FLAGS})
++ ENDIF()
++ MESSAGE (STATUS "CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE}= ${COMPILER_FLAGS}")
++ SET(CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE} ${COMPILER_FLAGS} CACHE
++ STRING "overwritten by libmariadb" FORCE)
++ ENDIF()
++ ENDFOREACH()
++ ENDFOREACH()
+ ENDIF()
- ENDIF()
++ENDIF()
++
++# Disable dbug information for release builds
++SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DDBUG_OFF")
++SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDBUG_OFF")
++SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DDBUG_OFF")
++SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDBUG_OFF")
IF(UNIX)
- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
- ENDIF()
-
-+IF(CMAKE_COMPILER_IS_GNUCC)
-+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wno-uninitialized")
+- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
++ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFE_MUTEX")
+ENDIF()
+
++IF(CMAKE_COMPILER_IS_GNUCC)
++ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wno-uninitialized")
+ ENDIF()
+
# If the build type isn't specified, set to Relwithdebinfo as default.
- IF(NOT CMAKE_BUILD_TYPE)
+@@ -28,33 +70,59 @@
SET(CMAKE_BUILD_TYPE "Relwithdebinfo")
ENDIF()
@@ -65,8 +861,13 @@
+
SET(PROTOCOL_VERSION 10) # we adapted new password option from PHP's mysqlnd !
SET(MYSQL_CLIENT_VERSION_MAJOR "5")
- SET(MYSQL_CLIENT_VERSION_MINOR "3")
-@@ -40,14 +62,15 @@
+-SET(MYSQL_CLIENT_VERSION_MINOR "3")
+-SET(MYSQL_CLIENT_VERSION_PATCH "2")
++SET(MYSQL_CLIENT_VERSION_MINOR "5")
++SET(MYSQL_CLIENT_VERSION_PATCH "0")
+ SET(MYSQL_CLIENT_VERSION "${MYSQL_CLIENT_VERSION_MAJOR}.${MYSQL_CLIENT_VERSION_MINOR}.${MYSQL_CLIENT_VERSION_PATCH}")
+ MATH(EXPR MYSQL_VERSION_ID "${MYSQL_CLIENT_VERSION_MAJOR} * 10000 +
+ ${MYSQL_CLIENT_VERSION_MINOR} * 100 +
${MYSQL_CLIENT_VERSION_PATCH}")
IF (NOT MYSQL_PORT)
SET(MYSQL_PORT 3306)
@@ -81,12 +882,54 @@
SET(SHAREDIR "share")
SET(DEFAULT_CHARSET_HOME "${CMAKE_INSTALL_PREFIX}")
+SET(PLUGINDIR "${CMAKE_INSTALL_PREFIX}/lib/plugin")
++
++INCLUDE(cmake/SearchLibrary.cmake)
++
++IF(WITH_EXTERNAL_ZLIB)
++ FIND_PACKAGE(ZLIB QUIET)
++ IF(${ZLIB_FOUND})
++ SET(LIBZ "-lz")
++ ENDIF()
++ENDIF()
++
++IF(UNIX)
++ SEARCH_LIBRARY(LIBNSL inet_ntoa "nsl_r;nsl")
++ SEARCH_LIBRARY(LIBBIND bind "bind;socket")
++ SEARCH_LIBRARY(LIBSOCKET setsockopt "socket")
++ SEARCH_LIBRARY(LIBDL dlopen "dl")
++ SEARCH_LIBRARY(LIBM floor m)
++ SET(EXTRA_LIBS "${LIBNSL}" "${LIBBIND}" "${LIBSOCKET}" "${LIBDL}" "${LIBM}" "${LIBZ}")
++ FIND_PACKAGE(Threads)
++ SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LIBNSL} ${LIBBIND}
++ ${LIBSOCKET} ${LIBDL} ${LIBM} ${CMAKE_THREAD_LIBS_INIT})
++ #remove possible dups from required libraries
++ LIST(LENGTH CMAKE_REQUIRED_LIBRARIES rllength)
++ IF(${rllength} GREATER 0)
++ LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
++ ENDIF()
++ENDIF()
- FIND_PACKAGE(Threads)
+-FIND_PACKAGE(Threads)
-@@ -72,13 +95,11 @@
+ IF(CMAKE_HAVE_PTHREAD_H)
+ SET(CMAKE_REQUIRED_INCLUDES pthread.h)
+ ENDIF()
+-#Check for threads
++
+ IF(WIN32)
+ SET(HAVE_THREADS 1)
+ ADD_DEFINITIONS(-DHAVE_DLOPEN)
+@@ -64,29 +132,28 @@
+ SET(HAVE_THREADS ${CMAKE_USE_PTHREADS})
ENDIF()
+-IF(UNIX)
+-FIND_LIBRARY(DL_LIBRARY dl)
+-IF(DL_LIBRARY)
+- SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${CMAKE_DL_LIBS})
+-ENDIF()
+-ENDIF()
+-
# check for various include files
-INCLUDE(LibmysqlIncludeFiles.cmake)
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckIncludeFiles.cmake)
@@ -100,26 +943,36 @@
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckTypes.cmake)
# Check for OpenSSL
- FIND_PACKAGE(OpenSSL)
-@@ -88,6 +109,10 @@
-
- FIND_PACKAGE(ZLIB QUIET)
-
+-FIND_PACKAGE(OpenSSL)
+-IF(OPENSSL_FOUND)
+- ADD_DEFINITIONS(-DHAVE_OPENSSL)
++IF(WITH_OPENSSL)
++ FIND_PACKAGE(OpenSSL)
++ IF(OPENSSL_FOUND)
++ ADD_DEFINITIONS(-DHAVE_OPENSSL)
++ ENDIF()
++ENDIF()
++
+IF(WITH_SQLITE)
+ ADD_DEFINITIONS(-DHAVE_SQLITE)
+ ENDIF()
+
+-FIND_PACKAGE(ZLIB QUIET)
++IF(NOT WIN32)
++ INCLUDE(cmake/FindIconv.cmake)
+ENDIF()
-+
+
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/mysql_version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/mysql_version.h)
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/my_config.h.in
-@@ -95,15 +120,16 @@
+@@ -95,15 +162,16 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include)
-ADD_SUBDIRECTORY(libmysql)
+-ADD_SUBDIRECTORY(examples)
++ADD_SUBDIRECTORY(include)
+ADD_SUBDIRECTORY(plugins)
+ADD_SUBDIRECTORY(libmariadb)
- ADD_SUBDIRECTORY(examples)
IF(NOT WIN32)
- ADD_SUBDIRECTORY(mysql_config)
+ ADD_SUBDIRECTORY(mariadb_config)
@@ -132,37 +985,28 @@
ENDIF()
IF(BUILD_DOCS)
-
-=== modified file 'README'
---- mariadb/README 2012-11-26 10:23:56 +0000
-+++ mariadb/README 2013-03-14 21:01:43 +0000
-@@ -4,10 +4,15 @@
- This code is based on the LGPL libmysql client library from MySQL 3.23
- and PHP's mysqlnd extension.
+@@ -115,14 +183,16 @@
+ SET(CMAKE_INSTALL_PREFIX "")
+ ENDIF()
-+This product includes PHP software, freely available from
-+<http://www.php.net/software/>
-+
- The following are the main known limitations:
+-
++IF(WIN32)
++ ADD_SUBDIRECTORY(win/packaging)
++ENDIF()
-- - float to string conversion for prepared statements
-- doesn't work correctly
-+- double to string conversion for prepared statements
-+ doesn't work correctly
-+- support for dynamic columns is not integrated yet
-+- Asynchronus interface is not integrated yet
+ SET(CPACK_PACKAGE_VENDOR "Monty Program AB")
+ SET(CPACK_PACKAGE_DESCRIPTION "MariaDB client library. A library for connecting to MariaDB and MySQL servers")
+ SET(CPACK_PACKAGE_NAME "mariadb_client")
+ SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING.LIB")
+ SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
+-SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${MYSQL_CLIENT_VERSION}-src")
++SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-src")
- If you want to be part of this development effort, you can discuss this at
- maria-developers@lists.launchpad.org.
-
-=== added directory 'cmake'
-=== renamed file 'LibmysqlFunctions.cmake' => 'cmake/CheckFunctions.cmake'
-=== renamed file 'LibmysqlIncludeFiles.cmake' => 'cmake/CheckIncludeFiles.cmake'
-=== renamed file 'LibmysqlTypes.cmake' => 'cmake/CheckTypes.cmake'
-=== renamed file 'WindowsCache.cmake' => 'cmake/WindowsCache.cmake'
-=== modified file 'docs/funcref/functions.ent'
---- mariadb/docs/funcref/functions.ent 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/funcref/functions.ent 2013-03-14 21:01:43 +0000
+ SET(CPACK_SOURCE_IGNORE_FILES
+ .bzr/
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/functions.ent mariadb-native-client.trunk/docs/funcref/functions.ent
+--- mariadb/docs/funcref/functions.ent 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/funcref/functions.ent 2013-10-19 07:29:16.000000000 +0200
@@ -1,97 +1,97 @@
-<!ENTITY myodbc_remove_escape "funcref/myodbc_remove_escape.xml">
-<!ENTITY mysql_affected_rows "funcref/mysql_affected_rows.xml">
@@ -359,10 +1203,9 @@
+<!ENTITY functions.mysql_thread_safe "funcref/mysql_thread_safe.xml">
+<!ENTITY functions.mysql_use_result "funcref/mysql_use_result.xml">
+<!ENTITY functions.mysql_warning_count "funcref/mysql_warning_count.xml">
-
-=== removed file 'docs/funcref/myodbc_remove_escape.xml'
---- mariadb/docs/funcref/myodbc_remove_escape.xml 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/funcref/myodbc_remove_escape.xml 1970-01-01 00:00:00 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/myodbc_remove_escape.xml mariadb-native-client.trunk/docs/funcref/myodbc_remove_escape.xml
+--- mariadb/docs/funcref/myodbc_remove_escape.xml 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/funcref/myodbc_remove_escape.xml 1970-01-01 01:00:00.000000000 +0100
@@ -1,40 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
- <refentry id="functions.myodbc_remove_escape" display-name="0">
@@ -404,10 +1247,9 @@
- <title>See also</title>
- </refsect1>
- </refentry>
-
-=== modified file 'docs/funcref/mysql_commit.xml'
---- mariadb/docs/funcref/mysql_commit.xml 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/funcref/mysql_commit.xml 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/mysql_commit.xml mariadb-native-client.trunk/docs/funcref/mysql_commit.xml
+--- mariadb/docs/funcref/mysql_commit.xml 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/funcref/mysql_commit.xml 2013-10-19 07:29:16.000000000 +0200
@@ -39,6 +39,6 @@
</refsect1>
<refsect1 role="seealso">
@@ -416,10 +1258,9 @@
+ <para><function>mysql_rollback</function></para>
</refsect1>
</refentry>
-
-=== added file 'docs/funcref/mysql_get_server_name.xml'
---- mariadb/docs/funcref/mysql_get_server_name.xml 1970-01-01 00:00:00 +0000
-+++ mariadb/docs/funcref/mysql_get_server_name.xml 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/mysql_get_server_name.xml mariadb-native-client.trunk/docs/funcref/mysql_get_server_name.xml
+--- mariadb/docs/funcref/mysql_get_server_name.xml 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/docs/funcref/mysql_get_server_name.xml 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
@@ -465,10 +1306,9 @@
+ <para><function>mysql_options()</function>, <function>mysql_real_connect()</function></para>
+ </refsect1>
+ </refentry>
-
-=== modified file 'docs/funcref/mysql_options.xml'
---- mariadb/docs/funcref/mysql_options.xml 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/funcref/mysql_options.xml 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/mysql_options.xml mariadb-native-client.trunk/docs/funcref/mysql_options.xml
+--- mariadb/docs/funcref/mysql_options.xml 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/funcref/mysql_options.xml 2013-10-19 07:29:16.000000000 +0200
@@ -202,6 +202,19 @@
</informalexample>
</listitem>
@@ -489,10 +1329,9 @@
</variablelist>
</listitem></varlistentry>
<varlistentry><term><parameter>arg</parameter></term><listitem><para>The value for the option</para></listitem></varlistentry>
-
-=== modified file 'docs/funcref/mysql_real_escape_string.xml'
---- mariadb/docs/funcref/mysql_real_escape_string.xml 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/funcref/mysql_real_escape_string.xml 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/funcref/mysql_real_escape_string.xml mariadb-native-client.trunk/docs/funcref/mysql_real_escape_string.xml
+--- mariadb/docs/funcref/mysql_real_escape_string.xml 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/funcref/mysql_real_escape_string.xml 2013-10-19 07:29:16.000000000 +0200
@@ -19,7 +19,7 @@
<methodparam><type>MYSQL *</type><parameter>mysql</parameter></methodparam>
<methodparam><type>char *</type><parameter>to</parameter></methodparam>
@@ -527,10 +1366,9 @@
<refsect1 role="seealso">
<title>See also</title>
</refsect1>
-
-=== modified file 'docs/mariadb-client.xml'
---- mariadb/docs/mariadb-client.xml 2012-11-26 10:23:56 +0000
-+++ mariadb/docs/mariadb-client.xml 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/docs/mariadb-client.xml mariadb-native-client.trunk/docs/mariadb-client.xml
+--- mariadb/docs/mariadb-client.xml 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/docs/mariadb-client.xml 2013-10-19 07:29:16.000000000 +0200
@@ -3,7 +3,6 @@
"docbook/dtd/xml/4.2/docbookx.dtd" [
<!ENTITY % global_ents SYSTEM "global.ent">
@@ -569,10 +1407,48 @@
<xi:include href="&mysql_get_server_version;" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="&mysql_get_ssl_cipher;" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="&mysql_hex_string;" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-
-=== modified file 'include/config-win.h'
---- mariadb/include/config-win.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/config-win.h 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/CMakeLists.txt mariadb-native-client.trunk/include/CMakeLists.txt
+--- mariadb/include/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/include/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,35 @@
++SET(MARIADB_CLIENT_INCLUDES config-win.h
++ dbug.h
++ errmsg.h
++ getopt.h
++ global.h
++ hash.h
++ ma_common.h
++ m_ctype.h
++ m_string.h
++ ma_dyncol.h
++ ma_secure.h
++ my_alarm.h
++ my_base.h
++ my_config.h
++ my_dir.h
++ my_global.h
++ my_list.h
++ my_net.h
++ my_no_pthread.h
++ my_pthread.h
++ my_stmt.h
++ my_sys.h
++ mysql.h
++ mysql_com.h
++ mysql_io.h
++ mysql_mm.h
++ mysql_priv.h
++ mysql_version.h
++ mysql_wireprotocol.h
++ mysqld_error.h
++ mysys_err.h
++ sha1.h
++ thr_alarm.h
++ violite.h
++ PARENT_SCOPE)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/config-win.h mariadb-native-client.trunk/include/config-win.h
+--- mariadb/include/config-win.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/config-win.h 2013-10-19 07:29:16.000000000 +0200
@@ -111,7 +111,7 @@
#define bool_defined
#define byte_defined
@@ -582,22 +1458,622 @@
#define VOID_SIGHANDLER
#define SIZEOF_CHAR 1
-
-=== modified file 'include/errmsg.h'
---- mariadb/include/errmsg.h 2012-11-26 07:32:41 +0000
-+++ mariadb/include/errmsg.h 2013-03-14 21:01:43 +0000
-@@ -71,5 +71,6 @@
+@@ -213,9 +213,9 @@
+ #define HAVE_STRPBRK
+ #define HAVE_STRSTR
+
+-#ifdef NOT_USED
++#ifdef WIN32
+ #define HAVE_SNPRINTF /* Gave link error */
+-#define _snprintf snprintf
++#define snprintf _snprintf
+ #endif
+
+ #ifdef _MSC_VER
+@@ -264,4 +264,9 @@
+ #define statistic_increment(V,L) thread_safe_increment((V),(L))
+ #define strcasecmp(A,B) _stricmp((A),(B))
+
++#define close(A) _close((A))
++#define fdopen(A,B) _fdopen((A),(B))
++#define sopen(A,B,C,D) _sopen((A),(B),(C),(D))
++
++
+ #endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/dbug.h mariadb-native-client.trunk/include/dbug.h
+--- mariadb/include/dbug.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/dbug.h 2013-10-19 07:29:16.000000000 +0200
+@@ -21,34 +21,48 @@
+ extern "C" {
+ #endif
+ #if !defined(DBUG_OFF) && !defined(_lint)
+-extern int _db_on_,_no_db_;
+-extern FILE *_db_fp_;
+-extern char *_db_process_;
+-extern int _db_keyword_(const char *keyword);
+-extern void _db_setjmp_(void);
+-extern void _db_longjmp_(void);
+-extern void _db_push_(const char *control);
+-extern void _db_pop_(void);
+-extern void _db_enter_(const char *_func_,const char *_file_,uint _line_,
+- const char **_sfunc_,const char **_sfile_,
+- uint *_slevel_, char ***);
+-extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_,
+- uint *_slevel_);
+-extern void _db_pargs_(uint _line_,const char *keyword);
+-extern void _db_doprnt_ _VARARGS((const char *format,...));
+-extern void _db_dump_(uint _line_,const char *keyword,const char *memory,
+- uint length);
+-extern void _db_lock_file();
+-extern void _db_unlock_file();
+
+-#define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \
+- char **_db_framep_; \
+- _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
+- &_db_framep_)
++struct _db_stack_frame_ {
++ const char *func; /* function name of the previous stack frame */
++ const char *file; /* filename of the function of previous frame */
++ uint level; /* this nesting level, highest bit enables tracing */
++ struct _db_stack_frame_ *prev; /* pointer to the previous frame */
++};
++
++struct _db_code_state_;
++extern my_bool _dbug_on_;
++extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
++extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
++extern int _db_explain_init_(char *buf, size_t len);
++extern int _db_is_pushed_(void);
++extern void _db_setjmp_(void);
++extern void _db_longjmp_(void);
++extern void _db_process_(const char *name);
++extern void _db_push_(const char *control);
++extern void _db_pop_(void);
++extern void _db_set_(const char *control);
++extern void _db_set_init_(const char *control);
++extern void _db_enter_(const char *_func_, const char *_file_, uint _line_,
++ struct _db_stack_frame_ *_stack_frame_);
++extern void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_);
++extern void _db_pargs_(uint _line_,const char *keyword);
++extern void _db_doprnt_ _VARARGS((const char *format,...));
++extern void _db_dump_(uint _line_,const char *keyword,
++ const unsigned char *memory, size_t length);
++extern void _db_end_(void);
++extern void _db_lock_file_(void);
++extern void _db_unlock_file_(void);
++extern FILE *_db_fp_(void);
++extern void _db_flush_();
++extern const char* _db_get_func_(void);
++/*
++#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
++ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
+ #define DBUG_LEAVE \
+ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
+-#define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);}
++#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0)
+ #define DBUG_VOID_RETURN {DBUG_LEAVE; return;}
++#define DBUG_END() _db_end_ ()
+ #define DBUG_EXECUTE(keyword,a1) \
+ {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
+ #define DBUG_PRINT(keyword,arglist) \
+@@ -66,10 +80,49 @@
+ #define DEBUGGER_ON _no_db_=0
+ #define DBUG_LOCK_FILE { _db_lock_file(); }
+ #define DBUG_UNLOCK_FILE { _db_unlock_file(); }
++#define DBUG_ASSERT(A) assert(A) */
++#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
++ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
++#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_)
++#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0)
++#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0)
++#define DBUG_EXECUTE(keyword,a1) \
++ do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0)
++#define DBUG_EXECUTE_IF(keyword,a1) \
++ do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0)
++#define DBUG_EVALUATE(keyword,a1,a2) \
++ (_db_keyword_(0,(keyword), 0) ? (a1) : (a2))
++#define DBUG_EVALUATE_IF(keyword,a1,a2) \
++ (_db_keyword_(0,(keyword), 1) ? (a1) : (a2))
++#define DBUG_PRINT(keyword,arglist) \
++ do {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;} while(0)
++#define DBUG_PUSH(a1) _db_push_ (a1)
++#define DBUG_POP() _db_pop_ ()
++#define DBUG_SET(a1) _db_set_ (a1)
++#define DBUG_SET_INITIAL(a1) _db_set_init_ (a1)
++#define DBUG_PROCESS(a1) _db_process_(a1)
++#define DBUG_FILE _db_fp_()
++#define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
++#define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
++#define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2)
++#define DBUG_END() _db_end_ ()
++#define DBUG_LOCK_FILE _db_lock_file_()
++#define DBUG_UNLOCK_FILE _db_unlock_file_()
+ #define DBUG_ASSERT(A) assert(A)
++#define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len))
++#define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len))
++#define DEBUGGER_OFF do { _dbug_on_= 0; } while(0)
++#define DEBUGGER_ON do { _dbug_on_= 1; } while(0)
++#ifndef _WIN32
++#define DBUG_ABORT() (_db_flush_(), abort())
++#else
++#define DBUG_ABORT() (_db_flush_(), exit(3))
++#endif
++
+ #else /* No debugger */
+
+ #define DBUG_ENTER(a1)
++#define DBUG_END() {}
+ #define DBUG_RETURN(a1) return(a1)
+ #define DBUG_VOID_RETURN return
+ #define DBUG_EXECUTE(keyword,a1) {}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/errmsg.h mariadb-native-client.trunk/include/errmsg.h
+--- mariadb/include/errmsg.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/errmsg.h 2013-10-19 07:29:16.000000000 +0200
+@@ -17,6 +17,8 @@
+
+ /* Error messages for mysql clients */
+ /* error messages for the demon is in share/language/errmsg.sys */
++#ifndef _errmsg_h_
++#define _errmsg_h_
+
+ #ifdef __cplusplus
+ extern "C" {
+@@ -71,5 +73,8 @@
#define CR_NEW_STMT_METADATA 2057
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2058
#define CR_ALREADY_CONNECTED 2059
+#define CR_PLUGIN_FUNCTION_NOT_SUPPORTED 2060
#define SQLSTATE_UNKNOWN "HY000"
-
-=== modified file 'include/m_ctype.h'
---- mariadb/include/m_ctype.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/m_ctype.h 2013-03-14 21:01:43 +0000
-@@ -32,6 +32,8 @@
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/global.h mariadb-native-client.trunk/include/global.h
+--- mariadb/include/global.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/global.h 2013-10-19 07:29:16.000000000 +0200
+@@ -402,11 +402,7 @@
+ #define IO_SIZE 4096
+ /* How much overhead does malloc have. The code often allocates
+ something like 1024-MALLOC_OVERHEAD bytes */
+-#ifdef SAFEMALLOC
+-#define MALLOC_OVERHEAD (8+24+4)
+-#else
+ #define MALLOC_OVERHEAD 8
+-#endif
+ /* get memory in huncs */
+ #define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD)
+ /* Typical record cash */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/hash.h mariadb-native-client.trunk/include/hash.h
+--- mariadb/include/hash.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/hash.h 2013-10-19 07:29:16.000000000 +0200
+@@ -1,4 +1,6 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++/************************************************************************************
++ Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
++ Monty Program AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+@@ -11,11 +13,13 @@
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Dynamic hashing of record with different key-length */
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*************************************************************************************/
+
+ #ifndef _hash_h
+ #define _hash_h
+@@ -23,7 +27,7 @@
+ extern "C" {
+ #endif
+
+-typedef byte *(*hash_get_key)(const byte *,uint*,my_bool);
++typedef uchar *(*hash_get_key)(const uchar *,uint*,my_bool);
+ typedef void (*hash_free_key)(void *);
+
+ /* flags for hash_init */
+@@ -31,7 +35,7 @@
+
+ typedef struct st_hash_info {
+ uint next; /* index to next key */
+- byte *data; /* data for current entry */
++ uchar *data; /* data for current entry */
+ } HASH_LINK;
+
+ typedef struct st_hash {
+@@ -41,7 +45,7 @@
+ DYNAMIC_ARRAY array; /* Place for hash_keys */
+ hash_get_key get_key;
+ void (*free)(void *);
+- uint (*calc_hashnr)(const byte *key,uint length);
++ uint (*calc_hashnr)(const uchar *key,uint length);
+ } HASH;
+
+ #define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G CALLER_INFO)
+@@ -49,12 +53,12 @@
+ uint key_length, hash_get_key get_key,
+ void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
+ void hash_free(HASH *tree);
+-byte *hash_element(HASH *hash,uint idx);
+-gptr hash_search(HASH *info,const byte *key,uint length);
+-gptr hash_next(HASH *info,const byte *key,uint length);
+-my_bool hash_insert(HASH *info,const byte *data);
+-my_bool hash_delete(HASH *hash,byte *record);
+-my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
++uchar *hash_element(HASH *hash,uint idx);
++gptr hash_search(HASH *info,const uchar *key,uint length);
++gptr hash_next(HASH *info,const uchar *key,uint length);
++my_bool hash_insert(HASH *info,const uchar *data);
++my_bool hash_delete(HASH *hash,uchar *record);
++my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,uint old_key_length);
+ my_bool hash_check(HASH *hash); /* Only in debug library */
+
+ #define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/ma_common.h mariadb-native-client.trunk/include/ma_common.h
+--- mariadb/include/ma_common.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/include/ma_common.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,52 @@
++/* Copyright (C) 2013 by MontyProgram AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* defines for the libmariadb library */
++
++#ifndef _ma_common_h
++#define _ma_common_h
++
++#include <mysql.h>
++#include <hash.h>
++
++
++typedef struct st_mariadb_db_driver
++{
++ struct st_mariadb_client_plugin_DB *plugin;
++ char *name;
++ void *buffer;
++} MARIADB_DB_DRIVER;
++
++struct st_mysql_options_extention {
++ char *plugin_dir;
++ char *default_auth;
++ char *ssl_crl;
++ char *ssl_crlpath;
++ char *server_public_key_path;
++ HASH connect_attrs;
++ size_t connect_attrs_len;
++ void (*report_progress)(const MYSQL *mysql,
++ unsigned int stage,
++ unsigned int max_stage,
++ double progress,
++ const char *proc_info,
++ unsigned int proc_info_length);
++ MARIADB_DB_DRIVER *db_driver;
++};
++
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/ma_dyncol.h mariadb-native-client.trunk/include/ma_dyncol.h
+--- mariadb/include/ma_dyncol.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/include/ma_dyncol.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,244 @@
++/* Copyright (c) 2011, Monty Program Ab
++ Copyright (c) 2011, Oleksandr Byelkin
++
++ Redistribution and use in source and binary forms, with or without
++ modification, are permitted provided that the following conditions are
++ met:
++
++ 1. Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++
++ 2. Redistributions in binary form must the following disclaimer in
++ the documentation and/or other materials provided with the
++ distribution.
++
++ THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
++ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
++ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ SUCH DAMAGE.
++*/
++
++#ifndef ma_dyncol_h
++#define ma_dyncol_h
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifndef LIBMARIADB
++#include <decimal.h>
++#include <my_decimal_limits.h>
++#endif
++#include <mysql.h>
++
++#ifndef _my_sys_h
++typedef struct st_dynamic_string
++{
++ char *str;
++ size_t length,max_length,alloc_increment;
++} DYNAMIC_STRING;
++#endif
++
++struct st_mysql_lex_string
++{
++ char *str;
++ size_t length;
++};
++typedef struct st_mysql_lex_string MYSQL_LEX_STRING;
++typedef struct st_mysql_lex_string LEX_STRING;
++/*
++ Limits of implementation
++*/
++#define MAX_TOTAL_NAME_LENGTH 65535
++#define MAX_NAME_LENGTH (MAX_TOTAL_NAME_LENGTH/4)
++
++/* NO and OK is the same used just to show semantics */
++#define ER_DYNCOL_NO ER_DYNCOL_OK
++
++enum enum_dyncol_func_result
++{
++ ER_DYNCOL_OK= 0,
++ ER_DYNCOL_YES= 1, /* For functions returning 0/1 */
++ ER_DYNCOL_FORMAT= -1, /* Wrong format of the encoded string */
++ ER_DYNCOL_LIMIT= -2, /* Some limit reached */
++ ER_DYNCOL_RESOURCE= -3, /* Out of resourses */
++ ER_DYNCOL_DATA= -4, /* Incorrect input data */
++ ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */
++ ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */
++};
++
++typedef DYNAMIC_STRING DYNAMIC_COLUMN;
++
++enum enum_dynamic_column_type
++{
++ DYN_COL_NULL= 0,
++ DYN_COL_INT,
++ DYN_COL_UINT,
++ DYN_COL_DOUBLE,
++ DYN_COL_STRING,
++ DYN_COL_DECIMAL,
++ DYN_COL_DATETIME,
++ DYN_COL_DATE,
++ DYN_COL_TIME,
++ DYN_COL_DYNCOL
++};
++
++typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE;
++
++struct st_dynamic_column_value
++{
++ DYNAMIC_COLUMN_TYPE type;
++ union
++ {
++ long long long_value;
++ unsigned long long ulong_value;
++ double double_value;
++ struct {
++ MYSQL_LEX_STRING value;
++ CHARSET_INFO *charset;
++ } string;
++#ifndef LIBMARIADB
++ struct {
++ decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
++ decimal_t value;
++ } decimal;
++#endif
++ MYSQL_TIME time_value;
++ } x;
++};
++
++typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
++
++#ifdef MADYNCOL_DEPRECATED
++enum enum_dyncol_func_result
++dynamic_column_create(DYNAMIC_COLUMN *str,
++ uint column_nr, DYNAMIC_COLUMN_VALUE *value);
++
++enum enum_dyncol_func_result
++dynamic_column_create_many(DYNAMIC_COLUMN *str,
++ uint column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values);
++enum enum_dyncol_func_result
++dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *value);
++enum enum_dyncol_func_result
++dynamic_column_update_many(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values);
++
++enum enum_dyncol_func_result
++dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr);
++
++enum enum_dyncol_func_result
++dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint);
++
++enum enum_dyncol_func_result
++dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *store_it_here);
++#endif
++
++/* new functions */
++enum enum_dyncol_func_result
++mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str,
++ uint column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_string);
++enum enum_dyncol_func_result
++mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
++ uint column_count,
++ MYSQL_LEX_STRING *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_string);
++
++
++enum enum_dyncol_func_result
++mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ uint *column_keys,
++ DYNAMIC_COLUMN_VALUE *values);
++enum enum_dyncol_func_result
++mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ MYSQL_LEX_STRING *column_keys,
++ DYNAMIC_COLUMN_VALUE *values);
++
++
++enum enum_dyncol_func_result
++mariadb_dyncol_exists_num(DYNAMIC_COLUMN *org, uint column_nr);
++enum enum_dyncol_func_result
++mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name);
++
++/* List of not NULL columns */
++enum enum_dyncol_func_result
++mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums);
++enum enum_dyncol_func_result
++mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count,
++ MYSQL_LEX_STRING **names);
++
++/*
++ if the column do not exists it is NULL
++*/
++enum enum_dyncol_func_result
++mariadb_dyncol_get_num(DYNAMIC_COLUMN *org, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *store_it_here);
++enum enum_dyncol_func_result
++mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name,
++ DYNAMIC_COLUMN_VALUE *store_it_here);
++
++my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str);
++
++enum enum_dyncol_func_result
++mariadb_dyncol_check(DYNAMIC_COLUMN *str);
++
++enum enum_dyncol_func_result
++mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json);
++
++void mariadb_dyncol_free(DYNAMIC_COLUMN *str);
++
++#define mariadb_dyncol_init(A) memset((A), 0, sizeof(DYNAMIC_COLUMN))
++#define dynamic_column_initialize(A) mariadb_dyncol_init((A))
++#define dynamic_column_column_free(A) mariadb_dyncol_free((A))
++
++/* conversion of values to 3 base types */
++enum enum_dyncol_func_result
++mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
++ CHARSET_INFO *cs, my_bool quote);
++enum enum_dyncol_func_result
++mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val);
++enum enum_dyncol_func_result
++mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val);
++
++enum enum_dyncol_func_result
++mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
++ uint *count,
++ MYSQL_LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals);
++
++int mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1,
++ const MYSQL_LEX_STRING *s2);
++
++enum enum_dyncol_func_result
++mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count);
++
++#define mariadb_dyncol_value_init(V) (V)->type= DYN_COL_NULL
++
++/*
++ Prepare value for using as decimal
++*/
++void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);
++
++
++#ifdef __cplusplus
++}
++#endif
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/ma_secure.h mariadb-native-client.trunk/include/ma_secure.h
+--- mariadb/include/ma_secure.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/include/ma_secure.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,44 @@
++/************************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*************************************************************************************/
++#ifndef _ma_secure_h_
++#define _ma_secure_h_
++
++#ifdef HAVE_OPENSSL
++#include <mysql.h>
++#include <openssl/ssl.h> /* SSL and SSL_CTX */
++#include <openssl/err.h> /* error reporting */
++#include <openssl/conf.h>
++
++struct MYSQL;
++
++size_t my_ssl_read(Vio *vio, uchar* buf, size_t size);
++int my_ssl_close(Vio *vio);
++size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size);
++SSL *my_ssl_init(MYSQL *mysql);
++int my_ssl_connect(SSL *ssl);
++int my_ssl_verify_server_cert(SSL *ssl);
++
++int my_ssl_start(MYSQL *mysql);
++void my_ssl_end(void);
++
++#endif /* HAVE_OPENSSL */
++#endif /* _ma_secure_h_ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/m_ctype.h mariadb-native-client.trunk/include/m_ctype.h
+--- mariadb/include/m_ctype.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/m_ctype.h 2013-10-19 07:29:16.000000000 +0200
+@@ -32,28 +32,42 @@
#define CHARSET_DIR "charsets/"
#define MY_CS_NAME_SIZE 32
@@ -606,41 +2082,72 @@
/* we use the mysqlnd implementation */
typedef struct charset_info_st
-@@ -56,4 +58,8 @@
+ {
+- uint nr; /* so far only 1 byte for charset */
+- uint state;
++ unsigned int nr; /* so far only 1 byte for charset */
++ unsigned int state;
+ char *csname;
+ char *name;
+- char *comment;
+ char *dir;
+- uint char_minlen;
+- uint char_maxlen;
+- uint (*mb_charlen)(uint c);
+- uint (*mb_valid)(const char *start, const char *end);
++ char *encoding;
++ unsigned int char_minlen;
++ unsigned int char_maxlen;
++ unsigned int (*mb_charlen)(unsigned int c);
++ unsigned int (*mb_valid)(const char *start, const char *end);
+ } CHARSET_INFO;
+
+ extern const CHARSET_INFO compiled_charsets[];
+ extern CHARSET_INFO *default_charset_info;
++extern CHARSET_INFO *my_charset_bin;
++extern CHARSET_INFO *my_charset_latin1;
++extern CHARSET_INFO *my_charset_utf8_general_ci;
+
+-CHARSET_INFO *find_compiled_charset(uint cs_number);
++CHARSET_INFO *find_compiled_charset(unsigned int cs_number);
+ CHARSET_INFO *find_compiled_charset_by_name(const char *name);
size_t mysql_cset_escape_quotes(const CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len);
size_t mysql_cset_escape_slashes(const CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len);
-+char* madb_get_os_character_set();
++char* madb_get_os_character_set(void);
+#ifdef _WIN32
+int madb_get_windows_cp(const char *charset);
+#endif
++
++#ifdef __cplusplus
++}
++#endif
++
#endif
-
-=== renamed file 'include/my_secure.h' => 'include/ma_secure.h'
---- mariadb/include/my_secure.h 2012-11-26 07:32:41 +0000
-+++ mariadb/include/ma_secure.h 2013-03-14 21:01:43 +0000
-@@ -19,8 +19,8 @@
- Part of this code includes code from the PHP project which
- is freely available from http://www.php.net
- *************************************************************************************/
--#ifndef _my_secure_h_
--#define _my_secure_h_
-+#ifndef _ma_secure_h_
-+#define _ma_secure_h_
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/m_string.h mariadb-native-client.trunk/include/m_string.h
+--- mariadb/include/m_string.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/m_string.h 2013-10-19 07:29:16.000000000 +0200
+@@ -88,9 +88,6 @@
- #ifdef HAVE_OPENSSL
- #include <mysql.h>
-@@ -40,4 +40,4 @@
- void my_ssl_end();
+ #if defined(HAVE_STPCPY) && !defined(HAVE_mit_thread)
+ #define strmov(A,B) stpcpy((A),(B))
+-#ifndef stpcpy
+-extern char *stpcpy(char *, const char *); /* For AIX with gcc 2.95.3 */
+-#endif
+ #endif
- #endif /* HAVE_OPENSSL */
--#endif /* _my_secure_h_ */
-+#endif /* _ma_secure_h_ */
-
-=== modified file 'include/my_config.h.in'
---- mariadb/include/my_config.h.in 2012-11-14 17:43:45 +0000
-+++ mariadb/include/my_config.h.in 2013-03-14 21:01:43 +0000
-@@ -137,6 +137,7 @@
+ extern char NEAR _dig_vec[]; /* Declared in int2str() */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_config.h.in mariadb-native-client.trunk/include/my_config.h.in
+--- mariadb/include/my_config.h.in 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_config.h.in 2013-10-19 07:29:16.000000000 +0200
+@@ -1,6 +1,4 @@
+
+-#define HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE 1
+-
+ /*
+ * Include file constants (processed in LibmysqlIncludeFiles.txt 1
+ */
+@@ -137,6 +135,7 @@
#cmakedefine HAVE_SIGWAIT 1
#cmakedefine HAVE_SLEEP 1
#cmakedefine HAVE_SNPRINTF 1
@@ -648,16 +2155,121 @@
#cmakedefine HAVE_STPCPY 1
#cmakedefine HAVE_STRERROR 1
#cmakedefine HAVE_STRLCPY 1
-@@ -275,3 +276,4 @@
+@@ -275,3 +274,5 @@
#cmakedefine HAVE_THREADS 1
#cmakedefine SHAREDIR "@SHAREDIR@"
#cmakedefine DEFAULT_CHARSET_HOME "@DEFAULT_CHARSET_HOME@"
+#cmakedefine PLUGINDIR "@PLUGINDIR@"
-
-=== modified file 'include/my_global.h'
---- mariadb/include/my_global.h 2012-11-27 08:57:10 +0000
-+++ mariadb/include/my_global.h 2013-03-14 21:01:43 +0000
-@@ -581,8 +581,8 @@
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_global.h mariadb-native-client.trunk/include/my_global.h
+--- mariadb/include/my_global.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_global.h 2013-10-19 07:29:16.000000000 +0200
+@@ -326,13 +326,6 @@
+ #define DBUG_OFF
+ #endif
+
+-#include <dbug.h>
+-#ifndef DBUG_OFF
+-#define dbug_assert(A) assert(A)
+-#else
+-#define dbug_assert(A)
+-#endif
+-
+ #define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
+ #define ASCII_BITS_USED 8 /* Bit char used */
+ #define NEAR_F /* No near function handling */
+@@ -347,7 +340,7 @@
+ #endif
+ /* Type for fuctions that handles signals */
+ #define sig_handler RETSIGTYPE
+-typedef void (*sig_return)();/* Returns type from signal */
++typedef void (*sig_return)(void);/* Returns type from signal */
+ #if defined(__GNUC__) && !defined(_lint)
+ typedef char pchar; /* Mixed prototypes can take char */
+ typedef char puchar; /* Mixed prototypes can take char */
+@@ -446,11 +439,7 @@
+ How much overhead does malloc have. The code often allocates
+ something like 1024-MALLOC_OVERHEAD bytes
+ */
+-#ifdef SAFEMALLOC
+-#define MALLOC_OVERHEAD (8+24+4)
+-#else
+ #define MALLOC_OVERHEAD 8
+-#endif
+ /* get memory in huncs */
+ #define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD)
+ /* Typical record cash */
+@@ -510,6 +499,14 @@
+ /* #define sigset(A,B) signal((A),(B)) */
+ #endif
+
++#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \
++ defined(__cplusplus) || !defined(__GNUC__)
++#define UNINIT_VAR(x) x= 0
++#else
++/* GCC specific self-initialization which inhibits the warning. */
++#define UNINIT_VAR(x) x= x
++#endif
++
+ /* Remove some things that mit_thread break or doesn't support */
+ #if defined(HAVE_mit_thread) && defined(THREAD)
+ #undef HAVE_PREAD
+@@ -532,25 +529,20 @@
+ #define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
+ #endif
+
+-#if SIZEOF_LONG == 4
+-#define INT_MIN32 (long) 0x80000000L
+-#define INT_MAX32 (long) 0x7FFFFFFFL
++#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL)
++#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL
++#define INT_MIN32 (~0x7FFFFFFFL)
++#define INT_MAX32 0x7FFFFFFFL
+ #define UINT_MAX32 0xFFFFFFFFL
+-#define INT_MIN24 ((long) 0xff800000L)
+-#define INT_MAX24 0x007fffffL
+-#define INT_MIN16 ((short int) 0x8000)
+-#define INT_MAX16 0x7FFF
+-#define UINT_MAX16 0xFFFF
+-#define INT_MIN8 ((char) 0x80)
+-#define INT_MAX8 ((char) 0x7F)
+-#else /* Probably Alpha */
+-#define INT_MIN32 ((long) (int) 0x80000000)
+-#define INT_MAX32 ((long) (int) 0x7FFFFFFF)
+-#define INT_MIN24 ((long) (int) 0xff800000)
+-#define INT_MAX24 ((long) (int) 0x007fffff)
+-#define INT_MIN16 ((short int) 0xffff8000)
+-#define INT_MAX16 ((short int) 0x00007FFF)
+-#endif
++#define INT_MIN24 (~0x007FFFFF)
++#define INT_MAX24 0x007FFFFF
++#define UINT_MAX24 0x00FFFFFF
++#define INT_MIN16 (~0x7FFF)
++#define INT_MAX16 0x7FFF
++#define UINT_MAX16 0xFFFF
++#define INT_MIN8 (~0x7F)
++#define INT_MAX8 0x7F
++#define UINT_MAX8 0xFF
+
+ #ifndef ULL
+ #ifdef HAVE_LONG_LONG
+@@ -560,6 +552,15 @@
+ #endif
+ #endif
+
++#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)
++/* First check for ANSI C99 definition: */
++#ifdef ULLONG_MAX
++#define ULONGLONG_MAX ULLONG_MAX
++#else
++#define ULONGLONG_MAX ((unsigned long long)(~0ULL))
++#endif
++#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/
++
+ /* From limits.h instead */
+ #ifndef DBL_MIN
+ #define DBL_MIN 4.94065645841246544e-324
+@@ -581,8 +582,8 @@
#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A),sizeof(t)))
/* Offset of filed f in structure t */
#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f)
@@ -668,7 +2280,24 @@
#define NullS (char *) 0
/* Nowdays we do not support MessyDos */
-@@ -698,9 +698,6 @@
+@@ -641,6 +642,7 @@
+ typedef unsigned long ulonglong; /* ulong or unsigned long long */
+ typedef long longlong;
+ #endif
++#define longlong_defined
+ #endif
+
+ #ifndef MIN
+@@ -649,7 +651,7 @@
+ #ifndef MAX
+ #define MAX(a,b) (((a) > (b)) ? (a) : (b))
+ #endif
+-
++#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
+ #ifdef USE_RAID
+ /*
+ The following is done with a if to not get problems with pre-processors
+@@ -698,9 +700,6 @@
typedef char *my_string; /* String of characters */
typedef unsigned long size_s; /* Size of strings (In string-funcs) */
typedef int myf; /* Type of MyFlags in my_funcs */
@@ -678,349 +2307,302 @@
typedef char my_bool; /* Small bool */
#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus))
typedef char bool; /* Ordinary boolean values 0 1 */
-
-=== modified file 'include/my_stmt.h'
---- mariadb/include/my_stmt.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/my_stmt.h 2013-03-14 21:01:43 +0000
-@@ -198,7 +198,7 @@
-
- my_bool cursor_exists;
+@@ -1064,6 +1063,13 @@
+ #define SO_EXT ".so"
+ #endif
-- MYSQL_CMD_BUFFER cmd_buffer;
-+ void *ext_stmt;
- mysql_stmt_fetch_row_func fetch_row_func;
- unsigned int execute_count;/* count how many times the stmt was executed */
- mysql_stmt_use_or_store_func default_rset_handler;
-@@ -206,18 +206,17 @@
- };
++#include <dbug.h>
++#ifndef DBUG_OFF
++#define dbug_assert(A) assert(A)
++#else
++#define dbug_assert(A)
++#endif
++
+ #ifdef HAVE_DLOPEN
+ #ifdef _WIN32
+ #define dlsym(lib, name) GetProcAddress((HMODULE)lib, name)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_net.h mariadb-native-client.trunk/include/my_net.h
+--- mariadb/include/my_net.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_net.h 2013-10-19 07:29:16.000000000 +0200
+@@ -34,43 +34,6 @@
+ #endif
+ #endif /* !defined(MSDOS) && !defined(_WIN32) */
- typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row);
--struct st_mysql_perm_bind {
-+typedef struct st_mysql_perm_bind {
- ps_field_fetch_func func;
- /* should be signed int */
- int pack_len;
- unsigned long max_len;
--};
-+} MYSQL_PS_CONVERSION;
+-void my_inet_ntoa(struct in_addr in, char *buf);
+-
+-/*
+- Handling of gethostbyname_r()
+-*/
+-
+-#if !defined(HPUX)
+-struct hostent;
+-#endif /* HPUX */
+-#if !defined(HAVE_GETHOSTBYNAME_R)
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop);
+-void my_gethostbyname_r_free();
+-#elif defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop);
+-#define my_gethostbyname_r_free()
+-#if !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) && !defined(HPUX)
+-#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data)
+-#endif /* !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) */
+-
+-#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT)
+-#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data)
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop);
+-#define my_gethostbyname_r_free()
+-#else
+-#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(C),(D),(E))
+-#define my_gethostbyname_r_free()
+-#endif /* !defined(HAVE_GETHOSTBYNAME_R) */
+-
+-#ifndef GETHOSTBYNAME_BUFF_SIZE
+-#define GETHOSTBYNAME_BUFF_SIZE 2048
+-#endif
--extern struct st_mysql_perm_bind mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
-+extern MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
- unsigned long net_safe_read(MYSQL *mysql);
- void mysql_init_ps_subsystem(void);
- unsigned long net_field_length(unsigned char **packet);
--int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check);
- /*
- * function prototypes
- */
-@@ -255,3 +254,5 @@
- my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length);
- my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt);
- my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt);
-+MYSQL_RES* STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt);
-+int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt);
-
-=== modified file 'include/my_sys.h'
---- mariadb/include/my_sys.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/my_sys.h 2013-03-14 21:01:43 +0000
-@@ -139,7 +139,7 @@
- #define my_malloc_ci(SZ,FLAG) my_malloc( SZ, FLAG )
- extern gptr my_realloc(gptr oldpoint, size_t Size,myf MyFlags);
- extern void my_no_flags_free(gptr ptr);
--extern gptr my_memdup(const byte *from, size_t length,myf MyFlags);
-+extern gptr my_memdup(const unsigned char *from, size_t length,myf MyFlags);
- extern my_string my_strdup(const char *from,myf MyFlags);
- extern my_string my_strndup(const char *from, size_t length, myf MyFlags);
- #define my_free(PTR,FG) my_no_flags_free(PTR)
-@@ -261,7 +261,7 @@
- int rc_seek,error,inited;
- uint rc_length,read_length,reclength;
- my_off_t rc_record_pos,end_of_file;
-- byte *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
-+ unsigned char *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
- #ifdef HAVE_AIOWAIT
- int use_async_io;
- my_aio_result aio_result;
-@@ -298,8 +298,8 @@
- typedef struct st_io_cache /* Used when cacheing files */
- {
- my_off_t pos_in_file,end_of_file;
-- byte *rc_pos,*rc_end,*buffer,*rc_request_pos;
-- int (*read_function)(struct st_io_cache *,byte *,uint);
-+ unsigned char *rc_pos,*rc_end,*buffer,*rc_request_pos;
-+ int (*read_function)(struct st_io_cache *,unsigned char *,uint);
- char *file_name; /* if used with 'open_cached_file' */
- char *dir,*prefix;
- File file;
-@@ -414,18 +414,18 @@
- extern int my_delete_with_symlink(const char *name, myf MyFlags);
- extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags);
- extern int my_symlink(const char *content, const char *linkname, myf MyFlags);
--extern uint my_read(File Filedes,byte *Buffer,uint Count,myf MyFlags);
--extern uint my_pread(File Filedes,byte *Buffer,uint Count,my_off_t offset,
-+extern uint my_read(File Filedes,unsigned char *Buffer,uint Count,myf MyFlags);
-+extern uint my_pread(File Filedes,unsigned char *Buffer,uint Count,my_off_t offset,
- myf MyFlags);
- extern int my_rename(const char *from,const char *to,myf MyFlags);
- extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags);
- extern my_off_t my_tell(File fd,myf MyFlags);
--extern uint my_write(File Filedes,const byte *Buffer,uint Count,
-+extern uint my_write(File Filedes,const unsigned char *Buffer,uint Count,
- myf MyFlags);
--extern uint my_pwrite(File Filedes,const byte *Buffer,uint Count,
-+extern uint my_pwrite(File Filedes,const unsigned char *Buffer,uint Count,
- my_off_t offset,myf MyFlags);
--extern uint my_fread(FILE *stream,byte *Buffer,uint Count,myf MyFlags);
--extern uint my_fwrite(FILE *stream,const byte *Buffer,uint Count,
-+extern uint my_fread(FILE *stream,unsigned char *Buffer,uint Count,myf MyFlags);
-+extern uint my_fwrite(FILE *stream,const unsigned char *Buffer,uint Count,
- myf MyFlags);
- extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags);
- extern my_off_t my_ftell(FILE *stream,myf MyFlags);
-@@ -436,7 +436,7 @@
- extern gptr my_multi_malloc _VARARGS((myf MyFlags, ...));
- extern void _myfree(gptr pPtr,const char *sFile,uint uLine, myf MyFlag);
- extern int _sanity(const char *sFile,unsigned int uLine);
--extern gptr _my_memdup(const byte *from, size_t length,
-+extern gptr _my_memdup(const unsigned char *from, size_t length,
- const char *sFile, uint uLine,myf MyFlag);
- extern my_string _my_strdup(const char *from, const char *sFile, uint uLine,
- myf MyFlag);
-@@ -517,18 +517,18 @@
- extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file,
- uint reclength,enum cache_type type,
- pbool use_async_io);
--extern int read_cache_record(RECORD_CACHE *info,byte *to);
-+extern int read_cache_record(RECORD_CACHE *info,unsigned char *to);
- extern int end_record_cache(RECORD_CACHE *info);
- extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos,
-- const byte *record,uint length);
-+ const unsigned char *record,uint length);
- extern int flush_write_cache(RECORD_CACHE *info);
- extern long my_clock(void);
- extern sig_handler sigtstp_handler(int signal_number);
- extern void handle_recived_signals(void);
- extern int init_key_cache(ulong use_mem,ulong leave_this_much_mem);
--extern byte *key_cache_read(File file,my_off_t filepos,byte* buff,uint length,
-+extern unsigned char *key_cache_read(File file,my_off_t filepos,unsigned char* buff,uint length,
- uint block_length,int return_buffer);
--extern int key_cache_write(File file,my_off_t filepos,byte* buff,uint length,
-+extern int key_cache_write(File file,my_off_t filepos,unsigned char* buff,uint length,
- uint block_length,int force_write);
- extern int flush_key_blocks(int file, enum flush_type type);
- extern void end_key_cache(void);
-@@ -545,12 +545,12 @@
- extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type,
- my_off_t seek_offset,pbool use_async_io,
- pbool clear_cache);
--extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count);
--extern int _my_b_net_read(IO_CACHE *info,byte *Buffer,uint Count);
-+extern int _my_b_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
-+extern int _my_b_net_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
- extern int _my_b_get(IO_CACHE *info);
--extern int _my_b_async_read(IO_CACHE *info,byte *Buffer,uint Count);
--extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
--extern int my_block_write(IO_CACHE *info, const byte *Buffer,
-+extern int _my_b_async_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
-+extern int _my_b_write(IO_CACHE *info,const unsigned char *Buffer,uint Count);
-+extern int my_block_write(IO_CACHE *info, const unsigned char *Buffer,
- uint Count, my_off_t pos);
- extern int flush_io_cache(IO_CACHE *info);
- extern int end_io_cache(IO_CACHE *info);
-@@ -571,8 +571,8 @@
- extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
- uint init_alloc,uint alloc_increment CALLER_INFO_PROTO);
- extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element);
--extern byte *alloc_dynamic(DYNAMIC_ARRAY *array);
--extern byte *pop_dynamic(DYNAMIC_ARRAY*);
-+extern unsigned char *alloc_dynamic(DYNAMIC_ARRAY *array);
-+extern unsigned char *pop_dynamic(DYNAMIC_ARRAY*);
- extern my_bool set_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
- extern void get_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
- extern void delete_dynamic(DYNAMIC_ARRAY *array);
-@@ -598,8 +598,8 @@
- my_bool set_changeable_varval(const char *var, ulong val,
- CHANGEABLE_VAR *vars);
- #ifdef HAVE_MLOCK
--extern byte *my_malloc_lock(size_t length,myf flags);
--extern void my_free_lock(byte *ptr,myf flags);
-+extern unsigned char *my_malloc_lock(size_t length,myf flags);
-+extern void my_free_lock(unsigned char *ptr,myf flags);
- #else
- #define my_malloc_lock(A,B) my_malloc((A),(B))
- #define my_free_lock(A,B) my_free((A),(B))
-@@ -614,10 +614,10 @@
- int *argc, char ***argv);
- void free_defaults(char **argv);
- void print_defaults(const char *conf_file, const char **groups);
--my_bool my_compress(byte *, ulong *, ulong *);
--my_bool my_uncompress(byte *, ulong *, ulong *);
--byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
--ulong checksum(const byte *mem, uint count);
-+my_bool my_compress(unsigned char *, ulong *, ulong *);
-+my_bool my_uncompress(unsigned char *, ulong *, ulong *);
-+unsigned char *my_compress_alloc(const unsigned char *packet, ulong *len, ulong *complen);
-+ulong checksum(const unsigned char *mem, uint count);
+ /* On SCO you get a link error when refering to h_errno */
+ #ifdef SCO
+@@ -78,6 +41,8 @@
+ #define h_errno errno
+ #endif
- #if defined(_MSC_VER) && !defined(_WIN32)
- extern void sleep(int sec);
-
-=== modified file 'include/mysql.h'
---- mariadb/include/mysql.h 2012-11-27 23:53:08 +0000
-+++ mariadb/include/mysql.h 2013-03-14 21:01:43 +0000
-@@ -1,5 +1,6 @@
- /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
--
-+ 2012 by MontyProgram AB
++void my_inet_ntoa(struct in_addr in, char *buf);
+
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
-@@ -15,7 +16,7 @@
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA */
+ #ifdef __cplusplus
+ }
+ #endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_pthread.h mariadb-native-client.trunk/include/my_pthread.h
+--- mariadb/include/my_pthread.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_pthread.h 2013-10-19 07:29:16.000000000 +0200
+@@ -29,19 +29,10 @@
+ extern "C" {
+ #endif /* __cplusplus */
--/* defines for the libmysql library */
-+/* defines for the libmariadb library */
+-#if defined(_WIN32) || defined(OS2)
++#if defined(_WIN32)
- #ifndef _mysql_h
- #define _mysql_h
-@@ -181,9 +182,10 @@
- MYSQL_REPORT_DATA_TRUNCATION,
- MYSQL_OPT_RECONNECT,
- MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
-- MYSQL_OPT_PLUGIN_DIR,
-- MYSQL_OPT_DEFAULT_AUTH,
-- MYSQL_OPT_PROGRESS_CALLBACK
-+ MYSQL_PLUGIN_DIR,
-+ MYSQL_DEFAULT_AUTH,
-+ MYSQL_PROGRESS_CALLBACK,
-+ MYSQL_DATABASE_DRIVER=255
- };
-
- enum mysql_status { MYSQL_STATUS_READY,
-@@ -207,7 +209,7 @@
- unsigned int port, protocol;
- unsigned long client_flag;
- char *host,*user,*password,*unix_socket,*db;
-- char *init_command;
-+ struct st_dynamic_array *init_command;
- char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
- char *ssl_key; /* PEM key file */
- char *ssl_cert; /* PEM cert file */
-@@ -232,14 +234,21 @@
- struct st_mysql_options_extention *extension;
+-#ifdef OS2
+-typedef ULONG HANDLE;
+-typedef ULONG DWORD;
+-typedef int sigset_t;
+-#endif
+-
+-#ifdef OS2
+-typedef HMTX pthread_mutex_t;
+-#else
+ typedef CRITICAL_SECTION pthread_mutex_t;
+-#endif
++
+ typedef HANDLE pthread_t;
+ typedef struct thread_attr {
+ DWORD dwStackSize ;
+@@ -76,17 +67,13 @@
};
-+typedef struct st_mariadb_db_driver
-+{
-+ struct st_mariadb_client_plugin_DB *plugin;
-+ char *name;
-+ void *buffer;
-+} MARIADB_DB_DRIVER;
+ typedef int pthread_mutexattr_t;
+-#define win_pthread_self my_thread_var->pthread_self
+-#ifdef OS2
+-#define pthread_handler_decl(A,B) void * _Optlink A(void *B)
+-typedef void * (_Optlink *pthread_handler)(void *);
+-#else
++#define pthread_self() GetCurrentThreadId()
+
- typedef struct st_mysql {
- NET net; /* Communication parameters */
-- unsigned char *unused;
-- char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
-- char *info,*db;
-+ void *unused_0;
-+ char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
-+ char *info,*db;
- const struct charset_info_st *charset; /* character set */
-- MYSQL_FIELD *fields;
-- MEM_ROOT field_alloc;
-+ MYSQL_FIELD *fields;
-+ MEM_ROOT field_alloc;
- my_ulonglong affected_rows;
- my_ulonglong insert_id; /* id if insert on table with NEXTNR */
- my_ulonglong extra_info; /* Used by mysqlshow */
-@@ -282,6 +291,7 @@
- double progress,
- const char *proc_info,
- unsigned int proc_info_length);
-+ MARIADB_DB_DRIVER *db_driver;
- };
+ #define pthread_handler_decl(A,B) void * __cdecl A(void *B)
+ typedef void * (__cdecl *pthread_handler)(void *);
+-#endif
- typedef struct st_mysql_res {
-@@ -305,6 +315,7 @@
- MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2
- };
+ void win_pthread_init(void);
+-int win_pthread_setspecific(void *A,void *B,uint length);
++
+ int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *);
+ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
+ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+@@ -106,12 +93,11 @@
+ #ifndef OS2
+ #define getpid() GetCurrentThreadId()
+ #endif
+-#define pthread_self() win_pthread_self
++
+ #define HAVE_LOCALTIME_R 1
+ #define _REENTRANT 1
+ #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
+-#ifdef USE_TLS /* For LIBMYSQL.DLL */
+ #undef SAFE_MUTEX /* This will cause conflicts */
+ #define pthread_key(T,V) DWORD V
+ #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF)
+@@ -120,18 +106,10 @@
+ #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V))
+ #define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V)))
+ #define pthread_setspecific(A,B) (!TlsSetValue((A),(B)))
+-#else
+-#define pthread_key(T,V) __declspec(thread) T V
+-#define pthread_key_create(A,B) pthread_dummy(0)
+-#define pthread_getspecific(A) (&(A))
+-#define my_pthread_getspecific(T,A) (&(A))
+-#define my_pthread_getspecific_ptr(T,V) (V)
+-#define my_pthread_setspecific_ptr(T,V) ((T)=(V),0)
+-#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A))
+-#endif /* USE_TLS */
+
- typedef struct st_mysql_time
- {
- unsigned int year, month, day, hour, minute, second;
-@@ -370,7 +381,7 @@
- MYSQL * STDCALL mysql_init(MYSQL *mysql);
- int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
- const char *cert, const char *ca,
-- const char *capath);
-+ const char *capath, const char *cipher);
- const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql);
- int STDCALL mysql_ssl_clear(MYSQL *mysql);
- MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
-@@ -394,7 +405,7 @@
- unsigned int length);
- int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
- int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
--int STDCALL mysql_shutdown(MYSQL *mysql);
-+int STDCALL mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level);
- int STDCALL mysql_dump_debug_info(MYSQL *mysql);
- int STDCALL mysql_refresh(MYSQL *mysql,
- unsigned int refresh_options);
-@@ -413,7 +424,7 @@
- MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
- MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
- int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
-- const char *arg);
-+ const void *arg);
- void STDCALL mysql_free_result(MYSQL_RES *result);
- void STDCALL mysql_data_seek(MYSQL_RES *result,
- my_ulonglong offset);
-@@ -443,10 +454,38 @@
- enum enum_mysql_set_option option);
- const char * STDCALL mysql_get_client_info(void);
- unsigned long STDCALL mysql_get_client_version(void);
-+my_bool STDCALL mariadb_connection(MYSQL *mysql);
-+const char * STDCALL mysql_get_server_name(MYSQL *mysql);
- #include <my_stmt.h>
-
-+/* these methods can be overwritten by db plugins */
-+struct st_mysql_methods {
-+ MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd,
-+ const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag);
-+ void (*db_close)(MYSQL *mysql);
-+ int (*db_command)(MYSQL *mysql,enum enum_server_command command, const char *arg,
-+ size_t length, my_bool skipp_check, void *opt_arg);
-+ void (*db_skip_result)(MYSQL *mysql);
-+ int (*db_read_query_result)(MYSQL *mysql);
-+ MYSQL_DATA *(*db_read_rows)(MYSQL *mysql,MYSQL_FIELD *fields, unsigned int field_count);
-+ int (*db_read_one_row)(MYSQL *mysql,unsigned int fields,MYSQL_ROW row, unsigned long *lengths);
-+ /* prepared statements */
-+ my_bool (*db_supported_buffer_type)(enum enum_field_types type);
-+ my_bool (*db_read_prepare_response)(MYSQL_STMT *stmt);
-+ int (*db_read_stmt_result)(MYSQL *mysql);
-+ my_bool (*db_stmt_get_result_metadata)(MYSQL_STMT *stmt);
-+ my_bool (*db_stmt_get_param_metadata)(MYSQL_STMT *stmt);
-+ int (*db_stmt_read_all_rows)(MYSQL_STMT *stmt);
-+ int (*db_stmt_fetch)(MYSQL_STMT *stmt, unsigned char **row);
-+ int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row);
-+ void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt);
-+};
+ #define pthread_equal(A,B) ((A) == (B))
+-#ifdef _WIN32
++
+ #define pthread_mutex_init(A,B) InitializeCriticalSection(A)
+ #define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
+ #define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT)
+@@ -139,7 +117,7 @@
+ #define pthread_mutex_destroy(A) DeleteCriticalSection(A)
+ #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
+ #define pthread_kill(A,B) pthread_dummy(0)
+-#endif /* _WIN32 */
+
-+/* synonyms/aliases functions */
- #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
-+#define mysql_library_init mysql_server_init
-+#define mysql_library_end mysql_server_end
- /* new api functions */
+ /* Dummy defines for easier code */
+ #define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
+@@ -258,27 +236,8 @@
+ #define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL
+ #define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL
+ #define USE_ALARM_THREAD
+-#elif defined(HAVE_mit_thread)
+-#define USE_ALARM_THREAD
+-#undef HAVE_LOCALTIME_R
+-#define HAVE_LOCALTIME_R
+-#undef HAVE_PTHREAD_ATTR_SETSCOPE
+-#define HAVE_PTHREAD_ATTR_SETSCOPE
+-#undef HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE /* If we are running linux */
+-#undef HAVE_RWLOCK_T
+-#undef HAVE_RWLOCK_INIT
+-#undef HAVE_PTHREAD_RWLOCK_RDLOCK
+-#undef HAVE_SNPRINTF
+-
+-#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B))
+-#define signal(A,B) pthread_signal((A),(void (*)(int)) (B))
+-#define my_pthread_attr_setprio(A,B)
+ #endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */
-
-=== modified file 'include/mysql/client_plugin.h'
---- mariadb/include/mysql/client_plugin.h 2012-11-27 08:57:10 +0000
-+++ mariadb/include/mysql/client_plugin.h 2013-03-14 21:01:43 +0000
+-#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910
+-int sigwait(sigset_t *set, int *sig);
+-#endif
+-
+ #if defined(HAVE_UNIXWARE7_POSIX)
+ #undef HAVE_NONPOSIX_SIGWAIT
+ #define HAVE_NONPOSIX_SIGWAIT /* sigwait takes only 1 argument */
+@@ -308,14 +267,16 @@
+ #if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX)
+ int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */
+ #endif
+-#if !defined(HAVE_SIGSET) && !defined(HAVE_mit_thread) && !defined(sigset)
+-#define sigset(A,B) do { struct sigaction s; sigset_t set; \
++#if !defined(HAVE_SIGSET) && !defined(my_sigset)
++#define my_sigset(A,B) do { struct sigaction s; sigset_t set; \
+ sigemptyset(&set); \
+ s.sa_handler = (B); \
+ s.sa_mask = set; \
+ s.sa_flags = 0; \
+ sigaction((A), &s, (struct sigaction *) NULL); \
+ } while (0)
++#elif !defined(my_sigset)
++ #define my_sigset(A,B) signal((A),(B))
+ #endif
+
+ #ifndef my_pthread_setprio
+@@ -348,15 +309,12 @@
+ #define pthread_cond_timedwait(A,B,C) my_pthread_cond_timedwait((A),(B),(C))
+ #endif
+
+-#if defined(OS2)
+-#define my_pthread_getspecific(T,A) ((T) &(A))
+-#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A))
+-#elif !defined( HAVE_NONPOSIX_PTHREAD_GETSPECIFIC)
++#if !defined( HAVE_NONPOSIX_PTHREAD_GETSPECIFIC)
+ #define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B))
+ #else
+ #define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B))
+ void *my_pthread_getspecific_imp(pthread_key_t key);
+-#endif /* OS2 */
++#endif
+
+ #ifndef HAVE_LOCALTIME_R
+ struct tm *localtime_r(const time_t *clock, struct tm *res);
+@@ -414,7 +372,7 @@
+ #define pthread_kill(A,B) pthread_dummy(0)
+ #undef pthread_detach_this_thread
+ #define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
+-#else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */
+++#elif !defined(HAVE_PTHREAD_KILL) /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */
+ #define HAVE_PTHREAD_KILL
+ #endif
+
+@@ -587,9 +545,11 @@
+ gptr dbug;
+ char name[THREAD_NAME_SIZE+1];
+ #endif
++ my_bool initialized;
+ };
+
+ extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
++extern void **my_thread_var_dbug();
+ #define my_thread_var (_my_thread_var())
+ #define my_errno my_thread_var->thr_errno
+
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_secure.h mariadb-native-client.trunk/include/my_secure.h
+--- mariadb/include/my_secure.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_secure.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,43 +0,0 @@
+-/************************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-
+- Part of this code includes code from the PHP project which
+- is freely available from http://www.php.net
+-*************************************************************************************/
+-#ifndef _my_secure_h_
+-#define _my_secure_h_
+-
+-#ifdef HAVE_OPENSSL
+-#include <mysql.h>
+-#include <openssl/ssl.h> /* SSL and SSL_CTX */
+-#include <openssl/err.h> /* error reporting */
+-#include <openssl/conf.h>
+-
+-struct MYSQL;
+-
+-size_t my_ssl_read(Vio *vio, uchar* buf, size_t size);
+-int my_ssl_close(Vio *vio);
+-size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size);
+-SSL *my_ssl_init(MYSQL *mysql);
+-int my_ssl_connect(SSL *ssl);
+-
+-int my_ssl_start(MYSQL *mysql);
+-void my_ssl_end();
+-
+-#endif /* HAVE_OPENSSL */
+-#endif /* _my_secure_h_ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql/client_plugin.h mariadb-native-client.trunk/include/mysql/client_plugin.h
+--- mariadb/include/mysql/client_plugin.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql/client_plugin.h 2013-10-19 07:29:16.000000000 +0200
@@ -35,11 +35,12 @@
#endif
@@ -1036,6 +2618,15 @@
#define MYSQL_CLIENT_MAX_PLUGINS 3
+@@ -59,7 +60,7 @@
+ const char *desc; \
+ unsigned int version[3]; \
+ int (*init)(char *, size_t, int, va_list); \
+- int (*deinit)();
++ int (*deinit)(void);
+
+ struct st_mysql_client_plugin
+ {
@@ -68,6 +69,32 @@
struct st_mysql;
@@ -1069,10 +2660,9 @@
/******** authentication plugin specific declarations *********/
#include <mysql/plugin_auth_common.h>
-
-=== modified file 'include/mysql/plugin_auth.h'
---- mariadb/include/mysql/plugin_auth.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/mysql/plugin_auth.h 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql/plugin_auth_common.h mariadb-native-client.trunk/include/mysql/plugin_auth_common.h
+--- mariadb/include/mysql/plugin_auth_common.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql/plugin_auth_common.h 2013-10-19 07:29:16.000000000 +0200
@@ -33,7 +33,7 @@
/**
@@ -1100,10 +2690,21 @@
but it will use the data at mysql->net.read_pos.
A plugin may return this value if the number of roundtrips in the
-
-=== modified file 'include/mysql/plugin_auth_common.h'
---- mariadb/include/mysql/plugin_auth_common.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/mysql/plugin_auth_common.h 2013-03-14 21:01:43 +0000
+@@ -68,8 +68,10 @@
+ {
+ enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
+ MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
++#ifndef _WIN32
+ int socket; /**< it's set, if the protocol is SOCKET or TCP */
+-#ifdef _WIN32
++#else
++ SOCKET socket; /**< it's set, if the protocol is SOCKET or TCP */
+ HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */
+ #endif
+ } MYSQL_PLUGIN_VIO_INFO;
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql/plugin_auth.h mariadb-native-client.trunk/include/mysql/plugin_auth.h
+--- mariadb/include/mysql/plugin_auth.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql/plugin_auth.h 2013-10-19 07:29:16.000000000 +0200
@@ -33,7 +33,7 @@
/**
@@ -1131,10 +2732,9 @@
but it will use the data at mysql->net.read_pos.
A plugin may return this value if the number of roundtrips in the
-
-=== modified file 'include/mysql_com.h'
---- mariadb/include/mysql_com.h 2012-11-27 08:57:10 +0000
-+++ mariadb/include/mysql_com.h 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql_com.h mariadb-native-client.trunk/include/mysql_com.h
+--- mariadb/include/mysql_com.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql_com.h 2013-10-19 07:29:16.000000000 +0200
@@ -48,6 +48,12 @@
#define MYSQL_SERVICENAME "MySql"
#endif /* _WIN32 */
@@ -1148,15 +2748,42 @@
enum enum_server_command
{
-@@ -147,7 +153,6 @@
+@@ -143,11 +149,12 @@
+ #define CLIENT_MULTI_RESULTS (1UL << 17)
+ #define CLIENT_PS_MULTI_RESULTS (1UL << 18)
+ #define CLIENT_PLUGIN_AUTH (1UL << 19)
++#define CLIENT_CONNECT_ATTRS (1UL << 20)
+ #define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
++#define CLIENT_REMEMBER_OPTIONS (1UL << 31)
#define CLIENT_SUPPORTED_FLAGS (CLIENT_LONG_PASSWORD | \
- CLIENT_LONG_PASSWORD |\
CLIENT_FOUND_ROWS |\
CLIENT_LONG_FLAG |\
CLIENT_CONNECT_WITH_DB |\
-@@ -189,7 +194,9 @@
+@@ -166,7 +173,9 @@
+ CLIENT_MULTI_STATEMENTS |\
+ CLIENT_MULTI_RESULTS |\
+ CLIENT_PROGRESS |\
+- CLIENT_SSL_VERIFY_SERVER_CERT)
++ CLIENT_SSL_VERIFY_SERVER_CERT |\
++ CLIENT_REMEMBER_OPTIONS |\
++ CLIENT_CONNECT_ATTRS)
+
+ #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD |\
+ CLIENT_LONG_FLAG |\
+@@ -175,7 +184,8 @@
+ CLIENT_MULTI_RESULTS | \
+ CLIENT_PS_MULTI_RESULTS |\
+ CLIENT_PROTOCOL_41 |\
+- CLIENT_PLUGIN_AUTH)
++ CLIENT_PLUGIN_AUTH |\
++ CLIENT_CONNECT_ATTRS)
+
+ #define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\
+ & ~CLIENT_SSL)
+@@ -189,7 +199,9 @@
#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256
#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
@@ -1167,7 +2794,23 @@
#define MYSQL_ERRMSG_SIZE 512
#define NET_READ_TIMEOUT 30 /* Timeout on read */
-@@ -215,7 +222,6 @@
+@@ -209,13 +221,22 @@
+ #define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */
+ #define MAX_BLOB_WIDTH 8192 /* Default width for blob */
+
++/* the following defines were added for PHP's mysqli and pdo extensions:
++ see: CONC-56
++*/
++#define MAX_TINYINT_WIDTH 3
++#define MAX_SMALLINT_WIDTH 5
++#define MAX_MEDIUMINT_WIDTH 8
++#define MAX_INT_WIDTH 10
++#define MAX_BIGINT_WIDTH 20
++
++
+ typedef struct st_net {
+ Vio *vio;
+ unsigned char *buff;
unsigned char *buff_end,*write_pos,*read_pos;
my_socket fd; /* For Perl DBI/dbd */
unsigned long remain_in_buf,length;
@@ -1175,10 +2818,26 @@
unsigned long buf_length, where_b;
unsigned long max_packet, max_packet_size;
unsigned int pkt_nr, compress_pkt_nr;
-
-=== modified file 'include/mysqld_error.h'
---- mariadb/include/mysqld_error.h 2012-11-14 17:43:45 +0000
-+++ mariadb/include/mysqld_error.h 2013-03-14 21:01:43 +0000
+@@ -309,7 +330,7 @@
+ int my_net_write(NET *net,const char *packet, size_t len);
+ int net_write_command(NET *net,unsigned char command,const char *packet,
+ size_t len);
+-int net_real_write(NET *net,const char *packet,unsigned long len);
++int net_real_write(NET *net,const char *packet, size_t len);
+ unsigned long my_net_read(NET *net);
+
+ struct rand_struct {
+@@ -368,7 +389,6 @@
+
+ /* Some other useful functions */
+
+-void my_init(void);
+ void load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv);
+ my_bool my_thread_init(void);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysqld_error.h mariadb-native-client.trunk/include/mysqld_error.h
+--- mariadb/include/mysqld_error.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysqld_error.h 2013-10-19 07:29:16.000000000 +0200
@@ -1,8 +1,9 @@
-/* This file is automaticly generated from errmsg.sys ; Do not edit! */
-/* mysqld server error messagenumbers */
@@ -1881,55 +3540,2102 @@
+#define ER_NO_SUCH_TABLE_IN_ENGINE 1932
+#define ER_GEOMETRY_SRID_MISMATCH 1933
+#define ER_NO_SUCH_SPATIAL_REF_ID 1934
-
-=== renamed directory 'libmysql' => 'libmariadb'
-=== modified file 'libmariadb/CMakeLists.txt'
---- mariadb/libmysql/CMakeLists.txt 2012-11-29 00:58:44 +0000
-+++ mariadb/libmariadb/CMakeLists.txt 2013-03-14 21:01:43 +0000
-@@ -1,9 +1,13 @@
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
- ${ZLIB_INC}
-- ${CMAKE_SOURCE_DIR}/libmysql)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql.h mariadb-native-client.trunk/include/mysql.h
+--- mariadb/include/mysql.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql.h 2013-10-19 07:29:16.000000000 +0200
+@@ -1,5 +1,6 @@
+ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
++ 2012 by MontyProgram AB
++
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+@@ -15,29 +16,26 @@
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+-/* defines for the libmysql library */
++/* defines for the libmariadb library */
+
+ #ifndef _mysql_h
+ #define _mysql_h
+
+-#ifndef MYSQL_SERVER
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
++
++#ifndef LIBMARIADB
++#define LIBMARIADB
+ #endif
+
+-
+ #ifndef _global_h /* If not standard header */
+ #include <sys/types.h>
+-#ifdef __LCC__
+-#include <winsock2.h> /* For windows */
+-#endif
+ typedef char my_bool;
+
+ #if !defined(_WIN32)
+ #define STDCALL
+ #else
+-#include <WinSock2.h>
+ #define STDCALL __stdcall
+ #endif
+ typedef char * gptr;
+@@ -46,8 +44,10 @@
+
+ #ifndef my_socket_defined
+ #define my_socket_defined
+-#ifdef _WIN32
+-#define my_socket SOCKET
++#if defined(_WIN64)
++#define my_socket unsigned long long
++#elif defined(_WIN32)
++#define my_socket unsigned int
+ #else
+ typedef int my_socket;
+ #endif
+@@ -56,25 +56,26 @@
+ #include "mysql_com.h"
+ #include "mysql_version.h"
+ #include "my_list.h"
++#include "m_ctype.h"
+
+ #ifndef ST_USED_MEM_DEFINED
+ #define ST_USED_MEM_DEFINED
+-typedef struct st_used_mem { /* struct for once_alloc */
+- struct st_used_mem *next; /* Next block in use */
+- size_t left; /* memory left in block */
+- size_t size; /* Size of block */
+-} USED_MEM;
+-
+-typedef struct st_mem_root {
+- USED_MEM *free;
+- USED_MEM *used;
+- USED_MEM *pre_alloc;
+- size_t min_malloc;
+- size_t block_size;
+- unsigned int block_num;
+- unsigned int first_block_usage;
+- void (*error_handler)(void);
+-} MEM_ROOT;
++ typedef struct st_used_mem { /* struct for once_alloc */
++ struct st_used_mem *next; /* Next block in use */
++ size_t left; /* memory left in block */
++ size_t size; /* Size of block */
++ } USED_MEM;
++
++ typedef struct st_mem_root {
++ USED_MEM *free;
++ USED_MEM *used;
++ USED_MEM *pre_alloc;
++ size_t min_malloc;
++ size_t block_size;
++ unsigned int block_num;
++ unsigned int first_block_usage;
++ void (*error_handler)(void);
++ } MEM_ROOT;
+ #endif
+
+ extern unsigned int mysql_port;
+@@ -87,203 +88,214 @@
+ #define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG)
+ #define INTERNAL_NUM_FIELD(f) (((f)->type <= MYSQL_TYPE_INT24 && ((f)->type != MYSQL_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == MYSQL_TYPE_YEAR)
+
+-typedef struct st_mysql_field {
+- char *name; /* Name of column */
+- char *org_name; /* Name of original column (added after 3.23.58) */
+- char *table; /* Table of column if column was a field */
+- char *org_table; /* Name of original table (added after 3.23.58 */
+- char *db; /* table schema (added after 3.23.58) */
+- char *catalog; /* table catalog (added after 3.23.58) */
+- char *def; /* Default value (set by mysql_list_fields) */
+- unsigned long length; /* Width of column */
+- unsigned long max_length; /* Max width of selected set */
+-/* added after 3.23.58 */
+- unsigned int name_length;
+- unsigned int org_name_length;
+- unsigned int table_length;
+- unsigned int org_table_length;
+- unsigned int db_length;
+- unsigned int catalog_length;
+- unsigned int def_length;
+-/***********************/
+- unsigned int flags; /* Div flags */
+- unsigned int decimals; /* Number of decimals in field */
+- unsigned int charsetnr; /* char set number (added in 4.1) */
+- enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
+- void *extension; /* added in 4.1 */
+-} MYSQL_FIELD;
++ typedef struct st_mysql_field {
++ char *name; /* Name of column */
++ char *org_name; /* Name of original column (added after 3.23.58) */
++ char *table; /* Table of column if column was a field */
++ char *org_table; /* Name of original table (added after 3.23.58 */
++ char *db; /* table schema (added after 3.23.58) */
++ char *catalog; /* table catalog (added after 3.23.58) */
++ char *def; /* Default value (set by mysql_list_fields) */
++ unsigned long length; /* Width of column */
++ unsigned long max_length; /* Max width of selected set */
++ /* added after 3.23.58 */
++ unsigned int name_length;
++ unsigned int org_name_length;
++ unsigned int table_length;
++ unsigned int org_table_length;
++ unsigned int db_length;
++ unsigned int catalog_length;
++ unsigned int def_length;
++ /***********************/
++ unsigned int flags; /* Div flags */
++ unsigned int decimals; /* Number of decimals in field */
++ unsigned int charsetnr; /* char set number (added in 4.1) */
++ enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
++ void *extension; /* added in 4.1 */
++ } MYSQL_FIELD;
+
+-typedef char **MYSQL_ROW; /* return data as array of strings */
+-typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
++ typedef char **MYSQL_ROW; /* return data as array of strings */
++ typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
+
+ #if defined(NO_CLIENT_LONG_LONG)
+-typedef unsigned long my_ulonglong;
++ typedef unsigned long my_ulonglong;
+ #elif defined (_WIN32)
+-typedef unsigned __int64 my_ulonglong;
++ typedef unsigned __int64 my_ulonglong;
+ #else
+-typedef unsigned long long my_ulonglong;
++ typedef unsigned long long my_ulonglong;
+ #endif
+
++#ifndef longlong_defined
++#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8
++typedef long long int longlong;
++#else
++typedef long longlong;
++#endif
++#define longlong_defined
++#endif
++
++
+
+ #define SET_CLIENT_ERROR(a, b, c, d) \
+-{ \
+- (a)->net.last_errno= (b);\
+- strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\
+- strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\
+-}
++ { \
++ (a)->net.last_errno= (b);\
++ strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\
++ strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\
++ }
+
+ #define CLEAR_CLIENT_ERROR(a) \
+-{ \
+- (a)->net.last_errno= 0;\
+- strcpy((a)->net.sqlstate, "00000");\
+- (a)->net.last_error[0]= '\0';\
+-}
++ { \
++ (a)->net.last_errno= 0;\
++ strcpy((a)->net.sqlstate, "00000");\
++ (a)->net.last_error[0]= '\0';\
++ }
+
+ #define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
+
+
+-typedef struct st_mysql_rows {
+- struct st_mysql_rows *next; /* list of rows */
+- MYSQL_ROW data;
+- unsigned long length;
+-} MYSQL_ROWS;
+-
+-typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
+-
+-typedef struct st_mysql_data {
+- my_ulonglong rows;
+- unsigned int fields;
+- MYSQL_ROWS *data;
+- MEM_ROOT alloc;
+-} MYSQL_DATA;
+-
+-enum mysql_option
+-{
+- MYSQL_OPT_CONNECT_TIMEOUT,
+- MYSQL_OPT_COMPRESS,
+- MYSQL_OPT_NAMED_PIPE,
+- MYSQL_INIT_COMMAND,
+- MYSQL_READ_DEFAULT_FILE,
+- MYSQL_READ_DEFAULT_GROUP,
+- MYSQL_SET_CHARSET_DIR,
+- MYSQL_SET_CHARSET_NAME,
+- MYSQL_OPT_LOCAL_INFILE,
+- MYSQL_OPT_PROTOCOL,
+- MYSQL_SHARED_MEMORY_BASE_NAME,
+- MYSQL_OPT_READ_TIMEOUT,
+- MYSQL_OPT_WRITE_TIMEOUT,
+- MYSQL_OPT_USE_RESULT,
+- MYSQL_OPT_USE_REMOTE_CONNECTION,
+- MYSQL_OPT_USE_EMBEDDED_CONNECTION,
+- MYSQL_OPT_GUESS_CONNECTION,
+- MYSQL_SET_CLIENT_IP,
+- MYSQL_SECURE_AUTH,
+- MYSQL_REPORT_DATA_TRUNCATION,
+- MYSQL_OPT_RECONNECT,
+- MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+- MYSQL_OPT_PLUGIN_DIR,
+- MYSQL_OPT_DEFAULT_AUTH,
+- MYSQL_OPT_PROGRESS_CALLBACK
+-};
+-
+-enum mysql_status { MYSQL_STATUS_READY,
+- MYSQL_STATUS_GET_RESULT,
+- MYSQL_STATUS_USE_RESULT,
+- MYSQL_STATUS_QUERY_SENT,
+- MYSQL_STATUS_SENDING_LOAD_DATA,
+- MYSQL_STATUS_FETCHING_DATA,
+- MYSQL_STATUS_NEXT_RESULT_PENDING,
+- MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */
+-};
++ typedef struct st_mysql_rows {
++ struct st_mysql_rows *next; /* list of rows */
++ MYSQL_ROW data;
++ unsigned long length;
++ } MYSQL_ROWS;
++
++ typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
++
++ typedef struct st_mysql_data {
++ my_ulonglong rows;
++ unsigned int fields;
++ MYSQL_ROWS *data;
++ MEM_ROOT alloc;
++ } MYSQL_DATA;
++
++ enum mysql_option
++ {
++ MYSQL_OPT_CONNECT_TIMEOUT,
++ MYSQL_OPT_COMPRESS,
++ MYSQL_OPT_NAMED_PIPE,
++ MYSQL_INIT_COMMAND,
++ MYSQL_READ_DEFAULT_FILE,
++ MYSQL_READ_DEFAULT_GROUP,
++ MYSQL_SET_CHARSET_DIR,
++ MYSQL_SET_CHARSET_NAME,
++ MYSQL_OPT_LOCAL_INFILE,
++ MYSQL_OPT_PROTOCOL,
++ MYSQL_SHARED_MEMORY_BASE_NAME,
++ MYSQL_OPT_READ_TIMEOUT,
++ MYSQL_OPT_WRITE_TIMEOUT,
++ MYSQL_OPT_USE_RESULT,
++ MYSQL_OPT_USE_REMOTE_CONNECTION,
++ MYSQL_OPT_USE_EMBEDDED_CONNECTION,
++ MYSQL_OPT_GUESS_CONNECTION,
++ MYSQL_SET_CLIENT_IP,
++ MYSQL_SECURE_AUTH,
++ MYSQL_REPORT_DATA_TRUNCATION,
++ MYSQL_OPT_RECONNECT,
++ MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
++ MYSQL_PLUGIN_DIR,
++ MYSQL_DEFAULT_AUTH,
++ MYSQL_OPT_BIND,
++ MYSQL_OPT_SSL_KEY,
++ MYSQL_OPT_SSL_CERT,
++ MYSQL_OPT_SSL_CA,
++ MYSQL_OPT_SSL_CAPATH,
++ MYSQL_OPT_SSL_CIPHER,
++ MYSQL_OPT_SSL_CRL,
++ MYSQL_OPT_SSL_CRLPATH,
++ /* Connection attribute options */
++ MYSQL_OPT_CONNECT_ATTR_RESET,
++ MYSQL_OPT_CONNECT_ATTR_ADD,
++ MYSQL_OPT_CONNECT_ATTR_DELETE,
++
++ /* MariaDB specific */
++ MYSQL_PROGRESS_CALLBACK=5999,
++ MYSQL_DATABASE_DRIVER=7000
++ };
++
++ enum mysql_status { MYSQL_STATUS_READY,
++ MYSQL_STATUS_GET_RESULT,
++ MYSQL_STATUS_USE_RESULT,
++ MYSQL_STATUS_QUERY_SENT,
++ MYSQL_STATUS_SENDING_LOAD_DATA,
++ MYSQL_STATUS_FETCHING_DATA,
++ MYSQL_STATUS_NEXT_RESULT_PENDING,
++ MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */
++ };
++
++ enum mysql_protocol_type
++ {
++ MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET,
++ MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
++ };
+
+-enum mysql_protocol_type
+-{
+- MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET,
+- MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
+-};
++struct st_mysql_options_extention;
+
+ struct st_mysql_options {
+- unsigned int connect_timeout, read_timeout, write_timeout;
+- unsigned int port, protocol;
+- unsigned long client_flag;
+- char *host,*user,*password,*unix_socket,*db;
+- char *init_command;
+- char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
+- char *ssl_key; /* PEM key file */
+- char *ssl_cert; /* PEM cert file */
+- char *ssl_ca; /* PEM CA file */
+- char *ssl_capath; /* PEM directory of CA-s? */
+- char *ssl_cipher;
+- char *shared_memory_base_name;
+- unsigned long max_allowed_packet;
+- my_bool use_ssl; /* if to use SSL or not */
+- my_bool compress,named_pipe;
+- my_bool unused_1, unused_2, unused_3, unused_4;
+- enum mysql_option methods_to_use;
+- char *client_ip;
+- my_bool secure_auth;
+- my_bool report_data_truncation;
+- /* function pointers for local infile support */
+- int (*local_infile_init)(void **, const char *, void *);
+- int (*local_infile_read)(void *, char *, unsigned int);
+- void (*local_infile_end)(void *);
+- int (*local_infile_error)(void *, char *, unsigned int);
+- void *local_infile_userdata;
+- struct st_mysql_options_extention *extension;
++ unsigned int connect_timeout, read_timeout, write_timeout;
++ unsigned int port, protocol;
++ unsigned long client_flag;
++ char *host,*user,*password,*unix_socket,*db;
++ struct st_dynamic_array *init_command;
++ char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
++ char *ssl_key; /* PEM key file */
++ char *ssl_cert; /* PEM cert file */
++ char *ssl_ca; /* PEM CA file */
++ char *ssl_capath; /* PEM directory of CA-s? */
++ char *ssl_cipher;
++ char *shared_memory_base_name;
++ unsigned long max_allowed_packet;
++ my_bool use_ssl; /* if to use SSL or not */
++ my_bool compress,named_pipe;
++ my_bool unused_1, unused_2, unused_3, unused_4;
++ enum mysql_option methods_to_use;
++ char *client_ip;
++ my_bool secure_auth;
++ my_bool report_data_truncation;
++ /* function pointers for local infile support */
++ int (*local_infile_init)(void **, const char *, void *);
++ int (*local_infile_read)(void *, char *, unsigned int);
++ void (*local_infile_end)(void *);
++ int (*local_infile_error)(void *, char *, unsigned int);
++ void *local_infile_userdata;
++ struct st_mysql_options_extention *extension;
+ };
+
+-typedef struct st_mysql {
+- NET net; /* Communication parameters */
+- unsigned char *unused;
+- char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
+- char *info,*db;
+- const struct charset_info_st *charset; /* character set */
+- MYSQL_FIELD *fields;
+- MEM_ROOT field_alloc;
+- my_ulonglong affected_rows;
+- my_ulonglong insert_id; /* id if insert on table with NEXTNR */
+- my_ulonglong extra_info; /* Used by mysqlshow */
+- unsigned long thread_id; /* Id for connection in server */
+- unsigned long packet_length;
+- unsigned int port;
+- unsigned long client_flag,server_capabilities; /* changed from int to long in 4.1 protocol */
+- unsigned int protocol_version;
+- unsigned int field_count;
+- unsigned int server_status;
+- unsigned int server_language;
+- unsigned int warning_count; /* warning count, added in 4.1 protocol */
+- struct st_mysql_options options;
+- enum mysql_status status;
+- my_bool free_me; /* If free in mysql_close */
+- my_bool reconnect; /* set to 1 if automatic reconnect */
+- char scramble_buff[20+ 1];
+- /* madded after 3.23.58 */
+- my_bool unused_1;
+- void *unused_2, *unused_3, *unused_4, *unused_5;
+- LIST *stmts;
+- const struct st_mysql_methods *methods;
+- void *thd;
+- my_bool *unbuffered_fetch_owner;
+- char *info_buffer;
+- void *extension;
++ typedef struct st_mysql {
++ NET net; /* Communication parameters */
++ void *unused_0;
++ char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
++ char *info,*db;
++ const struct charset_info_st *charset; /* character set */
++ MYSQL_FIELD *fields;
++ MEM_ROOT field_alloc;
++ my_ulonglong affected_rows;
++ my_ulonglong insert_id; /* id if insert on table with NEXTNR */
++ my_ulonglong extra_info; /* Used by mysqlshow */
++ unsigned long thread_id; /* Id for connection in server */
++ unsigned long packet_length;
++ unsigned int port;
++ unsigned long client_flag,server_capabilities; /* changed from int to long in 4.1 protocol */
++ unsigned int protocol_version;
++ unsigned int field_count;
++ unsigned int server_status;
++ unsigned int server_language;
++ unsigned int warning_count; /* warning count, added in 4.1 protocol */
++ struct st_mysql_options options;
++ enum mysql_status status;
++ my_bool free_me; /* If free in mysql_close */
++ my_bool reconnect; /* set to 1 if automatic reconnect */
++ char scramble_buff[20+ 1];
++ /* madded after 3.23.58 */
++ my_bool unused_1;
++ void *unused_2, *unused_3, *unused_4, *unused_5;
++ LIST *stmts;
++ const struct st_mysql_methods *methods;
++ void *thd;
++ my_bool *unbuffered_fetch_owner;
++ char *info_buffer;
++ void *extension;
+ } MYSQL;
+
+-typedef struct st_mysql_lex_string {
+- char *str;
+- size_t length;
+-} MYSQL_LEX_STRING;
+-
+-struct st_mysql_options_extention {
+- char *plugin_dir;
+- char *default_auth;
+- void (*report_progress)(const MYSQL *mysql,
+- unsigned int stage,
+- unsigned int max_stage,
+- double progress,
+- const char *proc_info,
+- unsigned int proc_info_length);
+-};
+-
+ typedef struct st_mysql_res {
+ my_ulonglong row_count;
+ unsigned int field_count, current_field;
+@@ -305,6 +317,7 @@
+ MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2
+ };
+
++
+ typedef struct st_mysql_time
+ {
+ unsigned int year, month, day, hour, minute, second;
+@@ -313,6 +326,9 @@
+ enum enum_mysql_timestamp_type time_type;
+ } MYSQL_TIME;
+
++#define AUTO_SEC_PART_DIGITS 31
++#define SEC_PART_DIGITS 6
++
+ typedef struct character_set
+ {
+ unsigned int number; /* character set number */
+@@ -325,6 +341,16 @@
+ unsigned int mbmaxlen; /* max. length for multibyte strings */
+ } MY_CHARSET_INFO;
+
++typedef struct
++{
++ unsigned long *p_max_allowed_packet;
++ unsigned long *p_net_buffer_length;
++ void *extension;
++} MYSQL_PARAMETERS;
++
++#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length)
++#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet)
++
+ /* Local infile support functions */
+ #define LOCAL_INFILE_ERROR_LEN 512
+
+@@ -370,7 +396,7 @@
+ MYSQL * STDCALL mysql_init(MYSQL *mysql);
+ int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
+ const char *cert, const char *ca,
+- const char *capath);
++ const char *capath, const char *cipher);
+ const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql);
+ int STDCALL mysql_ssl_clear(MYSQL *mysql);
+ MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
+@@ -388,13 +414,13 @@
+ int STDCALL mysql_select_db(MYSQL *mysql, const char *db);
+ int STDCALL mysql_query(MYSQL *mysql, const char *q);
+ int STDCALL mysql_send_query(MYSQL *mysql, const char *q,
+- unsigned int length);
+-int STDCALL mysql_read_query_result(MYSQL *mysql);
++ unsigned long length);
++my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
+ int STDCALL mysql_real_query(MYSQL *mysql, const char *q,
+- unsigned int length);
++ unsigned long length);
+ int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
+ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
+-int STDCALL mysql_shutdown(MYSQL *mysql);
++int STDCALL mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level);
+ int STDCALL mysql_dump_debug_info(MYSQL *mysql);
+ int STDCALL mysql_refresh(MYSQL *mysql,
+ unsigned int refresh_options);
+@@ -413,7 +439,7 @@
+ MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
+ MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
+ int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
+- const char *arg);
++ const void *arg);
+ void STDCALL mysql_free_result(MYSQL_RES *result);
+ void STDCALL mysql_data_seek(MYSQL_RES *result,
+ my_ulonglong offset);
+@@ -430,7 +456,7 @@
+ unsigned long length);
+ void STDCALL mysql_debug(const char *debug);
+ #define mysql_debug_init(A) mysql_debug((A));
+-void STDCALL mysql_debug_end();
++void STDCALL mysql_debug_end(void);
+ void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
+ unsigned int STDCALL mysql_thread_safe(void);
+ unsigned int STDCALL mysql_warning_count(MYSQL *mysql);
+@@ -443,10 +469,45 @@
+ enum enum_mysql_set_option option);
+ const char * STDCALL mysql_get_client_info(void);
+ unsigned long STDCALL mysql_get_client_version(void);
++my_bool STDCALL mariadb_connection(MYSQL *mysql);
++const char * STDCALL mysql_get_server_name(MYSQL *mysql);
++CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *csname);
++CHARSET_INFO * STDCALL mysql_get_charset_by_nr(unsigned int csnr);
++size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs,
++ char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode);
++int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
++ const void *arg1, const void *arg2);
++MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void);
+
+ #include <my_stmt.h>
+
++/* these methods can be overwritten by db plugins */
++struct st_mysql_methods {
++ MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd,
++ const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag);
++ void (*db_close)(MYSQL *mysql);
++ int (*db_command)(MYSQL *mysql,enum enum_server_command command, const char *arg,
++ size_t length, my_bool skipp_check, void *opt_arg);
++ void (*db_skip_result)(MYSQL *mysql);
++ int (*db_read_query_result)(MYSQL *mysql);
++ MYSQL_DATA *(*db_read_rows)(MYSQL *mysql,MYSQL_FIELD *fields, unsigned int field_count);
++ int (*db_read_one_row)(MYSQL *mysql,unsigned int fields,MYSQL_ROW row, unsigned long *lengths);
++ /* prepared statements */
++ my_bool (*db_supported_buffer_type)(enum enum_field_types type);
++ my_bool (*db_read_prepare_response)(MYSQL_STMT *stmt);
++ int (*db_read_stmt_result)(MYSQL *mysql);
++ my_bool (*db_stmt_get_result_metadata)(MYSQL_STMT *stmt);
++ my_bool (*db_stmt_get_param_metadata)(MYSQL_STMT *stmt);
++ int (*db_stmt_read_all_rows)(MYSQL_STMT *stmt);
++ int (*db_stmt_fetch)(MYSQL_STMT *stmt, unsigned char **row);
++ int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row);
++ void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt);
++};
++
++/* synonyms/aliases functions */
+ #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
++#define mysql_library_init mysql_server_init
++#define mysql_library_end mysql_server_end
+
+ /* new api functions */
+
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysql_version.h.in mariadb-native-client.trunk/include/mysql_version.h.in
+--- mariadb/include/mysql_version.h.in 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysql_version.h.in 2013-10-19 07:29:16.000000000 +0200
+@@ -16,6 +16,10 @@
+ #define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@"
+ #define MYSQL_CONFIG_NAME "my"
+
++#define MARIADB_PACKAGE_VERSION "@CPACK_PACKAGE_VERSION@"
++#define MARIADB_SYSTEM_TYPE "@CMAKE_SYSTEM_NAME@"
++#define MARIADB_MACHINE_TYPE "@CMAKE_SYSTEM_PROCESSOR@"
++
+ /* mysqld compile time options */
+ #ifndef MYSQL_CHARSET
+ #define MYSQL_CHARSET "@default_charset@"
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_stmt.h mariadb-native-client.trunk/include/my_stmt.h
+--- mariadb/include/my_stmt.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_stmt.h 2013-10-19 07:29:16.000000000 +0200
+@@ -77,8 +77,6 @@
+ MYSQL_STMT_FETCH_DONE
+ } enum_mysqlnd_stmt_state;
+
+-
+-
+ typedef struct st_mysql_bind
+ {
+ unsigned long *length; /* output length pointer */
+@@ -198,7 +196,7 @@
+
+ my_bool cursor_exists;
+
+- MYSQL_CMD_BUFFER cmd_buffer;
++ void *extension;
+ mysql_stmt_fetch_row_func fetch_row_func;
+ unsigned int execute_count;/* count how many times the stmt was executed */
+ mysql_stmt_use_or_store_func default_rset_handler;
+@@ -206,18 +204,19 @@
+ };
+
+ typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row);
+-struct st_mysql_perm_bind {
++typedef struct st_mysql_perm_bind {
+ ps_field_fetch_func func;
+ /* should be signed int */
+ int pack_len;
+ unsigned long max_len;
+-};
++} MYSQL_PS_CONVERSION;
+
+-extern struct st_mysql_perm_bind mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
++extern MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
+ unsigned long net_safe_read(MYSQL *mysql);
+ void mysql_init_ps_subsystem(void);
+ unsigned long net_field_length(unsigned char **packet);
+-int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check);
++int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
++ size_t length, my_bool skipp_check, void *opt_arg);
+ /*
+ * function prototypes
+ */
+@@ -248,10 +247,5 @@
+ my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt);
+ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt);
+ unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt);
+-my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt);
+-MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt);
+-MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET new_row);
+-unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT *stmt);
+-my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length);
+-my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt);
+-my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt);
++int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt);
++my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/mysys_err.h mariadb-native-client.trunk/include/mysys_err.h
+--- mariadb/include/mysys_err.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/mysys_err.h 2013-10-19 07:29:16.000000000 +0200
+@@ -22,38 +22,46 @@
+ #endif
+
+ #define GLOB 0 /* Error maps */
+-#define GLOBERRS 27 /* Max number of error messages in map's */
+-#define EE(X) globerrs[ X ] /* Defines to add error to right map */
++#define GLOBERRS EE_LASTERROR - EE_FIRSTERROR + 1 /* Max number of error messages in map's */
++#define EE(X) globerrs[ (X) - EE_FIRSTERROR ] /* Defines to add error to right map */
+
+ extern const char * NEAR globerrs[]; /* my_error_messages is here */
+
+-/* Error message numbers in global map */
+-#define EE_FILENOTFOUND 0
+-#define EE_CANTCREATEFILE 1
+-#define EE_READ 2
+-#define EE_WRITE 3
+-#define EE_BADCLOSE 4
+-#define EE_OUTOFMEMORY 5
+-#define EE_DELETE 6
+-#define EE_LINK 7
+-#define EE_EOFERR 9
+-#define EE_CANTLOCK 10
+-#define EE_CANTUNLOCK 11
+-#define EE_DIR 12
+-#define EE_STAT 13
+-#define EE_CANT_CHSIZE 14
+-#define EE_CANT_OPEN_STREAM 15
+-#define EE_GETWD 16
+-#define EE_SETWD 17
+-#define EE_LINK_WARNING 18
+-#define EE_OPEN_WARNING 19
+-#define EE_DISK_FULL 20
+-#define EE_CANT_MKDIR 21
+-#define EE_UNKNOWN_CHARSET 22
++/* Error message numbers in global map
++
++*/
++#define EE_FIRSTERROR 1
++#define EE_CANTCREATEFILE 1
++#define EE_READ 2
++#define EE_WRITE 3
++#define EE_BADCLOSE 4
++#define EE_OUTOFMEMORY 5
++#define EE_DELETE 6
++#define EE_LINK 7
++#define EE_EOFERR 9
++#define EE_CANTLOCK 10
++#define EE_CANTUNLOCK 11
++#define EE_DIR 12
++#define EE_STAT 13
++#define EE_CANT_CHSIZE 14
++#define EE_CANT_OPEN_STREAM 15
++#define EE_GETWD 16
++#define EE_SETWD 17
++#define EE_LINK_WARNING 18
++#define EE_OPEN_WARNING 19
++#define EE_DISK_FULL 20
++#define EE_CANT_MKDIR 21
++#define EE_UNKNOWN_CHARSET 22
+ #define EE_OUT_OF_FILERESOURCES 23
+-#define EE_CANT_READLINK 24
+-#define EE_CANT_SYMLINK 25
+-#define EE_REALPATH 26
++#define EE_CANT_READLINK 24
++#define EE_CANT_SYMLINK 25
++#define EE_REALPATH 26
++#define EE_SYNC 27
++#define EE_UNKNOWN_COLLATION 28
++#define EE_FILENOTFOUND 29
++#define EE_FILE_NOT_CLOSED 30
++#define EE_CANT_CHMOD 31
++#define EE_LASTERROR 31
+
+ #ifdef __cplusplus
+ }
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/my_sys.h mariadb-native-client.trunk/include/my_sys.h
+--- mariadb/include/my_sys.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/my_sys.h 2013-10-19 07:29:16.000000000 +0200
+@@ -114,22 +114,6 @@
+
+ /* defines when allocating data */
+
+-#ifdef SAFEMALLOC
+-#define my_malloc(SZ,FLAG) _mymalloc( SZ, __FILE__, __LINE__, FLAG )
+-#define my_malloc_ci(SZ,FLAG) _mymalloc( SZ, sFile, uLine, FLAG )
+-#define my_realloc(PTR,SZ,FLAG) _myrealloc( PTR, SZ, __FILE__, __LINE__, FLAG )
+-#define my_checkmalloc() _sanity( __FILE__, __LINE__ )
+-#define my_free(PTR,FLAG) _myfree( PTR, __FILE__, __LINE__,FLAG)
+-#define my_memdup(A,B,C) _my_memdup(A,B,__FILE__,__LINE__,C)
+-#define my_strdup(A,C) _my_strdup(A,__FILE__,__LINE__,C)
+-#define QUICK_SAFEMALLOC sf_malloc_quick=1
+-#define NORMAL_SAFEMALLOC sf_malloc_quick=0
+-extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick;
+-extern ulonglong safemalloc_mem_limit;
+-#define CALLER_INFO_PROTO , const char *sFile, uint uLine
+-#define CALLER_INFO , __FILE__, __LINE__
+-#define ORIG_CALLER_INFO , sFile, uLine
+-#else
+ #define my_checkmalloc() (0)
+ #undef TERMINATE
+ #define TERMINATE(A) {}
+@@ -139,14 +123,13 @@
+ #define my_malloc_ci(SZ,FLAG) my_malloc( SZ, FLAG )
+ extern gptr my_realloc(gptr oldpoint, size_t Size,myf MyFlags);
+ extern void my_no_flags_free(gptr ptr);
+-extern gptr my_memdup(const byte *from, size_t length,myf MyFlags);
++extern gptr my_memdup(const unsigned char *from, size_t length,myf MyFlags);
+ extern my_string my_strdup(const char *from,myf MyFlags);
+ extern my_string my_strndup(const char *from, size_t length, myf MyFlags);
+ #define my_free(PTR,FG) my_no_flags_free(PTR)
+ #define CALLER_INFO_PROTO /* nothing */
+ #define CALLER_INFO /* nothing */
+ #define ORIG_CALLER_INFO /* nothing */
+-#endif
+
+ #ifdef HAVE_ALLOCA
+ #if defined(_AIX) && !defined(__GNUC__)
+@@ -178,11 +161,13 @@
+ #endif
+ #endif /* MSDOS */
+
++#ifndef errno
+ #ifdef HAVE_ERRNO_AS_DEFINE
+ #include <errno.h> /* errno is a define */
+ #else
+ extern int errno; /* declare errno */
+ #endif
++#endif
+ extern const char ** NEAR my_errmsg[];
+ extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
+ extern char *home_dir; /* Home directory for user */
+@@ -261,7 +246,7 @@
+ int rc_seek,error,inited;
+ uint rc_length,read_length,reclength;
+ my_off_t rc_record_pos,end_of_file;
+- byte *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
++ unsigned char *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
+ #ifdef HAVE_AIOWAIT
+ int use_async_io;
+ my_aio_result aio_result;
+@@ -298,8 +283,8 @@
+ typedef struct st_io_cache /* Used when cacheing files */
+ {
+ my_off_t pos_in_file,end_of_file;
+- byte *rc_pos,*rc_end,*buffer,*rc_request_pos;
+- int (*read_function)(struct st_io_cache *,byte *,uint);
++ unsigned char *rc_pos,*rc_end,*buffer,*rc_request_pos;
++ int (*read_function)(struct st_io_cache *,unsigned char *,uint);
+ char *file_name; /* if used with 'open_cached_file' */
+ char *dir,*prefix;
+ File file;
+@@ -414,18 +399,18 @@
+ extern int my_delete_with_symlink(const char *name, myf MyFlags);
+ extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags);
+ extern int my_symlink(const char *content, const char *linkname, myf MyFlags);
+-extern uint my_read(File Filedes,byte *Buffer,uint Count,myf MyFlags);
+-extern uint my_pread(File Filedes,byte *Buffer,uint Count,my_off_t offset,
++extern uint my_read(File Filedes,unsigned char *Buffer,uint Count,myf MyFlags);
++extern uint my_pread(File Filedes,unsigned char *Buffer,uint Count,my_off_t offset,
+ myf MyFlags);
+ extern int my_rename(const char *from,const char *to,myf MyFlags);
+ extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags);
+ extern my_off_t my_tell(File fd,myf MyFlags);
+-extern uint my_write(File Filedes,const byte *Buffer,uint Count,
++extern uint my_write(File Filedes,const unsigned char *Buffer,uint Count,
+ myf MyFlags);
+-extern uint my_pwrite(File Filedes,const byte *Buffer,uint Count,
++extern uint my_pwrite(File Filedes,const unsigned char *Buffer,uint Count,
+ my_off_t offset,myf MyFlags);
+-extern uint my_fread(FILE *stream,byte *Buffer,uint Count,myf MyFlags);
+-extern uint my_fwrite(FILE *stream,const byte *Buffer,uint Count,
++extern uint my_fread(FILE *stream,unsigned char *Buffer,uint Count,myf MyFlags);
++extern uint my_fwrite(FILE *stream,const unsigned char *Buffer,uint Count,
+ myf MyFlags);
+ extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags);
+ extern my_off_t my_ftell(FILE *stream,myf MyFlags);
+@@ -436,7 +421,7 @@
+ extern gptr my_multi_malloc _VARARGS((myf MyFlags, ...));
+ extern void _myfree(gptr pPtr,const char *sFile,uint uLine, myf MyFlag);
+ extern int _sanity(const char *sFile,unsigned int uLine);
+-extern gptr _my_memdup(const byte *from, size_t length,
++extern gptr _my_memdup(const unsigned char *from, size_t length,
+ const char *sFile, uint uLine,myf MyFlag);
+ extern my_string _my_strdup(const char *from, const char *sFile, uint uLine,
+ myf MyFlag);
+@@ -517,18 +502,18 @@
+ extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file,
+ uint reclength,enum cache_type type,
+ pbool use_async_io);
+-extern int read_cache_record(RECORD_CACHE *info,byte *to);
++extern int read_cache_record(RECORD_CACHE *info,unsigned char *to);
+ extern int end_record_cache(RECORD_CACHE *info);
+ extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos,
+- const byte *record,uint length);
++ const unsigned char *record,uint length);
+ extern int flush_write_cache(RECORD_CACHE *info);
+ extern long my_clock(void);
+ extern sig_handler sigtstp_handler(int signal_number);
+ extern void handle_recived_signals(void);
+ extern int init_key_cache(ulong use_mem,ulong leave_this_much_mem);
+-extern byte *key_cache_read(File file,my_off_t filepos,byte* buff,uint length,
++extern unsigned char *key_cache_read(File file,my_off_t filepos,unsigned char* buff,uint length,
+ uint block_length,int return_buffer);
+-extern int key_cache_write(File file,my_off_t filepos,byte* buff,uint length,
++extern int key_cache_write(File file,my_off_t filepos,unsigned char* buff,uint length,
+ uint block_length,int force_write);
+ extern int flush_key_blocks(int file, enum flush_type type);
+ extern void end_key_cache(void);
+@@ -545,12 +530,12 @@
+ extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type,
+ my_off_t seek_offset,pbool use_async_io,
+ pbool clear_cache);
+-extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count);
+-extern int _my_b_net_read(IO_CACHE *info,byte *Buffer,uint Count);
++extern int _my_b_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
++extern int _my_b_net_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
+ extern int _my_b_get(IO_CACHE *info);
+-extern int _my_b_async_read(IO_CACHE *info,byte *Buffer,uint Count);
+-extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
+-extern int my_block_write(IO_CACHE *info, const byte *Buffer,
++extern int _my_b_async_read(IO_CACHE *info,unsigned char *Buffer,uint Count);
++extern int _my_b_write(IO_CACHE *info,const unsigned char *Buffer,uint Count);
++extern int my_block_write(IO_CACHE *info, const unsigned char *Buffer,
+ uint Count, my_off_t pos);
+ extern int flush_io_cache(IO_CACHE *info);
+ extern int end_io_cache(IO_CACHE *info);
+@@ -571,8 +556,8 @@
+ extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
+ uint init_alloc,uint alloc_increment CALLER_INFO_PROTO);
+ extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element);
+-extern byte *alloc_dynamic(DYNAMIC_ARRAY *array);
+-extern byte *pop_dynamic(DYNAMIC_ARRAY*);
++extern unsigned char *alloc_dynamic(DYNAMIC_ARRAY *array);
++extern unsigned char *pop_dynamic(DYNAMIC_ARRAY*);
+ extern my_bool set_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
+ extern void get_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
+ extern void delete_dynamic(DYNAMIC_ARRAY *array);
+@@ -591,15 +576,15 @@
+ my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
+ size_t length);
+ extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str);
+-extern my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size);
++extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size);
+ extern void dynstr_free(DYNAMIC_STRING *str);
+ void set_all_changeable_vars(CHANGEABLE_VAR *vars);
+ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars);
+ my_bool set_changeable_varval(const char *var, ulong val,
+ CHANGEABLE_VAR *vars);
+ #ifdef HAVE_MLOCK
+-extern byte *my_malloc_lock(size_t length,myf flags);
+-extern void my_free_lock(byte *ptr,myf flags);
++extern unsigned char *my_malloc_lock(size_t length,myf flags);
++extern void my_free_lock(unsigned char *ptr,myf flags);
+ #else
+ #define my_malloc_lock(A,B) my_malloc((A),(B))
+ #define my_free_lock(A,B) my_free((A),(B))
+@@ -614,10 +599,10 @@
+ int *argc, char ***argv);
+ void free_defaults(char **argv);
+ void print_defaults(const char *conf_file, const char **groups);
+-my_bool my_compress(byte *, ulong *, ulong *);
+-my_bool my_uncompress(byte *, ulong *, ulong *);
+-byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
+-ulong checksum(const byte *mem, uint count);
++my_bool my_compress(unsigned char *, size_t *, size_t *);
++my_bool my_uncompress(unsigned char *, size_t *, size_t *);
++unsigned char *my_compress_alloc(const unsigned char *packet, size_t *len, size_t *complen);
++ulong checksum(const unsigned char *mem, uint count);
+
+ #if defined(_MSC_VER) && !defined(_WIN32)
+ extern void sleep(int sec);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/include/violite.h mariadb-native-client.trunk/include/violite.h
+--- mariadb/include/violite.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/include/violite.h 2013-10-19 07:29:16.000000000 +0200
+@@ -69,11 +69,9 @@
+ * vio_read and vio_write should have the same semantics
+ * as read(2) and write(2).
+ */
+-int vio_read( Vio* vio,
+- gptr buf, int size);
+-int vio_write( Vio* vio,
+- const gptr buf,
+- int size);
++size_t vio_read(Vio* vio, gptr buf, size_t size);
++my_bool vio_read_peek(Vio *vio, size_t *bytes);
++size_t vio_write(Vio* vio, const gptr buf, size_t size);
+ /*
+ * Whenever the socket is set to blocking mode or not.
+ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/acinclude.m4 mariadb-native-client.trunk/libmariadb/acinclude.m4
+--- mariadb/libmariadb/acinclude.m4 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/acinclude.m4 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,91 @@
++# Local macros for automake & autoconf
++
++AC_DEFUN(MYSQL_TYPE_ACCEPT,
++[ac_save_CXXFLAGS="$CXXFLAGS"
++AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
++AC_LANG_SAVE
++AC_LANG_CPLUSPLUS
++if test "$ac_cv_prog_gxx" = "yes"
++then
++ CXXFLAGS="$CXXFLAGS -Werror"
++fi
++mysql_cv_btype_last_arg_accept=none
++[AC_TRY_COMPILE([#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++],
++[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0);],
++mysql_cv_btype_last_arg_accept=socklen_t)]
++if test $mysql_cv_btype_last_arg_accept = none; then
++[AC_TRY_COMPILE([#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++],
++[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0);],
++mysql_cv_btype_last_arg_accept=size_t)]
++fi
++if test $mysql_cv_btype_last_arg_accept = none; then
++mysql_cv_btype_last_arg_accept=int
++fi)
++AC_LANG_RESTORE
++AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $mysql_cv_btype_last_arg_accept)
++CXXFLAGS="$ac_save_CXXFLAGS"
++])
++
++
++#---START: Used in for client configure
++AC_DEFUN(MYSQL_CHECK_ULONG,
++[AC_MSG_CHECKING(for type ulong)
++AC_CACHE_VAL(ac_cv_ulong,
++[AC_TRY_RUN([#include <stdio.h>
++#include <sys/types.h>
++main()
++{
++ ulong foo;
++ foo++;
++ exit(0);
++}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
++AC_MSG_RESULT($ac_cv_ulong)
++if test "$ac_cv_ulong" = "yes"
++then
++ AC_DEFINE(HAVE_ULONG)
++fi
++])
++
++AC_DEFUN(MYSQL_CHECK_UCHAR,
++[AC_MSG_CHECKING(for type uchar)
++AC_CACHE_VAL(ac_cv_uchar,
++[AC_TRY_RUN([#include <stdio.h>
++#include <sys/types.h>
++main()
++{
++ uchar foo;
++ foo++;
++ exit(0);
++}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
++AC_MSG_RESULT($ac_cv_uchar)
++if test "$ac_cv_uchar" = "yes"
++then
++ AC_DEFINE(HAVE_UCHAR)
++fi
++])
++
++AC_DEFUN(MYSQL_CHECK_UINT,
++[AC_MSG_CHECKING(for type uint)
++AC_CACHE_VAL(ac_cv_uint,
++[AC_TRY_RUN([#include <stdio.h>
++#include <sys/types.h>
++main()
++{
++ uint foo;
++ foo++;
++ exit(0);
++}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
++AC_MSG_RESULT($ac_cv_uint)
++if test "$ac_cv_uint" = "yes"
++then
++ AC_DEFINE(HAVE_UINT)
++fi
++])
++
++#---END:
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/array.c mariadb-native-client.trunk/libmariadb/array.c
+--- mariadb/libmariadb/array.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/array.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,175 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Handling of arrays that can grow dynamicly. */
++
++#undef SAFEMALLOC /* Problems with threads */
++
++#include "mysys_priv.h"
++#include "m_string.h"
++
++/*
++ Initiate array and alloc space for init_alloc elements. Array is usable
++ even if space allocation failed
++*/
++
++my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
++ uint init_alloc, uint alloc_increment CALLER_INFO_PROTO)
++{
++ DBUG_ENTER("init_dynamic_array");
++ if (!alloc_increment)
++ {
++ alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
++ if (init_alloc > 8 && alloc_increment > init_alloc * 2)
++ alloc_increment=init_alloc*2;
++ }
++
++ if (!init_alloc)
++ init_alloc=alloc_increment;
++ array->elements=0;
++ array->max_element=init_alloc;
++ array->alloc_increment=alloc_increment;
++ array->size_of_element=element_size;
++ if (!(array->buffer=(char*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
++ {
++ array->max_element=0;
++ DBUG_RETURN(TRUE);
++ }
++ DBUG_RETURN(FALSE);
++}
++
++
++my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
++{
++ gptr buffer;
++ if (array->elements == array->max_element)
++ { /* Call only when nessesary */
++ if (!(buffer=alloc_dynamic(array)))
++ return TRUE;
++ }
++ else
++ {
++ buffer=array->buffer+(array->elements * array->size_of_element);
++ array->elements++;
++ }
++ memcpy(buffer,element,(size_t) array->size_of_element);
++ return FALSE;
++}
++
++
++ /* Alloc room for one element */
++
++unsigned char *alloc_dynamic(DYNAMIC_ARRAY *array)
++{
++ if (array->elements == array->max_element)
++ {
++ char *new_ptr;
++ if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
++ array->alloc_increment)*
++ array->size_of_element,
++ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
++ return 0;
++ array->buffer=new_ptr;
++ array->max_element+=array->alloc_increment;
++ }
++ return array->buffer+(array->elements++ * array->size_of_element);
++}
++
++
++ /* remove last element from array and return it */
++
++unsigned char *pop_dynamic(DYNAMIC_ARRAY *array)
++{
++ if (array->elements)
++ return array->buffer+(--array->elements * array->size_of_element);
++ return 0;
++}
++
++
++my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
++{
++ if (idx >= array->elements)
++ {
++ if (idx >= array->max_element)
++ {
++ uint size;
++ char *new_ptr;
++ size=(idx+array->alloc_increment)/array->alloc_increment;
++ size*= array->alloc_increment;
++ if (!(new_ptr=(char*) my_realloc(array->buffer,size*
++ array->size_of_element,
++ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
++ return TRUE;
++ array->buffer=new_ptr;
++ array->max_element=size;
++ }
++ bzero((gptr) (array->buffer+array->elements*array->size_of_element),
++ (idx - array->elements)*array->size_of_element);
++ array->elements=idx+1;
++ }
++ memcpy(array->buffer+(idx * array->size_of_element),element,
++ (size_t) array->size_of_element);
++ return FALSE;
++}
++
++
++void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
++{
++ if (idx >= array->elements)
++ {
++ DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
++ idx,array->elements));
++ bzero(element,array->size_of_element);
++ return;
++ }
++ memcpy(element,array->buffer+idx*array->size_of_element,
++ (size_t) array->size_of_element);
++}
++
++
++void delete_dynamic(DYNAMIC_ARRAY *array)
++{
++ if (array->buffer)
++ {
++ my_free(array->buffer,MYF(MY_WME));
++ array->buffer=0;
++ array->elements=array->max_element=0;
++ }
++}
++
++
++void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
++{
++ char *ptr=array->buffer+array->size_of_element*idx;
++ array->elements--;
++ memmove(ptr,ptr+array->size_of_element,
++ (array->elements-idx)*array->size_of_element);
++}
++
++
++void freeze_size(DYNAMIC_ARRAY *array)
++{
++ uint elements=max(array->elements,1);
++
++ if (array->buffer && array->max_element != elements)
++ {
++ array->buffer=(char*) my_realloc(array->buffer,
++ elements*array->size_of_element,
++ MYF(MY_WME));
++ array->max_element=elements;
++ }
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/bchange.c mariadb-native-client.trunk/libmariadb/bchange.c
+--- mariadb/libmariadb/bchange.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/bchange.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,39 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : bchange.c
++ Author : Michael widenius
++ Updated: 1987-03-20
++ Defines: bchange()
++
++ bchange(dst, old_length, src, new_length, tot_length)
++ replaces old_length characters at dst to new_length characters from
++ src in a buffer with tot_length bytes.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++void bchange(register char *dst, size_t old_length, register const char *src, size_t new_length, size_t tot_length)
++{
++ size_t rest=tot_length-old_length;
++ if (old_length < new_length)
++ bmove_upp(dst+rest+new_length,dst+tot_length,rest);
++ else
++ bmove(dst+new_length,dst+old_length,rest);
++ memcpy(dst,src,new_length);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/bmove.c mariadb-native-client.trunk/libmariadb/bmove.c
+--- mariadb/libmariadb/bmove.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/bmove.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,80 @@
++/* Copyright (C) 2002 MySQL AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : bmove.c
++ Author : Richard A. O'Keefe.
++ Michael Widenius; ifdef MC68000
++ Updated: 23 April 1984
++ Defines: bmove()
++
++ bmove(dst, src, len) moves exactly "len" bytes from the source "src"
++ to the destination "dst". It does not check for NUL characters as
++ strncpy() and strnmov() do. Thus if your C compiler doesn't support
++ structure assignment, you can simulate it with
++ bmove(&to, &from, sizeof from);
++ The standard 4.2bsd routine for this purpose is bcopy. But as bcopy
++ has its first two arguments the other way around you may find this a
++ bit easier to get right.
++ No value is returned.
++
++ Note: the "b" routines are there to exploit certain VAX order codes,
++ but the MOVC3 instruction will only move 65535 characters. The asm
++ code is presented for your interest and amusement.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#if !defined(HAVE_BMOVE) && !defined(bmove)
++
++#if VaxAsm
++
++void bmove(dst, src, len)
++ char *dst, *src;
++ uint len;
++ {
++ asm("movc3 12(ap),*8(ap),*4(ap)");
++ }
++
++#else
++#if defined(MC68000) && defined(DS90)
++
++void bmove(dst, src, len)
++char *dst,*src;
++uint len; /* 0 <= len <= 65535 */
++{
++asm(" movl 12(a7),d0 ");
++asm(" subql #1,d0 ");
++asm(" blt .L5 ");
++asm(" movl 4(a7),a1 ");
++asm(" movl 8(a7),a0 ");
++asm(".L4: movb (a0)+,(a1)+ ");
++asm(" dbf d0,.L4 ");
++asm(".L5: ");
++}
++#else
++
++void bmove(dst, src, len)
++register char *dst;
++register const char *src;
++register uint len;
++{
++ while (len-- != 0) *dst++ = *src++;
++}
++#endif
++#endif
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/bmove_upp.c mariadb-native-client.trunk/libmariadb/bmove_upp.c
+--- mariadb/libmariadb/bmove_upp.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/bmove_upp.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,51 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : bmove.c
++ Author : Michael widenius
++ Updated: 1987-03-20
++ Defines: bmove_upp()
++
++ bmove_upp(dst, src, len) moves exactly "len" bytes from the source
++ "src-len" to the destination "dst-len" counting downwards.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#if defined(MC68000) && defined(DS90)
++
++/* 0 <= len <= 65535 */
++void bmove_upp(byte *dst, const byte *src, size_t len)
++{
++asm(" movl 12(a7),d0 ");
++asm(" subql #1,d0 ");
++asm(" blt .L5 ");
++asm(" movl 4(a7),a1 ");
++asm(" movl 8(a7),a0 ");
++asm(".L4: movb -(a0),-(a1) ");
++asm(" dbf d0,.L4 ");
++asm(".L5: ");
++}
++#else
++
++void bmove_upp(register char *dst, register const char *src, register size_t len)
++{
++ while (len-- != 0) *--dst = *--src;
++}
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/charset.c mariadb-native-client.trunk/libmariadb/charset.c
+--- mariadb/libmariadb/charset.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/charset.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,78 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <m_ctype.h>
++#include <m_string.h>
++#include <my_dir.h>
++
++CHARSET_INFO *default_charset_info = (CHARSET_INFO *)&compiled_charsets[5];
++CHARSET_INFO *my_charset_bin= (CHARSET_INFO *)&compiled_charsets[32];
++CHARSET_INFO *my_charset_latin1= (CHARSET_INFO *)&compiled_charsets[5];
++CHARSET_INFO *my_charset_utf8_general_ci= (CHARSET_INFO *)&compiled_charsets[21];
++
++CHARSET_INFO * STDCALL mysql_get_charset_by_nr(uint cs_number)
++{
++ int i= 0;
++
++ while (compiled_charsets[i].nr && cs_number != compiled_charsets[i].nr)
++ i++;
++
++ return (compiled_charsets[i].nr) ? (CHARSET_INFO *)&compiled_charsets[i] : NULL;
++}
++
++my_bool set_default_charset(uint cs, myf flags)
++{
++ CHARSET_INFO *new_charset;
++ DBUG_ENTER("set_default_charset");
++ DBUG_PRINT("enter",("character set: %d",(int) cs));
++ new_charset = mysql_get_charset_by_nr(cs);
++ if (!new_charset)
++ {
++ DBUG_PRINT("error",("Couldn't set default character set"));
++ DBUG_RETURN(TRUE); /* error */
++ }
++ default_charset_info = new_charset;
++ DBUG_RETURN(FALSE);
++}
++
++CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *cs_name)
++{
++ int i= 0;
++
++ while (compiled_charsets[i].nr && strcmp(cs_name, compiled_charsets[i].csname) != 0)
++ i++;
++
++ return (compiled_charsets[i].nr) ? (CHARSET_INFO *)&compiled_charsets[i] : NULL;
++}
++
++my_bool set_default_charset_by_name(const char *cs_name, myf flags)
++{
++ CHARSET_INFO *new_charset;
++ DBUG_ENTER("set_default_charset_by_name");
++ DBUG_PRINT("enter",("character set: %s", cs_name));
++ new_charset = mysql_get_charset_by_name(cs_name);
++ if (!new_charset)
++ {
++ DBUG_PRINT("error",("Couldn't set default character set"));
++ DBUG_RETURN(TRUE); /* error */
++ }
++
++ default_charset_info = new_charset;
++ DBUG_RETURN(FALSE);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/client_plugin.c mariadb-native-client.trunk/libmariadb/client_plugin.c
+--- mariadb/libmariadb/client_plugin.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/client_plugin.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,460 @@
++/* Copyright (C) 2010 - 2012 Sergei Golubchik and Monty Program Ab
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA */
++
++/**
++ @file
++
++ Support code for the client side (libmariadb) plugins
++
++ Client plugins are somewhat different from server plugins, they are simpler.
++
++ They do not need to be installed or in any way explicitly loaded on the
++ client, they are loaded automatically on demand.
++ One client plugin per shared object, soname *must* match the plugin name.
++
++ There is no reference counting and no unloading either.
++*/
++
++#if _MSC_VER
++/* Silence warnings about variable 'unused' being used. */
++#define FORCE_INIT_OF_VARS 1
++#endif
++
++#include <my_global.h>
++#include <my_sys.h>
++#include <ma_common.h>
++#include <m_string.h>
++#ifdef THREAD
++#include <my_pthread.h>
++#else
++#include <my_no_pthread.h>
++#endif
++
++#include "errmsg.h"
++#include <mysql/client_plugin.h>
++
++struct st_client_plugin_int {
++ struct st_client_plugin_int *next;
++ void *dlhandle;
++ struct st_mysql_client_plugin *plugin;
++};
++
++static my_bool initialized= 0;
++static MEM_ROOT mem_root;
++
++#define plugin_declarations_sym "_mysql_client_plugin_declaration_"
++
++static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
++{
++ MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION, /* these two are taken by Connector/C */
++ 0, /* these two are taken by Connector/C */
++ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
++};
++
++/*
++ Loaded plugins are stored in a linked list.
++ The list is append-only, the elements are added to the head (like in a stack).
++ The elements are added under a mutex, but the list can be read and traversed
++ without any mutex because once an element is added to the list, it stays
++ there. The main purpose of a mutex is to prevent two threads from
++ loading the same plugin twice in parallel.
++*/
++struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS];
++#ifdef THREAD
++static pthread_mutex_t LOCK_load_client_plugin;
++#endif
++
++static int is_not_initialized(MYSQL *mysql, const char *name)
++{
++ if (initialized)
++ return 0;
++
++ my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
++ SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
++ name, "not initialized");
++ return 1;
++}
++
++
++/**
++ finds a plugin in the list
++
++ @param name plugin name to search for
++ @param type plugin type
++
++ @note this does NOT necessarily need a mutex, take care!
++
++ @retval a pointer to a found plugin or 0
++*/
++
++static struct st_mysql_client_plugin *find_plugin(const char *name, int type)
++{
++ struct st_client_plugin_int *p;
++
++ DBUG_ASSERT(initialized);
++ DBUG_ASSERT(type >= 0 && type < MYSQL_CLIENT_MAX_PLUGINS);
++ if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
++ return 0;
++
++ for (p= plugin_list[type]; p; p= p->next)
++ {
++ if (strcmp(p->plugin->name, name) == 0)
++ return p->plugin;
++ }
++ return NULL;
++}
++
++
++/**
++ verifies the plugin and adds it to the list
++
++ @param mysql MYSQL structure (for error reporting)
++ @param plugin plugin to install
++ @param dlhandle a handle to the shared object (returned by dlopen)
++ or 0 if the plugin was not dynamically loaded
++ @param argc number of arguments in the 'va_list args'
++ @param args arguments passed to the plugin initialization function
++
++ @retval a pointer to an installed plugin or 0
++*/
++
++static struct st_mysql_client_plugin *
++add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
++ int argc, va_list args)
++{
++ const char *errmsg;
++ struct st_client_plugin_int plugin_int, *p;
++ char errbuf[1024];
++
++ DBUG_ASSERT(initialized);
++
++ plugin_int.plugin= plugin;
++ plugin_int.dlhandle= dlhandle;
++
++ if (plugin->type >= MYSQL_CLIENT_MAX_PLUGINS)
++ {
++ errmsg= "Unknown client plugin type";
++ goto err1;
++ }
++
++ if (plugin->interface_version < plugin_version[plugin->type] ||
++ (plugin->interface_version >> 8) >
++ (plugin_version[plugin->type] >> 8))
++ {
++ errmsg= "Incompatible client plugin interface";
++ goto err1;
++ }
++
++ /* Call the plugin initialization function, if any */
++ if (plugin->init && plugin->init(errbuf, sizeof(errbuf), argc, args))
++ {
++ errmsg= errbuf;
++ goto err1;
++ }
++
++ p= (struct st_client_plugin_int *)
++ memdup_root(&mem_root, (char *)&plugin_int, sizeof(plugin_int));
++
++ if (!p)
++ {
++ errmsg= "Out of memory";
++ goto err2;
++ }
++
++#ifdef THREAD
++ safe_mutex_assert_owner(&LOCK_load_client_plugin);
++#endif
++
++ p->next= plugin_list[plugin->type];
++ plugin_list[plugin->type]= p;
++
++ return plugin;
++
++err2:
++ if (plugin->deinit)
++ plugin->deinit();
++err1:
++ if (dlhandle)
++ (void)dlclose(dlhandle);
++ my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
++ ER(CR_AUTH_PLUGIN_CANNOT_LOAD), plugin->name, errmsg);
++ return NULL;
++}
++
++
++/**
++ Loads plugins which are specified in the environment variable
++ LIBMYSQL_PLUGINS.
++
++ Multiple plugins must be separated by semicolon. This function doesn't
++ return or log an error.
++
++ The function is be called by mysql_client_plugin_init
++
++ @todo
++ Support extended syntax, passing parameters to plugins, for example
++ LIBMYSQL_PLUGINS="plugin1(param1,param2);plugin2;..."
++ or
++ LIBMYSQL_PLUGINS="plugin1=int:param1,str:param2;plugin2;..."
++*/
++
++static void load_env_plugins(MYSQL *mysql)
++{
++ char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
++
++ /* no plugins to load */
++ if (!s)
++ return;
++
++ free_env= plugs= my_strdup(s, MYF(MY_WME));
++
++ do {
++ if ((s= strchr(plugs, ';')))
++ *s= '\0';
++ mysql_load_plugin(mysql, plugs, -1, 0);
++ plugs= s + 1;
++ } while (s);
++
++ my_free(free_env, MYF(0));
++}
++
++/********** extern functions to be used by libmariadb *********************/
++
++/**
++ Initializes the client plugin layer.
++
++ This function must be called before any other client plugin function.
++
++ @retval 0 successful
++ @retval != 0 error occured
++*/
++
++int mysql_client_plugin_init()
++{
++ MYSQL mysql;
++ struct st_mysql_client_plugin **builtin;
++ va_list unused;
++ LINT_INIT_STRUCT(unused);
++
++ if (initialized)
++ return 0;
++
++ bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
++
++ pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
++ init_alloc_root(&mem_root, 128, 128);
++
++ bzero(&plugin_list, sizeof(plugin_list));
++
++ initialized= 1;
++
++ pthread_mutex_lock(&LOCK_load_client_plugin);
++
++ for (builtin= mysql_client_builtins; *builtin; builtin++)
++ add_plugin(&mysql, *builtin, 0, 0, unused);
++ pthread_mutex_unlock(&LOCK_load_client_plugin);
++
++ load_env_plugins(&mysql);
++
++ return 0;
++}
++
++
++/**
++ Deinitializes the client plugin layer.
++
++ Unloades all client plugins and frees any associated resources.
++*/
++
++void mysql_client_plugin_deinit()
++{
++ int i;
++ struct st_client_plugin_int *p;
++
++ if (!initialized)
++ return;
++
++ for (i=0; i < MYSQL_CLIENT_MAX_PLUGINS; i++)
++ for (p= plugin_list[i]; p; p= p->next)
++ {
++ if (p->plugin->deinit)
++ p->plugin->deinit();
++ if (p->dlhandle)
++ (void)dlclose(p->dlhandle);
++ }
++
++ bzero(&plugin_list, sizeof(plugin_list));
++ initialized= 0;
++ free_root(&mem_root, MYF(0));
++ pthread_mutex_destroy(&LOCK_load_client_plugin);
++}
++
++/************* public facing functions, for client consumption *********/
++
++/* see <mysql/client_plugin.h> for a full description */
++struct st_mysql_client_plugin *
++mysql_client_register_plugin(MYSQL *mysql,
++ struct st_mysql_client_plugin *plugin)
++{
++ va_list unused;
++ LINT_INIT_STRUCT(unused);
++
++ if (is_not_initialized(mysql, plugin->name))
++ return NULL;
++
++ pthread_mutex_lock(&LOCK_load_client_plugin);
++
++ /* make sure the plugin wasn't loaded meanwhile */
++ if (find_plugin(plugin->name, plugin->type))
++ {
++ my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
++ SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
++ plugin->name, "it is already loaded");
++ plugin= NULL;
++ }
++ else
++ plugin= add_plugin(mysql, plugin, 0, 0, unused);
++
++ pthread_mutex_unlock(&LOCK_load_client_plugin);
++ return plugin;
++}
++
++
++/* see <mysql/client_plugin.h> for a full description */
++struct st_mysql_client_plugin *
++mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
++ int argc, va_list args)
++{
++ const char *errmsg;
++#ifdef _WIN32
++ char errbuf[255];
++#endif
++ char dlpath[FN_REFLEN+1];
++ void *sym, *dlhandle;
++ struct st_mysql_client_plugin *plugin;
++
++ if (is_not_initialized(mysql, name))
++ return NULL;
++
++ pthread_mutex_lock(&LOCK_load_client_plugin);
++
++ /* make sure the plugin wasn't loaded meanwhile */
++ if (type >= 0 && find_plugin(name, type))
++ {
++ errmsg= "it is already loaded";
++ goto err;
++ }
++
++ /* Compile dll path */
++ strxnmov(dlpath, sizeof(dlpath) - 1,
++ mysql->options.extension && mysql->options.extension->plugin_dir ?
++ mysql->options.extension->plugin_dir : PLUGINDIR, "/",
++ name, SO_EXT, NullS);
++
++ /* Open new dll handle */
++ if (!(dlhandle= dlopen((const char *)dlpath, RTLD_NOW)))
++ {
++#ifdef _WIN32
++ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
++ NULL,
++ GetLastError(),
++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
++ (LPTSTR)&errbuf, 255, NULL);
++ errmsg= errbuf;
++#else
++ errmsg= dlerror();
++#endif
++ goto err;
++ }
++
++ if (!(sym= dlsym(dlhandle, plugin_declarations_sym)))
++ {
++ errmsg= "not a plugin";
++ (void)dlclose(dlhandle);
++ goto err;
++ }
++
++ plugin= (struct st_mysql_client_plugin*)sym;
++
++ if (type >=0 && type != plugin->type)
++ {
++ errmsg= "type mismatch";
++ goto err;
++ }
++
++ if (strcmp(name, plugin->name))
++ {
++ errmsg= "name mismatch";
++ goto err;
++ }
++
++ if (type < 0 && find_plugin(name, plugin->type))
++ {
++ errmsg= "it is already loaded";
++ goto err;
++ }
++
++ plugin= add_plugin(mysql, plugin, dlhandle, argc, args);
++
++ pthread_mutex_unlock(&LOCK_load_client_plugin);
++
++ return plugin;
++
++err:
++ pthread_mutex_unlock(&LOCK_load_client_plugin);
++ my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
++ ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg);
++ return NULL;
++}
++
++
++/* see <mysql/client_plugin.h> for a full description */
++struct st_mysql_client_plugin *
++mysql_load_plugin(MYSQL *mysql, const char *name, int type, int argc, ...)
++{
++ struct st_mysql_client_plugin *p;
++ va_list args;
++ va_start(args, argc);
++ p= mysql_load_plugin_v(mysql, name, type, argc, args);
++ va_end(args);
++ return p;
++}
++
++
++/* see <mysql/client_plugin.h> for a full description */
++struct st_mysql_client_plugin *
++mysql_client_find_plugin(MYSQL *mysql, const char *name, int type)
++{
++ struct st_mysql_client_plugin *p;
++
++ if (is_not_initialized(mysql, name))
++ return NULL;
++
++ if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
++ {
++ my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
++ ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, "invalid type");
++ }
++
++ if ((p= find_plugin(name, type)))
++ return p;
++
++ /* not found, load it */
++ return mysql_load_plugin(mysql, name, type, 0);
++}
++
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/CMakeLists.txt mariadb-native-client.trunk/libmariadb/CMakeLists.txt
+--- mariadb/libmariadb/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,228 @@
++INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
++ ${ZLIB_INC}
+ ${CMAKE_SOURCE_DIR}/libmariadb)
-
- IF(OPENSSL_FOUND)
- INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
++
++IF(OPENSSL_FOUND)
++ INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
+ SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES})
+ IF(OPENSSL_CRYPTO_LIBRARIES)
+ SET(SSL_LIBRARIES ${SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES})
+ ENDIF()
- ENDIF()
-
-
-@@ -11,7 +15,7 @@
- ADD_DEFINITIONS(-D HAVE_COMPRESS)
- ADD_DEFINITIONS(-D THREAD)
-
--SET(LIBMYSQL_SOURCES
++ENDIF()
++
++
++ADD_DEFINITIONS(-D ENABLED_LOCAL_INFILE)
++ADD_DEFINITIONS(-D HAVE_COMPRESS)
++ADD_DEFINITIONS(-D LIBMARIADB)
++ADD_DEFINITIONS(-D THREAD)
++
+SET(LIBMARIADB_SOURCES
- array.c
- bchange.c
- bmove.c
-@@ -30,7 +34,7 @@
- get_password.c
- int2str.c
- is_prefix.c
--libmysql.c
++array.c
++ma_dyncol.c
++bchange.c
++bmove.c
++bmove_upp.c
++my_charset.c
++hash.c
++violite.c
++net.c
++charset.c
++ma_time.c
++dbug.c
++default.c
++errmsg.c
++my_vsnprintf.c
++errors.c
++getopt1.c
++getopt.c
++get_password.c
++int2str.c
++is_prefix.c
+libmariadb.c
- list.c
- llstr.c
- longlong2str.c
-@@ -94,11 +98,17 @@
- my_stmt_codec.c
- client_plugin.c
- my_auth.c
--my_secure.c
--libmysql_exports.def
++list.c
++llstr.c
++longlong2str.c
++mf_dirname.c
++mf_fn_ext.c
++mf_format.c
++mf_loadpath.c
++mf_pack.c
++mf_path.c
++mf_unixpath.c
++mf_wcomp.c
++mulalloc.c
++my_alloc.c
++my_compress.c
++my_div.c
++my_error.c
++my_fopen.c
++my_fstream.c
++my_getwd.c
++my_init.c
++my_lib.c
++my_malloc.c
++my_messnc.c
++my_net.c
++my_once.c
++my_open.c
++my_port.c
++my_pthread.c
++my_read.c
++my_realloc.c
++my_seek.c
++my_static.c
++my_symlink.c
++my_thr_init.c
++my_write.c
++password.c
++str2int.c
++strcend.c
++strcont.c
++strend.c
++strfill.c
++string.c
++strinstr.c
++strmake.c
++strmov.c
++strnmov.c
++strtoll.c
++strtoull.c
++strxmov.c
++strxnmov.c
++thr_mutex.c
++typelib.c
++sha1.c
++my_stmt.c
++my_loaddata.c
++my_stmt_codec.c
++client_plugin.c
++my_auth.c
+ma_secure.c
+libmariadb_exports.def
- )
-
--
++)
++
++IF(WIN32)
++ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/win-iconv)
++ SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
++ ${CMAKE_SOURCE_DIR}/win-iconv/win_iconv.c)
++ENDIF()
++
+IF(WITH_SQLITE)
+ SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
+ ${CMAKE_SOURCE_DIR}/plugins/sqlite/sqlite3.c
@@ -1937,44 +5643,69 @@
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/plugins/sqlite)
+ ADD_DEFINITIONS(-DSQLITE_ENABLE_COLUMN_METADATA=1)
+ENDIF()
-
- IF(ZLIB_FOUND)
- INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
-@@ -122,25 +132,24 @@
- ../zlib/uncompr.c
- ../zlib/zutil.c
- )
-- SET(LIBMYSQL_SOURCES ${LIBMYSQL_SOURCES} ${ZLIB_SOURCES})
-+SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} ${ZLIB_SOURCES})
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib)
- ENDIF()
-
-
--ADD_LIBRARY(mariadbclient STATIC ${LIBMYSQL_SOURCES})
++
++IF(ZLIB_FOUND)
++ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
++ LINK_LIBRARIES(${ZLIB_LIBRARY})
++ELSE()
++ SET(ZLIB_SOURCES
++ ../zlib/adler32.c
++ ../zlib/compress.c
++ ../zlib/crc32.c
++ ../zlib/deflate.c
++ ../zlib/example.c
++ ../zlib/gzclose.c
++ ../zlib/gzlib.c
++ ../zlib/gzread.c
++ ../zlib/gzwrite.c
++ ../zlib/infback.c
++ ../zlib/inffast.c
++ ../zlib/inflate.c
++ ../zlib/inftrees.c
++ ../zlib/trees.c
++ ../zlib/uncompr.c
++ ../zlib/zutil.c
++ )
++ SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} ${ZLIB_SOURCES})
++ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib)
++ENDIF()
++
+ADD_LIBRARY(mariadbclient STATIC ${LIBMARIADB_SOURCES})
- TARGET_LINK_LIBRARIES(mariadbclient ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
- IF(OPENSSL_FOUND)
-- TARGET_LINK_LIBRARIES(mariadbclient ${OPENSSL_LIBRARIES})
++TARGET_LINK_LIBRARIES(mariadbclient ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ${MATH_LIBRARY} ${ICONV_LIBRARIES})
++IF(OPENSSL_FOUND)
+ TARGET_LINK_LIBRARIES(mariadbclient ${SSL_LIBRARIES})
- ENDIF()
-
--ADD_LIBRARY(libmariadb SHARED ${LIBMYSQL_SOURCES})
++ENDIF()
++
+ADD_LIBRARY(libmariadb SHARED ${LIBMARIADB_SOURCES})
- TARGET_LINK_LIBRARIES(libmariadb ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
-
- IF(OPENSSL_FOUND)
-- TARGET_LINK_LIBRARIES(libmariadb ${OPENSSL_LIBRARIES})
++TARGET_LINK_LIBRARIES(libmariadb ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ${MATH_LIBRARY} ${ICONV_LIBRARIES})
++
++IF(OPENSSL_FOUND)
+ TARGET_LINK_LIBRARIES(libmariadb ${SSL_LIBRARIES})
- ENDIF()
-
--
- IF(WIN32)
- TARGET_LINK_LIBRARIES(libmariadb ws2_32)
- TARGET_LINK_LIBRARIES(mariadbclient ws2_32)
-@@ -164,16 +173,52 @@
- # Installation
- #
-
++ENDIF()
++
++IF(WIN32)
++ TARGET_LINK_LIBRARIES(libmariadb ws2_32 advapi32 kernel32)
++ TARGET_LINK_LIBRARIES(mariadbclient ws2_32 advapi32 kernel32)
++ELSE()
++ TARGET_LINK_LIBRARIES(libmariadb m)
++ TARGET_LINK_LIBRARIES(mariadbclient m)
++ENDIF()
++
++IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
++ TARGET_LINK_LIBRARIES (libmariadb "-Wl,--no-undefined")
++ TARGET_LINK_LIBRARIES (libmariadb "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.txt")
++ENDIF()
++
++SET_TARGET_PROPERTIES(libmariadb PROPERTIES PREFIX "")
++
++SET_TARGET_PROPERTIES(libmariadb PROPERTIES VERSION
++ ${CPACK_PACKAGE_VERSION_MAJOR}
++ SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
++
++#
++# Installation
++#
++
+# There are still several projects which don't make use
+# of the config program. To make sure these programs can
+# use mariadb client library we provide libmysql symlinks
@@ -1990,7 +5721,7 @@
+ COMMAND ${CMAKE_COMMAND} ARGS -E remove -f libmysqlclient${CMAKE_SHARED_LIBRARY_SUFFIX}
+ COMMAND ${CMAKE_COMMAND} ARGS -E create_symlink libmariadb${CMAKE_SHARED_LIBRARY_SUFFIX} libmysqlclient${CMAKE_SHARED_LIBRARY_SUFFIX}
+ COMMAND ${CMAKE_COMMAND} ARGS -E remove -f libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}
-+ COMMAND ${CMAKE_COMMAND} ARGS -E create_symlink libmariadb${CMAKE_STATIC_LIBRARY_SUFFIX} libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}
++ COMMAND ${CMAKE_COMMAND} ARGS -E create_symlink libmariadbclient${CMAKE_STATIC_LIBRARY_SUFFIX} libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/libmariadb
+ DEPENDS libmariadb mariadbclient)
+
@@ -2004,178 +5735,5233 @@
+ENDIF()
+
+
- INSTALL(TARGETS
- libmariadb mariadbclient
-- RUNTIME DESTINATION "lib"
-- LIBRARY DESTINATION "lib"
-- ARCHIVE DESTINATION "lib")
++INSTALL(TARGETS
++ libmariadb mariadbclient
+ RUNTIME DESTINATION "lib/mariadb"
+ LIBRARY DESTINATION "lib/mariadb"
+ ARCHIVE DESTINATION "lib/mariadb")
+IF(NOT WIN32 AND WITH_MYSQLCOMPAT)
-+ INSTALL(FILES "libmysql${CMAKE_SHARED_LIBRARY_SUFFIX}"
-+ "libmysqlclient${CMAKE_SHARED_LIBRARY_SUFFIX}"
-+ "libmysqlclient_r${CMAKE_SHARED_LIBRARY_SUFFIX}"
-+ "libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}"
++ INSTALL(FILES "${CMAKE_BINARY_DIR}/libmariadb/libmysql${CMAKE_SHARED_LIBRARY_SUFFIX}"
++ "${CMAKE_BINARY_DIR}/libmariadb/libmysqlclient${CMAKE_SHARED_LIBRARY_SUFFIX}"
++ "${CMAKE_BINARY_DIR}/libmariadb/libmysqlclient_r${CMAKE_SHARED_LIBRARY_SUFFIX}"
++ "${CMAKE_BINARY_DIR}/libmariadb/libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ DESTINATION lib/mariadb)
+ENDIF()
-
--INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include
-- DESTINATION mariadbclient)
++
+INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
+ DESTINATION include/mariadb)
- INSTALL(FILES
- ${CMAKE_BINARY_DIR}/include/my_config.h
- ${CMAKE_BINARY_DIR}/include/mysql_version.h
-- DESTINATION mariadbclient/include
++INSTALL(FILES
++ ${CMAKE_BINARY_DIR}/include/my_config.h
++ ${CMAKE_BINARY_DIR}/include/mysql_version.h
+ DESTINATION include/mariadb
- )
-
-=== modified file 'libmariadb/array.c'
---- mariadb/libmysql/array.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/array.c 2013-03-14 21:01:43 +0000
-@@ -75,7 +75,7 @@
-
- /* Alloc room for one element */
-
--byte *alloc_dynamic(DYNAMIC_ARRAY *array)
-+unsigned char *alloc_dynamic(DYNAMIC_ARRAY *array)
- {
- if (array->elements == array->max_element)
- {
-@@ -94,7 +94,7 @@
-
- /* remove last element from array and return it */
-
--byte *pop_dynamic(DYNAMIC_ARRAY *array)
-+unsigned char *pop_dynamic(DYNAMIC_ARRAY *array)
- {
- if (array->elements)
- return array->buffer+(--array->elements * array->size_of_element);
-
-=== modified file 'libmariadb/client_plugin.c'
---- mariadb/libmysql/client_plugin.c 2012-11-27 08:57:10 +0000
-+++ mariadb/libmariadb/client_plugin.c 2013-03-14 21:01:43 +0000
-@@ -18,7 +18,7 @@
- /**
- @file
-
-- Support code for the client side (libmysql) plugins
-+ Support code for the client side (libmariadb) plugins
-
- Client plugins are somewhat different from server plugins, they are simpler.
-
-@@ -60,7 +60,7 @@
-
- static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
- {
-- 0, /* these two are taken by Connector/C */
-+ MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION, /* these two are taken by Connector/C */
- 0, /* these two are taken by Connector/C */
- MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
- };
-@@ -230,7 +230,7 @@
- my_free(free_env, MYF(0));
- }
-
--/********** extern functions to be used by libmysql *********************/
-+/********** extern functions to be used by libmariadb *********************/
-
- /**
- Initializes the client plugin layer.
-@@ -264,7 +264,6 @@
-
- for (builtin= mysql_client_builtins; *builtin; builtin++)
- add_plugin(&mysql, *builtin, 0, 0, unused);
--
- pthread_mutex_unlock(&LOCK_load_client_plugin);
-
- load_env_plugins(&mysql);
-
-=== modified file 'libmariadb/dbug.c'
---- mariadb/libmysql/dbug.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/dbug.c 2013-03-14 21:01:43 +0000
-@@ -707,8 +707,8 @@
- int save_errno=errno;
- if (!init_done)
- _db_push_ (_DBUG_START_CONDITION_);
-- state=code_state();
--
-+ if(!(state=code_state()))
-+ return;
- *_sfunc_ = state->func;
- *_sfile_ = state->file;
- state->func =(char*) _func_;
-
-=== modified file 'libmariadb/errmsg.c'
---- mariadb/libmysql/errmsg.c 2012-11-26 07:32:41 +0000
-+++ mariadb/libmariadb/errmsg.c 2013-03-14 21:01:43 +0000
-@@ -106,17 +106,17 @@
- /* 2023 */ "",
- /* 2024 */ "",
- /* 2025 */ "",
--/* 2026 */ "SSL connection error",
++)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/dbug.c mariadb-native-client.trunk/libmariadb/dbug.c
+--- mariadb/libmariadb/dbug.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/dbug.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,2456 @@
++/******************************************************************************
++ * *
++ * N O T I C E *
++ * *
++ * Copyright Abandoned, 1987, Fred Fish *
++ * *
++ * *
++ * This previously copyrighted work has been placed into the public *
++ * domain by the author and may be freely used for any purpose, *
++ * private or commercial. *
++ * *
++ * Because of the number of inquiries I was receiving about the use *
++ * of this product in commercially developed works I have decided to *
++ * simply make it public domain to further its unrestricted use. I *
++ * specifically would be most happy to see this material become a *
++ * part of the standard Unix distributions by AT&T and the Berkeley *
++ * Computer Science Research Group, and a standard part of the GNU *
++ * system from the Free Software Foundation. *
++ * *
++ * I would appreciate it, as a courtesy, if this notice is left in *
++ * all copies and derivative works. Thank you. *
++ * *
++ * The author makes no warranty of any kind with respect to this *
++ * product and explicitly disclaims any implied warranties of mer- *
++ * chantability or fitness for any particular purpose. *
++ * *
++ ******************************************************************************
++ */
++
++/*
++ * FILE
++ *
++ * dbug.c runtime support routines for dbug package
++ *
++ * SCCS
++ *
++ * @(#)dbug.c 1.25 7/25/89
++ *
++ * DESCRIPTION
++ *
++ * These are the runtime support routines for the dbug package.
++ * The dbug package has two main components; the user include
++ * file containing various macro definitions, and the runtime
++ * support routines which are called from the macro expansions.
++ *
++ * Externally visible functions in the runtime support module
++ * use the naming convention pattern "_db_xx...xx_", thus
++ * they are unlikely to collide with user defined function names.
++ *
++ * AUTHOR(S)
++ *
++ * Fred Fish (base code)
++ * Enhanced Software Technologies, Tempe, AZ
++ * asuvax!mcdphx!estinc!fnf
++ *
++ * Binayak Banerjee (profiling enhancements)
++ * seismo!bpa!sjuvax!bbanerje
++ *
++ * Michael Widenius:
++ * DBUG_DUMP - To dump a block of memory.
++ * PUSH_FLAG "O" - To be used insted of "o" if we
++ * want flushing after each write
++ * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
++ * of creating a new one.
++ * Check of malloc on entry/exit (option "S")
++ *
++ * Sergei Golubchik:
++ * DBUG_EXECUTE_IF
++ * incremental mode (-#+t:-d,info ...)
++ * DBUG_SET, _db_explain_
++ * thread-local settings
++ * negative lists (-#-d,info => everything but "info")
++ *
++ * function/ syntax
++ * (the logic is - think of a call stack as of a path.
++ * "function" means only this function, "function/" means the hierarchy.
++ * in the future, filters like function1/function2 could be supported.
++ * following this logic glob(7) wildcards are supported.)
++ *
++ */
++
++/*
++ We can't have SAFE_MUTEX defined here as this will cause recursion
++ in pthread_mutex_lock
++*/
++
++#undef SAFE_MUTEX
++#include <my_global.h>
++#include <m_string.h>
++#include <errno.h>
++
++#ifdef HAVE_FNMATCH_H
++#include <fnmatch.h>
++#else
++#define fnmatch(A,B,C) strcmp(A,B)
++#endif
++
++#if defined(_WIN32)
++#include <process.h>
++#else
++#include <signal.h>
++#endif
++
++extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
++
++char _dig_vec_upper[] =
++ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
++char _dig_vec_lower[] =
++ "0123456789abcdefghijklmnopqrstuvwxyz";
++
++#ifndef DBUG_OFF
++
++
++/*
++ * Manifest constants which may be "tuned" if desired.
++ */
++
++#define PRINTBUF 1024 /* Print buffer size */
++#define INDENT 2 /* Indentation per trace level */
++#define MAXDEPTH 200 /* Maximum trace depth default */
++
++/*
++ * The following flags are used to determine which
++ * capabilities the user has enabled with the settings
++ * push macro.
++ *
++ * TRACE_ON is also used in _db_stack_frame_->level
++ * (until we add flags to _db_stack_frame_, increasing it by 4 bytes)
++ */
++
++#define DEBUG_ON (1 << 1) /* Debug enabled */
++#define FILE_ON (1 << 2) /* File name print enabled */
++#define LINE_ON (1 << 3) /* Line number print enabled */
++#define DEPTH_ON (1 << 4) /* Function nest level print enabled */
++#define PROCESS_ON (1 << 5) /* Process name print enabled */
++#define NUMBER_ON (1 << 6) /* Number each line of output */
++#define PROFILE_ON (1 << 7) /* Print out profiling code */
++#define PID_ON (1 << 8) /* Identify each line with process id */
++#define TIMESTAMP_ON (1 << 9) /* timestamp every line of output */
++#define FLUSH_ON_WRITE (1 << 10) /* Flush on every write */
++#define OPEN_APPEND (1 << 11) /* Open for append */
++#define TRACE_ON ((uint)1 << 31) /* Trace enabled. MUST be the highest bit!*/
++
++#define TRACING (cs->stack->flags & TRACE_ON)
++#define DEBUGGING (cs->stack->flags & DEBUG_ON)
++#define PROFILING (cs->stack->flags & PROFILE_ON)
++
++/*
++ * Typedefs to make things more obvious.
++ */
++
++#define BOOLEAN my_bool
++
++/*
++ * Make it easy to change storage classes if necessary.
++ */
++
++#define IMPORT extern /* Names defined externally */
++#define EXPORT /* Allocated here, available globally */
++
++/*
++ * The default file for profiling. Could also add another flag
++ * (G?) which allowed the user to specify this.
++ *
++ * If the automatic variables get allocated on the stack in
++ * reverse order from their declarations, then define AUTOS_REVERSE to 1.
++ * This is used by the code that keeps track of stack usage. For
++ * forward allocation, the difference in the dbug frame pointers
++ * represents stack used by the callee function. For reverse allocation,
++ * the difference represents stack used by the caller function.
++ *
++ */
++
++#define PROF_FILE "dbugmon.out"
++#define PROF_EFMT "E\t%ld\t%s\n"
++#define PROF_SFMT "S\t%lx\t%lx\t%s\n"
++#define PROF_XFMT "X\t%ld\t%s\n"
++
++#ifdef M_I386 /* predefined by xenix 386 compiler */
++#define AUTOS_REVERSE 1
++#else
++#define AUTOS_REVERSE 0
++#endif
++
++/*
++ * Externally supplied functions.
++ */
++
++#ifndef HAVE_PERROR
++static void perror(); /* Fake system/library error print routine */
++#endif
++
++/*
++ * The user may specify a list of functions to trace or
++ * debug. These lists are kept in a linear linked list,
++ * a very simple implementation.
++ */
++
++struct link {
++ struct link *next_link; /* Pointer to the next link */
++ char flags;
++ char str[1]; /* Pointer to link's contents */
++};
++
++/* flags for struct link and return flags of InList */
++#define SUBDIR 1 /* this MUST be 1 */
++#define INCLUDE 2
++#define EXCLUDE 4
++/* this is not a struct link flag, but only a return flags of InList */
++#define MATCHED 65536
++#define NOT_MATCHED 0
++
++/*
++ * Debugging settings can be pushed or popped off of a
++ * stack which is implemented as a linked list. Note
++ * that the head of the list is the current settings and the
++ * stack is pushed by adding a new settings to the head of the
++ * list or popped by removing the first link.
++ *
++ * Note: if out_file is NULL, the other fields are not initialized at all!
++ */
++
++struct settings {
++ uint flags; /* Current settings flags */
++ uint maxdepth; /* Current maximum trace depth */
++ uint delay; /* Delay after each output line */
++ uint sub_level; /* Sub this from code_state->level */
++ FILE *out_file; /* Current output stream */
++ FILE *prof_file; /* Current profiling stream */
++ char name[FN_REFLEN]; /* Name of output file */
++ struct link *functions; /* List of functions */
++ struct link *p_functions; /* List of profiled functions */
++ struct link *keywords; /* List of debug keywords */
++ struct link *processes; /* List of process names */
++ struct settings *next; /* Next settings in the list */
++};
++
++#define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
++
++/*
++ * Local variables not seen by user.
++ */
++
++
++static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
++/**
++ Global debugging settings.
++ This structure shared between all threads,
++ and is the last element in each thread @c CODE_STATE::stack chain.
++ Protected by @c THR_LOCK_init_settings.
++*/
++static struct settings init_settings;
++static const char *db_process= 0;/* Pointer to process name; argv[0] */
++my_bool _dbug_on_= TRUE; /* FALSE if no debugging at all */
++
++typedef struct _db_code_state_ {
++ const char *process; /* Pointer to process name; usually argv[0] */
++ const char *func; /* Name of current user function */
++ const char *file; /* Name of current user file */
++ struct _db_stack_frame_ *framep; /* Pointer to current frame */
++ struct settings *stack; /* debugging settings */
++ const char *jmpfunc; /* Remember current function for setjmp */
++ const char *jmpfile; /* Remember current file for setjmp */
++ int lineno; /* Current debugger output line number */
++ uint level; /* Current function nesting level */
++ int jmplevel; /* Remember nesting level at setjmp() */
++
++/*
++ * The following variables are used to hold the state information
++ * between the call to _db_pargs_() and _db_doprnt_(), during
++ * expansion of the DBUG_PRINT macro. This is the only macro
++ * that currently uses these variables.
++ *
++ * These variables are currently used only by _db_pargs_() and
++ * _db_doprnt_().
++ */
++
++ uint u_line; /* User source code line number */
++ int locked; /* If locked with _db_lock_file_ */
++ const char *u_keyword; /* Keyword for current macro */
++ uint m_read_lock_count;
++} CODE_STATE;
++
++/*
++ The test below is so we could call functions with DBUG_ENTER before
++ my_thread_init().
++*/
++#define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return
++#define get_code_state_or_return if (!((cs=code_state()))) return
++
++ /* Handling lists */
++#define ListAdd(A,B,C) ListAddDel(A,B,C,INCLUDE)
++#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
++static struct link *ListAddDel(struct link *, const char *, const char *, int);
++static struct link *ListCopy(struct link *);
++static int InList(struct link *linkp,const char *cp);
++static uint ListFlags(struct link *linkp);
++static void FreeList(struct link *linkp);
++
++ /* OpenClose debug output stream */
++static void DBUGOpenFile(CODE_STATE *,const char *, const char *, int);
++static void DBUGCloseFile(CODE_STATE *cs, FILE *fp);
++ /* Push current debug settings */
++static void PushState(CODE_STATE *cs);
++ /* Free memory associated with debug state. */
++static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
++ /* Test for tracing enabled */
++static int DoTrace(CODE_STATE *cs);
++/*
++ return values of DoTrace.
++ Can also be used as bitmask: ret & DO_TRACE
++*/
++#define DO_TRACE 1
++#define DONT_TRACE 2
++#define ENABLE_TRACE 3
++#define DISABLE_TRACE 4
++
++ /* Test to see if file is writable */
++#if defined(HAVE_ACCESS)
++static BOOLEAN Writable(const char *pathname);
++#endif
++
++static void DoPrefix(CODE_STATE *cs, uint line);
++
++static char *DbugMalloc(size_t size);
++static const char *BaseName(const char *pathname);
++static void Indent(CODE_STATE *cs, int indent);
++static void DbugFlush(CODE_STATE *);
++static void DbugExit(const char *why);
++static const char *DbugStrTok(const char *s);
++
++/*
++ * Miscellaneous printf format strings.
++ */
++
++#define ERR_MISSING_RETURN "missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
++#define ERR_MISSING_UNLOCK "missing DBUG_UNLOCK_FILE macro in function \"%s\"\n"
++#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
++#define ERR_CLOSE "%s: can't close debug file: "
++#define ERR_ABORT "%s: debugger aborting because %s\n"
++
++/*
++ * Macros and defines for testing file accessibility under UNIX and MSDOS.
++ */
++
++#undef EXISTS
++#if !defined(HAVE_ACCESS)
++#define EXISTS(pathname) (FALSE) /* Assume no existance */
++#define Writable(name) (TRUE)
++#else
++#define EXISTS(pathname) (access(pathname, F_OK) == 0)
++#define WRITABLE(pathname) (access(pathname, W_OK) == 0)
++#endif
++
++
++/*
++** Macros to allow dbugging with threads
++*/
++
++#include <my_pthread.h>
++static pthread_mutex_t THR_LOCK_dbug;
++
++/**
++ A mutex protecting flushing of gcov data, see _db_flush_gcov_().
++ We don't re-use THR_LOCK_dbug, because that would disallow:
++ DBUG_LOCK_FILE; ..... DBUG_SUICIDE(); .... DBUG_UNLOCK_FILE;
++*/
++static pthread_mutex_t THR_LOCK_gcov;
++static pthread_mutex_t THR_LOCK_init_settings;
++
++static CODE_STATE *code_state(void)
++{
++ CODE_STATE *cs, **cs_ptr;
++
++ /*
++ _dbug_on_ is reset if we don't plan to use any debug commands at all and
++ we want to run on maximum speed
++ */
++ if (!_dbug_on_)
++ return 0;
++
++ if (!init_done)
++ {
++ init_done=TRUE;
++ pthread_mutex_init(&THR_LOCK_dbug, NULL);
++ pthread_mutex_init(&THR_LOCK_gcov, NULL);
++ pthread_mutex_init(&THR_LOCK_init_settings, NULL);
++ memset(&init_settings, 0, sizeof(init_settings));
++ init_settings.out_file=stderr;
++ init_settings.flags=OPEN_APPEND;
++ }
++
++ if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug()))
++ return 0; /* Thread not initialised */
++ if (!(cs= *cs_ptr))
++ {
++ cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
++ memset(cs, 0, sizeof(*cs));
++ cs->process= db_process ? db_process : "dbug";
++ cs->func="?func";
++ cs->file="?file";
++ cs->stack=&init_settings;
++ cs->m_read_lock_count= 0;
++ *cs_ptr= cs;
++ }
++ return cs;
++}
++
++/**
++ Lock the stack debugging settings.
++ Only the shared (global) settings are locked if necessary,
++ per thread settings are local and safe to use.
++ This lock is re entrant.
++ @sa unlock_stack
++*/
++static void read_lock_stack(CODE_STATE *cs)
++{
++ if (cs->stack == &init_settings)
++ {
++ if (++(cs->m_read_lock_count) == 1)
++ pthread_mutex_lock(&THR_LOCK_init_settings);
++ }
++}
++
++/**
++ Unlock the stack debugging settings.
++ @sa read_lock_stack
++*/
++static void unlock_stack(CODE_STATE *cs)
++{
++ if (cs->stack == &init_settings)
++ {
++ if (--(cs->m_read_lock_count) == 0)
++ pthread_mutex_unlock(&THR_LOCK_init_settings);
++ }
++}
++
++/*
++ * Translate some calls among different systems.
++ */
++
++#ifdef HAVE_SLEEP
++/* sleep() wants seconds */
++#define Delay(A) sleep(((uint) A)/10)
++#else
++#define Delay(A) (0)
++#endif
++
++/*
++ * FUNCTION
++ *
++ * _db_process_ give the name to the current process/thread
++ *
++ * SYNOPSIS
++ *
++ * VOID _process_(name)
++ * char *name;
++ *
++ */
++
++void _db_process_(const char *name)
++{
++ CODE_STATE *cs;
++
++ if (!db_process)
++ db_process= name;
++
++ get_code_state_or_return;
++ cs->process= name;
++}
++
++/*
++ * FUNCTION
++ *
++ * DbugParse parse control string and set current debugger settings
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to a debug control string in "control",
++ * parses the control string, and sets
++ * up a current debug settings.
++ *
++ * The debug control string is a sequence of colon separated fields
++ * as follows:
++ *
++ * [+]<field_1>:<field_2>:...:<field_N>
++ *
++ * Each field consists of a mandatory flag character followed by
++ * an optional "," and comma separated list of modifiers:
++ *
++ * [sign]flag[,modifier,modifier,...,modifier]
++ *
++ * See the manual for the list of supported signs, flags, and modifiers
++ *
++ * For convenience, any leading "-#" is stripped off.
++ *
++ * RETURN
++ * 1 - a list of functions ("f" flag) was possibly changed
++ * 0 - a list of functions was not changed
++ */
++
++int DbugParse(CODE_STATE *cs, const char *control)
++{
++ const char *end;
++ int rel, f_used=0;
++ struct settings *stack;
++
++ /*
++ Make sure we are not changing settings while inside a
++ DBUG_LOCK_FILE
++ DBUG_UNLOCK_FILE
++ section, that is a mis use, that would cause changing
++ DBUG_FILE while the caller prints to it.
++ */
++ assert(! cs->locked);
++
++ stack= cs->stack;
++
++ /*
++ When parsing the global init_settings itself,
++ make sure to block every other thread using dbug functions.
++ */
++ assert(cs->m_read_lock_count == 0);
++ if (stack == &init_settings)
++ pthread_mutex_lock(&THR_LOCK_init_settings);
++
++ if (control[0] == '-' && control[1] == '#')
++ control+=2;
++
++ rel= control[0] == '+' || control[0] == '-';
++ if ((!rel || (!stack->out_file && !stack->next)))
++ {
++ /* Free memory associated with the state before resetting its members */
++ FreeState(cs, stack, 0);
++ stack->flags= 0;
++ stack->delay= 0;
++ stack->maxdepth= 0;
++ stack->sub_level= 0;
++ stack->out_file= stderr;
++ stack->prof_file= NULL;
++ stack->functions= NULL;
++ stack->p_functions= NULL;
++ stack->keywords= NULL;
++ stack->processes= NULL;
++ }
++ else if (!stack->out_file)
++ {
++ stack->flags= stack->next->flags;
++ stack->delay= stack->next->delay;
++ stack->maxdepth= stack->next->maxdepth;
++ stack->sub_level= stack->next->sub_level;
++ strcpy(stack->name, stack->next->name);
++ stack->prof_file= stack->next->prof_file;
++ if (stack->next == &init_settings)
++ {
++ assert(stack != &init_settings);
++ pthread_mutex_lock(&THR_LOCK_init_settings);
++
++ /*
++ Never share with the global parent - it can change under your feet.
++
++ Reset out_file to stderr to prevent sharing of trace files between
++ global and session settings.
++ */
++ stack->out_file= stderr;
++ stack->functions= ListCopy(init_settings.functions);
++ stack->p_functions= ListCopy(init_settings.p_functions);
++ stack->keywords= ListCopy(init_settings.keywords);
++ stack->processes= ListCopy(init_settings.processes);
++
++ pthread_mutex_unlock(&THR_LOCK_init_settings);
++ }
++ else
++ {
++ stack->out_file= stack->next->out_file;
++ stack->functions= stack->next->functions;
++ stack->p_functions= stack->next->p_functions;
++ stack->keywords= stack->next->keywords;
++ stack->processes= stack->next->processes;
++ }
++ }
++
++ end= DbugStrTok(control);
++ while (control < end)
++ {
++ int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
++ if (sign) control++;
++ c= *control++;
++ if (*control == ',') control++;
++ /* XXX when adding new cases here, don't forget _db_explain_ ! */
++ switch (c) {
++ case 'd':
++ if (sign < 0 && control == end)
++ {
++ if (!is_shared(stack, keywords))
++ FreeList(stack->keywords);
++ stack->keywords=NULL;
++ stack->flags &= ~DEBUG_ON;
++ break;
++ }
++ if (rel && is_shared(stack, keywords))
++ stack->keywords= ListCopy(stack->keywords);
++ if (sign < 0)
++ {
++ if (DEBUGGING)
++ stack->keywords= ListDel(stack->keywords, control, end);
++ break;
++ }
++ stack->keywords= ListAdd(stack->keywords, control, end);
++ stack->flags |= DEBUG_ON;
++ break;
++ case 'D':
++ stack->delay= atoi(control);
++ break;
++ case 'f':
++ f_used= 1;
++ if (sign < 0 && control == end)
++ {
++ if (!is_shared(stack,functions))
++ FreeList(stack->functions);
++ stack->functions=NULL;
++ break;
++ }
++ if (rel && is_shared(stack,functions))
++ stack->functions= ListCopy(stack->functions);
++ if (sign < 0)
++ stack->functions= ListDel(stack->functions, control, end);
++ else
++ stack->functions= ListAdd(stack->functions, control, end);
++ break;
++ case 'F':
++ if (sign < 0)
++ stack->flags &= ~FILE_ON;
++ else
++ stack->flags |= FILE_ON;
++ break;
++ case 'i':
++ if (sign < 0)
++ stack->flags &= ~PID_ON;
++ else
++ stack->flags |= PID_ON;
++ break;
++ case 'L':
++ if (sign < 0)
++ stack->flags &= ~LINE_ON;
++ else
++ stack->flags |= LINE_ON;
++ break;
++ case 'n':
++ if (sign < 0)
++ stack->flags &= ~DEPTH_ON;
++ else
++ stack->flags |= DEPTH_ON;
++ break;
++ case 'N':
++ if (sign < 0)
++ stack->flags &= ~NUMBER_ON;
++ else
++ stack->flags |= NUMBER_ON;
++ break;
++ case 'A':
++ case 'O':
++ stack->flags |= FLUSH_ON_WRITE;
++ /* fall through */
++ case 'a':
++ case 'o':
++ /* In case we already have an open file. */
++ if (!is_shared(stack, out_file))
++ DBUGCloseFile(cs, stack->out_file);
++ if (sign < 0)
++ {
++ stack->flags &= ~FLUSH_ON_WRITE;
++ stack->out_file= stderr;
++ break;
++ }
++ if (c == 'a' || c == 'A')
++ stack->flags |= OPEN_APPEND;
++ else
++ stack->flags &= ~OPEN_APPEND;
++ if (control != end)
++ DBUGOpenFile(cs, control, end, stack->flags & OPEN_APPEND);
++ else
++ DBUGOpenFile(cs, "-",0,0);
++ break;
++ case 'p':
++ if (sign < 0 && control == end)
++ {
++ if (!is_shared(stack,processes))
++ FreeList(stack->processes);
++ stack->processes=NULL;
++ break;
++ }
++ if (rel && is_shared(stack, processes))
++ stack->processes= ListCopy(stack->processes);
++ if (sign < 0)
++ stack->processes= ListDel(stack->processes, control, end);
++ else
++ stack->processes= ListAdd(stack->processes, control, end);
++ break;
++ case 'P':
++ if (sign < 0)
++ stack->flags &= ~PROCESS_ON;
++ else
++ stack->flags |= PROCESS_ON;
++ break;
++ case 'r':
++ stack->sub_level= cs->level;
++ break;
++ case 't':
++ if (sign < 0)
++ {
++ if (control != end)
++ stack->maxdepth-= atoi(control);
++ else
++ stack->maxdepth= 0;
++ }
++ else
++ {
++ if (control != end)
++ stack->maxdepth+= atoi(control);
++ else
++ stack->maxdepth= MAXDEPTH;
++ }
++ if (stack->maxdepth > 0)
++ stack->flags |= TRACE_ON;
++ else
++ stack->flags &= ~TRACE_ON;
++ break;
++ case 'T':
++ if (sign < 0)
++ stack->flags &= ~TIMESTAMP_ON;
++ else
++ stack->flags |= TIMESTAMP_ON;
++ break;
++ }
++ if (!*end)
++ break;
++ control=end+1;
++ end= DbugStrTok(control);
++ }
++
++ if (stack->next == &init_settings)
++ {
++ /*
++ Enforce nothing is shared with the global init_settings
++ */
++ assert((stack->functions == NULL) || (stack->functions != init_settings.functions));
++ assert((stack->p_functions == NULL) || (stack->p_functions != init_settings.p_functions));
++ assert((stack->keywords == NULL) || (stack->keywords != init_settings.keywords));
++ assert((stack->processes == NULL) || (stack->processes != init_settings.processes));
++ }
++
++ if (stack == &init_settings)
++ pthread_mutex_unlock(&THR_LOCK_init_settings);
++
++ return !rel || f_used;
++}
++
++#define framep_trace_flag(cs, frp) (frp ? \
++ frp->level & TRACE_ON : \
++ (ListFlags(cs->stack->functions) & INCLUDE) ? \
++ 0 : (uint)TRACE_ON)
++
++void FixTraceFlags_helper(CODE_STATE *cs, const char *func,
++ struct _db_stack_frame_ *framep)
++{
++ if (framep->prev)
++ FixTraceFlags_helper(cs, framep->func, framep->prev);
++
++ cs->func= func;
++ cs->level= framep->level & ~TRACE_ON;
++ framep->level= cs->level | framep_trace_flag(cs, framep->prev);
++ /*
++ we don't set cs->framep correctly, even though DoTrace uses it.
++ It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return
++ values, but we ignore them here anyway
++ */
++ switch(DoTrace(cs)) {
++ case ENABLE_TRACE:
++ framep->level|= TRACE_ON;
++ break;
++ case DISABLE_TRACE:
++ framep->level&= ~TRACE_ON;
++ break;
++ }
++}
++
++#define fflags(cs) cs->stack->out_file ? ListFlags(cs->stack->functions) : TRACE_ON;
++
++void FixTraceFlags(uint old_fflags, CODE_STATE *cs)
++{
++ const char *func;
++ uint new_fflags, traceon, level;
++ struct _db_stack_frame_ *framep;
++
++ /*
++ first (a.k.a. safety) check:
++ if we haven't started tracing yet, no call stack at all - we're safe.
++ */
++ framep=cs->framep;
++ if (framep == 0)
++ return;
++
++ /*
++ Ok, the tracing has started, call stack isn't empty.
++
++ second check: does the new list have a SUBDIR rule ?
++ */
++ new_fflags=fflags(cs);
++ if (new_fflags & SUBDIR)
++ goto yuck;
++
++ /*
++ Ok, new list doesn't use SUBDIR.
++
++ third check: we do NOT need to re-scan if
++ neither old nor new lists used SUBDIR flag and if a default behavior
++ (whether an unlisted function is traced) hasn't changed.
++ Default behavior depends on whether there're INCLUDE elements in the list.
++ */
++ if (!(old_fflags & SUBDIR) && !((new_fflags^old_fflags) & INCLUDE))
++ return;
++
++ /*
++ Ok, old list may've used SUBDIR, or defaults could've changed.
++
++ fourth check: are we inside a currently active SUBDIR rule ?
++ go up the call stack, if TRACE_ON flag ever changes its value - we are.
++ */
++ for (traceon=framep->level; framep; framep=framep->prev)
++ if ((traceon ^ framep->level) & TRACE_ON)
++ goto yuck;
++
++ /*
++ Ok, TRACE_ON flag doesn't change in the call stack.
++
++ fifth check: but is the top-most value equal to a default one ?
++ */
++ if (((traceon & TRACE_ON) != 0) == ((new_fflags & INCLUDE) == 0))
++ return;
++
++yuck:
++ /*
++ Yuck! function list was changed, and one of the currently active rules
++ was possibly affected. For example, a tracing could've been enabled or
++ disabled for a function somewhere up the call stack.
++ To react correctly, we must go up the call stack all the way to
++ the top and re-match rules to set TRACE_ON bit correctly.
++
++ We must traverse the stack forwards, not backwards.
++ That's what a recursive helper is doing.
++ It'll destroy two CODE_STATE fields, save them now.
++ */
++ func= cs->func;
++ level= cs->level;
++ FixTraceFlags_helper(cs, func, cs->framep);
++ /* now we only need to restore CODE_STATE fields, and we're done */
++ cs->func= func;
++ cs->level= level;
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_set_ set current debugger settings
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_set_(control)
++ * char *control;
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to a debug control string in "control",
++ * parses the control string, and sets up a current debug
++ * settings. Pushes a new debug settings if the current is
++ * set to the initial debugger settings.
++ *
++ */
++
++void _db_set_(const char *control)
++{
++ CODE_STATE *cs;
++ uint old_fflags;
++ get_code_state_or_return;
++
++ read_lock_stack(cs);
++ old_fflags=fflags(cs);
++ unlock_stack(cs);
++
++ if (cs->stack == &init_settings)
++ PushState(cs);
++
++ if (DbugParse(cs, control))
++ {
++ read_lock_stack(cs);
++ FixTraceFlags(old_fflags, cs);
++ unlock_stack(cs);
++ }
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_push_ push current debugger settings and set up new one
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_push_(control)
++ * char *control;
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to a debug control string in "control", pushes
++ * the current debug settings, parses the control string, and sets
++ * up a new debug settings with DbugParse()
++ *
++ */
++
++void _db_push_(const char *control)
++{
++ CODE_STATE *cs;
++ uint old_fflags;
++ get_code_state_or_return;
++
++ read_lock_stack(cs);
++ old_fflags=fflags(cs);
++ unlock_stack(cs);
++
++ PushState(cs);
++
++ if (DbugParse(cs, control))
++ {
++ read_lock_stack(cs);
++ FixTraceFlags(old_fflags, cs);
++ unlock_stack(cs);
++ }
++}
++
++
++/**
++ Returns TRUE if session-local settings have been set.
++*/
++
++int _db_is_pushed_()
++{
++ CODE_STATE *cs= NULL;
++ get_code_state_or_return FALSE;
++ return (cs->stack != &init_settings);
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_set_init_ set initial debugger settings
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_set_init_(control)
++ * char *control;
++ *
++ * DESCRIPTION
++ * see _db_set_
++ *
++ */
++
++void _db_set_init_(const char *control)
++{
++ CODE_STATE tmp_cs;
++ memset(&tmp_cs, 0, sizeof(tmp_cs));
++ tmp_cs.stack= &init_settings;
++ tmp_cs.process= db_process ? db_process : "dbug";
++ DbugParse(&tmp_cs, control);
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_pop_ pop the debug stack
++ *
++ * DESCRIPTION
++ *
++ * Pops the debug stack, returning the debug settings to its
++ * condition prior to the most recent _db_push_ invocation.
++ * Note that the pop will fail if it would remove the last
++ * valid settings from the stack. This prevents user errors
++ * in the push/pop sequence from screwing up the debugger.
++ * Maybe there should be some kind of warning printed if the
++ * user tries to pop too many states.
++ *
++ */
++
++void _db_pop_()
++{
++ struct settings *discard;
++ uint old_fflags;
++ CODE_STATE *cs;
++
++ get_code_state_or_return;
++
++ discard= cs->stack;
++ if (discard != &init_settings)
++ {
++ read_lock_stack(cs);
++ old_fflags=fflags(cs);
++ unlock_stack(cs);
++
++ cs->stack= discard->next;
++ FreeState(cs, discard, 1);
++
++ read_lock_stack(cs);
++ FixTraceFlags(old_fflags, cs);
++ unlock_stack(cs);
++ }
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_explain_ generates 'control' string for the current settings
++ *
++ * RETURN
++ * 0 - ok
++ * 1 - buffer too short, output truncated
++ *
++ */
++
++/* helper macros */
++#define char_to_buf(C) do { \
++ *buf++=(C); \
++ if (buf >= end) goto overflow; \
++ } while (0)
++#define str_to_buf(S) do { \
++ char_to_buf(','); \
++ buf=strnmov(buf, (S), len+1); \
++ if (buf >= end) goto overflow; \
++ } while (0)
++#define list_to_buf(l, f) do { \
++ struct link *listp=(l); \
++ while (listp) \
++ { \
++ if (listp->flags & (f)) \
++ { \
++ str_to_buf(listp->str); \
++ if (listp->flags & SUBDIR) \
++ char_to_buf('/'); \
++ } \
++ listp=listp->next_link; \
++ } \
++ } while (0)
++#define int_to_buf(i) do { \
++ char b[50]; \
++ int10_to_str((i), b, 10); \
++ str_to_buf(b); \
++ } while (0)
++#define colon_to_buf do { \
++ if (buf != start) char_to_buf(':'); \
++ } while(0)
++#define op_int_to_buf(C, val, def) do { \
++ if ((val) != (def)) \
++ { \
++ colon_to_buf; \
++ char_to_buf((C)); \
++ int_to_buf(val); \
++ } \
++ } while (0)
++#define op_intf_to_buf(C, val, def, cond) do { \
++ if ((cond)) \
++ { \
++ colon_to_buf; \
++ char_to_buf((C)); \
++ if ((val) != (def)) int_to_buf(val); \
++ } \
++ } while (0)
++#define op_str_to_buf(C, val, cond) do { \
++ if ((cond)) \
++ { \
++ char *s=(val); \
++ colon_to_buf; \
++ char_to_buf((C)); \
++ if (*s) str_to_buf(s); \
++ } \
++ } while (0)
++#define op_list_to_buf(C, val, cond) do { \
++ if ((cond)) \
++ { \
++ int f=ListFlags(val); \
++ colon_to_buf; \
++ char_to_buf((C)); \
++ if (f & INCLUDE) \
++ list_to_buf(val, INCLUDE); \
++ if (f & EXCLUDE) \
++ { \
++ colon_to_buf; \
++ char_to_buf('-'); \
++ char_to_buf((C)); \
++ list_to_buf(val, EXCLUDE); \
++ } \
++ } \
++ } while (0)
++#define op_bool_to_buf(C, cond) do { \
++ if ((cond)) \
++ { \
++ colon_to_buf; \
++ char_to_buf((C)); \
++ } \
++ } while (0)
++
++int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
++{
++ char *start=buf, *end=buf+len-4;
++
++ get_code_state_if_not_set_or_return *buf=0;
++
++ read_lock_stack(cs);
++
++ op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
++ op_int_to_buf ('D', cs->stack->delay, 0);
++ op_list_to_buf('f', cs->stack->functions, cs->stack->functions);
++ op_bool_to_buf('F', cs->stack->flags & FILE_ON);
++ op_bool_to_buf('i', cs->stack->flags & PID_ON);
++ op_list_to_buf('g', cs->stack->p_functions, PROFILING);
++ op_bool_to_buf('L', cs->stack->flags & LINE_ON);
++ op_bool_to_buf('n', cs->stack->flags & DEPTH_ON);
++ op_bool_to_buf('N', cs->stack->flags & NUMBER_ON);
++ op_str_to_buf(
++ ((cs->stack->flags & FLUSH_ON_WRITE ? 0 : 32) |
++ (cs->stack->flags & OPEN_APPEND ? 'A' : 'O')),
++ cs->stack->name, cs->stack->out_file != stderr);
++ op_list_to_buf('p', cs->stack->processes, cs->stack->processes);
++ op_bool_to_buf('P', cs->stack->flags & PROCESS_ON);
++ op_bool_to_buf('r', cs->stack->sub_level != 0);
++ op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING);
++ op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);
++
++ unlock_stack(cs);
++
++ *buf= '\0';
++ return 0;
++
++overflow:
++ *end++= '.';
++ *end++= '.';
++ *end++= '.';
++ *end= '\0';
++
++ unlock_stack(cs);
++ return 1;
++}
++
++#undef char_to_buf
++#undef str_to_buf
++#undef list_to_buf
++#undef int_to_buf
++#undef colon_to_buf
++#undef op_int_to_buf
++#undef op_intf_to_buf
++#undef op_str_to_buf
++#undef op_list_to_buf
++#undef op_bool_to_buf
++
++/*
++ * FUNCTION
++ *
++ * _db_explain_init_ explain initial debugger settings
++ *
++ * DESCRIPTION
++ * see _db_explain_
++ */
++
++int _db_explain_init_(char *buf, size_t len)
++{
++ CODE_STATE cs;
++ memset(&cs, 0, sizeof(cs));
++ cs.stack=&init_settings;
++ return _db_explain_(&cs, buf, len);
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_enter_ process entry point to user function
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_enter_(_func_, _file_, _line_, _stack_frame_)
++ * char *_func_; points to current function name
++ * char *_file_; points to current file name
++ * int _line_; called from source line number
++ * struct _db_stack_frame_ allocated on the caller's stack
++ *
++ * DESCRIPTION
++ *
++ * Called at the beginning of each user function to tell
++ * the debugger that a new function has been entered.
++ * Note that the pointers to the previous user function
++ * name and previous user file name are stored on the
++ * caller's stack (this is why the ENTER macro must be
++ * the first "executable" code in a function, since it
++ * allocates these storage locations). The previous nesting
++ * level is also stored on the callers stack for internal
++ * self consistency checks.
++ *
++ * Also prints a trace line if tracing is enabled and
++ * increments the current function nesting depth.
++ *
++ * Note that this mechanism allows the debugger to know
++ * what the current user function is at all times, without
++ * maintaining an internal stack for the function names.
++ *
++ */
++
++void _db_enter_(const char *_func_, const char *_file_,
++ uint _line_, struct _db_stack_frame_ *_stack_frame_)
++{
++ int save_errno;
++ CODE_STATE *cs;
++ if (!((cs=code_state())))
++ {
++ _stack_frame_->level= 0; /* Set to avoid valgrind warnings if dbug is enabled later */
++ _stack_frame_->prev= 0;
++ return;
++ }
++ save_errno= errno;
++
++ read_lock_stack(cs);
++
++ _stack_frame_->func= cs->func;
++ _stack_frame_->file= cs->file;
++ cs->func= _func_;
++ cs->file= _file_;
++ _stack_frame_->prev= cs->framep;
++ _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
++ cs->framep= _stack_frame_;
++
++ switch (DoTrace(cs)) {
++ case ENABLE_TRACE:
++ cs->framep->level|= TRACE_ON;
++ if (!TRACING) break;
++ /* fall through */
++ case DO_TRACE:
++ if (TRACING)
++ {
++ if (!cs->locked)
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ DoPrefix(cs, _line_);
++ Indent(cs, cs->level);
++ (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
++ DbugFlush(cs); /* This does a unlock */
++ }
++ break;
++ case DISABLE_TRACE:
++ cs->framep->level&= ~TRACE_ON;
++ /* fall through */
++ case DONT_TRACE:
++ break;
++ }
++ errno=save_errno;
++
++ unlock_stack(cs);
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_return_ process exit from user function
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_return_(_line_, _stack_frame_)
++ * int _line_; current source line number
++ * struct _db_stack_frame_ allocated on the caller's stack
++ *
++ * DESCRIPTION
++ *
++ * Called just before user function executes an explicit or implicit
++ * return. Prints a trace line if trace is enabled, decrements
++ * the current nesting level, and restores the current function and
++ * file names from the defunct function's stack.
++ *
++ */
++
++void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
++{
++ int save_errno=errno;
++ uint _slevel_= _stack_frame_->level & ~TRACE_ON;
++ CODE_STATE *cs;
++ get_code_state_or_return;
++
++ if (cs->framep != _stack_frame_)
++ {
++ char buf[512];
++ my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
++ DbugExit(buf);
++ }
++
++ read_lock_stack(cs);
++
++ if (DoTrace(cs) & DO_TRACE)
++ {
++ if (TRACING)
++ {
++ if (!cs->locked)
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ DoPrefix(cs, _line_);
++ Indent(cs, cs->level);
++ (void) fprintf(cs->stack->out_file, "<%s %u\n", cs->func, _line_);
++ DbugFlush(cs);
++ }
++ }
++ /*
++ Check to not set level < 0. This can happen if DBUG was disabled when
++ function was entered and enabled in function.
++ */
++ cs->level= _slevel_ != 0 ? _slevel_ - 1 : 0;
++ cs->func= _stack_frame_->func;
++ cs->file= _stack_frame_->file;
++ if (cs->framep != NULL)
++ cs->framep= cs->framep->prev;
++ errno=save_errno;
++
++ unlock_stack(cs);
++}
++
++
++/*
++ * FUNCTION
++ *
++ * _db_pargs_ log arguments for subsequent use by _db_doprnt_()
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_pargs_(_line_, keyword)
++ * int _line_;
++ * char *keyword;
++ *
++ * DESCRIPTION
++ *
++ * The new universal printing macro DBUG_PRINT, which replaces
++ * all forms of the DBUG_N macros, needs two calls to runtime
++ * support routines. The first, this function, remembers arguments
++ * that are used by the subsequent call to _db_doprnt_().
++ *
++ */
++
++void _db_pargs_(uint _line_, const char *keyword)
++{
++ CODE_STATE *cs;
++ get_code_state_or_return;
++ cs->u_line= _line_;
++ cs->u_keyword= keyword;
++}
++
++
++/*
++ * FUNCTION
++ *
++ * _db_doprnt_ handle print of debug lines
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_doprnt_(format, va_alist)
++ * char *format;
++ * va_dcl;
++ *
++ * DESCRIPTION
++ *
++ * When invoked via one of the DBUG macros, tests the current keyword
++ * set by calling _db_pargs_() to see if that macro has been selected
++ * for processing via the debugger control string, and if so, handles
++ * printing of the arguments via the format string. The line number
++ * of the DBUG macro in the source is found in u_line.
++ *
++ * Note that the format string SHOULD NOT include a terminating
++ * newline, this is supplied automatically.
++ *
++ */
++
++#include <stdarg.h>
++
++void _db_doprnt_(const char *format,...)
++{
++ va_list args;
++ CODE_STATE *cs;
++ get_code_state_or_return;
++
++ /* Dirty read, for DBUG_PRINT() performance. */
++ if (! DEBUGGING)
++ return;
++
++ va_start(args,format);
++ read_lock_stack(cs);
++
++ if (_db_keyword_(cs, cs->u_keyword, 0))
++ {
++ int save_errno=errno;
++ if (!cs->locked)
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ DoPrefix(cs, cs->u_line);
++ if (TRACING)
++ Indent(cs, cs->level + 1);
++ else
++ (void) fprintf(cs->stack->out_file, "%s: ", cs->func);
++ (void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
++ (void) vfprintf(cs->stack->out_file, format, args);
++ DbugFlush(cs);
++ errno=save_errno;
++ }
++ unlock_stack(cs);
++ va_end(args);
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_dump_ dump a string in hex
++ *
++ * SYNOPSIS
++ *
++ * void _db_dump_(_line_,keyword,memory,length)
++ * int _line_; current source line number
++ * char *keyword;
++ * char *memory; Memory to print
++ * int length; Bytes to print
++ *
++ * DESCRIPTION
++ * Dump N characters in a binary array.
++ * Is used to examine corrupted memory or arrays.
++ */
++
++void _db_dump_(uint _line_, const char *keyword,
++ const unsigned char *memory, size_t length)
++{
++ int pos;
++ CODE_STATE *cs;
++ get_code_state_or_return;
++
++ /* Dirty read, for DBUG_DUMP() performance. */
++ if (! DEBUGGING)
++ return;
++
++ read_lock_stack(cs);
++
++ if (_db_keyword_(cs, keyword, 0))
++ {
++ if (!cs->locked)
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ DoPrefix(cs, _line_);
++ if (TRACING)
++ {
++ Indent(cs, cs->level + 1);
++ pos= MIN(MAX(cs->level-cs->stack->sub_level,0)*INDENT,80);
++ }
++ else
++ {
++ fprintf(cs->stack->out_file, "%s: ", cs->func);
++ }
++ (void) fprintf(cs->stack->out_file, "%s: Memory: 0x%lx Bytes: (%ld)\n",
++ keyword, (ulong) memory, (long) length);
++
++ pos=0;
++ while (length-- > 0)
++ {
++ uint tmp= *((unsigned char*) memory++);
++ if ((pos+=3) >= 80)
++ {
++ fputc('\n',cs->stack->out_file);
++ pos=3;
++ }
++ fputc(_dig_vec_upper[((tmp >> 4) & 15)], cs->stack->out_file);
++ fputc(_dig_vec_upper[tmp & 15], cs->stack->out_file);
++ fputc(' ',cs->stack->out_file);
++ }
++ (void) fputc('\n',cs->stack->out_file);
++ DbugFlush(cs);
++ }
++
++ unlock_stack(cs);
++}
++
++
++/*
++ * FUNCTION
++ *
++ * ListAddDel modify the list according to debug control string
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to a comma separated list of strings in "cltp",
++ * parses the list, and modifies "listp", returning a pointer
++ * to the new list.
++ *
++ * The mode of operation is defined by "todo" parameter.
++ *
++ * If it is INCLUDE, elements (strings from "cltp") are added to the
++ * list, they will have INCLUDE flag set. If the list already contains
++ * the string in question, new element is not added, but a flag of
++ * the existing element is adjusted (INCLUDE bit is set, EXCLUDE bit
++ * is removed).
++ *
++ * If it is EXCLUDE, elements are added to the list with the EXCLUDE
++ * flag set. If the list already contains the string in question,
++ * it is removed, new element is not added.
++ */
++
++static struct link *ListAddDel(struct link *head, const char *ctlp,
++ const char *end, int todo)
++{
++ const char *start;
++ struct link **cur;
++ size_t len;
++ int subdir;
++
++ ctlp--;
++next:
++ while (++ctlp < end)
++ {
++ start= ctlp;
++ subdir=0;
++ while (ctlp < end && *ctlp != ',')
++ ctlp++;
++ len=ctlp-start;
++ if (start[len-1] == '/')
++ {
++ len--;
++ subdir=SUBDIR;
++ }
++ if (len == 0) continue;
++ for (cur=&head; *cur; cur=&((*cur)->next_link))
++ {
++ if (!strncmp((*cur)->str, start, len))
++ {
++ if ((*cur)->flags & todo) /* same action ? */
++ (*cur)->flags|= subdir; /* just merge the SUBDIR flag */
++ else if (todo == EXCLUDE)
++ {
++ struct link *delme=*cur;
++ *cur=(*cur)->next_link;
++ free((void*) delme);
++ }
++ else
++ {
++ (*cur)->flags&=~(EXCLUDE | SUBDIR);
++ (*cur)->flags|=INCLUDE | subdir;
++ }
++ goto next;
++ }
++ }
++ *cur= (struct link *) DbugMalloc(sizeof(struct link)+len);
++ memcpy((*cur)->str, start, len);
++ (*cur)->str[len]=0;
++ (*cur)->flags=todo | subdir;
++ (*cur)->next_link=0;
++ }
++ return head;
++}
++
++/*
++ * FUNCTION
++ *
++ * ListCopy make a copy of the list
++ *
++ * SYNOPSIS
++ *
++ * static struct link *ListCopy(orig)
++ * struct link *orig;
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to list, which contains a copy of every element from
++ * the original list.
++ *
++ * the orig pointer can be NULL
++ *
++ * Note that since each link is added at the head of the list,
++ * the final list will be in "reverse order", which is not
++ * significant for our usage here.
++ *
++ */
++
++static struct link *ListCopy(struct link *orig)
++{
++ struct link *new_malloc;
++ struct link *head;
++ size_t len;
++
++ head= NULL;
++ while (orig != NULL)
++ {
++ len= strlen(orig->str);
++ new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
++ memcpy(new_malloc->str, orig->str, len);
++ new_malloc->str[len]= 0;
++ new_malloc->flags=orig->flags;
++ new_malloc->next_link= head;
++ head= new_malloc;
++ orig= orig->next_link;
++ }
++ return head;
++}
++
++/*
++ * FUNCTION
++ *
++ * InList test a given string for member of a given list
++ *
++ * DESCRIPTION
++ *
++ * Tests the string pointed to by "cp" to determine if it is in
++ * the list pointed to by "linkp". Linkp points to the first
++ * link in the list. If linkp is NULL or contains only EXCLUDE
++ * elements then the string is treated as if it is in the list.
++ * This may seem rather strange at first but leads to the desired
++ * operation if no list is given. The net effect is that all
++ * strings will be accepted when there is no list, and when there
++ * is a list, only those strings in the list will be accepted.
++ *
++ * RETURN
++ * combination of SUBDIR, INCLUDE, EXCLUDE, MATCHED flags
++ *
++ */
++
++static int InList(struct link *linkp, const char *cp)
++{
++ int result;
++
++ for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
++ {
++ if (!fnmatch(linkp->str, cp, 0))
++ return linkp->flags;
++ if (!(linkp->flags & EXCLUDE))
++ result=NOT_MATCHED;
++ if (linkp->flags & SUBDIR)
++ result|=SUBDIR;
++ }
++ return result;
++}
++
++/*
++ * FUNCTION
++ *
++ * ListFlags returns aggregated list flags (ORed over all elements)
++ *
++ */
++
++static uint ListFlags(struct link *linkp)
++{
++ uint f;
++ for (f=0; linkp != NULL; linkp= linkp->next_link)
++ f|= linkp->flags;
++ return f;
++}
++
++/*
++ * FUNCTION
++ *
++ * PushState push current settings onto stack and set up new one
++ *
++ * SYNOPSIS
++ *
++ * static VOID PushState()
++ *
++ * DESCRIPTION
++ *
++ * Pushes the current settings on the settings stack, and creates
++ * a new settings. The new settings is NOT initialized
++ *
++ * The settings stack is a linked list of settings, with the new
++ * settings added at the head. This allows the stack to grow
++ * to the limits of memory if necessary.
++ *
++ */
++
++static void PushState(CODE_STATE *cs)
++{
++ struct settings *new_malloc;
++
++ new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
++ memset(new_malloc, 0, sizeof(struct settings));
++ new_malloc->next= cs->stack;
++ cs->stack= new_malloc;
++}
++
++/*
++ * FUNCTION
++ *
++ * FreeState Free memory associated with a struct state.
++ *
++ * SYNOPSIS
++ *
++ * static void FreeState (state)
++ * struct state *state;
++ * int free_state;
++ *
++ * DESCRIPTION
++ *
++ * Deallocates the memory allocated for various information in a
++ * state. If free_state is set, also free 'state'
++ *
++ */
++static void FreeState(CODE_STATE *cs, struct settings *state, int free_state)
++{
++ if (!is_shared(state, keywords))
++ FreeList(state->keywords);
++ if (!is_shared(state, functions))
++ FreeList(state->functions);
++ if (!is_shared(state, processes))
++ FreeList(state->processes);
++ if (!is_shared(state, p_functions))
++ FreeList(state->p_functions);
++
++ if (!is_shared(state, out_file))
++ DBUGCloseFile(cs, state->out_file);
++ else
++ (void) fflush(state->out_file);
++
++ if (!is_shared(state, prof_file))
++ DBUGCloseFile(cs, state->prof_file);
++ else
++ (void) fflush(state->prof_file);
++
++ if (free_state)
++ free((void*) state);
++}
++
++
++/*
++ * FUNCTION
++ *
++ * _db_end_ End debugging, freeing state stack memory.
++ *
++ * SYNOPSIS
++ *
++ * static VOID _db_end_ ()
++ *
++ * DESCRIPTION
++ *
++ * Ends debugging, de-allocating the memory allocated to the
++ * state stack.
++ *
++ * To be called at the very end of the program.
++ *
++ */
++void _db_end_()
++{
++ struct settings *discard;
++ static struct settings tmp;
++ CODE_STATE *cs;
++ /*
++ Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was
++ called after dbug was initialized
++ */
++ _dbug_on_= 1;
++ get_code_state_or_return;
++
++ /*
++ The caller may have missed a DBUG_UNLOCK_FILE,
++ we are breaking this lock to enforce DBUG_END can proceed.
++ */
++ if (cs->locked)
++ {
++ fprintf(stderr, ERR_MISSING_UNLOCK, "(unknown)");
++ cs->locked= 0;
++ pthread_mutex_unlock(&THR_LOCK_dbug);
++ }
++
++ while ((discard= cs->stack))
++ {
++ if (discard == &init_settings)
++ break;
++ cs->stack= discard->next;
++ FreeState(cs, discard, 1);
++ }
++
++ pthread_mutex_lock(&THR_LOCK_init_settings);
++ tmp= init_settings;
++ init_settings.flags= OPEN_APPEND;
++ init_settings.out_file= stderr;
++ init_settings.prof_file= stderr;
++ init_settings.maxdepth= 0;
++ init_settings.delay= 0;
++ init_settings.sub_level= 0;
++ init_settings.functions= 0;
++ init_settings.p_functions= 0;
++ init_settings.keywords= 0;
++ init_settings.processes= 0;
++ pthread_mutex_unlock(&THR_LOCK_init_settings);
++ FreeState(cs, &tmp, 0);
++}
++
++
++/*
++ * FUNCTION
++ *
++ * DoTrace check to see if tracing is current enabled
++ *
++ * DESCRIPTION
++ *
++ * Checks to see if dbug in this function is enabled based on
++ * whether the maximum trace depth has been reached, the current
++ * function is selected, and the current process is selected.
++ *
++ */
++
++static int DoTrace(CODE_STATE *cs)
++{
++ if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
++ InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
++ switch(InList(cs->stack->functions, cs->func)) {
++ case INCLUDE|SUBDIR: return ENABLE_TRACE;
++ case INCLUDE: return DO_TRACE;
++ case MATCHED|SUBDIR:
++ case NOT_MATCHED|SUBDIR:
++ case MATCHED: return framep_trace_flag(cs, cs->framep) ?
++ DO_TRACE : DONT_TRACE;
++ case EXCLUDE:
++ case NOT_MATCHED: return DONT_TRACE;
++ case EXCLUDE|SUBDIR: return DISABLE_TRACE;
++ }
++ return DONT_TRACE;
++}
++
++FILE *_db_fp_(void)
++{
++ CODE_STATE *cs;
++ get_code_state_or_return NULL;
++ return cs->stack->out_file;
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_keyword_ test keyword for member of keyword list
++ *
++ * DESCRIPTION
++ *
++ * Test a keyword to determine if it is in the currently active
++ * keyword list. If strict=0, a keyword is accepted
++ * if the list is null, otherwise it must match one of the list
++ * members. When debugging is not on, no keywords are accepted.
++ * After the maximum trace level is exceeded, no keywords are
++ * accepted (this behavior subject to change). Additionally,
++ * the current function and process must be accepted based on
++ * their respective lists.
++ *
++ * Returns TRUE if keyword accepted, FALSE otherwise.
++ *
++ */
++
++BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
++{
++ BOOLEAN result;
++ get_code_state_if_not_set_or_return FALSE;
++
++ /* Dirty read, for DBUG_EXECUTE(), DBUG_EXECUTE_IF() ... performance. */
++ if (! DEBUGGING)
++ return FALSE;
++
++ read_lock_stack(cs);
++
++ strict=strict ? INCLUDE : INCLUDE|MATCHED;
++ result= DoTrace(cs) & DO_TRACE &&
++ InList(cs->stack->keywords, keyword) & strict;
++
++ unlock_stack(cs);
++
++ return result;
++}
++
++/*
++ * FUNCTION
++ *
++ * Indent indent a line to the given indentation level
++ *
++ * SYNOPSIS
++ *
++ * static VOID Indent(indent)
++ * int indent;
++ *
++ * DESCRIPTION
++ *
++ * Indent a line to the given level. Note that this is
++ * a simple minded but portable implementation.
++ * There are better ways.
++ *
++ * Also, the indent must be scaled by the compile time option
++ * of character positions per nesting level.
++ *
++ */
++
++static void Indent(CODE_STATE *cs, int indent)
++{
++ int count;
++
++ indent= MAX(indent-1-cs->stack->sub_level,0)*INDENT;
++ for (count= 0; count < indent ; count++)
++ {
++ if ((count % INDENT) == 0)
++ fputc('|',cs->stack->out_file);
++ else
++ fputc(' ',cs->stack->out_file);
++ }
++}
++
++
++/*
++ * FUNCTION
++ *
++ * FreeList free all memory associated with a linked list
++ *
++ * SYNOPSIS
++ *
++ * static VOID FreeList(linkp)
++ * struct link *linkp;
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to the head of a linked list, frees all
++ * memory held by the list and the members of the list.
++ *
++ */
++
++static void FreeList(struct link *linkp)
++{
++ struct link *old;
++
++ while (linkp != NULL)
++ {
++ old= linkp;
++ linkp= linkp->next_link;
++ free((void*) old);
++ }
++}
++
++
++/*
++ * FUNCTION
++ *
++ * DoPrefix print debugger line prefix prior to indentation
++ *
++ * SYNOPSIS
++ *
++ * static VOID DoPrefix(_line_)
++ * int _line_;
++ *
++ * DESCRIPTION
++ *
++ * Print prefix common to all debugger output lines, prior to
++ * doing indentation if necessary. Print such information as
++ * current process name, current source file name and line number,
++ * and current function nesting depth.
++ *
++ */
++
++static void DoPrefix(CODE_STATE *cs, uint _line_)
++{
++ cs->lineno++;
++ if (cs->stack->flags & PID_ON)
++ {
++ (void) fprintf(cs->stack->out_file, "%-7s: ", my_thread_name());
++ }
++ if (cs->stack->flags & NUMBER_ON)
++ (void) fprintf(cs->stack->out_file, "%5d: ", cs->lineno);
++ if (cs->stack->flags & TIMESTAMP_ON)
++ {
++#ifdef _WIN32
++ /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
++ in system ticks, 10 ms intervals. See my_getsystime.c for high res */
++ SYSTEMTIME loc_t;
++ GetLocalTime(&loc_t);
++ (void) fprintf (cs->stack->out_file,
++ /* "%04d-%02d-%02d " */
++ "%02d:%02d:%02d.%06d ",
++ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
++ loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
++#else
++ struct timeval tv;
++ struct tm *tm_p;
++ if (gettimeofday(&tv, NULL) != -1)
++ {
++ if ((tm_p= localtime((const time_t *)&tv.tv_sec)))
++ {
++ (void) fprintf (cs->stack->out_file,
++ /* "%04d-%02d-%02d " */
++ "%02d:%02d:%02d.%06d ",
++ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
++ tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
++ (int) (tv.tv_usec));
++ }
++ }
++#endif
++ }
++ if (cs->stack->flags & PROCESS_ON)
++ (void) fprintf(cs->stack->out_file, "%s: ", cs->process);
++ if (cs->stack->flags & FILE_ON)
++ (void) fprintf(cs->stack->out_file, "%14s: ", BaseName(cs->file));
++ if (cs->stack->flags & LINE_ON)
++ (void) fprintf(cs->stack->out_file, "%5d: ", _line_);
++ if (cs->stack->flags & DEPTH_ON)
++ (void) fprintf(cs->stack->out_file, "%4d: ", cs->level);
++}
++
++
++/*
++ * FUNCTION
++ *
++ * DBUGOpenFile open new output stream for debugger output
++ *
++ * SYNOPSIS
++ *
++ * static VOID DBUGOpenFile(name)
++ * char *name;
++ *
++ * DESCRIPTION
++ *
++ * Given name of a new file (or "-" for stdout) opens the file
++ * and sets the output stream to the new file.
++ *
++ */
++
++static void DBUGOpenFile(CODE_STATE *cs,
++ const char *name,const char *end,int append)
++{
++ FILE *fp;
++
++ if (name != NULL)
++ {
++ if (end)
++ {
++ size_t len=end-name;
++ memcpy(cs->stack->name, name, len);
++ cs->stack->name[len]=0;
++ }
++ else
++ strmov(cs->stack->name,name);
++ name=cs->stack->name;
++ if (strcmp(name, "-") == 0)
++ {
++ cs->stack->out_file= stdout;
++ cs->stack->flags |= FLUSH_ON_WRITE;
++ cs->stack->name[0]=0;
++ }
++ else
++ {
++ if (!Writable(name))
++ {
++ (void) fprintf(stderr, ERR_OPEN, cs->process, name);
++ perror("");
++ fflush(stderr);
++ }
++ else
++ {
++#ifdef _WIN32
++ if (fopen_s(&fp, name, append ? "a+" : "w"))
++#else
++ if (!(fp= fopen(name, append ? "a+" : "w")))
++#endif
++ {
++ (void) fprintf(stderr, ERR_OPEN, cs->process, name);
++ perror("");
++ fflush(stderr);
++ }
++ else
++ {
++ cs->stack->out_file= fp;
++ }
++ }
++ }
++ }
++}
++
++/*
++ * FUNCTION
++ *
++ * DBUGCloseFile close the debug output stream
++ *
++ * SYNOPSIS
++ *
++ * static VOID DBUGCloseFile(fp)
++ * FILE *fp;
++ *
++ * DESCRIPTION
++ *
++ * Closes the debug output stream unless it is standard output
++ * or standard error.
++ *
++ */
++
++static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
++{
++ if (fp != NULL && fp != stderr && fp != stdout && fclose(fp) == EOF)
++ {
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ (void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
++ perror("");
++ DbugFlush(cs);
++ }
++}
++
++
++/*
++ * FUNCTION
++ *
++ * DbugExit print error message and exit
++ *
++ * SYNOPSIS
++ *
++ * static VOID DbugExit(why)
++ * char *why;
++ *
++ * DESCRIPTION
++ *
++ * Prints error message using current process name, the reason for
++ * aborting (typically out of memory), and exits with status 1.
++ * This should probably be changed to use a status code
++ * defined in the user's debugger include file.
++ *
++ */
++
++static void DbugExit(const char *why)
++{
++ CODE_STATE *cs=code_state();
++ (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
++ (void) fflush(stderr);
++ DBUG_ABORT();
++}
++
++
++/*
++ * FUNCTION
++ *
++ * DbugMalloc allocate memory for debugger runtime support
++ *
++ * SYNOPSIS
++ *
++ * static long *DbugMalloc(size)
++ * int size;
++ *
++ * DESCRIPTION
++ *
++ * Allocate more memory for debugger runtime support functions.
++ * Failure to to allocate the requested number of bytes is
++ * immediately fatal to the current process. This may be
++ * rather unfriendly behavior. It might be better to simply
++ * print a warning message, freeze the current debugger cs,
++ * and continue execution.
++ *
++ */
++
++static char *DbugMalloc(size_t size)
++{
++ char *new_malloc;
++
++ if (!(new_malloc= (char*) malloc(size)))
++ DbugExit("out of memory");
++ return new_malloc;
++}
++
++
++/*
++ * strtok lookalike - splits on ':', magically handles ::, :\ and :/
++ */
++
++static const char *DbugStrTok(const char *s)
++{
++ while (s[0] && (s[0] != ':' ||
++ (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++))))
++ s++;
++ return s;
++}
++
++
++/*
++ * FUNCTION
++ *
++ * BaseName strip leading pathname components from name
++ *
++ * SYNOPSIS
++ *
++ * static char *BaseName(pathname)
++ * char *pathname;
++ *
++ * DESCRIPTION
++ *
++ * Given pointer to a complete pathname, locates the base file
++ * name at the end of the pathname and returns a pointer to
++ * it.
++ *
++ */
++
++static const char *BaseName(const char *pathname)
++{
++ const char *base;
++
++ base= strrchr(pathname, FN_LIBCHAR);
++ if (base++ == NullS)
++ base= pathname;
++ return base;
++}
++
++
++/*
++ * FUNCTION
++ *
++ * Writable test to see if a pathname is writable/creatable
++ *
++ * SYNOPSIS
++ *
++ * static BOOLEAN Writable(pathname)
++ * char *pathname;
++ *
++ * DESCRIPTION
++ *
++ * Because the debugger might be linked in with a program that
++ * runs with the set-uid-bit (suid) set, we have to be careful
++ * about opening a user named file for debug output. This consists
++ * of checking the file for write access with the real user id,
++ * or checking the directory where the file will be created.
++ *
++ * Returns TRUE if the user would normally be allowed write or
++ * create access to the named file. Returns FALSE otherwise.
++ *
++ */
++
++
++#ifndef Writable
++
++static BOOLEAN Writable(const char *pathname)
++{
++ BOOLEAN granted;
++ char *lastslash;
++
++ granted= FALSE;
++ if (EXISTS(pathname))
++ {
++ if (WRITABLE(pathname))
++ granted= TRUE;
++ }
++ else
++ {
++ lastslash= strrchr(pathname, '/');
++ if (lastslash != NULL)
++ *lastslash= '\0';
++ else
++ pathname= ".";
++ if (WRITABLE(pathname))
++ granted= TRUE;
++ if (lastslash != NULL)
++ *lastslash= '/';
++ }
++ return granted;
++}
++#endif
++
++
++/*
++ * FUNCTION
++ *
++ * _db_setjmp_ save debugger environment
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_setjmp_()
++ *
++ * DESCRIPTION
++ *
++ * Invoked as part of the user's DBUG_SETJMP macro to save
++ * the debugger environment in parallel with saving the user's
++ * environment.
++ *
++ */
++
++#ifdef HAVE_LONGJMP
++
++EXPORT void _db_setjmp_()
++{
++ CODE_STATE *cs;
++ get_code_state_or_return;
++
++ cs->jmplevel= cs->level;
++ cs->jmpfunc= cs->func;
++ cs->jmpfile= cs->file;
++}
++
++/*
++ * FUNCTION
++ *
++ * _db_longjmp_ restore previously saved debugger environment
++ *
++ * SYNOPSIS
++ *
++ * VOID _db_longjmp_()
++ *
++ * DESCRIPTION
++ *
++ * Invoked as part of the user's DBUG_LONGJMP macro to restore
++ * the debugger environment in parallel with restoring the user's
++ * previously saved environment.
++ *
++ */
++
++EXPORT void _db_longjmp_()
++{
++ CODE_STATE *cs;
++ get_code_state_or_return;
++
++ cs->level= cs->jmplevel;
++ if (cs->jmpfunc)
++ cs->func= cs->jmpfunc;
++ if (cs->jmpfile)
++ cs->file= cs->jmpfile;
++}
++#endif
++
++/*
++ * FUNCTION
++ *
++ * perror perror simulation for systems that don't have it
++ *
++ * SYNOPSIS
++ *
++ * static VOID perror(s)
++ * char *s;
++ *
++ * DESCRIPTION
++ *
++ * Perror produces a message on the standard error stream which
++ * provides more information about the library or system error
++ * just encountered. The argument string s is printed, followed
++ * by a ':', a blank, and then a message and a newline.
++ *
++ * An undocumented feature of the unix perror is that if the string
++ * 's' is a null string (NOT a NULL pointer!), then the ':' and
++ * blank are not printed.
++ *
++ * This version just complains about an "unknown system error".
++ *
++ */
++
++#ifndef HAVE_PERROR
++static void perror(s)
++char *s;
++{
++ if (s && *s != '\0')
++ (void) fprintf(stderr, "%s: ", s);
++ (void) fprintf(stderr, "<unknown system error>\n");
++}
++#endif /* HAVE_PERROR */
++
++
++ /* flush dbug-stream, free mutex lock & wait delay */
++ /* This is because some systems (MSDOS!!) dosn't flush fileheader */
++ /* and dbug-file isn't readable after a system crash !! */
++
++static void DbugFlush(CODE_STATE *cs)
++{
++ if (cs->stack->flags & FLUSH_ON_WRITE)
++ {
++ (void) fflush(cs->stack->out_file);
++ if (cs->stack->delay)
++ (void) Delay(cs->stack->delay);
++ }
++ if (!cs->locked)
++ pthread_mutex_unlock(&THR_LOCK_dbug);
++} /* DbugFlush */
++
++
++/* For debugging */
++
++void _db_flush_()
++{
++ CODE_STATE *cs= NULL;
++ get_code_state_or_return;
++ (void) fflush(cs->stack->out_file);
++}
++
++
++#ifndef _WIN32
++
++#ifdef HAVE_GCOV
++extern void __gcov_flush();
++#endif
++
++void _db_flush_gcov_()
++{
++#ifdef HAVE_GCOV
++ // Gcov will assert() if we try to flush in parallel.
++ pthread_mutex_lock(&THR_LOCK_gcov);
++ __gcov_flush();
++ pthread_mutex_unlock(&THR_LOCK_gcov);
++#endif
++}
++
++void _db_suicide_()
++{
++ int retval;
++ sigset_t new_mask;
++ sigfillset(&new_mask);
++
++#ifdef HAVE_GCOV
++ fprintf(stderr, "Flushing gcov data\n");
++ fflush(stderr);
++ _db_flush_gcov_();
++#endif
++
++ fprintf(stderr, "SIGKILL myself\n");
++ fflush(stderr);
++
++ retval= kill(getpid(), SIGKILL);
++ assert(retval == 0);
++ retval= sigsuspend(&new_mask);
++ fprintf(stderr, "sigsuspend returned %d errno %d \n", retval, errno);
++ assert(FALSE); /* With full signal mask, we should never return here. */
++}
++#endif /* ! _WIN32 */
++
++
++void _db_lock_file_()
++{
++ CODE_STATE *cs;
++ get_code_state_or_return;
++ pthread_mutex_lock(&THR_LOCK_dbug);
++ cs->locked=1;
++}
++
++void _db_unlock_file_()
++{
++ CODE_STATE *cs;
++ get_code_state_or_return;
++ cs->locked=0;
++ pthread_mutex_unlock(&THR_LOCK_dbug);
++}
++
++const char* _db_get_func_(void)
++{
++ CODE_STATE *cs;
++ get_code_state_or_return NULL;
++ return cs->func;
++}
++
++
++#else
++
++/*
++ * Dummy function, workaround for MySQL bug#14420 related
++ * build failure on a platform where linking with an empty
++ * archive fails.
++ *
++ * This block can be removed as soon as a fix for bug#14420
++ * is implemented.
++ */
++int i_am_a_dummy_function() {
++ return 0;
++}
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/default.c mariadb-native-client.trunk/libmariadb/default.c
+--- mariadb/libmariadb/default.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/default.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,414 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/****************************************************************************
++** Add all options from files named "group".cnf from the default_directories
++** before the command line arguments.
++** On Windows defaults will also search in the Windows directory for a file
++** called 'group'.ini
++** As long as the program uses the last argument for conflicting
++** options one only have to add a call to "load_defaults" to enable
++** use of default values.
++** pre- and end 'blank space' are removed from options and values. The
++** following escape sequences are recognized in values: \b \t \n \r \\
++**
++** The following arguments are handled automaticly; If used, they must be
++** first argument on the command line!
++** --no-defaults ; no options are read.
++** --defaults-file=full-path-to-default-file ; Only this file will be read.
++** --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
++** --print-defaults ; Print the modified command line and exit
++****************************************************************************/
++
++#undef SAFEMALLOC /* safe_malloc is not yet initailized */
++
++#include "mysys_priv.h"
++#include "m_string.h"
++#include <ctype.h>
++#include "m_ctype.h"
++#include <my_dir.h>
++
++char *defaults_extra_file=0;
++
++/* Which directories are searched for options (and in which order) */
++
++const char *default_directories[]= {
++#ifdef _WIN32
++"C:/",
++#else
++"/etc/",
++#endif
++#ifdef DATADIR
++DATADIR,
++#endif
++"", /* Place for defaults_extra_dir */
++#ifndef _WIN32
++"~/",
++#endif
++NullS,
++};
++
++#define default_ext ".cnf" /* extension for config file */
++#ifdef _WIN32
++#include <winbase.h>
++#define windows_ext ".ini"
++#endif
++
++static my_bool search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc,
++ const char *dir, const char *config_file,
++ const char *ext, TYPELIB *group);
++
++
++void load_defaults(const char *conf_file, const char **groups,
++ int *argc, char ***argv)
++{
++ DYNAMIC_ARRAY args;
++ const char **dirs, *forced_default_file;
++ TYPELIB group;
++ my_bool found_print_defaults=0;
++ uint args_used=0;
++ MEM_ROOT alloc;
++ char *ptr,**res;
++ DBUG_ENTER("load_defaults");
++
++ init_alloc_root(&alloc,128,0);
++ if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
++ {
++ /* remove the --no-defaults argument and return only the other arguments */
++ uint i;
++ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
++ (*argc + 1)*sizeof(char*))))
++ goto err;
++ res= (char**) (ptr+sizeof(alloc));
++ res[0]= **argv; /* Copy program name */
++ for (i=2 ; i < (uint) *argc ; i++)
++ res[i-1]=argv[0][i];
++ (*argc)--;
++ *argv=res;
++ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
++ DBUG_VOID_RETURN;
++ }
++
++ /* Check if we want to force the use a specific default file */
++ forced_default_file=0;
++ if (*argc >= 2)
++ {
++ if (is_prefix(argv[0][1],"--defaults-file="))
++ {
++ forced_default_file=strchr(argv[0][1],'=')+1;
++ args_used++;
++ }
++ else if (is_prefix(argv[0][1],"--defaults-extra-file="))
++ {
++ defaults_extra_file=strchr(argv[0][1],'=')+1;
++ args_used++;
++ }
++ }
++
++ group.count=0;
++ group.name= "defaults";
++ group.type_names= groups;
++ for (; *groups ; groups++)
++ group.count++;
++
++ if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
++ goto err;
++ if (forced_default_file)
++ {
++ if (search_default_file(&args, &alloc, "", forced_default_file, "",
++ &group))
++ goto err;
++ }
++ else if (dirname_length(conf_file))
++ {
++ if (search_default_file(&args, &alloc, NullS, conf_file, default_ext,
++ &group))
++ goto err;
++ }
++ else
++ {
++#ifdef _WIN32
++ char system_dir[FN_REFLEN];
++ GetWindowsDirectory(system_dir,sizeof(system_dir));
++ if (search_default_file(&args, &alloc, system_dir, conf_file, windows_ext,
++ &group))
++ goto err;
++#endif
++#if defined(__EMX__) || defined(OS2)
++ if (getenv("ETC") &&
++ search_default_file(&args, &alloc, getenv("ETC"), conf_file,
++ default_ext, &group))
++ goto err;
++#endif
++ for (dirs=default_directories ; *dirs; dirs++)
++ {
++ int error=0;
++ if (**dirs)
++ error=search_default_file(&args, &alloc, *dirs, conf_file,
++ default_ext, &group);
++ else if (defaults_extra_file)
++ error=search_default_file(&args, &alloc, NullS, defaults_extra_file,
++ default_ext, &group);
++ if (error)
++ goto err;
++ }
++ }
++ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
++ (args.elements + *argc +1) *sizeof(char*))))
++ goto err;
++ res= (char**) (ptr+sizeof(alloc));
++
++ /* copy name + found arguments + command line arguments to new array */
++ res[0]=argv[0][0];
++ memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
++ /* Skipp --defaults-file and --defaults-extra-file */
++ (*argc)-= args_used;
++ (*argv)+= args_used;
++
++ /* Check if we wan't to see the new argument list */
++ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
++ {
++ found_print_defaults=1;
++ --*argc; ++*argv; /* skipp argument */
++ }
++
++ memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
++ (*argc-1)*sizeof(char*));
++ res[args.elements+ *argc]=0; /* last null */
++
++ (*argc)+=args.elements;
++ *argv= (char**) res;
++ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
++ delete_dynamic(&args);
++ if (found_print_defaults)
++ {
++ int i;
++ printf("%s would have been started with the following arguments:\n",
++ **argv);
++ for (i=1 ; i < *argc ; i++)
++ printf("%s ", (*argv)[i]);
++ puts("");
++ exit(1);
++ }
++ DBUG_VOID_RETURN;
++
++ err:
++ fprintf(stderr,"Program aborted\n");
++ exit(1);
++}
++
++
++void free_defaults(char **argv)
++{
++ MEM_ROOT ptr;
++ memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
++ free_root(&ptr,MYF(0));
++}
++
++
++static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
++ const char *dir, const char *config_file,
++ const char *ext, TYPELIB *group)
++{
++ char name[FN_REFLEN+10],buff[4096],*ptr,*end,*value,*tmp;
++ FILE *fp;
++ uint line=0;
++ my_bool read_values=0,found_group=0;
++
++ if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
++ return 0; /* Ignore wrong paths */
++ if (dir)
++ {
++ strmov(name,dir);
++ convert_dirname(name);
++ if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
++ strcat(name,".");
++ strxmov(strend(name),config_file,ext,NullS);
++ }
++ else
++ {
++ strmov(name,config_file);
++ }
++ fn_format(name,name,"","",4);
++#if !defined(_WIN32) && !defined(OS2)
++ {
++ MY_STAT stat_info;
++ if (!my_stat(name,&stat_info,MYF(0)))
++ return 0;
++ if (stat_info.st_mode & S_IWOTH) /* ignore world-writeable files */
++ {
++ fprintf(stderr, "warning: World-writeable config file %s is ignored\n",
++ name);
++ return 0;
++ }
++ }
++#endif
++ if (!(fp = my_fopen(fn_format(name,name,"","",4),O_RDONLY,MYF(0))))
++ return 0; /* Ignore wrong files */
++
++ while (fgets(buff,sizeof(buff)-1,fp))
++ {
++ line++;
++ /* Ignore comment and empty lines */
++ for (ptr=buff ; isspace(*ptr) ; ptr++ ) ;
++ if (*ptr == '#' || *ptr == ';' || !*ptr)
++ continue;
++ if (*ptr == '[') /* Group name */
++ {
++ found_group=1;
++ if (!(end=(char *) strchr(++ptr,']')))
++ {
++ fprintf(stderr,
++ "error: Wrong group definition in config file: %s at line %d\n",
++ name,line);
++ goto err;
++ }
++ for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
++ end[0]=0;
++ read_values=find_type(ptr,group,3) > 0;
++ continue;
++ }
++ if (!found_group)
++ {
++ fprintf(stderr,
++ "error: Found option without preceding group in config file: %s at line: %d\n",
++ name,line);
++ goto err;
++ }
++ if (!read_values)
++ continue;
++ if (!(end=value=strchr(ptr,'=')))
++ end=strend(ptr); /* Option without argument */
++ for ( ; isspace(end[-1]) ; end--) ;
++ if (!value)
++ {
++ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
++ goto err;
++ strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
++ if (insert_dynamic(args,(gptr) &tmp))
++ goto err;
++ }
++ else
++ {
++ /* Remove pre- and end space */
++ char *value_end;
++ for (value++ ; isspace(*value); value++) ;
++ value_end=strend(value);
++ for ( ; isspace(value_end[-1]) ; value_end--) ;
++ if (value_end < value) /* Empty string */
++ value_end=value;
++ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
++ (uint) (value_end-value)+1)))
++ goto err;
++ if (insert_dynamic(args,(gptr) &tmp))
++ goto err;
++ ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
++ *ptr++= '=';
++ for ( ; value != value_end; value++)
++ {
++ if (*value == '\\' && value != value_end-1)
++ {
++ switch(*++value) {
++ case 'n':
++ *ptr++='\n';
++ break;
++ case 't':
++ *ptr++= '\t';
++ break;
++ case 'r':
++ *ptr++ = '\r';
++ break;
++ case 'b':
++ *ptr++ = '\b';
++ break;
++ case 's':
++ *ptr++= ' '; /* space */
++ break;
++ case '\\':
++ *ptr++= '\\';
++ break;
++ default: /* Unknown; Keep '\' */
++ *ptr++= '\\';
++ *ptr++= *value;
++ break;
++ }
++ }
++ else
++ *ptr++= *value;
++ }
++ *ptr=0;
++ }
++ }
++ my_fclose(fp,MYF(0));
++ return(0);
++
++ err:
++ my_fclose(fp,MYF(0));
++ return 1;
++}
++
++
++void print_defaults(const char *conf_file, const char **groups)
++{
++#ifdef _WIN32
++ bool have_ext=fn_ext(conf_file)[0] != 0;
++#endif
++ char name[FN_REFLEN];
++ const char **dirs;
++ puts("\nDefault options are read from the following files in the given order:");
++
++ if (dirname_length(conf_file))
++ fputs(conf_file,stdout);
++ else
++ {
++#ifdef _WIN32
++ GetWindowsDirectory(name,sizeof(name));
++ printf("%s\\%s%s ",name,conf_file,have_ext ? "" : windows_ext);
++#endif
++#if defined(__EMX__) || defined(OS2)
++ if (getenv("ETC"))
++ printf("%s\\%s%s ", getenv("ETC"), conf_file, default_ext);
++#endif
++ for (dirs=default_directories ; *dirs; dirs++)
++ {
++ if (**dirs)
++ strmov(name,*dirs);
++ else if (defaults_extra_file)
++ strmov(name,defaults_extra_file);
++ else
++ continue;
++ convert_dirname(name);
++ if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
++ strcat(name,".");
++ strxmov(strend(name),conf_file,default_ext," ",NullS);
++ fputs(name,stdout);
++ }
++ puts("");
++ }
++ fputs("The following groups are read:",stdout);
++ for ( ; *groups ; groups++)
++ {
++ fputc(' ',stdout);
++ fputs(*groups,stdout);
++ }
++ puts("\nThe following options may be given as the first argument:\n\
++--print-defaults Print the program argument list and exit\n\
++--no-defaults Don't read default options from any options file\n\
++--defaults-file=# Only read default options from the given file #\n\
++--defaults-extra-file=# Read this file after the global files are read");
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/errmsg.c mariadb-native-client.trunk/libmariadb/errmsg.c
+--- mariadb/libmariadb/errmsg.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/errmsg.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,152 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Error messages for MySQL clients */
++/* error messages for the demon is in share/language/errmsg.sys */
++
++#include <my_global.h>
++#include <my_sys.h>
++#include "errmsg.h"
++#include <stdarg.h>
++
++#ifdef GERMAN
++const char *client_errors[]=
++{
++ "Unbekannter MySQL Fehler",
++ "Kann UNIX-Socket nicht anlegen (%d)",
++ "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
++ "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
++ "Kann TCP/IP-Socket nicht anlegen (%d)",
++ "Unbekannter MySQL Server Host (%-.64s) (%d)",
++ "MySQL Server nicht vorhanden",
++ "Protokolle ungleich. Server Version = % d Client Version = %d",
++ "MySQL client got out of memory",
++ "Wrong host info",
++ "Localhost via UNIX socket",
++ "%-.64s via TCP/IP",
++ "Error in server handshake",
++ "Lost connection to MySQL server during query",
++ "Commands out of sync; you can't run this command now",
++ "Verbindung ueber Named Pipe; Host: %-.64s",
++ "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)",
++ "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
++ "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)",
++ "Can't initialize character set %-.64s (path: %-.64s)",
++ "Got packet bigger than 'max_allowed_packet'"
++};
++
++/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
++
++#elif defined PORTUGUESE
++const char *client_errors[]=
++{
++ "Erro desconhecido do MySQL",
++ "No pode criar 'UNIX socket' (%d)",
++ "No pode se conectar ao servidor MySQL local atravs do 'socket' '%-.64s' (%d)",
++ "No pode se conectar ao servidor MySQL em '%-.64s' (%d)",
++ "No pode criar 'socket TCP/IP' (%d)",
++ "'Host' servidor MySQL '%-.64s' (%d) desconhecido",
++ "Servidor MySQL desapareceu",
++ "Incompatibilidade de protocolos. Verso do Servidor: %d - Verso do Cliente: %d",
++ "Cliente do MySQL com falta de memria",
++ "Informao invlida de 'host'",
++ "Localhost via 'UNIX socket'",
++ "%-.64s via 'TCP/IP'",
++ "Erro na negociao de acesso ao servidor",
++ "Conexo perdida com servidor MySQL durante 'query'",
++ "Comandos fora de sincronismo. Voc no pode executar este comando agora",
++ "%-.64s via 'named pipe'",
++ "No pode esperar pelo 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
++ "No pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
++ "No pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
++ "No pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)",
++ "Obteve pacote maior do que 'max_allowed_packet'"
++};
++
++#else /* ENGLISH */
++const char *client_errors[]=
++{
++/* 2000 */ "Unknown MySQL error",
++/* 2001 */ "Can't create UNIX socket (%d)",
++/* 2002 */ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
++/* 2003 */ "Can't connect to MySQL server on '%-.64s' (%d)",
++/* 2004 */ "Can't create TCP/IP socket (%d)",
++/* 2005 */ "Unknown MySQL Server Host '%-.64s' (%d)",
++/* 2006 */ "MySQL server has gone away",
++/* 2007 */ "Protocol mismatch. Server Version = %d Client Version = %d",
++/* 2008 */ "MySQL client run out of memory",
++/* 2009 */ "Wrong host info",
++/* 2010 */ "Localhost via UNIX socket",
++/* 2011 */ "%-.64s via TCP/IP",
++/* 2012 */ "Error in server handshake",
++/* 2013 */ "Lost connection to MySQL server during query",
++/* 2014 */ "Commands out of sync; you can't run this command now",
++/* 2015 */ "%-.64s via named pipe",
++/* 2016 */ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
++/* 2017 */ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
++/* 2018 */ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
++/* 2019 */ "Can't initialize character set %-.64s (path: %-.64s)",
++/* 2020 */ "Got packet bigger than 'max_allowed_packet'",
++/* 2021 */ "",
++/* 2022 */ "",
++/* 2023 */ "",
++/* 2024 */ "",
++/* 2025 */ "",
+/* 2026 */ "SSL connection error: %100s",
- /* 2027 */ "received malformed packet",
- /* 2028 */ "",
- /* 2029 */ "",
--/* 2030 */ "",
--/* 2031 */ "",
++/* 2027 */ "received malformed packet",
++/* 2028 */ "",
++/* 2029 */ "",
+/* 2030 */ "Statement is not prepared",
+/* 2031 */ "No data supplied for parameters in prepared statement",
- /* 2032 */ "",
- /* 2033 */ "",
- /* 2034 */ "",
- /* 2035 */ "",
--/* 2036 */ "",
++/* 2032 */ "",
++/* 2033 */ "",
++/* 2034 */ "",
++/* 2035 */ "",
+/* 2036 */ "Buffer type is not supported",
- /* 2037 */ "",
- /* 2038 */ "",
- /* 2039 */ "",
-@@ -132,14 +132,15 @@
- /* 2049 */ "",
- /* 2050 */ "",
- /* 2051 */ "",
--/* 2052 */ "",
++/* 2037 */ "",
++/* 2038 */ "",
++/* 2039 */ "",
++/* 2040 */ "",
++/* 2041 */ "",
++/* 2042 */ "",
++/* 2043 */ "",
++/* 2044 */ "",
++/* 2045 */ "",
++/* 2046 */ "",
++/* 2047 */ "",
++/* 2048 */ "",
++/* 2049 */ "",
++/* 2050 */ "",
++/* 2051 */ "",
+/* 2052 */ "Prepared statement contains no metadata",
- /* 2053 */ "",
--/* 2054 */ "",
++/* 2053 */ "",
+/* 2054 */ "This feature is not implemented or disabled",
- /* 2055 */ "",
- /* 2056 */ "",
- /* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
--/* 2058 */ "Can't connect twice. Already connected",
--/* 2059 */ "Plugin %s could not be loaded: %s",
++/* 2055 */ "Lost connection to MySQL server at '%s', system error: %d",
++/* 2056 */ "",
++/* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
+/* 2058 */ "Plugin %s could not be loaded: %s",
+/* 2059 */ "Can't connect twice. Already connected",
+/* 2060 */ "Plugin doesn't support this function",
- ""
- };
- #endif
-
-=== renamed file 'libmysql/libmysql.c' => 'libmariadb/libmariadb.c'
---- mariadb/libmysql/libmysql.c 2012-11-27 08:57:10 +0000
-+++ mariadb/libmariadb/libmariadb.c 2013-03-14 21:01:43 +0000
-@@ -1,5 +1,5 @@
- /************************************************************************************
-- Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
++ ""
++};
++#endif
++
++
++void init_client_errs(void)
++{
++ my_errmsg[CLIENT_ERRMAP] = &client_errors[0];
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/errors.c mariadb-native-client.trunk/libmariadb/errors.c
+--- mariadb/libmariadb/errors.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/errors.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,96 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++
++#ifndef SHARED_LIBRARY
++
++const char * NEAR globerrs[GLOBERRS]=
++{
++ "Can't create/write to file '%s' (Errcode: %d)",
++ "Error reading file '%s' (Errcode: %d)",
++ "Error writing file '%s' (Errcode: %d)",
++ "Error on close of '%s' (Errcode: %d)",
++ "Out of memory (Needed %u bytes)",
++ "Error on delete of '%s' (Errcode: %d)",
++ "Error on rename of '%s' to '%s' (Errcode: %d)",
++ "",
++ "Unexpected eof found when reading file '%s' (Errcode: %d)",
++ "Can't lock file (Errcode: %d)",
++ "Can't unlock file (Errcode: %d)",
++ "Can't read dir of '%s' (Errcode: %d)",
++ "Can't get stat of '%s' (Errcode: %d)",
++ "Can't change size of file (Errcode: %d)",
++ "Can't open stream from handle (Errcode: %d)",
++ "Can't get working dirctory (Errcode: %d)",
++ "Can't change dir to '%s' (Errcode: %d)",
++ "Warning: '%s' had %d links",
++ "Warning: %d files and %d streams is left open\n",
++ "Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... (Expect up to %d secs delay for server to continue after freeing disk space)",
++ "Can't create directory '%s' (Errcode: %d)",
++ "Character set '%s' is not a compiled character set and is not specified in the '%s' file",
++ "Out of resources when opening file '%s' (Errcode: %d)",
++ "Can't read value for symlink '%s' (Error %d)",
++ "Can't create symlink '%s' pointing at '%s' (Error %d)",
++ "Error on realpath() on '%s' (Error %d)",
++ "Can't sync file '%s' to disk (Errcode: %d)",
++ "Collation '%s' is not a compiled collation and is not specified in the '%s' file",
++ "File '%s' not found (Errcode: %d)",
++ "File '%s' (fileno: %d) was not closed",
++ "Can't change mode for file '%s' to 0x%lx (Error: %d)"
++};
++
++void init_glob_errs(void)
++{
++ my_errmsg[GLOB] = & globerrs[0];
++} /* init_glob_errs */
++
++#else
++
++void init_glob_errs()
++{
++ my_errmsg[GLOB] = & globerrs[0];
++
++ EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
++ EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
++ EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
++ EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
++ EE(EE_BADCLOSE) = "Error on close of '%'s (Errcode: %d)";
++ EE(EE_OUTOFMEMORY) = "Out of memory (Needed %u bytes)";
++ EE(EE_DELETE) = "Error on delete of '%s' (Errcode: %d)";
++ EE(EE_LINK) = "Error on rename of '%s' to '%s' (Errcode: %d)";
++ EE(EE_EOFERR) = "Unexpected eof found when reading file '%s' (Errcode: %d)";
++ EE(EE_CANTLOCK) = "Can't lock file (Errcode: %d)";
++ EE(EE_CANTUNLOCK) = "Can't unlock file (Errcode: %d)";
++ EE(EE_DIR) = "Can't read dir of '%s' (Errcode: %d)";
++ EE(EE_STAT) = "Can't get stat of '%s' (Errcode: %d)";
++ EE(EE_CANT_CHSIZE) = "Can't change size of file (Errcode: %d)";
++ EE(EE_CANT_OPEN_STREAM)= "Can't open stream from handle (Errcode: %d)";
++ EE(EE_GETWD) = "Can't get working dirctory (Errcode: %d)";
++ EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
++ EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
++ EE(EE_OPEN_WARNING) = "%d files and %d streams is left open\n";
++ EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
++ EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
++ EE(EE_UNKNOWN_CHARSET)= "Character set is not a compiled character set and is not specified in the %s file";
++ EE(EE_OUT_OF_FILERESOURCES)="Out of resources when opening file '%s' (Errcode: %d)";
++ EE(EE_CANT_READLINK)="Can't read value for symlink '%s' (Error %d)";
++ EE(EE_CANT_SYMLINK)="Can't create symlink '%s' pointing at '%s' (Error %d)";
++ EE(EE_REALPATH)="Error on realpath() on '%s' (Error %d)";
++}
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/getopt1.c mariadb-native-client.trunk/libmariadb/getopt1.c
+--- mariadb/libmariadb/getopt1.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/getopt1.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,170 @@
++/* getopt_long and getopt_long_only entry points for GNU getopt.
++ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
++ Free Software Foundation, Inc.
++
++This file is part of the GNU C Library. Its master source is NOT part of
++the C library, however. The master source lives in /gd/gnu/lib.
++
++The GNU C Library is free software; you can redistribute it and/or
++modify it under the terms of the GNU Library General Public License as
++published by the Free Software Foundation; either version 2 of the
++License, or (at your option) any later version.
++
++The GNU C Library is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++Library General Public License for more details.
++
++You should have received a copy of the GNU Library General Public
++License along with the GNU C Library; see the file COPYING.LIB. If
++not, write to the Free Software Foundation, Inc., 675 Mass Ave,
++Cambridge, MA 02139, USA. */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <my_global.h>
++#include "getopt.h"
++
++#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
++/* This is a separate conditional since some stdc systems
++ reject `defined (const)'. */
++#ifndef const
++#define const
++#endif
++#endif
++
++#include <stdio.h>
++
++/* Comment out all this code if we are using the GNU C Library, and are not
++ actually compiling the library itself. This code is part of the GNU C
++ Library, but also included in many other GNU distributions. Compiling
++ and linking in this code is a waste when using the GNU C library
++ (especially if it is a shared library). Rather than having every GNU
++ program understand `configure --with-gnu-libc' and omit the object files,
++ it is simpler to just do this in the source for each such file. */
++
++#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
++
++#ifndef _WIN32
++#include <stdlib.h>
++#endif /* _WIN32 */
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++int
++getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
++{
++ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
++}
++
++/* Like getopt_long, but '-' as well as '--' can indicate a long option.
++ If an option that starts with '-' (not '--') doesn't match a long option,
++ but does match a short option, it is parsed as a short option
++ instead. */
++
++int
++getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
++{
++ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
++}
++
++
++#endif /* _LIBC or not __GNU_LIBRARY__. */
++
++#ifdef TEST
++
++#include <stdio.h>
++
++int
++main (argc, argv)
++ int argc;
++ char **argv;
++{
++ int c;
++ int digit_optind = 0;
++
++ while (1)
++ {
++ int this_option_optind = optind ? optind : 1;
++ int option_index = 0;
++ static struct option long_options[] =
++ {
++ {"add", 1, 0, 0},
++ {"append", 0, 0, 0},
++ {"delete", 1, 0, 0},
++ {"verbose", 0, 0, 0},
++ {"create", 0, 0, 0},
++ {"file", 1, 0, 0},
++ {0, 0, 0, 0}
++ };
++
++ c = getopt_long (argc, argv, "abc:d:0123456789",
++ long_options, &option_index);
++ if (c == EOF)
++ break;
++
++ switch (c)
++ {
++ case 0:
++ printf ("option %s", long_options[option_index].name);
++ if (optarg)
++ printf (" with arg %s", optarg);
++ printf ("\n");
++ break;
++
++ case '0':
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '8':
++ case '9':
++ if (digit_optind != 0 && digit_optind != this_option_optind)
++ printf ("digits occur in two different argv-elements.\n");
++ digit_optind = this_option_optind;
++ printf ("option %c\n", c);
++ break;
++
++ case 'a':
++ printf ("option a\n");
++ break;
++
++ case 'b':
++ printf ("option b\n");
++ break;
++
++ case 'c':
++ printf ("option c with value `%s'\n", optarg);
++ break;
++
++ case 'd':
++ printf ("option d with value `%s'\n", optarg);
++ break;
++
++ case '?':
++ break;
++
++ default:
++ printf ("?? getopt returned character code 0%o ??\n", c);
++ }
++ }
++
++ if (optind < argc)
++ {
++ printf ("non-option ARGV-elements: ");
++ while (optind < argc)
++ printf ("%s ", argv[optind++]);
++ printf ("\n");
++ }
++
++ exit (0);
++}
++
++#endif /* TEST */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/getopt.c mariadb-native-client.trunk/libmariadb/getopt.c
+--- mariadb/libmariadb/getopt.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/getopt.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,746 @@
++/* Getopt for GNU.
++ NOTE: getopt is now part of the C library, so if you don't know what
++ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
++ before changing it!
++
++ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
++ Free Software Foundation, Inc.
++
++Changes by monty:
++- Added include of string.h when nessessary.
++- Removed two warnings from gcc.
++
++This file is part of the GNU C Library. Its master source is NOT part of
++the C library, however. The master source lives in /gd/gnu/lib.
++
++The GNU C Library is free software; you can redistribute it and/or
++modify it under the terms of the GNU Library General Public License as
++published by the Free Software Foundation; either version 2 of the
++License, or (at your option) any later version.
++
++The GNU C Library is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++Library General Public License for more details.
++
++You should have received a copy of the GNU Library General Public
++License along with the GNU C Library; see the file COPYING.LIB. If
++not, write to the Free Software Foundation, Inc., 675 Mass Ave,
++Cambridge, MA 02139, USA. */
++
++/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
++ Ditto for AIX 3.2 and <stdlib.h>. */
++#ifndef _NO_PROTO
++#define _NO_PROTO
++#endif
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
++/* This is a separate conditional since some stdc systems
++ reject `defined (const)'. */
++#ifndef const
++#define const
++#endif
++#endif
++
++#include <my_global.h> /* Changes for mysys */
++#include <m_string.h>
++
++/* Comment out all this code if we are using the GNU C Library, and are not
++ actually compiling the library itself. This code is part of the GNU C
++ Library, but also included in many other GNU distributions. Compiling
++ and linking in this code is a waste when using the GNU C library
++ (especially if it is a shared library). Rather than having every GNU
++ program understand `configure --with-gnu-libc' and omit the object files,
++ it is simpler to just do this in the source for each such file. */
++
++#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
++
++
++/* This needs to come after some library #include
++ to get __GNU_LIBRARY__ defined. */
++#ifdef __GNU_LIBRARY__
++/* Don't include stdlib.h for non-GNU C libraries because some of them
++ contain conflicting prototypes for getopt. */
++#include <stdlib.h>
++#endif /* GNU C library. */
++
++/* This version of `getopt' appears to the caller like standard Unix `getopt'
++ but it behaves differently for the user, since it allows the user
++ to intersperse the options with the other arguments.
++
++ As `getopt' works, it permutes the elements of ARGV so that,
++ when it is done, all the options precede everything else. Thus
++ all application programs are extended to handle flexible argument order.
++
++ Setting the environment variable POSIXLY_CORRECT disables permutation.
++ Then the behavior is completely standard.
++
++ GNU application programs can use a third alternative mode in which
++ they can distinguish the relative order of options and other arguments. */
++
++#include "getopt.h"
++
++/* For communication from `getopt' to the caller.
++ When `getopt' finds an option that takes an argument,
++ the argument value is returned here.
++ Also, when `ordering' is RETURN_IN_ORDER,
++ each non-option ARGV-element is returned here. */
++
++char *optarg = NULL;
++
++/* Index in ARGV of the next element to be scanned.
++ This is used for communication to and from the caller
++ and for communication between successive calls to `getopt'.
++
++ On entry to `getopt', zero means this is the first call; initialize.
++
++ When `getopt' returns EOF, this is the index of the first of the
++ non-option elements that the caller should itself scan.
++
++ Otherwise, `optind' communicates from one call to the next
++ how much of ARGV has been scanned so far. */
++
++/* XXX 1003.2 says this must be 1 before any call. */
++int optind = 1;
++
++/* The next char to be scanned in the option-element
++ in which the last option character we returned was found.
++ This allows us to pick up the scan where we left off.
++
++ If this is zero, or a null string, it means resume the scan
++ by advancing to the next ARGV-element. */
++
++static char *nextchar;
++
++/* Callers store zero here to inhibit the error message
++ for unrecognized options. */
++
++int opterr = 1;
++
++/* Set to an option character which was unrecognized.
++ This must be initialized on some systems to avoid linking in the
++ system's own getopt implementation. */
++
++int optopt = '?';
++
++/* Describe how to deal with options that follow non-option ARGV-elements.
++
++ If the caller did not specify anything,
++ the default is REQUIRE_ORDER if the environment variable
++ POSIXLY_CORRECT is defined, PERMUTE otherwise.
++
++ REQUIRE_ORDER means don't recognize them as options;
++ stop option processing when the first non-option is seen.
++ This is what Unix does.
++ This mode of operation is selected by either setting the environment
++ variable POSIXLY_CORRECT, or using `+' as the first character
++ of the list of option characters.
++
++ PERMUTE is the default. We permute the contents of ARGV as we scan,
++ so that eventually all the non-options are at the end. This allows options
++ to be given in any order, even with programs that were not written to
++ expect this.
++
++ RETURN_IN_ORDER is an option available to programs that were written
++ to expect options and other ARGV-elements in any order and that care about
++ the ordering of the two. We describe each non-option ARGV-element
++ as if it were the argument of an option with character code 1.
++ Using `-' as the first character of the list of option characters
++ selects this mode of operation.
++
++ The special argument `--' forces an end of option-scanning regardless
++ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
++ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
++
++static enum
++{
++ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
++} ordering;
++
++/* Value of POSIXLY_CORRECT environment variable. */
++static char *posixly_correct;
++
++#ifdef __GNU_LIBRARY__
++/* We want to avoid inclusion of string.h with non-GNU libraries
++ because there are many ways it can cause trouble.
++ On some systems, it contains special magic macros that don't work
++ in GCC. */
++#include <string.h>
++#define my_index strchr
++#else
++
++/* Avoid depending on library functions or files
++ whose names are inconsistent. */
++
++static char *
++my_index (const char *str, int chr)
++{
++ while (*str)
++ {
++ if (*str == chr)
++ return (char *) str;
++ str++;
++ }
++ return 0;
++}
++
++/* If using GCC, we can safely declare strlen this way.
++ If not using GCC, it is ok not to declare it. */
++#ifdef __GNUC__
++/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
++ That was relevant to code that was here before. */
++#if !defined (__STDC__) || !__STDC__
++/* gcc with -traditional declares the built-in strlen to return int,
++ and has done so at least since version 2.4.5. -- rms. */
++extern int strlen (const char *);
++#endif /* not __STDC__ */
++#endif /* __GNUC__ */
++
++#endif /* not __GNU_LIBRARY__ */
++
++/* Handle permutation of arguments. */
++
++/* Describe the part of ARGV that contains non-options that have
++ been skipped. `first_nonopt' is the index in ARGV of the first of them;
++ `last_nonopt' is the index after the last of them. */
++
++static int first_nonopt;
++static int last_nonopt;
++
++/* Exchange two adjacent subsequences of ARGV.
++ One subsequence is elements [first_nonopt,last_nonopt)
++ which contains all the non-options that have been skipped so far.
++ The other is elements [last_nonopt,optind), which contains all
++ the options processed since those non-options were skipped.
++
++ `first_nonopt' and `last_nonopt' are relocated so that they describe
++ the new indices of the non-options in ARGV after they are moved. */
++
++static void
++exchange (char **argv)
++{
++ int bottom = first_nonopt;
++ int middle = last_nonopt;
++ int top = optind;
++ char *tem;
++
++ /* Exchange the shorter segment with the far end of the longer segment.
++ That puts the shorter segment into the right place.
++ It leaves the longer segment in the right place overall,
++ but it consists of two parts that need to be swapped next. */
++
++ while (top > middle && middle > bottom)
++ {
++ if (top - middle > middle - bottom)
++ {
++ /* Bottom segment is the short one. */
++ int len = middle - bottom;
++ register int i;
++
++ /* Swap it with the top part of the top segment. */
++ for (i = 0; i < len; i++)
++ {
++ tem = argv[bottom + i];
++ argv[bottom + i] = argv[top - (middle - bottom) + i];
++ argv[top - (middle - bottom) + i] = tem;
++ }
++ /* Exclude the moved bottom segment from further swapping. */
++ top -= len;
++ }
++ else
++ {
++ /* Top segment is the short one. */
++ int len = top - middle;
++ register int i;
++
++ /* Swap it with the bottom part of the bottom segment. */
++ for (i = 0; i < len; i++)
++ {
++ tem = argv[bottom + i];
++ argv[bottom + i] = argv[middle + i];
++ argv[middle + i] = tem;
++ }
++ /* Exclude the moved top segment from further swapping. */
++ bottom += len;
++ }
++ }
++
++ /* Update records for the slots the non-options now occupy. */
++
++ first_nonopt += (optind - last_nonopt);
++ last_nonopt = optind;
++}
++
++/* Initialize the internal data when the first call is made. */
++
++static const char *
++_getopt_initialize (const char *optstring)
++{
++ /* Start processing options with ARGV-element 1 (since ARGV-element 0
++ is the program name); the sequence of previously skipped
++ non-option ARGV-elements is empty. */
++
++ first_nonopt = last_nonopt = optind = 1;
++
++ nextchar = NULL;
++
++ posixly_correct = getenv ("POSIXLY_CORRECT");
++
++ /* Determine how to handle the ordering of options and nonoptions. */
++
++ if (optstring[0] == '-')
++ {
++ ordering = RETURN_IN_ORDER;
++ ++optstring;
++ }
++ else if (optstring[0] == '+')
++ {
++ ordering = REQUIRE_ORDER;
++ ++optstring;
++ }
++ else if (posixly_correct != NULL)
++ ordering = REQUIRE_ORDER;
++ else
++ ordering = PERMUTE;
++
++ return optstring;
++}
++
++/* Scan elements of ARGV (whose length is ARGC) for option characters
++ given in OPTSTRING.
++
++ If an element of ARGV starts with '-', and is not exactly "-" or "--",
++ then it is an option element. The characters of this element
++ (aside from the initial '-') are option characters. If `getopt'
++ is called repeatedly, it returns successively each of the option characters
++ from each of the option elements.
++
++ If `getopt' finds another option character, it returns that character,
++ updating `optind' and `nextchar' so that the next call to `getopt' can
++ resume the scan with the following option character or ARGV-element.
++
++ If there are no more option characters, `getopt' returns `EOF'.
++ Then `optind' is the index in ARGV of the first ARGV-element
++ that is not an option. (The ARGV-elements have been permuted
++ so that those that are not options now come last.)
++
++ OPTSTRING is a string containing the legitimate option characters.
++ If an option character is seen that is not listed in OPTSTRING,
++ return '?' after printing an error message. If you set `opterr' to
++ zero, the error message is suppressed but we still return '?'.
++
++ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
++ so the following text in the same ARGV-element, or the text of the following
++ ARGV-element, is returned in `optarg'. Two colons mean an option that
++ wants an optional arg; if there is text in the current ARGV-element,
++ it is returned in `optarg', otherwise `optarg' is set to zero.
++
++ If OPTSTRING starts with `-' or `+', it requests different methods of
++ handling the non-option ARGV-elements.
++ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
++
++ Long-named options begin with `--' instead of `-'.
++ Their names may be abbreviated as long as the abbreviation is unique
++ or is an exact match for some defined option. If they have an
++ argument, it follows the option name in the same ARGV-element, separated
++ from the option name by a `=', or else the in next ARGV-element.
++ When `getopt' finds a long-named option, it returns 0 if that option's
++ `flag' field is nonzero, the value of the option's `val' field
++ if the `flag' field is zero.
++
++ The elements of ARGV aren't really const, because we permute them.
++ But we pretend they're const in the prototype to be compatible
++ with other systems.
++
++ LONGOPTS is a vector of `struct option' terminated by an
++ element containing a name which is zero.
++
++ LONGIND returns the index in LONGOPT of the long-named option found.
++ It is only valid when a long-named option has been found by the most
++ recent call.
++
++ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
++ long-named options. */
++
++int
++_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
++{
++ optarg = NULL;
++
++ if (optind == 0)
++ optstring = _getopt_initialize (optstring);
++
++ if (nextchar == NULL || *nextchar == '\0')
++ {
++ /* Advance to the next ARGV-element. */
++
++ if (ordering == PERMUTE)
++ {
++ /* If we have just processed some options following some non-options,
++ exchange them so that the options come first. */
++
++ if (first_nonopt != last_nonopt && last_nonopt != optind)
++ exchange ((char **) argv);
++ else if (last_nonopt != optind)
++ first_nonopt = optind;
++
++ /* Skip any additional non-options
++ and extend the range of non-options previously skipped. */
++
++ while (optind < argc
++ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
++ optind++;
++ last_nonopt = optind;
++ }
++
++ /* The special ARGV-element `--' means premature end of options.
++ Skip it like a null option,
++ then exchange with previous non-options as if it were an option,
++ then skip everything else like a non-option. */
++
++ if (optind != argc && !strcmp (argv[optind], "--"))
++ {
++ optind++;
++
++ if (first_nonopt != last_nonopt && last_nonopt != optind)
++ exchange ((char **) argv);
++ else if (first_nonopt == last_nonopt)
++ first_nonopt = optind;
++ last_nonopt = argc;
++
++ optind = argc;
++ }
++
++ /* If we have done all the ARGV-elements, stop the scan
++ and back over any non-options that we skipped and permuted. */
++
++ if (optind == argc)
++ {
++ /* Set the next-arg-index to point at the non-options
++ that we previously skipped, so the caller will digest them. */
++ if (first_nonopt != last_nonopt)
++ optind = first_nonopt;
++ return EOF;
++ }
++
++ /* If we have come to a non-option and did not permute it,
++ either stop the scan or describe it to the caller and pass it by. */
++
++ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
++ {
++ if (ordering == REQUIRE_ORDER)
++ return EOF;
++ optarg = argv[optind++];
++ return 1;
++ }
++
++ /* We have found another option-ARGV-element.
++ Skip the initial punctuation. */
++
++ nextchar = (argv[optind] + 1
++ + (longopts != NULL && argv[optind][1] == '-'));
++ }
++
++ /* Decode the current option-ARGV-element. */
++
++ /* Check whether the ARGV-element is a long option.
++
++ If long_only and the ARGV-element has the form "-f", where f is
++ a valid short option, don't consider it an abbreviated form of
++ a long option that starts with f. Otherwise there would be no
++ way to give the -f short option.
++
++ On the other hand, if there's a long option "fubar" and
++ the ARGV-element is "-fu", do consider that an abbreviation of
++ the long option, just like "--fu", and not "-f" with arg "u".
++
++ This distinction seems to be the most useful approach. */
++
++ if (longopts != NULL
++ && (argv[optind][1] == '-'
++ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
++ {
++ char *nameend;
++ const struct option *p;
++ const struct option *pfound = NULL;
++ int exact = 0;
++ int ambig = 0;
++ int indfound=0; /* Keep gcc happy */
++ int option_index;
++
++ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
++ /* Do nothing. */ ;
++
++ /* Test all long options for either exact match
++ or abbreviated matches. */
++ for (p = longopts, option_index = 0; p->name; p++, option_index++)
++ if (!strncmp (p->name, nextchar, nameend - nextchar))
++ {
++ if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
++ {
++ /* Exact match found. */
++ pfound = p;
++ indfound = option_index;
++ exact = 1;
++ break;
++ }
++ else if (pfound == NULL)
++ {
++ /* First nonexact match found. */
++ pfound = p;
++ indfound = option_index;
++ }
++ else
++ /* Second or later nonexact match found. */
++ ambig = 1;
++ }
++
++ if (ambig && !exact)
++ {
++ if (opterr)
++ fprintf (stderr, "%s: option `%s' is ambiguous\n",
++ argv[0], argv[optind]);
++ nextchar += strlen (nextchar);
++ optind++;
++ return '?';
++ }
++
++ if (pfound != NULL)
++ {
++ option_index = indfound;
++ optind++;
++ if (*nameend)
++ {
++ /* Don't test has_arg with >, because some C compilers don't
++ allow it to be used on enums. */
++ if (pfound->has_arg)
++ optarg = nameend + 1;
++ else
++ {
++ if (opterr)
++ {
++ if (argv[optind - 1][1] == '-')
++ /* --option */
++ fprintf (stderr,
++ "%s: option `--%s' doesn't allow an argument\n",
++ argv[0], pfound->name);
++ else
++ /* +option or -option */
++ fprintf (stderr,
++ "%s: option `%c%s' doesn't allow an argument\n",
++ argv[0], argv[optind - 1][0], pfound->name);
++ }
++ nextchar += strlen (nextchar);
++ return '?';
++ }
++ }
++ else if (pfound->has_arg == 1)
++ {
++ if (optind < argc)
++ optarg = argv[optind++];
++ else
++ {
++ if (opterr)
++ fprintf (stderr, "%s: option `%s' requires an argument\n",
++ argv[0], argv[optind - 1]);
++ nextchar += strlen (nextchar);
++ return optstring[0] == ':' ? ':' : '?';
++ }
++ }
++ nextchar += strlen (nextchar);
++ if (longind != NULL)
++ *longind = option_index;
++ if (pfound->flag)
++ {
++ *(pfound->flag) = pfound->val;
++ return 0;
++ }
++ return pfound->val;
++ }
++
++ /* Can't find it as a long option. If this is not getopt_long_only,
++ or the option starts with '--' or is not a valid short
++ option, then it's an error.
++ Otherwise interpret it as a short option. */
++ if (!long_only || argv[optind][1] == '-'
++ || my_index (optstring, *nextchar) == NULL)
++ {
++ if (opterr)
++ {
++ if (argv[optind][1] == '-')
++ /* --option */
++ fprintf (stderr, "%s: unrecognized option `--%s'\n",
++ argv[0], nextchar);
++ else
++ /* +option or -option */
++ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
++ argv[0], argv[optind][0], nextchar);
++ }
++ nextchar = (char *) "";
++ optind++;
++ return '?';
++ }
++ }
++
++ /* Look at and handle the next short option-character. */
++
++ {
++ char c = *nextchar++;
++ char *temp = my_index (optstring, c);
++
++ /* Increment `optind' when we start to process its last character. */
++ if (*nextchar == '\0')
++ ++optind;
++
++ if (temp == NULL || c == ':')
++ {
++ if (opterr)
++ {
++ if (posixly_correct)
++ /* 1003.2 specifies the format of this message. */
++ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
++ else
++ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
++ }
++ optopt = c;
++ return '?';
++ }
++ if (temp[1] == ':')
++ {
++ if (temp[2] == ':')
++ {
++ /* This is an option that accepts an argument optionally. */
++ if (*nextchar != '\0')
++ {
++ optarg = nextchar;
++ optind++;
++ }
++ else
++ optarg = NULL;
++ nextchar = NULL;
++ }
++ else
++ {
++ /* This is an option that requires an argument. */
++ if (*nextchar != '\0')
++ {
++ optarg = nextchar;
++ /* If we end this ARGV-element by taking the rest as an arg,
++ we must advance to the next element now. */
++ optind++;
++ }
++ else if (optind == argc)
++ {
++ if (opterr)
++ {
++ /* 1003.2 specifies the format of this message. */
++ fprintf (stderr, "%s: option requires an argument -- %c\n",
++ argv[0], c);
++ }
++ optopt = c;
++ if (optstring[0] == ':')
++ c = ':';
++ else
++ c = '?';
++ }
++ else
++ /* We already incremented `optind' once;
++ increment it again when taking next ARGV-elt as argument. */
++ optarg = argv[optind++];
++ nextchar = NULL;
++ }
++ }
++ return c;
++ }
++}
++
++#ifdef __EMX__
++int getopt (int argc, char **argv, __const__ char *optstring)
++#else
++int
++getopt (int argc, char *const *argv, const char *optstring)
++#endif
++{
++ return _getopt_internal (argc, argv, optstring,
++ (const struct option *) 0,
++ (int *) 0,
++ 0);
++}
++
++#endif /* _LIBC or not __GNU_LIBRARY__. */
++
++#ifdef TEST
++
++/* Compile with -DTEST to make an executable for use in testing
++ the above definition of `getopt'. */
++
++int
++main (argc, argv)
++ int argc;
++ char **argv;
++{
++ int c;
++ int digit_optind = 0;
++
++ while (1)
++ {
++ int this_option_optind = optind ? optind : 1;
++
++ c = getopt (argc, argv, "abc:d:0123456789");
++ if (c == EOF)
++ break;
++
++ switch (c)
++ {
++ case '0':
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '8':
++ case '9':
++ if (digit_optind != 0 && digit_optind != this_option_optind)
++ printf ("digits occur in two different argv-elements.\n");
++ digit_optind = this_option_optind;
++ printf ("option %c\n", c);
++ break;
++
++ case 'a':
++ printf ("option a\n");
++ break;
++
++ case 'b':
++ printf ("option b\n");
++ break;
++
++ case 'c':
++ printf ("option c with value `%s'\n", optarg);
++ break;
++
++ case '?':
++ break;
++
++ default:
++ printf ("?? getopt returned character code 0%o ??\n", c);
++ }
++ }
++
++ if (optind < argc)
++ {
++ printf ("non-option ARGV-elements: ");
++ while (optind < argc)
++ printf ("%s ", argv[optind++]);
++ printf ("\n");
++ }
++
++ exit (0);
++}
++
++#endif /* TEST */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/get_password.c mariadb-native-client.trunk/libmariadb/get_password.c
+--- mariadb/libmariadb/get_password.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/get_password.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,211 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++** Ask for a password from tty
++** This is an own file to avoid conflicts with curses
++*/
++#include <my_global.h>
++#include <my_sys.h>
++#include "mysql.h"
++#include <m_string.h>
++#include <m_ctype.h>
++#include <dbug.h>
++
++#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
++#undef HAVE_GETPASS
++#endif
++
++#ifdef HAVE_GETPASS
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif /* HAVE_PWD_H */
++#else /* ! HAVE_GETPASS */
++#if !defined( _WIN32) && !defined(OS2)
++#include <sys/ioctl.h>
++#ifdef HAVE_TERMIOS_H /* For tty-password */
++#include <termios.h>
++#define TERMIO struct termios
++#else
++#ifdef HAVE_TERMIO_H /* For tty-password */
++#include <termio.h>
++#define TERMIO struct termio
++#else
++#include <sgtty.h>
++#define TERMIO struct sgttyb
++#endif
++#endif
++#ifdef alpha_linux_port
++#include <asm/ioctls.h> /* QQ; Fix this in configure */
++#include <asm/termiobits.h>
++#endif
++#else
++#include <conio.h>
++#endif /* _WIN32 */
++#endif /* HAVE_GETPASS */
++
++#ifdef HAVE_GETPASSPHRASE /* For Solaris */
++ #define getpass(A) getpassphrase(A)
++#endif
++
++#if defined( _WIN32) || defined(OS2)
++/* were just going to fake it here and get input from the keyboard */
++
++char *get_tty_password(char *opt_message)
++{
++ char to[80];
++ char *pos=to,*end=to+sizeof(to)-1;
++ int i=0;
++ DBUG_ENTER("get_tty_password");
++ fprintf(stdout,opt_message ? opt_message : "Enter password: ");
++ for (;;)
++ {
++ char tmp;
++ tmp=_getch();
++ if (tmp == '\b' || (int) tmp == 127)
++ {
++ if (pos != to)
++ {
++ _cputs("\b \b");
++ pos--;
++ continue;
++ }
++ }
++ if (tmp == '\n' || tmp == '\r' || tmp == 3)
++ break;
++ if (iscntrl(tmp) || pos == end)
++ continue;
++ _cputs("*");
++ *(pos++) = tmp;
++ }
++ while (pos != to && isspace(pos[-1]) == ' ')
++ pos--; /* Allow dummy space at end */
++ *pos=0;
++ _cputs("\n");
++ DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
++}
++
++#else
++
++
++#ifndef HAVE_GETPASS
++/*
++** Can't use fgets, because readline will get confused
++** length is max number of chars in to, not counting \0
++* to will not include the eol characters.
++*/
++
++static void get_password(char *to,uint length,int fd,bool echo)
++{
++ char *pos=to,*end=to+length;
++
++ for (;;)
++ {
++ char tmp;
++ if (my_read(fd,&tmp,1,MYF(0)) != 1)
++ break;
++ if (tmp == '\b' || (int) tmp == 127)
++ {
++ if (pos != to)
++ {
++ if (echo)
++ {
++ fputs("\b \b",stdout);
++ fflush(stdout);
++ }
++ pos--;
++ continue;
++ }
++ }
++ if (tmp == '\n' || tmp == '\r' || tmp == 3)
++ break;
++ if (iscntrl(tmp) || pos == end)
++ continue;
++ if (echo)
++ {
++ fputc('*',stdout);
++ fflush(stdout);
++ }
++ *(pos++) = tmp;
++ }
++ while (pos != to && isspace(pos[-1]) == ' ')
++ pos--; /* Allow dummy space at end */
++ *pos=0;
++ return;
++}
++#endif /* ! HAVE_GETPASS */
++
++
++char *get_tty_password(char *opt_message)
++{
++#ifdef HAVE_GETPASS
++ char *passbuff;
++#else /* ! HAVE_GETPASS */
++ TERMIO org,tmp;
++#endif /* HAVE_GETPASS */
++ char buff[80];
++
++ DBUG_ENTER("get_tty_password");
++
++#ifdef HAVE_GETPASS
++ passbuff = getpass(opt_message ? opt_message : "Enter password: ");
++
++ /* copy the password to buff and clear original (static) buffer */
++ strnmov(buff, passbuff, sizeof(buff) - 1);
++#ifdef _PASSWORD_LEN
++ memset(passbuff, 0, _PASSWORD_LEN);
++#endif
++#else
++ if (isatty(fileno(stdout)))
++ {
++ fputs(opt_message ? opt_message : "Enter password: ",stdout);
++ fflush(stdout);
++ }
++#if defined(HAVE_TERMIOS_H)
++ tcgetattr(fileno(stdin), &org);
++ tmp = org;
++ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
++ tmp.c_cc[VMIN] = 1;
++ tmp.c_cc[VTIME] = 0;
++ tcsetattr(fileno(stdin), TCSADRAIN, &tmp);
++ get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout)));
++ tcsetattr(fileno(stdin), TCSADRAIN, &org);
++#elif defined(HAVE_TERMIO_H)
++ ioctl(fileno(stdin), (int) TCGETA, &org);
++ tmp=org;
++ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
++ tmp.c_cc[VMIN] = 1;
++ tmp.c_cc[VTIME]= 0;
++ ioctl(fileno(stdin),(int) TCSETA, &tmp);
++ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
++ ioctl(fileno(stdin),(int) TCSETA, &org);
++#else
++ gtty(fileno(stdin), &org);
++ tmp=org;
++ tmp.sg_flags &= ~ECHO;
++ tmp.sg_flags |= RAW;
++ stty(fileno(stdin), &tmp);
++ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
++ stty(fileno(stdin), &org);
++#endif
++ if (isatty(fileno(stdout)))
++ fputc('\n',stdout);
++#endif /* HAVE_GETPASS */
++
++ DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
++}
++#endif /*_WIN32*/
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/hash.c mariadb-native-client.trunk/libmariadb/hash.c
+--- mariadb/libmariadb/hash.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/hash.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,644 @@
++/************************************************************************************
+ Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
- Monty Program AB
-
- This library is free software; you can redistribute it and/or
-@@ -61,7 +61,7 @@
- #include <sha1.h>
- #include <violite.h>
- #ifdef HAVE_OPENSSL
--#include <my_secure.h>
++ Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*************************************************************************************/
++
++/* The hash functions used for saveing keys */
++/* One of key_length or key_length_offset must be given */
++/* Key length of 0 isn't allowed */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#include <m_ctype.h>
++#include "hash.h"
++
++#define NO_RECORD ((uint) -1)
++#define LOWFIND 1
++#define LOWUSED 2
++#define HIGHFIND 4
++#define HIGHUSED 8
++
++static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
++static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
++static uint calc_hashnr(const uchar *key,uint length);
++static uint calc_hashnr_caseup(const uchar *key,uint length);
++static int hashcmp(HASH *hash,HASH_LINK *pos,const uchar *key,uint length);
++
++
++my_bool _hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
++ hash_get_key get_key,
++ void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
++{
++ DBUG_ENTER("hash_init");
++ DBUG_PRINT("enter",("hash: %lx size: %d",hash,size));
++
++ hash->records=0;
++ if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0))
++ {
++ hash->free=0; /* Allow call to hash_free */
++ DBUG_RETURN(TRUE);
++ }
++ hash->key_offset=key_offset;
++ hash->key_length=key_length;
++ hash->blength=1;
++ hash->current_record= NO_RECORD; /* For the future */
++ hash->get_key=get_key;
++ hash->free=free_element;
++ hash->flags=flags;
++ if (flags & HASH_CASE_INSENSITIVE)
++ hash->calc_hashnr=calc_hashnr_caseup;
++ else
++ hash->calc_hashnr=calc_hashnr;
++ DBUG_RETURN(0);
++}
++
++
++void hash_free(HASH *hash)
++{
++ DBUG_ENTER("hash_free");
++ if (hash->free)
++ {
++ uint i,records;
++ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
++ for (i=0,records=hash->records ; i < records ; i++)
++ (*hash->free)(data[i].data);
++ hash->free=0;
++ }
++ delete_dynamic(&hash->array);
++ hash->records=0;
++ DBUG_VOID_RETURN;
++}
++
++ /* some helper functions */
++
++/*
++ This function is char* instead of uchar* as HPUX11 compiler can't
++ handle inline functions that are not defined as native types
++*/
++
++inline char*
++hash_key(HASH *hash,const uchar *record,uint *length,my_bool first)
++{
++ if (hash->get_key)
++ return (*hash->get_key)(record,(uint *)length,first);
++ *length=hash->key_length;
++ return (uchar*) record+hash->key_offset;
++}
++
++ /* Calculate pos according to keys */
++
++static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
++{
++ if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
++ return (hashnr & ((buffmax >> 1) -1));
++}
++
++static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
++ uint maxlength)
++{
++ uint length;
++ uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
++ return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
++}
++
++#ifndef NEW_HASH_FUNCTION
++
++ /* Calc hashvalue for a key */
++
++static uint calc_hashnr(const uchar *key,uint length)
++{
++ register uint nr=1, nr2=4;
++ while (length--)
++ {
++ nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
++ nr2+=3;
++ }
++ return((uint) nr);
++}
++
++ /* Calc hashvalue for a key, case indepenently */
++
++static uint calc_hashnr_caseup(const uchar *key,uint length)
++{
++ register uint nr=1, nr2=4;
++ while (length--)
++ {
++ nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
++ nr2+=3;
++ }
++ return((uint) nr);
++}
++
++#else
++
++/*
++ * Fowler/Noll/Vo hash
++ *
++ * The basis of the hash algorithm was taken from an idea sent by email to the
++ * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
++ * Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
++ * later improved on their algorithm.
++ *
++ * The magic is in the interesting relationship between the special prime
++ * 16777619 (2^24 + 403) and 2^32 and 2^8.
++ *
++ * This hash produces the fewest collisions of any function that we've seen so
++ * far, and works well on both numbers and strings.
++ */
++
++uint calc_hashnr(const uchar *key, uint len)
++{
++ const uchar *end=key+len;
++ uint hash;
++ for (hash = 0; key < end; key++)
++ {
++ hash *= 16777619;
++ hash ^= (uint) *(uchar*) key;
++ }
++ return (hash);
++}
++
++uint calc_hashnr_caseup(const uchar *key, uint len)
++{
++ const uchar *end=key+len;
++ uint hash;
++ for (hash = 0; key < end; key++)
++ {
++ hash *= 16777619;
++ hash ^= (uint) (uchar) toupper(*key);
++ }
++ return (hash);
++}
++
++#endif
++
++
++#ifndef __SUNPRO_C /* SUNPRO can't handle this */
++inline
++#endif
++unsigned int rec_hashnr(HASH *hash,const uchar *record)
++{
++ uint length;
++ uchar *key= (uchar*) hash_key(hash,record,&length,0);
++ return (*hash->calc_hashnr)(key,length);
++}
++
++
++ /* Search after a record based on a key */
++ /* Sets info->current_ptr to found record */
++
++gptr hash_search(HASH *hash,const uchar *key,uint length)
++{
++ HASH_LINK *pos;
++ uint flag,idx;
++ DBUG_ENTER("hash_search");
++
++ flag=1;
++ if (hash->records)
++ {
++ idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
++ hash->key_length),
++ hash->blength,hash->records);
++ do
++ {
++ pos= dynamic_element(&hash->array,idx,HASH_LINK*);
++ if (!hashcmp(hash,pos,key,length))
++ {
++ DBUG_PRINT("exit",("found key at %d",idx));
++ hash->current_record= idx;
++ DBUG_RETURN (pos->data);
++ }
++ if (flag)
++ {
++ flag=0; /* Reset flag */
++ if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
++ break; /* Wrong link */
++ }
++ }
++ while ((idx=pos->next) != NO_RECORD);
++ }
++ hash->current_record= NO_RECORD;
++ DBUG_RETURN(0);
++}
++
++ /* Get next record with identical key */
++ /* Can only be called if previous calls was hash_search */
++
++gptr hash_next(HASH *hash,const uchar *key,uint length)
++{
++ HASH_LINK *pos;
++ uint idx;
++
++ if (hash->current_record != NO_RECORD)
++ {
++ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
++ for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
++ {
++ pos=data+idx;
++ if (!hashcmp(hash,pos,key,length))
++ {
++ hash->current_record= idx;
++ return pos->data;
++ }
++ }
++ hash->current_record=NO_RECORD;
++ }
++ return 0;
++}
++
++
++ /* Change link from pos to new_link */
++
++static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
++{
++ HASH_LINK *old_link;
++ do
++ {
++ old_link=array+next_link;
++ }
++ while ((next_link=old_link->next) != find);
++ old_link->next= newlink;
++ return;
++}
++
++ /* Compare a key in a record to a whole key. Return 0 if identical */
++
++static int hashcmp(HASH *hash,HASH_LINK *pos,const uchar *key,uint length)
++{
++ uint rec_keylength;
++ uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
++ return (length && length != rec_keylength) ||
++ memcmp(rec_key,key,rec_keylength);
++}
++
++
++ /* Write a hash-key to the hash-index */
++
++my_bool hash_insert(HASH *info,const uchar *record)
++{
++ int flag;
++ uint halfbuff,hash_nr,first_index,idx;
++ uchar *ptr_to_rec,*ptr_to_rec2;
++ HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
++
++ LINT_INIT(gpos); LINT_INIT(gpos2);
++ LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
++
++ flag=0;
++ if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
++ return(TRUE); /* No more memory */
++
++ info->current_record= NO_RECORD;
++ data=dynamic_element(&info->array,0,HASH_LINK*);
++ halfbuff= info->blength >> 1;
++
++ idx=first_index=info->records-halfbuff;
++ if (idx != info->records) /* If some records */
++ {
++ do
++ {
++ pos=data+idx;
++ hash_nr=rec_hashnr(info,pos->data);
++ if (flag == 0) /* First loop; Check if ok */
++ if (hash_mask(hash_nr,info->blength,info->records) != first_index)
++ break;
++ if (!(hash_nr & halfbuff))
++ { /* Key will not move */
++ if (!(flag & LOWFIND))
++ {
++ if (flag & HIGHFIND)
++ {
++ flag=LOWFIND | HIGHFIND;
++ /* key shall be moved to the current empty position */
++ gpos=empty;
++ ptr_to_rec=pos->data;
++ empty=pos; /* This place is now free */
++ }
++ else
++ {
++ flag=LOWFIND | LOWUSED; /* key isn't changed */
++ gpos=pos;
++ ptr_to_rec=pos->data;
++ }
++ }
++ else
++ {
++ if (!(flag & LOWUSED))
++ {
++ /* Change link of previous LOW-key */
++ gpos->data=ptr_to_rec;
++ gpos->next=(uint) (pos-data);
++ flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
++ }
++ gpos=pos;
++ ptr_to_rec=pos->data;
++ }
++ }
++ else
++ { /* key will be moved */
++ if (!(flag & HIGHFIND))
++ {
++ flag= (flag & LOWFIND) | HIGHFIND;
++ /* key shall be moved to the last (empty) position */
++ gpos2 = empty; empty=pos;
++ ptr_to_rec2=pos->data;
++ }
++ else
++ {
++ if (!(flag & HIGHUSED))
++ {
++ /* Change link of previous hash-key and save */
++ gpos2->data=ptr_to_rec2;
++ gpos2->next=(uint) (pos-data);
++ flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
++ }
++ gpos2=pos;
++ ptr_to_rec2=pos->data;
++ }
++ }
++ }
++ while ((idx=pos->next) != NO_RECORD);
++
++ if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
++ {
++ gpos->data=ptr_to_rec;
++ gpos->next=NO_RECORD;
++ }
++ if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
++ {
++ gpos2->data=ptr_to_rec2;
++ gpos2->next=NO_RECORD;
++ }
++ }
++ /* Check if we are at the empty position */
++
++ idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
++ pos=data+idx;
++ if (pos == empty)
++ {
++ pos->data=(uchar*) record;
++ pos->next=NO_RECORD;
++ }
++ else
++ {
++ /* Check if more records in same hash-nr family */
++ empty[0]=pos[0];
++ gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
++ if (pos == gpos)
++ {
++ pos->data=(uchar*) record;
++ pos->next=(uint) (empty - data);
++ }
++ else
++ {
++ pos->data=(uchar*) record;
++ pos->next=NO_RECORD;
++ movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
++ }
++ }
++ if (++info->records == info->blength)
++ info->blength+= info->blength;
++ return(0);
++}
++
++
++/******************************************************************************
++** Remove one record from hash-table. The record with the same record
++** ptr is removed.
++** if there is a free-function it's called for record if found
++******************************************************************************/
++
++my_bool hash_delete(HASH *hash,uchar *record)
++{
++ uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
++ HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
++ DBUG_ENTER("hash_delete");
++ if (!hash->records)
++ DBUG_RETURN(1);
++
++ blength=hash->blength;
++ data=dynamic_element(&hash->array,0,HASH_LINK*);
++ /* Search after record with key */
++ pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
++ gpos = 0;
++
++ while (pos->data != record)
++ {
++ gpos=pos;
++ if (pos->next == NO_RECORD)
++ DBUG_RETURN(1); /* Key not found */
++ pos=data+pos->next;
++ }
++
++ if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
++ hash->current_record= NO_RECORD;
++ lastpos=data+hash->records;
++
++ /* Remove link to record */
++ empty=pos; empty_index=(uint) (empty-data);
++ if (gpos)
++ gpos->next=pos->next; /* unlink current ptr */
++ else if (pos->next != NO_RECORD)
++ {
++ empty=data+(empty_index=pos->next);
++ pos->data=empty->data;
++ pos->next=empty->next;
++ }
++
++ if (empty == lastpos) /* last key at wrong pos or no next link */
++ goto exit;
++
++ /* Move the last key (lastpos) */
++ lastpos_hashnr=rec_hashnr(hash,lastpos->data);
++ /* pos is where lastpos should be */
++ pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
++ if (pos == empty) /* Move to empty position. */
++ {
++ empty[0]=lastpos[0];
++ goto exit;
++ }
++ pos_hashnr=rec_hashnr(hash,pos->data);
++ /* pos3 is where the pos should be */
++ pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
++ if (pos != pos3)
++ { /* pos is on wrong posit */
++ empty[0]=pos[0]; /* Save it here */
++ pos[0]=lastpos[0]; /* This should be here */
++ movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
++ goto exit;
++ }
++ pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
++ if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
++ { /* Identical key-positions */
++ if (pos2 != hash->records)
++ {
++ empty[0]=lastpos[0];
++ movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
++ goto exit;
++ }
++ idx= (uint) (pos-data); /* Link pos->next after lastpos */
++ }
++ else idx= NO_RECORD; /* Different positions merge */
++
++ empty[0]=lastpos[0];
++ movelink(data,idx,empty_index,pos->next);
++ pos->next=empty_index;
++
++exit:
++ VOID(pop_dynamic(&hash->array));
++ if (hash->free)
++ (*hash->free)((uchar*) record);
++ DBUG_RETURN(0);
++}
++
++ /*
++ Update keys when record has changed.
++ This is much more efficent than using a delete & insert.
++ */
++
++my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,uint old_key_length)
++{
++ uint idx,new_index,new_pos_index,blength,records,empty;
++ HASH_LINK org_link,*data,*previous,*pos;
++ DBUG_ENTER("hash_update");
++
++ data=dynamic_element(&hash->array,0,HASH_LINK*);
++ blength=hash->blength; records=hash->records;
++
++ /* Search after record with key */
++
++ idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
++ old_key_length :
++ hash->key_length)),
++ blength,records);
++ new_index=hash_mask(rec_hashnr(hash,record),blength,records);
++ if (idx == new_index)
++ DBUG_RETURN(0); /* Nothing to do (No record check) */
++ previous=0;
++ for (;;)
++ {
++
++ if ((pos= data+idx)->data == record)
++ break;
++ previous=pos;
++ if ((idx=pos->next) == NO_RECORD)
++ DBUG_RETURN(1); /* Not found in links */
++ }
++ hash->current_record= NO_RECORD;
++ org_link= *pos;
++ empty=idx;
++
++ /* Relink record from current chain */
++
++ if (!previous)
++ {
++ if (pos->next != NO_RECORD)
++ {
++ empty=pos->next;
++ *pos= data[pos->next];
++ }
++ }
++ else
++ previous->next=pos->next; /* unlink pos */
++
++ /* Move data to correct position */
++ pos=data+new_index;
++ new_pos_index=hash_rec_mask(hash,pos,blength,records);
++ if (new_index != new_pos_index)
++ { /* Other record in wrong position */
++ data[empty] = *pos;
++ movelink(data,new_index,new_pos_index,empty);
++ org_link.next=NO_RECORD;
++ data[new_index]= org_link;
++ }
++ else
++ { /* Link in chain at right position */
++ org_link.next=data[new_index].next;
++ data[empty]=org_link;
++ data[new_index].next=empty;
++ }
++ DBUG_RETURN(0);
++}
++
++
++uchar *hash_element(HASH *hash,uint idx)
++{
++ if (idx < hash->records)
++ return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
++ return 0;
++}
++
++
++#ifndef DBUG_OFF
++
++my_bool hash_check(HASH *hash)
++{
++ int error;
++ uint i,rec_link,found,max_links,seek,links,idx;
++ uint records,blength;
++ HASH_LINK *data,*hash_info;
++
++ records=hash->records; blength=hash->blength;
++ data=dynamic_element(&hash->array,0,HASH_LINK*);
++ error=0;
++
++ for (i=found=max_links=seek=0 ; i < records ; i++)
++ {
++ if (hash_rec_mask(hash,data+i,blength,records) == i)
++ {
++ found++; seek++; links=1;
++ for (idx=data[i].next ;
++ idx != NO_RECORD && found < records + 1;
++ idx=hash_info->next)
++ {
++ if (idx >= records)
++ {
++ DBUG_PRINT("error",
++ ("Found pointer outside array to %d from link starting at %d",
++ idx,i));
++ error=1;
++ }
++ hash_info=data+idx;
++ seek+= ++links;
++ if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i)
++ {
++ DBUG_PRINT("error",
++ ("Record in wrong link at %d: Start %d Record: %lx Record-link %d", idx,i,hash_info->data,rec_link));
++ error=1;
++ }
++ else
++ found++;
++ }
++ if (links > max_links) max_links=links;
++ }
++ }
++ if (found != records)
++ {
++ DBUG_PRINT("error",("Found %ld of %ld records"));
++ error=1;
++ }
++ if (records)
++ DBUG_PRINT("info",
++ ("records: %ld seeks: %d max links: %d hitrate: %.2f",
++ records,seek,max_links,(float) seek / (float) records));
++ return error;
++}
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/int2str.c mariadb-native-client.trunk/libmariadb/int2str.c
+--- mariadb/libmariadb/int2str.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/int2str.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,153 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Defines: int2str(), itoa(), ltoa()
++
++ int2str(dst, radix, val)
++ converts the (long) integer "val" to character form and moves it to
++ the destination string "dst" followed by a terminating NUL. The
++ result is normally a pointer to this NUL character, but if the radix
++ is dud the result will be NullS and nothing will be changed.
++
++ If radix is -2..-36, val is taken to be SIGNED.
++ If radix is 2.. 36, val is taken to be UNSIGNED.
++ That is, val is signed if and only if radix is. You will normally
++ use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
++ unsigned is what you generally want.
++
++ _dig_vec is public just in case someone has a use for it.
++ The definitions of itoa and ltoa are actually macros in m_string.h,
++ but this is where the code is.
++
++ Note: The standard itoa() returns a pointer to the argument, when int2str
++ returns the pointer to the end-null.
++ itoa assumes that 10 -base numbers are allways signed and other arn't.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++char NEAR _dig_vec[] =
++ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
++
++
++char *int2str(register long int val, register char *dst, register int radix)
++{
++ char buffer[65];
++ register char *p;
++ long int new_val;
++
++ if (radix < 0) {
++ if (radix < -36 || radix > -2) return NullS;
++ if (val < 0) {
++ *dst++ = '-';
++ val = -val;
++ }
++ radix = -radix;
++ } else {
++ if (radix > 36 || radix < 2) return NullS;
++ }
++ /* The slightly contorted code which follows is due to the
++ fact that few machines directly support unsigned long / and %.
++ Certainly the VAX C compiler generates a subroutine call. In
++ the interests of efficiency (hollow laugh) I let this happen
++ for the first digit only; after that "val" will be in range so
++ that signed integer division will do. Sorry 'bout that.
++ CHECK THE CODE PRODUCED BY YOUR C COMPILER. The first % and /
++ should be unsigned, the second % and / signed, but C compilers
++ tend to be extraordinarily sensitive to minor details of style.
++ This works on a VAX, that's all I claim for it.
++ */
++ p = &buffer[sizeof(buffer)-1];
++ *p = '\0';
++ new_val=(ulong) val / (ulong) radix;
++ *--p = _dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)];
++ val = new_val;
++#ifdef HAVE_LDIV
++ while (val != 0)
++ {
++ ldiv_t res;
++ res=ldiv(val,radix);
++ *--p = _dig_vec[res.rem];
++ val= res.quot;
++ }
++#else
++ while (val != 0)
++ {
++ new_val=val/radix;
++ *--p = _dig_vec[(uchar) (val-new_val*radix)];
++ val= new_val;
++ }
++#endif
++ while ((*dst++ = *p++) != 0) ;
++ return dst-1;
++}
++
++
++/*
++ This is a faster version of the above optimized for the normal case of
++ radix 10 / -10
++*/
++
++char *int10_to_str(long int val, char *dst, int radix)
++{
++ char buffer[65];
++ register char *p;
++ long int new_val;
++ unsigned long int uval= (unsigned long int)val;
++
++ if (radix < 0 && val < 0) /* -10 */
++ {
++ *dst++ = '-';
++ uval = (unsigned long int)0-uval;
++ }
++
++ p = &buffer[sizeof(buffer)-1];
++ *p = '\0';
++ new_val= (long)(uval / 10);
++ *--p = '0'+ (char)(uval - (unsigned long)new_val * 10);
++ val = new_val;
++
++ while (val != 0)
++ {
++ new_val=val/10;
++ *--p = '0' + (char) (val-new_val*10);
++ val= new_val;
++ }
++ while ((*dst++ = *p++) != 0) ;
++ return dst-1;
++}
++
++
++#ifdef USE_MY_ITOA
++
++ /* Change to less general itoa interface */
++
++char *my_itoa(int val, char *dst, int radix)
++{
++ VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
++ return dst;
++}
++
++char *my_ltoa(long int val, char *dst, int radix)
++{
++ VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
++ return dst;
++}
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/is_prefix.c mariadb-native-client.trunk/libmariadb/is_prefix.c
+--- mariadb/libmariadb/is_prefix.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/is_prefix.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,34 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : is_prefix.c
++ Author : Michael Widenius
++ Defines: is_prefix()
++
++ is_prefix(s, t) returns 1 if s starts with t.
++ A empty t is allways a prefix.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++int is_prefix(register const char *s, register const char *t)
++{
++ while (*t)
++ if (*s++ != *t++) return 0;
++ return 1; /* WRONG */
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/libmariadb.c mariadb-native-client.trunk/libmariadb/libmariadb.c
+--- mariadb/libmariadb/libmariadb.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/libmariadb.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,3437 @@
++/************************************************************************************
++ Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
++ Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*************************************************************************************/
++
++#include <my_global.h>
++
++#include <my_sys.h>
++#include <mysys_err.h>
++#include <m_string.h>
++#include <m_ctype.h>
++#include <ma_common.h>
++#include "mysql.h"
++#include "mysql_version.h"
++#include "mysqld_error.h"
++#include "errmsg.h"
++#include <sys/stat.h>
++#include <signal.h>
++#include <time.h>
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif
++#if !defined(MSDOS) && !defined(_WIN32)
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#ifdef HAVE_SELECT_H
++# include <select.h>
++#endif
++#ifdef HAVE_SYS_SELECT_H
++#include <sys/select.h>
++#endif
++#endif
++#ifdef HAVE_SYS_UN_H
++# include <sys/un.h>
++#endif
++#if defined(THREAD) && !defined(_WIN32)
++#include <my_pthread.h> /* because of signal() */
++#endif
++#ifndef INADDR_NONE
++#define INADDR_NONE -1
++#endif
++#include <sha1.h>
++#include <violite.h>
++#ifdef HAVE_OPENSSL
+#include <ma_secure.h>
- #endif
-
- static my_bool mysql_client_init=0;
-@@ -72,6 +72,17 @@
- extern const CHARSET_INFO * mysql_find_charset_name(const char * const name);
- extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
- const char *data_plugin, const char *db);
++#endif
++#ifndef _WIN32
++#include <poll.h>
++#endif
++#include <ma_dyncol.h>
++
++#undef max_allowed_packet
++#undef net_buffer_length
++extern ulong max_allowed_packet; /* net.c */
++extern ulong net_buffer_length; /* net.c */
++static MYSQL_PARAMETERS mariadb_internal_parameters=
++{&max_allowed_packet, &net_buffer_length, 0};
++
++static my_bool mysql_client_init=0;
++static void mysql_close_options(MYSQL *mysql);
++extern my_bool my_init_done;
++extern my_bool mysql_ps_subsystem_initialized;
++extern my_bool mysql_handle_local_infile(MYSQL *mysql, const char *filename);
++extern const CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
++extern const CHARSET_INFO * mysql_find_charset_name(const char * const name);
++extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
++ const char *data_plugin, const char *db);
+
+/* prepare statement methods from my_stmt.c */
+extern my_bool mthd_supported_buffer_type(enum enum_field_types type);
@@ -2186,89 +10972,684 @@
+extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
+extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
+extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt);
++extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
++
++uint mysql_port=0;
++my_string mysql_unix_port=0;
++
++#ifdef _WIN32
++#define CONNECT_TIMEOUT 20
++#else
++#define CONNECT_TIMEOUT 0
++#endif
+
- uint mysql_port=0;
- my_string mysql_unix_port=0;
-
-@@ -81,6 +92,8 @@
- #define CONNECT_TIMEOUT 0
- #endif
-
+struct st_mysql_methods MARIADB_DEFAULT_METHODS;
+
- #if defined(MSDOS) || defined(_WIN32)
- // socket_errno is defined in my_global.h for all platforms
- #define perror(A)
-@@ -94,10 +107,6 @@
- #define native_password_plugin_name "mysql_native_password"
- const char *unknown_sqlstate= "HY000";
-
--MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
-- uint field_count);
--static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
-- ulong *lengths);
- static void end_server(MYSQL *mysql);
- static void mysql_close_memory(MYSQL *mysql);
- void read_user_name(char *name);
-@@ -125,6 +134,7 @@
- #endif
-
-
++#if defined(MSDOS) || defined(_WIN32)
++// socket_errno is defined in my_global.h for all platforms
++#define perror(A)
++#else
++#include <errno.h>
++#define SOCKET_ERROR -1
++#endif /* _WIN32 */
+
- /****************************************************************************
- * A modified version of connect(). connect2() allows you to specify
- * a timeout value, in seconds, that we should wait until we
-@@ -523,14 +533,14 @@
-
-
- int
--simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
-- size_t length, my_bool skipp_check)
++#include <mysql/client_plugin.h>
++
++#define native_password_plugin_name "mysql_native_password"
++const char *unknown_sqlstate= "HY000";
++
++static void end_server(MYSQL *mysql);
++static void mysql_close_memory(MYSQL *mysql);
++void read_user_name(char *name);
++static void append_wild(char *to,char *end,const char *wild);
++static my_bool mysql_reconnect(MYSQL *mysql);
++static sig_handler pipe_sig_handler(int sig);
++static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
++
++extern int mysql_client_plugin_init();
++extern void mysql_client_plugin_deinit();
++
++/*
++ Let the user specify that we don't want SIGPIPE; This doesn't however work
++ with threaded applications as we can have multiple read in progress.
++*/
++
++#if !defined(_WIN32) && defined(SIGPIPE) && !defined(THREAD)
++#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
++#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
++#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
++#else
++#define init_sigpipe_variables
++#define set_sigpipe(mysql)
++#define reset_sigpipe(mysql)
++#endif
++
++
++
++/****************************************************************************
++* A modified version of connect(). connect2() allows you to specify
++* a timeout value, in seconds, that we should wait until we
++* derermine we can't connect to a particular host. If timeout is 0,
++* connect2() will behave exactly like connect().
++*
++* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
++*****************************************************************************/
++
++int socket_block(my_socket s,my_bool blocked)
++{
++#ifdef _WIN32
++ unsigned long socket_blocked= blocked ? 0 : 1;
++ return ioctlsocket(s, FIONBIO, &socket_blocked);
++#else
++ int flags= fcntl(s, F_GETFL, 0);
++ if (blocked)
++ flags&= ~O_NONBLOCK;
++ else
++ flags|= O_NONBLOCK;
++ return fcntl(s, F_SETFL, flags);
++#endif
++}
++
++static int connect2(my_socket s, const struct sockaddr *name, size_t namelen,
++ uint timeout)
++{
++ int res, s_err;
++ socklen_t s_err_size = sizeof(uint);
++#ifndef _WIN32
++ struct pollfd poll_fd;
++#else
++ FD_SET sfds, efds;
++ struct timeval tv;
++#endif
++
++ if (!timeout)
++ return connect(s, (struct sockaddr*) name, (int)namelen);
++
++ /* set socket to non blocking */
++ if (socket_block(s, 0) == SOCKET_ERROR)
++ return -1;
++
++ res= connect(s, (struct sockaddr*) name, (int)namelen);
++ if (res == 0)
++ return res;
++
++#ifdef _WIN32
++ if (GetLastError() != WSAEWOULDBLOCK &&
++ GetLastError() != WSAEINPROGRESS)
++#else
++ if (errno != EINPROGRESS)
++#endif
++ return -1;
++#ifndef _WIN32
++ memset(&poll_fd, 0, sizeof(struct pollfd));
++ poll_fd.events= POLLOUT | POLLERR;
++ poll_fd.fd= s;
++
++ /* connection timeout in milliseconds */
++ res= poll(&poll_fd, 1, (timeout > -1) ? timeout * 1000 : timeout);
++
++ switch(res)
++ {
++ /* Error= - 1, timeout = 0 */
++ case -1:
++ break;
++ case 0:
++ errno= ETIMEDOUT;
++ break;
++ }
++#else
++ FD_ZERO(&sfds);
++ FD_ZERO(&efds);
++ FD_SET(s, &sfds);
++ FD_SET(s, &efds);
++
++ memset(&tv, 0, sizeof(struct timeval));
++ tv.tv_sec= timeout;
++
++ res= select((int)s+1, NULL, &sfds, &efds, &tv);
++ if (res < 1)
++ return -1;
++#endif
++
++ s_err=0;
++ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
++ return(-1);
++
++ if (s_err)
++ { /* getsockopt could succeed */
++ errno = s_err;
++ return(-1); /* but return an error... */
++ }
++ return (0); /* ok */
++}
++
++/*
++** Create a named pipe connection
++*/
++
++#ifdef _WIN32
++
++HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
++ char **arg_unix_socket)
++{
++ HANDLE hPipe=INVALID_HANDLE_VALUE;
++ char szPipeName [ 257 ];
++ DWORD dwMode;
++ int i;
++ my_bool testing_named_pipes=0;
++ char *host= *arg_host, *unix_socket= *arg_unix_socket;
++
++ if ( ! unix_socket || (unix_socket)[0] == 0x00)
++ unix_socket = mysql_unix_port;
++ if (!host || !strcmp(host,LOCAL_HOST))
++ host=LOCAL_HOST_NAMEDPIPE;
++
++ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
++ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
++ host, unix_socket));
++
++ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
++ {
++ if ((hPipe = CreateFile(szPipeName,
++ GENERIC_READ | GENERIC_WRITE,
++ 0,
++ NULL,
++ OPEN_EXISTING,
++ 0,
++ NULL )) != INVALID_HANDLE_VALUE)
++ break;
++ if (GetLastError() != ERROR_PIPE_BUSY)
++ {
++ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
++ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
++ (ulong) GetLastError());
++ return INVALID_HANDLE_VALUE;
++ }
++ /* wait for for an other instance */
++ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
++ {
++ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
++ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
++ (ulong) GetLastError());
++ return INVALID_HANDLE_VALUE;
++ }
++ }
++ if (hPipe == INVALID_HANDLE_VALUE)
++ {
++ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
++ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
++ (ulong) GetLastError());
++ return INVALID_HANDLE_VALUE;
++ }
++ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
++ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
++ {
++ CloseHandle( hPipe );
++ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
++ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
++ (ulong) GetLastError());
++ return INVALID_HANDLE_VALUE;
++ }
++ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
++ return (hPipe);
++}
++#endif
++
++/* net_get_error */
++void net_get_error(char *buf, size_t buf_len,
++ char *error, size_t error_len,
++ unsigned int *error_no,
++ char *sqlstate)
++{
++ char *p= buf;
++ size_t error_msg_len= 0;
++
++ if (buf_len > 2)
++ {
++ *error_no= uint2korr(p);
++ p+= 2;
++
++ /* since 4.1 sqlstate is following */
++ if (*p == '#')
++ {
++ memcpy(sqlstate, ++p, SQLSTATE_LENGTH);
++ p+= SQLSTATE_LENGTH;
++ }
++ error_msg_len= buf_len - (p - buf);
++ error_msg_len= MIN(error_msg_len, error_len - 1);
++ memcpy(error, p, error_msg_len);
++ }
++ else
++ {
++ *error_no= CR_UNKNOWN_ERROR;
++ memcpy(sqlstate, unknown_sqlstate, SQLSTATE_LENGTH);
++ }
++}
++
++
++/*****************************************************************************
++** read a packet from server. Give error message if socket was down
++** or packet is an error message
++*****************************************************************************/
++
++ulong
++net_safe_read(MYSQL *mysql)
++{
++ NET *net= &mysql->net;
++ ulong len=0;
++ init_sigpipe_variables
++
++restart:
++ /* Don't give sigpipe errors if the client doesn't want them */
++ set_sigpipe(mysql);
++ if (net->vio != 0)
++ len=my_net_read(net);
++ reset_sigpipe(mysql);
++
++ if (len == packet_error || len == 0)
++ {
++ end_server(mysql);
++ my_set_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
++ CR_NET_PACKET_TOO_LARGE:
++ CR_SERVER_LOST,
++ SQLSTATE_UNKNOWN, 0);
++ return(packet_error);
++ }
++ if (net->read_pos[0] == 255)
++ {
++ if (len > 3)
++ {
++ char *pos=(char*) net->read_pos+1;
++ uint last_errno=uint2korr(pos);
++ pos+=2;
++ len-=2;
++
++ if (last_errno== 65535 &&
++ (mysql->server_capabilities & CLIENT_PROGRESS))
++ {
++ if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1)))
++ {
++ /* Wrong packet */
++ my_set_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate, 0);
++ return (packet_error);
++ }
++ goto restart;
++ }
++ net->last_errno= last_errno;
++ if (pos[0]== '#')
++ {
++ strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
++ pos+= SQLSTATE_LENGTH + 1;
++ }
++ else
++ {
++ strmov(net->sqlstate, SQLSTATE_UNKNOWN);
++ }
++ (void) strmake(net->last_error,(char*) pos,
++ min(len,sizeof(net->last_error)-1));
++ }
++ else
++ {
++ my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
++ }
++
++ mysql->server_status&= ~SERVER_MORE_RESULTS_EXIST;
++
++ DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
++ net->last_error));
++ return(packet_error);
++ }
++ return len;
++}
++
++/*
++ Report progress to the client
++
++ RETURN VALUES
++ 0 ok
++ 1 error
++*/
++static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length)
++{
++ uint stage, max_stage, proc_length;
++ double progress;
++ uchar *start= packet;
++
++ if (length < 5)
++ return 1; /* Wrong packet */
++
++ if (!(mysql->options.extension && mysql->options.extension->report_progress))
++ return 0; /* No callback, ignore packet */
++
++ packet++; /* Ignore number of strings */
++ stage= (uint) *packet++;
++ max_stage= (uint) *packet++;
++ progress= uint3korr(packet)/1000.0;
++ packet+= 3;
++ proc_length= net_field_length(&packet);
++ if (packet + proc_length > start + length)
++ return 1; /* Wrong packet */
++ (*mysql->options.extension->report_progress)(mysql, stage, max_stage,
++ progress, (char*) packet,
++ proc_length);
++ return 0;
++}
++
++/* Get the length of next field. Change parameter to point at fieldstart */
++ulong
++net_field_length(uchar **packet)
++{
++ reg1 uchar *pos= *packet;
++ if (*pos < 251)
++ {
++ (*packet)++;
++ return (ulong) *pos;
++ }
++ if (*pos == 251)
++ {
++ (*packet)++;
++ return NULL_LENGTH;
++ }
++ if (*pos == 252)
++ {
++ (*packet)+=3;
++ return (ulong) uint2korr(pos+1);
++ }
++ if (*pos == 253)
++ {
++ (*packet)+=4;
++ return (ulong) uint3korr(pos+1);
++ }
++ (*packet)+=9; /* Must be 254 when here */
++ return (ulong) uint4korr(pos+1);
++}
++
++/* Same as above, but returns ulonglong values */
++
++static my_ulonglong
++net_field_length_ll(uchar **packet)
++{
++ reg1 uchar *pos= *packet;
++ if (*pos < 251)
++ {
++ (*packet)++;
++ return (my_ulonglong) *pos;
++ }
++ if (*pos == 251)
++ {
++ (*packet)++;
++ return (my_ulonglong) NULL_LENGTH;
++ }
++ if (*pos == 252)
++ {
++ (*packet)+=3;
++ return (my_ulonglong) uint2korr(pos+1);
++ }
++ if (*pos == 253)
++ {
++ (*packet)+=4;
++ return (my_ulonglong) uint3korr(pos+1);
++ }
++ (*packet)+=9; /* Must be 254 when here */
++#ifdef NO_CLIENT_LONGLONG
++ return (my_ulonglong) uint4korr(pos+1);
++#else
++ return (my_ulonglong) uint8korr(pos+1);
++#endif
++}
++
++
++void free_rows(MYSQL_DATA *cur)
++{
++ if (cur)
++ {
++ free_root(&cur->alloc,MYF(0));
++ my_free((gptr) cur,MYF(0));
++ }
++}
++
++
++int
+mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ size_t length, my_bool skipp_check, void *opt_arg)
- {
- NET *net= &mysql->net;
- int result= -1;
- init_sigpipe_variables
-
-- DBUG_ENTER("simple_command");
++{
++ NET *net= &mysql->net;
++ int result= -1;
++ init_sigpipe_variables
++
+ DBUG_ENTER("mthd_my_send_command");
-
- DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
-
-@@ -591,6 +601,12 @@
- DBUG_RETURN(result);
- }
-
++
++ DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
++
++ /* Don't give sigpipe errors if the client doesn't want them */
++ set_sigpipe(mysql);
++ if (mysql->net.vio == 0)
++ { /* Do reconnect if possible */
++ if (mysql_reconnect(mysql))
++ {
++ DBUG_PRINT("info", ("reconnect failed"));
++ DBUG_RETURN(1);
++ }
++ }
++ if (mysql->status != MYSQL_STATUS_READY ||
++ mysql->server_status & SERVER_MORE_RESULTS_EXIST)
++ {
++ SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
++ goto end;
++ }
++
++ CLEAR_CLIENT_ERROR(mysql);
++
++ mysql->info=0;
++ mysql->affected_rows= ~(my_ulonglong) 0;
++ net_clear(net); /* Clear receive buffer */
++ if (!arg)
++ arg="";
++
++ if (net_write_command(net,(uchar) command,arg,
++ length ? length : (ulong) strlen(arg)))
++ {
++ DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno));
++ if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
++ {
++ my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
++ goto end;
++ }
++ end_server(mysql);
++ if (mysql_reconnect(mysql))
++ goto end;
++ if (net_write_command(net,(uchar) command,arg,
++ length ? length : (ulong) strlen(arg)))
++ {
++ my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
++ goto end;
++ }
++ }
++ result=0;
++ if (!skipp_check) {
++ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
++ 1 : 0);
++ DBUG_PRINT("info", ("packet_length=%llu", mysql->packet_length));
++ }
++ end:
++ reset_sigpipe(mysql);
++ DBUG_RETURN(result);
++}
++
+int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ size_t length, my_bool skipp_check, void *opt_arg)
+{
+ return mysql->methods->db_command(mysql, command, arg, length, skipp_check, opt_arg);
+}
-
- static void free_old_query(MYSQL *mysql)
- {
-@@ -711,13 +727,13 @@
- DBUG_PUSH(env);
- #if !defined(_WINVER) && !defined(WINVER)
- puts("\n-------------------------------------------------------");
-- puts("MYSQL_DEBUG found. libmysql started with the following:");
++
++static void free_old_query(MYSQL *mysql)
++{
++ DBUG_ENTER("free_old_query");
++ if (mysql->fields)
++ free_root(&mysql->field_alloc,MYF(0));
++ init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
++ mysql->fields=0;
++ mysql->field_count=0; /* For API */
++ DBUG_VOID_RETURN;
++}
++
++#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
++struct passwd *getpwuid(uid_t);
++char* getlogin(void);
++#endif
++
++#if !defined(MSDOS) && ! defined(VMS) && !defined(_WIN32) && !defined(OS2)
++void read_user_name(char *name)
++{
++ DBUG_ENTER("read_user_name");
++ if (geteuid() == 0)
++ (void) strmov(name,"root"); /* allow use of surun */
++ else
++ {
++#ifdef HAVE_GETPWUID
++ struct passwd *skr;
++ const char *str;
++ if ((str=getlogin()) == NULL)
++ {
++ if ((skr=getpwuid(geteuid())) != NULL)
++ str=skr->pw_name;
++ else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
++ !(str=getenv("LOGIN")))
++ str="UNKNOWN_USER";
++ }
++ (void) strmake(name,str,USERNAME_LENGTH);
++#elif HAVE_CUSERID
++ (void) cuserid(name);
++#else
++ strmov(name,"UNKNOWN_USER");
++#endif
++ }
++ DBUG_VOID_RETURN;
++}
++
++#else /* If MSDOS || VMS */
++
++void read_user_name(char *name)
++{
++ char *str=getenv("USERNAME"); /* ODBC will send user variable */
++ strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
++}
++
++#endif
++
++#ifdef _WIN32
++static my_bool is_NT(void)
++{
++ char *os=getenv("OS");
++ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
++}
++#endif
++
++/*
++** Expand wildcard to a sql string
++*/
++
++static void
++append_wild(char *to, char *end, const char *wild)
++{
++ end-=5; /* Some extra */
++ if (wild && wild[0])
++ {
++ to=strmov(to," like '");
++ while (*wild && to < end)
++ {
++ if (*wild == '\\' || *wild == '\'')
++ *to++='\\';
++ *to++= *wild++;
++ }
++ if (*wild) /* Too small buffer */
++ *to++='%'; /* Nicer this way */
++ to[0]='\'';
++ to[1]=0;
++ }
++}
++
++
++
++/**************************************************************************
++** Init debugging if MYSQL_DEBUG environment variable is found
++**************************************************************************/
++void STDCALL mysql_debug_end()
++{
++#ifndef DBUG_OFF
++ DEBUGGER_OFF;
++ DBUG_POP();
++#endif
++}
++
++void STDCALL
++mysql_debug(const char *debug __attribute__((unused)))
++{
++#ifndef DBUG_OFF
++ char *env;
++ if (debug)
++ {
++ DEBUGGER_ON;
++ DBUG_PUSH(debug);
++ }
++ else if ((env = getenv("MYSQL_DEBUG")))
++ {
++ DEBUGGER_ON;
++ DBUG_PUSH(env);
++#if !defined(_WINVER) && !defined(WINVER)
++ puts("\n-------------------------------------------------------");
+ puts("MYSQL_DEBUG found. libmariadb started with the following:");
- puts(env);
- puts("-------------------------------------------------------\n");
- #else
- {
- char buff[80];
-- strmov(strmov(buff,"libmysql: "),env);
++ puts(env);
++ puts("-------------------------------------------------------\n");
++#else
++ {
++ char buff[80];
+ strmov(strmov(buff,"libmariadb: "),env);
- MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
- }
- #endif
-@@ -762,6 +778,18 @@
- DBUG_VOID_RETURN;
- }
-
++ MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
++ }
++#endif
++ }
++#endif
++}
++
++
++/**************************************************************************
++** Close the server connection if we get a SIGPIPE
++ ARGSUSED
++**************************************************************************/
++
++static sig_handler
++pipe_sig_handler(int sig __attribute__((unused)))
++{
++ DBUG_PRINT("info",("Hit by signal %d",sig));
++#ifdef DONT_REMEMBER_SIGNAL
++ (void) signal(SIGPIPE,pipe_sig_handler);
++#endif
++}
++
++
++/**************************************************************************
++** Shut down connection
++**************************************************************************/
++
++static void
++end_server(MYSQL *mysql)
++{
++ DBUG_ENTER("end_server");
++ if (mysql->net.vio != 0)
++ {
++ init_sigpipe_variables
++ set_sigpipe(mysql);
++ vio_delete(mysql->net.vio);
++ reset_sigpipe(mysql);
++ mysql->net.vio= 0; /* Marker */
++ }
++ net_end(&mysql->net);
++ free_old_query(mysql);
++ DBUG_VOID_RETURN;
++}
++
+void mthd_my_skip_result(MYSQL *mysql)
+{
+ ulong pkt_len;
@@ -2281,73 +11662,82 @@
+ } while (pkt_len > 8 || mysql->net.read_pos[0] != 254);
+ DBUG_VOID_RETURN;
+}
-
- void STDCALL
- mysql_free_result(MYSQL_RES *result)
-@@ -772,14 +800,7 @@
- {
- if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
- {
-- ulong pkt_len;
-- DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
--
-- do {
-- pkt_len= net_safe_read(result->handle);
-- if (pkt_len == packet_error)
-- break;
-- } while (pkt_len > 8 || result->handle->net.read_pos[0] != 254);
++
++void STDCALL
++mysql_free_result(MYSQL_RES *result)
++{
++ DBUG_ENTER("mysql_free_result");
++ DBUG_PRINT("enter",("mysql_res: %lx",result));
++ if (result)
++ {
++ if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
++ {
+ result->handle->methods->db_skip_result(result->handle);
- result->handle->status=MYSQL_STATUS_READY;
- }
- free_rows(result->data);
-@@ -806,7 +827,7 @@
- "connect-timeout", "local-infile", "disable-local-infile",
- "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
- "multi-results", "multi-statements", "multi-queries", "secure-auth",
-- "report-data-truncation", "plugin-dir", "default-auth",
++ result->handle->status=MYSQL_STATUS_READY;
++ }
++ free_rows(result->data);
++ if (result->fields)
++ free_root(&result->field_alloc,MYF(0));
++ if (result->row)
++ my_free((gptr) result->row,MYF(0));
++ my_free((gptr) result,MYF(0));
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++/****************************************************************************
++** Get options from my.cnf
++****************************************************************************/
++
++static const char *default_options[]=
++{
++ "port","socket","compress","password","pipe", "timeout", "user",
++ "init-command", "host", "database", "debug", "return-found-rows",
++ "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
++ "character-sets-dir", "default-character-set", "interactive-timeout",
++ "connect-timeout", "local-infile", "disable-local-infile",
++ "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
++ "multi-results", "multi-statements", "multi-queries", "secure-auth",
+ "report-data-truncation", "plugin-dir", "default-auth", "database-type",
- NULL
- };
-
-@@ -820,29 +841,44 @@
- OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
- OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
- OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
-- OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth
++ NULL
++};
++
++enum option_val
++{
++ OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe,
++ OPT_timeout, OPT_user, OPT_init_command, OPT_host, OPT_database,
++ OPT_debug, OPT_return_found_rows, OPT_ssl_key, OPT_ssl_cert,
++ OPT_ssl_ca, OPT_ssl_capath, OPT_charset_dir,
++ OPT_charset_name, OPT_interactive_timeout,
++ OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
++ OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
++ OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
+ OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, OPT_db_type
- };
-
-+#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL, IS_STRING) \
++};
++
++#define CHECK_OPT_EXTENSION_SET(OPTS)\
+ if (!(OPTS)->extension) \
+ (OPTS)->extension= (struct st_mysql_options_extention *) \
+ my_malloc(sizeof(struct st_mysql_options_extention), \
+ MYF(MY_WME | MY_ZEROFILL)); \
++
++#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL, IS_STRING) \
++ CHECK_OPT_EXTENSION_SET(OPTS) \
+ if (IS_STRING) { \
+ my_free((char *)(OPTS)->extension->KEY, MYF(MY_ALLOW_ZERO_PTR)); \
+ (OPTS)->extension->KEY= my_strdup((char *)(VAL), MYF(MY_WME)); \
+ } else \
+ (OPTS)->extension->KEY= (VAL);
+
- static TYPELIB option_types={array_elements(default_options)-1,
- "options",default_options};
-
--#define extension_set(OPTS, X, VAL) \
-- if (!(OPTS)->extension) \
-- (OPTS)->extension= (struct st_mysql_options_extention *) \
-- my_malloc(sizeof(struct st_mysql_options_extention), \
-- MYF(MY_WME | MY_ZEROFILL)); \
-- (OPTS)->extension->X= VAL;
--
--#define extension_set_string(OPTS, X, STR) \
-- if ((OPTS)->extension) \
-- my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR)); \
-- extension_set(OPTS, X, my_strdup((STR), MYF(MY_WME)));
--
- const char *protocol_names[]= {"TCP", "SOCKED", "PIPE", "MEMORY", NULL};
- static TYPELIB protocol_types= {array_elements(protocol_names)-1,
- "protocol names",
- protocol_names};
-
++static TYPELIB option_types={array_elements(default_options)-1,
++ "options",default_options};
++
++const char *protocol_names[]= {"TCP", "SOCKED", "PIPE", "MEMORY", NULL};
++static TYPELIB protocol_types= {array_elements(protocol_names)-1,
++ "protocol names",
++ protocol_names};
++
+static void options_add_initcommand(struct st_mysql_options *options,
+ const char *init_cmd)
+{
@@ -2359,97 +11749,32 @@
+ my_init_dynamic_array(options->init_command, sizeof(char*), 5, 5);
+ }
+
-+ if (insert_dynamic(options->init_command, (uchar*)&insert))
++ if (insert_dynamic(options->init_command, (gptr)&insert))
+ my_free(insert, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
- static void mysql_read_default_options(struct st_mysql_options *options,
- const char *filename,const char *group)
- {
-@@ -864,132 +900,128 @@
- /* DBUG_PRINT("info",("option: %s",option[0])); */
- if (option[0][0] == '-' && option[0][1] == '-')
- {
-- char *end=strcend(*option,'=');
-- char *opt_arg=0;
-- if (*end)
-- {
-- opt_arg=end+1;
-- *end=0; /* Remove '=' */
-- }
-- /* Change all '_' in variable name to '-' */
-- for (end= *option ; *(end= strcend(end,'_')) ; )
-- *end= '-';
-- switch (find_type(*option+2,&option_types,2)) {
-- case OPT_port:
-- if (opt_arg)
-- options->port=atoi(opt_arg);
-- break;
-- case OPT_socket:
-- if (opt_arg)
-- {
-- my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR));
-- options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
-- }
-- break;
-- case OPT_compress:
-- options->compress=1;
-- break;
-- case OPT_password:
-- if (opt_arg)
-- {
-- my_free(options->password,MYF(MY_ALLOW_ZERO_PTR));
-- options->password=my_strdup(opt_arg,MYF(MY_WME));
-- }
-- break;
-- case OPT_pipe:
-- options->named_pipe=1; /* Force named pipe */
-- break;
-- case OPT_connect_timeout:
-- case OPT_timeout:
-- if (opt_arg)
-- options->connect_timeout=atoi(opt_arg);
-- break;
-- case OPT_user:
-- if (opt_arg)
-- {
-- my_free(options->user,MYF(MY_ALLOW_ZERO_PTR));
-- options->user=my_strdup(opt_arg,MYF(MY_WME));
-- }
-- break;
-- case OPT_init_command:
-- if (opt_arg)
-- {
-- /* todo
-- my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
-- options->init_command=my_strdup(opt_arg,MYF(MY_WME));
-- */
-- }
-- break;
-- case OPT_host:
-- if (opt_arg)
-- {
-- my_free(options->host,MYF(MY_ALLOW_ZERO_PTR));
-- options->host=my_strdup(opt_arg,MYF(MY_WME));
-- }
-- break;
-- case OPT_database:
-- if (opt_arg)
-- {
-- my_free(options->db,MYF(MY_ALLOW_ZERO_PTR));
-- options->db=my_strdup(opt_arg,MYF(MY_WME));
-- }
-- break;
-- case OPT_debug:
-- mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
-- break;
-- case OPT_return_found_rows:
-- options->client_flag|=CLIENT_FOUND_ROWS;
-- break;
--#ifdef HAVE_OPENSSL
-- case OPT_ssl_key:
-- my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
++static void mysql_read_default_options(struct st_mysql_options *options,
++ const char *filename,const char *group)
++{
++ int argc;
++ char *argv_buff[1],**argv;
++ const char *groups[3];
++ DBUG_ENTER("mysql_read_default_options");
++ DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
++
++ argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
++ groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
++
++ load_defaults(filename, groups, &argc, &argv);
++ if (argc != 1) /* If some default option */
++ {
++ char **option=argv;
++ while (*++option)
++ {
++ /* DBUG_PRINT("info",("option: %s",option[0])); */
++ if (option[0][0] == '-' && option[0][1] == '-')
++ {
+ char *end=strcend(*option,'=');
+ char *opt_arg=0;
+ if (*end)
@@ -2524,64 +11849,37 @@
+ #ifdef HAVE_OPENSSL
+ case OPT_ssl_key:
+ my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
- options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
- break;
-- case OPT_ssl_cert:
-- my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
++ options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
++ break;
+ case OPT_ssl_cert:
+ my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
- options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
- break;
-- case OPT_ssl_ca:
-- my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
++ options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
++ break;
+ case OPT_ssl_ca:
+ my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
- options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
- break;
-- case OPT_ssl_capath:
++ options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
++ break;
+ case OPT_ssl_capath:
- my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
- options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
- break;
- case OPT_ssl_cipher:
- break;
- #else
-- case OPT_ssl_key:
-- case OPT_ssl_cert:
-- case OPT_ssl_ca:
-- case OPT_ssl_capath:
++ my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
++ options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
++ break;
++ case OPT_ssl_cipher:
++ break;
++#else
+ case OPT_ssl_key:
+ case OPT_ssl_cert:
+ case OPT_ssl_ca:
+ case OPT_ssl_capath:
- case OPT_ssl_cipher:
- break;
- #endif /* HAVE_OPENSSL */
-- case OPT_charset_dir:
-- my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
++ case OPT_ssl_cipher:
++ break;
++#endif /* HAVE_OPENSSL */
+ case OPT_charset_dir:
+ my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
- options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
-- break;
-- case OPT_charset_name:
-- my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
++ options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case OPT_charset_name:
+ my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
- options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
-- break;
-- case OPT_interactive_timeout:
-- options->client_flag|= CLIENT_INTERACTIVE;
-- break;
-- case OPT_local_infile:
-- if (!opt_arg || atoi(opt_arg) != 0)
-- options->client_flag|= CLIENT_LOCAL_FILES;
-- else
-- options->client_flag&= ~CLIENT_LOCAL_FILES;
-- break;
-- case OPT_disable_local_infile:
-- options->client_flag&= CLIENT_LOCAL_FILES;
-- break;
++ options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case OPT_interactive_timeout:
+ options->client_flag|= CLIENT_INTERACTIVE;
@@ -2595,40 +11893,41 @@
+ case OPT_disable_local_infile:
+ options->client_flag&= CLIENT_LOCAL_FILES;
+ break;
- case OPT_max_allowed_packet:
- if(opt_arg)
- options->max_allowed_packet= atoi(opt_arg);
++ case OPT_max_allowed_packet:
++ if(opt_arg)
++ options->max_allowed_packet= atoi(opt_arg);
+ break;
- case OPT_protocol:
- options->protocol= find_type(opt_arg, &protocol_types, 0);
- #ifndef _WIN32
-@@ -998,14 +1030,12 @@
- if (options->protocol < 0)
- #endif
- {
-- fprintf(stderr,
-- "Unknown or unsupported protocol %s",
-- opt_arg);
++ case OPT_protocol:
++ options->protocol= find_type(opt_arg, &protocol_types, 0);
++#ifndef _WIN32
++ if (options->protocol < 0 || options->protocol > 1)
++#else
++ if (options->protocol < 0)
++#endif
++ {
+ fprintf(stderr, "Unknown or unsupported protocol %s", opt_arg);
- }
- break;
- case OPT_shared_memory_base_name:
- /* todo */
-- break;
++ }
+ break;
- case OPT_multi_results:
- options->client_flag|= CLIENT_MULTI_RESULTS;
- break;
-@@ -1018,15 +1048,25 @@
- options->report_data_truncation= atoi(opt_arg);
- else
- options->report_data_truncation= 1;
-- break;
++ case OPT_shared_memory_base_name:
++ /* todo */
++ break;
++ case OPT_multi_results:
++ options->client_flag|= CLIENT_MULTI_RESULTS;
++ break;
++ case OPT_multi_statements:
++ case OPT_multi_queries:
++ options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
+ break;
- case OPT_secure_auth:
++ case OPT_report_data_truncation:
++ if (opt_arg)
++ options->report_data_truncation= atoi(opt_arg);
++ else
++ options->report_data_truncation= 1;
++ break;
++ case OPT_secure_auth:
+ options->secure_auth= 1;
+ break;
- case OPT_plugin_dir:
++ case OPT_plugin_dir:
+ {
+ char directory[FN_REFLEN];
+ if (strlen(opt_arg) >= FN_REFLEN)
@@ -2637,73 +11936,417 @@
+ OPT_SET_EXTENDED_VALUE(options, plugin_dir, convert_dirname(directory), 1);
+ }
+ break;
- case OPT_default_auth:
-- /* todo */
-- break;
-- default:
-- DBUG_PRINT("warning",("unknown option: %s",option[0]));
-- }
++ case OPT_default_auth:
+ OPT_SET_EXTENDED_VALUE(options, default_auth, opt_arg, 1);
+ break;
+ default:
+ DBUG_PRINT("warning",("unknown option: %s",option[0]));
+ }
- }
- }
- }
-@@ -1120,7 +1160,7 @@
-
- /* Read all rows (fields or data) from server */
-
--MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
++ }
++ }
++ }
++ free_defaults(argv);
++ DBUG_VOID_RETURN;
++}
++
++
++/***************************************************************************
++** Change field rows to field structs
++***************************************************************************/
++
++static size_t rset_field_offsets[]= {
++ OFFSET(MYSQL_FIELD, catalog),
++ OFFSET(MYSQL_FIELD, catalog_length),
++ OFFSET(MYSQL_FIELD, db),
++ OFFSET(MYSQL_FIELD, db_length),
++ OFFSET(MYSQL_FIELD, table),
++ OFFSET(MYSQL_FIELD, table_length),
++ OFFSET(MYSQL_FIELD, org_table),
++ OFFSET(MYSQL_FIELD, org_table_length),
++ OFFSET(MYSQL_FIELD, name),
++ OFFSET(MYSQL_FIELD, name_length),
++ OFFSET(MYSQL_FIELD, org_name),
++ OFFSET(MYSQL_FIELD, org_name_length)
++};
++
++MYSQL_FIELD *
++unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
++ my_bool default_value, my_bool long_flag_protocol)
++{
++ MYSQL_ROWS *row;
++ MYSQL_FIELD *field,*result;
++ char *p;
++ unsigned int i, field_count= sizeof(rset_field_offsets)/sizeof(size_t)/2;
++
++ DBUG_ENTER("unpack_fields");
++ field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
++ if (!result)
++ DBUG_RETURN(0);
++
++ for (row=data->data; row ; row = row->next,field++)
++ {
++ for (i=0; i < field_count; i++)
++ {
++ switch(row->data[i][0]) {
++ case 0:
++ *(char **)(((char *)field) + rset_field_offsets[i*2])= strdup_root(alloc, "");
++ *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= 0;
++ break;
++ default:
++ *(char **)(((char *)field) + rset_field_offsets[i*2])=
++ strdup_root(alloc, (char *)row->data[i]);
++ *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])=
++ (uint)(row->data[i+1] - row->data[i] - 1);
++ break;
++ }
++ }
++
++ p= (char *)row->data[6];
++ /* filler */
++ field->charsetnr= uint2korr(p);
++ p+= 2;
++ field->length= (uint) uint4korr(p);
++ p+= 4;
++ field->type= (enum enum_field_types)uint1korr(p);
++ p++;
++ field->flags= uint2korr(p);
++ p+= 2;
++ field->decimals= (uint) p[0];
++ p++;
++
++ /* filler */
++ p+= 2;
++
++ if (INTERNAL_NUM_FIELD(field))
++ field->flags|= NUM_FLAG;
++
++ if (default_value && row->data[7])
++ {
++ field->def=strdup_root(alloc,(char*) row->data[7]);
++ }
++ else
++ field->def=0;
++ field->max_length= 0;
++ }
++ free_rows(data); /* Free old data */
++ DBUG_RETURN(result);
++}
++
++
++/* Read all rows (fields or data) from server */
++
+MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
- uint fields)
- {
- uint field;
-@@ -1131,7 +1171,7 @@
- MYSQL_DATA *result;
- MYSQL_ROWS **prev_ptr,*cur;
- NET *net = &mysql->net;
-- DBUG_ENTER("read_rows");
++ uint fields)
++{
++ uint field;
++ ulong pkt_len;
++ ulong len;
++ uchar *cp;
++ char *to, *end_to;
++ MYSQL_DATA *result;
++ MYSQL_ROWS **prev_ptr,*cur;
++ NET *net = &mysql->net;
+ DBUG_ENTER("madb_read_rows");
-
- if ((pkt_len= net_safe_read(mysql)) == packet_error)
- DBUG_RETURN(0);
-@@ -1216,8 +1256,7 @@
- */
-
-
--static int
--read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
++
++ if ((pkt_len= net_safe_read(mysql)) == packet_error)
++ DBUG_RETURN(0);
++ if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
++ MYF(MY_WME | MY_ZEROFILL))))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
++ result->alloc.min_malloc=sizeof(MYSQL_ROWS);
++ prev_ptr= &result->data;
++ result->rows=0;
++ result->fields=fields;
++
++ while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
++ {
++ result->rows++;
++ if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
++ sizeof(MYSQL_ROWS))) ||
++ !(cur->data= ((MYSQL_ROW)
++ alloc_root(&result->alloc,
++ (fields+1)*sizeof(char *)+pkt_len))))
++ {
++ free_rows(result);
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ *prev_ptr=cur;
++ prev_ptr= &cur->next;
++ to= (char*) (cur->data+fields+1);
++ end_to=to+pkt_len-1;
++ for (field=0 ; field < fields ; field++)
++ {
++ if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
++ { /* null field */
++ cur->data[field] = 0;
++ }
++ else
++ {
++ cur->data[field] = to;
++ if (len > (ulong) (end_to - to))
++ {
++ free_rows(result);
++ SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ memcpy(to,(char*) cp,len); to[len]=0;
++ to+=len+1;
++ cp+=len;
++ if (mysql_fields)
++ {
++ if (mysql_fields[field].max_length < len)
++ mysql_fields[field].max_length=len;
++ }
++ }
++ }
++ cur->data[field]=to; /* End of last field */
++ if ((pkt_len=net_safe_read(mysql)) == packet_error)
++ {
++ free_rows(result);
++ DBUG_RETURN(0);
++ }
++ }
++ *prev_ptr=0; /* last pointer is null */
++ /* save status */
++ if (pkt_len > 1)
++ {
++ cp++;
++ mysql->warning_count= uint2korr(cp);
++ cp+= 2;
++ mysql->server_status= uint2korr(cp);
++ }
++ DBUG_PRINT("exit",("Got %d rows",result->rows));
++ DBUG_RETURN(result);
++}
++
++
++/*
++** Read one row. Uses packet buffer as storage for fields.
++** When next packet is read, the previous field values are destroyed
++*/
++
++
+int mthd_my_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
- {
- uint field;
- ulong pkt_len,len;
-@@ -1310,12 +1349,13 @@
-
- int STDCALL
- mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
-- const char *ca, const char *capath)
++{
++ uint field;
++ ulong pkt_len,len;
++ uchar *pos,*prev_pos, *end_pos;
++
++ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
++ return -1;
++
++ if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
++ {
++ mysql->warning_count= uint2korr(mysql->net.read_pos + 1);
++ mysql->server_status= uint2korr(mysql->net.read_pos + 3);
++ return 1; /* End of data */
++ }
++ prev_pos= 0; /* allowed to write at packet[-1] */
++ pos=mysql->net.read_pos;
++ end_pos=pos+pkt_len;
++ for (field=0 ; field < fields ; field++)
++ {
++ if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
++ { /* null field */
++ row[field] = 0;
++ *lengths++=0;
++ }
++ else
++ {
++ if (len > (ulong) (end_pos - pos))
++ {
++ mysql->net.last_errno=CR_UNKNOWN_ERROR;
++ strmov(mysql->net.last_error,ER(mysql->net.last_errno));
++ return -1;
++ }
++ row[field] = (char*) pos;
++ pos+=len;
++ *lengths++=len;
++ }
++ if (prev_pos)
++ *prev_pos=0; /* Terminate prev field */
++ prev_pos=pos;
++ }
++ row[field]=(char*) prev_pos+1; /* End of last field */
++ *prev_pos=0; /* Terminate last field */
++ return 0;
++}
++
++/****************************************************************************
++** Init MySQL structure or allocate one
++****************************************************************************/
++
++MYSQL * STDCALL
++mysql_init(MYSQL *mysql)
++{
++ if (mysql_server_init(0, NULL, NULL))
++ return NULL;
++ if (!mysql)
++ {
++ if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
++ return 0;
++ mysql->free_me=1;
++ mysql->net.vio= 0;
++ }
++ else
++ bzero((char*) (mysql),sizeof(*(mysql)));
++ mysql->options.connect_timeout=CONNECT_TIMEOUT;
++ mysql->charset= default_charset_info;
++ strmov(mysql->net.sqlstate, "00000");
++ mysql->net.last_error[0]= mysql->net.last_errno= 0;
++#if defined(SIGPIPE) && defined(THREAD) && !defined(_WIN32)
++ if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
++ (void) signal(SIGPIPE,pipe_sig_handler);
++#endif
++
++/*
++ Only enable LOAD DATA INFILE by default if configured with
++ --enable-local-infile
++*/
++#ifdef ENABLED_LOCAL_INFILE
++ mysql->options.client_flag|= CLIENT_LOCAL_FILES;
++#endif
++ mysql->reconnect= 0;
++ return mysql;
++}
++
++
++
++int STDCALL
++mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
+ const char *ca, const char *capath, const char *cipher)
- {
- mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
- mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
- mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
- mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
++{
++ mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
++ mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
++ mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
++ mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
+ mysql->options.ssl_cipher = cipher==0 ? 0 : my_strdup(cipher,MYF(0));
- mysql->options.use_ssl = 1;
- //mysql->connector_fd = new_VioSSLConnectorFd(key, cert, ca, capath);
- return 0;
-@@ -1371,19 +1411,28 @@
- ** before calling mysql_real_connect !
- */
-
--MYSQL * STDCALL
++/* todo: add crl stuff */
++ return 0;
++}
++
++/**************************************************************************
++**************************************************************************/
++
++const char * STDCALL
++mysql_get_ssl_cipher(MYSQL *mysql)
++{
++#ifdef HAVE_OPENSSL
++ if (mysql->net.vio && mysql->net.vio->ssl)
++ {
++ return SSL_get_cipher_name(mysql->net.vio->ssl);
++ }
++#endif
++ return(NULL);
++}
++
++/**************************************************************************
++** Free strings in the SSL structure and clear 'use_ssl' flag.
++** NB! Errors are not reported until you do mysql_real_connect.
++**************************************************************************/
++
++/**************************************************************************
++** Connect to sql server
++** If host == 0 then use localhost
++**************************************************************************/
++
++MYSQL * STDCALL
++mysql_connect(MYSQL *mysql,const char *host,
++ const char *user, const char *passwd)
++{
++ MYSQL *res;
++ mysql=mysql_init(mysql); /* Make it thread safe */
++ {
++ DBUG_ENTER("mysql_connect");
++ if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
++ {
++ if (mysql->free_me)
++ my_free((gptr) mysql,MYF(0));
++ }
++ DBUG_RETURN(res);
++ }
++}
++
++uchar *ma_send_connect_attr(MYSQL *mysql, uchar *buffer)
++{
++ if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
++ {
++ buffer= mysql_net_store_length((unsigned char *)buffer, (mysql->options.extension) ?
++ mysql->options.extension->connect_attrs_len : 0);
++ if (mysql->options.extension &&
++ hash_inited(&mysql->options.extension->connect_attrs))
++ {
++ uint i;
++ for (i=0; i < mysql->options.extension->connect_attrs.records; i++)
++ {
++ size_t len;
++ uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
++
++ len= *(size_t *)p;
++ buffer= mysql_net_store_length(buffer, len);
++ p+= sizeof(size_t);
++ memcpy(buffer, p, len);
++ buffer+= len;
++ p+= len;
++ len= *(size_t *)p;
++ buffer= mysql_net_store_length(buffer, len);
++ p+= sizeof(size_t);
++ memcpy(buffer, p, len);
++ buffer+= len;
++ }
++ }
++ }
++ return buffer;
++}
++
++/** set some default attributes */
++static my_bool
++ma_set_connect_attrs(MYSQL *mysql)
++{
++ char buffer[255];
++ int rc= 0;
++
++ rc= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name") +
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version") +
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os") +
++#ifdef _WIN32
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread") +
++#endif
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid") +
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
++
++ rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "libmariadb")
++ + mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version", MARIADB_PACKAGE_VERSION)
++ + mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", MARIADB_SYSTEM_TYPE);
++
++#ifdef _WIN32
++ snprintf(buffer, 255, "%lu", (ulong) GetCurrentThreadId());
++ rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buffer);
++ snprintf(buffer, 255, "%lu", (ulong) GetCurrentProcessId());
++#else
++ snprintf(buffer, 255, "%lu", (ulong) getpid());
++#endif
++ rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buffer);
++
++ rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform", MARIADB_MACHINE_TYPE);
++ return(test(rc>0));
++}
++
++/*
++** Note that the mysql argument must be initialized with mysql_init()
++** before calling mysql_real_connect !
++*/
++
+MYSQL * STDCALL
- mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
- const char *passwd, const char *db,
- uint port, const char *unix_socket,unsigned long client_flag)
- {
++mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
++ const char *passwd, const char *db,
++ uint port, const char *unix_socket,unsigned long client_flag)
++{
+ if (!mysql->methods)
+ mysql->methods= &MARIADB_DEFAULT_METHODS;
+
@@ -2711,77 +12354,167 @@
+ db, port, unix_socket, client_flag);
+}
+
-+MYSQL *mthd_my_real_connect(MYSQL *mysql,const char *host, const char *user,
++MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
+ const char *passwd, const char *db,
-+ uint port, const char *unix_socket,unsigned long client_flag)
++ uint port, const char *unix_socket, unsigned long client_flag)
+{
- char buff[NAME_LEN+USERNAME_LENGTH+100];
- char *end, *end_pkt, *host_info,
- *charset_name= NULL;
- my_socket sock;
- char *scramble_data;
- const char * scramble_plugin;
-- uint32 ip_addr;
-- struct sockaddr_in sock_addr;
- uint pkt_length, scramble_len, pkt_scramble_len= 0;
- NET *net= &mysql->net;
- #ifdef _WIN32
-@@ -1451,7 +1500,9 @@
- */
-
- #if defined(HAVE_SYS_UN_H)
-- if ((!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
++ char buff[NAME_LEN+USERNAME_LENGTH+100];
++ char *end, *end_pkt, *host_info,
++ *charset_name= NULL;
++ my_socket sock;
++ char *scramble_data;
++ const char *scramble_plugin;
++ uint pkt_length, scramble_len, pkt_scramble_len= 0;
++ NET *net= &mysql->net;
++#ifdef _WIN32
++ HANDLE hPipe=INVALID_HANDLE_VALUE;
++#endif
++#ifdef HAVE_SYS_UN_H
++ struct sockaddr_un UNIXaddr;
++#endif
++ init_sigpipe_variables
++ DBUG_ENTER("mysql_real_connect");
++
++ DBUG_PRINT("enter",("host: %s db: %s user: %s",
++ host ? host : "(Null)",
++ db ? db : "(Null)",
++ user ? user : "(Null)"));
++
++ ma_set_connect_attrs(mysql);
++
++ if (net->vio) /* check if we are already connected */
++ {
++ SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(NULL);
++ }
++
++ /* Don't give sigpipe errors if the client doesn't want them */
++ set_sigpipe(mysql);
++
++ /* use default options */
++ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
++ {
++ mysql_read_default_options(&mysql->options,
++ (mysql->options.my_cnf_file ?
++ mysql->options.my_cnf_file : "my"),
++ mysql->options.my_cnf_group);
++ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
++ }
++
++ /* Some empty-string-tests are done because of ODBC */
++ if (!host || !host[0])
++ host=mysql->options.host;
++ if (!user || !user[0])
++ user=mysql->options.user;
++ if (!passwd)
++ {
++ passwd=mysql->options.password;
++#ifndef DONT_USE_MYSQL_PWD
++ if (!passwd)
++ passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
++#endif
++ }
++ if (!db || !db[0])
++ db=mysql->options.db;
++ if (!port)
++ port=mysql->options.port;
++ if (!unix_socket)
++ unix_socket=mysql->options.unix_socket;
++
++
++ /* Since 5.0.3 reconnect is not enabled by default!!
++ mysql->reconnect=1; */
++ mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
++
++ /*
++ ** Grab a socket and connect it to the server
++ */
++
++#if defined(HAVE_SYS_UN_H)
+ if ((!host || strcmp(host,LOCAL_HOST) == 0) &&
+ mysql->options.protocol != MYSQL_PROTOCOL_TCP &&
+ (unix_socket || mysql_unix_port))
- {
- host=LOCAL_HOST;
- if (!unix_socket)
-@@ -1481,9 +1532,11 @@
- #elif defined(_WIN32)
- {
- if ((unix_socket ||
-- !host && is_NT() ||
-- host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
-- mysql->options.named_pipe || !have_tcpip))
++ {
++ host=LOCAL_HOST;
++ if (!unix_socket)
++ unix_socket=mysql_unix_port;
++ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
++ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
++ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
++ {
++ net->last_errno=CR_SOCKET_CREATE_ERROR;
++ sprintf(net->last_error,ER(net->last_errno),socket_errno);
++ goto error;
++ }
++ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
++ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
++ UNIXaddr.sun_family = AF_UNIX;
++ strmov(UNIXaddr.sun_path, unix_socket);
++ if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
++ mysql->options.connect_timeout) <0)
++ {
++ DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno));
++ my_set_error(mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_CONNECTION_ERROR),
++ unix_socket, socket_errno);
++ goto error;
++ }
++ if (socket_block(sock, 1) == SOCKET_ERROR)
++ goto error;
++ }
++ else
++#elif defined(_WIN32)
++ {
++ if ((unix_socket ||
+ (!host && is_NT()) ||
+ (host && strcmp(host,LOCAL_HOST_NAMEDPIPE) == 0) ||
+ mysql->options.named_pipe ||
+ !have_tcpip) &&
+ mysql->options.protocol != MYSQL_PROTOCOL_TCP)
- {
- sock=0;
- if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
-@@ -1504,65 +1557,80 @@
- }
- else
- {
-- net->vio=vio_new_win32pipe(hPipe);
-- sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
-- unix_socket);
++ {
++ sock=0;
++ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
++ (char**) &host, (char**) &unix_socket)) ==
++ INVALID_HANDLE_VALUE)
++ {
++ DBUG_PRINT("error",
++ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
++ host ? host : "<null>",
++ unix_socket ? unix_socket : "<null>",
++ (int) mysql->options.named_pipe,
++ (int) have_tcpip));
++ if (mysql->options.named_pipe ||
++ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
++ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
++ goto error; /* User only requested named pipes */
++ /* Try also with TCP/IP */
++ }
++ else
++ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
- }
- }
- }
- if (hPipe == INVALID_HANDLE_VALUE)
- #endif
- {
-+ struct addrinfo hints, *save_res, *res= 0;
++ }
++ }
++ }
++ if (hPipe == INVALID_HANDLE_VALUE)
++#endif
++ {
++ struct addrinfo hints, *save_res= 0, *res= 0;
+ char server_port[NI_MAXSERV];
++ int gai_rc;
+ int rc;
+
- unix_socket=0; /* This is not used */
- if (!port)
- port=mysql_port;
- if (!host)
- host=LOCAL_HOST;
- sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
++ unix_socket=0; /* This is not used */
++ if (!port)
++ port=mysql_port;
++ if (!host)
++ host=LOCAL_HOST;
++ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
++ bzero(&server_port, NI_MAXSERV);
+
- DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
-- /* _WIN64 ; Assume that the (int) range is enough for socket() */
-- if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
++ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+
+ my_snprintf(server_port, NI_MAXSERV, "%d", port);
+
@@ -2792,31 +12525,40 @@
+ hints.ai_socktype= SOCK_STREAM;
+
+ /* Get the address information for the server using getaddrinfo() */
-+ if ((rc= getaddrinfo(host, server_port, &hints, &res)))
++ gai_rc= getaddrinfo(host, server_port, &hints, &res);
++ if (gai_rc != 0)
+ {
+ my_set_error(mysql, CR_UNKNOWN_HOST, SQLSTATE_UNKNOWN,
-+ ER(CR_UNKNOWN_HOST), host, rc);
++ ER(CR_UNKNOWN_HOST), host, gai_rc);
+ goto error;
+ }
+
+ /* res is a linked list of addresses. If connect to an address fails we will not return
+ an error, instead we will try the next address */
+ for (save_res= res; save_res; save_res= save_res->ai_next)
-+ {
-+ if ((sock= (my_socket)socket(save_res->ai_family,
-+ save_res->ai_socktype,
-+ save_res->ai_protocol)) == SOCKET_ERROR)
++ {
++ sock= socket(save_res->ai_family, save_res->ai_socktype,
++ save_res->ai_protocol);
++ if (sock == SOCKET_ERROR)
+ /* we do error handling after for loop only for last call */
+ continue;
+ if (!(net->vio= vio_new(sock, VIO_TYPE_TCPIP, FALSE)))
+ {
+ my_set_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ closesocket(sock);
+ freeaddrinfo(res);
+ goto error;
+ }
+ if (!(rc= connect2(sock, save_res->ai_addr, save_res->ai_addrlen,
-+ mysql->options.connect_timeout)))
++ mysql->options.connect_timeout)))
++ {
++ if (socket_block(sock, 1) == SOCKET_ERROR)
++ {
++ closesocket(sock);
++ continue;
++ }
+ break; /* success! */
++ }
+
+ vio_delete(mysql->net.vio);
+ mysql->net.vio= NULL;
@@ -2825,82 +12567,239 @@
+ freeaddrinfo(res);
+
+ if (sock == SOCKET_ERROR)
- {
- my_set_error(mysql, CR_IPSOCK_ERROR, SQLSTATE_UNKNOWN, ER(CR_IPSOCK_ERROR),
- socket_errno);
- goto error;
- }
-- net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
-- bzero((char*) &sock_addr,sizeof(sock_addr));
-- sock_addr.sin_family = AF_INET;
--
-- /*
-- ** The server name may be a host name or IP address
-- */
--
-- if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
-- {
-- memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
-- }
-- else
-- {
-- int tmp_errno;
-- struct hostent tmp_hostent,*hp;
-- char buff2[GETHOSTBYNAME_BUFF_SIZE];
-- hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
-- &tmp_errno);
-- if (!hp)
-- {
-- my_set_error(mysql, CR_UNKNOWN_HOST, SQLSTATE_UNKNOWN, ER(CR_UNKNOWN_HOST),
-- host, tmp_errno);
-- my_gethostbyname_r_free();
-- goto error;
-- }
-- memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
-- my_gethostbyname_r_free();
-- }
-- sock_addr.sin_port = (ushort) htons((ushort) port);
-- if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
-- mysql->options.connect_timeout) <0)
-- {
-- DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,host));
-- my_set_error(mysql, CR_CONN_HOST_ERROR, SQLSTATE_UNKNOWN,
-- ER(CR_CONN_HOST_ERROR), host, socket_errno);
++ {
++ my_set_error(mysql, CR_IPSOCK_ERROR, SQLSTATE_UNKNOWN, ER(CR_IPSOCK_ERROR),
++ socket_errno);
++ goto error;
++ }
+
++ /* last call to connect 2 failed */
+ if (rc)
+ {
-+ my_set_error(mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_CONNECTION_ERROR),
-+ unix_socket, socket_errno);
- goto error;
- }
- }
-@@ -1749,22 +1817,25 @@
-
- if (mysql->options.init_command)
- {
-- MYSQL_RES *res;
-- int status;
++ my_set_error(mysql, CR_CONN_HOST_ERROR, SQLSTATE_UNKNOWN, ER(CR_CONN_HOST_ERROR),
++ host, socket_errno);
++ closesocket(sock);
++ goto error;
++ }
++ }
++
++ if (!net->vio || my_net_init(net, net->vio))
++ {
++ vio_delete(net->vio);
++ net->vio = 0;
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ goto error;
++ }
++ vio_keepalive(net->vio,TRUE);
++ strmov(mysql->net.sqlstate, "00000");
++
++
++ /* set read timeout */
++ if (mysql->options.read_timeout)
++ vio_read_timeout(net->vio, mysql->options.read_timeout);
++
++ /* set write timeout */
++ if (mysql->options.write_timeout)
++ vio_write_timeout(net->vio, mysql->options.read_timeout);
++ /* Get version info */
++ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
++ if (mysql->options.connect_timeout &&
++ vio_poll_read(net->vio, mysql->options.connect_timeout))
++ {
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "handshake: waiting for inital communication packet",
++ errno);
++ goto error;
++ }
++ if ((pkt_length=net_safe_read(mysql)) == packet_error)
++ {
++ if (mysql->net.last_errno == CR_SERVER_LOST)
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "handshake: reading inital communication packet",
++ errno);
++
++ goto error;
++ }
++ end= (char *)net->read_pos;
++ end_pkt= (char *)net->read_pos + pkt_length;
++
++ /* Check if version of protocoll matches current one */
++
++ mysql->protocol_version= end[0];
++ end++;
++
++ /* Check if server sends an error */
++ if (mysql->protocol_version == 0XFF)
++ {
++ net_get_error(end, pkt_length - 1, net->last_error, sizeof(net->last_error),
++ &net->last_errno, net->sqlstate);
++ /* fix for bug #26426 */
++ if (net->last_errno == 1040)
++ memcpy(net->sqlstate, "08004", SQLSTATE_LENGTH);
++ goto error;
++ }
++
++ DBUG_DUMP("packet",net->read_pos,10);
++ DBUG_PRINT("info",("mysql protocol version %d, server=%d",
++ PROTOCOL_VERSION, mysql->protocol_version));
++ if (mysql->protocol_version < PROTOCOL_VERSION)
++ {
++ net->last_errno= CR_VERSION_ERROR;
++ sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
++ PROTOCOL_VERSION);
++ goto error;
++ }
++ /* Save connection information */
++ if (!user) user="";
++ if (!passwd) passwd="";
++
++ if (!my_multi_malloc(MYF(0),
++ &mysql->host_info, (uint) strlen(host_info)+1,
++ &mysql->host, (uint) strlen(host)+1,
++ &mysql->unix_socket,unix_socket ?
++ (uint) strlen(unix_socket)+1 : (uint) 1,
++ &mysql->server_version, (uint) (end - (char*) net->read_pos),
++ NullS) ||
++ !(mysql->user=my_strdup(user,MYF(0))) ||
++ !(mysql->passwd=my_strdup(passwd,MYF(0))))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ goto error;
++ }
++ strmov(mysql->host_info,host_info);
++ strmov(mysql->host,host);
++ if (unix_socket)
++ strmov(mysql->unix_socket,unix_socket);
++ else
++ mysql->unix_socket=0;
++ mysql->port=port;
++ client_flag|=mysql->options.client_flag;
++
++ if (strncmp(end, "5.5.5-", 6) == 0)
++ {
++ if (!(mysql->server_version= my_strdup(end + 6, 0)))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ goto error;
++ }
++ }
++ else
++ {
++ if (!(mysql->server_version= my_strdup(end, MYF(0))))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ goto error;
++ }
++ }
++ end+= strlen(end) + 1;
++
++ mysql->thread_id=uint4korr(end);
++ end+=4;
++
++ /* This is the first part of scramble packet. In 4.1 and later
++ a second package will follow later */
++ scramble_data= end;
++ scramble_len= SCRAMBLE_LENGTH_323 + 1;
++ scramble_plugin= old_password_plugin_name;
++ end+= SCRAMBLE_LENGTH_323;
++
++ /* 1st pad */
++ end++;
++
++ if (end + 1<= end_pkt)
++ {
++ mysql->server_capabilities=uint2korr(end);
++ }
++
++ /* mysql 5.5 protocol */
++ if (end + 18 <= end_pkt)
++ {
++ mysql->server_language= uint1korr(end + 2);
++ mysql->server_status= uint2korr(end + 3);
++ mysql->server_capabilities|= uint2korr(end + 5) << 16;
++ pkt_scramble_len= uint1korr(end + 7);
++ }
++ /* pad 2 */
++ end+= 18;
++
++ /* second scramble package */
++ if (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 <= end_pkt)
++ {
++ memcpy(end - SCRAMBLE_LENGTH_323, scramble_data, SCRAMBLE_LENGTH_323);
++ scramble_data= end - SCRAMBLE_LENGTH_323;
++ if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
++ {
++ scramble_len= pkt_scramble_len;
++ scramble_plugin= scramble_data + scramble_len;
++ if (scramble_data + scramble_len > end_pkt)
++ scramble_len= (uint)(end_pkt - scramble_data);
++ } else
++ {
++ scramble_len= (uint)(end_pkt - scramble_data);
++ scramble_plugin= native_password_plugin_name;
++ }
++ } else
++ mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
++
++ /* Set character set */
++ if (mysql->options.charset_name)
++ mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
++ else if (mysql->server_language)
++ mysql->charset= mysql_find_charset_nr(mysql->server_language);
++ else
++ mysql->charset=default_charset_info;
++
++ if (!mysql->charset)
++ {
++ net->last_errno=CR_CANT_READ_CHARSET;
++ sprintf(net->last_error,ER(net->last_errno),
++ charset_name ? charset_name : "unknown",
++ "compiled_in");
++ goto error;
++ }
++
++ mysql->client_flag= client_flag;
++
++ if (run_plugin_auth(mysql, scramble_data, scramble_len,
++ scramble_plugin, db))
++ goto error;
++
++ if (mysql->client_flag & CLIENT_COMPRESS)
++ net->compress= 1;
++
++ /* last part: select default db */
++ if (db && !mysql->db)
++ {
++ if (mysql_select_db(mysql, db))
++ {
++ my_set_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "Setting intital database",
++ errno);
++ goto error;
++ }
++ }
++
++ DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d",
++ mysql->server_version,mysql->server_capabilities,
++ mysql->server_status, client_flag));
++
++ if (mysql->options.init_command)
++ {
+ char **begin= (char **)mysql->options.init_command->buffer;
+ char **end= begin + mysql->options.init_command->elements;
+
- /* Avoid reconnect in mysql_real_connect */
- my_bool save_reconnect= mysql->reconnect;
--
- mysql->reconnect= 0;
-
-- if (mysql_query(mysql, mysql->options.init_command))
-- goto error;
++ /* Avoid reconnect in mysql_real_connect */
++ my_bool save_reconnect= mysql->reconnect;
++ mysql->reconnect= 0;
++
+ for (;begin < end; begin++)
+ {
-+ if (mysql_real_query(mysql, *begin, strlen(*begin)))
++ if (mysql_real_query(mysql, *begin, (unsigned long)strlen(*begin)))
+ goto error;
-
-- /* handle possible multi results */
-- do {
-- if ((res= mysql_use_result(mysql)))
-- mysql_free_result(res);
-- status= mysql_next_result(mysql);
-- } while (status == 0);
++
+ /* check if query produced a result set */
+ do {
+ MYSQL_RES *res;
@@ -2908,25 +12807,171 @@
+ mysql_free_result(res);
+ } while (!mysql_next_result(mysql));
+ }
- mysql->reconnect= save_reconnect;
- }
-
-@@ -1908,7 +1979,7 @@
- DBUG_ENTER("mysql_select_db");
- DBUG_PRINT("enter",("db: '%s'",db));
-
-- if ((error=simple_command(mysql,MYSQL_COM_INIT_DB,db,(uint) strlen(db),0)))
++ mysql->reconnect= save_reconnect;
++ }
++
++ strmov(mysql->net.sqlstate, "00000");
++
++ DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
++ reset_sigpipe(mysql);
++ DBUG_RETURN(mysql);
++
++error:
++ reset_sigpipe(mysql);
++ DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
++ {
++ /* Free alloced memory */
++ end_server(mysql);
++ /* only free the allocated memory, user needs to call mysql_close */
++ mysql_close_memory(mysql);
++ if (!(((ulong) client_flag) & CLIENT_REMEMBER_OPTIONS))
++ mysql_close_options(mysql);
++ }
++ DBUG_RETURN(0);
++}
++
++
++static my_bool mysql_reconnect(MYSQL *mysql)
++{
++ MYSQL tmp_mysql;
++ LIST *li_stmt= mysql->stmts;
++ DBUG_ENTER("mysql_reconnect");
++
++ if (!mysql->reconnect ||
++ (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
++ {
++ /* Allov reconnect next time */
++ mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
++ my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ mysql_init(&tmp_mysql);
++ tmp_mysql.options=mysql->options;
++ tmp_mysql.reconnect= mysql->reconnect;
++ bzero((char*) &mysql->options,sizeof(mysql->options));
++ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
++ mysql->db, mysql->port, mysql->unix_socket,
++ mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
++ {
++ my_set_error(mysql, tmp_mysql.net.last_errno,
++ tmp_mysql.net.sqlstate,
++ tmp_mysql.net.last_error);
++ DBUG_RETURN(1);
++ }
++ tmp_mysql.free_me=mysql->free_me;
++ mysql->free_me=0;
++ mysql_close(mysql);
++ *mysql=tmp_mysql;
++ net_clear(&mysql->net);
++ mysql->affected_rows= ~(my_ulonglong) 0;
++
++ /* reset the connection in all active statements
++ todo: check stmt->mysql in mysql_stmt* functions ! */
++ for (;li_stmt;li_stmt= li_stmt->next)
++ {
++ MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
++ stmt->mysql= NULL;
++ stmt->state= MYSQL_STMT_INITTED;
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ }
++ DBUG_RETURN(0);
++}
++
++
++/**************************************************************************
++** Change user and database
++**************************************************************************/
++
++my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
++ const char *passwd, const char *db)
++{
++ const CHARSET_INFO *s_cs= mysql->charset;
++ char *s_user= mysql->user,
++ *s_passwd= mysql->passwd,
++ *s_db= mysql->db;
++ int rc;
++
++ DBUG_ENTER("mysql_change_user");
++
++ if (!user)
++ user="";
++ if (!passwd)
++ passwd="";
++ if (!db)
++ db="";
++
++ if (mysql->options.charset_name)
++ mysql->charset =mysql_find_charset_name(mysql->options.charset_name);
++ else if (mysql->server_language)
++ mysql->charset=mysql_find_charset_nr(mysql->server_language);
++ else
++ mysql->charset=default_charset_info;
++
++ mysql->user= (char *)user;
++ mysql->passwd= (char *)passwd;
++ mysql->db= (char *)db;
++ rc= run_plugin_auth(mysql, 0, 0, 0, db);
++
++ if (rc==0)
++ {
++ LIST *li_stmt= mysql->stmts;
++ my_free(s_user,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(s_passwd,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(s_db,MYF(MY_ALLOW_ZERO_PTR));
++
++ if (!(mysql->user= my_strdup(user,MYF(MY_WME))) ||
++ !(mysql->passwd=my_strdup(passwd,MYF(MY_WME))) ||
++ !(mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ rc= 1;
++ }
++
++ for (;li_stmt;li_stmt= li_stmt->next)
++ {
++ MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
++ stmt->mysql= NULL;
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ }/* detach stmts */
++ mysql->stmts= NULL;
++
++ } else
++ {
++ mysql->user= s_user;
++ mysql->passwd= s_passwd;
++ mysql->db= s_db;
++ mysql->charset= s_cs;
++ }
++ DBUG_RETURN(rc);
++}
++
++
++/**************************************************************************
++** Set current database
++**************************************************************************/
++
++int STDCALL
++mysql_select_db(MYSQL *mysql, const char *db)
++{
++ int error;
++ DBUG_ENTER("mysql_select_db");
++ DBUG_PRINT("enter",("db: '%s'",db));
++
+ if ((error=simple_command(mysql,MYSQL_COM_INIT_DB,db,(uint) strlen(db),0,0)))
- DBUG_RETURN(error);
- my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
- mysql->db=my_strdup(db,MYF(MY_WME));
-@@ -1923,9 +1994,16 @@
-
- static void mysql_close_options(MYSQL *mysql)
- {
--/* todo
-- my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
--*/
++ DBUG_RETURN(error);
++ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->db=my_strdup(db,MYF(MY_WME));
++ DBUG_RETURN(0);
++}
++
++
++/*************************************************************************
++** Send a QUIT to the server and close the connection
++** If handle is alloced by mysql connect free it.
++*************************************************************************/
++
++static void mysql_close_options(MYSQL *mysql)
++{
+ if (mysql->options.init_command)
+ {
+ char **begin= (char **)mysql->options.init_command->buffer;
@@ -2937,36 +12982,67 @@
+ delete_dynamic(mysql->options.init_command);
+ my_free((gptr)mysql->options.init_command, MYF(MY_WME));
+ }
- my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
-@@ -1940,7 +2018,14 @@
- my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
- #endif /* HAVE_OPENSSL */
+ if (mysql->options.extension)
+ {
+ my_free(mysql->options.extension->plugin_dir, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.extension->default_auth, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((gptr)mysql->options.extension->db_driver, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.extension->ssl_crl, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->options.extension->ssl_crlpath, MYF(MY_ALLOW_ZERO_PTR));
++ if(hash_inited(&mysql->options.extension->connect_attrs))
++ hash_free(&mysql->options.extension->connect_attrs);
+ }
- }
-
- static void mysql_close_memory(MYSQL *mysql)
-@@ -1951,7 +2036,6 @@
- my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql->server_version,MYF(MY_ALLOW_ZERO_PTR));
- mysql->host_info= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
-- mysql_close_options(mysql);
- }
-
-
-@@ -1976,6 +2060,18 @@
- DBUG_VOID_RETURN;
- }
-
++ my_free((gptr)mysql->options.extension, MYF(MY_ALLOW_ZERO_PTR));
++ /* clear all pointer */
++ memset(&mysql->options, 0, sizeof(mysql->options));
++}
++
++static void mysql_close_memory(MYSQL *mysql)
++{
++ my_free(mysql->host_info, MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
++ my_free(mysql->server_version,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->host_info= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
++}
++
++
++
++void my_set_error(MYSQL *mysql,
++ unsigned int error_nr,
++ const char *sqlstate,
++ const char *format,
++ ...)
++{
++ va_list ap;
++
++ DBUG_ENTER("my_set_error");
++
++ mysql->net.last_errno= error_nr;
++ strncpy(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
++ va_start(ap, format);
++ my_vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE,
++ format ? format : ER(error_nr), ap);
++ DBUG_PRINT("info", ("error(%d) %s", error_nr, mysql->net.last_error));
++ va_end(ap);
++ DBUG_VOID_RETURN;
++}
++
+void mthd_my_close(MYSQL *mysql)
+{
+ if (mysql->net.vio)
@@ -2979,103 +13055,245 @@
+ }
+}
+
- void STDCALL
- mysql_close(MYSQL *mysql)
- {
-@@ -1983,14 +2079,9 @@
- if (mysql) /* Some simple safety */
- {
- LIST *li_stmt= mysql->stmts;
-- if (mysql->net.vio)
-- {
-- free_old_query(mysql);
-- mysql->status=MYSQL_STATUS_READY; /* Force command */
-- mysql->reconnect=0;
-- simple_command(mysql,MYSQL_COM_QUIT,NullS,0,1);
-- end_server(mysql);
-- }
++void STDCALL
++mysql_close(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_close");
++ if (mysql) /* Some simple safety */
++ {
++ LIST *li_stmt= mysql->stmts;
+
+ if (mysql->methods)
+ mysql->methods->db_close(mysql);
-
- /* reset the connection in all active statements
- todo: check stmt->mysql in mysql_stmt* functions ! */
-@@ -2001,6 +2092,7 @@
- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
- }
- mysql_close_memory(mysql);
++
++ /* reset the connection in all active statements
++ todo: check stmt->mysql in mysql_stmt* functions ! */
++ for (;li_stmt;li_stmt= li_stmt->next)
++ {
++ MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
++ stmt->mysql= NULL;
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ }
++ mysql_close_memory(mysql);
+ mysql_close_options(mysql);
- mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
-
- /* Clear pointers for better safety */
-@@ -2033,10 +2125,10 @@
- int STDCALL
- mysql_send_query(MYSQL* mysql, const char* query, uint length)
- {
-- return simple_command(mysql, MYSQL_COM_QUERY, query, length, 1);
++ mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
++
++ /* Clear pointers for better safety */
++ bzero((char*) &mysql->options,sizeof(mysql->options));
++ mysql->net.vio= 0;
++ if (mysql->free_me)
++ my_free((gptr) mysql,MYF(0));
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++/**************************************************************************
++** Do a query. If query returned rows, free old rows.
++** Read data by mysql_store_result or by repeat call of mysql_fetch_row
++**************************************************************************/
++
++int STDCALL
++mysql_query(MYSQL *mysql, const char *query)
++{
++ return mysql_real_query(mysql,query, (uint) strlen(query));
++}
++
++/*
++ Send the query and return so we can do something else.
++ Needs to be followed by mysql_read_query_result() when we want to
++ finish processing it.
++*/
++
++int STDCALL
++mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
++{
+ return simple_command(mysql, MYSQL_COM_QUERY, query, length, 1,0);
- }
-
--int STDCALL mysql_read_query_result(MYSQL *mysql)
++}
++
+int mthd_my_read_query_result(MYSQL *mysql)
- {
- uchar *pos;
- ulong field_count;
-@@ -2073,7 +2165,7 @@
- mysql->server_status|= SERVER_STATUS_IN_TRANS;
-
- mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
-- if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,8)))
++{
++ uchar *pos;
++ ulong field_count;
++ MYSQL_DATA *fields;
++ ulong length;
++ DBUG_ENTER("mthd_my_read_query_result");
++
++ if (!mysql || (length = net_safe_read(mysql)) == packet_error)
++ DBUG_RETURN(1);
++ free_old_query(mysql); /* Free old result */
++get_info:
++ pos=(uchar*) mysql->net.read_pos;
++ if ((field_count= net_field_length(&pos)) == 0)
++ {
++ mysql->affected_rows= net_field_length_ll(&pos);
++ mysql->insert_id= net_field_length_ll(&pos);
++ mysql->server_status=uint2korr(pos);
++ pos+=2;
++ mysql->warning_count=uint2korr(pos);
++ pos+=2;
++ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
++ mysql->info=(char*) pos;
++ DBUG_RETURN(0);
++ }
++ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
++ {
++ int error=mysql_handle_local_infile(mysql, (char *)pos);
++
++ if ((length=net_safe_read(mysql)) == packet_error || error)
++ DBUG_RETURN(-1);
++ goto get_info; /* Get info packet */
++ }
++ if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
++ mysql->server_status|= SERVER_STATUS_IN_TRANS;
++
++ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+ if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
- DBUG_RETURN(-1);
- if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
- (uint) field_count,1,
-@@ -2092,9 +2184,11 @@
- DBUG_PRINT("enter",("handle: %lx",mysql));
- DBUG_PRINT("query",("Query = \"%.255s\" length=%u",query, length));
-
-- if (simple_command(mysql,MYSQL_COM_QUERY,query,length,1))
++ DBUG_RETURN(-1);
++ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
++ (uint) field_count,1,
++ (my_bool) test(mysql->server_capabilities &
++ CLIENT_LONG_FLAG))))
++ DBUG_RETURN(-1);
++ mysql->status=MYSQL_STATUS_GET_RESULT;
++ mysql->field_count=field_count;
++ DBUG_RETURN(0);
++}
++
++my_bool STDCALL
++mysql_read_query_result(MYSQL *mysql)
++{
++ return test(mysql->methods->db_read_query_result(mysql)) ? 1 : 0;
++}
++
++int STDCALL
++mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)
++{
++ DBUG_ENTER("mysql_real_query");
++ DBUG_PRINT("enter",("handle: %lx",mysql));
++ DBUG_PRINT("query",("Query = \"%.255s\" length=%u",query, length));
++
+ free_old_query(mysql);
+
+ if (simple_command(mysql,MYSQL_COM_QUERY,query,length,1,0))
- DBUG_RETURN(-1);
-- DBUG_RETURN(mysql_read_query_result(mysql));
++ DBUG_RETURN(-1);
+ DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
- }
-
- /**************************************************************************
-@@ -2125,7 +2219,7 @@
- }
- result->eof=1; /* Marker for buffered */
- result->lengths=(ulong*) (result+1);
-- if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
++}
++
++/**************************************************************************
++** Alloc result struct for buffered results. All rows are read to buffer.
++** mysql_data_seek may be used.
++**************************************************************************/
++
++MYSQL_RES * STDCALL
++mysql_store_result(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ DBUG_ENTER("mysql_store_result");
++
++ if (!mysql->fields)
++ DBUG_RETURN(0);
++ if (mysql->status != MYSQL_STATUS_GET_RESULT)
++ {
++ SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ mysql->status=MYSQL_STATUS_READY; /* server is ready */
++ if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
++ sizeof(ulong)*mysql->field_count,
++ MYF(MY_WME | MY_ZEROFILL))))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ result->eof=1; /* Marker for buffered */
++ result->lengths=(ulong*) (result+1);
+ if (!(result->data=mysql->methods->db_read_rows(mysql,mysql->fields,mysql->field_count)))
- {
- my_free((gptr) result,MYF(0));
- DBUG_RETURN(0);
-@@ -2205,23 +2299,22 @@
- mysql_fetch_row(MYSQL_RES *res)
- {
- DBUG_ENTER("mysql_fetch_row");
++ {
++ my_free((gptr) result,MYF(0));
++ DBUG_RETURN(0);
++ }
++ mysql->affected_rows= result->row_count= result->data->rows;
++ result->data_cursor= result->data->data;
++ result->fields= mysql->fields;
++ result->field_alloc= mysql->field_alloc;
++ result->field_count= mysql->field_count;
++ result->current_field=0;
++ result->current_row=0; /* Must do a fetch first */
++ mysql->fields=0; /* fields is now in result */
++ DBUG_RETURN(result); /* Data fetched */
++}
++
++
++/**************************************************************************
++** Alloc struct for use with unbuffered reads. Data is fetched by domand
++** when calling to mysql_fetch_row.
++** mysql_data_seek is a noop.
++**
++** No other queries may be specified with the same MYSQL handle.
++** There shouldn't be much processing per row because mysql server shouldn't
++** have to wait for the client (and will not wait more than 30 sec/packet).
++**************************************************************************/
++
++MYSQL_RES * STDCALL
++mysql_use_result(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ DBUG_ENTER("mysql_use_result");
++
++ if (!mysql->fields)
++ DBUG_RETURN(0);
++ if (mysql->status != MYSQL_STATUS_GET_RESULT)
++ {
++ SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
++ DBUG_RETURN(0);
++ }
++ if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
++ sizeof(ulong)*mysql->field_count,
++ MYF(MY_WME | MY_ZEROFILL))))
++ DBUG_RETURN(0);
++ result->lengths=(ulong*) (result+1);
++ if (!(result->row=(MYSQL_ROW)
++ my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
++ { /* Ptrs: to one row */
++ my_free((gptr) result,MYF(0));
++ DBUG_RETURN(0);
++ }
++ result->fields= mysql->fields;
++ result->field_alloc= mysql->field_alloc;
++ result->field_count= mysql->field_count;
++ result->current_field=0;
++ result->handle= mysql;
++ result->current_row= 0;
++ mysql->fields=0; /* fields is now in result */
++ mysql->status=MYSQL_STATUS_USE_RESULT;
++ DBUG_RETURN(result); /* Data is read to be fetched */
++}
++
++/**************************************************************************
++** Return next field of the query results
++**************************************************************************/
++MYSQL_FIELD * STDCALL
++mysql_fetch_field(MYSQL_RES *result)
++{
++ if (result->current_field >= result->field_count)
++ return(NULL);
++ return &result->fields[result->current_field++];
++}
++
++/**************************************************************************
++** Return next row of the query results
++**************************************************************************/
++MYSQL_ROW STDCALL
++mysql_fetch_row(MYSQL_RES *res)
++{
++ DBUG_ENTER("mysql_fetch_row");
+ if (!res)
+ return 0;
- if (!res->data)
- { /* Unbufferred fetch */
- if (!res->eof)
- {
-- if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
-- {
-- res->row_count++;
-- DBUG_RETURN(res->current_row=res->row);
-- }
-- else
-- {
-- DBUG_PRINT("info",("end of data"));
-- res->eof=1;
-- res->handle->status=MYSQL_STATUS_READY;
-- /* Don't clear handle in mysql_free_results */
-- res->handle=0;
-- }
++ if (!res->data)
++ { /* Unbufferred fetch */
++ if (!res->eof)
++ {
+ if (!(res->handle->methods->db_read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+ {
+ res->row_count++;
@@ -3086,149 +13304,410 @@
+ res->handle->status=MYSQL_STATUS_READY;
+ /* Don't clear handle in mysql_free_results */
+ res->handle=0;
- }
- DBUG_RETURN((MYSQL_ROW) NULL);
- }
-@@ -2367,8 +2460,8 @@
- LINT_INIT(query);
-
- end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
-- if (simple_command(mysql,MYSQL_COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
-- !(query = read_rows(mysql,(MYSQL_FIELD*) 0,8)))
++ }
++ DBUG_RETURN((MYSQL_ROW) NULL);
++ }
++ {
++ MYSQL_ROW tmp;
++ if (!res->data_cursor)
++ {
++ DBUG_PRINT("info",("end of data"));
++ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
++ }
++ tmp = res->data_cursor->data;
++ res->data_cursor = res->data_cursor->next;
++ DBUG_RETURN(res->current_row=tmp);
++ }
++}
++
++/**************************************************************************
++** 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)
++{
++ ulong *lengths,*prev_length;
++ char *start;
++ MYSQL_ROW column,end;
++
++ if (!(column=res->current_row))
++ return 0; /* Something is wrong */
++ if (res->data)
++ {
++ start=0;
++ prev_length=0; /* Keep gcc happy */
++ lengths=res->lengths;
++ for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
++ {
++ if (!*column)
++ {
++ *lengths=0; /* Null */
++ continue;
++ }
++ if (start) /* Found end of prev string */
++ *prev_length= (uint) (*column-start-1);
++ start= *column;
++ prev_length=lengths;
++ }
++ }
++ return res->lengths;
++}
++
++/**************************************************************************
++** Move to a specific row and column
++**************************************************************************/
++
++void STDCALL
++mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
++{
++ MYSQL_ROWS *tmp=0;
++ DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
++ if (result->data)
++ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
++ result->current_row=0;
++ result->data_cursor = tmp;
++}
++
++/*************************************************************************
++** put the row or field cursor one a position one got from mysql_row_tell()
++** This doesn't restore any data. The next mysql_fetch_row or
++** mysql_fetch_field will return the next row or field after the last used
++*************************************************************************/
++
++MYSQL_ROW_OFFSET STDCALL
++mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
++{
++ MYSQL_ROW_OFFSET return_value=result->data_cursor;
++ result->current_row= 0;
++ result->data_cursor= row;
++ return return_value;
++}
++
++
++MYSQL_FIELD_OFFSET STDCALL
++mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
++{
++ MYSQL_FIELD_OFFSET return_value=result->current_field;
++ result->current_field=field_offset;
++ return return_value;
++}
++
++/*****************************************************************************
++** List all databases
++*****************************************************************************/
++
++MYSQL_RES * STDCALL
++mysql_list_dbs(MYSQL *mysql, const char *wild)
++{
++ char buff[255];
++ DBUG_ENTER("mysql_list_dbs");
++
++ append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
++ if (mysql_query(mysql,buff))
++ DBUG_RETURN(0);
++ DBUG_RETURN (mysql_store_result(mysql));
++}
++
++
++/*****************************************************************************
++** List all tables in a database
++** If wild is given then only the tables matching wild is returned
++*****************************************************************************/
++
++MYSQL_RES * STDCALL
++mysql_list_tables(MYSQL *mysql, const char *wild)
++{
++ char buff[255];
++ DBUG_ENTER("mysql_list_tables");
++
++ append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
++ if (mysql_query(mysql,buff))
++ DBUG_RETURN(0);
++ DBUG_RETURN (mysql_store_result(mysql));
++}
++
++
++/**************************************************************************
++** List all fields in a table
++** If wild is given then only the fields matching wild is returned
++** Instead of this use query:
++** show fields in 'table' like "wild"
++**************************************************************************/
++
++MYSQL_RES * STDCALL
++mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
++{
++ MYSQL_RES *result;
++ MYSQL_DATA *query;
++ char buff[257],*end;
++ DBUG_ENTER("mysql_list_fields");
++ DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : ""));
++
++ LINT_INIT(query);
++
++ end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+ if (simple_command(mysql,MYSQL_COM_FIELD_LIST,buff,(uint) (end-buff),1,0) ||
+ !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
- DBUG_RETURN(NULL);
-
- free_old_query(mysql);
-@@ -2400,12 +2493,12 @@
- DBUG_ENTER("mysql_list_processes");
-
- LINT_INIT(fields);
-- if (simple_command(mysql,MYSQL_COM_PROCESS_INFO,0,0,0))
++ DBUG_RETURN(NULL);
++
++ free_old_query(mysql);
++ if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
++ MYF(MY_WME | MY_ZEROFILL))))
++ {
++ free_rows(query);
++ DBUG_RETURN(NULL);
++ }
++ result->field_alloc=mysql->field_alloc;
++ mysql->fields=0;
++ result->field_count = (uint) query->rows;
++ result->fields= unpack_fields(query,&result->field_alloc,
++ result->field_count,1,
++ (my_bool) test(mysql->server_capabilities &
++ CLIENT_LONG_FLAG));
++ result->eof=1;
++ DBUG_RETURN(result);
++}
++
++/* List all running processes (threads) in server */
++
++MYSQL_RES * STDCALL
++mysql_list_processes(MYSQL *mysql)
++{
++ MYSQL_DATA *fields;
++ uint field_count;
++ uchar *pos;
++ DBUG_ENTER("mysql_list_processes");
++
++ LINT_INIT(fields);
+ if (simple_command(mysql,MYSQL_COM_PROCESS_INFO,0,0,0,0))
- DBUG_RETURN(0);
- free_old_query(mysql);
- pos=(uchar*) mysql->net.read_pos;
- field_count=(uint) net_field_length(&pos);
-- if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
++ DBUG_RETURN(0);
++ free_old_query(mysql);
++ pos=(uchar*) mysql->net.read_pos;
++ field_count=(uint) net_field_length(&pos);
+ if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
- DBUG_RETURN(NULL);
- if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
- (my_bool) test(mysql->server_capabilities &
-@@ -2422,7 +2515,7 @@
- {
- DBUG_ENTER("mysql_createdb");
- DBUG_PRINT("enter",("db: %s",db));
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_CREATE_DB,db, (uint) strlen(db),0));
++ DBUG_RETURN(NULL);
++ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
++ (my_bool) test(mysql->server_capabilities &
++ CLIENT_LONG_FLAG))))
++ DBUG_RETURN(0);
++ mysql->status=MYSQL_STATUS_GET_RESULT;
++ mysql->field_count=field_count;
++ DBUG_RETURN(mysql_store_result(mysql));
++}
++
++
++int STDCALL
++mysql_create_db(MYSQL *mysql, const char *db)
++{
++ DBUG_ENTER("mysql_createdb");
++ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,MYSQL_COM_CREATE_DB,db, (uint) strlen(db),0,0));
- }
-
-
-@@ -2431,25 +2524,26 @@
- {
- DBUG_ENTER("mysql_drop_db");
- DBUG_PRINT("enter",("db: %s",db));
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_DROP_DB,db,(uint) strlen(db),0));
++}
++
++
++int STDCALL
++mysql_drop_db(MYSQL *mysql, const char *db)
++{
++ DBUG_ENTER("mysql_drop_db");
++ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,MYSQL_COM_DROP_DB,db,(uint) strlen(db),0,0));
- }
-
--
++}
++
+/* In 5.0 this version became an additional parameter shutdown_level */
- int STDCALL
--mysql_shutdown(MYSQL *mysql)
++int STDCALL
+mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
- {
++{
+ uchar s_level[2];
- DBUG_ENTER("mysql_shutdown");
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_SHUTDOWN,0,0,0));
++ DBUG_ENTER("mysql_shutdown");
+ s_level[0]= (uchar)shutdown_level;
+ DBUG_RETURN(simple_command(mysql, MYSQL_COM_SHUTDOWN, (char *)s_level, 1, 0, 0));
- }
-
--
- int STDCALL
- mysql_refresh(MYSQL *mysql,uint options)
- {
- uchar bits[1];
- DBUG_ENTER("mysql_refresh");
- bits[0]= (uchar) options;
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_REFRESH,(char*) bits,1,0));
++}
++
++int STDCALL
++mysql_refresh(MYSQL *mysql,uint options)
++{
++ uchar bits[1];
++ DBUG_ENTER("mysql_refresh");
++ bits[0]= (uchar) options;
+ DBUG_RETURN(simple_command(mysql,MYSQL_COM_REFRESH,(char*) bits,1,0,0));
- }
-
- int STDCALL
-@@ -2459,7 +2553,7 @@
- DBUG_ENTER("mysql_kill");
- int4store(buff,pid);
- /* if we kill our own thread, reading the response packet will fail */
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_PROCESS_KILL,buff,4,0));
++}
++
++int STDCALL
++mysql_kill(MYSQL *mysql,ulong pid)
++{
++ char buff[12];
++ DBUG_ENTER("mysql_kill");
++ int4store(buff,pid);
++ /* if we kill our own thread, reading the response packet will fail */
+ DBUG_RETURN(simple_command(mysql,MYSQL_COM_PROCESS_KILL,buff,4,0,0));
- }
-
-
-@@ -2467,14 +2561,14 @@
- mysql_dump_debug_info(MYSQL *mysql)
- {
- DBUG_ENTER("mysql_dump_debug_info");
-- DBUG_RETURN(simple_command(mysql,MYSQL_COM_DEBUG,0,0,0));
++}
++
++
++int STDCALL
++mysql_dump_debug_info(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_dump_debug_info");
+ DBUG_RETURN(simple_command(mysql,MYSQL_COM_DEBUG,0,0,0,0));
- }
-
- char * STDCALL
- mysql_stat(MYSQL *mysql)
- {
- DBUG_ENTER("mysql_stat");
-- if (simple_command(mysql,MYSQL_COM_STATISTICS,0,0,0))
++}
++
++char * STDCALL
++mysql_stat(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,MYSQL_COM_STATISTICS,0,0,0,0))
- return mysql->net.last_error;
- mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
- if (!mysql->net.read_pos[0])
-@@ -2491,11 +2585,11 @@
- {
- int rc;
- DBUG_ENTER("mysql_ping");
-- rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
++ return mysql->net.last_error;
++ mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
++ if (!mysql->net.read_pos[0])
++ {
++ SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , unknown_sqlstate, 0);
++ return mysql->net.last_error;
++ }
++ DBUG_RETURN((char*) mysql->net.read_pos);
++}
++
++
++int STDCALL
++mysql_ping(MYSQL *mysql)
++{
++ int rc;
++ DBUG_ENTER("mysql_ping");
+ rc= simple_command(mysql,MYSQL_COM_PING,0,0,0,0);
-
- /* if connection was terminated and reconnect is true, try again */
- if (rc!=0 && mysql->reconnect)
-- rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
++
++ /* if connection was terminated and reconnect is true, try again */
++ if (rc!=0 && mysql->reconnect)
+ rc= simple_command(mysql,MYSQL_COM_PING,0,0,0,0);
- return rc;
- }
-
-@@ -2547,7 +2641,7 @@
-
-
- int STDCALL
--mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
++ return rc;
++}
++
++
++char * STDCALL
++mysql_get_server_info(MYSQL *mysql)
++{
++ return((char*) mysql->server_version);
++}
++
++unsigned long STDCALL mysql_get_server_version(MYSQL *mysql)
++{
++ long major, minor, patch;
++ char *p;
++
++ if (!(p = mysql->server_version)) {
++ return 0;
++ }
++
++ major = strtol(p, &p, 10);
++ p += 1; /* consume the dot */
++ minor = strtol(p, &p, 10);
++ p += 1; /* consume the dot */
++ patch = strtol(p, &p, 10);
++
++ return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch));
++}
++
++
++
++char * STDCALL
++mysql_get_host_info(MYSQL *mysql)
++{
++ return(mysql->host_info);
++}
++
++
++uint STDCALL
++mysql_get_proto_info(MYSQL *mysql)
++{
++ return (mysql->protocol_version);
++}
++
++const char * STDCALL
++mysql_get_client_info(void)
++{
++ return (char*) MYSQL_CLIENT_VERSION;
++}
++
++static size_t get_store_length(size_t length)
++{
++ if (length < (size_t) L64(251))
++ return 1;
++ if (length < (size_t) L64(65536))
++ return 2;
++ if (length < (size_t) L64(16777216))
++ return 3;
++ return 9;
++}
++
++int STDCALL
+mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
- {
- DBUG_ENTER("mysql_option");
- DBUG_PRINT("enter",("option: %d",(int) option));
-@@ -2569,8 +2663,7 @@
- mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
- break;
- case MYSQL_INIT_COMMAND:
-- my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
-- mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
-+ options_add_initcommand(&mysql->options, arg);
- break;
- case MYSQL_READ_DEFAULT_FILE:
- my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
-@@ -2609,14 +2702,43 @@
- case MYSQL_REPORT_DATA_TRUNCATION:
- mysql->options.report_data_truncation= *(uint *)arg;
- break;
-- case MYSQL_OPT_PROGRESS_CALLBACK:
++{
++ DBUG_ENTER("mysql_option");
++ DBUG_PRINT("enter",("option: %d",(int) option));
++ switch (option) {
++ case MYSQL_OPT_CONNECT_TIMEOUT:
++ mysql->options.connect_timeout= *(uint*) arg;
++ break;
++ case MYSQL_OPT_COMPRESS:
++ mysql->options.compress= 1; /* Remember for connect */
++ mysql->options.client_flag|= CLIENT_COMPRESS;
++ break;
++ case MYSQL_OPT_NAMED_PIPE:
++ mysql->options.named_pipe=1; /* Force named pipe */
++ break;
++ case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
++ if (!arg || test(*(uint*) arg))
++ mysql->options.client_flag|= CLIENT_LOCAL_FILES;
++ else
++ mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
++ break;
++ case MYSQL_INIT_COMMAND:
++ options_add_initcommand(&mysql->options, (char *)arg);
++ break;
++ case MYSQL_READ_DEFAULT_FILE:
++ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.my_cnf_file=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_READ_DEFAULT_GROUP:
++ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.my_cnf_group=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_SET_CHARSET_DIR:
++ /* not supported in this version. Since all character sets
++ are internally available, we don't throw an error */
++ break;
++ case MYSQL_SET_CHARSET_NAME:
++ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.charset_name=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_RECONNECT:
++ mysql->reconnect= *(uint *)arg;
++ break;
++ case MYSQL_OPT_PROTOCOL:
++#ifdef _WIN32
++ if (*(uint *)arg > MYSQL_PROTOCOL_PIPE)
++#else
++ if (*(uint *)arg > MYSQL_PROTOCOL_SOCKET)
++#endif
++ DBUG_RETURN(-1);
++ mysql->options.protocol= *(uint *)arg;
++ break;
++ case MYSQL_OPT_READ_TIMEOUT:
++ mysql->options.read_timeout= *(uint *)arg;
++ break;
++ case MYSQL_OPT_WRITE_TIMEOUT:
++ mysql->options.write_timeout= *(uint *)arg;
++ break;
++ case MYSQL_REPORT_DATA_TRUNCATION:
++ mysql->options.report_data_truncation= *(uint *)arg;
++ break;
+ case MYSQL_PROGRESS_CALLBACK:
- if (!mysql->options.extension)
- mysql->options.extension= (struct st_mysql_options_extention *)
- my_malloc(sizeof(struct st_mysql_options_extention),
- MYF(MY_WME | MY_ZEROFILL));
- if (mysql->options.extension)
- mysql->options.extension->report_progress=
-- (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
++ if (!mysql->options.extension)
++ mysql->options.extension= (struct st_mysql_options_extention *)
++ my_malloc(sizeof(struct st_mysql_options_extention),
++ MYF(MY_WME | MY_ZEROFILL));
++ if (mysql->options.extension)
++ mysql->options.extension->report_progress=
+ (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
+ break;
+ case MYSQL_PLUGIN_DIR:
@@ -3259,60 +13738,519 @@
+ mysql->methods= db_plugin->methods;
+ }
+ }
- break;
- default:
- DBUG_RETURN(-1);
-@@ -2740,7 +2862,7 @@
-
- if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
- {
-- DBUG_RETURN(mysql_read_query_result(mysql));
++ break;
++ case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
++ if (*(uint *)arg)
++ mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT;
++ else
++ mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT;
++ break;
++ case MYSQL_OPT_SSL_KEY:
++ my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.ssl_key=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_SSL_CERT:
++ my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.ssl_cert=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_SSL_CA:
++ my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.ssl_ca=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_SSL_CAPATH:
++ my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.ssl_capath=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_SSL_CIPHER:
++ my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
++ mysql->options.ssl_cipher=my_strdup((char *)arg,MYF(MY_WME));
++ break;
++ case MYSQL_OPT_SSL_CRL:
++ OPT_SET_EXTENDED_VALUE(&mysql->options, ssl_crl, (char *)arg, 1);
++ break;
++ case MYSQL_OPT_SSL_CRLPATH:
++ OPT_SET_EXTENDED_VALUE(&mysql->options, ssl_crlpath, (char *)arg, 1);
++ break;
++ case MYSQL_OPT_CONNECT_ATTR_DELETE:
++ {
++ uchar *p;
++ CHECK_OPT_EXTENSION_SET(&mysql->options);
++ if (hash_inited(&mysql->options.extension->connect_attrs) &&
++ (p= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg,
++ arg ? (uint)strlen((char *)arg) : 0)))
++ {
++ size_t key_len= *(size_t *)p;
++ mysql->options.extension->connect_attrs_len-= key_len;
++ mysql->options.extension->connect_attrs_len-= get_store_length(key_len);
++ key_len= *(size_t *)(p + sizeof(size_t) + key_len);
++ mysql->options.extension->connect_attrs_len-= key_len;
++ mysql->options.extension->connect_attrs_len-= get_store_length(key_len);
++ hash_delete(&mysql->options.extension->connect_attrs, p);
++ }
++
++ }
++ break;
++ case MYSQL_OPT_CONNECT_ATTR_RESET:
++ CHECK_OPT_EXTENSION_SET(&mysql->options);
++ if (hash_inited(&mysql->options.extension->connect_attrs))
++ {
++ hash_free(&mysql->options.extension->connect_attrs);
++ mysql->options.extension->connect_attrs_len= 0;
++ }
++ break;
++ default:
++ DBUG_RETURN(-1);
++ }
++ DBUG_RETURN(0);
++}
++
++uchar *ma_get_hash_key(const uchar *hash_entry,
++ unsigned int *length,
++ my_bool not_used __attribute__((unused)))
++{
++ /* Hash entry has the following format:
++ Offset: 0 key length
++ sizeof(size_t) key
++ key_length +
++ sizeof(size_t) value length
++ value
++ */
++ uchar *p= (uchar *)hash_entry;
++ size_t len=*((size_t*)p);
++ p+= sizeof(size_t);
++ *length= (uint)len;
++ return p;
++}
++
++void ma_hash_free(void *p)
++{
++ my_free((gptr)p, MYF(MYF_ALLOW_ZERO_PTR));
++}
++
++int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
++ const void *arg1, const void *arg2)
++{
++ DBUG_ENTER("mysql_option4");
++ DBUG_PRINT("enter",("option: %d",(int) option));
++
++ switch (option) {
++ case MYSQL_OPT_CONNECT_ATTR_ADD:
++ {
++ uchar *buffer;
++ size_t key_len= arg1 ? strlen((char *)arg1) : 0,
++ value_len= arg2 ? strlen((char *)arg2) : 0;
++ size_t storage_len= key_len + value_len +
++ get_store_length(key_len) +
++ get_store_length(value_len);
++
++ CHECK_OPT_EXTENSION_SET(&mysql->options);
++ if (!key_len ||
++ storage_len + mysql->options.extension->connect_attrs_len > 0xFFFF)
++ {
++ SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (!hash_inited(&mysql->options.extension->connect_attrs))
++ {
++ if (_hash_init(&mysql->options.extension->connect_attrs,
++ 0, 0, 0, ma_get_hash_key, ma_hash_free, 0))
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ DBUG_RETURN(1);
++ }
++ }
++ if ((buffer= (uchar *)my_malloc(2 * sizeof(size_t) + key_len + value_len,
++ MYF(MY_WME | MY_ZEROFILL))))
++ {
++ uchar *p= buffer;
++ *((size_t *)p)= key_len;
++ p+= sizeof(size_t);
++ memcpy(p, arg1, key_len);
++ p+= key_len;
++ *((size_t *)p)= value_len;
++ p+= sizeof(size_t);
++ if (arg2)
++ memcpy(p, arg2, value_len);
++
++ if (hash_insert(&mysql->options.extension->connect_attrs, buffer))
++ {
++ my_free((gptr)buffer, MYF(0));
++ SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0);
++ DBUG_RETURN(1);
++ }
++ mysql->options.extension->connect_attrs_len+= storage_len;
++ }
++ else
++ {
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
++ DBUG_RETURN(1);
++ }
++ }
++ break;
++ default:
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++/****************************************************************************
++** Functions to get information from the MySQL structure
++** These are functions to make shared libraries more usable.
++****************************************************************************/
++
++/* MYSQL_RES */
++my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
++{
++ return res->row_count;
++}
++
++unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
++{
++ return res->field_count;
++}
++
++/* deprecated */
++my_bool STDCALL mysql_eof(MYSQL_RES *res)
++{
++ return res->eof;
++}
++
++MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
++{
++ return &(res)->fields[fieldnr];
++}
++
++MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
++{
++ return (res)->fields;
++}
++
++MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
++{
++ return res->data_cursor;
++}
++
++uint STDCALL mysql_field_tell(MYSQL_RES *res)
++{
++ return (res)->current_field;
++}
++
++/* MYSQL */
++
++unsigned int STDCALL mysql_field_count(MYSQL *mysql)
++{
++ return mysql->field_count;
++}
++
++my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
++{
++ return (mysql)->affected_rows;
++}
++
++my_bool STDCALL mysql_autocommit(MYSQL *mysql, my_bool mode)
++{
++ DBUG_ENTER("mysql_autocommit");
++ DBUG_RETURN((my_bool) mysql_real_query(mysql, (mode) ? "SET autocommit=1" :
++ "SET autocommit=0", 16));
++}
++
++my_bool STDCALL mysql_commit(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_commit");
++ DBUG_RETURN((my_bool)mysql_real_query(mysql, "COMMIT", sizeof("COMMIT")));
++}
++
++my_bool STDCALL mysql_rollback(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_rollback");
++ DBUG_RETURN((my_bool)mysql_real_query(mysql, "ROLLBACK", sizeof("ROLLBACK")));
++}
++
++my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
++{
++ return (mysql)->insert_id;
++}
++
++uint STDCALL mysql_errno(MYSQL *mysql)
++{
++ return (mysql)->net.last_errno;
++}
++
++char * STDCALL mysql_error(MYSQL *mysql)
++{
++ return (mysql)->net.last_error;
++}
++
++char *STDCALL mysql_info(MYSQL *mysql)
++{
++ return (mysql)->info;
++}
++
++my_bool STDCALL mysql_more_results(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_more_results");
++ DBUG_RETURN(test(mysql->server_status & SERVER_MORE_RESULTS_EXIST));
++}
++
++int STDCALL mysql_next_result(MYSQL *mysql)
++{
++ DBUG_ENTER("mysql_next_result");
++
++ /* make sure communication is not blocking */
++ if (mysql->status != MYSQL_STATUS_READY)
++ {
++ SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
++ DBUG_RETURN(1);
++ }
++
++ /* clear error, and mysql status variables */
++ CLEAR_CLIENT_ERROR(mysql);
++ mysql->affected_rows = (ulonglong) ~0;
++
++ if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
++ {
+ DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
- }
-
- DBUG_RETURN(-1);
-@@ -2891,7 +3013,7 @@
- struct servent *serv_ptr;
- char *env;
-
-- mysql_port = MYSQL_PORT;
++ }
++
++ DBUG_RETURN(-1);
++}
++
++ulong STDCALL mysql_thread_id(MYSQL *mysql)
++{
++ return (mysql)->thread_id;
++}
++
++const char * STDCALL mysql_character_set_name(MYSQL *mysql)
++{
++ return mysql->charset->csname;
++}
++
++
++uint STDCALL mysql_thread_safe(void)
++{
++#ifdef THREAD
++ return 1;
++#else
++ return 0;
++#endif
++}
++
++/****************************************************************************
++** Some support functions
++****************************************************************************/
++
++/*
++** Add escape characters to a string (blob?) to make it suitable for a insert
++** to should at least have place for length*2+1 chars
++** Returns the length of the to string
++*/
++
++ulong STDCALL
++mysql_escape_string(char *to,const char *from, ulong length)
++{
++ return (ulong)mysql_cset_escape_slashes(default_charset_info, to, from, length);
++}
++
++ulong STDCALL
++mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
++ ulong length)
++{
++ if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
++ return (ulong)mysql_cset_escape_quotes(mysql->charset, to, from, length);
++ else
++ return (ulong)mysql_cset_escape_slashes(mysql->charset, to, from, length);
++}
++
++void STDCALL
++myodbc_remove_escape(MYSQL *mysql,char *name)
++{
++ char *to;
++ my_bool use_mb_flag= (mysql->charset->char_maxlen > 1);
++ char *end= 0;
++ if (use_mb_flag)
++ for (end=name; *end ; end++) ;
++
++ for (to=name ; *name ; name++)
++ {
++ int l;
++ if (use_mb_flag && (l = mysql->charset->mb_valid(name , end)))
++ {
++ while (l--)
++ *to++ = *name++;
++ name--;
++ continue;
++ }
++ if (*name == '\\' && name[1])
++ name++;
++ *to++= *name;
++ }
++ *to=0;
++}
++
++void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
++{
++ DBUG_ENTER("mysql_get_character_set_info");
++
++ if (!cs)
++ DBUG_VOID_RETURN;
++
++ cs->number= mysql->charset->nr;
++ cs->csname= mysql->charset->csname;
++ cs->name= mysql->charset->name;
++ cs->state= 0;
++ cs->comment= NULL;
++ cs->dir= NULL;
++ cs->mbminlen= mysql->charset->char_minlen;
++ cs->mbmaxlen= mysql->charset->char_maxlen;
++
++ DBUG_VOID_RETURN;
++}
++
++int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname)
++{
++ const CHARSET_INFO *cs;
++ DBUG_ENTER("mysql_set_character_set");
++
++ if (!csname)
++ goto error;
++
++ if ((cs= mysql_find_charset_name(csname)))
++ {
++ char buff[64];
++
++ my_snprintf(buff, 63, "SET NAMES %s", cs->csname);
++ if (!mysql_real_query(mysql, buff, (uint)strlen(buff)))
++ {
++ mysql->charset= cs;
++ DBUG_RETURN(0);
++ }
++ }
++
++error:
++ my_set_error(mysql, CR_CANT_READ_CHARSET, SQLSTATE_UNKNOWN,
++ 0, csname, "compiled_in");
++ DBUG_RETURN(mysql->net.last_errno);
++}
++
++unsigned int STDCALL mysql_warning_count(MYSQL *mysql)
++{
++ return mysql->warning_count;
++}
++
++const char * STDCALL mysql_sqlstate(MYSQL *mysql)
++{
++ return mysql->net.sqlstate;
++}
++
++int STDCALL mysql_server_init(int argc __attribute__((unused)),
++ char **argv __attribute__((unused)),
++ char **groups __attribute__((unused)))
++{
++ int rc= 0;
++
++ if (!mysql_client_init)
++ {
++ mysql_client_init=1;
++ my_init(); /* Will init threads */
++ init_client_errs();
++ if (mysql_client_plugin_init())
++ return 1;
++ if (!mysql_port)
++ {
++ struct servent *serv_ptr;
++ char *env;
++
+ mysql_port = MYSQL_PORT;
- if ((serv_ptr = getservbyname("mysql", "tcp")))
- mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
- if ((env = getenv("MYSQL_TCP_PORT")))
-@@ -2906,7 +3028,7 @@
- mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
- #endif
- if ((env = getenv("MYSQL_UNIX_PORT")))
-- mysql_unix_port = env;
++ if ((serv_ptr = getservbyname("mysql", "tcp")))
++ mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
++ if ((env = getenv("MYSQL_TCP_PORT")))
++ mysql_port =(uint) atoi(env);
++ }
++ if (!mysql_unix_port)
++ {
++ char *env;
++#ifdef _WIN32
++ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
++#else
++ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
++#endif
++ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env;
- }
- mysql_debug(NullS);
- #if defined(SIGPIPE) && !defined(THREAD) && !defined(_WIN32)
-@@ -2934,10 +3056,6 @@
-
- if (my_init_done)
- my_end(0);
--#ifdef THREAD
-- else
-- mysql_thread_end();
--#endif
- mysql_client_init= 0;
- my_init_done= 0;
- }
-@@ -2963,7 +3081,7 @@
- char buffer[2];
- DBUG_ENTER("mysql_set_server_option");
- int2store(buffer, (uint)option);
-- DBUG_RETURN(simple_command(mysql, MYSQL_COM_SET_OPTION, buffer, sizeof(buffer), 0));
++ }
++ mysql_debug(NullS);
++#if defined(SIGPIPE) && !defined(THREAD) && !defined(_WIN32)
++ (void) signal(SIGPIPE,SIG_IGN);
++#endif
++ }
++#ifdef THREAD
++ else
++ rc= mysql_thread_init();
++#endif
++ if (!mysql_ps_subsystem_initialized)
++ mysql_init_ps_subsystem();
++ return(rc);
++}
++
++void STDCALL mysql_server_end()
++{
++ if (!mysql_client_init)
++ return;
++#ifdef HAVE_OPENSSL
++ my_ssl_end();
++#endif
++
++ mysql_client_plugin_deinit();
++
++ if (my_init_done)
++ my_end(0);
++ mysql_client_init= 0;
++ my_init_done= 0;
++}
++
++my_bool STDCALL mysql_thread_init()
++{
++#ifdef THREAD
++ return my_thread_init();
++#endif
++ return 0;
++}
++
++void STDCALL mysql_thread_end()
++{
++ #ifdef THREAD
++ my_thread_end();
++ #endif
++}
++
++int STDCALL mysql_set_server_option(MYSQL *mysql,
++ enum enum_mysql_set_option option)
++{
++ char buffer[2];
++ DBUG_ENTER("mysql_set_server_option");
++ int2store(buffer, (uint)option);
+ DBUG_RETURN(simple_command(mysql, MYSQL_COM_SET_OPTION, buffer, sizeof(buffer), 0, 0));
- }
-
- ulong STDCALL mysql_get_client_version(void)
-@@ -2986,3 +3104,58 @@
- *to= 0;
- return (to - start);
- }
++}
++
++ulong STDCALL mysql_get_client_version(void)
++{
++ return MYSQL_VERSION_ID;
++}
++
++ulong STDCALL mysql_hex_string(char *to, const char *from,
++ unsigned long len)
++{
++ char *start= to;
++ char hexdigits[]= "012345679ABCDEF";
++
++ while (len--)
++ {
++ *to++= hexdigits[*from >> 4];
++ *to++= hexdigits[*from & 0x0F];
++ from++;
++ }
++ *to= 0;
++ return (ulong)(to - start);
++}
+
+my_bool STDCALL mariadb_connection(MYSQL *mysql)
+{
@@ -3329,6 +14267,12 @@
+ return mariadb_connection(mysql) ? "MariaDB" : "MySQL";
+}
+
++MYSQL_PARAMETERS *STDCALL
++mysql_get_parameters(void)
++{
++ return &mariadb_internal_parameters;
++}
++
+/*
+ * Default methods for a connection. These methods are
+ * stored in mysql->methods and can be overwritten by
@@ -3368,213 +14312,8381 @@
+ /* skip unbuffered stmt result */
+ mthd_stmt_flush_unbuffered
+};
-
-=== renamed file 'libmysql/libmysql_exports.def' => 'libmariadb/libmariadb_exports.def'
---- mariadb/libmysql/libmysql_exports.def 2012-11-28 13:09:17 +0000
-+++ mariadb/libmariadb/libmariadb_exports.def 2013-03-14 21:01:43 +0000
-@@ -1,4 +1,5 @@
- EXPORTS
-+ mysql_ps_fetch_functions DATA
- get_tty_password
- load_defaults
- mysql_thread_end
-@@ -53,11 +54,10 @@
- mysql_num_rows
- mysql_options
- mysql_stmt_param_count
-- ;mysql_stmt_param_metadata
-+ mysql_stmt_param_metadata
- mysql_ping
- mysql_stmt_result_metadata
- mysql_query
-- mysql_read_query_result
- mysql_real_connect
- mysql_real_escape_string
- mysql_real_query
-@@ -102,6 +102,6 @@
- mysql_server_end
- mysql_set_character_set
- mysql_get_character_set_info
-- ;mysql_stmt_next_result
--
--
-+ mysql_stmt_next_result
-+ mariadb_connection
-+ mysql_get_server_name
-
-=== renamed file 'libmysql/my_secure.c' => 'libmariadb/ma_secure.c'
---- mariadb/libmysql/my_secure.c 2012-11-26 07:32:41 +0000
-+++ mariadb/libmariadb/ma_secure.c 2013-03-14 21:01:43 +0000
-@@ -21,7 +21,7 @@
-
- #include <my_global.h>
- #include <my_sys.h>
--#include <my_secure.h>
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/libmariadb_exports.def mariadb-native-client.trunk/libmariadb/libmariadb_exports.def
+--- mariadb/libmariadb/libmariadb_exports.def 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/libmariadb_exports.def 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,135 @@
++EXPORTS
++ mysql_ps_fetch_functions DATA
++ get_tty_password
++ load_defaults
++ mysql_thread_end
++ mysql_thread_init
++ myodbc_remove_escape
++ mysql_affected_rows
++ mysql_autocommit
++ mysql_stmt_bind_param
++ mysql_stmt_bind_result
++ mysql_change_user
++ mysql_character_set_name
++ mysql_close
++ mysql_commit
++ mysql_data_seek
++ mysql_debug
++ mysql_dump_debug_info
++ mysql_eof
++ mysql_errno
++ mysql_error
++ mysql_escape_string
++ mysql_hex_string
++ mysql_stmt_execute
++ mysql_stmt_fetch
++ mysql_stmt_fetch_column
++ mysql_fetch_field
++ mysql_fetch_field_direct
++ mysql_fetch_fields
++ mysql_fetch_lengths
++ mysql_fetch_row
++ mysql_field_count
++ mysql_field_seek
++ mysql_field_tell
++ mysql_free_result
++ mysql_get_client_info
++ mysql_get_host_info
++ mysql_get_proto_info
++ mysql_get_server_info
++ mysql_get_client_version
++ mysql_get_ssl_cipher
++ mysql_info
++ mysql_init
++ mysql_insert_id
++ mysql_kill
++ mysql_set_server_option
++ mysql_list_dbs
++ mysql_list_fields
++ mysql_list_processes
++ mysql_list_tables
++ mysql_more_results
++ mysql_next_result
++ mysql_num_fields
++ mysql_num_rows
++ mysql_options
++ mysql_options4
++ mysql_stmt_param_count
++ mysql_stmt_param_metadata
++ mysql_ping
++ mysql_stmt_result_metadata
++ mysql_query
++ mysql_read_query_result
++ mysql_real_connect
++ mysql_real_escape_string
++ mysql_real_query
++ mysql_refresh
++ mysql_rollback
++ mysql_row_seek
++ mysql_row_tell
++ mysql_select_db
++ mysql_stmt_send_long_data
++ mysql_send_query
++ mysql_shutdown
++ mysql_ssl_set
++ mysql_stat
++ mysql_stmt_affected_rows
++ mysql_stmt_close
++ mysql_stmt_reset
++ mysql_stmt_data_seek
++ mysql_stmt_errno
++ mysql_stmt_error
++ mysql_stmt_free_result
++ mysql_stmt_num_rows
++ mysql_stmt_row_seek
++ mysql_stmt_row_tell
++ mysql_stmt_store_result
++ mysql_store_result
++ mysql_thread_id
++ mysql_thread_safe
++ mysql_use_result
++ mysql_warning_count
++ mysql_stmt_sqlstate
++ mysql_sqlstate
++ mysql_get_server_version
++ mysql_stmt_prepare
++ mysql_stmt_init
++ mysql_stmt_insert_id
++ mysql_stmt_attr_get
++ mysql_stmt_attr_set
++ mysql_stmt_field_count
++ mysql_set_local_infile_default
++ mysql_set_local_infile_handler
++ mysql_server_init
++ mysql_server_end
++ mysql_set_character_set
++ mysql_get_character_set_info
++ mysql_stmt_next_result
++ mysql_stmt_more_results
++ mariadb_connection
++ mysql_get_server_name
++ mysql_get_charset_by_name
++ mysql_get_charset_by_nr
++ mysql_get_parameters
++ mariadb_convert_string
++ mariadb_dyncol_free
++ mariadb_dyncol_create_many_num
++ mariadb_dyncol_create_many_named
++ mariadb_dyncol_update_many_num
++ mariadb_dyncol_update_many_named
++ mariadb_dyncol_exists_num
++ mariadb_dyncol_exists_named
++ mariadb_dyncol_list_num
++ mariadb_dyncol_list_named
++ mariadb_dyncol_get_num
++ mariadb_dyncol_get_named
++ mariadb_dyncol_has_names
++ mariadb_dyncol_check
++ mariadb_dyncol_val_str
++ mariadb_dyncol_val_long
++ mariadb_dyncol_val_double
++ mariadb_dyncol_unpack
++ mariadb_dyncol_column_cmp_named
++ mariadb_dyncol_column_count
++ mariadb_dyncol_json
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/list.c mariadb-native-client.trunk/libmariadb/list.c
+--- mariadb/libmariadb/list.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/list.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,116 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Code for handling dubble-linked lists in C
++*/
++
++#include "mysys_priv.h"
++#include <my_list.h>
++
++
++
++ /* Add a element to start of list */
++
++LIST *list_add(LIST *root, LIST *element)
++{
++ DBUG_ENTER("list_add");
++ DBUG_PRINT("enter",("root: %lx element: %lx", root, element));
++ if (root)
++ {
++ if (root->prev) /* If add in mid of list */
++ root->prev->next= element;
++ element->prev=root->prev;
++ root->prev=element;
++ }
++ else
++ element->prev=0;
++ element->next=root;
++ DBUG_RETURN(element); /* New root */
++}
++
++
++LIST *list_delete(LIST *root, LIST *element)
++{
++ if (element->prev)
++ element->prev->next=element->next;
++ else
++ root=element->next;
++ if (element->next)
++ element->next->prev=element->prev;
++ return root;
++}
++
++
++void list_free(LIST *root, unsigned int free_data)
++{
++ LIST *next;
++ while (root)
++ {
++ next=root->next;
++ if (free_data)
++ my_free((gptr) root->data,MYF(0));
++ my_free((gptr) root,MYF(0));
++ root=next;
++ }
++}
++
++
++LIST *list_cons(void *data, LIST *list)
++{
++ LIST *new_charset=(LIST*) my_malloc(sizeof(LIST),MYF(MY_FAE));
++ if (!new_charset)
++ return 0;
++ new_charset->data=data;
++ return list_add(list,new_charset);
++}
++
++
++LIST *list_reverse(LIST *root)
++{
++ LIST *last;
++
++ last=root;
++ while (root)
++ {
++ last=root;
++ root=root->next;
++ last->next=last->prev;
++ last->prev=root;
++ }
++ return last;
++}
++
++uint list_length(LIST *list)
++{
++ uint count;
++ for (count=0 ; list ; list=list->next, count++) ;
++ return count;
++}
++
++
++int list_walk(LIST *list, list_walk_action action, gptr argument)
++{
++ int error=0;
++ while (list)
++ {
++ if ((error = (*action)(list->data,argument)))
++ return error;
++ list=rest(list);
++ }
++ return 0;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/llstr.c mariadb-native-client.trunk/libmariadb/llstr.c
+--- mariadb/libmariadb/llstr.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/llstr.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Defines: llstr();
++
++ llstr(value, buff);
++
++ This function saves a longlong value in a buffer and returns the pointer to
++ the buffer. This is useful when trying to portable print longlong
++ variables with printf() as there is no usable printf() standard one can use.
++*/
++
++
++#include <my_global.h>
++#include "m_string.h"
++
++char *llstr(longlong value,char *buff)
++{
++ longlong2str(value,buff,-10);
++ return buff;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/longlong2str.c mariadb-native-client.trunk/libmariadb/longlong2str.c
+--- mariadb/libmariadb/longlong2str.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/longlong2str.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,143 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Defines: longlong2str();
++
++ longlong2str(dst, radix, val)
++ converts the (longlong) integer "val" to character form and moves it to
++ the destination string "dst" followed by a terminating NUL. The
++ result is normally a pointer to this NUL character, but if the radix
++ is dud the result will be NullS and nothing will be changed.
++
++ If radix is -2..-36, val is taken to be SIGNED.
++ If radix is 2.. 36, val is taken to be UNSIGNED.
++ That is, val is signed if and only if radix is. You will normally
++ use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
++ unsigned is what you generally want.
++
++ _dig_vec is public just in case someone has a use for it.
++ The definitions of itoa and ltoa are actually macros in m_string.h,
++ but this is where the code is.
++
++ Note: The standard itoa() returns a pointer to the argument, when int2str
++ returns the pointer to the end-null.
++ itoa assumes that 10 -base numbers are allways signed and other arn't.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#if defined(HAVE_LONG_LONG) && !defined(longlong2str) && !defined(HAVE_LONGLONG2STR)
++
++extern char NEAR _dig_vec[];
++
++/*
++ This assumes that longlong multiplication is faster than longlong division.
++*/
++
++char *longlong2str(longlong val,char *dst,int radix)
++{
++ char buffer[65];
++ register char *p;
++ long long_val;
++
++ if (radix < 0)
++ {
++ if (radix < -36 || radix > -2) return (char*) 0;
++ if (val < 0) {
++ *dst++ = '-';
++ val = -val;
++ }
++ radix = -radix;
++ }
++ else
++ {
++ if (radix > 36 || radix < 2) return (char*) 0;
++ }
++ if (val == 0)
++ {
++ *dst++='0';
++ *dst='\0';
++ return dst;
++ }
++ p = &buffer[sizeof(buffer)-1];
++ *p = '\0';
++
++ while ((ulonglong) val > (ulonglong) LONG_MAX)
++ {
++ ulonglong quo=(ulonglong) val/(uint) radix;
++ uint rem= (uint) (val- quo* (uint) radix);
++ *--p = _dig_vec[rem];
++ val= quo;
++ }
++ long_val= (long) val;
++ while (long_val != 0)
++ {
++ long quo= long_val/radix;
++ *--p = _dig_vec[(uchar) (long_val - quo*radix)];
++ long_val= quo;
++ }
++ while ((*dst++ = *p++) != 0) ;
++ return dst-1;
++}
++
++#endif
++
++#ifndef longlong10_to_str
++char *longlong10_to_str(longlong val,char *dst,int radix)
++{
++ char buffer[65];
++ register char *p;
++ long long_val;
++
++ if (radix < 0)
++ {
++ if (val < 0)
++ {
++ *dst++ = '-';
++ val = -val;
++ }
++ }
++
++ if (val == 0)
++ {
++ *dst++='0';
++ *dst='\0';
++ return dst;
++ }
++ p = &buffer[sizeof(buffer)-1];
++ *p = '\0';
++
++ while ((ulonglong) val > (ulonglong) LONG_MAX)
++ {
++ ulonglong quo=(ulonglong) val/(uint) 10;
++ uint rem= (uint) (val- quo* (uint) 10);
++ *--p = _dig_vec[rem];
++ val= quo;
++ }
++ long_val= (long) val;
++ while (long_val != 0)
++ {
++ long quo= long_val/10;
++ *--p = _dig_vec[(uchar) (long_val - quo*10)];
++ long_val= quo;
++ }
++ while ((*dst++ = *p++) != 0) ;
++ return dst-1;
++}
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/ma_dyncol.c mariadb-native-client.trunk/libmariadb/ma_dyncol.c
+--- mariadb/libmariadb/ma_dyncol.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/ma_dyncol.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,4421 @@
++/* Copyright (c) 2011,2013 Monty Program Ab;
++ Copyright (c) 2011,2012 Oleksandr Byelkin
++
++ Redistribution and use in source and binary forms, with or without
++ modification, are permitted provided that the following conditions are
++ met:
++
++ 1. Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++
++ 2. Redistributions in binary form must the following disclaimer in
++ the documentation and/or other materials provided with the
++ distribution.
++
++ THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
++ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
++ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ SUCH DAMAGE.
++*/
++
++/*
++ Numeric format:
++ ===============
++ * Fixed header part
++ 1 byte flags:
++ 0,1 bits - <offset size> - 1
++ 2-7 bits - 0
++ 2 bytes column counter
++ * Columns directory sorted by column number, each entry contains of:
++ 2 bytes column number
++ <offset size> bytes (1-4) combined offset from beginning of
++ the data segment + 3 bit type
++ * Data of above columns size of data and length depend on type
++
++ Columns with names:
++ ===================
++ * Fixed header part
++ 1 byte flags:
++ 0,1 bits - <offset size> - 2
++ 2 bit - 1 (means format with names)
++ 3,4 bits - 00 (means <names offset size> - 2,
++ now 2 is the only supported size)
++ 5-7 bits - 0
++ 2 bytes column counter
++ * Variable header part (now it is actually fixed part)
++ <names offset size> (2) bytes size of stored names pool
++ * Column directory sorted by names, each consists of
++ <names offset size> (2) bytes offset of name
++ <offset size> bytes (2-5)bytes combined offset from beginning of
++ the data segment + 4 bit type
++ * Names stored one after another
++ * Data of above columns size of data and length depend on type
++*/
++
++#include <stdio.h>
++#include "mysys_priv.h"
++#include <my_global.h>
++#include <m_string.h>
++#include <hash.h>
++#include <ma_dyncol.h>
++#include <mysql.h>
++
++
++
++#ifndef LIBMARIADB
++uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
++ const char *from, uint32 from_length,
++ CHARSET_INFO *from_cs, uint *errors);
++#else
++
++size_t mariadb_time_to_string(const MYSQL_TIME *tm, char *time_str, size_t len,
++ unsigned int digits);
++size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs,
++ char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode);
++#endif
++/*
++ Flag byte bits
++
++ 2 bits which determinate size of offset in the header -1
++*/
++/* mask to get above bits */
++#define DYNCOL_FLG_OFFSET (1|2)
++#define DYNCOL_FLG_NAMES 4
++#define DYNCOL_FLG_NMOFFSET (8|16)
++/**
++ All known flags mask that could be set.
++
++ @note DYNCOL_FLG_NMOFFSET should be 0 for now.
++*/
++#define DYNCOL_FLG_KNOWN (1|2|4)
++
++/* formats */
++enum enum_dyncol_format
++{
++ dyncol_fmt_num= 0,
++ dyncol_fmt_str= 1
++};
++
++/* dynamic column size reserve */
++#define DYNCOL_SYZERESERVE 80
++
++#define DYNCOL_OFFSET_ERROR 0xffffffff
++
++/* length of fixed string header 1 byte - flags, 2 bytes - columns counter */
++#define FIXED_HEADER_SIZE 3
++/*
++ length of fixed string header with names
++ 1 byte - flags, 2 bytes - columns counter, 2 bytes - name pool size
++*/
++#define FIXED_HEADER_SIZE_NM 5
++
++#define COLUMN_NUMBER_SIZE 2
++/* 2 bytes offset from the name pool */
++#define COLUMN_NAMEPTR_SIZE 2
++
++#define MAX_OFFSET_LENGTH 4
++#define MAX_OFFSET_LENGTH_NM 5
++
++#define DYNCOL_NUM_CHAR 6
++
++my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str)
++{
++ if (str->length < 1)
++ return FALSE;
++ return test(str->str[0] & DYNCOL_FLG_NAMES);
++}
++
++static enum enum_dyncol_func_result
++dynamic_column_time_store(DYNAMIC_COLUMN *str,
++ MYSQL_TIME *value, enum enum_dyncol_format format);
++static enum enum_dyncol_func_result
++dynamic_column_date_store(DYNAMIC_COLUMN *str,
++ MYSQL_TIME *value);
++static enum enum_dyncol_func_result
++dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length);
++static enum enum_dyncol_func_result
++dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length);
++static enum enum_dyncol_func_result
++dynamic_column_get_internal(DYNAMIC_COLUMN *str,
++ DYNAMIC_COLUMN_VALUE *store_it_here,
++ uint num_key, LEX_STRING *str_key);
++static enum enum_dyncol_func_result
++dynamic_column_exists_internal(DYNAMIC_COLUMN *str, uint num_key,
++ LEX_STRING *str_key);
++static enum enum_dyncol_func_result
++dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ void *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool string_keys);
++static int plan_sort_num(const void *a, const void *b);
++static int plan_sort_named(const void *a, const void *b);
++
++/*
++ Structure to hold information about dynamic columns record and
++ iterate through it.
++*/
++
++struct st_dyn_header
++{
++ uchar *header, *nmpool, *dtpool, *data_end;
++ size_t offset_size;
++ size_t entry_size;
++ size_t header_size;
++ size_t nmpool_size;
++ size_t data_size;
++ /* dyncol_fmt_num - numeric columns, dyncol_fmt_str - column names */
++ enum enum_dyncol_format format;
++ uint column_count;
++
++ uchar *entry, *data, *name;
++ size_t offset;
++ size_t length;
++ enum enum_dynamic_column_type type;
++};
++
++typedef struct st_dyn_header DYN_HEADER;
++
++static inline my_bool read_fixed_header(DYN_HEADER *hdr,
++ DYNAMIC_COLUMN *str);
++static void set_fixed_header(DYNAMIC_COLUMN *str,
++ uint offset_size,
++ uint column_count);
++
++/*
++ Calculate entry size (E) and header size (H) by offset size (O) and column
++ count (C) and fixed part of entry size (F).
++*/
++
++#define calc_param(E,H,F,O,C) do { \
++ (*(E))= (O) + F; \
++ (*(H))= (*(E)) * (C); \
++}while(0);
++
++
++/**
++ Name pool size functions, for numeric format it is 0
++*/
++
++static size_t name_size_num(void *keys __attribute__((unused)),
++ uint i __attribute__((unused)))
++{
++ return 0;
++}
++
++
++/**
++ Name pool size functions.
++*/
++static size_t name_size_named(void *keys, uint i)
++{
++ return ((LEX_STRING *) keys)[i].length;
++}
++
++
++/**
++ Comparator function for references on column numbers for qsort
++ (numeric format)
++*/
++
++static int column_sort_num(const void *a, const void *b)
++{
++ return **((uint **)a) - **((uint **)b);
++}
++
++/**
++ Comparator function for references on column numbers for qsort
++ (names format)
++*/
++
++int mariadb_dyncol_column_cmp_named(const LEX_STRING *s1, const LEX_STRING *s2)
++{
++ /*
++ We compare instead of subtraction to avoid data loss in case of huge
++ length difference (more then fit in int).
++ */
++ int rc= (s1->length > s2->length ? 1 :
++ (s1->length < s2->length ? -1 : 0));
++ if (rc == 0)
++ rc= memcmp((void *)s1->str, (void *)s2->str,
++ (size_t) s1->length);
++ return rc;
++}
++
++
++/**
++ Comparator function for references on column numbers for qsort
++ (names format)
++*/
++
++static int column_sort_named(const void *a, const void *b)
++{
++ return mariadb_dyncol_column_cmp_named(*((LEX_STRING **)a),
++ *((LEX_STRING **)b));
++}
++
++
++/**
++ Check limit function (numeric format)
++*/
++
++static my_bool check_limit_num(const void *val)
++{
++ return **((uint **)val) > UINT_MAX16;
++}
++
++
++/**
++ Check limit function (names format)
++*/
++
++static my_bool check_limit_named(const void *val)
++{
++ return (*((LEX_STRING **)val))->length > MAX_NAME_LENGTH;
++}
++
++
++/**
++ Write numeric format static header part.
++*/
++
++static void set_fixed_header_num(DYNAMIC_COLUMN *str, DYN_HEADER *hdr)
++{
++ set_fixed_header(str, (uint)hdr->offset_size, hdr->column_count);
++ hdr->header= (uchar *)str->str + FIXED_HEADER_SIZE;
++ hdr->nmpool= hdr->dtpool= hdr->header + hdr->header_size;
++}
++
++
++/**
++ Write names format static header part.
++*/
++
++static void set_fixed_header_named(DYNAMIC_COLUMN *str, DYN_HEADER *hdr)
++{
++ DBUG_ASSERT(hdr->column_count <= 0xffff);
++ DBUG_ASSERT(hdr->offset_size <= MAX_OFFSET_LENGTH_NM);
++ /* size of data offset, named format flag, size of names offset (0 means 2) */
++ str->str[0]=
++ (char) ((str->str[0] & ~(DYNCOL_FLG_OFFSET | DYNCOL_FLG_NMOFFSET)) |
++ (hdr->offset_size - 2) | DYNCOL_FLG_NAMES);
++ int2store(str->str + 1, hdr->column_count); /* columns number */
++ int2store(str->str + 3, hdr->nmpool_size);
++ hdr->header= (uchar *)str->str + FIXED_HEADER_SIZE_NM;
++ hdr->nmpool= hdr->header + hdr->header_size;
++ hdr->dtpool= hdr->nmpool + hdr->nmpool_size;
++}
++
++
++/**
++ Store offset and type information in the given place
++
++ @param place Beginning of the index entry
++ @param offset_size Size of offset field in bytes
++ @param type Type to be written
++ @param offset Offset to be written
++*/
++
++static my_bool type_and_offset_store_num(uchar *place, size_t offset_size,
++ DYNAMIC_COLUMN_TYPE type,
++ size_t offset)
++{
++ ulong val = (((ulong) offset) << 3) | (type - 1);
++ DBUG_ASSERT(type != DYN_COL_NULL);
++ DBUG_ASSERT(((type - 1) & (~7)) == 0); /* fit in 3 bits */
++ DBUG_ASSERT(offset_size >= 1 && offset_size <= 4);
++
++ /* Index entry starts with column number; jump over it */
++ place+= COLUMN_NUMBER_SIZE;
++
++ switch (offset_size) {
++ case 1:
++ if (offset >= 0x1f) /* all 1 value is reserved */
++ return TRUE;
++ place[0]= (uchar)val;
++ break;
++ case 2:
++ if (offset >= 0x1fff) /* all 1 value is reserved */
++ return TRUE;
++ int2store(place, val);
++ break;
++ case 3:
++ if (offset >= 0x1fffff) /* all 1 value is reserved */
++ return TRUE;
++ int3store(place, val);
++ break;
++ case 4:
++ if (offset >= 0x1fffffff) /* all 1 value is reserved */
++ return TRUE;
++ int4store(place, val);
++ break;
++ default:
++ return TRUE;
++ }
++ return FALSE;
++}
++
++
++static my_bool type_and_offset_store_named(uchar *place, size_t offset_size,
++ DYNAMIC_COLUMN_TYPE type,
++ size_t offset)
++{
++ ulonglong val = (((ulong) offset) << 4) | (type - 1);
++ DBUG_ASSERT(type != DYN_COL_NULL);
++ DBUG_ASSERT(((type - 1) & (~0xf)) == 0); /* fit in 4 bits */
++ DBUG_ASSERT(offset_size >= 2 && offset_size <= 5);
++
++ /* Index entry starts with name offset; jump over it */
++ place+= COLUMN_NAMEPTR_SIZE;
++ switch (offset_size) {
++ case 2:
++ if (offset >= 0xfff) /* all 1 value is reserved */
++ return TRUE;
++ int2store(place, val);
++ break;
++ case 3:
++ if (offset >= 0xfffff) /* all 1 value is reserved */
++ return TRUE;
++ int3store(place, val);
++ break;
++ case 4:
++ if (offset >= 0xfffffff) /* all 1 value is reserved */
++ return TRUE;
++ int4store(place, val);
++ break;
++ case 5:
++#if SIZEOF_SIZE_T > 4
++ if (offset >= 0xfffffffffull) /* all 1 value is reserved */
++ return TRUE;
++#endif
++ int5store(place, val);
++ break;
++ case 1:
++ default:
++ return TRUE;
++ }
++ return FALSE;
++}
++
++/**
++ Write numeric format header entry
++ 2 bytes - column number
++ 1-4 bytes - data offset combined with type
++
++ @param hdr descriptor of dynamic column record
++ @param column_key pointer to uint (column number)
++ @param value value which will be written (only type used)
++ @param offset offset of the data
++*/
++
++static my_bool put_header_entry_num(DYN_HEADER *hdr,
++ void *column_key,
++ DYNAMIC_COLUMN_VALUE *value,
++ size_t offset)
++{
++ uint *column_number= (uint *)column_key;
++ int2store(hdr->entry, *column_number);
++ DBUG_ASSERT(hdr->nmpool_size == 0);
++ if (type_and_offset_store_num(hdr->entry, hdr->offset_size,
++ value->type,
++ offset))
++ return TRUE;
++ hdr->entry= hdr->entry + hdr->entry_size;
++ return FALSE;
++}
++
++
++/**
++ Write names format header entry
++ 1 byte - name length
++ 2 bytes - name offset in the name pool
++ 1-4 bytes - data offset combined with type
++
++ @param hdr descriptor of dynamic column record
++ @param column_key pointer to LEX_STRING (column name)
++ @param value value which will be written (only type used)
++ @param offset offset of the data
++*/
++
++static my_bool put_header_entry_named(DYN_HEADER *hdr,
++ void *column_key,
++ DYNAMIC_COLUMN_VALUE *value,
++ size_t offset)
++{
++ LEX_STRING *column_name= (LEX_STRING *)column_key;
++ DBUG_ASSERT(column_name->length <= MAX_NAME_LENGTH);
++ DBUG_ASSERT(hdr->name - hdr->nmpool < (long) 0x10000L);
++ int2store(hdr->entry, hdr->name - hdr->nmpool);
++ memcpy(hdr->name, column_name->str, column_name->length);
++ DBUG_ASSERT(hdr->nmpool_size != 0 || column_name->length == 0);
++ if (type_and_offset_store_named(hdr->entry, hdr->offset_size,
++ value->type,
++ offset))
++ return TRUE;
++ hdr->entry+= hdr->entry_size;
++ hdr->name+= column_name->length;
++ return FALSE;
++}
++
++
++/**
++ Calculate length of offset field for given data length
++
++ @param data_length Length of the data segment
++
++ @return number of bytes
++*/
++
++static size_t dynamic_column_offset_bytes_num(size_t data_length)
++{
++ if (data_length < 0x1f) /* all 1 value is reserved */
++ return 1;
++ if (data_length < 0x1fff) /* all 1 value is reserved */
++ return 2;
++ if (data_length < 0x1fffff) /* all 1 value is reserved */
++ return 3;
++ if (data_length < 0x1fffffff) /* all 1 value is reserved */
++ return 4;
++ return MAX_OFFSET_LENGTH + 1; /* For an error generation*/
++}
++
++static size_t dynamic_column_offset_bytes_named(size_t data_length)
++{
++ if (data_length < 0xfff) /* all 1 value is reserved */
++ return 2;
++ if (data_length < 0xfffff) /* all 1 value is reserved */
++ return 3;
++ if (data_length < 0xfffffff) /* all 1 value is reserved */
++ return 4;
++#if SIZEOF_SIZE_T > 4
++ if (data_length < 0xfffffffffull) /* all 1 value is reserved */
++#endif
++ return 5;
++ return MAX_OFFSET_LENGTH_NM + 1; /* For an error generation */
++}
++
++/**
++ Read offset and type information from index entry
++
++ @param type Where to put type info
++ @param offset Where to put offset info
++ @param place beginning of the type and offset
++ @param offset_size Size of offset field in bytes
++*/
++
++static my_bool type_and_offset_read_num(DYNAMIC_COLUMN_TYPE *type,
++ size_t *offset,
++ uchar *place, size_t offset_size)
++{
++ ulong UNINIT_VAR(val);
++ ulong UNINIT_VAR(lim);
++
++ DBUG_ASSERT(offset_size >= 1 && offset_size <= 4);
++
++ switch (offset_size) {
++ case 1:
++ val= (ulong)place[0];
++ lim= 0x1f;
++ break;
++ case 2:
++ val= uint2korr(place);
++ lim= 0x1fff;
++ break;
++ case 3:
++ val= uint3korr(place);
++ lim= 0x1fffff;
++ break;
++ case 4:
++ val= uint4korr(place);
++ lim= 0x1fffffff;
++ break;
++ default:
++ DBUG_ASSERT(0); /* impossible */
++ return 1;
++ }
++ *type= (val & 0x7) + 1;
++ *offset= val >> 3;
++ return (*offset >= lim);
++}
++
++static my_bool type_and_offset_read_named(DYNAMIC_COLUMN_TYPE *type,
++ size_t *offset,
++ uchar *place, size_t offset_size)
++{
++ ulonglong UNINIT_VAR(val);
++ ulonglong UNINIT_VAR(lim);
++ DBUG_ASSERT(offset_size >= 2 && offset_size <= 5);
++
++ switch (offset_size) {
++ case 2:
++ val= uint2korr(place);
++ lim= 0xfff;
++ break;
++ case 3:
++ val= uint3korr(place);
++ lim= 0xfffff;
++ break;
++ case 4:
++ val= uint4korr(place);
++ lim= 0xfffffff;
++ break;
++ case 5:
++ val= uint5korr(place);
++ lim= 0xfffffffffull;
++ break;
++ case 1:
++ default:
++ DBUG_ASSERT(0); /* impossible */
++ return 1;
++ }
++ *type= (val & 0xf) + 1;
++ *offset= (size_t)(val >> 4);
++ return (*offset >= lim);
++}
++
++/**
++ Format descriptor, contain constants and function references for
++ format processing
++*/
++
++struct st_service_funcs
++{
++ /* size of fixed header */
++ uint fixed_hdr;
++ /* size of fixed part of header entry */
++ uint fixed_hdr_entry;
++
++ /*size of array element which stores keys */
++ uint key_size_in_array;
++
++ /* Maximum data offset size in bytes */
++ size_t max_offset_size;
++
++ size_t (*name_size)
++ (void *, uint);
++ int (*column_sort)
++ (const void *a, const void *b);
++ my_bool (*check_limit)
++ (const void *val);
++ void (*set_fixed_hdr)
++ (DYNAMIC_COLUMN *str, DYN_HEADER *hdr);
++ my_bool (*put_header_entry)(DYN_HEADER *hdr,
++ void *column_key,
++ DYNAMIC_COLUMN_VALUE *value,
++ size_t offset);
++ int (*plan_sort)(const void *a, const void *b);
++ size_t (*dynamic_column_offset_bytes)(size_t data_length);
++ my_bool (*type_and_offset_read)(DYNAMIC_COLUMN_TYPE *type,
++ size_t *offset,
++ uchar *place, size_t offset_size);
++
++};
++
++
++/**
++ Actual our 2 format descriptors
++*/
++
++static struct st_service_funcs fmt_data[2]=
++{
++ {
++ FIXED_HEADER_SIZE,
++ COLUMN_NUMBER_SIZE,
++ sizeof(uint),
++ MAX_OFFSET_LENGTH,
++ &name_size_num,
++ &column_sort_num,
++ &check_limit_num,
++ &set_fixed_header_num,
++ &put_header_entry_num,
++ &plan_sort_num,
++ &dynamic_column_offset_bytes_num,
++ &type_and_offset_read_num
++ },
++ {
++ FIXED_HEADER_SIZE_NM,
++ COLUMN_NAMEPTR_SIZE,
++ sizeof(LEX_STRING),
++ MAX_OFFSET_LENGTH_NM,
++ &name_size_named,
++ &column_sort_named,
++ &check_limit_named,
++ &set_fixed_header_named,
++ &put_header_entry_named,
++ &plan_sort_named,
++ &dynamic_column_offset_bytes_named,
++ &type_and_offset_read_named
++ }
++};
++
++
++/**
++ Read dynamic column record header and fill the descriptor
++
++ @param hdr dynamic columns record descriptor to fill
++ @param str dynamic columns record
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++init_read_hdr(DYN_HEADER *hdr, DYNAMIC_COLUMN *str)
++{
++ if (read_fixed_header(hdr, str))
++ return ER_DYNCOL_FORMAT;
++ hdr->header= (uchar*)str->str + fmt_data[hdr->format].fixed_hdr;
++ calc_param(&hdr->entry_size, &hdr->header_size,
++ fmt_data[hdr->format].fixed_hdr_entry, hdr->offset_size,
++ hdr->column_count);
++ hdr->nmpool= hdr->header + hdr->header_size;
++ hdr->dtpool= hdr->nmpool + hdr->nmpool_size;
++ hdr->data_size= str->length - fmt_data[hdr->format].fixed_hdr -
++ hdr->header_size - hdr->nmpool_size;
++ hdr->data_end= (uchar*)str->str + str->length;
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Initialize dynamic column string with (make it empty but correct format)
++
++ @param str The string to initialize
++ @param size Amount of preallocated memory for the string.
++
++ @retval FALSE OK
++ @retval TRUE error
++*/
++
++static my_bool dynamic_column_init_named(DYNAMIC_COLUMN *str, size_t size)
++{
++ DBUG_ASSERT(size != 0);
++
++ /*
++ Make string with no fields (empty header)
++ - First \0 is flags
++ - other 2 \0 is number of fields
++ */
++ if (init_dynamic_string(str, NULL, size, DYNCOL_SYZERESERVE))
++ return TRUE;
++ return FALSE;
++}
++
++
++/**
++ Calculate how many bytes needed to store val as variable length integer
++ where first bit indicate continuation of the sequence.
++
++ @param val The value for which we are calculating length
++
++ @return number of bytes
++*/
++
++static size_t dynamic_column_var_uint_bytes(ulonglong val)
++{
++ size_t len= 0;
++ do
++ {
++ len++;
++ val>>= 7;
++ } while (val);
++ return len;
++}
++
++
++/**
++ Stores variable length unsigned integer value to a string
++
++ @param str The string where to append the value
++ @param val The value to put in the string
++
++ @return ER_DYNCOL_* return code
++
++ @notes
++ This is used to store a number together with other data in the same
++ object. (Like decimals, length of string etc)
++ (As we don't know the length of this object, we can't store 0 in 0 bytes)
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_var_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
++{
++ if (dynstr_realloc(str, 10)) /* max what we can use */
++ return ER_DYNCOL_RESOURCE;
++
++ do
++ {
++ ulonglong rest= val >> 7;
++ str->str[str->length++]= ((val & 0x7f) | (rest ? 0x80 : 0x00));
++ val= rest;
++ } while (val);
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Reads variable length unsigned integer value from a string
++
++ @param data The string from which the int should be read
++ @param data_length Max length of data
++ @param len Where to put length of the string read in bytes
++
++ @return value of the unsigned integer read from the string
++
++ In case of error, *len is set to 0
++*/
++
++static ulonglong
++dynamic_column_var_uint_get(uchar *data, size_t data_length,
++ size_t *len)
++{
++ ulonglong val= 0;
++ uint length;
++ uchar *end= data + data_length;
++
++ for (length=0; data < end ; data++)
++ {
++ val+= (((ulonglong)((*data) & 0x7f)) << (length * 7));
++ length++;
++ if (!((*data) & 0x80))
++ {
++ /* End of data */
++ *len= length;
++ return val;
++ }
++ }
++ /* Something was wrong with data */
++ *len= 0; /* Mark error */
++ return 0;
++}
++
++
++/**
++ Calculate how many bytes needed to store val as unsigned.
++
++ @param val The value for which we are calculating length
++
++ @return number of bytes (0-8)
++*/
++
++static size_t dynamic_column_uint_bytes(ulonglong val)
++{
++ size_t len;
++
++ for (len= 0; val ; val>>= 8, len++)
++ ;
++ return len;
++}
++
++
++/**
++ Append the string with given unsigned int value.
++
++ @param str The string where to put the value
++ @param val The value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
++{
++ if (dynstr_realloc(str, 8)) /* max what we can use */
++ return ER_DYNCOL_RESOURCE;
++
++ for (; val; val>>= 8)
++ str->str[str->length++]= (char) (val & 0xff);
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Read unsigned int value of given length from the string
++
++ @param store_it_here The structure to store the value
++ @param data The string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_uint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ ulonglong value= 0;
++ size_t i;
++
++ for (i= 0; i < length; i++)
++ value+= ((ulonglong)data[i]) << (i*8);
++
++ store_it_here->x.ulong_value= value;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Calculate how many bytes needed to store val as signed in following encoding:
++ 0 -> 0
++ -1 -> 1
++ 1 -> 2
++ -2 -> 3
++ 2 -> 4
++ ...
++
++ @param val The value for which we are calculating length
++
++ @return number of bytes
++*/
++
++static size_t dynamic_column_sint_bytes(longlong val)
++{
++ return dynamic_column_uint_bytes((val << 1) ^
++ (val < 0 ? 0xffffffffffffffffull : 0));
++}
++
++
++/**
++ Append the string with given signed int value.
++
++ @param str the string where to put the value
++ @param val the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_sint_store(DYNAMIC_COLUMN *str, longlong val)
++{
++ return dynamic_column_uint_store(str,
++ (val << 1) ^
++ (val < 0 ? 0xffffffffffffffffULL : 0));
++}
++
++
++/**
++ Read signed int value of given length from the string
++
++ @param store_it_here The structure to store the value
++ @param data The string which should be read
++ @param length The length (in bytes) of the value in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ ulonglong val;
++ dynamic_column_uint_read(store_it_here, data, length);
++ val= store_it_here->x.ulong_value;
++ if (val & 1)
++ val= (val >> 1) ^ 0xffffffffffffffffULL;
++ else
++ val>>= 1;
++ store_it_here->x.long_value= (longlong) val;
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Calculate how many bytes needed to store the value.
++
++ @param value The value for which we are calculating length
++
++ @return
++ Error: (size_t) ~0
++ ok number of bytes
++*/
++
++static size_t
++dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value,
++ enum enum_dyncol_format format)
++{
++ switch (value->type) {
++ case DYN_COL_NULL:
++ return 0;
++ case DYN_COL_INT:
++ return dynamic_column_sint_bytes(value->x.long_value);
++ case DYN_COL_UINT:
++ return dynamic_column_uint_bytes(value->x.ulong_value);
++ case DYN_COL_DOUBLE:
++ return 8;
++ case DYN_COL_STRING:
++#ifdef LIBMARIADB
++ return (dynamic_column_var_uint_bytes(value->x.string.charset->nr) +
++ value->x.string.value.length);
++#else
++ return (dynamic_column_var_uint_bytes(value->x.string.charset->number) +
++ value->x.string.value.length);
++#endif
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ {
++ int precision= value->x.decimal.value.intg + value->x.decimal.value.frac;
++ int scale= value->x.decimal.value.frac;
++
++ if (precision == 0 || decimal_is_zero(&value->x.decimal.value))
++ {
++ /* This is here to simplify dynamic_column_decimal_store() */
++ value->x.decimal.value.intg= value->x.decimal.value.frac= 0;
++ return 0;
++ }
++ /*
++ Check if legal decimal; This is needed to not get an assert in
++ decimal_bin_size(). However this should be impossible as all
++ decimals entered here should be valid and we have the special check
++ above to handle the unlikely but possible case that decimal.value.intg
++ and decimal.frac is 0.
++ */
++ if (scale < 0 || precision <= 0)
++ {
++ DBUG_ASSERT(0); /* Impossible */
++ return (size_t) ~0;
++ }
++ return (dynamic_column_var_uint_bytes(value->x.decimal.value.intg) +
++ dynamic_column_var_uint_bytes(value->x.decimal.value.frac) +
++ decimal_bin_size(precision, scale));
++ }
++#endif
++ case DYN_COL_DATETIME:
++ if (format == dyncol_fmt_num || value->x.time_value.second_part)
++ /* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes*/
++ return 9;
++ else
++ return 6;
++ case DYN_COL_DATE:
++ /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
++ return 3;
++ case DYN_COL_TIME:
++ if (format == dyncol_fmt_num || value->x.time_value.second_part)
++ /* time in bits: 10 + 6 + 6 + 20 + 1 = 43bits ~= 6bytes*/
++ return 6;
++ else
++ return 3;
++ case DYN_COL_DYNCOL:
++ return value->x.string.value.length;
++ }
++ DBUG_ASSERT(0);
++ return 0;
++}
++
++
++/**
++ Append double value to a string
++
++ @param str the string where to put the value
++ @param val the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_double_store(DYNAMIC_COLUMN *str, double val)
++{
++ if (dynstr_realloc(str, 8))
++ return ER_DYNCOL_RESOURCE;
++ float8store(str->str + str->length, val);
++ str->length+= 8;
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Read double value of given length from the string
++
++ @param store_it_here The structure to store the value
++ @param data The string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_double_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ if (length != 8)
++ return ER_DYNCOL_FORMAT;
++ float8get(store_it_here->x.double_value, data);
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Append the string with given string value.
++
++ @param str the string where to put the value
++ @param val the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_string_store(DYNAMIC_COLUMN *str, LEX_STRING *string,
++ CHARSET_INFO *charset)
++{
++ enum enum_dyncol_func_result rc;
++#ifdef LIBMARIADB
++ if ((rc= dynamic_column_var_uint_store(str, charset->nr)))
++#else
++ if ((rc= dynamic_column_var_uint_store(str, charset->number)))
++#endif
++ return rc;
++ if (dynstr_append_mem(str, string->str, string->length))
++ return ER_DYNCOL_RESOURCE;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Append the string with given string value.
++
++ @param str the string where to put the value
++ @param val the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_dyncol_store(DYNAMIC_COLUMN *str, LEX_STRING *string)
++{
++ if (dynstr_append_mem(str, string->str, string->length))
++ return ER_DYNCOL_RESOURCE;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Read string value of given length from the packed string
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ size_t len;
++ uint charset_nr= (uint)dynamic_column_var_uint_get(data, length, &len);
++ if (len == 0) /* Wrong packed number */
++ return ER_DYNCOL_FORMAT;
++#ifndef LIBMARIADB
++ store_it_here->x.string.charset= get_charset_by_nr(charset_nr);
++#else
++ store_it_here->x.string.charset= mysql_get_charset_by_nr(charset_nr);
++#endif
++ if (store_it_here->x.string.charset == NULL)
++ return ER_DYNCOL_UNKNOWN_CHARSET;
++ data+= len;
++ store_it_here->x.string.value.length= (length-= len);
++ store_it_here->x.string.value.str= (char*) data;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Read Dynamic columns packet string value of given length
++ from the packed string
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_dyncol_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ store_it_here->x.string.charset= my_charset_bin;
++ store_it_here->x.string.value.length= length;
++ store_it_here->x.string.value.str= (char*) data;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Append the string with given decimal value.
++
++ @param str the string where to put the value
++ @param val the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++#ifndef LIBMARIADB
++static enum enum_dyncol_func_result
++dynamic_column_decimal_store(DYNAMIC_COLUMN *str,
++ decimal_t *value)
++{
++ uint bin_size;
++ int precision= value->intg + value->frac;
++
++ /* Store decimal zero as empty string */
++ if (precision == 0)
++ return ER_DYNCOL_OK;
++
++ bin_size= decimal_bin_size(precision, value->frac);
++ if (dynstr_realloc(str, bin_size + 20))
++ return ER_DYNCOL_RESOURCE;
++
++ /* The following can't fail as memory is already allocated */
++ (void) dynamic_column_var_uint_store(str, value->intg);
++ (void) dynamic_column_var_uint_store(str, value->frac);
++
++ decimal2bin(value, (uchar *) str->str + str->length,
++ precision, value->frac);
++ str->length+= bin_size;
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Prepare the value to be used as decimal.
++
++ @param value The value structure which sould be setup.
++*/
++
++void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
++{
++ value->x.decimal.value.buf= value->x.decimal.buffer;
++ value->x.decimal.value.len= DECIMAL_BUFF_LENGTH;
++ /* just to be safe */
++ value->type= DYN_COL_DECIMAL;
++ decimal_make_zero(&value->x.decimal.value);
++}
++
++void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
++{
++ mariadb_dyncol_prepare_decimal(value);
++}
++
++
++
++/**
++ Read decimal value of given length from the string
++
++ @param store_it_here The structure to store the value
++ @param data The string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ size_t intg_len, frac_len;
++ int intg, frac, precision, scale;
++
++ dynamic_column_prepare_decimal(store_it_here);
++ /* Decimals 0.0 is stored as a zero length string */
++ if (length == 0)
++ return ER_DYNCOL_OK; /* value contains zero */
++
++ intg= (int)dynamic_column_var_uint_get(data, length, &intg_len);
++ data+= intg_len;
++ frac= (int)dynamic_column_var_uint_get(data, length - intg_len, &frac_len);
++ data+= frac_len;
++
++ /* Check the size of data is correct */
++ precision= intg + frac;
++ scale= frac;
++ if (scale < 0 || precision <= 0 || scale > precision ||
++ (length - intg_len - frac_len) >
++ (size_t) (DECIMAL_BUFF_LENGTH*sizeof(decimal_digit_t)) ||
++ decimal_bin_size(intg + frac, frac) !=
++ (int) (length - intg_len - frac_len))
++ return ER_DYNCOL_FORMAT;
++
++ if (bin2decimal(data, &store_it_here->x.decimal.value, precision, scale) !=
++ E_DEC_OK)
++ return ER_DYNCOL_FORMAT;
++ return ER_DYNCOL_OK;
++}
++#endif
++
++/**
++ Append the string with given datetime value.
++
++ @param str the string where to put the value
++ @param value the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_date_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value,
++ enum enum_dyncol_format format)
++{
++ enum enum_dyncol_func_result rc;
++ /*
++ 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
++ 12345678901234123412345 1123456789012345612345612345678901234567890
++ <123456><123456><123456><123456><123456><123456><123456><123456><123456>
++ */
++ if ((rc= dynamic_column_date_store(str, value)) ||
++ (rc= dynamic_column_time_store(str, value, format)))
++ return rc;
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Read datetime value of given length from the packed string
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_date_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
++ /*
++ 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
++ 12345678901234123412345 1123456789012345612345612345678901234567890
++ <123456><123456><123456><123456><123456><123456><123456><123456><123456>
++ */
++ if (length != 9 && length != 6)
++ goto err;
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
++ if ((rc= dynamic_column_date_read_internal(store_it_here, data, 3)) ||
++ (rc= dynamic_column_time_read_internal(store_it_here, data + 3,
++ length - 3)))
++ goto err;
++ return ER_DYNCOL_OK;
++
++err:
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
++ return rc;
++}
++
++
++/**
++ Append the string with given time value.
++
++ @param str the string where to put the value
++ @param value the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value,
++ enum enum_dyncol_format format)
++{
++ uchar *buf;
++ if (dynstr_realloc(str, 6))
++ return ER_DYNCOL_RESOURCE;
++
++ buf= ((uchar *)str->str) + str->length;
++
++ if (value->time_type == MYSQL_TIMESTAMP_NONE ||
++ value->time_type == MYSQL_TIMESTAMP_ERROR ||
++ value->time_type == MYSQL_TIMESTAMP_DATE)
++ {
++ value->neg= 0;
++ value->second_part= 0;
++ value->hour= 0;
++ value->minute= 0;
++ value->second= 0;
++ }
++ DBUG_ASSERT(value->hour <= 838);
++ DBUG_ASSERT(value->minute <= 59);
++ DBUG_ASSERT(value->second <= 59);
++ DBUG_ASSERT(value->second_part <= 999999);
++ if (format == dyncol_fmt_num || value->second_part)
++ {
++ /*
++ 00000!<-hours--><min-><sec-><---microseconds--->
++ 1123456789012345612345612345678901234567890
++ <123456><123456><123456><123456><123456><123456>
++ */
++ buf[0]= (value->second_part & 0xff);
++ buf[1]= ((value->second_part & 0xff00) >> 8);
++ buf[2]= (uchar)(((value->second & 0xf) << 4) |
++ ((value->second_part & 0xf0000) >> 16));
++ buf[3]= ((value->minute << 2) | ((value->second & 0x30) >> 4));
++ buf[4]= (value->hour & 0xff);
++ buf[5]= ((value->neg ? 0x4 : 0) | (value->hour >> 8));
++ str->length+= 6;
++ }
++ else
++ {
++ /*
++ !<-hours--><min-><sec->
++ 11234567890123456123456
++ <123456><123456><123456>
++ */
++ buf[0]= (value->second) | ((value->minute & 0x3) << 6);
++ buf[1]= (value->minute >> 2) | ((value->hour & 0xf) << 4);
++ buf[2]= (value->hour >> 4) | (value->neg ? 0x80 : 0);
++ str->length+= 3;
++ }
++
++ return ER_DYNCOL_OK;
++}
++
++
++/**
++ Read time value of given length from the packed string
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ store_it_here->x.time_value.year= store_it_here->x.time_value.month=
++ store_it_here->x.time_value.day= 0;
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_TIME;
++ return dynamic_column_time_read_internal(store_it_here, data, length);
++}
++
++/**
++ Internal function for reading time part from the string.
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ if (length != 6 && length != 3)
++ goto err;
++ if (length == 6)
++ {
++ /*
++ 00000!<-hours--><min-><sec-><---microseconds--->
++ 1123456789012345612345612345678901234567890
++ <123456><123456><123456><123456><123456><123456>
++ */
++ store_it_here->x.time_value.second_part= (data[0] |
++ (data[1] << 8) |
++ ((data[2] & 0xf) << 16));
++ store_it_here->x.time_value.second= ((data[2] >> 4) |
++ ((data[3] & 0x3) << 4));
++ store_it_here->x.time_value.minute= (data[3] >> 2);
++ store_it_here->x.time_value.hour= (((((uint)data[5]) & 0x3 ) << 8) | data[4]);
++ store_it_here->x.time_value.neg= ((data[5] & 0x4) ? 1 : 0);
++ }
++ else
++ {
++ /*
++ !<-hours--><min-><sec->
++ 11234567890123456123456
++ <123456><123456><123456>
++ */
++ store_it_here->x.time_value.second_part= 0;
++ store_it_here->x.time_value.second= (data[0] & 0x3f);
++ store_it_here->x.time_value.minute= (data[0] >> 6) | ((data[1] & 0xf) << 2);
++ store_it_here->x.time_value.hour= (data[1] >> 4) | ((data[2] & 0x3f) << 4);
++ store_it_here->x.time_value.neg= ((data[2] & 0x80) ? 1 : 0);
++ }
++ if (store_it_here->x.time_value.second > 59 ||
++ store_it_here->x.time_value.minute > 59 ||
++ store_it_here->x.time_value.hour > 838 ||
++ store_it_here->x.time_value.second_part > 999999)
++ goto err;
++ return ER_DYNCOL_OK;
++
++err:
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
++ return ER_DYNCOL_FORMAT;
++}
++
++
++/**
++ Append the string with given date value.
++
++ @param str the string where to put the value
++ @param value the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_date_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
++{
++ uchar *buf;
++ if (dynstr_realloc(str, 3))
++ return ER_DYNCOL_RESOURCE;
++
++ buf= ((uchar *)str->str) + str->length;
++ if (value->time_type == MYSQL_TIMESTAMP_NONE ||
++ value->time_type == MYSQL_TIMESTAMP_ERROR ||
++ value->time_type == MYSQL_TIMESTAMP_TIME)
++ value->year= value->month= value->day = 0;
++ DBUG_ASSERT(value->year <= 9999);
++ DBUG_ASSERT(value->month <= 12);
++ DBUG_ASSERT(value->day <= 31);
++ /*
++ 0<----year----><mn><day>
++ 012345678901234123412345
++ <123456><123456><123456>
++ */
++ buf[0]= (value->day |
++ ((value->month & 0x7) << 5));
++ buf[1]= ((value->month >> 3) | ((value->year & 0x7F) << 1));
++ buf[2]= (value->year >> 7);
++ str->length+= 3;
++ return ER_DYNCOL_OK;
++}
++
++
++
++/**
++ Read date value of given length from the packed string
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_date_read(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data, size_t length)
++{
++ store_it_here->x.time_value.neg= 0;
++ store_it_here->x.time_value.second_part= 0;
++ store_it_here->x.time_value.hour= 0;
++ store_it_here->x.time_value.minute= 0;
++ store_it_here->x.time_value.second= 0;
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_DATE;
++ return dynamic_column_date_read_internal(store_it_here, data, length);
++}
++
++/**
++ Internal function for reading date part from the string.
++
++ @param store_it_here The structure to store the value
++ @param data The packed string which should be read
++ @param length The length (in bytes) of the value in nthe string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
++ uchar *data,
++ size_t length)
++{
++ if (length != 3)
++ goto err;
++ /*
++ 0<----year----><mn><day>
++ 12345678901234123412345
++ <123456><123456><123456>
++ */
++ store_it_here->x.time_value.day= (data[0] & 0x1f);
++ store_it_here->x.time_value.month= (((data[1] & 0x1) << 3) |
++ (data[0] >> 5));
++ store_it_here->x.time_value.year= ((((uint)data[2]) << 7) |
++ (data[1] >> 1));
++ if (store_it_here->x.time_value.day > 31 ||
++ store_it_here->x.time_value.month > 12 ||
++ store_it_here->x.time_value.year > 9999)
++ goto err;
++ return ER_DYNCOL_OK;
++
++err:
++ store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
++ return ER_DYNCOL_FORMAT;
++}
++
++
++/**
++ Append the string with given value.
++
++ @param str the string where to put the value
++ @param value the value to put in the string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++data_store(DYNAMIC_COLUMN *str, DYNAMIC_COLUMN_VALUE *value,
++ enum enum_dyncol_format format)
++{
++ switch (value->type) {
++ case DYN_COL_INT:
++ return dynamic_column_sint_store(str, value->x.long_value);
++ case DYN_COL_UINT:
++ return dynamic_column_uint_store(str, value->x.ulong_value);
++ case DYN_COL_DOUBLE:
++ return dynamic_column_double_store(str, value->x.double_value);
++ case DYN_COL_STRING:
++ return dynamic_column_string_store(str, &value->x.string.value,
++ value->x.string.charset);
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ return dynamic_column_decimal_store(str, &value->x.decimal.value);
++#endif
++ case DYN_COL_DATETIME:
++ /* date+time in bits: 14 + 4 + 5 + 5 + 6 + 6 40bits = 5 bytes */
++ return dynamic_column_date_time_store(str, &value->x.time_value, format);
++ case DYN_COL_DATE:
++ /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
++ return dynamic_column_date_store(str, &value->x.time_value);
++ case DYN_COL_TIME:
++ /* time in bits: 5 + 6 + 6 = 17bits ~= 3bytes*/
++ return dynamic_column_time_store(str, &value->x.time_value, format);
++ case DYN_COL_DYNCOL:
++ return dynamic_column_dyncol_store(str, &value->x.string.value);
++ case DYN_COL_NULL:
++ break; /* Impossible */
++ }
++ DBUG_ASSERT(0);
++ return ER_DYNCOL_OK; /* Impossible */
++}
++
++
++/**
++ Write information to the fixed header
++
++ @param str String where to write the header
++ @param offset_size Size of offset field in bytes
++ @param column_count Number of columns
++*/
++
++static void set_fixed_header(DYNAMIC_COLUMN *str,
++ uint offset_size,
++ uint column_count)
++{
++ DBUG_ASSERT(column_count <= 0xffff);
++ DBUG_ASSERT(offset_size <= MAX_OFFSET_LENGTH);
++ str->str[0]= ((str->str[0] & ~DYNCOL_FLG_OFFSET) |
++ (offset_size - 1)); /* size of offset */
++ int2store(str->str + 1, column_count); /* columns number */
++ DBUG_ASSERT((str->str[0] & (~DYNCOL_FLG_KNOWN)) == 0);
++}
++
++/**
++ Adds columns into the empty string
++
++ @param str String where to write the data (the record)
++ @param hdr Dynamic columns record descriptor
++ @param column_count Number of columns in the arrays
++ @param column_keys Array of columns keys (uint or LEX_STRING)
++ @param values Array of columns values
++ @param new_str True if we need to allocate new string
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_new_column_store(DYNAMIC_COLUMN *str,
++ DYN_HEADER *hdr,
++ uint column_count,
++ void *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_str)
++{
++ struct st_service_funcs *fmt= fmt_data + hdr->format;
++ void **columns_order;
++ uchar *element;
++ uint i;
++ enum enum_dyncol_func_result rc= ER_DYNCOL_RESOURCE;
++ size_t all_headers_size;
++
++ if (!(columns_order= malloc(sizeof(void*)*column_count)))
++ return ER_DYNCOL_RESOURCE;
++ if (new_str || str->str == 0)
++ {
++ if (column_count)
++ {
++ if (dynamic_column_init_named(str,
++ fmt->fixed_hdr +
++ hdr->header_size +
++ hdr->nmpool_size +
++ hdr->data_size +
++ DYNCOL_SYZERESERVE))
++ goto err;
++ }
++ else
++ {
++ dynamic_column_initialize(str);
++ }
++ }
++ else
++ {
++ str->length= 0;
++ if (dynstr_realloc(str,
++ fmt->fixed_hdr +
++ hdr->header_size +
++ hdr->nmpool_size +
++ hdr->data_size +
++ DYNCOL_SYZERESERVE))
++ goto err;
++ }
++ if (!column_count)
++ return ER_DYNCOL_OK;
++
++ bzero(str->str, fmt->fixed_hdr);
++ str->length= fmt->fixed_hdr;
++
++ /* sort columns for the header */
++ for (i= 0, element= (uchar *) column_keys;
++ i < column_count;
++ i++, element+= fmt->key_size_in_array)
++ columns_order[i]= (void *)element;
++ qsort(columns_order, (size_t)column_count, sizeof(void*), fmt->column_sort);
++
++ /*
++ For now we don't allow creating two columns with the same number
++ at the time of create. This can be fixed later to just use the later
++ by comparing the pointers.
++ */
++ for (i= 0; i < column_count - 1; i++)
++ {
++ if ((*fmt->check_limit)(&columns_order[i]) ||
++ (*fmt->column_sort)(&columns_order[i], &columns_order[i + 1]) == 0)
++ {
++ rc= ER_DYNCOL_DATA;
++ goto err;
++ }
++ }
++ if ((*fmt->check_limit)(&columns_order[i]))
++ {
++ rc= ER_DYNCOL_DATA;
++ goto err;
++ }
++
++ (*fmt->set_fixed_hdr)(str, hdr);
++ /* reserve place for header and name pool */
++ str->length+= hdr->header_size + hdr->nmpool_size;
++
++ hdr->entry= hdr->header;
++ hdr->name= hdr->nmpool;
++ all_headers_size= fmt->fixed_hdr + hdr->header_size + hdr->nmpool_size;
++ for (i= 0; i < column_count; i++)
++ {
++ uint ord= (uint)(((uchar*)columns_order[i] - (uchar*)column_keys) /
++ fmt->key_size_in_array);
++ if (values[ord].type != DYN_COL_NULL)
++ {
++ /* Store header first in the str */
++ if ((*fmt->put_header_entry)(hdr, columns_order[i], values + ord,
++ str->length - all_headers_size))
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++
++ /* Store value in 'str + str->length' and increase str->length */
++ if ((rc= data_store(str, values + ord, hdr->format)))
++ goto err;
++ }
++ }
++ rc= ER_DYNCOL_OK;
++err:
++ free(columns_order);
++ return rc;
++}
++
++/**
++ Calculate size of header, name pool and data pool
++
++ @param hdr descriptor of dynamic column record
++ @param column_count number of elements in arrays
++ @param column_count Number of columns in the arrays
++ @param column_keys Array of columns keys (uint or LEX_STRING)
++ @param values Array of columns values
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++calc_var_sizes(DYN_HEADER *hdr,
++ uint column_count,
++ void *column_keys,
++ DYNAMIC_COLUMN_VALUE *values)
++{
++ struct st_service_funcs *fmt= fmt_data + hdr->format;
++ uint i;
++ hdr->nmpool_size= hdr->data_size= 0;
++ hdr->column_count= 0;
++ for (i= 0; i < column_count; i++)
++ {
++ if (values[i].type != DYN_COL_NULL)
++ {
++ size_t tmp;
++ hdr->column_count++;
++ hdr->data_size+= (tmp= dynamic_column_value_len(values + i,
++ hdr->format));
++ if (tmp == (size_t) ~0)
++ return ER_DYNCOL_DATA;
++ hdr->nmpool_size+= (*fmt->name_size)(column_keys, i);
++ }
++ }
++ /*
++ We can handle data up to 0x1fffffff (old format) and
++ 0xfffffffff (new format) bytes now.
++ */
++ if ((hdr->offset_size= fmt->dynamic_column_offset_bytes(hdr->data_size)) >=
++ fmt->max_offset_size)
++ return ER_DYNCOL_LIMIT;
++
++ /* header entry is column number or string pointer + offset & type */
++ hdr->entry_size= fmt->fixed_hdr_entry + hdr->offset_size;
++ hdr->header_size= hdr->column_count * hdr->entry_size;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Create packed string which contains given columns (internal multi format)
++
++ @param str String where to write the data
++ @param column_count Number of columns in the arrays
++ @param column_keys Array of columns keys (format dependent)
++ @param values Array of columns values
++ @param new_str True if we need allocate new string
++ @param string_keys keys are strings
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_create_many_internal_fmt(DYNAMIC_COLUMN *str,
++ uint column_count,
++ void *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_str,
++ my_bool string_keys)
++{
++ DYN_HEADER header;
++ enum enum_dyncol_func_result rc;
++ bzero(&header, sizeof(header));
++ header.format= (string_keys ? 1 : 0);
++
++ if (new_str)
++ {
++ /* to make dynstr_free() working in case of errors */
++ bzero(str, sizeof(DYNAMIC_COLUMN));
++ }
++
++ if ((rc= calc_var_sizes(&header, column_count, column_keys, values)) < 0)
++ return rc;
++
++ return dynamic_new_column_store(str, &header,
++ column_count,
++ column_keys, values,
++ new_str);
++}
++
++
++/**
++ Create packed string which contains given columns
++
++ @param str String where to write the data
++ @param column_count Number of columns in the arrays
++ @param column_numbers Array of columns numbers
++ @param values Array of columns values
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++dynamic_column_create_many(DYNAMIC_COLUMN *str,
++ uint column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values)
++{
++ DBUG_ENTER("dynamic_column_create_many");
++ DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
++ column_numbers, values,
++ TRUE, FALSE));
++}
++
++/**
++ Create packed string which contains given columns
++
++ @param str String where to write the data
++ @param column_count Number of columns in the arrays
++ @param column_numbers Array of columns numbers
++ @param values Array of columns values
++ @param new_string True if we need allocate new string
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str,
++ uint column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_string)
++{
++ DBUG_ENTER("mariadb_dyncol_create_many");
++ DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
++ column_numbers, values,
++ new_string, FALSE));
++}
++
++/**
++ Create packed string which contains given columns
++
++ @param str String where to write the data
++ @param column_count Number of columns in the arrays
++ @param column_keys Array of columns keys
++ @param values Array of columns value
++ @param new_string True if we need allocate new string
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
++ uint column_count,
++ LEX_STRING *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool new_string)
++{
++ DBUG_ENTER("mariadb_dyncol_create_many_named");
++ DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
++ column_keys, values,
++ new_string, TRUE));
++}
++
++/**
++ Create packed string which contains given column
++
++ @param str String where to write the data
++ @param column_number Column number
++ @param value The columns value
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *value)
++{
++ DBUG_ENTER("dynamic_column_create");
++ DBUG_RETURN(dynamic_column_create_many(str, 1, &column_nr, value));
++}
++
++
++/**
++ Calculate length of data between given two header entries
++
++ @param entry Pointer to the first entry
++ @param entry_next Pointer to the last entry
++ @param header_end Pointer to the header end
++ @param offset_size Size of offset field in bytes
++ @param last_offset Size of the data segment
++
++ @return number of bytes
++*/
++
++static size_t get_length_interval(uchar *entry, uchar *entry_next,
++ uchar *header_end, size_t offset_size,
++ size_t last_offset)
++{
++ size_t offset, offset_next;
++ DYNAMIC_COLUMN_TYPE type, type_next;
++ DBUG_ASSERT(entry < entry_next);
++
++ if (type_and_offset_read_num(&type, &offset, entry + COLUMN_NUMBER_SIZE,
++ offset_size))
++ return DYNCOL_OFFSET_ERROR;
++ if (entry_next >= header_end)
++ return (last_offset - offset);
++ if (type_and_offset_read_num(&type_next, &offset_next,
++ entry_next + COLUMN_NUMBER_SIZE, offset_size))
++ return DYNCOL_OFFSET_ERROR;
++ return (offset_next - offset);
++}
++
++
++/**
++ Calculate length of data between given hdr->entry and next_entry
++
++ @param hdr descriptor of dynamic column record
++ @param next_entry next header entry (can point just after last header
++ entry)
++
++ @return number of bytes
++*/
++
++static size_t hdr_interval_length(DYN_HEADER *hdr, uchar *next_entry)
++{
++ struct st_service_funcs *fmt= fmt_data + hdr->format;
++ size_t next_entry_offset;
++ DYNAMIC_COLUMN_TYPE next_entry_type;
++ DBUG_ASSERT(hdr->entry < next_entry);
++ DBUG_ASSERT(hdr->entry >= hdr->header);
++ DBUG_ASSERT(next_entry <= hdr->header + hdr->header_size);
++
++ if ((*fmt->type_and_offset_read)(&hdr->type, &hdr->offset,
++ hdr->entry + fmt->fixed_hdr_entry,
++ hdr->offset_size))
++ return DYNCOL_OFFSET_ERROR;
++ if (next_entry == hdr->header + hdr->header_size)
++ return hdr->data_size - hdr->offset;
++ if ((*fmt->type_and_offset_read)(&next_entry_type, &next_entry_offset,
++ next_entry + fmt->fixed_hdr_entry,
++ hdr->offset_size))
++ return DYNCOL_OFFSET_ERROR;
++ return (next_entry_offset - hdr->offset);
++}
++
++
++/**
++ Comparator function for references to header entries for qsort
++*/
++
++static int header_compar_num(const void *a, const void *b)
++{
++ uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
++ return (va > vb ? 1 : (va < vb ? -1 : 0));
++}
++
++
++/**
++ Find entry in the numeric format header by the column number
++
++ @param hdr descriptor of dynamic column record
++ @param key number to find
++
++ @return pointer to the entry or NULL
++*/
++
++static uchar *find_entry_num(DYN_HEADER *hdr, uint key)
++{
++ uchar header_entry[2+4];
++ DBUG_ASSERT(hdr->format == dyncol_fmt_num);
++ int2store(header_entry, key);
++ return hdr->entry= bsearch(header_entry, hdr->header,
++ (size_t)hdr->column_count,
++ hdr->entry_size, &header_compar_num);
++}
++
++
++/**
++ Read name from header entry
++
++ @param hdr descriptor of dynamic column record
++ @param entry pointer to the header entry
++ @param name where to put name
++
++ @return 0 ok
++ @return 1 error in data
++*/
++
++static my_bool read_name(DYN_HEADER *hdr, uchar *entry, LEX_STRING *name)
++{
++ size_t nmoffset= uint2korr(entry);
++ uchar *next_entry= entry + hdr->entry_size;
++
++ if (nmoffset > hdr->nmpool_size)
++ return 1;
++
++ name->str= (char *)hdr->nmpool + nmoffset;
++ if (next_entry == hdr->header + hdr->header_size)
++ name->length= hdr->nmpool_size - nmoffset;
++ else
++ {
++ size_t next_nmoffset= uint2korr(next_entry);
++ if (next_nmoffset > hdr->nmpool_size)
++ return 1;
++ name->length= next_nmoffset - nmoffset;
++ }
++ return 0;
++}
++
++
++/**
++ Find entry in the names format header by the column number
++
++ @param hdr descriptor of dynamic column record
++ @param key name to find
++
++ @return pointer to the entry or NULL
++*/
++static uchar *find_entry_named(DYN_HEADER *hdr, LEX_STRING *key)
++{
++ uchar *min= hdr->header;
++ uchar *max= hdr->header + (hdr->column_count - 1) * hdr->entry_size;
++ uchar *mid;
++ DBUG_ASSERT(hdr->format == dyncol_fmt_str);
++ DBUG_ASSERT(hdr->nmpool != NULL);
++ while (max >= min)
++ {
++ LEX_STRING name;
++ int cmp;
++ mid= hdr->header + ((min - hdr->header) +
++ (max - hdr->header)) /
++ 2 /
++ hdr->entry_size * hdr->entry_size;
++ if (read_name(hdr, mid, &name))
++ return NULL;
++ cmp= mariadb_dyncol_column_cmp_named(&name, key);
++ if (cmp < 0)
++ min= mid + hdr->entry_size;
++ else if (cmp > 0)
++ max= mid - hdr->entry_size;
++ else
++ return mid;
++ }
++ return NULL;
++}
++
++
++/**
++ Write number in the buffer (backward direction - starts from the buffer end)
++
++ @return pointer on the number begining
++*/
++
++static char *backwritenum(char *chr, uint numkey)
++{
++ if (numkey == 0)
++ *(--chr)= '0';
++ else
++ while (numkey > 0)
++ {
++ *(--chr)= '0' + numkey % 10;
++ numkey/= 10;
++ }
++ return chr;
++}
++
++
++/**
++ Find column and fill information about it
++
++ @param hdr descriptor of dynamic column record
++ @param numkey Number of the column to fetch (if strkey is NULL)
++ @param strkey Name of the column to fetch (or NULL)
++
++ @return 0 ok
++ @return 1 error in data
++*/
++
++static my_bool
++find_column(DYN_HEADER *hdr, uint numkey, LEX_STRING *strkey)
++{
++ LEX_STRING nmkey;
++ char nmkeybuff[DYNCOL_NUM_CHAR]; /* to fit max 2 bytes number */
++ DBUG_ASSERT(hdr->header != NULL);
++
++ if (hdr->header + hdr->header_size > hdr->data_end)
++ return TRUE;
++
++ /* fix key */
++ if (hdr->format == dyncol_fmt_num && strkey != NULL)
++ {
++ char *end;
++ numkey= (uint) strtoul(strkey->str, &end, 10);
++ if (end != strkey->str + strkey->length)
++ {
++ /* we can't find non-numeric key among numeric ones */
++ hdr->type= DYN_COL_NULL;
++ return 0;
++ }
++ }
++ else if (hdr->format == dyncol_fmt_str && strkey == NULL)
++ {
++ nmkey.str= backwritenum(nmkeybuff + sizeof(nmkeybuff), numkey);
++ nmkey.length= (nmkeybuff + sizeof(nmkeybuff)) - nmkey.str;
++ strkey= &nmkey;
++ }
++ if (hdr->format == dyncol_fmt_num)
++ hdr->entry= find_entry_num(hdr, numkey);
++ else
++ hdr->entry= find_entry_named(hdr, strkey);
++
++ if (!hdr->entry)
++ {
++ /* Column not found */
++ hdr->type= DYN_COL_NULL;
++ return 0;
++ }
++ hdr->length= hdr_interval_length(hdr, hdr->entry + hdr->entry_size);
++ hdr->data= hdr->dtpool + hdr->offset;
++ /*
++ Check that the found data is withing the ranges. This can happen if
++ we get data with wrong offsets.
++ */
++ if (hdr->length == DYNCOL_OFFSET_ERROR ||
++ hdr->length > INT_MAX || hdr->offset > hdr->data_size)
++ return 1;
++
++ return 0;
++}
++
++
++/**
++ Read and check the header of the dynamic string
++
++ @param hdr descriptor of dynamic column record
++ @param str Dynamic string
++
++ @retval FALSE OK
++ @retval TRUE error
++
++ Note
++ We don't check for str->length == 0 as all code that calls this
++ already have handled this case.
++*/
++
++static inline my_bool read_fixed_header(DYN_HEADER *hdr,
++ DYNAMIC_COLUMN *str)
++{
++ DBUG_ASSERT(str != NULL && str->length != 0);
++ if ((str->length < 1) ||
++ (str->str[0] & (~DYNCOL_FLG_KNOWN)))
++ return 1;
++ hdr->format= ((str->str[0] & DYNCOL_FLG_NAMES) ?
++ dyncol_fmt_str:
++ dyncol_fmt_num);
++ if ((str->length < fmt_data[hdr->format].fixed_hdr))
++ return 1; /* Wrong header */
++ hdr->offset_size= (str->str[0] & DYNCOL_FLG_OFFSET) + 1 +
++ (hdr->format == dyncol_fmt_str ? 1 : 0);
++ hdr->column_count= uint2korr(str->str + 1);
++ if (hdr->format == dyncol_fmt_str)
++ hdr->nmpool_size= uint2korr(str->str + 3); // only 2 bytes supported for now
++ else
++ hdr->nmpool_size= 0;
++ return 0;
++}
++
++
++/**
++ Get dynamic column value by column number
++
++ @param str The packed string to extract the column
++ @param column_nr Number of column to fetch
++ @param store_it_here Where to store the extracted value
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *store_it_here)
++{
++ return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_get_num(DYNAMIC_COLUMN *str, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *store_it_here)
++{
++ return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
++}
++
++
++/**
++ Get dynamic column value by name
++
++ @param str The packed string to extract the column
++ @param name Name of column to fetch
++ @param store_it_here Where to store the extracted value
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, LEX_STRING *name,
++ DYNAMIC_COLUMN_VALUE *store_it_here)
++{
++ DBUG_ASSERT(name != NULL);
++ return dynamic_column_get_internal(str, store_it_here, 0, name);
++}
++
++
++static enum enum_dyncol_func_result
++dynamic_column_get_value(DYN_HEADER *hdr, DYNAMIC_COLUMN_VALUE *store_it_here)
++{
++ static enum enum_dyncol_func_result rc;
++ switch ((store_it_here->type= hdr->type)) {
++ case DYN_COL_INT:
++ rc= dynamic_column_sint_read(store_it_here, hdr->data, hdr->length);
++ break;
++ case DYN_COL_UINT:
++ rc= dynamic_column_uint_read(store_it_here, hdr->data, hdr->length);
++ break;
++ case DYN_COL_DOUBLE:
++ rc= dynamic_column_double_read(store_it_here, hdr->data, hdr->length);
++ break;
++ case DYN_COL_STRING:
++ rc= dynamic_column_string_read(store_it_here, hdr->data, hdr->length);
++ break;
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ rc= dynamic_column_decimal_read(store_it_here, hdr->data, hdr->length);
++ break;
++#endif
++ case DYN_COL_DATETIME:
++ rc= dynamic_column_date_time_read(store_it_here, hdr->data,
++ hdr->length);
++ break;
++ case DYN_COL_DATE:
++ rc= dynamic_column_date_read(store_it_here, hdr->data, hdr->length);
++ break;
++ case DYN_COL_TIME:
++ rc= dynamic_column_time_read(store_it_here, hdr->data, hdr->length);
++ break;
++ case DYN_COL_NULL:
++ rc= ER_DYNCOL_OK;
++ break;
++ case DYN_COL_DYNCOL:
++ rc= dynamic_column_dyncol_read(store_it_here, hdr->data, hdr->length);
++ break;
++ default:
++ rc= ER_DYNCOL_FORMAT;
++ store_it_here->type= DYN_COL_NULL;
++ break;
++ }
++ return rc;
++}
++
++/**
++ Get dynamic column value by number or name
++
++ @param str The packed string to extract the column
++ @param store_it_here Where to store the extracted value
++ @param numkey Number of the column to fetch (if strkey is NULL)
++ @param strkey Name of the column to fetch (or NULL)
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_get_internal(DYNAMIC_COLUMN *str,
++ DYNAMIC_COLUMN_VALUE *store_it_here,
++ uint num_key, LEX_STRING *str_key)
++{
++ DYN_HEADER header;
++ enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
++ bzero(&header, sizeof(header));
++
++ if (str->length == 0)
++ goto null;
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ goto err;
++
++ if (header.column_count == 0)
++ goto null;
++
++ if (find_column(&header, num_key, str_key))
++ goto err;
++
++ rc= dynamic_column_get_value(&header, store_it_here);
++ return rc;
++
++null:
++ rc= ER_DYNCOL_OK;
++err:
++ store_it_here->type= DYN_COL_NULL;
++ return rc;
++}
++
++
++/**
++ Check existence of the column in the packed string (by number)
++
++ @param str The packed string to check the column
++ @param column_nr Number of column to check
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_exists_num(DYNAMIC_COLUMN *str, uint column_nr)
++{
++ return dynamic_column_exists_internal(str, column_nr, NULL);
++}
++
++/**
++ Check existence of the column in the packed string (by name)
++
++ @param str The packed string to check the column
++ @param name Name of column to check
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, LEX_STRING *name)
++{
++ DBUG_ASSERT(name != NULL);
++ return dynamic_column_exists_internal(str, 0, name);
++}
++
++
++/**
++ Check existence of the column in the packed string (by name of number)
++
++ @param str The packed string to check the column
++ @param num_key Number of the column to fetch (if strkey is NULL)
++ @param str_key Name of the column to fetch (or NULL)
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_exists_internal(DYNAMIC_COLUMN *str, uint num_key,
++ LEX_STRING *str_key)
++{
++ DYN_HEADER header;
++ enum enum_dyncol_func_result rc;
++ bzero(&header, sizeof(header));
++
++ if (str->length == 0)
++ return ER_DYNCOL_NO; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++
++ if (header.column_count == 0)
++ return ER_DYNCOL_NO; /* no columns */
++
++ if (find_column(&header, num_key, str_key))
++ return ER_DYNCOL_FORMAT;
++
++ return (header.type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
++}
++
++
++/**
++ List not-null columns in the packed string (only numeric format)
++
++ @param str The packed string
++ @param array_of_uint Where to put reference on created array
++
++ @return ER_DYNCOL_* return code
++*/
++enum enum_dyncol_func_result
++dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
++{
++ DYN_HEADER header;
++ uchar *read;
++ uint i;
++ enum enum_dyncol_func_result rc;
++
++ bzero(array_of_uint, sizeof(*array_of_uint)); /* In case of errors */
++ if (str->length == 0)
++ return ER_DYNCOL_OK; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++
++ if (header.format != dyncol_fmt_num)
++ return ER_DYNCOL_FORMAT;
++
++ if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
++ str->length)
++ return ER_DYNCOL_FORMAT;
++
++ if (my_init_dynamic_array(array_of_uint, sizeof(uint), header.column_count, 0))
++ return ER_DYNCOL_RESOURCE;
++
++ for (i= 0, read= header.header;
++ i < header.column_count;
++ i++, read+= header.entry_size)
++ {
++ uint nm= uint2korr(read);
++ /* Insert can't never fail as it's pre-allocated above */
++ (void) insert_dynamic(array_of_uint, (uchar *)&nm);
++ }
++ return ER_DYNCOL_OK;
++}
++
++/**
++ List not-null columns in the packed string (only numeric format)
++
++ @param str The packed string
++ @param array_of_uint Where to put reference on created array
++
++ @return ER_DYNCOL_* return code
++*/
++enum enum_dyncol_func_result
++mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums)
++{
++ DYN_HEADER header;
++ uchar *read;
++ uint i;
++ enum enum_dyncol_func_result rc;
++
++ (*nums)= 0; (*count)= 0; /* In case of errors */
++ if (str->length == 0)
++ return ER_DYNCOL_OK; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++
++ if (header.format != dyncol_fmt_num)
++ return ER_DYNCOL_FORMAT;
++
++ if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
++ str->length)
++ return ER_DYNCOL_FORMAT;
++
++ if (!((*nums)= (uint *)my_malloc(sizeof(uint) * header.column_count, MYF(0))))
++ return ER_DYNCOL_RESOURCE;
++
++ for (i= 0, read= header.header;
++ i < header.column_count;
++ i++, read+= header.entry_size)
++ {
++ (*nums)[i]= uint2korr(read);
++ }
++ (*count)= header.column_count;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ List not-null columns in the packed string (any format)
++
++ @param str The packed string
++ @param count Number of names in the list
++ @param names Where to put names list (should be freed)
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, LEX_STRING **names)
++{
++ DYN_HEADER header;
++ uchar *read;
++ char *pool;
++ struct st_service_funcs *fmt;
++ uint i;
++ enum enum_dyncol_func_result rc;
++
++ (*names)= 0; (*count)= 0;
++
++ if (str->length == 0)
++ return ER_DYNCOL_OK; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++
++ fmt= fmt_data + header.format;
++
++ if (header.entry_size * header.column_count + fmt->fixed_hdr >
++ str->length)
++ return ER_DYNCOL_FORMAT;
++
++ if (header.format == dyncol_fmt_num)
++ *names= (LEX_STRING *)my_malloc(sizeof(LEX_STRING) * header.column_count +
++ DYNCOL_NUM_CHAR * header.column_count, MYF(0));
++ else
++ *names= (LEX_STRING *)my_malloc(sizeof(LEX_STRING) * header.column_count +
++ header.nmpool_size + header.column_count, MYF(0));
++ if (!(*names))
++ return ER_DYNCOL_RESOURCE;
++ pool= ((char *)(*names)) + sizeof(LEX_STRING) * header.column_count;
++
++ for (i= 0, read= header.header;
++ i < header.column_count;
++ i++, read+= header.entry_size)
++ {
++ if (header.format == dyncol_fmt_num)
++ {
++ uint nm= uint2korr(read);
++ (*names)[i].str= pool;
++ pool+= DYNCOL_NUM_CHAR;
++ (*names)[i].length=
++ longlong2str(nm, (*names)[i].str, 10) - (*names)[i].str;
++ }
++ else
++ {
++ LEX_STRING tmp;
++ if (read_name(&header, read, &tmp))
++ return ER_DYNCOL_FORMAT;
++ (*names)[i].length= tmp.length;
++ (*names)[i].str= pool;
++ pool+= tmp.length + 1;
++ memcpy((*names)[i].str, (const void *)tmp.str, tmp.length);
++ (*names)[i].str[tmp.length]= '\0'; // just for safety
++ }
++ }
++ (*count)= header.column_count;
++ return ER_DYNCOL_OK;
++}
++
++/**
++ Find the place of the column in the header or place where it should be put
++
++ @param hdr descriptor of dynamic column record
++ @param key Name or number of column to fetch
++ (depends on string_key)
++ @param string_key True if we gave pointer to LEX_STRING.
++
++ @retval TRUE found
++ @retval FALSE pointer set to the next row
++*/
++
++static my_bool
++find_place(DYN_HEADER *hdr, void *key, my_bool string_keys)
++{
++ uint mid, start, end, val;
++ int UNINIT_VAR(flag);
++ LEX_STRING str;
++ char buff[DYNCOL_NUM_CHAR];
++ my_bool need_conversion= ((string_keys ? dyncol_fmt_str : dyncol_fmt_num) !=
++ hdr->format);
++ /* new format can't be numeric if the old one is names */
++ DBUG_ASSERT(string_keys ||
++ hdr->format == dyncol_fmt_num);
++
++ start= 0;
++ end= hdr->column_count -1;
++ mid= 1;
++ while (start != end)
++ {
++ uint val;
++ mid= (start + end) / 2;
++ hdr->entry= hdr->header + mid * hdr->entry_size;
++ if (!string_keys)
++ {
++ val= uint2korr(hdr->entry);
++ flag= CMP_NUM(*((uint *)key), val);
++ }
++ else
++ {
++ if (need_conversion)
++ {
++ str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
++ str.length= (buff + sizeof(buff)) - str.str;
++ }
++ else
++ {
++ DBUG_ASSERT(hdr->format == dyncol_fmt_str);
++ if (read_name(hdr, hdr->entry, &str))
++ return 0;
++ }
++ flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
++ }
++ if (flag <= 0)
++ end= mid;
++ else
++ start= mid + 1;
++ }
++ hdr->entry= hdr->header + start * hdr->entry_size;
++ if (start != mid)
++ {
++ if (!string_keys)
++ {
++ val= uint2korr(hdr->entry);
++ flag= CMP_NUM(*((uint *)key), val);
++ }
++ else
++ {
++ if (need_conversion)
++ {
++ str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
++ str.length= (buff + sizeof(buff)) - str.str;
++ }
++ else
++ {
++ DBUG_ASSERT(hdr->format == dyncol_fmt_str);
++ if (read_name(hdr, hdr->entry, &str))
++ return 0;
++ }
++ flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
++ }
++ }
++ if (flag > 0)
++ hdr->entry+= hdr->entry_size; /* Point at next bigger key */
++ return flag == 0;
++}
++
++
++/*
++ It is internal structure which describes a plan of changing the record
++ of dynamic columns
++*/
++
++typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
++
++struct st_plan {
++ DYNAMIC_COLUMN_VALUE *val;
++ void *key;
++ uchar *place;
++ size_t length;
++ long long hdelta, ddelta, ndelta;
++ long long mv_offset, mv_length;
++ uint mv_end;
++ PLAN_ACT act;
++};
++typedef struct st_plan PLAN;
++
++
++/**
++ Sort function for plan by column number
++*/
++
++static int plan_sort_num(const void *a, const void *b)
++{
++ return *((uint *)((PLAN *)a)->key) - *((uint *)((PLAN *)b)->key);
++}
++
++
++/**
++ Sort function for plan by column name
++*/
++
++static int plan_sort_named(const void *a, const void *b)
++{
++ return mariadb_dyncol_column_cmp_named((LEX_STRING *)((PLAN *)a)->key,
++ (LEX_STRING *)((PLAN *)b)->key);
++}
++
++#define DELTA_CHECK(S, D, C) \
++ if ((S) == 0) \
++ (S)= (D); \
++ else if (((S) > 0 && (D) < 0) || \
++ ((S) < 0 && (D) > 0)) \
++ { \
++ (C)= TRUE; \
++ }
++
++/**
++ Update dynamic column by copying in a new record (string).
++
++ @param str Dynamic column record to change
++ @param plan Plan of changing the record
++ @param add_column_count number of records in the plan array.
++ @param hdr descriptor of old dynamic column record
++ @param new_hdr descriptor of new dynamic column record
++ @param convert need conversion from numeric to names format
++
++ @return ER_DYNCOL_* return code
++*/
++
++static enum enum_dyncol_func_result
++dynamic_column_update_copy(DYNAMIC_COLUMN *str, PLAN *plan,
++ uint add_column_count,
++ DYN_HEADER *hdr, DYN_HEADER *new_hdr,
++ my_bool convert)
++{
++ DYNAMIC_COLUMN tmp;
++ struct st_service_funcs *fmt= fmt_data + hdr->format,
++ *new_fmt= fmt_data + new_hdr->format;
++ uint i, j, k;
++ size_t all_headers_size;
++
++ if (dynamic_column_init_named(&tmp,
++ (new_fmt->fixed_hdr + new_hdr->header_size +
++ new_hdr->nmpool_size +
++ new_hdr->data_size + DYNCOL_SYZERESERVE)))
++ {
++ return ER_DYNCOL_RESOURCE;
++ }
++ bzero(tmp.str, new_fmt->fixed_hdr);
++ (*new_fmt->set_fixed_hdr)(&tmp, new_hdr);
++ /* Adjust tmp to contain whole the future header */
++ tmp.length= new_fmt->fixed_hdr + new_hdr->header_size + new_hdr->nmpool_size;
++
++
++ /*
++ Copy data to the new string
++ i= index in array of changes
++ j= index in packed string header index
++ */
++ new_hdr->entry= new_hdr->header;
++ new_hdr->name= new_hdr->nmpool;
++ all_headers_size= new_fmt->fixed_hdr +
++ new_hdr->header_size + new_hdr->nmpool_size;
++ for (i= 0, j= 0; i < add_column_count || j < hdr->column_count; i++)
++ {
++ size_t UNINIT_VAR(first_offset);
++ uint start= j, end;
++
++ /*
++ Search in i and j for the next column to add from i and where to
++ add.
++ */
++
++ while (i < add_column_count && plan[i].act == PLAN_NOP)
++ i++; /* skip NOP */
++
++ if (i == add_column_count)
++ j= end= hdr->column_count;
++ else
++ {
++ /*
++ old data portion. We don't need to check that j < column_count
++ as plan[i].place is guaranteed to have a pointer inside the
++ data.
++ */
++ while (hdr->header + j * hdr->entry_size < plan[i].place)
++ j++;
++ end= j;
++ if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
++ j++; /* data at 'j' will be removed */
++ }
++
++ /*
++ Adjust all headers since last loop.
++ We have to do this as the offset for data has moved
++ */
++ for (k= start; k < end; k++)
++ {
++ uchar *read= hdr->header + k * hdr->entry_size;
++ void *key;
++ LEX_STRING name;
++ size_t offs;
++ uint nm;
++ DYNAMIC_COLUMN_TYPE tp;
++ char buff[DYNCOL_NUM_CHAR];
++
++ if (hdr->format == dyncol_fmt_num)
++ {
++ if (convert)
++ {
++ name.str= backwritenum(buff + sizeof(buff), uint2korr(read));
++ name.length= (buff + sizeof(buff)) - name.str;
++ key= &name;
++ }
++ else
++ {
++ nm= uint2korr(read); /* Column nummber */
++ key= &nm;
++ }
++ }
++ else
++ {
++ if (read_name(hdr, read, &name))
++ goto err;
++ key= &name;
++ }
++ if (fmt->type_and_offset_read(&tp, &offs,
++ read + fmt->fixed_hdr_entry,
++ hdr->offset_size))
++ goto err;
++ if (k == start)
++ first_offset= offs;
++ else if (offs < first_offset)
++ goto err;
++
++ offs+= (size_t)plan[i].ddelta;
++ {
++ DYNAMIC_COLUMN_VALUE val;
++ val.type= tp; // only the type used in the header
++ if ((*new_fmt->put_header_entry)(new_hdr, key, &val, offs))
++ goto err;
++ }
++ }
++
++ /* copy first the data that was not replaced in original packed data */
++ if (start < end)
++ {
++ size_t data_size;
++ /* Add old data last in 'tmp' */
++ hdr->entry= hdr->header + start * hdr->entry_size;
++ data_size=
++ hdr_interval_length(hdr, hdr->header + end * hdr->entry_size);
++ if (data_size == DYNCOL_OFFSET_ERROR ||
++ (long) data_size < 0 ||
++ data_size > hdr->data_size - first_offset)
++ goto err;
++
++ memcpy(tmp.str + tmp.length, (char *)hdr->dtpool + first_offset,
++ data_size);
++ tmp.length+= data_size;
++ }
++
++ /* new data adding */
++ if (i < add_column_count)
++ {
++ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
++ {
++ if ((*new_fmt->put_header_entry)(new_hdr, plan[i].key,
++ plan[i].val,
++ tmp.length - all_headers_size))
++ goto err;
++ data_store(&tmp, plan[i].val, new_hdr->format); /* Append new data */
++ }
++ }
++ }
++ dynamic_column_column_free(str);
++ *str= tmp;
++ return ER_DYNCOL_OK;
++err:
++ dynamic_column_column_free(&tmp);
++ return ER_DYNCOL_FORMAT;
++}
++
++static enum enum_dyncol_func_result
++dynamic_column_update_move_left(DYNAMIC_COLUMN *str, PLAN *plan,
++ size_t offset_size,
++ size_t entry_size,
++ size_t header_size,
++ size_t new_offset_size,
++ size_t new_entry_size,
++ size_t new_header_size,
++ uint column_count,
++ uint new_column_count,
++ uint add_column_count,
++ uchar *header_end,
++ size_t max_offset)
++{
++ uchar *write;
++ uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
++ uint i, j, k;
++ size_t curr_offset;
++
++ write= (uchar *)str->str + FIXED_HEADER_SIZE;
++ set_fixed_header(str, (uint)new_offset_size, new_column_count);
++
++ /*
++ Move headers first.
++ i= index in array of changes
++ j= index in packed string header index
++ */
++ for (curr_offset= 0, i= 0, j= 0;
++ i < add_column_count || j < column_count;
++ i++)
++ {
++ size_t UNINIT_VAR(first_offset);
++ uint start= j, end;
++
++ /*
++ Search in i and j for the next column to add from i and where to
++ add.
++ */
++
++ while (i < add_column_count && plan[i].act == PLAN_NOP)
++ i++; /* skip NOP */
++
++ if (i == add_column_count)
++ j= end= column_count;
++ else
++ {
++ /*
++ old data portion. We don't need to check that j < column_count
++ as plan[i].place is guaranteed to have a pointer inside the
++ data.
++ */
++ while (header_base + j * entry_size < plan[i].place)
++ j++;
++ end= j;
++ if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
++ j++; /* data at 'j' will be removed */
++ }
++ plan[i].mv_end= end;
++
++ {
++ DYNAMIC_COLUMN_TYPE tp;
++ if (type_and_offset_read_num(&tp, &first_offset,
++ header_base + start * entry_size +
++ COLUMN_NUMBER_SIZE, offset_size))
++ return ER_DYNCOL_FORMAT;
++ }
++ /* find data to be moved */
++ if (start < end)
++ {
++ size_t data_size=
++ get_length_interval(header_base + start * entry_size,
++ header_base + end * entry_size,
++ header_end, offset_size, max_offset);
++ if (data_size == DYNCOL_OFFSET_ERROR ||
++ (long) data_size < 0 ||
++ data_size > max_offset - first_offset)
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++ DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
++ plan[i].mv_offset= first_offset;
++ plan[i].mv_length= data_size;
++ curr_offset+= data_size;
++ }
++ else
++ {
++ plan[i].mv_length= 0;
++ plan[i].mv_offset= curr_offset;
++ }
++
++ if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
++ plan[i].act != PLAN_DELETE)
++ write+= entry_size * (end - start);
++ else
++ {
++ /*
++ Adjust all headers since last loop.
++ We have to do this as the offset for data has moved
++ */
++ for (k= start; k < end; k++)
++ {
++ uchar *read= header_base + k * entry_size;
++ size_t offs;
++ uint nm;
++ DYNAMIC_COLUMN_TYPE tp;
++
++ nm= uint2korr(read); /* Column nummber */
++ if (type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
++ offset_size))
++ return ER_DYNCOL_FORMAT;
++
++ if (k > start && offs < first_offset)
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++
++ offs+= (size_t)plan[i].ddelta;
++ int2store(write, nm);
++ /* write rest of data at write + COLUMN_NUMBER_SIZE */
++ type_and_offset_store_num(write, new_offset_size, tp, offs);
++ write+= new_entry_size;
++ }
++ }
++
++ /* new data adding */
++ if (i < add_column_count)
++ {
++ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
++ {
++ int2store(write, *((uint *)plan[i].key));
++ type_and_offset_store_num(write, new_offset_size,
++ plan[i].val[0].type,
++ curr_offset);
++ write+= new_entry_size;
++ curr_offset+= plan[i].length;
++ }
++ }
++ }
++
++ /*
++ Move data.
++ i= index in array of changes
++ j= index in packed string header index
++ */
++ str->length= (FIXED_HEADER_SIZE + new_header_size);
++ for (i= 0, j= 0;
++ i < add_column_count || j < column_count;
++ i++)
++ {
++ uint start= j, end;
++
++ /*
++ Search in i and j for the next column to add from i and where to
++ add.
++ */
++
++ while (i < add_column_count && plan[i].act == PLAN_NOP)
++ i++; /* skip NOP */
++
++ j= end= plan[i].mv_end;
++ if (i != add_column_count &&
++ (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
++ j++;
++
++ /* copy first the data that was not replaced in original packed data */
++ if (start < end && plan[i].mv_length)
++ {
++ memmove((header_base + new_header_size +
++ (size_t)plan[i].mv_offset + (size_t)plan[i].ddelta),
++ header_base + header_size + (size_t)plan[i].mv_offset,
++ (size_t)plan[i].mv_length);
++ }
++ str->length+= (size_t)plan[i].mv_length;
++
++ /* new data adding */
++ if (i < add_column_count)
++ {
++ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
++ {
++ data_store(str, plan[i].val, dyncol_fmt_num);/* Append new data */
++ }
++ }
++ }
++ return ER_DYNCOL_OK;
++}
++
++#ifdef UNUSED
++static enum enum_dyncol_func_result
++dynamic_column_update_move_right(DYNAMIC_COLUMN *str, PLAN *plan,
++ size_t offset_size,
++ size_t entry_size,
++ size_t header_size,
++ size_t new_offset_size,
++ size_t new_entry_size,
++ size_t new_header_size,
++ uint column_count,
++ uint new_column_count,
++ uint add_column_count,
++ uchar *header_end,
++ size_t max_offset)
++{
++ uchar *write;
++ uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
++ uint i, j, k;
++ size_t curr_offset;
++
++ write= (uchar *)str->str + FIXED_HEADER_SIZE;
++ set_fixed_header(str, new_offset_size, new_column_count);
++
++ /*
++ Move data first.
++ i= index in array of changes
++ j= index in packed string header index
++ */
++ for (curr_offset= 0, i= 0, j= 0;
++ i < add_column_count || j < column_count;
++ i++)
++ {
++ size_t UNINIT_VAR(first_offset);
++ uint start= j, end;
++
++ /*
++ Search in i and j for the next column to add from i and where to
++ add.
++ */
++
++ while (i < add_column_count && plan[i].act == PLAN_NOP)
++ i++; /* skip NOP */
++
++ if (i == add_column_count)
++ j= end= column_count;
++ else
++ {
++ /*
++ old data portion. We don't need to check that j < column_count
++ as plan[i].place is guaranteed to have a pointer inside the
++ data.
++ */
++ while (header_base + j * entry_size < plan[i].place)
++ j++;
++ end= j;
++ if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
++ j++; /* data at 'j' will be removed */
++ }
++ plan[i].mv_end= end;
++
++ {
++ DYNAMIC_COLUMN_TYPE tp;
++ type_and_offset_read_num(&tp, &first_offset,
++ header_base +
++ start * entry_size + COLUMN_NUMBER_SIZE,
++ offset_size);
++ }
++ /* find data to be moved */
++ if (start < end)
++ {
++ size_t data_size=
++ get_length_interval(header_base + start * entry_size,
++ header_base + end * entry_size,
++ header_end, offset_size, max_offset);
++ if (data_size == DYNCOL_OFFSET_ERROR ||
++ (long) data_size < 0 ||
++ data_size > max_offset - first_offset)
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++ DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
++ plan[i].mv_offset= first_offset;
++ plan[i].mv_length= data_size;
++ curr_offset+= data_size;
++ }
++ else
++ {
++ plan[i].mv_length= 0;
++ plan[i].mv_offset= curr_offset;
++ }
++
++ if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
++ plan[i].act != PLAN_DELETE)
++ write+= entry_size * (end - start);
++ else
++ {
++ /*
++ Adjust all headers since last loop.
++ We have to do this as the offset for data has moved
++ */
++ for (k= start; k < end; k++)
++ {
++ uchar *read= header_base + k * entry_size;
++ size_t offs;
++ uint nm;
++ DYNAMIC_COLUMN_TYPE tp;
++
++ nm= uint2korr(read); /* Column nummber */
++ type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
++ offset_size);
++ if (k > start && offs < first_offset)
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++
++ offs+= plan[i].ddelta;
++ int2store(write, nm);
++ /* write rest of data at write + COLUMN_NUMBER_SIZE */
++ if (type_and_offset_store_num(write, new_offset_size, tp, offs))
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++ write+= new_entry_size;
++ }
++ }
++
++ /* new data adding */
++ if (i < add_column_count)
++ {
++ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
++ {
++ int2store(write, *((uint *)plan[i].key));
++ if (type_and_offset_store_num(write, new_offset_size,
++ plan[i].val[0].type,
++ curr_offset))
++ {
++ str->length= 0; // just something valid
++ return ER_DYNCOL_FORMAT;
++ }
++ write+= new_entry_size;
++ curr_offset+= plan[i].length;
++ }
++ }
++ }
++
++ /*
++ Move headers.
++ i= index in array of changes
++ j= index in packed string header index
++ */
++ str->length= (FIXED_HEADER_SIZE + new_header_size);
++ for (i= 0, j= 0;
++ i < add_column_count || j < column_count;
++ i++)
++ {
++ uint start= j, end;
++
++ /*
++ Search in i and j for the next column to add from i and where to
++ add.
++ */
++
++ while (i < add_column_count && plan[i].act == PLAN_NOP)
++ i++; /* skip NOP */
++
++ j= end= plan[i].mv_end;
++ if (i != add_column_count &&
++ (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
++ j++;
++
++ /* copy first the data that was not replaced in original packed data */
++ if (start < end && plan[i].mv_length)
++ {
++ memmove((header_base + new_header_size +
++ plan[i].mv_offset + plan[i].ddelta),
++ header_base + header_size + plan[i].mv_offset,
++ plan[i].mv_length);
++ }
++ str->length+= plan[i].mv_length;
++
++ /* new data adding */
++ if (i < add_column_count)
++ {
++ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
++ {
++ data_store(str, plan[i].val, dyncol_fmt_num); /* Append new data */
++ }
++ }
++ }
++ return ER_DYNCOL_OK;
++}
++#endif
++
++/**
++ Update the packed string with the given columns
++
++ @param str String where to write the data
++ @param add_column_count Number of columns in the arrays
++ @param column_numbers Array of columns numbers
++ @param values Array of columns values
++
++ @return ER_DYNCOL_* return code
++*/
++/* plan allocated on the stack */
++#define IN_PLACE_PLAN 4
++
++enum enum_dyncol_func_result
++dynamic_column_update_many(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values)
++{
++ return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
++ values, FALSE);
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ uint *column_numbers,
++ DYNAMIC_COLUMN_VALUE *values)
++{
++ return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
++ values, FALSE);
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ LEX_STRING *column_names,
++ DYNAMIC_COLUMN_VALUE *values)
++{
++ return dynamic_column_update_many_fmt(str, add_column_count, column_names,
++ values, TRUE);
++}
++
++static uint numlen(uint val)
++{
++ uint res;
++ if (val == 0)
++ return 1;
++ res= 0;
++ while(val)
++ {
++ res++;
++ val/=10;
++ }
++ return res;
++}
++
++static enum enum_dyncol_func_result
++dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
++ uint add_column_count,
++ void *column_keys,
++ DYNAMIC_COLUMN_VALUE *values,
++ my_bool string_keys)
++{
++ PLAN *plan, *alloc_plan= NULL, in_place_plan[IN_PLACE_PLAN];
++ uchar *element;
++ DYN_HEADER header, new_header;
++ struct st_service_funcs *fmt, *new_fmt;
++ long long data_delta= 0, name_delta= 0;
++ uint i;
++ uint not_null;
++ long long header_delta= 0;
++ long long header_delta_sign, data_delta_sign;
++ int copy= FALSE;
++ enum enum_dyncol_func_result rc;
++ my_bool convert;
++
++ if (add_column_count == 0)
++ return ER_DYNCOL_OK;
++
++ bzero(&header, sizeof(header));
++ bzero(&new_header, sizeof(new_header));
++ new_header.format= (string_keys ? dyncol_fmt_str : dyncol_fmt_num);
++ new_fmt= fmt_data + new_header.format;
++
++ /*
++ Get columns in column order. As the data in 'str' is already
++ in column order this allows to replace all columns in one loop.
++ */
++ if (IN_PLACE_PLAN > add_column_count)
++ plan= in_place_plan;
++ else if (!(alloc_plan= plan=
++ (PLAN *)my_malloc(sizeof(PLAN) * (add_column_count + 1), MYF(0))))
++ return ER_DYNCOL_RESOURCE;
++
++ not_null= add_column_count;
++ for (i= 0, element= (uchar *) column_keys;
++ i < add_column_count;
++ i++, element+= new_fmt->key_size_in_array)
++ {
++ if ((*new_fmt->check_limit)(&element))
++ {
++ rc= ER_DYNCOL_DATA;
++ goto end;
++ }
++
++ plan[i].val= values + i;
++ plan[i].key= element;
++ if (values[i].type == DYN_COL_NULL)
++ not_null--;
++
++ }
++
++ if (str->length == 0)
++ {
++ /*
++ Just add new columns. If there was no columns to add we return
++ an empty string.
++ */
++ goto create_new_string;
++ }
++
++ /* Check that header is ok */
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ goto end;
++ fmt= fmt_data + header.format;
++ /* new format can't be numeric if the old one is names */
++ DBUG_ASSERT(new_header.format == dyncol_fmt_str ||
++ header.format == dyncol_fmt_num);
++ if (header.column_count == 0)
++ goto create_new_string;
++
++ qsort(plan, (size_t)add_column_count, sizeof(PLAN), new_fmt->plan_sort);
++
++ new_header.column_count= header.column_count;
++ new_header.nmpool_size= header.nmpool_size;
++ if ((convert= (new_header.format == dyncol_fmt_str &&
++ header.format == dyncol_fmt_num)))
++ {
++ DBUG_ASSERT(new_header.nmpool_size == 0);
++ for(i= 0, header.entry= header.header;
++ i < header.column_count;
++ i++, header.entry+= header.entry_size)
++ {
++ new_header.nmpool_size+= numlen(uint2korr(header.entry));
++ }
++ }
++
++ if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto end;
++ }
++
++ /*
++ Calculate how many columns and data is added/deleted and make a 'plan'
++ for each of them.
++ */
++ for (i= 0; i < add_column_count; i++)
++ {
++ /*
++ For now we don't allow creating two columns with the same number
++ at the time of create. This can be fixed later to just use the later
++ by comparing the pointers.
++ */
++ if (i < add_column_count - 1 &&
++ new_fmt->column_sort(&plan[i].key, &plan[i + 1].key) == 0)
++ {
++ rc= ER_DYNCOL_DATA;
++ goto end;
++ }
++
++ /* Set common variables for all plans */
++ plan[i].ddelta= data_delta;
++ plan[i].ndelta= name_delta;
++ /* get header delta in entries */
++ plan[i].hdelta= header_delta;
++ plan[i].length= 0; /* Length if NULL */
++
++ if (find_place(&header, plan[i].key, string_keys))
++ {
++ size_t entry_data_size, entry_name_size= 0;
++
++ /* Data existed; We have to replace or delete it */
++
++ entry_data_size= hdr_interval_length(&header, header.entry +
++ header.entry_size);
++ if (entry_data_size == DYNCOL_OFFSET_ERROR ||
++ (long) entry_data_size < 0)
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto end;
++ }
++
++ if (new_header.format == dyncol_fmt_str)
++ {
++ if (header.format == dyncol_fmt_str)
++ {
++ LEX_STRING name;
++ if (read_name(&header, header.entry, &name))
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto end;
++ }
++ entry_name_size= name.length;
++ }
++ else
++ entry_name_size= numlen(uint2korr(header.entry));
++ }
++
++ if (plan[i].val->type == DYN_COL_NULL)
++ {
++ /* Inserting a NULL means delete the old data */
++
++ plan[i].act= PLAN_DELETE; /* Remove old value */
++ header_delta--; /* One row less in header */
++ data_delta-= entry_data_size; /* Less data to store */
++ name_delta-= entry_name_size;
++ }
++ else
++ {
++ /* Replace the value */
++
++ plan[i].act= PLAN_REPLACE;
++ /* get data delta in bytes */
++ if ((plan[i].length= dynamic_column_value_len(plan[i].val,
++ new_header.format)) ==
++ (size_t) ~0)
++ {
++ rc= ER_DYNCOL_DATA;
++ goto end;
++ }
++ data_delta+= plan[i].length - entry_data_size;
++ if (new_header.format == dyncol_fmt_str)
++ {
++ name_delta+= ((LEX_STRING *)(plan[i].key))->length - entry_name_size;
++ }
++ }
++ }
++ else
++ {
++ /* Data did not exists. Add if it it's not NULL */
++
++ if (plan[i].val->type == DYN_COL_NULL)
++ {
++ plan[i].act= PLAN_NOP; /* Mark entry to be skiped */
++ }
++ else
++ {
++ /* Add new value */
++
++ plan[i].act= PLAN_ADD;
++ header_delta++; /* One more row in header */
++ /* get data delta in bytes */
++ if ((plan[i].length= dynamic_column_value_len(plan[i].val,
++ new_header.format)) ==
++ (size_t) ~0)
++ {
++ rc= ER_DYNCOL_DATA;
++ goto end;
++ }
++ data_delta+= plan[i].length;
++ if (new_header.format == dyncol_fmt_str)
++ name_delta+= ((LEX_STRING *)plan[i].key)->length;
++ }
++ }
++ plan[i].place= header.entry;
++ }
++ plan[add_column_count].hdelta= header_delta;
++ plan[add_column_count].ddelta= data_delta;
++ plan[add_column_count].act= PLAN_NOP;
++ plan[add_column_count].place= header.dtpool;
++
++ new_header.column_count= (uint)(header.column_count + header_delta);
++
++ /*
++ Check if it is only "increasing" or only "decreasing" plan for (header
++ and data separately).
++ */
++ new_header.data_size= header.data_size + (size_t)data_delta;
++ new_header.nmpool_size= new_header.nmpool_size + (size_t)name_delta;
++ DBUG_ASSERT(new_header.format != dyncol_fmt_num ||
++ new_header.nmpool_size == 0);
++ if ((new_header.offset_size=
++ new_fmt->dynamic_column_offset_bytes(new_header.data_size)) >=
++ new_fmt->max_offset_size)
++ {
++ rc= ER_DYNCOL_LIMIT;
++ goto end;
++ }
++
++ copy= ((header.format != new_header.format) ||
++ (new_header.format == dyncol_fmt_str));
++ /* if (new_header.offset_size!=offset_size) then we have to rewrite header */
++ header_delta_sign=
++ ((int)new_header.offset_size + new_fmt->fixed_hdr_entry) -
++ ((int)header.offset_size + fmt->fixed_hdr_entry);
++ data_delta_sign= 0;
++ // plan[add_column_count] contains last deltas.
++ for (i= 0; i <= add_column_count && !copy; i++)
++ {
++ /* This is the check for increasing/decreasing */
++ DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
++ DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
++ }
++ calc_param(&new_header.entry_size, &new_header.header_size,
++ new_fmt->fixed_hdr_entry,
++ new_header.offset_size, new_header.column_count);
++
++ /*
++ Need copy because:
++ 1, Header/data parts moved in different directions.
++ 2. There is no enough allocated space in the string.
++ 3. Header and data moved in different directions.
++ */
++ if (copy || /*1.*/
++ str->max_length < str->length + header_delta + data_delta || /*2.*/
++ ((header_delta_sign < 0 && data_delta_sign > 0) ||
++ (header_delta_sign > 0 && data_delta_sign < 0))) /*3.*/
++ rc= dynamic_column_update_copy(str, plan, add_column_count,
++ &header, &new_header,
++ convert);
++ else
++ if (header_delta_sign < 0)
++ rc= dynamic_column_update_move_left(str, plan, header.offset_size,
++ header.entry_size,
++ header.header_size,
++ new_header.offset_size,
++ new_header.entry_size,
++ new_header.header_size,
++ header.column_count,
++ new_header.column_count,
++ add_column_count, header.dtpool,
++ header.data_size);
++ else
++ /*
++ rc= dynamic_column_update_move_right(str, plan, offset_size,
++ entry_size, header_size,
++ new_header.offset_size,
++ new_header.entry_size,
++ new_heder.header_size, column_count,
++ new_header.column_count,
++ add_column_count, header_end,
++ header.data_size);
++ */
++ rc= dynamic_column_update_copy(str, plan, add_column_count,
++ &header, &new_header,
++ convert);
++end:
++#ifndef LIBMARIADB
++ my_free(alloc_plan);
++#else
++ my_free((gptr)alloc_plan, MYF(0));
++#endif
++ return rc;
++
++create_new_string:
++ /* There is no columns from before, so let's just add the new ones */
++ rc= ER_DYNCOL_OK;
++#ifndef LIBMARIADB
++ my_free(alloc_plan);
++#else
++ my_free((gptr)alloc_plan, MYF(0));
++#endif
++ if (not_null != 0)
++ rc= dynamic_column_create_many_internal_fmt(str, add_column_count,
++ (uint*)column_keys, values,
++ str->str == NULL,
++ string_keys);
++ goto end;
++}
++
++
++/**
++ Update the packed string with the given column
++
++ @param str String where to write the data
++ @param column_number Array of columns number
++ @param values Array of columns values
++
++ @return ER_DYNCOL_* return code
++*/
++
++
++int dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
++ DYNAMIC_COLUMN_VALUE *value)
++{
++ return dynamic_column_update_many(str, 1, &column_nr, value);
++}
++
++
++enum enum_dyncol_func_result
++mariadb_dyncol_check(DYNAMIC_COLUMN *str)
++{
++ struct st_service_funcs *fmt;
++ enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
++ DYN_HEADER header;
++ uint i;
++ size_t data_offset= 0, name_offset= 0;
++ size_t prev_data_offset= 0, prev_name_offset= 0;
++ LEX_STRING name= {0,0}, prev_name= {0,0};
++ uint num= 0, prev_num= 0;
++ void *key, *prev_key;
++ enum enum_dynamic_column_type type= DYN_COL_NULL, prev_type= DYN_COL_NULL;
++
++ DBUG_ENTER("dynamic_column_check");
++
++ if (str->length == 0)
++ {
++ DBUG_PRINT("info", ("empty string is OK"));
++ DBUG_RETURN(ER_DYNCOL_OK);
++ }
++
++ bzero(&header, sizeof(header));
++
++ /* Check that header is OK */
++ if (read_fixed_header(&header, str))
++ {
++ DBUG_PRINT("info", ("Reading fixed string header failed"));
++ goto end;
++ }
++ fmt= fmt_data + header.format;
++ calc_param(&header.entry_size, &header.header_size,
++ fmt->fixed_hdr_entry, header.offset_size,
++ header.column_count);
++ /* headers are out of string length (no space for data and part of headers) */
++ if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
++ {
++ DBUG_PRINT("info", ("Fixed header: %u Header size: %u "
++ "Name pool size: %u but Strig length: %u",
++ (uint)fmt->fixed_hdr,
++ (uint)header.header_size,
++ (uint)header.nmpool_size,
++ (uint)str->length));
++ goto end;
++ }
++ header.header= (uchar*)str->str + fmt->fixed_hdr;
++ header.nmpool= header.header + header.header_size;
++ header.dtpool= header.nmpool + header.nmpool_size;
++ header.data_size= str->length - fmt->fixed_hdr -
++ header.header_size - header.nmpool_size;
++
++ /* read and check headers */
++ if (header.format == dyncol_fmt_num)
++ {
++ key= &num;
++ prev_key= &prev_num;
++ }
++ else
++ {
++ key= &name;
++ prev_key= &prev_name;
++ }
++ for (i= 0, header.entry= header.header;
++ i < header.column_count;
++ i++, header.entry+= header.entry_size)
++ {
++
++ if (header.format == dyncol_fmt_num)
++ {
++ num= uint2korr(header.entry);
++ }
++ else
++ {
++ DBUG_ASSERT(header.format == dyncol_fmt_str);
++ if (read_name(&header, header.entry, &name))
++ {
++ DBUG_PRINT("info", ("Reading name failed: Field order: %u"
++ " Name offset: %u"
++ " Name pool size: %u",
++ (uint) i,
++ uint2korr(header.entry),
++ (uint)header.nmpool_size));
++ goto end;
++ }
++ name_offset= name.str - (char *)header.nmpool;
++ }
++ if ((*fmt->type_and_offset_read)(&type, &data_offset,
++ header.entry + fmt->fixed_hdr_entry,
++ header.offset_size))
++ goto end;
++
++ DBUG_ASSERT(type != DYN_COL_NULL);
++ if (data_offset > header.data_size)
++ {
++ DBUG_PRINT("info", ("Field order: %u Data offset: %u"
++ " > Data pool size: %u",
++ (uint)i,
++ (uint)data_offset,
++ (uint)header.data_size));
++ goto end;
++ }
++ if (prev_type != DYN_COL_NULL)
++ {
++ /* It is not first entry */
++ if (prev_data_offset >= data_offset)
++ {
++ DBUG_PRINT("info", ("Field order: %u Previous data offset: %u"
++ " >= Current data offset: %u",
++ (uint)i,
++ (uint)prev_data_offset,
++ (uint)data_offset));
++ goto end;
++ }
++ if (prev_name_offset > name_offset)
++ {
++ DBUG_PRINT("info", ("Field order: %u Previous name offset: %u"
++ " > Current name offset: %u",
++ (uint)i,
++ (uint)prev_data_offset,
++ (uint)data_offset));
++ goto end;
++ }
++ if ((*fmt->column_sort)(&prev_key, &key) >= 0)
++ {
++ DBUG_PRINT("info", ("Field order: %u Previous key >= Current key",
++ (uint)i));
++ goto end;
++ }
++ }
++ prev_num= num;
++ prev_name= name;
++ prev_data_offset= data_offset;
++ prev_name_offset= name_offset;
++ prev_type= type;
++ }
++
++ /* check data, which we can */
++ for (i= 0, header.entry= header.header;
++ i < header.column_count;
++ i++, header.entry+= header.entry_size)
++ {
++ DYNAMIC_COLUMN_VALUE store;
++ // already checked by previouse pass
++ (*fmt->type_and_offset_read)(&header.type, &header.offset,
++ header.entry + fmt->fixed_hdr_entry,
++ header.offset_size);
++ header.length=
++ hdr_interval_length(&header, header.entry + header.entry_size);
++ header.data= header.dtpool + header.offset;
++ switch ((header.type)) {
++ case DYN_COL_INT:
++ rc= dynamic_column_sint_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_UINT:
++ rc= dynamic_column_uint_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_DOUBLE:
++ rc= dynamic_column_double_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_STRING:
++ rc= dynamic_column_string_read(&store, header.data, header.length);
++ break;
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ rc= dynamic_column_decimal_read(&store, header.data, header.length);
++ break;
++#endif
++ case DYN_COL_DATETIME:
++ rc= dynamic_column_date_time_read(&store, header.data,
++ header.length);
++ break;
++ case DYN_COL_DATE:
++ rc= dynamic_column_date_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_TIME:
++ rc= dynamic_column_time_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_DYNCOL:
++ rc= dynamic_column_dyncol_read(&store, header.data, header.length);
++ break;
++ case DYN_COL_NULL:
++ default:
++ rc= ER_DYNCOL_FORMAT;
++ goto end;
++ }
++ if (rc != ER_DYNCOL_OK)
++ {
++ DBUG_ASSERT(rc < 0);
++ DBUG_PRINT("info", ("Field order: %u Can't read data: %i",
++ (uint)i, (int) rc));
++ goto end;
++ }
++ }
++
++ rc= ER_DYNCOL_OK;
++end:
++ DBUG_RETURN(rc);
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
++ CHARSET_INFO *cs, char quote)
++{
++ char buff[40];
++ size_t len;
++ switch (val->type) {
++ case DYN_COL_INT:
++ len= snprintf(buff, sizeof(buff), "%lld", val->x.long_value);
++ if (dynstr_append_mem(str, buff, len))
++ return ER_DYNCOL_RESOURCE;
++ break;
++ case DYN_COL_UINT:
++ len= snprintf(buff, sizeof(buff), "%llu", val->x.ulong_value);
++ if (dynstr_append_mem(str, buff, len))
++ return ER_DYNCOL_RESOURCE;
++ break;
++ case DYN_COL_DOUBLE:
++ len= snprintf(buff, sizeof(buff), "%g", val->x.double_value);
++ if (dynstr_realloc(str, len + (quote ? 2 : 0)))
++ return ER_DYNCOL_RESOURCE;
++ if (quote)
++ str->str[str->length++]= quote;
++ dynstr_append_mem(str, buff, len);
++ if (quote)
++ str->str[str->length++]= quote;
++ break;
++ case DYN_COL_DYNCOL:
++ case DYN_COL_STRING:
++ {
++ char *alloc= NULL;
++ char *from= val->x.string.value.str;
++ ulong bufflen;
++ my_bool conv= ((val->x.string.charset == cs) ||
++ !strcmp(val->x.string.charset->name, cs->name));
++ my_bool rc;
++ len= val->x.string.value.length;
++ bufflen= (ulong)(len * (conv ? cs->char_maxlen : 1));
++ if (dynstr_realloc(str, bufflen))
++ return ER_DYNCOL_RESOURCE;
++
++ // guaranty UTF-8 string for value
++ if (!conv)
++ {
++#ifndef LIBMARIADB
++ uint dummy_errors;
++#else
++ int dummy_errors;
++#endif
++ if (!quote)
++ {
++ /* convert to the destination */
++ str->length+=
++#ifndef LIBMARIADB
++ copy_and_convert_extended(str->str, bufflen,
++ cs,
++ from, (uint32)len,
++ val->x.string.charset,
++ &dummy_errors);
++#else
++ mariadb_convert_string(from, &len, val->x.string.charset,
++ str->str, (size_t *)&bufflen, cs, &dummy_errors);
++#endif
++ return ER_DYNCOL_OK;
++ }
++ if ((alloc= (char *)my_malloc(bufflen, MYF(0))))
++ {
++ len=
++#ifndef LIBMARIADB
++ copy_and_convert_extended(alloc, bufflen, cs,
++ from, (uint32)len,
++ val->x.string.charset,
++ &dummy_errors);
++#else
++ mariadb_convert_string(from, &len, val->x.string.charset,
++ alloc, (size_t *)&bufflen, cs, &dummy_errors);
++#endif
++ from= alloc;
++ }
++ else
++ return ER_DYNCOL_RESOURCE;
++ }
++ if (quote)
++ rc= dynstr_append_mem(str, &quote, 1);
++ rc= dynstr_append_mem(str, from, len);
++ if (quote)
++ rc= dynstr_append_mem(str, &quote, 1);
++ if (alloc)
++#ifndef LIBMARIADB
++ my_free(alloc);
++#else
++ my_free((gptr)alloc, MYF(0));
++#endif
++ if (rc)
++ return ER_DYNCOL_RESOURCE;
++ break;
++ }
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ {
++ int len= sizeof(buff);
++ decimal2string(&val->x.decimal.value, buff, &len,
++ 0, val->x.decimal.value.frac,
++ '0');
++ if (dynstr_append_mem(str, buff, len))
++ return ER_DYNCOL_RESOURCE;
++ break;
++ }
++#endif
++ case DYN_COL_DATETIME:
++ case DYN_COL_DATE:
++ case DYN_COL_TIME:
++#ifndef LIBMARIADB
++ len= my_TIME_to_str(&val->x.time_value, buff, AUTO_SEC_PART_DIGITS);
++#else
++ len= mariadb_time_to_string(&val->x.time_value, buff, 39, AUTO_SEC_PART_DIGITS);
++#endif
++ if (dynstr_realloc(str, len + (quote ? 2 : 0)))
++ return ER_DYNCOL_RESOURCE;
++ if (quote)
++ str->str[str->length++]= '"';
++ dynstr_append_mem(str, buff, len);
++ if (quote)
++ str->str[str->length++]= '"';
++ break;
++ case DYN_COL_NULL:
++ if (dynstr_append_mem(str, "null", 4))
++ return ER_DYNCOL_RESOURCE;
++ break;
++ default:
++ return(ER_DYNCOL_FORMAT);
++ }
++ return(ER_DYNCOL_OK);
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val)
++{
++ enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
++ *ll= 0;
++ switch (val->type) {
++ case DYN_COL_INT:
++ *ll= val->x.long_value;
++ break;
++ case DYN_COL_UINT:
++ *ll= (longlong)val->x.ulong_value;
++ if (val->x.ulong_value > ULONGLONG_MAX)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ case DYN_COL_DOUBLE:
++ *ll= (longlong)val->x.double_value;
++ if (((double) *ll) != val->x.double_value)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ case DYN_COL_STRING:
++ {
++ char *src= val->x.string.value.str;
++ size_t len= val->x.string.value.length;
++ longlong i= 0, sign= 1;
++
++ while (len && isspace(*src)) src++,len--;
++
++ if (len)
++ {
++ if (*src == '-')
++ {
++ sign= -1;
++ src++;
++ } else if (*src == '-')
++ src++;
++ while(len && isdigit(*src))
++ {
++ i= i * 10 + (*src - '0');
++ src++;
++ }
++ }
++ else
++ rc= ER_DYNCOL_TRUNCATED;
++ if (len)
++ rc= ER_DYNCOL_TRUNCATED;
++ *ll= i * sign;
++ break;
++ }
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ if (decimal2longlong(&val->x.decimal.value, ll) != E_DEC_OK)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++#endif
++ case DYN_COL_DATETIME:
++ *ll= (val->x.time_value.year * 10000000000ull +
++ val->x.time_value.month * 100000000L +
++ val->x.time_value.day * 1000000 +
++ val->x.time_value.hour * 10000 +
++ val->x.time_value.minute * 100 +
++ val->x.time_value.second) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_DATE:
++ *ll= (val->x.time_value.year * 10000 +
++ val->x.time_value.month * 100 +
++ val->x.time_value.day) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_TIME:
++ *ll= (val->x.time_value.hour * 10000 +
++ val->x.time_value.minute * 100 +
++ val->x.time_value.second) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_DYNCOL:
++ case DYN_COL_NULL:
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ default:
++ return(ER_DYNCOL_FORMAT);
++ }
++ return(rc);
++}
++
++
++enum enum_dyncol_func_result
++mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val)
++{
++ enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
++ *dbl= 0;
++ switch (val->type) {
++ case DYN_COL_INT:
++ *dbl= (double)val->x.long_value;
++ if (((longlong) *dbl) != val->x.long_value)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ case DYN_COL_UINT:
++ *dbl= (double)val->x.ulong_value;
++ if (((ulonglong) *dbl) != val->x.ulong_value)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ case DYN_COL_DOUBLE:
++ *dbl= val->x.double_value;
++ break;
++ case DYN_COL_STRING:
++ {
++ char *str, *end;
++ if ((str= malloc(val->x.string.value.length + 1)))
++ return ER_DYNCOL_RESOURCE;
++ memcpy(str, val->x.string.value.str, val->x.string.value.length);
++ str[val->x.string.value.length]= '\0';
++ *dbl= strtod(str, &end);
++ if (*end != '\0')
++ rc= ER_DYNCOL_TRUNCATED;
++ }
++#ifndef LIBMARIADB
++ case DYN_COL_DECIMAL:
++ if (decimal2double(&val->x.decimal.value, dbl) != E_DEC_OK)
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++#endif
++ case DYN_COL_DATETIME:
++ *dbl= (double)(val->x.time_value.year * 10000000000ull +
++ val->x.time_value.month * 100000000L +
++ val->x.time_value.day * 1000000 +
++ val->x.time_value.hour * 10000 +
++ val->x.time_value.minute * 100 +
++ val->x.time_value.second) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_DATE:
++ *dbl= (double)(val->x.time_value.year * 10000 +
++ val->x.time_value.month * 100 +
++ val->x.time_value.day) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_TIME:
++ *dbl= (double)(val->x.time_value.hour * 10000 +
++ val->x.time_value.minute * 100 +
++ val->x.time_value.second) *
++ (val->x.time_value.neg ? -1 : 1);
++ break;
++ case DYN_COL_DYNCOL:
++ case DYN_COL_NULL:
++ rc= ER_DYNCOL_TRUNCATED;
++ break;
++ default:
++ return(ER_DYNCOL_FORMAT);
++ }
++ return(rc);
++}
++
++
++/**
++ Convert to JSON
++
++ @param str The packed string
++ @param json Where to put json result
++
++ @return ER_DYNCOL_* return code
++*/
++
++#define JSON_STACK_PROTECTION 10
++
++static enum enum_dyncol_func_result
++mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
++ uint lvl)
++{
++ DYN_HEADER header;
++ uint i;
++ enum enum_dyncol_func_result rc;
++
++ if (lvl >= JSON_STACK_PROTECTION)
++ {
++ rc= ER_DYNCOL_RESOURCE;
++ goto err;
++ }
++
++
++ if (str->length == 0)
++ return ER_DYNCOL_OK; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ goto err;
++
++ if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
++ str->length)
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++
++ rc= ER_DYNCOL_RESOURCE;
++
++ if (dynstr_append_mem(json, "{", 1))
++ goto err;
++ for (i= 0, header.entry= header.header;
++ i < header.column_count;
++ i++, header.entry+= header.entry_size)
++ {
++ DYNAMIC_COLUMN_VALUE val;
++ if (i != 0 && dynstr_append_mem(json, ",", 1))
++ goto err;
++ header.length=
++ hdr_interval_length(&header, header.entry + header.entry_size);
++ header.data= header.dtpool + header.offset;
++ /*
++ Check that the found data is withing the ranges. This can happen if
++ we get data with wrong offsets.
++ */
++ if (header.length == DYNCOL_OFFSET_ERROR ||
++ header.length > INT_MAX || header.offset > header.data_size)
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++ if ((rc= dynamic_column_get_value(&header, &val)) < 0)
++ goto err;
++ if (header.format == dyncol_fmt_num)
++ {
++ uint nm= uint2korr(header.entry);
++ if (dynstr_realloc(json, DYNCOL_NUM_CHAR + 3))
++ goto err;
++ json->str[json->length++]= '"';
++ json->length+= (my_snprintf(json->str + json->length,
++ DYNCOL_NUM_CHAR, "%u", nm));
++ }
++ else
++ {
++ LEX_STRING name;
++ if (read_name(&header, header.entry, &name))
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++ if (dynstr_realloc(json, name.length + 3))
++ goto err;
++ json->str[json->length++]= '"';
++ memcpy(json->str + json->length, name.str, name.length);
++ json->length+= name.length;
++ }
++ json->str[json->length++]= '"';
++ json->str[json->length++]= ':';
++ if (val.type == DYN_COL_DYNCOL)
++ {
++ /* here we use it only for read so can cheat a bit */
++ DYNAMIC_COLUMN dc;
++ bzero(&dc, sizeof(dc));
++ dc.str= val.x.string.value.str;
++ dc.length= val.x.string.value.length;
++ if (mariadb_dyncol_json_internal(&dc, json, lvl + 1) < 0)
++ {
++ dc.str= NULL; dc.length= 0;
++ goto err;
++ }
++ dc.str= NULL; dc.length= 0;
++ }
++ else
++ {
++ if ((rc= mariadb_dyncol_val_str(json, &val,
++ my_charset_utf8_general_ci, '"')) < 0)
++ goto err;
++ }
++ }
++ if (dynstr_append_mem(json, "}", 1))
++ {
++ rc= ER_DYNCOL_RESOURCE;
++ goto err;
++ }
++ return ER_DYNCOL_OK;
++
++err:
++ json->length= 0;
++ return rc;
++}
++
++enum enum_dyncol_func_result
++mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json)
++{
++
++ if (init_dynamic_string(json, NULL, str->length * 2, 100))
++ return ER_DYNCOL_RESOURCE;
++
++ return mariadb_dyncol_json_internal(str, json, 1);
++}
++
++/**
++ Convert to DYNAMIC_COLUMN_VALUE values and names (LEX_STING) dynamic array
++
++ @param str The packed string
++ @param count number of elements in the arrays
++ @param names Where to put names (should be free by user)
++ @param vals Where to put values (should be free by user)
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
++ uint *count,
++ LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals)
++{
++ DYN_HEADER header;
++ char *nm;
++ uint i;
++ enum enum_dyncol_func_result rc;
++
++ *count= 0; *names= 0; *vals= 0;
++
++ if (str->length == 0)
++ return ER_DYNCOL_OK; /* no columns */
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++
++
++ if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
++ str->length)
++ return ER_DYNCOL_FORMAT;
++
++ *vals= (DYNAMIC_COLUMN_VALUE *)my_malloc(sizeof(DYNAMIC_COLUMN_VALUE)* header.column_count, MYF(0));
++ if (header.format == dyncol_fmt_num)
++ {
++ *names= (LEX_STRING *)my_malloc(sizeof(LEX_STRING) * header.column_count +
++ DYNCOL_NUM_CHAR * header.column_count, MYF(0));
++ nm= (char *)(names + sizeof(LEX_STRING) * header.column_count);
++ }
++ else
++ {
++ *names= (LEX_STRING *)my_malloc(sizeof(LEX_STRING) * header.column_count, MYF(0));
++ nm= 0;
++ }
++ if (!(*vals) || !(*names))
++ {
++ rc= ER_DYNCOL_RESOURCE;
++ goto err;
++ }
++
++ for (i= 0, header.entry= header.header;
++ i < header.column_count;
++ i++, header.entry+= header.entry_size)
++ {
++ header.length=
++ hdr_interval_length(&header, header.entry + header.entry_size);
++ header.data= header.dtpool + header.offset;
++ /*
++ Check that the found data is withing the ranges. This can happen if
++ we get data with wrong offsets.
++ */
++ if (header.length == DYNCOL_OFFSET_ERROR ||
++ header.length > INT_MAX || header.offset > header.data_size)
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++ if ((rc= dynamic_column_get_value(&header, (*vals) + i)) < 0)
++ goto err;
++
++ if (header.format == dyncol_fmt_num)
++ {
++ uint num= uint2korr(header.entry);
++ (*names)[i].str= nm;
++ (*names)[i].length= snprintf(nm, DYNCOL_NUM_CHAR, "%u", num);
++ nm+= (*names)[i].length + 1;
++ }
++ else
++ {
++ if (read_name(&header, header.entry, (*names) + i))
++ {
++ rc= ER_DYNCOL_FORMAT;
++ goto err;
++ }
++ }
++ }
++
++ *count= header.column_count;
++ return ER_DYNCOL_OK;
++
++err:
++ if (*vals)
++ {
++#ifndef LIBMARIADB
++ my_free(*vals);
++#else
++ my_free((gptr)*vals, MYF(0));
++#endif
++ *vals= 0;
++ }
++ if (*names)
++ {
++#ifndef LIBMARIADB
++ my_free(*names);
++#else
++ my_free((gptr)*names, MYF(0));
++#endif
++ *names= 0;
++ }
++ return rc;
++}
++
++
++/**
++ Get not NULL column count
++
++ @param str The packed string
++ @param column_count Where to put column count
++
++ @return ER_DYNCOL_* return code
++*/
++
++enum enum_dyncol_func_result
++mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count)
++{
++ DYN_HEADER header;
++ enum enum_dyncol_func_result rc;
++
++ (*column_count)= 0;
++ if (str->length == 0)
++ return ER_DYNCOL_OK;
++
++ if ((rc= init_read_hdr(&header, str)) < 0)
++ return rc;
++ *column_count= header.column_count;
++ return rc;
++}
++
++/**
++ Release dynamic column memory
++
++ @param str dynamic column
++ @return void
++*/
++void mariadb_dyncol_free(DYNAMIC_COLUMN *str)
++{
++ dynstr_free(str);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/ma_secure.c mariadb-native-client.trunk/libmariadb/ma_secure.c
+--- mariadb/libmariadb/ma_secure.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/ma_secure.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,526 @@
++/************************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ *************************************************************************************/
++#ifdef HAVE_OPENSSL
++
++#include <my_global.h>
++#include <my_sys.h>
++#include <ma_common.h>
+#include <ma_secure.h>
- #include <errmsg.h>
- #include <violite.h>
-
-@@ -53,11 +53,13 @@
- }
- if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
- {
-- my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error_reason);
++#include <errmsg.h>
++#include <violite.h>
++
++static my_bool my_ssl_initialized= FALSE;
++static SSL_CTX *SSL_context= NULL;
++
++#define MAX_SSL_ERR_LEN 100
++
++extern pthread_mutex_t LOCK_ssl_config;
++static pthread_mutex_t *LOCK_crypto;
++
++/*
++ SSL error handling
++*/
++static void my_SSL_error(MYSQL *mysql)
++{
++ ulong ssl_errno= ERR_get_error();
++ char ssl_error[MAX_SSL_ERR_LEN];
++ const char *ssl_error_reason;
++
++ DBUG_ENTER("my_SSL_error");
++
++ if (mysql_errno(mysql))
++ DBUG_VOID_RETURN;
++
++ if (!ssl_errno)
++ {
++ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
++ DBUG_VOID_RETURN;
++ }
++ if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
++ {
+ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
+ ER(CR_SSL_CONNECTION_ERROR), ssl_error_reason);
- DBUG_VOID_RETURN;
- }
- my_snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno, mysql->charset);
-- my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error);
++ DBUG_VOID_RETURN;
++ }
++ my_snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno, mysql->charset);
+ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
+ ER(CR_SSL_CONNECTION_ERROR), ssl_error);
- DBUG_VOID_RETURN;
- }
-
-@@ -226,8 +228,9 @@
- /* set cert */
- if (mysql->options.ssl_cert && mysql->options.ssl_cert[0] != 0)
- {
-- if ((SSL_CTX_use_certificate_chain_file(SSL_context, mysql->options.ssl_cert) != 1) &&
-- (SSL_use_certificate_file(ssl, mysql->options.ssl_cert, SSL_FILETYPE_PEM) != 1))
-+ if (SSL_CTX_use_certificate_chain_file(SSL_context, mysql->options.ssl_cert) != 1)
++ DBUG_VOID_RETURN;
++}
++
++/*
++ thread safe callbacks for OpenSSL
++ Crypto call back functions will be
++ set during ssl_initialization
++ */
++static unsigned long my_cb_threadid(void)
++{
++ /* chast pthread_t to unsigned long */
++ return (unsigned long) pthread_self();
++}
++
++static void
++my_cb_locking(int mode, int n, const char *file, int line)
++{
++ if (mode & CRYPTO_LOCK)
++ pthread_mutex_lock(&LOCK_crypto[n]);
++ else
++ pthread_mutex_unlock(&LOCK_crypto[n]);
++}
++
++/*
++ Initializes SSL and allocate global
++ context SSL_context
++
++ SYNOPSIS
++ my_ssl_start
++ mysql connection handle
++
++ RETURN VALUES
++ 0 success
++ 1 error
++*/
++int my_ssl_start(MYSQL *mysql)
++{
++ int rc= 0;
++ DBUG_ENTER("my_ssl_start");
++ /* lock mutex to prevent multiple initialization */
++ pthread_mutex_lock(&LOCK_ssl_config);
++
++ if (!my_ssl_initialized)
++ {
++ if (!(LOCK_crypto=
++ (pthread_mutex_t *)my_malloc(sizeof(pthread_mutex_t) *
++ CRYPTO_num_locks(), MYF(0))))
++ {
++ rc= 1;
++ goto end;
++ } else
++ {
++ int i;
++
++ for (i=0; i < CRYPTO_num_locks(); i++)
++ pthread_mutex_init(&LOCK_crypto[i], NULL);
++ CRYPTO_set_id_callback(my_cb_threadid);
++ CRYPTO_set_locking_callback(my_cb_locking);
++ }
++#if SSLEAY_VERSION_NUMBER >= 0x00907000L
++ OPENSSL_config(NULL);
++#endif
++
++ /* always returns 1, so we can discard return code */
++ SSL_library_init();
++ /* load errors */
++ SSL_load_error_strings();
++ /* digests and ciphers */
++ OpenSSL_add_all_algorithms();
++
++ if (!(SSL_context= SSL_CTX_new(TLSv1_client_method())))
++ {
++ my_SSL_error(mysql);
++ rc= 1;
++ goto end;
++ }
++ my_ssl_initialized= TRUE;
++ }
++end:
++ pthread_mutex_unlock(&LOCK_ssl_config);
++ DBUG_RETURN(rc);
++}
++
++/*
++ Release SSL and free resources
++ Will be automatically executed by
++ mysql_server_end() function
++
++ SYNOPSIS
++ my_ssl_end()
++ void
++
++ RETURN VALUES
++ void
++*/
++void my_ssl_end()
++{
++ DBUG_ENTER("my_ssl_end");
++ pthread_mutex_lock(&LOCK_ssl_config);
++ if (my_ssl_initialized)
++ {
++ int i;
++ CRYPTO_set_locking_callback(NULL);
++ CRYPTO_set_id_callback(NULL);
++
++ for (i=0; i < CRYPTO_num_locks(); i++)
++ pthread_mutex_destroy(&LOCK_crypto[i]);
++
++ my_free((gptr)LOCK_crypto, MYF(0));
++ if (SSL_context)
++ {
++ SSL_CTX_free(SSL_context);
++ SSL_context= FALSE;
++ }
++ ERR_remove_state(0);
++ EVP_cleanup();
++ CRYPTO_cleanup_all_ex_data();
++ ERR_free_strings();
++ ENGINE_cleanup();
++ CONF_modules_free();
++ CONF_modules_unload(1);
++ sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
++ my_ssl_initialized= FALSE;
++ }
++ pthread_mutex_unlock(&LOCK_ssl_config);
++ pthread_mutex_destroy(&LOCK_ssl_config);
++ DBUG_VOID_RETURN;
++}
++
++/*
++ Set certification stuff.
++*/
++static int my_ssl_set_certs(SSL *ssl)
++{
++ int have_cert= 0;
++ MYSQL *mysql;
++
++ DBUG_ENTER("my_ssl_set_certs");
++
++ /* Make sure that ssl was allocated and
++ ssl_system was initialized */
++ DBUG_ASSERT(ssl != NULL);
++ DBUG_ASSERT(my_ssl_initialized == TRUE);
++
++ /* get connection for current ssl */
++ mysql= (MYSQL *)SSL_get_app_data(ssl);
++
++ /* add cipher */
++ if ((mysql->options.ssl_cipher &&
++ mysql->options.ssl_cipher[0] != 0) &&
++ SSL_set_cipher_list(ssl, mysql->options.ssl_cipher) == 0)
++ goto error;
++
++ /* set cert */
++ if (mysql->options.ssl_cert && mysql->options.ssl_cert[0] != 0)
++ {
++ if (SSL_CTX_use_certificate_chain_file(SSL_context, mysql->options.ssl_cert) <= 0)
++ goto error;
++ have_cert= 1;
++ }
++
++ /* set key */
++ if (mysql->options.ssl_key && mysql->options.ssl_key[0])
++ {
++ if (SSL_CTX_use_PrivateKey_file(SSL_context, mysql->options.ssl_key, SSL_FILETYPE_PEM) <= 0)
+ goto error;
-+ if (SSL_use_certificate_file(ssl, mysql->options.ssl_cert, SSL_FILETYPE_PEM) != 1)
- goto error;
- have_cert= 1;
- }
-@@ -250,6 +253,26 @@
- if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
- goto error;
- }
+
-+ if (mysql->options.ssl_ca || mysql->options.ssl_capath)
++ /* verify key */
++ if (have_cert && SSL_CTX_check_private_key(SSL_context) != 1)
++ goto error;
++ }
++ /* ca_file and ca_path */
++ if (SSL_CTX_load_verify_locations(SSL_context,
++ mysql->options.ssl_ca,
++ mysql->options.ssl_capath) == 0)
++ {
++ if (mysql->options.ssl_ca || mysql->options.ssl_capath)
++ goto error;
++ if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
++ goto error;
++ }
++ if (mysql->options.extension &&
++ (mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
+ {
+ X509_STORE *certstore;
+
+ if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
+ {
+ if (X509_STORE_load_locations(certstore, mysql->options.ssl_ca,
-+ mysql->options.ssl_capath) == 1)
-+ {
-+#ifdef X509_V_FLAG_CRL_CHECK
-+ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
-+#else
-+ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "OpenSSL library doesn't support CRL certificates");
-+ DBUG_RETURN(1);
-+#endif
-+ }
++ mysql->options.ssl_capath) == 0 ||
++ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK |
++ X509_V_FLAG_CRL_CHECK_ALL) == 0)
++ goto error;
+ }
+ }
+
- DBUG_RETURN(0);
-
- error:
-@@ -259,8 +282,21 @@
-
- static int my_verify_callback(int ok, X509_STORE_CTX *ctx)
- {
-- /* since we don't have access to the mysql structure, we just return */
-- return ok;
++ DBUG_RETURN(0);
++
++error:
++ my_SSL_error(mysql);
++ DBUG_RETURN(1);
++}
++
++static int my_verify_callback(int ok, X509_STORE_CTX *ctx)
++{
+ X509 *check_cert;
++ SSL *ssl;
++ MYSQL *mysql;
+ DBUG_ENTER("my_verify_callback");
+
++ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
++ DBUG_ASSERT(ssl != NULL);
++ mysql= (MYSQL *)SSL_get_app_data(ssl);
++ DBUG_ASSERT(mysql != NULL);
++
++ /* skip verification if no ca_file/path was specified */
++ if (!mysql->options.ssl_ca && !mysql->options.ssl_capath)
++ {
++ ok= 1;
++ DBUG_RETURN(1);
++ }
++
+ if (!ok)
+ {
+ uint depth;
+ if (!(check_cert= X509_STORE_CTX_get_current_cert(ctx)))
+ DBUG_RETURN(0);
+ depth= X509_STORE_CTX_get_error_depth(ctx);
-+ DBUG_PRINT("info", ("error_depth=%d", depth));
+ if (depth == 0)
++ {
++ ok= 1;
+ DBUG_RETURN(1);
++ }
++ }
++ else
++ DBUG_RETURN(1);
++
++ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
++ ER(CR_SSL_CONNECTION_ERROR),
++ X509_verify_cert_error_string(ctx->error));
++ DBUG_RETURN(0);
++}
++
++/*
++ allocates a new ssl object
++
++ SYNOPSIS
++ my_ssl_init
++ mysql connection object
++
++ RETURN VALUES
++ NULL on error
++ SSL new SSL object
++*/
++SSL *my_ssl_init(MYSQL *mysql)
++{
++ int verify;
++ SSL *ssl= NULL;
++
++ DBUG_ENTER("my_ssl_init");
++
++ DBUG_ASSERT(mysql->net.vio->ssl == NULL);
++
++ if (!my_ssl_initialized)
++ my_ssl_start(mysql);
++
++ if (!(ssl= SSL_new(SSL_context)))
++ goto error;
++
++ if (!SSL_set_app_data(ssl, mysql))
++ goto error;
++ if (my_ssl_set_certs(ssl))
++ goto error;
++
++ verify= (!mysql->options.ssl_ca && !mysql->options.ssl_capath) ?
++ SSL_VERIFY_NONE : SSL_VERIFY_PEER;
++ SSL_set_verify(ssl, verify, my_verify_callback);
++ SSL_set_verify_depth(ssl, 1);
++
++ DBUG_RETURN(ssl);
++error:
++ if (ssl)
++ SSL_free(ssl);
++ DBUG_RETURN(NULL);
++}
++
++/*
++ establish SSL connection between client
++ and server
++
++ SYNOPSIS
++ my_ssl_connect
++ ssl ssl object
++
++ RETURN VALUES
++ 0 success
++ 1 error
++*/
++int my_ssl_connect(SSL *ssl)
++{
++ my_bool blocking;
++ MYSQL *mysql;
++
++ DBUG_ENTER("my_ssl_connect");
++
++ DBUG_ASSERT(ssl != NULL);
++
++ mysql= (MYSQL *)SSL_get_app_data(ssl);
++ CLEAR_CLIENT_ERROR(mysql);
++
++ /* Set socket to blocking if not already set */
++ if (!(blocking= vio_is_blocking(mysql->net.vio)))
++ vio_blocking(mysql->net.vio, TRUE);
++
++ SSL_clear(ssl);
++ SSL_SESSION_set_timeout(SSL_get_session(ssl),
++ mysql->options.connect_timeout);
++ SSL_set_fd(ssl, mysql->net.vio->sd);
++
++ if (SSL_connect(ssl) != 1)
++ {
++ my_SSL_error(mysql);
++ /* restore blocking mode */
++ if (!blocking)
++ vio_blocking(mysql->net.vio, FALSE);
++ DBUG_RETURN(1);
++ }
++
++ vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0);
++ mysql->net.vio->ssl= ssl;
++ DBUG_RETURN(0);
++}
++
++/*
++ verify server certificate
++
++ SYNOPSIS
++ my_ssl_verify_server_cert()
++ MYSQL mysql
++ mybool verify_server_cert;
++
++ RETURN VALUES
++ 1 Error
++ 0 OK
++*/
++
++int my_ssl_verify_server_cert(SSL *ssl)
++{
++ X509 *cert;
++ MYSQL *mysql;
++ char *p1, *p2, buf[256];
++
++ DBUG_ENTER("my_ssl_verify_server_cert");
++
++ mysql= (MYSQL *)SSL_get_app_data(ssl);
++
++ if (!mysql->host)
++ {
++ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
++ ER(CR_SSL_CONNECTION_ERROR),
++ "Invalid (empty) hostname");
++ DBUG_RETURN(1);
++ }
++
++ if (!(cert= SSL_get_peer_certificate(ssl)))
++ {
++ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
++ ER(CR_SSL_CONNECTION_ERROR),
++ "Unable to get server certificate");
++ DBUG_RETURN(1);
+ }
-+ DBUG_PRINT("info", ("ctx->error= %d", ctx->error));
++
++ X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
++ X509_free(cert);
++
++ /* Extract the server name from buffer:
++ Format: ....CN=/hostname/.... */
++ if ((p1= strstr(buf, "/CN=")))
++ {
++ p1+= 4;
++ if ((p2= strchr(p1, '/')))
++ *p2= 0;
++ if (!strcmp(mysql->host, p1))
++ DBUG_RETURN(0);
++ }
++ my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
++ ER(CR_SSL_CONNECTION_ERROR),
++ "Validation of SSL server certificate failed");
+ DBUG_RETURN(1);
- }
-
- /*
-@@ -291,7 +327,6 @@
-
- if (!SSL_set_app_data(ssl, mysql))
- goto error;
--
- if (my_ssl_set_certs(ssl))
- goto error;
-
-@@ -340,6 +375,7 @@
-
- if (SSL_connect(ssl) != 1)
- {
-+ printf("connect failed\n");
- my_SSL_error(mysql);
- /* restore blocking mode */
- if (!blocking)
-
-=== modified file 'libmariadb/my_auth.c'
---- mariadb/libmysql/my_auth.c 2012-11-26 07:32:41 +0000
-+++ mariadb/libmariadb/my_auth.c 2013-03-14 21:01:43 +0000
-@@ -6,7 +6,7 @@
- #include <mysql/client_plugin.h>
- #include <violite.h>
- #ifdef HAVE_OPENSSL
--#include <my_secure.h>
++}
++/*
++ write to ssl socket
++
++ SYNOPSIS
++ my_ssl_write()
++ vio vio
++ buf write buffer
++ size size of buffer
++
++ RETURN VALUES
++ bytes written
++*/
++size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size)
++{
++ size_t written;
++ DBUG_ENTER("my_ssl_write");
++
++ written= SSL_write((SSL*) vio->ssl, buf, size);
++ DBUG_RETURN(written);
++}
++
++/*
++ read from ssl socket
++
++ SYNOPSIS
++ my_ssl_read()
++ vio vio
++ buf read buffer
++ size_t max number of bytes to read
++
++ RETURN VALUES
++ number of bytes read
++*/
++size_t my_ssl_read(Vio *vio, uchar* buf, size_t size)
++{
++ size_t read;
++ DBUG_ENTER("my_ssl_read");
++
++ read= SSL_read((SSL*) vio->ssl, buf, size);
++ DBUG_RETURN(read);
++}
++
++/*
++ close ssl connection and free
++ ssl object
++
++ SYNOPSIS
++ my_ssl_close()
++ vio vio
++
++ RETURN VALUES
++ 1 ok
++ 0 or -1 on error
++*/
++int my_ssl_close(Vio *vio)
++{
++ int i, rc;
++ DBUG_ENTER("my_ssl_close");
++
++
++ /* 2 x pending + 2 * data = 4 */
++ for (i=0; i < 4; i++)
++ if ((rc= SSL_shutdown(vio->ssl)))
++ break;
++
++ SSL_free(vio->ssl);
++ vio->ssl= NULL;
++
++ DBUG_RETURN(rc);
++}
++
++#endif /* HAVE_OPENSSL */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/ma_time.c mariadb-native-client.trunk/libmariadb/ma_time.c
+--- mariadb/libmariadb/ma_time.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/ma_time.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,65 @@
++/****************************************************************************
++ Copyright (C) 2013 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*****************************************************************************/
++#include "mysys_priv.h"
++#include <my_global.h>
++#include <mysql.h>
++#include <stdio.h>
++
++
++size_t mariadb_time_to_string(const MYSQL_TIME *tm, char *time_str, size_t len,
++ unsigned int digits)
++{
++ size_t length;
++
++ if (!time_str || !len)
++ return 0;
++
++ if (digits == AUTO_SEC_PART_DIGITS)
++ digits= MIN((tm->second_part) ? SEC_PART_DIGITS : 0, 15);
++
++ switch(tm->time_type) {
++ case MYSQL_TIMESTAMP_DATE:
++ length= snprintf(time_str, len, "%04u-%02u-%02u", tm->year, tm->month, tm->day);
++ digits= 0;
++ break;
++ case MYSQL_TIMESTAMP_DATETIME:
++ length= snprintf(time_str, len, "%04u-%02u-%02u %02u:%02u:%02u",
++ tm->year, tm->month, tm->day, tm->hour, tm->minute, tm->second);
++ break;
++ case MYSQL_TIMESTAMP_TIME:
++ length= snprintf(time_str, len, "%s%02u:%02u:%02u",
++ (tm->neg ? "-" : ""), tm->hour, tm->minute, tm->second);
++ break;
++ default:
++ time_str[0]= '\0';
++ return 0;
++ break;
++ }
++ if (digits && (len < length))
++ {
++ char helper[16];
++ snprintf(helper, 16, ".%%0%du", digits);
++ length+= snprintf(time_str + length, len - length, helper, digits);
++ }
++ return length;
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_dirname.c mariadb-native-client.trunk/libmariadb/mf_dirname.c
+--- mariadb/libmariadb/mf_dirname.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_dirname.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,100 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++ /* Functions definied in this file */
++
++uint dirname_length(const char *name)
++{
++ register my_string pos,gpos;
++#ifdef FN_DEVCHAR
++ if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0)
++#endif
++ pos=(char*) name-1;
++
++ gpos= pos++;
++ for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
++ if (*pos == FN_LIBCHAR || *pos == '/'
++#ifdef FN_C_AFTER_DIR
++ || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
++#endif
++ )
++ gpos=pos;
++ return ((uint) (uint) (gpos+1-(char*) name));
++}
++
++
++ /* Gives directory part of filename. Directory ends with '/' */
++ /* Returns length of directory part */
++
++uint dirname_part(my_string to, const char *name)
++{
++ uint length;
++ DBUG_ENTER("dirname_part");
++ DBUG_PRINT("enter",("'%s'",name));
++
++ length=dirname_length(name);
++ (void) strmake(to,(char*) name,min(length,FN_REFLEN-2));
++ convert_dirname(to); /* Convert chars */
++ DBUG_RETURN(length);
++} /* dirname */
++
++
++ /* convert dirname to use under this system */
++ /* If MSDOS converts '/' to '\' */
++ /* If VMS converts '<' to '[' and '>' to ']' */
++ /* Adds a '/' to end if there isn't one and the last isn't a dev_char */
++ /* ARGSUSED */
++
++#ifndef FN_DEVCHAR
++#define FN_DEVCHAR '\0' /* For easier code */
++#endif
++
++char *convert_dirname(my_string to)
++{
++ reg1 char *pos;
++#if FN_LIBCHAR != '/'
++ {
++ pos=to-1; /* Change from '/' */
++ while ((pos=strchr(pos+1,'/')) != 0)
++ *pos=FN_LIBCHAR;
++ }
++#endif
++#ifdef FN_C_BEFORE_DIR_2
++ {
++ for (pos=to ; *pos ; pos++)
++ {
++ if (*pos == FN_C_BEFORE_DIR_2)
++ *pos=FN_C_BEFORE_DIR;
++ if (*pos == FN_C_AFTER_DIR_2)
++ *pos=FN_C_AFTER_DIR;
++ }
++ }
++#else
++ { /* Append FN_LIBCHAR if not there */
++ pos=strend(to);
++ if (pos != to && (pos[-1] != FN_LIBCHAR && pos[-1] != FN_DEVCHAR))
++ {
++ *pos++=FN_LIBCHAR;
++ *pos=0;
++ }
++ }
++#endif
++ return pos; /* Pointer to end of dir */
++} /* convert_dirname */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_fn_ext.c mariadb-native-client.trunk/libmariadb/mf_fn_ext.c
+--- mariadb/libmariadb/mf_fn_ext.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_fn_ext.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,46 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Returnerar en pekare till filnamnets extension. */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++ /* Return a pointerto the extension of the filename
++ The pointer points at the extension character (normally '.'))
++ If there isn't any extension, the pointer points at the end
++ NULL of the filename
++ */
++
++my_string fn_ext(const char *name)
++{
++ register my_string pos,gpos;
++ DBUG_ENTER("fn_ext");
++ DBUG_PRINT("mfunkt",("name: '%s'",name));
++
++#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR)
++ {
++ char buff[FN_REFLEN];
++ gpos=(my_string) name+dirname_part(buff,(char*) name);
++ }
++#else
++ if (!(gpos=strrchr(name,FNLIBCHAR)))
++ gpos=name;
++#endif
++ pos=strrchr(gpos,FN_EXTCHAR);
++ DBUG_RETURN (pos ? pos : strend(gpos));
++} /* fn_ext */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_format.c mariadb-native-client.trunk/libmariadb/mf_format.c
+--- mariadb/libmariadb/mf_format.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_format.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,156 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#ifdef HAVE_REALPATH
++#include <sys/param.h>
++#include <sys/stat.h>
++#endif
++
++ /* format a filename with replace of library and extension */
++ /* params to and name may be identicall */
++ /* function doesn't change name if name != to */
++ /* Flag may be: 1 replace filenames library with 'dsk' */
++ /* 2 replace extension with 'form' */
++ /* 4 Unpack filename (replace ~ with home) */
++ /* 8 Pack filename as short as possibly */
++ /* 16 Resolve symbolic links for filename */
++ /* 32 Resolve filename to full path */
++ /* 64 Return NULL if too long path */
++
++#ifdef SCO
++#define BUFF_LEN 4097
++#else
++#ifdef MAXPATHLEN
++#define BUFF_LEN MAXPATHLEN
++#else
++#define BUFF_LEN FN_LEN
++#endif
++#endif
++
++my_string fn_format(my_string to, const char *name, const char *dsk,
++ const char *form, int flag)
++{
++ reg1 uint length;
++ char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos;
++ const char *ext;
++ DBUG_ENTER("fn_format");
++ DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d",
++ name,dsk,form,flag));
++
++ /* Kopiera & skippa enheten */
++ name+=(length=dirname_part(dev,(startpos=(my_string) name)));
++ if (length == 0 || flag & 1)
++ {
++ (void) strmake(dev,dsk, sizeof(dev) - 2);
++ /* Use given directory */
++ convert_dirname(dev); /* Fix to this OS */
++ }
++ if (flag & 8)
++ pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
++ if (flag & 4)
++ (void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
++ if ((pos=(char*)strchr(name,FN_EXTCHAR)) != NullS)
++ {
++ if ((flag & 2) == 0) /* Skall vi byta extension ? */
++ {
++ length=strlength(name); /* Old extension */
++ ext = "";
++ }
++ else
++ {
++ length=(uint) (pos-(char*) name); /* Change extension */
++ ext= form;
++ }
++ }
++ else
++ {
++ length=strlength(name); /* Har ingen ext- tag nya */
++ ext=form;
++ }
++
++ if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
++ { /* To long path, return original */
++ uint tmp_length;
++ if (flag & 64)
++ return 0;
++ tmp_length=strlength(startpos);
++ DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %d",dev,ext,length));
++ (void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
++ }
++ else
++ {
++ if (to == startpos)
++ {
++ bmove(buff,(char*) name,length); /* Save name for last copy */
++ name=buff;
++ }
++ pos=strmake(strmov(to,dev),name,length);
++#ifdef FN_UPPER_CASE
++ caseup_str(to);
++#endif
++#ifdef FN_LOWER_CASE
++ casedn_str(to);
++#endif
++ (void) strmov(pos,ext); /* Don't convert extension */
++ }
++ /* Purify gives a lot of UMR errors when using realpath */
++#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
++ if (flag & 16)
++ {
++ struct stat stat_buff;
++ if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
++ {
++ if (realpath(to,buff))
++ strmake(to,buff,FN_REFLEN-1);
++ }
++ }
++#endif
++ DBUG_RETURN (to);
++} /* fn_format */
++
++
++ /*
++ strlength(const string str)
++ Return length of string with end-space:s not counted.
++ */
++
++size_s strlength(const char *str)
++{
++ reg1 my_string pos;
++ reg2 my_string found;
++ DBUG_ENTER("strlength");
++
++ pos=found=(char*) str;
++
++ while (*pos)
++ {
++ if (*pos != ' ')
++ {
++ while (*++pos && *pos != ' ') {};
++ if (!*pos)
++ {
++ found=pos; /* String ends here */
++ break;
++ }
++ }
++ found=pos;
++ while (*++pos == ' ') {};
++ }
++ DBUG_RETURN((size_s) (found-(char*) str));
++} /* strlength */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_loadpath.c mariadb-native-client.trunk/libmariadb/mf_loadpath.c
+--- mariadb/libmariadb/mf_loadpath.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_loadpath.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,54 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++ /* Returns full load-path for a file. to may be = path */
++ /* if path is a hard-path return path */
++ /* if path starts with home-dir return path */
++ /* if path starts with current dir or parent-dir unpack path */
++ /* if there is no path, prepend with own_path_prefix if given */
++ /* else unpack path according to current dir */
++
++my_string my_load_path(my_string to, const char *path,
++ const char *own_path_prefix)
++{
++ char buff[FN_REFLEN];
++ DBUG_ENTER("my_load_path");
++ DBUG_PRINT("enter",("path: %s prefix: %s",path,
++ own_path_prefix ? own_path_prefix : ""));
++
++ if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
++ test_if_hard_path(path))
++ VOID(strmov(buff,path));
++ else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) ||
++ (is_prefix((gptr) path,FN_PARENTDIR) &&
++ path[strlen(FN_PARENTDIR)] == FN_LIBCHAR) ||
++ ! own_path_prefix)
++ {
++ if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
++ VOID(strcat(buff,path));
++ else
++ VOID(strmov(buff,path));
++ }
++ else
++ VOID(strxmov(buff,own_path_prefix,path,NullS));
++ strmov(to,buff);
++ DBUG_PRINT("exit",("to: %s",to));
++ DBUG_RETURN(to);
++} /* my_load_path */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_pack.c mariadb-native-client.trunk/libmariadb/mf_pack.c
+--- mariadb/libmariadb/mf_pack.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_pack.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,532 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif
++#ifdef VMS
++#include <rms.h>
++#include <iodef.h>
++#include <descrip.h>
++#endif /* VMS */
++
++static my_string NEAR_F expand_tilde(my_string *path);
++
++ /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
++ /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
++ /* to may be == from */
++
++void pack_dirname(my_string to, const char *from)
++{
++ int cwd_err;
++ uint d_length,length,buff_length= 0;
++ my_string start;
++ char buff[FN_REFLEN];
++ DBUG_ENTER("pack_dirname");
++
++ (void) intern_filename(to,from); /* Change to intern name */
++
++#ifdef FN_DEVCHAR
++ if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skipp device part */
++ start++;
++ else
++#endif
++ start=to;
++
++ LINT_INIT(buff_length);
++ if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
++ {
++ buff_length= (uint) strlen(buff);
++ d_length=(uint) (start-to);
++ if ((start == to ||
++ (buff_length == d_length && !bcmp(buff,start,d_length))) &&
++ *start != FN_LIBCHAR && *start)
++ { /* Put current dir before */
++ bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
++ }
++ }
++
++ if ((d_length= cleanup_dirname(to,to)) != 0)
++ {
++ length=0;
++ if (home_dir)
++ {
++ length= (uint) strlen(home_dir);
++ if (home_dir[length-1] == FN_LIBCHAR)
++ length--; /* Don't test last '/' */
++ }
++ if (length > 1 && length < d_length)
++ { /* test if /xx/yy -> ~/yy */
++ if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
++ {
++ to[0]=FN_HOMELIB; /* Filename begins with ~ */
++ (void) strmov_overlapp(to+1,to+length);
++ }
++ }
++ if (! cwd_err)
++ { /* Test if cwd is ~/... */
++ if (length > 1 && length < buff_length)
++ {
++ if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
++ {
++ buff[0]=FN_HOMELIB;
++ (void) strmov_overlapp(buff+1,buff+length);
++ }
++ }
++ if (is_prefix(to,buff))
++ {
++ length= (uint) strlen(buff);
++ if (to[length])
++ (void) strmov_overlapp(to,to+length); /* Remove everything before */
++ else
++ {
++ to[0]= FN_CURLIB; /* Put ./ instead of cwd */
++ to[1]= FN_LIBCHAR;
++ to[2]= '\0';
++ }
++ }
++ }
++ }
++ DBUG_PRINT("exit",("to: '%s'",to));
++ DBUG_VOID_RETURN;
++} /* pack_dirname */
++
++
++ /* remove unwanted chars from dirname */
++ /* if "/../" removes prev dir; "/~/" removes all before ~ */
++ /* "//" is same as "/", except on Win32 at start of a file */
++ /* "/./" is removed */
++ /* Unpacks home_dir if "~/.." used */
++ /* Unpacks current dir if if "./.." used */
++
++uint cleanup_dirname(register my_string to, const char *from)
++ /* to may be == from */
++
++{
++ reg5 uint length;
++ reg2 my_string pos;
++ reg3 my_string from_ptr;
++ reg4 my_string start;
++ char parent[5], /* for "FN_PARENTDIR" */
++ buff[FN_REFLEN+1],*end_parentdir;
++ DBUG_ENTER("cleanup_dirname");
++ DBUG_PRINT("enter",("from: '%s'",from));
++
++ start=buff;
++ from_ptr=(my_string) from;
++#ifdef FN_DEVCHAR
++ if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
++ { /* Skipp device part */
++ length=(uint) (pos-from_ptr)+1;
++ start=strnmov(buff,from_ptr,length); from_ptr+=length;
++ }
++#endif
++
++ parent[0]=FN_LIBCHAR;
++ length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
++ for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
++ {
++ if (*pos == '/')
++ *pos = FN_LIBCHAR;
++ if (*pos == FN_LIBCHAR)
++ {
++ if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
++ { /* If .../../; skipp prev */
++ pos-=length;
++ if (pos != start)
++ { /* not /../ */
++ pos--;
++ if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
++ {
++ if (!home_dir)
++ {
++ pos+=length+1; /* Don't unpack ~/.. */
++ continue;
++ }
++ pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
++ if (*pos == FN_LIBCHAR)
++ pos--; /* home ended with '/' */
++ }
++ if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
++ {
++ if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
++ {
++ pos+=length+1; /* Don't unpack ./.. */
++ continue;
++ }
++ pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
++ if (*pos == FN_LIBCHAR)
++ pos--; /* home ended with '/' */
++ }
++ end_parentdir=pos;
++ while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
++ pos--;
++ if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
++ { /* Don't remove ~user/ */
++ pos=strmov(end_parentdir+1,parent);
++ *pos=FN_LIBCHAR;
++ continue;
++ }
++ }
++ }
++ else if ((uint) (pos-start) == length-1 &&
++ !bcmp(start,parent+1,length-1))
++ start=pos; /* Starts with "../" */
++ else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
++ {
++#ifdef FN_NETWORK_DRIVES
++ if (pos-start != 1)
++#endif
++ pos--; /* Remove dupplicate '/' */
++ }
++ else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
++ pos-=2; /* Skipp /./ */
++ else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
++ { /* Found ..../~/ */
++ buff[0]=FN_HOMELIB;
++ buff[1]=FN_LIBCHAR;
++ start=buff; pos=buff+1;
++ }
++ }
++ }
++ (void) strmov(to,buff);
++ DBUG_PRINT("exit",("to: '%s'",to));
++ DBUG_RETURN((uint) (pos-buff));
++} /* cleanup_dirname */
++
++
++ /*
++ On system where you don't have symbolic links, the following
++ code will allow you to create a file:
++ directory-name.lnk that should contain the real path
++ to the directory. This will be used if the directory name
++ doesn't exists
++ */
++
++
++my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
++
++#ifdef USE_SYMDIR
++void symdirget(char *dir)
++{
++ char buff[FN_REFLEN];
++ char *pos=strend(dir);
++ if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK))
++ {
++ FILE *fp;
++ char temp= *(--pos); /* May be "/" or "\" */
++ strmov(pos,".sym");
++ fp = my_fopen(dir, O_RDONLY,MYF(0));
++ *pos++=temp; *pos=0; /* Restore old filename */
++ if (fp)
++ {
++ if (fgets(buff, sizeof(buff)-1, fp))
++ {
++ for (pos=strend(buff);
++ pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
++ pos --);
++
++ /* Ensure that the symlink ends with the directory symbol */
++ if (pos == buff || pos[-1] != FN_LIBCHAR)
++ *pos++=FN_LIBCHAR;
++
++ strmake(dir,buff, (uint) (pos-buff));
++ }
++ my_fclose(fp,MYF(0));
++ }
++ }
++}
++#endif /* USE_SYMDIR */
++
++ /* Unpacks dirname to name that can be used by open... */
++ /* Make that last char of to is '/' if from not empty and
++ from doesn't end in FN_DEVCHAR */
++ /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */
++ /* Returns length of new directory */
++
++uint unpack_dirname(my_string to, const char *from)
++
++ /* to may be == from */
++{
++ uint length,h_length;
++ char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
++ DBUG_ENTER("unpack_dirname");
++
++ (void) intern_filename(buff,from); /* Change to intern name */
++ length= (uint) strlen(buff); /* Fix that '/' is last */
++ if (length &&
++#ifdef FN_DEVCHAR
++ buff[length-1] != FN_DEVCHAR &&
++#endif
++ buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
++ {
++ buff[length]=FN_LIBCHAR;
++ buff[length+1]= '\0';
++ }
++
++ length=cleanup_dirname(buff,buff);
++ if (buff[0] == FN_HOMELIB)
++ {
++ suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
++ if (tilde_expansion)
++ {
++ length-=(uint) (suffix-buff)-1;
++ if (length+(h_length= (uint) strlen(tilde_expansion)) <= FN_REFLEN)
++ {
++ if (tilde_expansion[h_length-1] == FN_LIBCHAR)
++ h_length--;
++ if (buff+h_length < suffix)
++ bmove(buff+h_length,suffix,length);
++ else
++ bmove_upp(buff+h_length+length,suffix+length,length);
++ bmove(buff,tilde_expansion,h_length);
++ }
++ }
++ }
++#ifdef USE_SYMDIR
++ if (my_use_symdir)
++ symdirget(buff);
++#endif
++ DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
++} /* unpack_dirname */
++
++
++ /* Expand tilde to home or user-directory */
++ /* Path is reset to point at FN_LIBCHAR after ~xxx */
++
++static my_string NEAR_F expand_tilde(my_string *path)
++{
++ if (path[0][0] == FN_LIBCHAR)
++ return home_dir; /* ~/ expanded to home */
++#ifdef HAVE_GETPWNAM
++ {
++ char *str,save;
++ struct passwd *user_entry;
++
++ if (!(str=strchr(*path,FN_LIBCHAR)))
++ str=strend(*path);
++ save= *str; *str= '\0';
++ user_entry=getpwnam(*path);
++ *str=save;
++ endpwent();
++ if (user_entry)
++ {
++ *path=str;
++ return user_entry->pw_dir;
++ }
++ }
++#endif
++ return (my_string) 0;
++}
++
++ /* fix filename so it can be used by open, create .. */
++ /* to may be == from */
++ /* Returns to */
++
++my_string unpack_filename(my_string to, const char *from)
++{
++ uint length,n_length;
++ char buff[FN_REFLEN];
++ DBUG_ENTER("unpack_filename");
++
++ length=dirname_part(buff,from); /* copy & convert dirname */
++ n_length=unpack_dirname(buff,buff);
++ if (n_length+strlen(from+length) < FN_REFLEN)
++ {
++ (void) strmov(buff+n_length,from+length);
++ (void) system_filename(to,buff); /* Fix to usably filename */
++ }
++ else
++ (void) system_filename(to,from); /* Fix to usably filename */
++ DBUG_RETURN(to);
++} /* unpack_filename */
++
++
++ /* Convert filename (unix standard) to system standard */
++ /* Used before system command's like open(), create() .. */
++ /* Returns to */
++
++uint system_filename(my_string to, const char *from)
++{
++#ifndef FN_C_BEFORE_DIR
++ return (uint) (strmake(to,from,FN_REFLEN-1)-to);
++#else /* VMS */
++
++ /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
++ /* change 'dev:xxx' to 'dev:xxx' */
++ /* change './xxx' to 'xxx' */
++ /* change './lib/' or lib/ to '[.lib]' */
++ /* change '/x/y/z to '[x.y]x' */
++ /* change 'dev:/x' to 'dev:[000000]x' */
++
++ int libchar_found,length;
++ my_string to_pos,from_pos,pos;
++ char buff[FN_REFLEN];
++ DBUG_ENTER("system_filename");
++
++ libchar_found=0;
++ (void) strmov(buff,from); /* If to == from */
++ from_pos= buff;
++ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
++ {
++ pos++;
++ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
++ from_pos=pos;
++ }
++ else
++ to_pos=to;
++
++ if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
++ from_pos+=2; /* Skipp './' */
++ if (strchr(from_pos,FN_LIBCHAR))
++ {
++ *(to_pos++) = FN_C_BEFORE_DIR;
++ if (strinstr(from_pos,FN_ROOTDIR) == 1)
++ {
++ from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
++ if (! strchr(from_pos,FN_LIBCHAR))
++ { /* No dir, use [000000] */
++ to_pos=strmov(to_pos,FN_C_ROOT_DIR);
++ libchar_found++;
++ }
++ }
++ else
++ *(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
++
++ while ((pos=strchr(from_pos,FN_LIBCHAR)))
++ {
++ if (libchar_found++)
++ *(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
++ if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
++ from_pos+strlen(FN_PARENTDIR) == pos)
++ to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
++ else
++ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
++ from_pos=pos+1;
++ }
++ *(to_pos++)=FN_C_AFTER_DIR;
++ }
++ length=(int) (strmov(to_pos,from_pos)-to);
++ DBUG_PRINT("exit",("name: '%s'",to));
++ DBUG_RETURN((uint) length);
++#endif
++} /* system_filename */
++
++
++ /* Fix a filename to intern (UNIX format) */
++
++my_string intern_filename(my_string to, const char *from)
++{
++#ifndef VMS
++ {
++ uint length;
++ char buff[FN_REFLEN];
++ if (from == to)
++ { /* Dirname may destroy from */
++ strmov(buff,from);
++ from=buff;
++ }
++ length=dirname_part(to,from); /* Copy dirname & fix chars */
++ (void) strcat(to,from+length);
++ return (to);
++ }
++#else /* VMS */
++
++ /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
++ /* change 'dev:xxx' to 'dev:xxx' */
++ /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
++ /* change '[.lib]' to './lib/' */
++ /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
++ /* change '[000000.x] or [x.000000]' to '/x/' */
++
++ int par_length,root_length;
++ my_string pos,from_pos,to_pos,end_pos;
++ char buff[FN_REFLEN];
++
++ (void) strmov(buff,from);
++ convert_dirname(buff); /* change '<>' to '[]' */
++ from_pos=buff;
++ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
++ {
++ pos++;
++ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
++ from_pos=pos;
++ }
++ else
++ to_pos=to;
++
++ root_length=strlen(FN_C_ROOT_DIR);
++ if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
++ (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
++ {
++ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
++ /* Copy all between ':' and '[' */
++ from_pos=pos+1;
++ if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
++ (from_pos[root_length] == FN_C_DIR_SEP ||
++ from_pos[root_length] == FN_C_AFTER_DIR))
++ {
++ from_pos+=root_length+1;
++ }
++ else if (*from_pos == FN_C_DIR_SEP)
++ *(to_pos++) = FN_CURLIB; /* Set ./ first */
++ *(to_pos++) = FN_LIBCHAR;
++
++ par_length=strlen(FN_C_PARENT_DIR);
++ pos=to_pos;
++ for (; from_pos <= end_pos ; from_pos++)
++ {
++ switch (*from_pos) {
++ case FN_C_DIR_SEP:
++ case FN_C_AFTER_DIR:
++ if (pos != to_pos)
++ {
++ if ((int) (to_pos-pos) == root_length &&
++ is_suffix(pos,FN_C_ROOT_DIR))
++ to_pos=pos; /* remove root-pos */
++ else
++ {
++ *(to_pos++)=FN_LIBCHAR; /* Find lib */
++ pos=to_pos;
++ }
++ }
++ break;
++ case FN_C_BEFORE_DIR:
++ break;
++ case '-': /* *(FN_C_PARENT_DIR): */
++ if (to_pos[-1] == FN_LIBCHAR &&
++ strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
++ { /* Change '-' to '..' */
++ to_pos=strmov(to_pos,FN_PARENTDIR);
++ *(to_pos++)=FN_LIBCHAR;
++ pos=to_pos;
++ from_pos+=par_length-1;
++ break;
++ }
++ /* Fall through */
++ default:
++ *(to_pos++)= *from_pos;
++ break;
++ }
++ }
++ }
++ (void) strmov(to_pos,from_pos);
++ return (to);
++#endif /* VMS */
++} /* intern_filename */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_path.c mariadb-native-client.trunk/libmariadb/mf_path.c
+--- mariadb/libmariadb/mf_path.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_path.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,120 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++static char *find_file_in_path(char *to,const char *name);
++
++ /* Finds where program can find it's files.
++ pre_pathname is found by first locking at progname (argv[0]).
++ if progname contains path the path is returned.
++ else if progname is found in path, return it
++ else if progname is given and POSIX environment variable "_" is set
++ then path is taken from "_".
++ If filename doesn't contain a path append MY_BASEDIR_VERSION or
++ MY_BASEDIR if defined, else append "/my/running".
++ own_path_name_part is concatinated to result.
++ my_path puts result in to and returns to */
++
++my_string my_path(my_string to, const char *progname,
++ const char *own_pathname_part)
++{
++ my_string start,end,prog;
++ DBUG_ENTER("my_path");
++
++ start=to; /* Return this */
++ if (progname && (dirname_part(to, progname) ||
++ find_file_in_path(to,progname) ||
++ ((prog=getenv("_")) != 0 && dirname_part(to,prog))))
++ {
++ VOID(intern_filename(to,to));
++ if (!test_if_hard_path(to))
++ {
++ if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
++ bchange(to,0,curr_dir, (uint) strlen(curr_dir), (uint) strlen(to)+1);
++ }
++ }
++ else
++ {
++ if ((end = getenv("MY_BASEDIR_VERSION")) == 0 &&
++ (end = getenv("MY_BASEDIR")) == 0)
++ {
++#ifdef DEFAULT_BASEDIR
++ end= (char*) DEFAULT_BASEDIR;
++#else
++ end= (char*) "/my/";
++#endif
++ }
++ VOID(intern_filename(to,end));
++ to=strend(to);
++ if (to != start && to[-1] != FN_LIBCHAR)
++ *to++ = FN_LIBCHAR;
++ VOID(strmov(to,own_pathname_part));
++ }
++ DBUG_PRINT("exit",("to: '%s'",start));
++ DBUG_RETURN(start);
++} /* my_path */
++
++
++ /* test if file without filename is found in path */
++ /* Returns to if found and to has dirpart if found, else NullS */
++
++#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
++#define F_OK 0
++#define PATH_SEP ';'
++#define PROGRAM_EXTENSION ".exe"
++#else
++#define PATH_SEP ':'
++#endif
++
++static char *find_file_in_path(char *to, const char *name)
++{
++ char *path,*pos,dir[2];
++ const char *ext="";
++
++ if (!(path=getenv("PATH")))
++ return NullS;
++ dir[0]=FN_LIBCHAR; dir[1]=0;
++#ifdef PROGRAM_EXTENSION
++ if (!fn_ext(name)[0])
++ ext=PROGRAM_EXTENSION;
++#endif
++
++ for (pos=path ; (pos=strchr(pos,PATH_SEP)) ; path= ++pos)
++ {
++ if (path != pos)
++ {
++ strxmov(strnmov(to,path,(uint) (pos-path)),dir,name,ext,NullS);
++ if (!access(to,F_OK))
++ {
++ to[(uint) (pos-path)+1]=0; /* Return path only */
++ return to;
++ }
++ }
++ }
++#ifdef _WIN32
++ to[0]=FN_CURLIB;
++ strxmov(to+1,dir,name,ext,NullS);
++ if (!access(to,F_OK)) /* Test in current dir */
++ {
++ to[2]=0; /* Leave ".\" */
++ return to;
++ }
++#endif
++ return NullS; /* File not found */
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_unixpath.c mariadb-native-client.trunk/libmariadb/mf_unixpath.c
+--- mariadb/libmariadb/mf_unixpath.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_unixpath.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++ /* convert filename to unix style filename */
++ /* If MSDOS converts '\' to '/' */
++
++void to_unix_path(my_string to __attribute__((unused)))
++{
++#if FN_LIBCHAR != '/'
++ {
++ to--;
++ while ((to=strchr(to+1,FN_LIBCHAR)) != 0)
++ *to='/';
++ }
++#endif
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mf_wcomp.c mariadb-native-client.trunk/libmariadb/mf_wcomp.c
+--- mariadb/libmariadb/mf_wcomp.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mf_wcomp.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,68 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Funktions for comparing with wild-cards */
++
++#include "mysys_priv.h"
++
++ /* Test if a string is "comparable" to a wild-card string */
++ /* returns 0 if the strings are "comparable" */
++
++char wild_many='*';
++char wild_one='?';
++char wild_prefix=0;
++
++int wild_compare(register const char *str, register const char *wildstr)
++{
++ reg3 int flag;
++ DBUG_ENTER("wild_compare");
++
++ while (*wildstr)
++ {
++ while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
++ {
++ if (*wildstr == wild_prefix && wildstr[1])
++ wildstr++;
++ if (*wildstr++ != *str++) DBUG_RETURN(1);
++ }
++ if (! *wildstr ) DBUG_RETURN (*str != 0);
++ if (*wildstr++ == wild_one)
++ {
++ if (! *str++) DBUG_RETURN (1); /* One char; skipp */
++ }
++ else
++ { /* Found '*' */
++ if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
++ flag=(*wildstr != wild_many && *wildstr != wild_one);
++ do
++ {
++ if (flag)
++ {
++ char cmp;
++ if ((cmp= *wildstr) == wild_prefix && wildstr[1])
++ cmp=wildstr[1];
++ while (*str && *str != cmp)
++ str++;
++ if (!*str) DBUG_RETURN (1);
++ }
++ if (wild_compare(str,wildstr) == 0) DBUG_RETURN (0);
++ } while (*str++ && wildstr[0] != wild_many);
++ DBUG_RETURN(1);
++ }
++ }
++ DBUG_RETURN (*str != '\0');
++} /* wild_compare */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mulalloc.c mariadb-native-client.trunk/libmariadb/mulalloc.c
+--- mariadb/libmariadb/mulalloc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mulalloc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,53 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++ /* Malloc many pointers at the same time */
++ /* format myFlags,ptr,length,ptr,length ... until null ptr */
++
++#include "mysys_priv.h"
++#include <stdarg.h>
++
++gptr my_multi_malloc(myf myFlags, ...)
++{
++ va_list args;
++ char **ptr,*start,*res;
++ uint tot_length,length;
++ DBUG_ENTER("my_multi_malloc");
++
++ va_start(args,myFlags);
++ tot_length=0;
++ while ((ptr=va_arg(args, char **)))
++ {
++ length=va_arg(args,uint);
++ tot_length+=ALIGN_SIZE(length);
++ }
++ va_end(args);
++
++ if (!(start=(char *) my_malloc(tot_length,myFlags)))
++ DBUG_RETURN(0); /* purecov: inspected */
++
++ va_start(args,myFlags);
++ res=start;
++ while ((ptr=va_arg(args, char **)))
++ {
++ *ptr=res;
++ length=va_arg(args,uint);
++ res+=ALIGN_SIZE(length);
++ }
++ va_end(args);
++ DBUG_RETURN((gptr) start);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_alloc.c mariadb-native-client.trunk/libmariadb/my_alloc.c
+--- mariadb/libmariadb/my_alloc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_alloc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,154 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Routines to handle mallocing of results which will be freed the same time */
++
++#include <my_global.h>
++#include <my_sys.h>
++#include <m_string.h>
++
++void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size)
++{
++ mem_root->free=mem_root->used=0;
++ mem_root->min_malloc=32;
++ mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
++ mem_root->error_handler=0;
++#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
++ if (pre_alloc_size)
++ {
++ if ((mem_root->free = mem_root->pre_alloc=
++ (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
++ MYF(0))))
++ {
++ mem_root->free->size=pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
++ mem_root->free->left=pre_alloc_size;
++ mem_root->free->next=0;
++ }
++ }
++#endif
++}
++
++gptr alloc_root(MEM_ROOT *mem_root, size_t Size)
++{
++#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
++ reg1 USED_MEM *next;
++ Size+=ALIGN_SIZE(sizeof(USED_MEM));
++
++ if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
++ {
++ if (mem_root->error_handler)
++ (*mem_root->error_handler)();
++ return((gptr) 0); /* purecov: inspected */
++ }
++ next->next=mem_root->used;
++ mem_root->used=next;
++ return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
++#else
++ size_t get_size,max_left;
++ gptr point;
++ reg1 USED_MEM *next;
++ reg2 USED_MEM **prev;
++
++ Size= ALIGN_SIZE(Size);
++ prev= &mem_root->free;
++ max_left=0;
++ for (next= *prev ; next && next->left < Size ; next= next->next)
++ {
++ if (next->left > max_left)
++ max_left=next->left;
++ prev= &next->next;
++ }
++ if (! next)
++ { /* Time to alloc new block */
++ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
++ if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
++ get_size=mem_root->block_size; /* Normal alloc */
++
++ if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
++ {
++ if (mem_root->error_handler)
++ (*mem_root->error_handler)();
++ return((gptr) 0); /* purecov: inspected */
++ }
++ next->next= *prev;
++ next->size= get_size;
++ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
++ *prev=next;
++ }
++ point= (gptr) ((char*) next+ (next->size-next->left));
++ if ((next->left-= Size) < mem_root->min_malloc)
++ { /* Full block */
++ *prev=next->next; /* Remove block from list */
++ next->next=mem_root->used;
++ mem_root->used=next;
++ }
++ return(point);
++#endif
++}
++
++ /* deallocate everything used by alloc_root */
++
++void free_root(MEM_ROOT *root, myf MyFlags)
++{
++ reg1 USED_MEM *next,*old;
++ DBUG_ENTER("free_root");
++
++ if (!root)
++ DBUG_VOID_RETURN; /* purecov: inspected */
++ if (!(MyFlags & MY_KEEP_PREALLOC))
++ root->pre_alloc=0;
++
++ for ( next=root->used; next ;)
++ {
++ old=next; next= next->next ;
++ if (old != root->pre_alloc)
++ my_free((gptr) old,MYF(0));
++ }
++ for (next= root->free ; next ; )
++ {
++ old=next; next= next->next ;
++ if (old != root->pre_alloc)
++ my_free((gptr) old,MYF(0));
++ }
++ root->used=root->free=0;
++ if (root->pre_alloc)
++ {
++ root->free=root->pre_alloc;
++ root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
++ root->free->next=0;
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++char *strdup_root(MEM_ROOT *root,const char *str)
++{
++ size_t len= strlen(str)+1;
++ char *pos;
++ if ((pos=alloc_root(root,len)))
++ memcpy(pos,str,len);
++ return pos;
++}
++
++
++char *memdup_root(MEM_ROOT *root, const char *str, size_t len)
++{
++ char *pos;
++ if ((pos=alloc_root(root,len)))
++ memcpy(pos,str,len);
++ return pos;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_auth.c mariadb-native-client.trunk/libmariadb/my_auth.c
+--- mariadb/libmariadb/my_auth.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_auth.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,698 @@
++#include <my_global.h>
++#include <my_sys.h>
++#include <m_string.h>
++#include <errmsg.h>
++#include <ma_common.h>
++#include <mysql/client_plugin.h>
++#include <violite.h>
++#ifdef HAVE_OPENSSL
+#include <ma_secure.h>
- #endif
-
- typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
-@@ -45,10 +45,19 @@
- NULL,
- old_password_auth_client
- };
++#endif
++
++typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
++static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t);
++static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
++static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
++extern void read_user_name(char *name);
++extern uchar *ma_send_connect_attr(MYSQL *mysql, uchar *buffer);
++
++#define compile_time_assert(A) \
++do {\
++ typedef char constraint[(A) ? 1 : -1];\
++} while (0);
++
++static auth_plugin_t native_password_client_plugin=
++{
++ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
++ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
++ native_password_plugin_name,
++ "R.J.Silk, Sergei Golubchik",
++ "Native MySQL authentication",
++ {1, 0, 0},
++ NULL,
++ NULL,
++ native_password_auth_client
++};
++
++static auth_plugin_t old_password_client_plugin=
++{
++ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
++ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
++ old_password_plugin_name,
++ "R.J.Silk, Sergei Golubchik",
++ "Old MySQL-3.23 authentication",
++ {1, 0, 0},
++ NULL,
++ NULL,
++ old_password_auth_client
++};
+typedef struct st_mariadb_client_plugin_DBAPI dbapi_plugin_t;
+
+#ifdef HAVE_SQLITE
+extern dbapi_plugin_t sqlite3_plugin;
+#endif
-
- struct st_mysql_client_plugin *mysql_client_builtins[]=
- {
++
++struct st_mysql_client_plugin *mysql_client_builtins[]=
++{
+ (struct st_mysql_client_plugin *)&old_password_client_plugin,
- (struct st_mysql_client_plugin *)&native_password_client_plugin,
++ (struct st_mysql_client_plugin *)&native_password_client_plugin,
+#ifdef HAVE_SQLITE
+ (struct st_mysql_client_plugin *)&sqlite3_plugin,
+#endif
- 0
- };
-
-@@ -324,7 +333,7 @@
- Send mysql->client_flag, max_packet_size - unencrypted otherwise
- the server does not know we want to do SSL
- */
-- if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net))
++ 0
++};
++
++typedef struct {
++ int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
++ int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, size_t pkt_len);
++ void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
++ /* -= end of MYSQL_PLUGIN_VIO =- */
++ MYSQL *mysql;
++ auth_plugin_t *plugin; /**< what plugin we're under */
++ const char *db;
++ struct {
++ uchar *pkt; /**< pointer into NET::buff */
++ uint pkt_len;
++ } cached_server_reply;
++ uint packets_read, packets_written; /**< counters for send/received packets */
++ my_bool mysql_change_user; /**< if it's mysql_change_user() */
++ int last_read_packet_len; /**< the length of the last *read* packet */
++} MCPVIO_EXT;
++
++static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
++{
++ int pkt_len;
++ uchar *pkt;
++
++ if (((MCPVIO_EXT *)vio)->mysql_change_user)
++ {
++ /*
++ in mysql_change_user() the client sends the first packet.
++ we use the old scramble.
++ */
++ pkt= (uchar*)mysql->scramble_buff;
++ pkt_len= SCRAMBLE_LENGTH + 1;
++ }
++ else
++ {
++ /* read the scramble */
++ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
++ return CR_ERROR;
++
++ if (pkt_len != SCRAMBLE_LENGTH + 1)
++ return CR_SERVER_HANDSHAKE_ERR;
++
++ /* save it in MYSQL */
++ memcpy(mysql->scramble_buff, pkt, SCRAMBLE_LENGTH);
++ mysql->scramble_buff[SCRAMBLE_LENGTH] = 0;
++ }
++
++ if (mysql->passwd[0])
++ {
++ char scrambled[SCRAMBLE_LENGTH + 1];
++ my_scramble_41((uchar *)scrambled, (char*)pkt, mysql->passwd);
++ if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH))
++ return CR_ERROR;
++ }
++ else
++ if (vio->write_packet(vio, 0, 0)) /* no password */
++ return CR_ERROR;
++
++ return CR_OK;
++}
++
++
++/**
++ client authentication plugin that does old MySQL authentication
++ using an 8-byte (4.0-) scramble
++*/
++
++static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
++{
++ uchar *pkt;
++ int pkt_len;
++
++ if (((MCPVIO_EXT *)vio)->mysql_change_user)
++ {
++ /*
++ in mysql_change_user() the client sends the first packet.
++ we use the old scramble.
++ */
++ pkt= (uchar*)mysql->scramble_buff;
++ pkt_len= SCRAMBLE_LENGTH_323 + 1;
++ }
++ else
++ {
++ /* read the scramble */
++ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
++ return CR_ERROR;
++
++ if (pkt_len != SCRAMBLE_LENGTH_323 + 1 &&
++ pkt_len != SCRAMBLE_LENGTH + 1)
++ return CR_SERVER_HANDSHAKE_ERR;
++
++ /* save it in MYSQL */
++ memcpy(mysql->scramble_buff, pkt, pkt_len);
++ mysql->scramble_buff[pkt_len] = 0;
++ }
++
++ if (mysql->passwd[0])
++ {
++ char scrambled[SCRAMBLE_LENGTH_323 + 1];
++ scramble_323(scrambled, (char*)pkt, mysql->passwd);
++ if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1))
++ return CR_ERROR;
++ }
++ else
++ if (vio->write_packet(vio, 0, 0)) /* no password */
++ return CR_ERROR;
++
++ return CR_OK;
++}
++
++static int send_change_user_packet(MCPVIO_EXT *mpvio,
++ const uchar *data, int data_len)
++{
++ MYSQL *mysql= mpvio->mysql;
++ char *buff, *end;
++ int res= 1;
++ size_t conn_attr_len= (mysql->options.extension) ?
++ mysql->options.extension->connect_attrs_len : 0;
++
++ buff= my_alloca(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1 + 9 + conn_attr_len);
++
++ end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
++
++ if (!data_len)
++ *end++= 0;
++ else
++ {
++ if (mysql->client_flag & CLIENT_SECURE_CONNECTION)
++ {
++ DBUG_ASSERT(data_len <= 255);
++ if (data_len > 255)
++ {
++ my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0);
++ goto error;
++ }
++ *end++= data_len;
++ }
++ else
++ {
++ DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1);
++ DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0);
++ }
++ memcpy(end, data, data_len);
++ end+= data_len;
++ }
++ end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
++
++ if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
++ {
++ int2store(end, (ushort) mysql->charset->nr);
++ end+= 2;
++ }
++
++ if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
++ end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
++
++ end= ma_send_connect_attr(mysql, end);
++
++ res= simple_command(mysql, MYSQL_COM_CHANGE_USER,
++ buff, (ulong)(end-buff), 1, NULL);
++
++error:
++ my_afree(buff);
++ return res;
++}
++
++
++
++static int send_client_reply_packet(MCPVIO_EXT *mpvio,
++ const uchar *data, int data_len)
++{
++ MYSQL *mysql= mpvio->mysql;
++ NET *net= &mysql->net;
++ char *buff, *end;
++ size_t conn_attr_len= (mysql->options.extension) ?
++ mysql->options.extension->connect_attrs_len : 0;
++
++ /* see end= buff+32 below, fixed size of the packet is 32 bytes */
++ buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9);
++
++ mysql->client_flag|= mysql->options.client_flag;
++ mysql->client_flag|= CLIENT_CAPABILITIES;
++
++ if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
++ mysql->client_flag|= CLIENT_MULTI_RESULTS;
++
++#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
++ if (mysql->options.ssl_key || mysql->options.ssl_cert ||
++ mysql->options.ssl_ca || mysql->options.ssl_capath ||
++ mysql->options.ssl_cipher)
++ mysql->options.use_ssl= 1;
++ if (mysql->options.use_ssl)
++ mysql->client_flag|= CLIENT_SSL;
++#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
++ if (mpvio->db)
++ mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
++
++ /* Remove options that server doesn't support */
++ mysql->client_flag= mysql->client_flag &
++ (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
++ | mysql->server_capabilities);
++
++#ifndef HAVE_COMPRESS
++ mysql->client_flag&= ~CLIENT_COMPRESS;
++#endif
++
++ if (mysql->client_flag & CLIENT_PROTOCOL_41)
++ {
++ /* 4.1 server and 4.1 client has a 32 byte option flag */
++ int4store(buff,mysql->client_flag);
++ int4store(buff+4, net->max_packet_size);
++ buff[8]= (char) mysql->charset->nr;
++ bzero(buff+9, 32-9);
++ end= buff+32;
++ }
++ else
++ {
++ int2store(buff, mysql->client_flag);
++ int3store(buff+2, net->max_packet_size);
++ end= buff+5;
++ }
++#ifdef HAVE_OPENSSL
++ if (mysql->options.ssl_key ||
++ mysql->options.ssl_cert ||
++ mysql->options.ssl_ca ||
++ mysql->options.ssl_capath ||
++ mysql->options.ssl_cipher
++#ifdef CRL_IMPLEMENTED
++ || (mysql->options.extension &&
++ (mysql->options.extension->ssl_crl ||
++ mysql->options.extension->ssl_crlpath))
++#endif
++ )
++ mysql->options.use_ssl= 1;
++ if (mysql->options.use_ssl &&
++ (mysql->client_flag & CLIENT_SSL))
++ {
++ SSL *ssl;
++ /*
++ Send mysql->client_flag, max_packet_size - unencrypted otherwise
++ the server does not know we want to do SSL
++ */
+ if (my_net_write(net, (char*)buff, (size_t) (end-buff)) || net_flush(net))
- {
- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
- ER(CR_SERVER_LOST_EXTENDED),
-
-=== modified file 'libmariadb/my_charset.c'
---- mariadb/libmysql/my_charset.c 2012-11-27 08:57:10 +0000
-+++ mariadb/libmariadb/my_charset.c 2013-03-14 21:01:43 +0000
-@@ -15,6 +15,9 @@
- License along with this library; if not see <http://www.gnu.org/licenses>
- or write to the Free Software Foundation, Inc.,
- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++ {
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "sending connection information to server",
++ errno);
++ goto error;
++ }
++
++ /* Create SSL */
++ if (!(ssl= my_ssl_init(mysql)))
++ goto error;
++
++ /* Connect to the server */
++ if (my_ssl_connect(ssl))
++ {
++ SSL_free(ssl);
++ goto error;
++ }
++
++ if ((mysql->options.ssl_ca || mysql->options.ssl_capath) &&
++ (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
++ my_ssl_verify_server_cert(ssl))
++ goto error;
++ }
++#endif /* HAVE_OPENSSL */
++
++ DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
++ mysql->server_version, mysql->server_capabilities,
++ mysql->server_status, mysql->client_flag));
++
++ compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
++
++ /* This needs to be changed as it's not useful with big packets */
++ if (mysql->user[0])
++ strmake(end, mysql->user, USERNAME_LENGTH);
++ else
++ read_user_name(end);
++
++ /* We have to handle different version of handshake here */
++ DBUG_PRINT("info",("user: %s",end));
++ end= strend(end) + 1;
++ if (data_len)
++ {
++ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
++ {
++ *end++= data_len;
++ memcpy(end, data, data_len);
++ end+= data_len;
++ }
++ else
++ {
++ DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
++ memcpy(end, data, data_len);
++ end+= data_len;
++ }
++ }
++ else
++ *end++= 0;
++
++ /* Add database if needed */
++ if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
++ {
++ end= strmake(end, mpvio->db, NAME_LEN) + 1;
++ mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
++ }
++
++ if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
++ end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
++
++ end= ma_send_connect_attr(mysql, end);
++
++ /* Write authentication package */
++ if (my_net_write(net, buff, (size_t) (end-buff)) || net_flush(net))
++ {
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "sending authentication information",
++ errno);
++ goto error;
++ }
++ my_afree(buff);
++ return 0;
++
++error:
++ my_afree(buff);
++ return 1;
++}
++
++/**
++ vio->read_packet() callback method for client authentication plugins
++
++ This function is called by a client authentication plugin, when it wants
++ to read data from the server.
++*/
++
++static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
++{
++ MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
++ MYSQL *mysql= mpvio->mysql;
++ ulong pkt_len;
++
++ /* there are cached data left, feed it to a plugin */
++ if (mpvio->cached_server_reply.pkt)
++ {
++ *buf= mpvio->cached_server_reply.pkt;
++ mpvio->cached_server_reply.pkt= 0;
++ mpvio->packets_read++;
++ return mpvio->cached_server_reply.pkt_len;
++ }
++
++ if (mpvio->packets_read == 0)
++ {
++ /*
++ the server handshake packet came from the wrong plugin,
++ or it's mysql_change_user(). Either way, there is no data
++ for a plugin to read. send a dummy packet to the server
++ to initiate a dialog.
++ */
++ if (client_mpvio_write_packet(mpv, 0, 0))
++ return (int)packet_error;
++ }
++
++ /* otherwise read the data */
++ pkt_len= net_safe_read(mysql);
++ mpvio->last_read_packet_len= pkt_len;
++ *buf= mysql->net.read_pos;
++
++ /* was it a request to change plugins ? */
++ if (**buf == 254)
++ return (int)packet_error; /* if yes, this plugin shan't continue */
++
++ /*
++ the server sends \1\255 or \1\254 instead of just \255 or \254 -
++ for us to not confuse it with an error or "change plugin" packets.
++ We remove this escaping \1 here.
++
++ See also server_mpvio_write_packet() where the escaping is done.
++ */
++ if (pkt_len && **buf == 1)
++ {
++ (*buf)++;
++ pkt_len--;
++ }
++ mpvio->packets_read++;
++ return pkt_len;
++}
++
++/**
++ vio->write_packet() callback method for client authentication plugins
++
++ This function is called by a client authentication plugin, when it wants
++ to send data to the server.
++
++ It transparently wraps the data into a change user or authentication
++ handshake packet, if neccessary.
++*/
++
++static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
++ const uchar *pkt, size_t pkt_len)
++{
++ int res;
++ MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
++
++ if (mpvio->packets_written == 0)
++ {
++ if (mpvio->mysql_change_user)
++ res= send_change_user_packet(mpvio, pkt, (int)pkt_len);
++ else
++ res= send_client_reply_packet(mpvio, pkt, (int)pkt_len);
++ }
++ else
++ {
++ NET *net= &mpvio->mysql->net;
++ if (mpvio->mysql->thd)
++ res= 1; /* no chit-chat in embedded */
++ else
++ res= my_net_write(net, (char *)pkt, pkt_len) || net_flush(net);
++ if (res)
++ my_set_error(mpvio->mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "sending authentication information",
++ errno);
++ }
++ mpvio->packets_written++;
++ return res;
++}
++
++/**
++ fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
++ connection
++*/
++
++void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
++{
++ bzero(info, sizeof(*info));
++ switch (vio->type) {
++ case VIO_TYPE_TCPIP:
++ info->protocol= MYSQL_VIO_TCP;
++ info->socket= vio->sd;
++ return;
++ case VIO_TYPE_SOCKET:
++ info->protocol= MYSQL_VIO_SOCKET;
++ info->socket= vio->sd;
++ return;
++ case VIO_TYPE_SSL:
++ {
++ struct sockaddr addr;
++ SOCKET_SIZE_TYPE addrlen= sizeof(addr);
++ if (getsockname(vio->sd, &addr, &addrlen))
++ return;
++ info->protocol= addr.sa_family == AF_UNIX ?
++ MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
++ info->socket= vio->sd;
++ return;
++ }
++#ifdef _WIN32
++ case VIO_TYPE_NAMEDPIPE:
++ info->protocol= MYSQL_VIO_PIPE;
++ info->handle= vio->hPipe;
++ return;
++/* not supported yet
++ case VIO_TYPE_SHARED_MEMORY:
++ info->protocol= MYSQL_VIO_MEMORY;
++ info->handle= vio->handle_file_map;
++ return;
++*/
++#endif
++ default: DBUG_ASSERT(0);
++ }
++}
++
++static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
++ MYSQL_PLUGIN_VIO_INFO *info)
++{
++ MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio;
++ mpvio_info(mpvio->mysql->net.vio, info);
++}
++
++/**
++ Client side of the plugin driver authentication.
++
++ @note this is used by both the mysql_real_connect and mysql_change_user
++
++ @param mysql mysql
++ @param data pointer to the plugin auth data (scramble) in the
++ handshake packet
++ @param data_len the length of the data
++ @param data_plugin a plugin that data were prepared for
++ or 0 if it's mysql_change_user()
++ @param db initial db to use, can be 0
++
++ @retval 0 ok
++ @retval 1 error
++*/
++
++int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
++ const char *data_plugin, const char *db)
++{
++ const char *auth_plugin_name;
++ auth_plugin_t *auth_plugin;
++ MCPVIO_EXT mpvio;
++ ulong pkt_length;
++ int res;
++
++ /* determine the default/initial plugin to use */
++ if (mysql->options.extension && mysql->options.extension->default_auth &&
++ mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
++ {
++ auth_plugin_name= mysql->options.extension->default_auth;
++ if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
++ auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
++ return 1; /* oops, not found */
++ }
++ else
++ {
++ auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
++ &native_password_client_plugin : &old_password_client_plugin;
++ auth_plugin_name= auth_plugin->name;
++ }
++
++ mysql->net.last_errno= 0; /* just in case */
++
++ if (data_plugin && strcmp(data_plugin, auth_plugin_name))
++ {
++ /* data was prepared for a different plugin, don't show it to this one */
++ data= 0;
++ data_len= 0;
++ }
++
++ mpvio.mysql_change_user= data_plugin == 0;
++ mpvio.cached_server_reply.pkt= (uchar*)data;
++ mpvio.cached_server_reply.pkt_len= data_len;
++ mpvio.read_packet= client_mpvio_read_packet;
++ mpvio.write_packet= client_mpvio_write_packet;
++ mpvio.info= client_mpvio_info;
++ mpvio.mysql= mysql;
++ mpvio.packets_read= mpvio.packets_written= 0;
++ mpvio.db= db;
++ mpvio.plugin= auth_plugin;
++
++ res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
++
++ compile_time_assert(CR_OK == -1);
++ compile_time_assert(CR_ERROR == 0);
++ if (res > CR_OK && mysql->net.read_pos[0] != 254)
++ {
++ /*
++ the plugin returned an error. write it down in mysql,
++ unless the error code is CR_ERROR and mysql->net.last_errno
++ is already set (the plugin has done it)
++ */
++ if (res > CR_ERROR)
++ my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0);
++ else
++ if (!mysql->net.last_errno)
++ my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
++ return 1;
++ }
++
++ /* read the OK packet (or use the cached value in mysql->net.read_pos */
++ if (res == CR_OK)
++ pkt_length= net_safe_read(mysql);
++ else /* res == CR_OK_HANDSHAKE_COMPLETE */
++ pkt_length= mpvio.last_read_packet_len;
++
++ if (pkt_length == packet_error)
++ {
++ if (mysql->net.last_errno == CR_SERVER_LOST)
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "reading authorization packet",
++ errno);
++ return 1;
++ }
++
++ if (mysql->net.read_pos[0] == 254)
++ {
++ /* The server asked to use a different authentication plugin */
++ if (pkt_length == 1)
++ {
++ /* old "use short scramble" packet */
++ auth_plugin_name= old_password_plugin_name;
++ mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble_buff;
++ mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
++ }
++ else
++ {
++ /* new "use different plugin" packet */
++ uint len;
++ auth_plugin_name= (char*)mysql->net.read_pos + 1;
++ len= (uint)strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
++ mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
++ mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
++ }
++
++ if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql,
++ auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
++ return 1;
++
++ mpvio.plugin= auth_plugin;
++ res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
++
++ if (res > CR_OK)
++ {
++ if (res > CR_ERROR)
++ my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0);
++ else
++ if (!mysql->net.last_errno)
++ my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
++ return 1;
++ }
++
++ if (res != CR_OK_HANDSHAKE_COMPLETE)
++ {
++ /* Read what server thinks about out new auth message report */
++ if (net_safe_read(mysql) == packet_error)
++ {
++ if (mysql->net.last_errno == CR_SERVER_LOST)
++ my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
++ ER(CR_SERVER_LOST_EXTENDED),
++ "reading final connect information",
++ errno);
++ return 1;
++ }
++ }
++ }
++ /*
++ net->read_pos[0] should always be 0 here if the server implements
++ the protocol correctly
++ */
++ return mysql->net.read_pos[0] != 0;
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_charset.c mariadb-native-client.trunk/libmariadb/my_charset.c
+--- mariadb/libmariadb/my_charset.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_charset.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,1159 @@
++/****************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+
+ Part of this code includes code from the PHP project which
+ is freely available from http://www.php.net
- *****************************************************************************/
-
- /* The implementation for character set support was ported from PHP's mysqlnd
-@@ -826,3 +829,287 @@
- DBUG_RETURN((size_t)(newstr - newstr_s));
- }
- /* }}} */
++*****************************************************************************/
++
++/* The implementation for character set support was ported from PHP's mysqlnd
++ extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
++
++ Original file header:
++ +----------------------------------------------------------------------+
++ | PHP Version 5 |
++ +----------------------------------------------------------------------+
++ | Copyright (c) 2006-2011 The PHP Group |
++ +----------------------------------------------------------------------+
++ | This source file is subject to version 3.01 of the PHP license, |
++ | that is bundled with this package in the file LICENSE, and is |
++ | available through the world-wide-web at the following url: |
++ | http://www.php.net/license/3_01.txt |
++ | If you did not receive a copy of the PHP license and are unable to |
++ | obtain it through the world-wide-web, please send a note to |
++ | license@php.net so we can mail you a copy immediately. |
++ +----------------------------------------------------------------------+
++ | Authors: Georg Richter <georg@mysql.com> |
++ | Andrey Hristov <andrey@mysql.com> |
++ | Ulf Wendel <uwendel@mysql.com> |
++ +----------------------------------------------------------------------+
++*/
++
++#ifndef _WIN32
++#include <strings.h>
++#include <string.h>
++#else
++#include <string.h>
++#endif
++#include <my_global.h>
++#include <m_ctype.h>
++
++#include <iconv.h>
++
++extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
++/*
++ +----------------------------------------------------------------------+
++ | PHP Version 5 |
++ +----------------------------------------------------------------------+
++ | Copyright (c) 2006-2011 The PHP Group |
++ +----------------------------------------------------------------------+
++ | This source file is subject to version 3.01 of the PHP license, |
++ | that is bundled with this package in the file LICENSE, and is |
++ | available through the world-wide-web at the following url: |
++ | http://www.php.net/license/3_01.txt |
++ | If you did not receive a copy of the PHP license and are unable to |
++ | obtain it through the world-wide-web, please send a note to |
++ | license@php.net so we can mail you a copy immediately. |
++ +----------------------------------------------------------------------+
++ | Authors: Georg Richter <georg@mysql.com> |
++ | Andrey Hristov <andrey@mysql.com> |
++ | Ulf Wendel <uwendel@mysql.com> |
++ +----------------------------------------------------------------------+
++*/
++
++/* {{{ utf8 functions */
++static unsigned int check_mb_utf8mb3_sequence(const char *start, const char *end)
++{
++ uchar c;
++
++ if (start >= end) {
++ return 0;
++ }
++
++ c = (uchar) start[0];
++
++ if (c < 0x80) {
++ return 1; /* single byte character */
++ }
++ if (c < 0xC2) {
++ return 0; /* invalid mb character */
++ }
++ if (c < 0xE0) {
++ if (start + 2 > end) {
++ return 0; /* too small */
++ }
++ if (!(((uchar)start[1] ^ 0x80) < 0x40)) {
++ return 0;
++ }
++ return 2;
++ }
++ if (c < 0xF0) {
++ if (start + 3 > end) {
++ return 0; /* too small */
++ }
++ if (!(((uchar)start[1] ^ 0x80) < 0x40 && ((uchar)start[2] ^ 0x80) < 0x40 &&
++ (c >= 0xE1 || (uchar)start[1] >= 0xA0))) {
++ return 0; /* invalid utf8 character */
++ }
++ return 3;
++ }
++ return 0;
++}
++
++
++static unsigned int check_mb_utf8_sequence(const char *start, const char *end)
++{
++ uchar c;
++
++ if (start >= end) {
++ return 0;
++ }
++
++ c = (uchar) start[0];
++
++ if (c < 0x80) {
++ return 1; /* single byte character */
++ }
++ if (c < 0xC2) {
++ return 0; /* invalid mb character */
++ }
++ if (c < 0xE0) {
++ if (start + 2 > end) {
++ return 0; /* too small */
++ }
++ if (!(((uchar)start[1] ^ 0x80) < 0x40)) {
++ return 0;
++ }
++ return 2;
++ }
++ if (c < 0xF0) {
++ if (start + 3 > end) {
++ return 0; /* too small */
++ }
++ if (!(((uchar)start[1] ^ 0x80) < 0x40 && ((uchar)start[2] ^ 0x80) < 0x40 &&
++ (c >= 0xE1 || (uchar)start[1] >= 0xA0))) {
++ return 0; /* invalid utf8 character */
++ }
++ return 3;
++ }
++ if (c < 0xF5) {
++ if (start + 4 > end) { /* We need 4 characters */
++ return 0; /* too small */
++ }
++
++ /*
++ UTF-8 quick four-byte mask:
++ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
++ Encoding allows to encode U+00010000..U+001FFFFF
++
++ The maximum character defined in the Unicode standard is U+0010FFFF.
++ Higher characters U+00110000..U+001FFFFF are not used.
++
++ 11110000.10010000.10xxxxxx.10xxxxxx == F0.90.80.80 == U+00010000 (min)
++ 11110100.10001111.10111111.10111111 == F4.8F.BF.BF == U+0010FFFF (max)
++
++ Valid codes:
++ [F0][90..BF][80..BF][80..BF]
++ [F1][80..BF][80..BF][80..BF]
++ [F2][80..BF][80..BF][80..BF]
++ [F3][80..BF][80..BF][80..BF]
++ [F4][80..8F][80..BF][80..BF]
++ */
++
++ if (!(((uchar)start[1] ^ 0x80) < 0x40 &&
++ ((uchar)start[2] ^ 0x80) < 0x40 &&
++ ((uchar)start[3] ^ 0x80) < 0x40 &&
++ (c >= 0xf1 || (uchar)start[1] >= 0x90) &&
++ (c <= 0xf3 || (uchar)start[1] <= 0x8F)))
++ {
++ return 0; /* invalid utf8 character */
++ }
++ return 4;
++ }
++ return 0;
++}
++
++static unsigned int check_mb_utf8mb3_valid(const char *start, const char *end)
++{
++ unsigned int len = check_mb_utf8mb3_sequence(start, end);
++ return (len > 1)? len:0;
++}
++
++static unsigned int check_mb_utf8_valid(const char *start, const char *end)
++{
++ unsigned int len = check_mb_utf8_sequence(start, end);
++ return (len > 1)? len:0;
++}
++
++
++static unsigned int mysql_mbcharlen_utf8mb3(unsigned int utf8)
++{
++ if (utf8 < 0x80) {
++ return 1; /* single byte character */
++ }
++ if (utf8 < 0xC2) {
++ return 0; /* invalid multibyte header */
++ }
++ if (utf8 < 0xE0) {
++ return 2; /* double byte character */
++ }
++ if (utf8 < 0xF0) {
++ return 3; /* triple byte character */
++ }
++ return 0;
++}
++
++
++static unsigned int mysql_mbcharlen_utf8(unsigned int utf8)
++{
++ if (utf8 < 0x80) {
++ return 1; /* single byte character */
++ }
++ if (utf8 < 0xC2) {
++ return 0; /* invalid multibyte header */
++ }
++ if (utf8 < 0xE0) {
++ return 2; /* double byte character */
++ }
++ if (utf8 < 0xF0) {
++ return 3; /* triple byte character */
++ }
++ if (utf8 < 0xF8) {
++ return 4; /* four byte character */
++ }
++ return 0;
++}
++/* }}} */
++
++
++/* {{{ big5 functions */
++#define valid_big5head(c) (0xA1 <= (unsigned int)(c) && (unsigned int)(c) <= 0xF9)
++#define valid_big5tail(c) ((0x40 <= (unsigned int)(c) && (unsigned int)(c) <= 0x7E) || \
++ (0xA1 <= (unsigned int)(c) && (unsigned int)(c) <= 0xFE))
++
++#define isbig5code(c,d) (isbig5head(c) && isbig5tail(d))
++
++static unsigned int check_mb_big5(const char *start, const char *end)
++{
++ return (valid_big5head(*(start)) && (end - start) > 1 && valid_big5tail(*(start + 1)) ? 2 : 0);
++}
++
++
++static unsigned int mysql_mbcharlen_big5(unsigned int big5)
++{
++ return (valid_big5head(big5)) ? 2 : 1;
++}
++/* }}} */
++
++
++/* {{{ cp932 functions */
++#define valid_cp932head(c) ((0x81 <= (c) && (c) <= 0x9F) || (0xE0 <= (c) && c <= 0xFC))
++#define valid_cp932tail(c) ((0x40 <= (c) && (c) <= 0x7E) || (0x80 <= (c) && c <= 0xFC))
++
++
++static unsigned int check_mb_cp932(const char *start, const char *end)
++{
++ return (valid_cp932head((uchar)start[0]) && (end - start > 1) &&
++ valid_cp932tail((uchar)start[1])) ? 2 : 0;
++}
++
++
++static unsigned int mysql_mbcharlen_cp932(unsigned int cp932)
++{
++ return (valid_cp932head((uchar)cp932)) ? 2 : 1;
++}
++/* }}} */
++
++
++/* {{{ euckr functions */
++#define valid_euckr(c) ((0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE))
++
++static unsigned int check_mb_euckr(const char *start, const char *end)
++{
++ if (end - start <= 1) {
++ return 0; /* invalid length */
++ }
++ if (*(uchar *)start < 0x80) {
++ return 0; /* invalid euckr character */
++ }
++ if (valid_euckr(start[1])) {
++ return 2;
++ }
++ return 0;
++}
++
++
++static unsigned int mysql_mbcharlen_euckr(unsigned int kr)
++{
++ return (valid_euckr(kr)) ? 2 : 1;
++}
++/* }}} */
++
++
++/* {{{ eucjpms functions */
++#define valid_eucjpms(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xFE)
++#define valid_eucjpms_kata(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xDF)
++#define valid_eucjpms_ss2(c) (((c) & 0xFF) == 0x8E)
++#define valid_eucjpms_ss3(c) (((c) & 0xFF) == 0x8F)
++
++static unsigned int check_mb_eucjpms(const char *start, const char *end)
++{
++ if (*((uchar *)start) < 0x80) {
++ return 0; /* invalid eucjpms character */
++ }
++ if (valid_eucjpms(start[0]) && (end - start) > 1 && valid_eucjpms(start[1])) {
++ return 2;
++ }
++ if (valid_eucjpms_ss2(start[0]) && (end - start) > 1 && valid_eucjpms_kata(start[1])) {
++ return 2;
++ }
++ if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) &&
++ valid_eucjpms(start[2])) {
++ return 2;
++ }
++ return 0;
++}
++
++
++static unsigned int mysql_mbcharlen_eucjpms(unsigned int jpms)
++{
++ if (valid_eucjpms(jpms) || valid_eucjpms_ss2(jpms)) {
++ return 2;
++ }
++ if (valid_eucjpms_ss3(jpms)) {
++ return 3;
++ }
++ return 1;
++}
++/* }}} */
++
++
++/* {{{ gb2312 functions */
++#define valid_gb2312_head(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xF7)
++#define valid_gb2312_tail(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE)
++
++
++static unsigned int check_mb_gb2312(const char *start, const char *end)
++{
++ return (valid_gb2312_head((unsigned int)start[0]) && end - start > 1 &&
++ valid_gb2312_tail((unsigned int)start[1])) ? 2 : 0;
++}
++
++
++static unsigned int mysql_mbcharlen_gb2312(unsigned int gb)
++{
++ return (valid_gb2312_head(gb)) ? 2 : 1;
++}
++/* }}} */
++
++
++/* {{{ gbk functions */
++#define valid_gbk_head(c) (0x81<=(uchar)(c) && (uchar)(c)<=0xFE)
++#define valid_gbk_tail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7E) || (0x80<=(uchar)(c) && (uchar)(c)<=0xFE))
++
++static unsigned int check_mb_gbk(const char *start, const char *end)
++{
++ return (valid_gbk_head(start[0]) && (end) - (start) > 1 && valid_gbk_tail(start[1])) ? 2 : 0;
++}
++
++static unsigned int mysql_mbcharlen_gbk(unsigned int gbk)
++{
++ return (valid_gbk_head(gbk) ? 2 : 1);
++}
++/* }}} */
++
++
++/* {{{ sjis functions */
++#define valid_sjis_head(c) ((0x81 <= (c) && (c) <= 0x9F) || (0xE0 <= (c) && (c) <= 0xFC))
++#define valid_sjis_tail(c) ((0x40 <= (c) && (c) <= 0x7E) || (0x80 <= (c) && (c) <= 0xFC))
++
++
++static unsigned int check_mb_sjis(const char *start, const char *end)
++{
++ return (valid_sjis_head((uchar)start[0]) && (end - start) > 1 && valid_sjis_tail((uchar)start[1])) ? 2 : 0;
++}
++
++
++static unsigned int mysql_mbcharlen_sjis(unsigned int sjis)
++{
++ return (valid_sjis_head((uchar)sjis)) ? 2 : 1;
++}
++/* }}} */
++
++
++/* {{{ ucs2 functions */
++static unsigned int check_mb_ucs2(const char *start __attribute((unused)), const char *end __attribute((unused)))
++{
++ return 2; /* always 2 */
++}
++
++static unsigned int mysql_mbcharlen_ucs2(unsigned int ucs2 __attribute((unused)))
++{
++ return 2; /* always 2 */
++}
++/* }}} */
++
++
++/* {{{ ujis functions */
++#define valid_ujis(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xFE))
++#define valid_ujis_kata(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xDF))
++#define valid_ujis_ss2(c) (((c)&0xFF) == 0x8E)
++#define valid_ujis_ss3(c) (((c)&0xFF) == 0x8F)
++
++static unsigned int check_mb_ujis(const char *start, const char *end)
++{
++ if (*(uchar*)start < 0x80) {
++ return 0; /* invalid ujis character */
++ }
++ if (valid_ujis(*(start)) && valid_ujis(*((start)+1))) {
++ return 2;
++ }
++ if (valid_ujis_ss2(*(start)) && valid_ujis_kata(*((start)+1))) {
++ return 2;
++ }
++ if (valid_ujis_ss3(*(start)) && (end-start) > 2 && valid_ujis(*((start)+1)) && valid_ujis(*((start)+2))) {
++ return 3;
++ }
++ return 0;
++}
++
++
++static unsigned int mysql_mbcharlen_ujis(unsigned int ujis)
++{
++ return (valid_ujis(ujis)? 2: valid_ujis_ss2(ujis)? 2: valid_ujis_ss3(ujis)? 3: 1);
++}
++/* }}} */
++
++
++
++/* {{{ utf16 functions */
++#define UTF16_HIGH_HEAD(x) ((((uchar) (x)) & 0xFC) == 0xD8)
++#define UTF16_LOW_HEAD(x) ((((uchar) (x)) & 0xFC) == 0xDC)
++
++static unsigned int check_mb_utf16(const char *start, const char *end)
++{
++ if (start + 2 > end) {
++ return 0;
++ }
++
++ if (UTF16_HIGH_HEAD(*start)) {
++ return (start + 4 <= end) && UTF16_LOW_HEAD(start[2]) ? 4 : 0;
++ }
++
++ if (UTF16_LOW_HEAD(*start)) {
++ return 0;
++ }
++ return 2;
++}
++
++
++static uint mysql_mbcharlen_utf16(unsigned int utf16)
++{
++ return UTF16_HIGH_HEAD(utf16) ? 4 : 2;
++}
++/* }}} */
++
++
++/* {{{ utf32 functions */
++static uint
++check_mb_utf32(const char *start __attribute((unused)), const char *end __attribute((unused)))
++{
++ return 4;
++}
++
++
++static uint
++mysql_mbcharlen_utf32(unsigned int utf32 __attribute((unused)))
++{
++ return 4;
++}
++/* }}} */
++
++/*
++ The server compiles sometimes the full utf-8 (the mb4) as utf8m4, and the old as utf8,
++ for BC reasons. Sometimes, utf8mb4 is just utf8 but the old charsets are utf8mb3.
++ Change easily now, with a macro, could be made compilastion dependable.
++*/
++
++#define UTF8_MB4 "utf8mb4"
++#define UTF8_MB3 "utf8"
++
++/* {{{ mysql_charsets */
++const CHARSET_INFO compiled_charsets[] =
++{
++ { 1, 1, "big5","big5_chinese_ci", "", "BIG5", 1, 2, mysql_mbcharlen_big5, check_mb_big5},
++ { 3, 1, "dec8", "dec8_swedisch_ci", "", "DEC", 1, 1, NULL, NULL},
++ { 4, 1, "cp850", "cp850_general_ci", "", "CP850", 1, 1, NULL, NULL},
++ { 6, 1, "hp8", "hp8_english_ci", "", "HP-ROMAN8", 1, 1, NULL, NULL},
++ { 7, 1, "koi8r", "koi8r_general_ci", "", "KOI8R", 1, 1, NULL, NULL},
++ { 8, 1, "latin1", "latin1_swedish_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 9, 1, "latin2", "latin2_general_ci", "", "LATIN2", 1, 1, NULL, NULL},
++ { 10, 1, "swe7", "swe7_swedish_ci", "", "", 1, 1, NULL, NULL},
++ { 11, 1, "ascii", "ascii_general_ci", "", "ASCII", 1, 1, NULL, NULL},
++ { 12, 1, "ujis", "ujis_japanese_ci", "", "UJIS", 1, 3, mysql_mbcharlen_ujis, check_mb_ujis},
++ { 13, 1, "sjis", "sjis_japanese_ci", "", "SJIS", 1, 2, mysql_mbcharlen_sjis, check_mb_sjis},
++ { 16, 1, "hebrew", "hebrew_general_ci", "", "HEBREW", 1, 1, NULL, NULL},
++ { 18, 1, "tis620", "tis620_thai_ci", "", "TIS620", 1, 1, NULL, NULL},
++ { 19, 1, "euckr", "euckr_korean_ci", "", "EUCKR", 1, 2, mysql_mbcharlen_euckr, check_mb_euckr},
++ { 22, 1, "koi8u", "koi8u_general_ci", "", "KOI8U", 1, 1, NULL, NULL},
++ { 24, 1, "gb2312", "gb2312_chinese_ci", "", "GB2312", 1, 2, mysql_mbcharlen_gb2312, check_mb_gb2312},
++ { 25, 1, "greek", "greek_general_ci", "", "GREEK", 1, 1, NULL, NULL},
++ { 26, 1, "cp1250", "cp1250_general_ci", "", "CP1250", 1, 1, NULL, NULL},
++ { 28, 1, "gbk", "gbk_chinese_ci", "", "GBK", 1, 2, mysql_mbcharlen_gbk, check_mb_gbk},
++ { 30, 1, "latin5", "latin5_turkish_ci", "", "LATIN5", 1, 1, NULL, NULL},
++ { 32, 1, "armscii8", "armscii8_general_ci", "", "ARMSCII-8", 1, 1, NULL, NULL},
++ { 33, 1, UTF8_MB3, UTF8_MB3"_general_ci", "UTF-8 Unicode", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 35, 1, "ucs2", "ucs2_general_ci", "UCS-2 Unicode", "UCS-2BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 36, 1, "cp866", "cp866_general_ci", "", "CP866", 1, 1, NULL, NULL},
++ { 37, 1, "keybcs2", "keybcs2_general_ci", "", "", 1, 1, NULL, NULL},
++ { 38, 1, "macce", "macce_general_ci", "", "CP1282", 1, 1, NULL, NULL},
++ { 39, 1, "macroman", "macroman_general_ci", "MACINTOSH", "", 1, 1, NULL, NULL},
++ { 40, 1, "cp852", "cp852_general_ci", "", "CP852", 1, 1, NULL, NULL},
++ { 41, 1, "latin7", "latin7_general_ci", "", "LATIN7", 1, 1, NULL, NULL},
++ { 51, 1, "cp1251", "cp1251_general_ci", "", "CP1251", 1, 1, NULL, NULL},
++ { 57, 1, "cp1256", "cp1256_general_ci", "", "CP1256", 1, 1, NULL, NULL},
++ { 59, 1, "cp1257", "cp1257_general_ci", "", "CP1257", 1, 1, NULL, NULL},
++ { 63, 1, "binary", "binary", "", "ASCII", 1, 1, NULL, NULL},
++ { 92, 1, "geostd8", "geostd8_general_ci", "", "GEORGIAN-PS", 1, 1, NULL, NULL},
++ { 95, 1, "cp932", "cp932_japanese_ci", "", "CP932", 1, 2, mysql_mbcharlen_cp932, check_mb_cp932},
++ { 97, 1, "eucjpms", "eucjpms_japanese_ci", "", "EUC-JP-MS", 1, 3, mysql_mbcharlen_eucjpms, check_mb_eucjpms},
++ { 2, 1, "latin2", "latin2_czech_cs", "", "LATIN2", 1, 1, NULL, NULL},
++ { 5, 1, "latin1", "latin1_german_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 14, 1, "cp1251", "cp1251_bulgarian_ci", "", "CP1251", 1, 1, NULL, NULL},
++ { 15, 1, "latin1", "latin1_danish_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 17, 1, "filename", "filename", "", "", 1, 5, NULL, NULL},
++ { 20, 1, "latin7", "latin7_estonian_cs", "", "LATIN7", 1, 1, NULL, NULL},
++ { 21, 1, "latin2", "latin2_hungarian_ci", "", "LATIN2", 1, 1, NULL, NULL},
++ { 23, 1, "cp1251", "cp1251_ukrainian_ci", "", "CP1251", 1, 1, NULL, NULL},
++ { 27, 1, "latin2", "latin2_croatian_ci", "", "LATIN2", 1, 1, NULL, NULL},
++ { 29, 1, "cp1257", "cp1257_lithunian_ci", "", "CP1257", 1, 1, NULL, NULL},
++ { 31, 1, "latin1", "latin1_german2_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 34, 1, "cp1250", "cp1250_czech_cs", "", "CP1250", 1, 1, NULL, NULL},
++ { 42, 1, "latin7", "latin7_general_cs", "", "LATIN7", 1, 1, NULL, NULL},
++ { 43, 1, "macce", "macce_bin", "", "MACINTOSH", 1, 1, NULL, NULL},
++ { 44, 1, "cp1250", "cp1250_croatian_ci", "", "CP1250", 1, 1, NULL, NULL},
++ { 45, 1, UTF8_MB4, UTF8_MB4"_general_ci", "UTF-8 Unicode", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 46, 1, UTF8_MB4, UTF8_MB4"_bin", "UTF-8 Unicode", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 47, 1, "latin1", "latin1_bin", "", "LATIN1", 1, 1, NULL, NULL},
++ { 48, 1, "latin1", "latin1_general_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 49, 1, "latin1", "latin1_general_cs", "", "LATIN1", 1, 1, NULL, NULL},
++ { 50, 1, "cp1251", "cp1251_bin", "", "CP1251", 1, 1, NULL, NULL},
++ { 52, 1, "cp1251", "cp1251_general_cs", "", "CP1251", 1, 1, NULL, NULL},
++ { 53, 1, "macroman", "macroman_bin", "", "MACINTOSH", 1, 1, NULL, NULL},
++ { 54, 1, "utf16", "utf16_general_ci", "UTF_16 Unicode", "UTF16", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
++ { 55, 1, "utf16", "utf16_bin", "UTF-16 Unicode", "UTF16", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
++ { 56, 1, "utf16le", "utf16_general_ci", "UTF_16LE Unicode", "UTF16LE", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
++ { 58, 1, "cp1257", "cp1257_bin", "", "CP1257", 1, 1, NULL, NULL},
++#ifdef USED_TO_BE_SO_BEFORE_MYSQL_5_5
++ { 60, 1, "armascii8", "armascii8_bin", "", "ARMSCII-8", 1, 1, NULL, NULL},
++#endif
++ { 60, 1, "utf32", "utf32_general_ci", "UTF-32 Unicode", "UTF32", 4, 4, mysql_mbcharlen_utf32, check_mb_utf32},
++ { 61, 1, "utf32", "utf32_bin", "UTF-32 Unicode", "UTF32", 4, 4, mysql_mbcharlen_utf32, check_mb_utf32},
++ { 62, 1, "utf16le", "utf16_bin", "UTF_16LE Unicode", "UTF16LE", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
++ { 65, 1, "ascii", "ascii_bin", "", "ASCII", 1, 1, NULL, NULL},
++ { 66, 1, "cp1250", "cp1250_bin", "", "CP1250", 1, 1, NULL, NULL},
++ { 67, 1, "cp1256", "cp1256_bin", "", "CP1256", 1, 1, NULL, NULL},
++ { 68, 1, "cp866", "cp866_bin", "", "CP866", 1, 1, NULL, NULL},
++ { 69, 1, "dec8", "dec8_bin", "", "DEC", 1, 1, NULL, NULL},
++ { 70, 1, "greek", "greek_bin", "", "GREEK", 1, 1, NULL, NULL},
++ { 71, 1, "hebrew", "hebrew_bin", "", "hebrew", 1, 1, NULL, NULL},
++ { 72, 1, "hp8", "hp8_bin", "", "HPROMAN-8", 1, 1, NULL, NULL},
++ { 73, 1, "keybcs2", "keybcs2_bin", "", "", 1, 1, NULL, NULL},
++ { 74, 1, "koi8r", "koi8r_bin", "", "KOI8R", 1, 1, NULL, NULL},
++ { 75, 1, "koi8u", "koi8u_bin", "", "KOI8U", 1, 1, NULL, NULL},
++ { 77, 1, "latin2", "latin2_bin", "", "LATIN2", 1, 1, NULL, NULL},
++ { 78, 1, "latin5", "latin5_bin", "", "LATIN5", 1, 1, NULL, NULL},
++ { 79, 1, "latin7", "latin7_bin", "", "LATIN7", 1, 1, NULL, NULL},
++ { 80, 1, "cp850", "cp850_bin", "", "CP850", 1, 1, NULL, NULL},
++ { 81, 1, "cp852", "cp852_bin", "", "CP852", 1, 1, NULL, NULL},
++ { 82, 1, "swe7", "swe7_bin", "", "", 1, 1, NULL, NULL},
++ { 93, 1, "geostd8", "geostd8_bin", "", "GEORGIAN-PS", 1, 1, NULL, NULL},
++ { 83, 1, UTF8_MB3, UTF8_MB3"_bin", "UTF-8 Unicode", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 84, 1, "big5", "big5_bin", "", "BIG5", 1, 2, mysql_mbcharlen_big5, check_mb_big5},
++ { 85, 1, "euckr", "euckr_bin", "", "EUCKR", 1, 2, mysql_mbcharlen_euckr, check_mb_euckr},
++ { 86, 1, "gb2312", "gb2312_bin", "", "GB2312", 1, 2, mysql_mbcharlen_gb2312, check_mb_gb2312},
++ { 87, 1, "gbk", "gbk_bin", "", "GBK", 1, 2, mysql_mbcharlen_gbk, check_mb_gbk},
++ { 88, 1, "sjis", "sjis_bin", "", "SJIS", 1, 2, mysql_mbcharlen_sjis, check_mb_sjis},
++ { 89, 1, "tis620", "tis620_bin", "TIS620", "", 1, 1, NULL, NULL},
++ { 90, 1, "ucs2", "ucs2_bin", "UCS-2 Unicode", "UCS-2BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 91, 1, "ujis", "ujis_bin", "", "UJIS", 1, 3, mysql_mbcharlen_ujis, check_mb_ujis},
++ { 94, 1, "latin1", "latin1_spanish_ci", "", "LATIN1", 1, 1, NULL, NULL},
++ { 96, 1, "cp932", "cp932_bin", "", "CP932", 1, 2, mysql_mbcharlen_cp932, check_mb_cp932},
++ { 99, 1, "cp1250", "cp1250_polish_ci", "", "CP1250", 1, 1, NULL, NULL},
++ { 98, 1, "eucjpms", "eucjpms_bin", "", "EUCJP-MS", 1, 3, mysql_mbcharlen_eucjpms, check_mb_eucjpms},
++ { 128, 1, "ucs2", "ucs2_unicode_ci", "", "UCS-2BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 129, 1, "ucs2", "ucs2_icelandic_ci", "", "UCS-2BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 130, 1, "ucs2", "ucs2_latvian_ci", "", "UCS-2BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 131, 1, "ucs2", "ucs2_romanian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 132, 1, "ucs2", "ucs2_slovenian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 133, 1, "ucs2", "ucs2_polish_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 134, 1, "ucs2", "ucs2_estonian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 135, 1, "ucs2", "ucs2_spanish_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 136, 1, "ucs2", "ucs2_swedish_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 137, 1, "ucs2", "ucs2_turkish_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 138, 1, "ucs2", "ucs2_czech_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 139, 1, "ucs2", "ucs2_danish_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 140, 1, "ucs2", "ucs2_lithunian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 141, 1, "ucs2", "ucs2_slovak_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 142, 1, "ucs2", "ucs2_spanish2_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 143, 1, "ucs2", "ucs2_roman_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 144, 1, "ucs2", "ucs2_persian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 145, 1, "ucs2", "ucs2_esperanto_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 146, 1, "ucs2", "ucs2_hungarian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 147, 1, "ucs2", "ucs2_sinhala_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
++ { 149, 1, "ucs2", "ucs2_croatian_ci", "", "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2}, /* MDB */
++
++ { 192, 1, UTF8_MB3, UTF8_MB3"_general_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 193, 1, UTF8_MB3, UTF8_MB3"_icelandic_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 194, 1, UTF8_MB3, UTF8_MB3"_latvian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 195, 1, UTF8_MB3, UTF8_MB3"_romanian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 196, 1, UTF8_MB3, UTF8_MB3"_slovenian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 197, 1, UTF8_MB3, UTF8_MB3"_polish_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 198, 1, UTF8_MB3, UTF8_MB3"_estonian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 119, 1, UTF8_MB3, UTF8_MB3"_spanish_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 200, 1, UTF8_MB3, UTF8_MB3"_swedish_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 201, 1, UTF8_MB3, UTF8_MB3"_turkish_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 202, 1, UTF8_MB3, UTF8_MB3"_czech_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 203, 1, UTF8_MB3, UTF8_MB3"_danish_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid },
++ { 204, 1, UTF8_MB3, UTF8_MB3"_lithunian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid },
++ { 205, 1, UTF8_MB3, UTF8_MB3"_slovak_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 206, 1, UTF8_MB3, UTF8_MB3"_spanish2_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 207, 1, UTF8_MB3, UTF8_MB3"_roman_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 208, 1, UTF8_MB3, UTF8_MB3"_persian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 209, 1, UTF8_MB3, UTF8_MB3"_esperanto_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 210, 1, UTF8_MB3, UTF8_MB3"_hungarian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 211, 1, UTF8_MB3, UTF8_MB3"_sinhala_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
++ { 213, 1, UTF8_MB3, UTF8_MB3"_croatian_ci", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/
++
++ { 224, 1, UTF8_MB4, UTF8_MB4"_unicode_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 225, 1, UTF8_MB4, UTF8_MB4"_icelandic_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 226, 1, UTF8_MB4, UTF8_MB4"_latvian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 227, 1, UTF8_MB4, UTF8_MB4"_romanian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 228, 1, UTF8_MB4, UTF8_MB4"_slovenian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 229, 1, UTF8_MB4, UTF8_MB4"_polish_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 230, 1, UTF8_MB4, UTF8_MB4"_estonian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 231, 1, UTF8_MB4, UTF8_MB4"_spanish_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 232, 1, UTF8_MB4, UTF8_MB4"_swedish_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 233, 1, UTF8_MB4, UTF8_MB4"_turkish_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 234, 1, UTF8_MB4, UTF8_MB4"_czech_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 235, 1, UTF8_MB4, UTF8_MB4"_danish_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 236, 1, UTF8_MB4, UTF8_MB4"_lithuanian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 237, 1, UTF8_MB4, UTF8_MB4"_slovak_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 238, 1, UTF8_MB4, UTF8_MB4"_spanish2_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 239, 1, UTF8_MB4, UTF8_MB4"_roman_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 240, 1, UTF8_MB4, UTF8_MB4"_persian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 241, 1, UTF8_MB4, UTF8_MB4"_esperanto_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 242, 1, UTF8_MB4, UTF8_MB4"_hungarian_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 243, 1, UTF8_MB4, UTF8_MB4"_sinhala_ci", "", "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++
++ { 254, 1, UTF8_MB3, UTF8_MB3"_general_cs", "", "UTF-8", 1, 3, mysql_mbcharlen_utf8, check_mb_utf8_valid},
++ { 0, 0, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL}
++};
++/* }}} */
++
++
++/* {{{ mysql_find_charset_nr */
++const CHARSET_INFO * mysql_find_charset_nr(unsigned int charsetnr)
++{
++ const CHARSET_INFO * c = compiled_charsets;
++ DBUG_ENTER("mysql_find_charset_nr");
++
++ do {
++ if (c->nr == charsetnr) {
++ DBUG_PRINT("info", ("found character set %d %s", c->nr, c->csname));
++ DBUG_RETURN(c);
++ }
++ ++c;
++ } while (c[0].nr != 0);
++ DBUG_RETURN(NULL);
++}
++/* }}} */
++
++
++/* {{{ mysql_find_charset_name */
++CHARSET_INFO * mysql_find_charset_name(const char *name)
++{
++ CHARSET_INFO *c = (CHARSET_INFO *)compiled_charsets;
++ DBUG_ENTER("mysql_find_charset_nr");
++
++ do {
++ if (!strcasecmp(c->csname, name)) {
++ DBUG_PRINT("info", ("found character set %d %s", c->nr, c->csname));
++ DBUG_RETURN(c);
++ }
++ ++c;
++ } while (c[0].nr != 0);
++ return NULL;
++}
++/* }}} */
++
++
++/* {{{ mysql_cset_escape_quotes */
++size_t mysql_cset_escape_quotes(const CHARSET_INFO *cset, char *newstr,
++ const char * escapestr, size_t escapestr_len )
++{
++ const char *newstr_s = newstr;
++ const char *newstr_e = newstr + 2 * escapestr_len;
++ const char *end = escapestr + escapestr_len;
++ my_bool escape_overflow = FALSE;
++
++ DBUG_ENTER("mysql_cset_escape_quotes");
++
++ for (;escapestr < end; escapestr++) {
++ unsigned int len = 0;
++ /* check unicode characters */
++
++ if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
++
++ /* check possible overflow */
++ if ((newstr + len) > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ /* copy mb char without escaping it */
++ while (len--) {
++ *newstr++ = *escapestr++;
++ }
++ escapestr--;
++ continue;
++ }
++ if (*escapestr == '\'') {
++ if (newstr + 2 > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ *newstr++ = '\'';
++ *newstr++ = '\'';
++ } else {
++ if (newstr + 1 > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ *newstr++ = *escapestr;
++ }
++ }
++ *newstr = '\0';
++
++ if (escape_overflow) {
++ DBUG_RETURN((size_t)~0);
++ }
++ DBUG_RETURN((size_t)(newstr - newstr_s));
++}
++/* }}} */
++
++
++/* {{{ mysql_cset_escape_slashes */
++size_t mysql_cset_escape_slashes(const CHARSET_INFO * cset, char *newstr,
++ const char * escapestr, size_t escapestr_len )
++{
++ const char *newstr_s = newstr;
++ const char *newstr_e = newstr + 2 * escapestr_len;
++ const char *end = escapestr + escapestr_len;
++ my_bool escape_overflow = FALSE;
++
++ DBUG_ENTER("mysql_cset_escape_slashes");
++ DBUG_PRINT("info", ("charset=%s", cset->name));
++
++ for (;escapestr < end; escapestr++) {
++ char esc = '\0';
++ unsigned int len = 0;
++
++ /* check unicode characters */
++ if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
++ /* check possible overflow */
++ if ((newstr + len) > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ /* copy mb char without escaping it */
++ while (len--) {
++ *newstr++ = *escapestr++;
++ }
++ escapestr--;
++ continue;
++ }
++ if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
++ esc = *escapestr;
++ } else {
++ switch (*escapestr) {
++ case 0:
++ esc = '0';
++ break;
++ case '\n':
++ esc = 'n';
++ break;
++ case '\r':
++ esc = 'r';
++ break;
++ case '\\':
++ case '\'':
++ case '"':
++ esc = *escapestr;
++ break;
++ case '\032':
++ esc = 'Z';
++ break;
++ }
++ }
++ if (esc) {
++ if (newstr + 2 > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ /* copy escaped character */
++ *newstr++ = '\\';
++ *newstr++ = esc;
++ } else {
++ if (newstr + 1 > newstr_e) {
++ escape_overflow = TRUE;
++ break;
++ }
++ /* copy non escaped character */
++ *newstr++ = *escapestr;
++ }
++ }
++ *newstr = '\0';
++
++ if (escape_overflow) {
++ DBUG_RETURN((size_t)~0);
++ }
++ DBUG_RETURN((size_t)(newstr - newstr_s));
++}
++/* }}} */
+
+/* {{{ MADB_OS_CHARSET */
+struct st_madb_os_charset {
+ char *identifier;
+ char *description;
+ char *charset;
++ char *iconv_cs;
+ unsigned char supported;
+};
+
@@ -3586,227 +22698,228 @@
+{
+#ifdef _WIN32
+ /* Windows code pages */
-+ {"037", "IBM EBCDIC US-Canada", NULL, MADB_CS_UNSUPPORTED},
-+ {"437", "OEM United States", "cp850", MADB_CS_APPROX},
-+ {"500", "IBM EBCDIC International", NULL, MADB_CS_UNSUPPORTED},
-+ {"708", "Arabic (ASMO 708)", NULL, MADB_CS_UNSUPPORTED},
-+ {"709", "Arabic (ASMO-449+, BCON V4)", NULL, MADB_CS_UNSUPPORTED},
-+ {"710", "Transparent Arabic", NULL, MADB_CS_UNSUPPORTED},
-+ {"720", "Arabic (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"737", "Greek (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"775", "Baltic (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"850", "Western European (DOS)", "cp850", MADB_CS_EXACT},
-+ {"852", "Central European (DOS)", "cp852", MADB_CS_EXACT},
-+ {"855", "Cyrillic (primarily Russian)", NULL, MADB_CS_UNSUPPORTED},
-+ {"857", "Turkish (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"858", "OEM Multilingual Latin 1 + Euro symbol", "cp850", MADB_CS_EXACT},
-+ {"860", "Portuguese (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"861", "Icelandic (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"862", "Hebrew (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"863", "French Canadian (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"864", "Arabic (864)", NULL, MADB_CS_UNSUPPORTED},
-+ {"865", "Nordic (DOS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"866", "Cyrillic (DOS)", "cp866", MADB_CS_EXACT},
-+ {"869", "Greek, Modern (DOS)", "greek", MADB_CS_EXACT},
-+ {"870", "IBM EBCDIC Multilingual Latin 2", NULL, MADB_CS_UNSUPPORTED},
-+ {"874", "Thai (Windows)", "tis620", MADB_CS_UNSUPPORTED},
-+ {"875", "Greek Modern", NULL, MADB_CS_UNSUPPORTED},
-+ {"932", "Japanese (Shift-JIS)", "cp932", MADB_CS_EXACT},
-+ {"936", "Chinese Simplified (GB2312)", "gbk", MADB_CS_EXACT},
-+ {"949", "ANSI/OEM Korean (Unified Hangul Code)", "euckr", MADB_CS_EXACT},
-+ {"950", "Chinese Traditional (Big5)", "big5", MADB_CS_EXACT},
-+ {"1026", "EBCDIC Turkish (Latin 5)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1047", "EBCDIC Latin 1/Open System", NULL, MADB_CS_UNSUPPORTED},
-+ {"1140", "IBM EBCDIC (US-Canada-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1141", "IBM EBCDIC (Germany-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1142", "IBM EBCDIC (Denmark-Norway-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1143", "IBM EBCDIC (Finland-Sweden-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1144", "IBM EBCDIC (Italy-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1145", "IBM EBCDIC (Spain-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1146", "IBM EBCDIC (UK-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1147", "IBM EBCDIC (France-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1148", "IBM EBCDIC (International-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1149", "IBM EBCDIC (Icelandic-Euro)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1200", "UTF-16, little endian byte order", NULL, MADB_CS_UNSUPPORTED},
-+ {"1201", "UTF-16, big endian byte order", "utf16", MADB_CS_UNSUPPORTED},
-+ {"1250", "Central European (Windows)", "cp1250", MADB_CS_EXACT},
-+ {"1251", "Cyrillic (Windows)", "cp1251", MADB_CS_EXACT},
-+ {"1252", "Western European (Windows)", "latin1", MADB_CS_EXACT},
-+ {"1253", "Greek (Windows)", "greek", MADB_CS_EXACT},
-+ {"1254", "Turkish (Windows)", "latin5", MADB_CS_EXACT},
-+ {"1255", "Hebrew (Windows)", "hewbrew", MADB_CS_EXACT},
-+ {"1256", "Arabic (Windows)", "cp1256", MADB_CS_EXACT},
-+ {"1257", "Baltic (Windows)","cp1257", MADB_CS_EXACT},
-+ {"1258", "Vietnamese (Windows)", NULL, MADB_CS_UNSUPPORTED},
-+ {"1361", "Korean (Johab)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10000", "Western European (Mac)", "macroman", MADB_CS_EXACT},
-+ {"10001", "Japanese (Mac)", "sjis", MADB_CS_EXACT},
-+ {"10002", "Chinese Traditional (Mac)", "big5", MADB_CS_EXACT},
-+ {"10003", "Korean (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10004", "Arabic (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10005", "Hebrew (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10006", "Greek (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10007", "Cyrillic (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10008", "Chinese Simplified (Mac)", "gb2312", MADB_CS_EXACT},
-+ {"10010", "Romanian (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10017", "Ukrainian (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10021", "Thai (Mac)", "tis620", MADB_CS_EXACT},
-+ {"10029", "Central European (Mac)", "macce", MADB_CS_EXACT},
-+ {"10079", "Icelandic (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10081", "Turkish (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"10082", "Croatian (Mac)", NULL, MADB_CS_UNSUPPORTED},
-+ {"12000", "Unicode UTF-32, little endian byte order", NULL, MADB_CS_UNSUPPORTED},
-+ {"12001", "Unicode UTF-32, big endian byte order", "utf32", MADB_CS_UNSUPPORTED},
-+ {"20000", "Chinese Traditional (CNS)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20001", "TCA Taiwan", NULL, MADB_CS_UNSUPPORTED},
-+ {"20002", "Chinese Traditional (Eten)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20003", "IBM5550 Taiwan", NULL, MADB_CS_UNSUPPORTED},
-+ {"20004", "TeleText Taiwan", NULL, MADB_CS_UNSUPPORTED},
-+ {"20005", "Wang Taiwan", NULL, MADB_CS_UNSUPPORTED},
-+ {"20105", "Western European (IA5)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20106", "IA5 German (7-bit)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20107", "Swedish (7-bit)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20108", "Norwegian (7-bit)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20127", "US-ASCII (7-bit)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20261", "T.61", NULL, MADB_CS_UNSUPPORTED},
-+ {"20269", "Non-Spacing Accent", NULL, MADB_CS_UNSUPPORTED},
-+ {"20273", "EBCDIC Germany", NULL, MADB_CS_UNSUPPORTED},
-+ {"20277", "EBCDIC Denmark-Norway", NULL, MADB_CS_UNSUPPORTED},
-+ {"20278", "EBCDIC Finland-Sweden", NULL, MADB_CS_UNSUPPORTED},
-+ {"20280", "EBCDIC Italy", NULL, MADB_CS_UNSUPPORTED},
-+ {"20284", "EBCDIC Latin America-Spain", NULL, MADB_CS_UNSUPPORTED},
-+ {"20285", "EBCDIC United Kingdom", NULL, MADB_CS_UNSUPPORTED},
-+ {"20290", "EBCDIC Japanese Katakana Extended", NULL, MADB_CS_UNSUPPORTED},
-+ {"20297", "EBCDIC France", NULL, MADB_CS_UNSUPPORTED},
-+ {"20420", "EBCDIC Arabic", NULL, MADB_CS_UNSUPPORTED},
-+ {"20423", "EBCDIC Greek", NULL, MADB_CS_UNSUPPORTED},
-+ {"20424", "EBCDIC Hebrew", NULL, MADB_CS_UNSUPPORTED},
-+ {"20833", "EBCDIC Korean Extended", NULL, MADB_CS_UNSUPPORTED},
-+ {"20838", "EBCDIC Thai", NULL, MADB_CS_UNSUPPORTED},
-+ {"20866", "Cyrillic (KOI8-R)", "koi8r", MADB_CS_EXACT},
-+ {"20871", "EBCDIC Icelandic", NULL, MADB_CS_UNSUPPORTED},
-+ {"20880", "EBCDIC Cyrillic Russian", NULL, MADB_CS_UNSUPPORTED},
-+ {"20905", "EBCDIC Turkish", NULL, MADB_CS_UNSUPPORTED},
-+ {"20924", "EBCDIC Latin 1/Open System (1047 + Euro symbol)", NULL, MADB_CS_UNSUPPORTED},
-+ {"20932", "Japanese (JIS 0208-1990 and 0121-1990)", "ujis", MADB_CS_EXACT},
-+ {"20936", "Chinese Simplified (GB2312-80)", "gb2312", MADB_CS_APPROX},
-+ {"20949", "Korean Wansung", "euckr", MADB_CS_APPROX},
-+ {"21025", "EBCDIC Cyrillic Serbian-Bulgarian", NULL, MADB_CS_UNSUPPORTED},
-+ {"21866", "Cyrillic (KOI8-U)", "koi8u", MADB_CS_EXACT},
-+ {"28591", "Western European (ISO)", "latin1", MADB_CS_APPROX},
-+ {"28592", "Central European (ISO)", "latin2", MADB_CS_EXACT},
-+ {"28593", "Latin 3", NULL, MADB_CS_UNSUPPORTED},
-+ {"28594", "Baltic", NULL, MADB_CS_UNSUPPORTED},
-+ {"28595", "ISO 8859-5 Cyrillic", NULL, MADB_CS_UNSUPPORTED},
-+ {"28596", "ISO 8859-6 Arabic", NULL, MADB_CS_UNSUPPORTED},
-+ {"28597", "ISO 8859-7 Greek", "greek", MADB_CS_EXACT},
-+ {"28598", "Hebrew (ISO-Visual)", "hebrew", MADB_CS_EXACT},
-+ {"28599", "ISO 8859-9 Turkish", "latin5", MADB_CS_EXACT},
-+ {"28603", "ISO 8859-13 Estonian", "latin7", MADB_CS_EXACT},
-+ {"28605", "8859-15 Latin 9", NULL, MADB_CS_UNSUPPORTED},
-+ {"29001", "Europa 3", NULL, MADB_CS_UNSUPPORTED},
-+ {"38598", "ISO 8859-8 Hebrew; Hebrew (ISO-Logical)", "hebrew", MADB_CS_EXACT},
-+ {"50220", "ISO 2022 Japanese with no halfwidth Katakana", NULL, MADB_CS_UNSUPPORTED},
-+ {"50221", "ISO 2022 Japanese with halfwidth Katakana", NULL, MADB_CS_UNSUPPORTED},
-+ {"50222", "ISO 2022 Japanese JIS X 0201-1989", NULL, MADB_CS_UNSUPPORTED},
-+ {"50225", "ISO 2022 Korean", NULL, MADB_CS_UNSUPPORTED},
-+ {"50227", "ISO 2022 Simplified Chinese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50229", "ISO 2022 Traditional Chinese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50930", "EBCDIC Japanese (Katakana) Extended", NULL, MADB_CS_UNSUPPORTED},
-+ {"50931", "EBCDIC US-Canada and Japanese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50933", "EBCDIC Korean Extended and Korean", NULL, MADB_CS_UNSUPPORTED},
-+ {"50935", "EBCDIC Simplified Chinese Extended and Simplified Chinese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50936", "EBCDIC Simplified Chinese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50937", "EBCDIC US-Canada and Traditional Chinese", NULL, MADB_CS_UNSUPPORTED},
-+ {"50939", "EBCDIC Japanese (Latin) Extended and Japanese", NULL, MADB_CS_UNSUPPORTED},
-+ {"51932", "EUC Japanese", "ujis", MADB_CS_EXACT},
-+ {"51936", "EUC Simplified Chinese; Chinese Simplified (EUC)", "gb2312", MADB_CS_EXACT},
-+ {"51949", "EUC Korean", "euckr", MADB_CS_EXACT},
-+ {"51950", "EUC Traditional Chinese", "big5", MADB_CS_EXACT},
-+ {"52936", "Chinese Simplified (HZ)", NULL, MADB_CS_UNSUPPORTED},
-+ {"54936", "Chinese Simplified (GB18030)", NULL, MADB_CS_UNSUPPORTED},
-+ {"57002", "ISCII Devanagari", NULL, MADB_CS_UNSUPPORTED},
-+ {"57003", "ISCII Bengali", NULL, MADB_CS_UNSUPPORTED},
-+ {"57004", "ISCII Tamil", NULL, MADB_CS_UNSUPPORTED},
-+ {"57005", "ISCII Telugu", NULL, MADB_CS_UNSUPPORTED},
-+ {"57006", "ISCII Assamese", NULL, MADB_CS_UNSUPPORTED},
-+ {"57007", "ISCII Oriya", NULL, MADB_CS_UNSUPPORTED},
-+ {"57008", "ISCII Kannada", NULL, MADB_CS_UNSUPPORTED},
-+ {"57009", "ISCII Malayalam", NULL, MADB_CS_UNSUPPORTED},
-+ {"57010", "ISCII Gujarati", NULL, MADB_CS_UNSUPPORTED},
-+ {"57011", "ISCII Punjabi", NULL, MADB_CS_UNSUPPORTED},
-+ {"65000", "utf-7 Unicode (UTF-7)", NULL, MADB_CS_UNSUPPORTED},
-+ {"65001", "utf-8 Unicode (UTF-8)", "utf8", MADB_CS_EXACT},
++ {"037", "IBM EBCDIC US-Canada", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"437", "OEM United States", "cp850", NULL, MADB_CS_APPROX},
++ {"500", "IBM EBCDIC International", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"708", "Arabic (ASMO 708)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"709", "Arabic (ASMO-449+, BCON V4)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"710", "Transparent Arabic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"720", "Arabic (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"737", "Greek (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"775", "Baltic (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"850", "Western European (DOS)", "cp850", NULL, MADB_CS_EXACT},
++ {"852", "Central European (DOS)", "cp852", NULL, MADB_CS_EXACT},
++ {"855", "Cyrillic (primarily Russian)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"857", "Turkish (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"858", "OEM Multilingual Latin 1 + Euro symbol", "cp850", NULL, MADB_CS_EXACT},
++ {"860", "Portuguese (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"861", "Icelandic (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"862", "Hebrew (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"863", "French Canadian (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"864", "Arabic (864)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"865", "Nordic (DOS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"866", "Cyrillic (DOS)", "cp866", NULL, MADB_CS_EXACT},
++ {"869", "Greek, Modern (DOS)", "greek", NULL, MADB_CS_EXACT},
++ {"870", "IBM EBCDIC Multilingual Latin 2", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"874", "Thai (Windows)", "tis620", NULL, MADB_CS_UNSUPPORTED},
++ {"875", "Greek Modern", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"932", "Japanese (Shift-JIS)", "cp932", NULL, MADB_CS_EXACT},
++ {"936", "Chinese Simplified (GB2312)", "gbk", NULL, MADB_CS_EXACT},
++ {"949", "ANSI/OEM Korean (Unified Hangul Code)", "euckr", NULL, MADB_CS_EXACT},
++ {"950", "Chinese Traditional (Big5)", "big5", NULL, MADB_CS_EXACT},
++ {"1026", "EBCDIC Turkish (Latin 5)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1047", "EBCDIC Latin 1/Open System", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1140", "IBM EBCDIC (US-Canada-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1141", "IBM EBCDIC (Germany-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1142", "IBM EBCDIC (Denmark-Norway-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1143", "IBM EBCDIC (Finland-Sweden-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1144", "IBM EBCDIC (Italy-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1145", "IBM EBCDIC (Spain-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1146", "IBM EBCDIC (UK-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1147", "IBM EBCDIC (France-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1148", "IBM EBCDIC (International-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1149", "IBM EBCDIC (Icelandic-Euro)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1200", "UTF-16, little endian byte order", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1201", "UTF-16, big endian byte order", "utf16", NULL, MADB_CS_UNSUPPORTED},
++ {"1250", "Central European (Windows)", "cp1250", NULL, MADB_CS_EXACT},
++ {"1251", "Cyrillic (Windows)", "cp1251", NULL, MADB_CS_EXACT},
++ {"1252", "Western European (Windows)", "latin1", NULL, MADB_CS_EXACT},
++ {"1253", "Greek (Windows)", "greek", NULL, MADB_CS_EXACT},
++ {"1254", "Turkish (Windows)", "latin5", NULL, MADB_CS_EXACT},
++ {"1255", "Hebrew (Windows)", "hewbrew", NULL, MADB_CS_EXACT},
++ {"1256", "Arabic (Windows)", "cp1256", NULL, MADB_CS_EXACT},
++ {"1257", "Baltic (Windows)","cp1257", NULL, MADB_CS_EXACT},
++ {"1258", "Vietnamese (Windows)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"1361", "Korean (Johab)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10000", "Western European (Mac)", "macroman", NULL, MADB_CS_EXACT},
++ {"10001", "Japanese (Mac)", "sjis", NULL, MADB_CS_EXACT},
++ {"10002", "Chinese Traditional (Mac)", "big5", NULL, MADB_CS_EXACT},
++ {"10003", "Korean (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10004", "Arabic (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10005", "Hebrew (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10006", "Greek (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10007", "Cyrillic (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10008", "Chinese Simplified (Mac)", "gb2312", NULL, MADB_CS_EXACT},
++ {"10010", "Romanian (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10017", "Ukrainian (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10021", "Thai (Mac)", "tis620", NULL, MADB_CS_EXACT},
++ {"10029", "Central European (Mac)", "macce", NULL, MADB_CS_EXACT},
++ {"10079", "Icelandic (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10081", "Turkish (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"10082", "Croatian (Mac)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"12000", "Unicode UTF-32, little endian byte order", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"12001", "Unicode UTF-32, big endian byte order", "utf32", NULL, MADB_CS_UNSUPPORTED},
++ {"20000", "Chinese Traditional (CNS)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20001", "TCA Taiwan", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20002", "Chinese Traditional (Eten)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20003", "IBM5550 Taiwan", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20004", "TeleText Taiwan", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20005", "Wang Taiwan", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20105", "Western European (IA5)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20106", "IA5 German (7-bit)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20107", "Swedish (7-bit)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20108", "Norwegian (7-bit)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20127", "US-ASCII (7-bit)", "ascii", NULL, MADB_CS_EXACT},
++ {"20261", "T.61", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20269", "Non-Spacing Accent", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20273", "EBCDIC Germany", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20277", "EBCDIC Denmark-Norway", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20278", "EBCDIC Finland-Sweden", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20280", "EBCDIC Italy", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20284", "EBCDIC Latin America-Spain", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20285", "EBCDIC United Kingdom", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20290", "EBCDIC Japanese Katakana Extended", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20297", "EBCDIC France", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20420", "EBCDIC Arabic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20423", "EBCDIC Greek", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20424", "EBCDIC Hebrew", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20833", "EBCDIC Korean Extended", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20838", "EBCDIC Thai", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20866", "Cyrillic (KOI8-R)", "koi8r", NULL, MADB_CS_EXACT},
++ {"20871", "EBCDIC Icelandic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20880", "EBCDIC Cyrillic Russian", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20905", "EBCDIC Turkish", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20924", "EBCDIC Latin 1/Open System (1047 + Euro symbol)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"20932", "Japanese (JIS 0208-1990 and 0121-1990)", "ujis", NULL, MADB_CS_EXACT},
++ {"20936", "Chinese Simplified (GB2312-80)", "gb2312", NULL, MADB_CS_APPROX},
++ {"20949", "Korean Wansung", "euckr", NULL, MADB_CS_APPROX},
++ {"21025", "EBCDIC Cyrillic Serbian-Bulgarian", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"21866", "Cyrillic (KOI8-U)", "koi8u", NULL, MADB_CS_EXACT},
++ {"28591", "Western European (ISO)", "latin1", NULL, MADB_CS_APPROX},
++ {"28592", "Central European (ISO)", "latin2", NULL, MADB_CS_EXACT},
++ {"28593", "Latin 3", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"28594", "Baltic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"28595", "ISO 8859-5 Cyrillic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"28596", "ISO 8859-6 Arabic", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"28597", "ISO 8859-7 Greek", "greek", NULL, MADB_CS_EXACT},
++ {"28598", "Hebrew (ISO-Visual)", "hebrew", NULL, MADB_CS_EXACT},
++ {"28599", "ISO 8859-9 Turkish", "latin5", NULL, MADB_CS_EXACT},
++ {"28603", "ISO 8859-13 Estonian", "latin7", NULL, MADB_CS_EXACT},
++ {"28605", "8859-15 Latin 9", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"29001", "Europa 3", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"38598", "ISO 8859-8 Hebrew; Hebrew (ISO-Logical)", "hebrew", NULL, MADB_CS_EXACT},
++ {"50220", "ISO 2022 Japanese with no halfwidth Katakana", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50221", "ISO 2022 Japanese with halfwidth Katakana", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50222", "ISO 2022 Japanese JIS X 0201-1989", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50225", "ISO 2022 Korean", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50227", "ISO 2022 Simplified Chinese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50229", "ISO 2022 Traditional Chinese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50930", "EBCDIC Japanese (Katakana) Extended", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50931", "EBCDIC US-Canada and Japanese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50933", "EBCDIC Korean Extended and Korean", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50935", "EBCDIC Simplified Chinese Extended and Simplified Chinese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50936", "EBCDIC Simplified Chinese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50937", "EBCDIC US-Canada and Traditional Chinese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"50939", "EBCDIC Japanese (Latin) Extended and Japanese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"51932", "EUC Japanese", "ujis", NULL, MADB_CS_EXACT},
++ {"51936", "EUC Simplified Chinese; Chinese Simplified (EUC)", "gb2312", NULL, MADB_CS_EXACT},
++ {"51949", "EUC Korean", "euckr", NULL, MADB_CS_EXACT},
++ {"51950", "EUC Traditional Chinese", "big5", NULL, MADB_CS_EXACT},
++ {"52936", "Chinese Simplified (HZ)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"54936", "Chinese Simplified (GB18030)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57002", "ISCII Devanagari", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57003", "ISCII Bengali", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57004", "ISCII Tamil", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57005", "ISCII Telugu", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57006", "ISCII Assamese", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57007", "ISCII Oriya", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57008", "ISCII Kannada", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57009", "ISCII Malayalam", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57010", "ISCII Gujarati", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"57011", "ISCII Punjabi", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"65000", "utf-7 Unicode (UTF-7)", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"65001", "utf-8 Unicode (UTF-8)", "utf8", NULL, MADB_CS_EXACT},
+ /* non Windows */
+#else
-+ {"ASCII", "US-ASCII", "ascii", MADB_CS_APPROX},
-+ {"US-ASCII", "US-ASCII", "ascii", MADB_CS_APPROX},
-+ {"Big5", "Chinese for Taiwan Multi-byte set", "big5", MADB_CS_EXACT},
-+ {"CP866", "IBM 866", "cp866", MADB_CS_EXACT},
-+ {"IBM-1252", "Catalan Spain", "cp1252", MADB_CS_EXACT},
-+ {"ISCII-DEV", "Hindi", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO-8859-1", "ISO-8859-1", "latin1", MADB_CS_APPROX},
-+ {"ISO8859-1", "ISO-8859-1", "latin1", MADB_CS_APPROX},
-+ {"ISO_8859-1", "ISO-8859-1", "latin1", MADB_CS_APPROX},
-+ {"ISO88591", "ISO-8859-1", "latin1", MADB_CS_APPROX},
-+ {"ISO-8859-13", "ISO-8859-13", "latin7", MADB_CS_EXACT},
-+ {"ISO8859-13", "ISO-8859-13", "latin7", MADB_CS_EXACT},
-+ {"ISO_8859-13", "ISO-8859-13", "latin7", MADB_CS_EXACT},
-+ {"ISO885913", "ISO-8859-13", "latin7", MADB_CS_EXACT},
-+ {"ISO-8859-15", "ISO-8859-15", "latin9", MADB_CS_UNSUPPORTED},
-+ {"ISO8859-15", "ISO-8859-15", "latin9", MADB_CS_UNSUPPORTED},
-+ {"ISO_8859-15", "ISO-8859-15", "latin9", MADB_CS_UNSUPPORTED},
-+ {"ISO885915", "ISO-8859-15", "latin9", MADB_CS_UNSUPPORTED},
-+ {"ISO-8859-2", "ISO-8859-2", "latin2", MADB_CS_EXACT},
-+ {"ISO8859-2", "ISO-8859-2", "latin2", MADB_CS_EXACT},
-+ {"ISO_8859-2", "ISO-8859-2", "latin2", MADB_CS_EXACT},
-+ {"ISO88592", "ISO-8859-2", "latin2", MADB_CS_EXACT},
-+ {"ISO-8859-7", "ISO-8859-7", "greek", MADB_CS_EXACT},
-+ {"ISO8859-7", "ISO-8859-7", "greek", MADB_CS_EXACT},
-+ {"ISO_8859-7", "ISO-8859-7", "greek", MADB_CS_EXACT},
-+ {"ISO88597", "ISO-8859-7", "greek", MADB_CS_EXACT},
-+ {"ISO-8859-8", "ISO-8859-8", "hebrew", MADB_CS_EXACT},
-+ {"ISO8859-8", "ISO-8859-8", "hebrew", MADB_CS_EXACT},
-+ {"ISO_8859-8", "ISO-8859-8", "hebrew", MADB_CS_EXACT},
-+ {"ISO88598", "ISO-8859-8", "hebrew", MADB_CS_EXACT},
-+ {"ISO-8859-9", "ISO-8859-9", "latin5", MADB_CS_EXACT},
-+ {"ISO8859-9", "ISO-8859-9", "latin5", MADB_CS_EXACT},
-+ {"ISO_8859-9", "ISO-8859-9", "latin5", MADB_CS_EXACT},
-+ {"ISO88599", "ISO-8859-9", "latin5", MADB_CS_EXACT},
-+ {"ISO-8859-4", "ISO-8859-4", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO8859-4", "ISO-8859-4", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO_8859-4", "ISO-8859-4", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO88594", "ISO-8859-4", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO-8859-5", "ISO-8859-5", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO8859-5", "ISO-8859-5", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO_8859-5", "ISO-8859-5", NULL, MADB_CS_UNSUPPORTED},
-+ {"ISO88595", "ISO-8859-5", NULL, MADB_CS_UNSUPPORTED},
-+ {"KOI8-R", "KOI8-R", "koi8r", MADB_CS_EXACT},
-+ {"koi8r", "KOI8-R", "koi8r", MADB_CS_EXACT},
-+ {"KOI8-U", "KOI8-U", "koi8u", MADB_CS_EXACT},
-+ {"koi8u", "KOI8-U", "koi8u", MADB_CS_EXACT},
-+ {"koi8t", "KOI8-T", NULL, MADB_CS_UNSUPPORTED},
-+ {"KOI8-T", "KOI8-T", NULL, MADB_CS_UNSUPPORTED},
-+ {"SJIS", "SHIFT_JIS", "sjis", MADB_CS_EXACT},
-+ {"Shift-JIS", "SHIFT_JIS", "sjis", MADB_CS_EXACT},
-+ {"ansi1251", "Cyrillic", "cp1251", MADB_CS_EXACT},
-+ {"cp1251", "Cyrillic", "cp1251", MADB_CS_EXACT},
-+ {"armscii8", "Armenian", "armscii8", MADB_CS_EXACT},
-+ {"armscii-8", "Armenian", "armscii8", MADB_CS_EXACT},
-+ {"big5hkscs", "Big5-HKSCS", NULL, MADB_CS_UNSUPPORTED},
-+ {"cp1255", "Hebrew", "cp1255", MADB_CS_EXACT},
-+ {"eucCN", "GB-2312", "gb2312", MADB_CS_EXACT},
-+ {"eucJP", "UJIS", "ujis", MADB_CS_EXACT},
-+ {"eucKR", "EUC-KR", "euckr", MADB_CS_EXACT},
-+ {"euctw", "EUC-TW", NULL, MADB_CS_UNSUPPORTED},
-+ {"gb18030", "GB 18030-2000", "gb18030", MADB_CS_UNSUPPORTED},
-+ {"gb2312", "GB2312", "gb2312", MADB_CS_EXACT},
-+ {"gbk", "GBK", "gbk", MADB_CS_EXACT},
-+ {"georgianps", "Georgian", "geostd8", MADB_CS_EXACT},
-+ {"utf8", "UTF8", "utf8", MADB_CS_EXACT},
-+ {"utf-8", "UTF8", "utf8", MADB_CS_EXACT},
-+#endif
-+ {NULL, NULL, NULL, 0}
++ /* iconv encodings */
++ {"ASCII", "US-ASCII", "ascii", "ASCII", MADB_CS_APPROX},
++ {"US-ASCII", "US-ASCII", "ascii", "ASCII", MADB_CS_APPROX},
++ {"Big5", "Chinese for Taiwan Multi-byte set", "big5", "BIG5", MADB_CS_EXACT},
++ {"CP866", "IBM 866", "cp866", "CP866", MADB_CS_EXACT},
++ {"IBM-1252", "Catalan Spain", "cp1252", "CP1252", MADB_CS_EXACT},
++ {"ISCII-DEV", "Hindi", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"ISO-8859-1", "ISO-8859-1", "latin1", "ISO_8859-1", MADB_CS_APPROX},
++ {"ISO8859-1", "ISO-8859-1", "latin1", "ISO_8859-1", MADB_CS_APPROX},
++ {"ISO_8859-1", "ISO-8859-1", "latin1", "ISO_8859-1", MADB_CS_APPROX},
++ {"ISO88591", "ISO-8859-1", "latin1", "ISO_8859-1", MADB_CS_APPROX},
++ {"ISO-8859-13", "ISO-8859-13", "latin7", "ISO_8859-13", MADB_CS_EXACT},
++ {"ISO8859-13", "ISO-8859-13", "latin7", "ISO_8859-13", MADB_CS_EXACT},
++ {"ISO_8859-13", "ISO-8859-13", "latin7", "ISO_8859-13", MADB_CS_EXACT},
++ {"ISO885913", "ISO-8859-13", "latin7", "ISO_8859-13", MADB_CS_EXACT},
++ {"ISO-8859-15", "ISO-8859-15", "latin9", "ISO_8859-15", MADB_CS_UNSUPPORTED},
++ {"ISO8859-15", "ISO-8859-15", "latin9", "ISO_8859-15", MADB_CS_UNSUPPORTED},
++ {"ISO_8859-15", "ISO-8859-15", "latin9", "ISO_8859-15", MADB_CS_UNSUPPORTED},
++ {"ISO885915", "ISO-8859-15", "latin9", "ISO_8859-15", MADB_CS_UNSUPPORTED},
++ {"ISO-8859-2", "ISO-8859-2", "latin2", "ISO_8859-2", MADB_CS_EXACT},
++ {"ISO8859-2", "ISO-8859-2", "latin2", "ISO_8859-2", MADB_CS_EXACT},
++ {"ISO_8859-2", "ISO-8859-2", "latin2", "ISO_8859-2", MADB_CS_EXACT},
++ {"ISO88592", "ISO-8859-2", "latin2", "ISO_8859-2", MADB_CS_EXACT},
++ {"ISO-8859-7", "ISO-8859-7", "greek", "ISO_8859-7", MADB_CS_EXACT},
++ {"ISO8859-7", "ISO-8859-7", "greek", "ISO_8859-7", MADB_CS_EXACT},
++ {"ISO_8859-7", "ISO-8859-7", "greek", "ISO_8859-7", MADB_CS_EXACT},
++ {"ISO88597", "ISO-8859-7", "greek", "ISO_8859-7", MADB_CS_EXACT},
++ {"ISO-8859-8", "ISO-8859-8", "hebrew", "ISO_8859-8", MADB_CS_EXACT},
++ {"ISO8859-8", "ISO-8859-8", "hebrew", "ISO_8859-8", MADB_CS_EXACT},
++ {"ISO_8859-8", "ISO-8859-8", "hebrew", "ISO_8859-8", MADB_CS_EXACT},
++ {"ISO88598", "ISO-8859-8", "hebrew", "ISO_8859-8", MADB_CS_EXACT},
++ {"ISO-8859-9", "ISO-8859-9", "latin5", "ISO_8859-9", MADB_CS_EXACT},
++ {"ISO8859-9", "ISO-8859-9", "latin5", "ISO_8859-9", MADB_CS_EXACT},
++ {"ISO_8859-9", "ISO-8859-9", "latin5", "ISO_8859-9", MADB_CS_EXACT},
++ {"ISO88599", "ISO-8859-9", "latin5", "ISO_8859-9", MADB_CS_EXACT},
++ {"ISO-8859-4", "ISO-8859-4", NULL, "ISO_8859-4", MADB_CS_UNSUPPORTED},
++ {"ISO8859-4", "ISO-8859-4", NULL, "ISO_8859-4", MADB_CS_UNSUPPORTED},
++ {"ISO_8859-4", "ISO-8859-4", NULL, "ISO_8859-4", MADB_CS_UNSUPPORTED},
++ {"ISO88594", "ISO-8859-4", NULL, "ISO_8859-4", MADB_CS_UNSUPPORTED},
++ {"ISO-8859-5", "ISO-8859-5", NULL, "ISO_8859-5", MADB_CS_UNSUPPORTED},
++ {"ISO8859-5", "ISO-8859-5", NULL, "ISO_8859-5", MADB_CS_UNSUPPORTED},
++ {"ISO_8859-5", "ISO-8859-5", NULL, "ISO_8859-5", MADB_CS_UNSUPPORTED},
++ {"ISO88595", "ISO-8859-5", NULL, "ISO_8859-5", MADB_CS_UNSUPPORTED},
++ {"KOI8-R", "KOI8-R", "koi8r", "KOI8R", MADB_CS_EXACT},
++ {"koi8r", "KOI8-R", "koi8r", "KOI8R", MADB_CS_EXACT},
++ {"KOI8-U", "KOI8-U", "koi8u", "KOI8U", MADB_CS_EXACT},
++ {"koi8u", "KOI8-U", "koi8u", "KOI8U", MADB_CS_EXACT},
++ {"koi8t", "KOI8-T", NULL, "KOI8-T", MADB_CS_UNSUPPORTED},
++ {"KOI8-T", "KOI8-T", NULL, "KOI8-T", MADB_CS_UNSUPPORTED},
++ {"SJIS", "SHIFT_JIS", "sjis", "SJIS", MADB_CS_EXACT},
++ {"Shift-JIS", "SHIFT_JIS", "sjis", "SJIS", MADB_CS_EXACT},
++ {"ansi1251", "Cyrillic", "cp1251", "CP1251", MADB_CS_EXACT},
++ {"cp1251", "Cyrillic", "cp1251", "CP1251", MADB_CS_EXACT},
++ {"armscii8", "Armenian", "armscii8", "ASMSCII-8", MADB_CS_EXACT},
++ {"armscii-8", "Armenian", "armscii8", "ASMSCII-8", MADB_CS_EXACT},
++ {"big5hkscs", "Big5-HKSCS", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"cp1255", "Hebrew", "cp1255", "CP1255", MADB_CS_EXACT},
++ {"eucCN", "GB-2312", "gb2312", "GB2312", MADB_CS_EXACT},
++ {"eucJP", "UJIS", "ujis", "UJIS", MADB_CS_EXACT},
++ {"eucKR", "EUC-KR", "euckr", "EUCKR", MADB_CS_EXACT},
++ {"euctw", "EUC-TW", NULL, NULL, MADB_CS_UNSUPPORTED},
++ {"gb18030", "GB 18030-2000", "gb18030", "GB18030", MADB_CS_UNSUPPORTED},
++ {"gb2312", "GB2312", "gb2312", "GB2312", MADB_CS_EXACT},
++ {"gbk", "GBK", "gbk", "GBK", MADB_CS_EXACT},
++ {"georgianps", "Georgian", "geostd8", "GEORGIAN-PS", MADB_CS_EXACT},
++ {"utf8", "UTF8", "utf8", "UTF-8", MADB_CS_EXACT},
++ {"utf-8", "UTF8", "utf8", "UTF-8", MADB_CS_EXACT},
++#endif
++ {NULL, NULL, NULL, NULL, 0}
+};
+/* }}} */
+
@@ -3853,610 +22966,5263 @@
+#endif
+/* }}} */
+
-
-=== modified file 'libmariadb/my_compress.c'
---- mariadb/libmysql/my_compress.c 2011-10-10 11:01:17 +0000
-+++ mariadb/libmariadb/my_compress.c 2013-03-14 21:01:43 +0000
-@@ -29,13 +29,13 @@
- ** *complen is 0 if the packet wasn't compressed
- */
-
--my_bool my_compress(byte *packet, ulong *len, ulong *complen)
-+my_bool my_compress(unsigned char *packet, ulong *len, ulong *complen)
- {
- if (*len < MIN_COMPRESS_LENGTH)
- *complen=0;
- else
- {
-- byte *compbuf=my_compress_alloc(packet,len,complen);
++size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs,
++ char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode)
++{
++ iconv_t conv= 0;
++ size_t rc= -1;
++ size_t save_len= *to_len;
++ char to_encoding[128];
++
++ *errorcode= 0;
++
++ /* check if conversion is supported */
++ if (!from_cs || !from_cs->encoding || !from_cs->encoding[0] ||
++ !to_cs || !to_cs->encoding || !to_cs->encoding[0])
++ {
++ *errorcode= EINVAL;
++ return rc;
++ }
++ snprintf(to_encoding, 128, "%s//TRANSLIT", to_cs->encoding);
++
++ if ((conv= iconv_open(to_encoding, from_cs->encoding)) == (iconv_t)-1)
++ {
++ *errorcode= errno;
++ goto error;
++ }
++
++ if ((rc= iconv(conv, (char **)&from, from_len, &to, to_len)) == -1)
++ {
++ *errorcode= errno;
++ goto error;
++ }
++ rc= save_len - *to_len;
++error:
++ if (conv != (iconv_t)-1)
++ iconv_close(conv);
++ return rc;
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_compress.c mariadb-native-client.trunk/libmariadb/my_compress.c
+--- mariadb/libmariadb/my_compress.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_compress.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,88 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
++
++#include <my_global.h>
++#ifdef HAVE_COMPRESS
++#include <my_sys.h>
++#include <m_string.h>
++#include <zlib.h>
++
++/*
++** This replaces the packet with a compressed packet
++** Returns 1 on error
++** *complen is 0 if the packet wasn't compressed
++*/
++
++my_bool my_compress(unsigned char *packet, size_t *len, size_t *complen)
++{
++ if (*len < MIN_COMPRESS_LENGTH)
++ *complen=0;
++ else
++ {
+ unsigned char *compbuf=my_compress_alloc(packet,len,complen);
- if (!compbuf)
- return *complen ? 0 : 1;
- memcpy(packet,compbuf,*len);
-@@ -44,11 +44,11 @@
- }
-
-
--byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
-+unsigned char *my_compress_alloc(const unsigned char *packet, ulong *len, ulong *complen)
- {
-- byte *compbuf;
++ if (!compbuf)
++ return *complen ? 0 : 1;
++ memcpy(packet,compbuf,*len);
++ my_free((gptr)compbuf,MYF(MY_WME));
++ }
++ return 0;
++}
++
++
++unsigned char *my_compress_alloc(const unsigned char *packet, size_t *len, size_t *complen)
++{
+ unsigned char *compbuf;
- *complen = *len * 120 / 100 + 12;
-- if (!(compbuf = (byte *) my_malloc(*complen,MYF(MY_WME))))
++ *complen = *len * 120 / 100 + 12;
+ if (!(compbuf = (unsigned char *) my_malloc(*complen,MYF(MY_WME))))
- return 0; /* Not enough memory */
- if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
- (uLong) *len ) != Z_OK)
-@@ -67,11 +67,11 @@
- }
-
-
--my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
-+my_bool my_uncompress (unsigned char *packet, ulong *len, ulong *complen)
- {
- if (*complen) /* If compressed */
- {
-- byte *compbuf = (byte *) my_malloc (*complen,MYF(MY_WME));
++ return 0; /* Not enough memory */
++ if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
++ (uLong) *len ) != Z_OK)
++ {
++ my_free((gptr)compbuf,MYF(MY_WME));
++ return 0;
++ }
++ if (*complen >= *len)
++ {
++ *complen=0;
++ my_free((gptr)compbuf,MYF(MY_WME));
++ return 0;
++ }
++ swap(ulong,*len,*complen); /* *len is now packet length */
++ return compbuf;
++}
++
++my_bool my_uncompress (unsigned char *packet, size_t *len, size_t *complen)
++{
++ if (*complen) /* If compressed */
++ {
+ unsigned char *compbuf = (unsigned char *) my_malloc (*complen,MYF(MY_WME));
- if (!compbuf)
- return 1; /* Not enough memory */
- if (uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len) != Z_OK)
-
-=== modified file 'libmariadb/my_fstream.c'
---- mariadb/libmysql/my_fstream.c 2011-10-10 11:01:17 +0000
-+++ mariadb/libmariadb/my_fstream.c 2013-03-14 21:01:43 +0000
-@@ -32,7 +32,7 @@
- /* Read a chunk of bytes from a file */
- /* Returns (uint) -1 if error as my_read() */
-
--uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
++ if (!compbuf)
++ return 1; /* Not enough memory */
++ if (uncompress((Bytef*) compbuf, (uLongf *)complen, (Bytef*) packet, (uLongf)*len) != Z_OK)
++ { /* Probably wrong packet */
++ my_free ((gptr)compbuf,MYF(MY_WME));
++ return 1;
++ }
++ *len = *complen;
++ memcpy(packet,compbuf,*len);
++ my_free((gptr)compbuf,MYF(MY_WME));
++ }
++ return 0;
++}
++#endif /* HAVE_COMPRESS */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_div.c mariadb-native-client.trunk/libmariadb/my_div.c
+--- mariadb/libmariadb/my_div.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_div.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,31 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++
++my_string my_filename(File fd)
++{
++ DBUG_ENTER("my_filename");
++ if (fd >= MY_NFILE)
++ DBUG_RETURN((char*) "UNKNOWN");
++ if (fd >= 0 && my_file_info[fd].type != UNOPEN)
++ {
++ DBUG_RETURN(my_file_info[fd].name);
++ }
++ else
++ DBUG_RETURN((char*) "UNOPENED"); /* Debug message */
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_error.c mariadb-native-client.trunk/libmariadb/my_error.c
+--- mariadb/libmariadb/my_error.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_error.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,124 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <m_string.h>
++#include <stdarg.h>
++#include <m_ctype.h>
++
++/* Define some external variables for error handling */
++
++const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0};
++char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
++
++/* Error message to user */
++/*VARARGS2*/
++
++int my_error(int nr,myf MyFlags, ...)
++{
++ va_list ap;
++ uint olen, plen;
++ reg1 const char *tpos;
++ reg2 char *endpos;
++ char * par;
++ char ebuff[ERRMSGSIZE+20];
++ DBUG_ENTER("my_error");
++
++ va_start(ap,MyFlags);
++ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
++
++ if (nr / ERRMOD == GLOB && my_errmsg[GLOB] == 0)
++ init_glob_errs();
++
++ olen=(uint) strlen(tpos=my_errmsg[nr / ERRMOD][nr % ERRMOD]);
++ endpos=ebuff;
++
++ while (*tpos)
++ {
++ if (tpos[0] != '%')
++ {
++ *endpos++= *tpos++; /* Copy ordinary char */
++ olen++;
++ continue;
++ }
++ if (*++tpos == '%') /* test if %% */
++ {
++ olen--;
++ }
++ else
++ {
++ /* Skipp if max size is used (to be compatible with printf) */
++ while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
++ tpos++;
++ if (*tpos == 'l') /* Skipp 'l' argument */
++ tpos++;
++ if (*tpos == 's') /* String parameter */
++ {
++ par = va_arg(ap, char *);
++ plen = (uint) strlen(par);
++ if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
++ {
++ endpos=strmov(endpos,par);
++ tpos++;
++ olen+=plen-2;
++ continue;
++ }
++ }
++ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
++ {
++ register int iarg;
++ iarg = va_arg(ap, int);
++ if (*tpos == 'd')
++ plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
++ else
++ plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
++ if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
++ {
++ endpos+=plen;
++ tpos++;
++ olen+=plen-2;
++ continue;
++ }
++ }
++ }
++ *endpos++='%'; /* % used as % or unknown code */
++ }
++ *endpos='\0'; /* End of errmessage */
++ va_end(ap);
++ DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
++}
++
++ /* Error as printf */
++
++int my_printf_error (uint error, const char *format, myf MyFlags, ...)
++{
++ va_list args;
++ char ebuff[ERRMSGSIZE+20];
++
++ va_start(args,MyFlags);
++ (void) vsprintf (ebuff,format,args);
++ va_end(args);
++ return (*error_handler_hook)(error, ebuff, MyFlags);
++}
++
++ /* Give message using error_handler_hook */
++
++int my_message(uint error, const char *str, register myf MyFlags)
++{
++ return (*error_handler_hook)(error, str, MyFlags);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_fopen.c mariadb-native-client.trunk/libmariadb/my_fopen.c
+--- mariadb/libmariadb/my_fopen.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_fopen.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,178 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "my_static.h"
++#include <errno.h>
++#include "mysys_err.h"
++
++static void make_ftype(my_string to,int flag);
++
++ /* Open a file as stream */
++
++FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
++ /* Path-name of file */
++ /* Read | write .. */
++ /* Special flags */
++{
++ FILE *fd;
++ char type[5];
++ DBUG_ENTER("my_fopen");
++ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
++ FileName, Flags, MyFlags));
++
++ make_ftype(type,Flags);
++#ifdef _WIN32
++ if (fopen_s(&fd, FileName, type) == 0)
++#else
++ if ((fd = fopen(FileName, type)) != 0)
++#endif
++ {
++ /*
++ The test works if MY_NFILE < 128. The problem is that fileno() is char
++ on some OS (SUNOS). Actually the filename save isn't that important
++ so we can ignore if this doesn't work.
++ */
++ if ((uint) fileno(fd) >= MY_NFILE)
++ {
++ thread_safe_increment(my_stream_opened,&THR_LOCK_open);
++ DBUG_RETURN(fd); /* safeguard */
++ }
++ pthread_mutex_lock(&THR_LOCK_open);
++ if ((my_file_info[fileno(fd)].name = (char*)
++ my_strdup(FileName,MyFlags)))
++ {
++ my_stream_opened++;
++ my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
++ pthread_mutex_unlock(&THR_LOCK_open);
++ DBUG_PRINT("exit",("stream: %lx",fd));
++ DBUG_RETURN(fd);
++ }
++ pthread_mutex_unlock(&THR_LOCK_open);
++ (void) my_fclose(fd,MyFlags);
++ my_errno=ENOMEM;
++ }
++ else
++ my_errno=errno;
++ DBUG_PRINT("error",("Got error %d on open",my_errno));
++ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
++ my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND :
++ EE_CANTCREATEFILE,
++ MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
++ DBUG_RETURN((FILE*) 0);
++} /* my_fopen */
++
++
++ /* Close a stream */
++
++int my_fclose(FILE *fd, myf MyFlags)
++{
++ int err,file;
++ DBUG_ENTER("my_fclose");
++ DBUG_PRINT("my",("stream: %lx MyFlags: %d",fd, MyFlags));
++
++ pthread_mutex_lock(&THR_LOCK_open);
++ file=fileno(fd);
++ if ((err = fclose(fd)) < 0)
++ {
++ my_errno=errno;
++ if (MyFlags & (MY_FAE | MY_WME))
++ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(file),errno);
++ }
++ else
++ my_stream_opened--;
++ if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN)
++ {
++ my_file_info[file].type = UNOPEN;
++ my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR));
++ }
++ pthread_mutex_unlock(&THR_LOCK_open);
++ DBUG_RETURN(err);
++} /* my_fclose */
++
++
++ /* Make a stream out of a file handle */
++ /* Name may be 0 */
++
++FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
++{
++ FILE *fd;
++ char type[5];
++ DBUG_ENTER("my_fdopen");
++ DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
++ Filedes, Flags, MyFlags));
++
++ make_ftype(type,Flags);
++ if ((fd = fdopen(Filedes, type)) == 0)
++ {
++ my_errno=errno;
++ if (MyFlags & (MY_FAE | MY_WME))
++ my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno);
++ }
++ else
++ {
++ pthread_mutex_lock(&THR_LOCK_open);
++ my_stream_opened++;
++ if (Filedes < MY_NFILE)
++ {
++ if (my_file_info[Filedes].type != UNOPEN)
++ {
++ my_file_opened--; /* File is opened with my_open ! */
++ }
++ else
++ {
++ my_file_info[Filedes].name= my_strdup(name,MyFlags);
++ }
++ my_file_info[Filedes].type = STREAM_BY_FDOPEN;
++ }
++ pthread_mutex_unlock(&THR_LOCK_open);
++ }
++
++ DBUG_PRINT("exit",("stream: %lx",fd));
++ DBUG_RETURN(fd);
++} /* my_fdopen */
++
++
++ /* Make a filehandler-open-typestring from ordinary inputflags */
++
++static void make_ftype(register my_string to, register int flag)
++{
++#if FILE_BINARY /* If we have binary-files */
++ reg3 int org_flag=flag;
++#endif
++ flag&= ~FILE_BINARY; /* remove binary bit */
++ if (flag == O_RDONLY)
++ *to++= 'r';
++ else if (flag == O_WRONLY)
++ *to++= 'w';
++ else
++ { /* Add '+' after theese */
++ if (flag == O_RDWR)
++ *to++= 'r';
++ else if (flag & O_APPEND)
++ *to++= 'a';
++ else
++ *to++= 'w'; /* Create file */
++ *to++= '+';
++ }
++#if FILE_BINARY /* If we have binary-files */
++ if (org_flag & FILE_BINARY)
++ *to++='b';
++#endif
++ *to='\0';
++} /* make_ftype */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_fstream.c mariadb-native-client.trunk/libmariadb/my_fstream.c
+--- mariadb/libmariadb/my_fstream.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_fstream.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,171 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <errno.h>
++#include <stdio.h>
++
++#ifdef HAVE_FSEEKO
++#undef ftell
++#undef fseek
++#define ftell(A) ftello(A)
++#define fseek(A,B,C) fseeko((A),(B),(C))
++#endif
++
++ /* Read a chunk of bytes from a file */
++ /* Returns (uint) -1 if error as my_read() */
++
+uint my_fread(FILE *stream, unsigned char *Buffer, uint Count, myf MyFlags)
- /* File descriptor */
- /* Buffer must be at least count bytes */
- /* Max number of bytes returnd */
-@@ -73,7 +73,7 @@
- ** Does retries if interrupted
- */
-
--uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
++ /* File descriptor */
++ /* Buffer must be at least count bytes */
++ /* Max number of bytes returnd */
++ /* Flags on what to do on error */
++{
++ uint readbytes;
++ DBUG_ENTER("my_fread");
++ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
++ stream, Buffer, Count, MyFlags));
++
++ if ((readbytes = (uint) fread(Buffer,sizeof(char),(size_t) Count,stream))
++ != Count)
++ {
++ DBUG_PRINT("error",("Read only %d bytes",readbytes));
++ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
++ {
++ if (ferror(stream))
++ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(fileno(stream)),errno);
++ else
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(fileno(stream)),errno);
++ }
++ my_errno=errno ? errno : -1;
++ if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
++ DBUG_RETURN((uint) -1); /* Return with error */
++ }
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ DBUG_RETURN(0); /* Read ok */
++ DBUG_RETURN(readbytes);
++} /* my_fread */
++
++
++/*
++** Write a chunk of bytes to a stream
++** Returns (uint) -1 if error as my_write()
++** Does retries if interrupted
++*/
++
+uint my_fwrite(FILE *stream, const unsigned char *Buffer, uint Count, myf MyFlags)
- {
- uint writenbytes=0;
- off_t seekptr;
-
-=== modified file 'libmariadb/my_lib.c'
---- mariadb/libmysql/my_lib.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/my_lib.c 2013-03-14 21:01:43 +0000
-@@ -592,7 +592,7 @@
- int m_used;
- DBUG_ENTER("my_stat");
- DBUG_PRINT("my", ("path: '%s', stat_area: %lx, MyFlags: %d", path,
-- (byte *) stat_area, my_flags));
++{
++ uint writenbytes=0;
++ off_t seekptr;
++#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
++ uint errors;
++#endif
++ DBUG_ENTER("my_fwrite");
++ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
++ stream, Buffer, Count, MyFlags));
++
++#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
++ errors=0;
++#endif
++ seekptr=ftell(stream);
++ for (;;)
++ {
++ uint writen;
++ if ((writen = (uint) fwrite((char*) Buffer,sizeof(char),
++ (size_t) Count, stream)) != Count)
++ {
++ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
++ my_errno=errno;
++ if (writen != (uint) -1)
++ {
++ seekptr+=writen;
++ Buffer+=writen;
++ writenbytes+=writen;
++ Count-=writen;
++ }
++#ifdef EINTR
++ if (errno == EINTR)
++ {
++ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
++ continue;
++ }
++#endif
++#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
++#ifdef THREAD
++ if (my_thread_var->abort)
++ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
++#endif
++ if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
++ {
++ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
++ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH));
++ sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
++ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
++ continue;
++ }
++#endif
++ if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP)))
++ {
++ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
++ {
++ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(fileno(stream)),errno);
++ }
++ writenbytes=(uint) -1; /* Return that we got error */
++ break;
++ }
++ }
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ writenbytes=0; /* Everything OK */
++ else
++ writenbytes+=writen;
++ break;
++ }
++ DBUG_RETURN(writenbytes);
++} /* my_fwrite */
++
++ /* Seek to position in file */
++ /* ARGSUSED */
++
++my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
++{
++ DBUG_ENTER("my_fseek");
++ DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d",
++ stream, pos, whence, MyFlags));
++ DBUG_RETURN(fseek(stream, (off_t) pos, whence) ?
++ MY_FILEPOS_ERROR : (my_off_t) ftell(stream));
++} /* my_seek */
++
++
++ /* Tell current position of file */
++ /* ARGSUSED */
++
++my_off_t my_ftell(FILE *stream, myf MyFlags)
++{
++ off_t pos;
++ DBUG_ENTER("my_ftell");
++ DBUG_PRINT("my",("stream: %lx MyFlags: %d",stream, MyFlags));
++ pos=ftell(stream);
++ DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
++ DBUG_RETURN((my_off_t) pos);
++} /* my_ftell */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_getwd.c mariadb-native-client.trunk/libmariadb/my_getwd.c
+--- mariadb/libmariadb/my_getwd.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_getwd.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,202 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* my_setwd() and my_getwd() works with intern_filenames !! */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#include "mysys_err.h"
++#ifdef HAVE_GETWD
++#include <sys/param.h>
++#endif
++#if defined(MSDOS) || defined(_WIN32)
++#include <m_ctype.h>
++#include <dos.h>
++#include <direct.h>
++#endif
++#if defined(OS2)
++#include <direct.h>
++#endif
++
++#ifdef __EMX__
++// chdir2 support also drive change
++#define chdir _chdir2
++#endif
++
++ /* Gets current working directory in buff. Directory is allways ended
++ with FN_LIBCHAR */
++ /* One must pass a buffer to my_getwd. One can allways use
++ curr_dir[] */
++
++int my_getwd(my_string buf, uint size, myf MyFlags)
++{
++ my_string pos;
++ DBUG_ENTER("my_getwd");
++ DBUG_PRINT("my",("buf: %lx size: %d MyFlags %d", buf,size,MyFlags));
++
++#if ! defined(MSDOS)
++ if (curr_dir[0]) /* Current pos is saved here */
++ VOID(strmake(buf,&curr_dir[0],size-1));
++ else
++#endif
++ {
++#if defined(HAVE_GETCWD)
++#ifdef _WIN32
++ if (!(_getcwd(buf,size-2)) && MyFlags & MY_WME)
++#else
++ if (!(getcwd(buf,size-2)) && MyFlags & MY_WME)
++#endif
++ {
++ my_errno=errno;
++ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
++ return(-1);
++ }
++#elif defined(HAVE_GETWD)
++ {
++ char pathname[MAXPATHLEN];
++ getwd(pathname);
++ strmake(buf,pathname,size-1);
++ }
++#elif defined(VMS)
++ if (!getcwd(buf,size-2,1) && MyFlags & MY_WME)
++ {
++ my_errno=errno;
++ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
++ return(-1);
++ }
++ intern_filename(buf,buf);
++#else
++#error "No way to get current directory"
++#endif
++ if (*((pos=strend(buf))-1) != FN_LIBCHAR) /* End with FN_LIBCHAR */
++ {
++ pos[0]= FN_LIBCHAR;
++ pos[1]=0;
++ }
++ (void) strmake(&curr_dir[0],buf,(size_s) (FN_REFLEN-1));
++ }
++ DBUG_RETURN(0);
++} /* my_getwd */
++
++
++ /* Set new working directory */
++
++int my_setwd(const char *dir, myf MyFlags)
++{
++ int res;
++ size_s length;
++ my_string start,pos;
++#if defined(VMS) || defined(MSDOS) || defined(OS2)
++ char buff[FN_REFLEN];
++#endif
++ DBUG_ENTER("my_setwd");
++ DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
++
++ start=(my_string) dir;
++#if defined(MSDOS) || defined(OS2) /* OS2/MSDOS chdir can't change drive */
++#if !defined(_DDL) && !defined(WIN32)
++ if ((pos=(char*) strchr(dir,FN_DEVCHAR)) != 0)
++ {
++ uint drive,drives;
++
++ pos++; /* Skipp FN_DEVCHAR */
++ drive=(uint) (toupper(dir[0])-'A'+1); drives= (uint) -1;
++ if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
++ {
++#ifdef OS2
++ _chdrive(drive);
++ drives = _getdrive();
++#else
++ _dos_setdrive(drive,&drives);
++ _dos_getdrive(&drives);
++#endif
++ }
++ if (drive != drives)
++ {
++ *pos='\0'; /* Dir is now only drive */
++ my_errno=errno;
++ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
++ DBUG_RETURN(-1);
++ }
++ dir=pos; /* drive changed, change now path */
++ }
++#endif
++ if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
++ {
++ strmov(buff,dir)[-1]=0; /* Remove last '/' */
++ dir=buff;
++ }
++#endif /* MSDOS*/
++ if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
++ dir=FN_ROOTDIR;
++#ifdef VMS
++ {
++ pos=strmov(buff,dir);
++ if (pos[-1] != FN_LIBCHAR)
++ {
++ pos[0]=FN_LIBCHAR; /* Mark as directory */
++ pos[1]=0;
++ }
++ system_filename(buff,buff); /* Change to VMS format */
++ dir=buff;
++ }
++#endif /* VMS */
++#ifdef _WIN32
++ if ((res=_chdir((char*) dir)) != 0)
++#else
++ if ((res=chdir((char*) dir)) != 0)
++#endif
++ {
++ my_errno=errno;
++ if (MyFlags & MY_WME)
++ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),start,errno);
++ }
++ else
++ {
++ if (test_if_hard_path(start))
++ { /* Hard pathname */
++ pos=strmake(&curr_dir[0],start,(size_s) FN_REFLEN-1);
++ if (pos[-1] != FN_LIBCHAR)
++ {
++ length=(uint) (pos-(char*) curr_dir);
++ curr_dir[length]=FN_LIBCHAR; /* must end with '/' */
++ curr_dir[length+1]='\0';
++ }
++ }
++ else
++ curr_dir[0]='\0'; /* Don't save name */
++ }
++ DBUG_RETURN(res);
++} /* my_setwd */
++
++
++
++ /* Test if hard pathname */
++ /* Returns 1 if dirname is a hard path */
++
++int test_if_hard_path(register const char *dir_name)
++{
++ if (dir_name[0] == FN_HOMELIB && dir_name[1] == FN_LIBCHAR)
++ return (home_dir != NullS && test_if_hard_path(home_dir));
++ if (dir_name[0] == FN_LIBCHAR)
++ return (TRUE);
++#ifdef FN_DEVCHAR
++ return (strchr(dir_name,FN_DEVCHAR) != 0);
++#else
++ return FALSE;
++#endif
++} /* test_if_hard_path */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_init.c mariadb-native-client.trunk/libmariadb/my_init.c
+--- mariadb/libmariadb/my_init.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_init.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,273 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "my_static.h"
++#include "mysys_err.h"
++#include "m_ctype.h"
++#include <m_string.h>
++#include <m_ctype.h>
++#ifdef HAVE_GETRUSAGE
++#include <sys/resource.h>
++/* extern int getrusage(int, struct rusage *); */
++#endif
++#include <signal.h>
++#ifdef VMS
++#include <my_static.c>
++#include <m_ctype.h>
++#endif
++#ifdef _WIN32
++#ifdef _MSC_VER
++#include <locale.h>
++#include <crtdbg.h>
++#endif
++my_bool have_tcpip=0;
++static void my_win_init(void);
++static my_bool win32_have_tcpip(void);
++static my_bool win32_init_tcp_ip();
++#else
++#define my_win_init()
++#endif
++
++my_bool my_init_done=0;
++
++
++
++static ulong atoi_octal(const char *str)
++{
++ long int tmp;
++ while (*str && isspace(*str))
++ str++;
++ str2int(str,
++ (*str == '0' ? 8 : 10), /* Octalt or decimalt */
++ 0, INT_MAX, &tmp);
++ return (ulong) tmp;
++}
++
++
++ /* Init my_sys functions and my_sys variabels */
++
++void my_init(void)
++{
++ my_string str;
++ if (my_init_done)
++ return;
++ my_init_done=1;
++#ifdef THREAD
++#if defined(HAVE_PTHREAD_INIT)
++ pthread_init(); /* Must be called before DBUG_ENTER */
++#endif
++ my_thread_global_init();
++#ifndef _WIN32
++ sigfillset(&my_signals); /* signals blocked by mf_brkhant */
++#endif
++#endif /* THREAD */
++#ifdef UNIXWARE_7
++ (void) isatty(0); /* Go around connect() bug in UW7 */
++#endif
++ {
++ DBUG_ENTER("my_init");
++ DBUG_PROCESS(my_progname ? my_progname : (char*) "unknown");
++ if (!home_dir)
++ { /* Don't initialize twice */
++ if ((home_dir=getenv("HOME")) != 0)
++ home_dir=intern_filename(home_dir_buff,home_dir);
++#ifndef VMS
++ /* Default creation of new files */
++ if ((str=getenv("UMASK")) != 0)
++ my_umask=(int) (atoi_octal(str) | 0600);
++ /* Default creation of new dir's */
++ if ((str=getenv("UMASK_DIR")) != 0)
++ my_umask_dir=(int) (atoi_octal(str) | 0700);
++#endif
++#ifdef VMS
++ init_ctype(); /* Stupid linker don't link _ctype.c */
++#endif
++ DBUG_PRINT("exit",("home: '%s'",home_dir));
++ }
++#ifdef _WIN32
++ my_win_init();
++#endif
++ DBUG_VOID_RETURN;
++ }
++} /* my_init */
++
++
++ /* End my_sys */
++
++void my_end(int infoflag)
++{
++ FILE *info_file;
++ if (!(info_file=DBUG_FILE))
++ info_file=stderr;
++ if (infoflag & MY_CHECK_ERROR || info_file != stderr)
++ { /* Test if some file is left open */
++ if (my_file_opened | my_stream_opened)
++ {
++ sprintf(errbuff[0],EE(EE_OPEN_WARNING),my_file_opened,my_stream_opened);
++ (void) my_message_no_curses(EE_OPEN_WARNING,errbuff[0],ME_BELL);
++ DBUG_PRINT("error",("%s",errbuff[0]));
++ }
++ }
++ if (infoflag & MY_GIVE_INFO || info_file != stderr)
++ {
++#ifdef HAVE_GETRUSAGE
++ struct rusage rus;
++ if (!getrusage(RUSAGE_SELF, &rus))
++ fprintf(info_file,"\n\
++User time %.2f, System time %.2f\n\
++Maximum resident set size %ld, Integral resident set size %ld\n\
++Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
++Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
++Voluntary context switches %ld, Involuntary context switches %ld\n",
++ (rus.ru_utime.tv_sec * SCALE_SEC +
++ rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
++ (rus.ru_stime.tv_sec * SCALE_SEC +
++ rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
++ rus.ru_maxrss, rus.ru_idrss,
++ rus.ru_minflt, rus.ru_majflt,
++ rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
++ rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
++ rus.ru_nvcsw, rus.ru_nivcsw);
++#endif
++#if defined(MSDOS) && !defined(_WIN32)
++ fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
++#endif
++#if defined(SAFEMALLOC)
++ TERMINATE(stderr); /* Give statistic on screen */
++#elif defined(_WIN32) && defined(_MSC_VER)
++ _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
++ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
++ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
++ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
++ _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
++ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
++ _CrtCheckMemory();
++ _CrtDumpMemoryLeaks();
++#endif
++ }
++#ifdef THREAD
++ pthread_mutex_destroy(&THR_LOCK_malloc);
++ pthread_mutex_destroy(&THR_LOCK_open);
++ pthread_mutex_destroy(&THR_LOCK_net);
++ DBUG_END(); /* Must be done before my_thread_end */
++ my_thread_end();
++ my_thread_global_end();
++#endif
++#ifdef _WIN32
++ if (have_tcpip);
++ WSACleanup( );
++#endif /* _WIN32 */
++ my_init_done=0;
++} /* my_end */
++
++#ifdef _WIN32
++
++/*
++ This code is specially for running MySQL, but it should work in
++ other cases too.
++
++ Inizializzazione delle variabili d'ambiente per Win a 32 bit.
++
++ Vengono inserite nelle variabili d'ambiente (utilizzando cosi'
++ le funzioni getenv e putenv) i valori presenti nelle chiavi
++ del file di registro:
++
++ HKEY_LOCAL_MACHINE\software\MySQL
++
++ Se la kiave non esiste nonn inserisce nessun valore
++*/
++
++/* Crea la stringa d'ambiente */
++
++void setEnvString(char *ret, const char *name, const char *value)
++{
++ DBUG_ENTER("setEnvString");
++ strxmov(ret, name,"=",value,NullS);
++ DBUG_VOID_RETURN ;
++}
++
++static void my_win_init(void)
++{
++ DBUG_ENTER("my_win_init");
++ win32_init_tcp_ip();
++ DBUG_VOID_RETURN ;
++}
++
++
++/*------------------------------------------------------------------
++** Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
++** According to Microsoft Developers documentation the first registry
++** entry should be enough to check if TCP/IP is installed, but as expected
++** this doesn't work on all Win32 machines :(
++------------------------------------------------------------------*/
++
++#define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
++#define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
++#define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
++
++static my_bool win32_have_tcpip(void)
++{
++ HKEY hTcpipRegKey;
++ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
++ &hTcpipRegKey) != ERROR_SUCCESS)
++ {
++ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
++ &hTcpipRegKey) != ERROR_SUCCESS)
++ {
++ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
++ &hTcpipRegKey) != ERROR_SUCCESS)
++ if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
++ return (FALSE);
++ }
++ }
++ RegCloseKey ( hTcpipRegKey);
++ return (TRUE);
++}
++
++static my_bool win32_init_tcp_ip()
++{
++ if (win32_have_tcpip())
++ {
++ WORD wVersionRequested = MAKEWORD( 2, 0 );
++ WSADATA wsaData;
++ /* Be a good citizen: maybe another lib has already initialised
++ sockets, so dont clobber them unless necessary */
++ if (WSAStartup( wVersionRequested, &wsaData ))
++ {
++ /* Load failed, maybe because of previously loaded
++ incompatible version; try again */
++ WSACleanup( );
++ if (!WSAStartup( wVersionRequested, &wsaData ))
++ have_tcpip=1;
++ }
++ else
++ {
++ if (wsaData.wVersion != wVersionRequested)
++ {
++ /* Version is no good, try again */
++ WSACleanup( );
++ if (!WSAStartup( wVersionRequested, &wsaData ))
++ have_tcpip=1;
++ }
++ else
++ have_tcpip=1;
++ }
++ }
++ return(0);
++}
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_lib.c mariadb-native-client.trunk/libmariadb/my_lib.c
+--- mariadb/libmariadb/my_lib.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_lib.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,614 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* TODO: check for overun of memory for names. */
++/* Convert MSDOS-TIME to standar time_t */
++
++#define USES_TYPES /* sys/types is included */
++#include "mysys_priv.h"
++#include <m_string.h>
++#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
++#include "mysys_err.h"
++#if defined(HAVE_DIRENT_H)
++# include <dirent.h>
++# define NAMLEN(dirent) strlen((dirent)->d_name)
++#else
++#ifndef OS2
++# define dirent direct
++#endif
++# define NAMLEN(dirent) (dirent)->d_namlen
++# if defined(HAVE_SYS_NDIR_H)
++# include <sys/ndir.h>
++# endif
++# if defined(HAVE_SYS_DIR_H)
++# include <sys/dir.h>
++# endif
++# if defined(HAVE_NDIR_H)
++# include <ndir.h>
++# endif
++# if defined(MSDOS) || defined(_WIN32)
++# include <dos.h>
++# ifdef __BORLANDC__
++# include <dir.h>
++# endif
++# endif
++#endif
++#ifdef VMS
++#include <rms.h>
++#include <iodef.h>
++#include <descrip.h>
++#endif
++
++#ifdef OS2
++#include "my_os2dirsrch.h"
++#endif
++
++#if defined(THREAD) && defined(HAVE_READDIR_R)
++#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
++#else
++#define READDIR(A,B,C) (!(C=readdir(A)))
++#endif
++
++
++#define STARTSIZE ONCE_ALLOC_INIT*8 /* some mallocmargin */
++
++static int comp_names(struct fileinfo *a,struct fileinfo *b);
++
++
++ /* We need this because program don't know with malloc we used */
++
++void my_dirend(MY_DIR *buffer)
++{
++ DBUG_ENTER("my_dirend");
++ if (buffer)
++ my_free((gptr) buffer,MYF(0));
++ DBUG_VOID_RETURN;
++} /* my_dirend */
++
++
++ /* Compare in sort of filenames */
++
++static int comp_names(struct fileinfo *a, struct fileinfo *b)
++{
++ return (strcmp(a->name,b->name));
++} /* comp_names */
++
++
++#if !defined(MSDOS) && !defined(_WIN32)
++
++MY_DIR *my_dir(const char *path, myf MyFlags)
++{
++ DIR *dirp;
++ struct dirent *dp;
++ struct fileinfo *fnames;
++ char *buffer, *obuffer, *tempptr;
++ uint fcnt,i,size,firstfcnt, maxfcnt,length;
++ char tmp_path[FN_REFLEN+1],*tmp_file;
++ my_ptrdiff_t diff;
++ bool eof;
++#ifdef THREAD
++ char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
++#endif
++ DBUG_ENTER("my_dir");
++ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
++
++#if defined(THREAD) && !defined(HAVE_READDIR_R)
++ pthread_mutex_lock(&THR_LOCK_open);
++#endif
++
++ dirp = opendir(directory_file_name(tmp_path,(my_string) path));
++ size = STARTSIZE;
++ if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags)))
++ goto error;
++
++ fcnt = 0;
++ tmp_file=strend(tmp_path);
++ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
++ (sizeof(struct fileinfo) + FN_LEN);
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr = (char *) (fnames + maxfcnt);
++
++#ifdef THREAD
++ dp= (struct dirent*) dirent_tmp;
++#else
++ dp=0;
++#endif
++ eof=0;
++ for (;;)
++ {
++ while (fcnt < maxfcnt &&
++ !(eof= READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
++ {
++ bzero((gptr) (fnames+fcnt),sizeof(fnames[0])); /* for purify */
++ fnames[fcnt].name = tempptr;
++ tempptr = strmov(tempptr,dp->d_name) + 1;
++ if (MyFlags & MY_WANT_STAT)
++ {
++ (void)strmov(tmp_file,dp->d_name);
++ (void)my_stat(tmp_path, &fnames[fcnt].mystat, MyFlags);
++ }
++ ++fcnt;
++ }
++ if (eof)
++ break;
++ size += STARTSIZE; obuffer = buffer;
++ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
++ MyFlags | MY_FREE_ON_ERROR)))
++ goto error; /* No memory */
++ length= (uint) (sizeof(struct fileinfo ) * firstfcnt);
++ diff= PTR_BYTE_DIFF(buffer , obuffer) + (int) length;
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr= ADD_TO_PTR(tempptr,diff,char*);
++ for (i = 0; i < maxfcnt; i++)
++ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
++
++ /* move filenames upp a bit */
++ maxfcnt += firstfcnt;
++ bmove_upp(tempptr,tempptr-length,
++ (uint) (tempptr- (char*) (fnames+maxfcnt)));
++ }
++
++ (void) closedir(dirp);
++ {
++ MY_DIR * s = (MY_DIR *) buffer;
++ s->number_off_files = (uint) fcnt;
++ s->dir_entry = fnames;
++ }
++ if (!(MyFlags & MY_DONT_SORT))
++ qsort((void *) fnames, (size_s) fcnt, sizeof(struct fileinfo),
++ (qsort_cmp) comp_names);
++#if defined(THREAD) && !defined(HAVE_READDIR_R)
++ pthread_mutex_unlock(&THR_LOCK_open);
++#endif
++ DBUG_RETURN((MY_DIR *) buffer);
++
++ error:
++#if defined(THREAD) && !defined(HAVE_READDIR_R)
++ pthread_mutex_unlock(&THR_LOCK_open);
++#endif
++ my_errno=errno;
++ if (dirp)
++ (void) closedir(dirp);
++ if (MyFlags & (MY_FAE+MY_WME))
++ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
++ DBUG_RETURN((MY_DIR *) NULL);
++} /* my_dir */
++
++
++/*
++ * Convert from directory name to filename.
++ * On VMS:
++ * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
++ * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
++ * On UNIX, it's simple: just make sure there is a terminating /
++
++ * Returns pointer to dst;
++ */
++
++my_string directory_file_name (my_string dst, const char *src)
++{
++#ifndef VMS
++
++ /* Process as Unix format: just remove test the final slash. */
++
++ my_string end;
++
++ if (src[0] == 0)
++ src= (char*) "."; /* Use empty as current */
++ end=strmov(dst, src);
++ if (end[-1] != FN_LIBCHAR)
++ {
++ end[0]=FN_LIBCHAR; /* Add last '/' */
++ end[1]='\0';
++ }
++ return dst;
++
++#else /* VMS */
++
++ long slen;
++ long rlen;
++ my_string ptr, rptr;
++ char bracket;
++ struct FAB fab = cc$rms_fab;
++ struct NAM nam = cc$rms_nam;
++ char esa[NAM$C_MAXRSS];
++
++ if (! src[0])
++ src="[.]"; /* Empty is == current dir */
++
++ slen = strlen (src) - 1;
++ if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
++ src[slen] == FN_DEVCHAR)
++ {
++ /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
++ fab.fab$l_fna = src;
++ fab.fab$b_fns = slen + 1;
++ fab.fab$l_nam = &nam;
++ fab.fab$l_fop = FAB$M_NAM;
++
++ nam.nam$l_esa = esa;
++ nam.nam$b_ess = sizeof esa;
++ nam.nam$b_nop |= NAM$M_SYNCHK;
++
++ /* We call SYS$PARSE to handle such things as [--] for us. */
++ if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
++ {
++ slen = nam.nam$b_esl - 1;
++ if (esa[slen] == ';' && esa[slen - 1] == '.')
++ slen -= 2;
++ esa[slen + 1] = '\0';
++ src = esa;
++ }
++ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
++ {
++ /* what about when we have logical_name:???? */
++ if (src[slen] == FN_DEVCHAR)
++ { /* Xlate logical name and see what we get */
++ VOID(strmov(dst,src));
++ dst[slen] = 0; /* remove colon */
++ if (!(src = getenv (dst)))
++ return dst; /* Can't translate */
++
++ /* should we jump to the beginning of this procedure?
++ Good points: allows us to use logical names that xlate
++ to Unix names,
++ Bad points: can be a problem if we just translated to a device
++ name...
++ For now, I'll punt and always expect VMS names, and hope for
++ the best! */
++
++ slen = strlen (src) - 1;
++ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
++ { /* no recursion here! */
++ VOID(strmov(dst, src));
++ return(dst);
++ }
++ }
++ else
++ { /* not a directory spec */
++ VOID(strmov(dst, src));
++ return(dst);
++ }
++ }
++
++ bracket = src[slen]; /* End char */
++ if (!(ptr = strchr (src, bracket - 2)))
++ { /* no opening bracket */
++ VOID(strmov (dst, src));
++ return dst;
++ }
++ if (!(rptr = strrchr (src, '.')))
++ rptr = ptr;
++ slen = rptr - src;
++ VOID(strmake (dst, src, slen));
++
++ if (*rptr == '.')
++ { /* Put bracket and add */
++ dst[slen++] = bracket; /* (rptr+1) after this */
++ }
++ else
++ {
++ /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
++ then translate the device and recurse. */
++
++ if (dst[slen - 1] == ':'
++ && dst[slen - 2] != ':' /* skip decnet nodes */
++ && strcmp(src + slen, "[000000]") == 0)
++ {
++ dst[slen - 1] = '\0';
++ if ((ptr = getenv (dst))
++ && (rlen = strlen (ptr) - 1) > 0
++ && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
++ && ptr[rlen - 1] == '.')
++ {
++ VOID(strmov(esa,ptr));
++ esa[rlen - 1] = FN_C_AFTER_DIR;
++ esa[rlen] = '\0';
++ return (directory_file_name (dst, esa));
++ }
++ else
++ dst[slen - 1] = ':';
++ }
++ VOID(strmov(dst+slen,"[000000]"));
++ slen += 8;
++ }
++ VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
++ return dst;
++ }
++ VOID(strmov(dst, src));
++ if (dst[slen] == '/' && slen > 1)
++ dst[slen] = 0;
++ return dst;
++#endif /* VMS */
++} /* directory_file_name */
++
++#elif defined(_WIN32)
++
++/*
++*****************************************************************************
++** Read long filename using windows rutines
++*****************************************************************************
++*/
++
++MY_DIR *my_dir(const char *path, myf MyFlags)
++{
++ struct fileinfo *fnames;
++ char *buffer, *obuffer, *tempptr;
++ int eof,i,fcnt,firstfcnt,length,maxfcnt;
++ uint size;
++#ifdef __BORLANDC__
++ struct ffblk find;
++#else
++ struct _finddata_t find;
++#endif
++ ushort mode;
++ char tmp_path[FN_REFLEN],*tmp_file,attrib;
++ my_ptrdiff_t diff;
++#ifdef _WIN64
++ __int64 handle;
++#else
++ long handle;
++#endif
++ DBUG_ENTER("my_dir");
++ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
++
++ /* Put LIB-CHAR as last path-character if not there */
++
++ tmp_file=tmp_path;
++ if (!*path)
++ *tmp_file++ ='.'; /* From current dir */
++ tmp_file= strmov(tmp_file,path);
++ if (tmp_file[-1] == FN_DEVCHAR)
++ *tmp_file++= '.'; /* From current dev-dir */
++ if (tmp_file[-1] != FN_LIBCHAR)
++ *tmp_file++ =FN_LIBCHAR;
++ tmp_file[0]='*'; /* MSDOS needs this !??? */
++ tmp_file[1]='.';
++ tmp_file[2]='*';
++ tmp_file[3]='\0';
++
++#ifdef __BORLANDC__
++ if ((handle= findfirst(tmp_path,&find,0)) == -1L)
++ goto error;
++#else
++ if ((handle=_findfirst(tmp_path,&find)) == -1L)
++ goto error;
++#endif
++
++ size = STARTSIZE;
++ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
++ (sizeof(struct fileinfo) + FN_LEN);
++ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
++ goto error;
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr = (char *) (fnames + maxfcnt);
++
++ fcnt = 0;
++ for (;;)
++ {
++ do
++ {
++ fnames[fcnt].name = tempptr;
++#ifdef __BORLANDC__
++ tempptr = strmov(tempptr,find.ff_name) + 1;
++ fnames[fcnt].mystat.st_size=find.ff_fsize;
++ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
++ mode=MY_S_IREAD; attrib=find.ff_attrib;
++#else
++ tempptr = strmov(tempptr,find.name) + 1;
++ fnames[fcnt].mystat.st_size=find.size;
++ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
++ mode=MY_S_IREAD; attrib=find.attrib;
++#endif
++ if (!(attrib & _A_RDONLY))
++ mode|=MY_S_IWRITE;
++ if (attrib & _A_SUBDIR)
++ mode|=MY_S_IFDIR;
++ fnames[fcnt].mystat.st_mode=mode;
++#ifdef __BORLANDC__
++ fnames[fcnt].mystat.st_mtime=((uint32) find.ff_ftime);
++#else
++ fnames[fcnt].mystat.st_mtime=((uint32) find.time_write);
++#endif
++ ++fcnt;
++#ifdef __BORLANDC__
++ } while ((eof= findnext(&find)) == 0 && fcnt < maxfcnt);
++#else
++ } while ((eof= _findnext(handle,&find)) == 0 && fcnt < maxfcnt);
++#endif
++
++ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
++ if (eof)
++ break;
++ size += STARTSIZE; obuffer = buffer;
++ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
++ MyFlags | MY_FREE_ON_ERROR)))
++ goto error;
++ length= sizeof(struct fileinfo ) * firstfcnt;
++ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr= ADD_TO_PTR(tempptr,diff,char*);
++ for (i = 0; i < maxfcnt; i++)
++ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
++
++ /* move filenames upp a bit */
++ maxfcnt += firstfcnt;
++ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
++ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
++ }
++ {
++ MY_DIR * s = (MY_DIR *) buffer;
++ s->number_off_files = (uint) fcnt;
++ s->dir_entry = fnames;
++ }
++ if (!(MyFlags & MY_DONT_SORT))
++ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
++#ifndef __BORLANDC__
++ _findclose(handle);
++#endif
++ DBUG_RETURN((MY_DIR *) buffer);
++
++error:
++ my_errno=errno;
++#ifndef __BORLANDC__
++ if (handle != -1)
++ _findclose(handle);
++#endif
++ if (MyFlags & MY_FAE+MY_WME)
++ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
++ DBUG_RETURN((MY_DIR *) NULL);
++} /* my_dir */
++
++#else /* MSDOS and not WIN32 */
++
++
++/******************************************************************************
++** At MSDOS you always get stat of files, but time is in packed MSDOS-format
++******************************************************************************/
++
++MY_DIR *my_dir(const char* path, myf MyFlags)
++{
++ struct fileinfo *fnames;
++ char *buffer, *obuffer, *tempptr;
++ int eof,i,fcnt,firstfcnt,length,maxfcnt;
++ uint size;
++ struct find_t find;
++ ushort mode;
++ char tmp_path[FN_REFLEN],*tmp_file,attrib;
++ my_ptrdiff_t diff;
++ DBUG_ENTER("my_dir");
++ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
++
++ /* Put LIB-CHAR as last path-character if not there */
++
++ tmp_file=tmp_path;
++ if (!*path)
++ *tmp_file++ ='.'; /* From current dir */
++ tmp_file= strmov(tmp_file,path);
++ if (tmp_file[-1] == FN_DEVCHAR)
++ *tmp_file++= '.'; /* From current dev-dir */
++ if (tmp_file[-1] != FN_LIBCHAR)
++ *tmp_file++ =FN_LIBCHAR;
++ tmp_file[0]='*'; /* MSDOS needs this !??? */
++ tmp_file[1]='.';
++ tmp_file[2]='*';
++ tmp_file[3]='\0';
++
++ if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
++ goto error;
++
++ size = STARTSIZE;
++ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
++ (sizeof(struct fileinfo) + FN_LEN);
++ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
++ goto error;
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr = (char *) (fnames + maxfcnt);
++
++ fcnt = 0;
++ for (;;)
++ {
++ do
++ {
++ fnames[fcnt].name = tempptr;
++ tempptr = strmov(tempptr,find.name) + 1;
++ fnames[fcnt].mystat.st_size=find.size;
++ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
++ mode=MY_S_IREAD; attrib=find.attrib;
++ if (!(attrib & _A_RDONLY))
++ mode|=MY_S_IWRITE;
++ if (attrib & _A_SUBDIR)
++ mode|=MY_S_IFDIR;
++ fnames[fcnt].mystat.st_mode=mode;
++ fnames[fcnt].mystat.st_mtime=((uint32) find.wr_date << 16) +
++ find.wr_time;
++ ++fcnt;
++ } while ((eof= _dos_findnext(&find)) == 0 && fcnt < maxfcnt);
++
++ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
++ if (eof)
++ break;
++ size += STARTSIZE; obuffer = buffer;
++ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
++ MyFlags | MY_FREE_ON_ERROR)))
++ goto error;
++ length= sizeof(struct fileinfo ) * firstfcnt;
++ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
++ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
++ tempptr= ADD_TO_PTR(tempptr,diff,char*);
++ for (i = 0; i < maxfcnt; i++)
++ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
++
++ /* move filenames upp a bit */
++ maxfcnt += firstfcnt;
++ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
++ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
++ }
++ {
++ MY_DIR * s = (MY_DIR *) buffer;
++ s->number_off_files = (uint) fcnt;
++ s->dir_entry = fnames;
++ }
++ if (!(MyFlags & MY_DONT_SORT))
++ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
++ DBUG_RETURN((MY_DIR *) buffer);
++
++error:
++ if (MyFlags & MY_FAE+MY_WME)
++ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
++ DBUG_RETURN((MY_DIR *) NULL);
++} /* my_dir */
++
++#endif /* WIN32 && MSDOS */
++
++/****************************************************************************
++** File status
++** Note that MY_STAT is assumed to be same as struct stat
++****************************************************************************/
++
++int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags )
++{
++ DBUG_ENTER("my_fstat");
++ DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
++ DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
++}
++
++MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
++{
++ int m_used;
++ DBUG_ENTER("my_stat");
++ DBUG_PRINT("my", ("path: '%s', stat_area: %lx, MyFlags: %d", path,
+ (unsigned char *) stat_area, my_flags));
-
- if ((m_used= (stat_area == NULL)))
- if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
-
-=== modified file 'libmariadb/my_malloc.c'
---- mariadb/libmysql/my_malloc.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/my_malloc.c 2013-03-14 21:01:43 +0000
-@@ -65,11 +65,11 @@
-
- /* malloc and copy */
-
--gptr my_memdup(const byte *from, size_t length, myf MyFlags)
++
++ if ((m_used= (stat_area == NULL)))
++ if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
++ goto error;
++ if ( ! stat((my_string) path, (struct stat *) stat_area) )
++ DBUG_RETURN(stat_area);
++ my_errno=errno;
++ if (m_used) /* Free if new area */
++ my_free((gptr) stat_area,MYF(0));
++
++error:
++ if (my_flags & (MY_FAE+MY_WME))
++ {
++ my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
++ DBUG_RETURN((MY_STAT *) NULL);
++ }
++ DBUG_RETURN((MY_STAT *) NULL);
++} /* my_stat */
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_loaddata.c mariadb-native-client.trunk/libmariadb/my_loaddata.c
+--- mariadb/libmariadb/my_loaddata.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_loaddata.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,303 @@
++/************************************************************************************
++ Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
++ Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++*************************************************************************************/
++/*
++ +----------------------------------------------------------------------+
++ | PHP Version 5 |
++ +----------------------------------------------------------------------+
++ | Copyright (c) 2006-2011 The PHP Group |
++ +----------------------------------------------------------------------+
++ | This source file is subject to version 3.01 of the PHP license, |
++ | that is bundled with this package in the file LICENSE, and is |
++ | available through the world-wide-web at the following url: |
++ | http://www.php.net/license/3_01.txt |
++ | If you did not receive a copy of the PHP license and are unable to |
++ | obtain it through the world-wide-web, please send a note to |
++ | license@php.net so we can mail you a copy immediately. |
++ +----------------------------------------------------------------------+
++ | Authors: Georg Richter <georg@mysql.com> |
++ | Andrey Hristov <andrey@mysql.com> |
++ | Ulf Wendel <uwendel@mysql.com> |
++ +----------------------------------------------------------------------+
++*/
++
++#include "my_global.h"
++#include <my_sys.h>
++#include <mysys_err.h>
++#include <m_string.h>
++#include "errmsg.h"
++#include "mysql.h"
++#include <string.h>
++#ifdef _WIN32
++#include <share.h>
++#endif
++
++typedef struct st_mysql_infile_info
++{
++ int fd;
++ int error_no;
++ char error_msg[MYSQL_ERRMSG_SIZE + 1];
++ const char *filename;
++} MYSQL_INFILE_INFO;
++
++/* {{{ mysql_local_infile_init */
++static
++int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
++{
++ MYSQL_INFILE_INFO *info;
++ int CodePage= -1;
++#ifdef _WIN32
++ MYSQL *mysql= (MYSQL *)userdata;
++ wchar_t *w_filename= NULL;
++ int Length;
++#endif
++ DBUG_ENTER("mysql_local_infile_init");
++
++ info = (MYSQL_INFILE_INFO *)my_malloc(sizeof(MYSQL_INFILE_INFO), MYF(MY_ZEROFILL));
++ if (!info) {
++ DBUG_RETURN(1);
++ }
++
++ *ptr = info;
++
++ info->filename = filename;
++
++#ifdef _WIN32
++ if (mysql)
++ CodePage= madb_get_windows_cp(mysql->charset->csname);
++#endif
++ if (CodePage == -1)
++ {
++#ifdef _WIN32
++ info->fd= sopen(info->filename, _O_RDONLY | _O_BINARY, _SH_DENYNO , _S_IREAD | _S_IWRITE);
++#else
++ info->fd = open(info->filename, O_RDONLY | O_BINARY, my_umask);
++#endif
++ my_errno= errno;
++ }
++#ifdef _WIN32
++ else
++ {
++ if ((Length= MultiByteToWideChar(CodePage, 0, info->filename, (int)strlen(info->filename), NULL, 0)))
++ {
++ if (!(w_filename= (wchar_t *)my_malloc((Length + 1) * sizeof(wchar_t), MYF(MY_ZEROFILL))))
++ {
++ info->error_no= CR_OUT_OF_MEMORY;
++ my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
++ ER(CR_OUT_OF_MEMORY));
++ DBUG_RETURN(1);
++ }
++ Length= MultiByteToWideChar(CodePage, 0, info->filename, (int)strlen(info->filename), w_filename, (int)Length);
++ }
++ if (Length == 0)
++ {
++ my_free((gptr)w_filename, MYF(0));
++ info->error_no= CR_UNKNOWN_ERROR;
++ my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
++ "Character conversion error: %d", GetLastError());
++ DBUG_RETURN(1);
++ }
++ info->fd= _wsopen(w_filename, _O_RDONLY | _O_BINARY, _SH_DENYNO , _S_IREAD | _S_IWRITE);
++ my_errno= errno;
++ my_free((gptr)w_filename, MYF(0));
++ }
++#endif
++
++ if (info->fd < 0)
++ {
++ info->error_no = my_errno;
++ my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
++ EE(EE_FILENOTFOUND), filename, info->error_no);
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++/* }}} */
++
++
++/* {{{ mysql_local_infile_read */
++static
++int mysql_local_infile_read(void *ptr, char * buf, unsigned int buf_len)
++{
++ MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
++ int count;
++
++ DBUG_ENTER("mysql_local_infile_read");
++
++ count= read(info->fd, (void *)buf, (size_t)buf_len);
++
++ if (count < 0)
++ {
++ strcpy(info->error_msg, "Error reading file");
++ info->error_no = EE_READ;
++ }
++ DBUG_RETURN(count);
++}
++/* }}} */
++
++
++/* {{{ mysql_local_infile_error */
++static
++int mysql_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len)
++{
++ MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
++
++ DBUG_ENTER("mysql_local_infile_error");
++
++ if (info) {
++ strncpy(error_buf, info->error_msg, error_buf_len);
++ DBUG_RETURN(info->error_no);
++ }
++
++ strncpy(error_buf, "Unknown error", error_buf_len);
++ DBUG_RETURN(CR_UNKNOWN_ERROR);
++}
++/* }}} */
++
++
++/* {{{ mysql_local_infile_end */
++static
++void mysql_local_infile_end(void *ptr)
++{
++ MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
++
++ DBUG_ENTER("mysql_local_infile_end");
++
++ if (info)
++ {
++ if (info->fd >= 0)
++ close(info->fd);
++ my_free((gptr)ptr, MYF(0));
++ }
++ DBUG_VOID_RETURN;
++}
++/* }}} */
++
++
++/* {{{ mysql_local_infile_default */
++void mysql_set_local_infile_default(MYSQL *conn)
++{
++ DBUG_ENTER("mysql_local_infile_default");
++ conn->options.local_infile_init = mysql_local_infile_init;
++ conn->options.local_infile_read = mysql_local_infile_read;
++ conn->options.local_infile_error = mysql_local_infile_error;
++ conn->options.local_infile_end = mysql_local_infile_end;
++ DBUG_VOID_RETURN;
++}
++/* }}} */
++
++/* {{{ mysql_set_local_infile_handler */
++void STDCALL mysql_set_local_infile_handler(MYSQL *conn,
++ int (*local_infile_init)(void **, const char *, void *),
++ int (*local_infile_read)(void *, char *, uint),
++ void (*local_infile_end)(void *),
++ int (*local_infile_error)(void *, char *, uint),
++ void *userdata)
++{
++ DBUG_ENTER("mysql_set_local_infile_handler");
++ conn->options.local_infile_init= local_infile_init;
++ conn->options.local_infile_read= local_infile_read;
++ conn->options.local_infile_end= local_infile_end;
++ conn->options.local_infile_error= local_infile_error;
++ conn->options.local_infile_userdata = userdata;
++ DBUG_VOID_RETURN;
++}
++/* }}} */
++
++/* {{{ mysql_handle_local_infile */
++my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename)
++{
++ unsigned int buflen= 4096;
++ int bufread;
++ unsigned char *buf= NULL;
++ void *info= NULL;
++ my_bool result= 1;
++
++ DBUG_ENTER("mysql_handle_local_infile");
++
++ if (!(conn->options.client_flag & CLIENT_LOCAL_FILES)) {
++ my_set_error(conn, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, "Load data local infile forbidden");
++ /* write empty packet to server */
++ my_net_write(&conn->net, "", 0);
++ net_flush(&conn->net);
++ goto infile_error;
++ }
++
++ /* check if all callback functions exist */
++ if (!conn->options.local_infile_init || !conn->options.local_infile_end ||
++ !conn->options.local_infile_read || !conn->options.local_infile_error)
++ {
++ conn->options.local_infile_userdata= conn;
++ mysql_set_local_infile_default(conn);
++ }
++ /* allocate buffer for reading data */
++ buf = (uchar *)my_malloc(buflen, MYF(0));
++
++ /* init handler: allocate read buffer and open file */
++ if (conn->options.local_infile_init(&info, filename,
++ conn->options.local_infile_userdata))
++ {
++ char tmp_buf[MYSQL_ERRMSG_SIZE];
++ int tmp_errno;
++
++ tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
++ my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
++ my_net_write(&conn->net, "", 0);
++ net_flush(&conn->net);
++ goto infile_error;
++ }
++
++ /* read data */
++ while ((bufread= conn->options.local_infile_read(info, (char *)buf, buflen)) > 0)
++ {
++ if (my_net_write(&conn->net, (char *)buf, bufread))
++ {
++ my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
++ goto infile_error;
++ }
++ }
++
++ /* send empty packet for eof */
++ if (my_net_write(&conn->net, "", 0) || net_flush(&conn->net))
++ {
++ my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
++ goto infile_error;
++ }
++
++ /* error during read occured */
++ if (bufread < 0)
++ {
++ char tmp_buf[MYSQL_ERRMSG_SIZE];
++ int tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
++ my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
++ goto infile_error;
++ }
++
++ result = 0;
++
++infile_error:
++ conn->options.local_infile_end(info);
++ my_free((char *)buf, MYF(0));
++ DBUG_RETURN(result);
++}
++/* }}} */
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_malloc.c mariadb-native-client.trunk/libmariadb/my_malloc.c
+--- mariadb/libmariadb/my_malloc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_malloc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,96 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
++#undef SAFEMALLOC
++#endif
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <m_string.h>
++
++ /* My memory allocator */
++
++gptr my_malloc(size_t Size, myf MyFlags)
++{
++ gptr point;
++ DBUG_ENTER("my_malloc");
++ DBUG_PRINT("my",("Size: %u MyFlags: %d",Size, MyFlags));
++
++ if (!Size)
++ Size=1; /* Safety */
++ if ((point = (char*)malloc(Size)) == NULL)
++ {
++ my_errno=errno;
++ if (MyFlags & MY_FAE)
++ error_handler_hook=fatal_error_handler_hook;
++ if (MyFlags & (MY_FAE+MY_WME))
++ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
++ if (MyFlags & MY_FAE)
++ exit(1);
++ }
++ else if (MyFlags & MY_ZEROFILL)
++ bzero(point,Size);
++ DBUG_PRINT("exit",("ptr: %lx",point));
++ DBUG_RETURN(point);
++} /* my_malloc */
++
++
++ /* Free memory allocated with my_malloc */
++ /*ARGSUSED*/
++
++void my_no_flags_free(gptr ptr)
++{
++ DBUG_ENTER("my_free");
++ DBUG_PRINT("my",("ptr: %lx",ptr));
++ if (ptr)
++ free(ptr);
++ DBUG_VOID_RETURN;
++} /* my_free */
++
++
++ /* malloc and copy */
++
+gptr my_memdup(const unsigned char *from, size_t length, myf MyFlags)
- {
- gptr ptr;
- if ((ptr=my_malloc(length,MyFlags)) != 0)
-- memcpy((byte*) ptr, (byte*) from,(size_t) length);
++{
++ gptr ptr;
++ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
- return(ptr);
- }
-
-@@ -79,7 +79,7 @@
- gptr ptr;
- uint length=(uint) strlen(from)+1;
- if ((ptr=my_malloc(length,MyFlags)) != 0)
-- memcpy((byte*) ptr, (byte*) from,(size_t) length);
++ return(ptr);
++}
++
++
++my_string my_strdup(const char *from, myf MyFlags)
++{
++ gptr ptr;
++ uint length=(uint) strlen(from)+1;
++ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
- return((my_string) ptr);
- }
-
-
-=== modified file 'libmariadb/my_read.c'
---- mariadb/libmysql/my_read.c 2011-10-10 11:01:17 +0000
-+++ mariadb/libmariadb/my_read.c 2013-03-14 21:01:43 +0000
-@@ -22,7 +22,7 @@
-
- /* Read a chunk of bytes from a file */
-
--uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
++ return((my_string) ptr);
++}
++
++my_string my_strndup(const char *src, size_t length, myf MyFlags)
++{
++ gptr ptr;
++
++ if ((ptr= my_malloc(length+1, MyFlags))) {
++ memcpy(ptr, src, length);
++ ptr[length] = 0;
++ }
++ return ptr;
++}
++/* }}} */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_messnc.c mariadb-native-client.trunk/libmariadb/my_messnc.c
+--- mariadb/libmariadb/my_messnc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_messnc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++
++int my_message_no_curses(uint error __attribute__((unused)),
++ const char *str, myf MyFlags)
++{
++ DBUG_ENTER("my_message_no_curses");
++ DBUG_PRINT("enter",("message: %s",str));
++ (void) fflush(stdout);
++ if (MyFlags & ME_BELL)
++ (void) fputc('\007',stderr); /* Bell */
++ if (my_progname)
++ {
++ (void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
++ }
++ (void)fputs(str,stderr);
++ (void)fputc('\n',stderr);
++ (void)fflush(stderr);
++ DBUG_RETURN(0);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_net.c mariadb-native-client.trunk/libmariadb/my_net.c
+--- mariadb/libmariadb/my_net.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_net.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,44 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* thread safe version of some common functions */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++/* for thread safe my_inet_ntoa */
++#if !defined(MSDOS) && !defined(_WIN32)
++#include <netdb.h>
++#ifdef HAVE_SYS_SOCKET_H
++#include <sys/socket.h>
++#endif
++#ifdef HAVE_NETINET_IN_H
++#include <netinet/in.h>
++#endif
++#ifdef HAVE_ARPA_INET_H
++#include <arpa/inet.h>
++#endif
++#endif /* !defined(MSDOS) && !defined(_WIN32) */
++
++void my_inet_ntoa(struct in_addr in, char *buf)
++{
++ char *ptr;
++ pthread_mutex_lock(&THR_LOCK_net);
++ ptr=inet_ntoa(in);
++ strmov(buf,ptr);
++ pthread_mutex_unlock(&THR_LOCK_net);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_once.c mariadb-native-client.trunk/libmariadb/my_once.c
+--- mariadb/libmariadb/my_once.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_once.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,88 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Not MT-SAFE */
++
++#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
++#undef SAFEMALLOC
++#endif
++
++#include "mysys_priv.h"
++#include "my_static.h"
++#include "mysys_err.h"
++
++ /* alloc for things we don't nead to free */
++ /* No DBUG_ENTER... here to get smaller dbug-startup */
++
++gptr my_once_alloc(unsigned int Size, myf MyFlags)
++{
++ size_t get_size,max_left;
++ gptr point;
++ reg1 USED_MEM *next;
++ reg2 USED_MEM **prev;
++
++ Size= ALIGN_SIZE(Size);
++ prev= &my_once_root_block;
++ max_left=0;
++ for (next=my_once_root_block ; next && next->left < Size ; next= next->next)
++ {
++ if (next->left > max_left)
++ max_left=next->left;
++ prev= &next->next;
++ }
++ if (! next)
++ { /* Time to alloc new block */
++ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
++ if (max_left*4 < my_once_extra && get_size < my_once_extra)
++ get_size=my_once_extra; /* Normal alloc */
++
++ if ((next = (USED_MEM*) malloc(get_size)) == 0)
++ {
++ my_errno=errno;
++ if (MyFlags & (MY_FAE+MY_WME))
++ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
++ return((gptr) 0);
++ }
++ DBUG_PRINT("test",("my_once_malloc %u byte malloced",get_size));
++ next->next= 0;
++ next->size= get_size;
++ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
++ *prev=next;
++ }
++ point= (gptr) ((char*) next+ (next->size-next->left));
++ next->left-= Size;
++
++ return(point);
++} /* my_once_alloc */
++
++
++ /* deallocate everything used by my_once_alloc */
++
++void my_once_free(void)
++{
++ reg1 USED_MEM *next,*old;
++ DBUG_ENTER("my_once_free");
++
++ for (next=my_once_root_block ; next ; )
++ {
++ old=next; next= next->next ;
++ free((gptr) old);
++ }
++ my_once_root_block=0;
++
++ DBUG_VOID_RETURN;
++} /* my_once_free */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_open.c mariadb-native-client.trunk/libmariadb/my_open.c
+--- mariadb/libmariadb/my_open.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_open.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,126 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#define USES_TYPES
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <my_dir.h>
++#include <errno.h>
++#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
++#include <share.h>
++#endif
++
++ /* Open a file */
++
++File my_open(const char *FileName, int Flags, myf MyFlags)
++ /* Path-name of file */
++ /* Read | write .. */
++ /* Special flags */
++{
++ File fd;
++ DBUG_ENTER("my_open");
++ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
++ FileName, Flags, MyFlags));
++#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
++ if (Flags & O_SHARE)
++ fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
++ MY_S_IREAD | MY_S_IWRITE);
++ else
++ fd = open((my_string) FileName, Flags | O_BINARY,
++ MY_S_IREAD | MY_S_IWRITE);
++#elif !defined(NO_OPEN_3)
++ fd = open(FileName, Flags, my_umask); /* Normal unix */
++#else
++ fd = open((my_string) FileName, Flags);
++#endif
++ DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_OPEN,
++ EE_FILENOTFOUND, MyFlags));
++} /* my_open */
++
++
++ /* Close a file */
++
++int my_close(File fd, myf MyFlags)
++{
++ int err;
++ DBUG_ENTER("my_close");
++ DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
++
++ pthread_mutex_lock(&THR_LOCK_open);
++ if ((err = close(fd)))
++ {
++ DBUG_PRINT("error",("Got error %d on close",err));
++ my_errno=errno;
++ if (MyFlags & (MY_FAE | MY_WME))
++ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
++ }
++ if ((uint) fd < MY_NFILE && my_file_info[fd].type != UNOPEN)
++ {
++ my_free(my_file_info[fd].name, MYF(0));
++#if defined(THREAD) && !defined(HAVE_PREAD)
++ pthread_mutex_destroy(&my_file_info[fd].mutex);
++#endif
++ my_file_info[fd].type = UNOPEN;
++ }
++ my_file_opened--;
++ pthread_mutex_unlock(&THR_LOCK_open);
++ DBUG_RETURN(err);
++} /* my_close */
++
++
++File my_register_filename(File fd, const char *FileName, enum file_type
++ type_of_file, uint error_message_number, myf MyFlags)
++{
++ if ((int) fd >= 0)
++ {
++ if ((int) fd >= MY_NFILE)
++ {
++#if defined(THREAD) && !defined(HAVE_PREAD)
++ (void) my_close(fd,MyFlags);
++ my_errno=EMFILE;
++ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
++ my_error(EE_OUT_OF_FILERESOURCES, MYF(ME_BELL+ME_WAITTANG),
++ FileName, my_errno);
++ return(-1);
++#endif
++ thread_safe_increment(my_file_opened,&THR_LOCK_open);
++ return(fd); /* safeguard */
++ }
++ pthread_mutex_lock(&THR_LOCK_open);
++ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
++ {
++ my_file_opened++;
++ my_file_info[fd].type = type_of_file;
++#if defined(THREAD) && !defined(HAVE_PREAD)
++ pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
++#endif
++ pthread_mutex_unlock(&THR_LOCK_open);
++ DBUG_PRINT("exit",("fd: %d",fd));
++ return(fd);
++ }
++ pthread_mutex_unlock(&THR_LOCK_open);
++ (void) my_close(fd, MyFlags);
++ my_errno=ENOMEM;
++ }
++ else
++ my_errno=errno;
++ DBUG_PRINT("error",("Got error %d on open",my_errno));
++ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
++ my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
++ FileName, my_errno);
++ return(fd);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_port.c mariadb-native-client.trunk/libmariadb/my_port.c
+--- mariadb/libmariadb/my_port.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_port.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,40 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Small functions to make code portable
++*/
++
++#include "mysys_priv.h"
++
++#ifdef _AIX
++
++/*
++ On AIX, at least with gcc 3.1, the expression
++ '(double) (ulonglong) var' doesn't always work for big unsigned
++ integers like '18446744073709551615'. The end result is that the
++ high bit is simply dropped. (probably bug in gcc optimizations)
++ Handling the conversion in a sub function seems to work.
++*/
++
++
++
++double my_ulonglong2double(unsigned long long nr)
++{
++ return (double) nr;
++}
++#endif /* _AIX */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_pthread.c mariadb-native-client.trunk/libmariadb/my_pthread.c
+--- mariadb/libmariadb/my_pthread.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_pthread.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,555 @@
++/* Copyright (C) 2000 MySQL AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Functions to get threads more portable */
++
++#define DONT_REMAP_PTHREAD_FUNCTIONS
++
++#include "mysys_priv.h"
++#ifdef THREAD
++#include <signal.h>
++#include <m_string.h>
++#include <thr_alarm.h>
++#include <assert.h>
++
++#ifdef _WIN32
++
++int
++pthread_cond_init (pthread_cond_t *cv, const pthread_condattr_t *attr)
++{
++ DBUG_ENTER("pthread_cond_init");
++ /* Initialize the count to 0 */
++ InitializeCriticalSection(&cv->waiters_count_lock);
++ cv->waiting = 0;
++
++ /* Create an auto-reset and manual-reset event */
++ if (!(cv->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL)) ||
++ !(cv->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL)))
++ {
++ DBUG_RETURN(GetLastError());
++ }
++ DBUG_RETURN(0);
++}
++
++int pthread_cond_timedwait(pthread_cond_t *cond,
++ pthread_mutex_t *mutex,
++ struct timespec *abstime)
++{
++ int result= 0;
++ return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
++}
++
++int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
++{
++ return pthread_cond_timedwait(cv,mutex,NULL);
++}
++
++int pthread_cond_destroy(pthread_cond_t *cv)
++{
++ DeleteCriticalSection(&cv->waiters_count_lock);
++
++ if (CloseHandle(cv->events[SIGNAL]) == 0 ||
++ CloseHandle(cv->events[BROADCAST]) == 0)
++ return EINVAL;
++ return 0;
++}
++
++#endif
++
++#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
++#define SCHED_POLICY SCHED_RR
++#else
++#define SCHED_POLICY SCHED_OTHER
++#endif
++
++#ifndef my_pthread_setprio
++void my_pthread_setprio(pthread_t thread_id,int prior)
++{
++#ifdef HAVE_PTHREAD_SETSCHEDPARAM
++ struct sched_param tmp_sched_param;
++ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
++ tmp_sched_param.sched_priority=prior;
++ VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
++#endif
++}
++#endif
++
++#ifndef my_pthread_getprio
++int my_pthread_getprio(pthread_t thread_id)
++{
++#ifdef HAVE_PTHREAD_SETSCHEDPARAM
++ struct sched_param tmp_sched_param;
++ int policy;
++ if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
++ {
++ DBUG_PRINT("thread",("policy: %d priority: %d",
++ policy,tmp_sched_param.sched_priority));
++ return tmp_sched_param.sched_priority;
++ }
++#endif
++ return -1;
++}
++#endif
++
++#ifndef my_pthread_attr_setprio
++void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
++{
++#ifdef HAVE_PTHREAD_SETSCHEDPARAM
++ struct sched_param tmp_sched_param;
++ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
++ tmp_sched_param.sched_priority=priority;
++ VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
++#endif
++}
++#endif
++
++
++/* To allow use of pthread_getspecific with two arguments */
++
++#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
++#undef pthread_getspecific
++#ifdef HAVE_UNIXWARE7_THREADS
++#define pthread_getspecific thr_getspecific
++#endif
++
++void *my_pthread_getspecific_imp(pthread_key_t key)
++{
++ void *value;
++ if (pthread_getspecific(key,(void *) &value))
++ return 0;
++ return value;
++}
++#endif
++
++
++/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
++ (and DEC OSF/1 3.2 too) */
++
++int my_pthread_create_detached=1;
++
++#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
++
++int my_sigwait(const sigset_t *set,int *sig)
++{
++ int signal=sigwait((sigset_t*) set);
++ if (signal < 0)
++ return errno;
++ *sig=signal;
++ return 0;
++}
++#endif
++
++/* localtime_r for SCO 3.2V4.2 */
++
++#ifndef HAVE_LOCALTIME_R
++
++extern pthread_mutex_t LOCK_localtime_r;
++
++struct tm *localtime_r(const time_t *clock, struct tm *res)
++{
++ struct tm *tmp;
++ pthread_mutex_lock(&LOCK_localtime_r);
++ tmp=localtime(clock);
++ *res= *tmp;
++ pthread_mutex_unlock(&LOCK_localtime_r);
++ return res;
++}
++#endif
++
++
++/****************************************************************************
++** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
++**
++** Note:
++** This version of sigwait() is assumed to called in a loop so the signalmask
++** is permanently modified to reflect the signal set. This is done to get
++** a much faster implementation.
++**
++** This implementation isn't thread safe: It assumes that only one
++** thread is using sigwait.
++**
++** If one later supplies a different signal mask, all old signals that
++** was used before are unblocked and set to SIGDFL.
++**
++** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
++****************************************************************************/
++
++#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(_WIN32) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(OS2)
++
++#if !defined(DONT_USE_SIGSUSPEND)
++
++static sigset_t sigwait_set,rev_sigwait_set,px_recd;
++
++void px_handle_sig(int sig)
++{
++ sigaddset(&px_recd, sig);
++}
++
++
++void sigwait_setup(sigset_t *set)
++{
++ int i;
++ struct sigaction sact,sact1;
++ sigset_t unblock_mask;
++
++ sact.sa_flags = 0;
++ sact.sa_handler = px_handle_sig;
++ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
++ sigemptyset(&unblock_mask);
++ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
++
++ for (i = 1; i <= sizeof(sigwait_set)*8; i++)
++ {
++ if (sigismember(set,i))
++ {
++ sigdelset(&rev_sigwait_set,i);
++ if (!sigismember(&sigwait_set,i))
++ sigaction(i, &sact, (struct sigaction*) 0);
++ }
++ else
++ {
++ sigdelset(&px_recd,i); /* Don't handle this */
++ if (sigismember(&sigwait_set,i))
++ { /* Remove the old handler */
++ sigaddset(&unblock_mask,i);
++ sigdelset(&rev_sigwait_set,i);
++ sact1.sa_flags = 0;
++ sact1.sa_handler = SIG_DFL;
++ sigemptyset(&sact1.sa_mask);
++ sigaction(i, &sact1, 0);
++ }
++ }
++ }
++ memcpy_fixed(&sigwait_set,set,sizeof(*set));
++ pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
++ pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
++}
++
++
++int sigwait(sigset_t *setp, int *sigp)
++{
++ if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
++ sigwait_setup(setp); /* Init or change of set */
++
++ for (;;)
++ {
++ /*
++ This is a fast, not 100% portable implementation to find the signal.
++ Because the handler is blocked there should be at most 1 bit set, but
++ the specification on this is somewhat shady so we use a set instead a
++ single variable.
++ */
++
++ ulong *ptr= (ulong*) &px_recd;
++ ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
++
++ for ( ; ptr != end ; ptr++)
++ {
++ if (*ptr)
++ {
++ ulong set= *ptr;
++ int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
++ while (!(set & 1))
++ {
++ found++;
++ set>>=1;
++ }
++ *sigp=found;
++ sigdelset(&px_recd,found);
++ return 0;
++ }
++ }
++ sigsuspend(&rev_sigwait_set);
++ }
++ return 0;
++}
++#else /* !DONT_USE_SIGSUSPEND */
++
++/****************************************************************************
++** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
++**
++** Note:
++** This version of sigwait() is assumed to called in a loop so the signalmask
++** is permanently modified to reflect the signal set. This is done to get
++** a much faster implementation.
++**
++** This implementation uses a extra thread to handle the signals and one
++** must always call sigwait() with the same signal mask!
++**
++** BSDI 3.0 NOTE:
++**
++** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
++** After adding the sleep to sigwait_thread, all signals are checked and
++** delivered every second. This isn't that terrible performance vice, but
++** someone should report this to BSDI and ask for a fix!
++** Another problem is that when the sleep() ends, every select() in other
++** threads are interrupted!
++****************************************************************************/
++
++static sigset_t pending_set;
++static bool inited=0;
++static pthread_cond_t COND_sigwait;
++static pthread_mutex_t LOCK_sigwait;
++
++
++void sigwait_handle_sig(int sig)
++{
++ pthread_mutex_lock(&LOCK_sigwait);
++ sigaddset(&pending_set, sig);
++ VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
++ pthread_mutex_unlock(&LOCK_sigwait);
++}
++
++extern pthread_t alarm_thread;
++
++void *sigwait_thread(void *set_arg)
++{
++ sigset_t *set=(sigset_t*) set_arg;
++
++ int i;
++ struct sigaction sact;
++ sact.sa_flags = 0;
++ sact.sa_handler = sigwait_handle_sig;
++ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
++ sigemptyset(&pending_set);
++
++ for (i = 1; i <= sizeof(pending_set)*8; i++)
++ {
++ if (sigismember(set,i))
++ {
++ sigaction(i, &sact, (struct sigaction*) 0);
++ }
++ }
++ sigaddset(set,THR_CLIENT_ALARM);
++ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
++ alarm_thread=pthread_self(); /* For thr_alarm */
++
++ for (;;)
++ { /* Wait for signals */
++#ifdef HAVE_NOT_BROKEN_SELECT
++ fd_set fd;
++ FD_ZERO(&fd);
++ select(0,&fd,0,0,0);
++#else
++ sleep(1); /* Because of broken BSDI */
++#endif
++ }
++}
++
++
++int sigwait(sigset_t *setp, int *sigp)
++{
++ if (!inited)
++ {
++ pthread_attr_t thr_attr;
++ pthread_t sigwait_thread_id;
++ inited=1;
++ sigemptyset(&pending_set);
++ pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST);
++ pthread_cond_init(&COND_sigwait,NULL);
++
++ pthread_attr_init(&thr_attr);
++ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
++ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
++ pthread_attr_setstacksize(&thr_attr,8196);
++ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
++ VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
++ VOID(pthread_attr_destroy(&thr_attr));
++ }
++
++ pthread_mutex_lock(&LOCK_sigwait);
++ for (;;)
++ {
++ ulong *ptr= (ulong*) &pending_set;
++ ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
++
++ for ( ; ptr != end ; ptr++)
++ {
++ if (*ptr)
++ {
++ ulong set= *ptr;
++ int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
++ while (!(set & 1))
++ {
++ found++;
++ set>>=1;
++ }
++ *sigp=found;
++ sigdelset(&pending_set,found);
++ pthread_mutex_unlock(&LOCK_sigwait);
++ return 0;
++ }
++ }
++ VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
++ }
++ return 0;
++}
++
++#endif /* DONT_USE_SIGSUSPEND */
++#endif /* HAVE_SIGWAIT */
++
++/*****************************************************************************
++** Implement pthread_signal for systems that can't use signal() with threads
++** Currently this is only used with BSDI 3.0
++*****************************************************************************/
++
++#ifdef USE_PTHREAD_SIGNAL
++
++int pthread_signal(int sig, void (*func)())
++{
++ struct sigaction sact;
++ sact.sa_flags= 0;
++ sact.sa_handler= func;
++ sigemptyset(&sact.sa_mask);
++ sigaction(sig, &sact, (struct sigaction*) 0);
++ return 0;
++}
++#endif
++
++/****************************************************************************
++ The following functions fixes that all pthread functions should work
++ according to latest posix standard
++****************************************************************************/
++
++/* Undefined wrappers set my_pthread.h so that we call os functions */
++#undef pthread_mutex_init
++#undef pthread_mutex_lock
++#undef pthread_mutex_unlock
++#undef pthread_mutex_destroy
++#undef pthread_mutex_wait
++#undef pthread_mutex_timedwait
++#undef pthread_mutex_trylock
++#undef pthread_mutex_t
++#undef pthread_cond_init
++#undef pthread_cond_wait
++#undef pthread_cond_timedwait
++#undef pthread_cond_t
++
++
++/*****************************************************************************
++** Patches for AIX and DEC OSF/1 3.2
++*****************************************************************************/
++
++#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
++
++#include <netdb.h>
++
++int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
++{
++ int error;
++ if (!attr)
++ error=pthread_mutex_init(mp,pthread_mutexattr_default);
++ else
++ error=pthread_mutex_init(mp,*attr);
++ return error;
++}
++
++int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
++{
++ int error;
++ if (!attr)
++ error=pthread_cond_init(mp,pthread_condattr_default);
++ else
++ error=pthread_cond_init(mp,*attr);
++ return error;
++}
++
++#endif
++
++
++/*****************************************************************************
++ Patches for HPUX
++ We need these because the pthread_mutex.. code returns -1 on error,
++ instead of the error code.
++
++ Note that currently we only remap pthread_ functions used by MySQL.
++ If we are depending on the value for some other pthread_xxx functions,
++ this has to be added here.
++****************************************************************************/
++
++#if defined(HPUX) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT)
++
++int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
++ struct timespec *abstime)
++{
++ int error=pthread_cond_timedwait(cond, mutex, abstime);
++ if (error == -1) /* Safety if the lib is fixed */
++ {
++ if (!(error=errno))
++ error= ETIMEDOUT; /* Can happen on HPUX */
++ }
++ if (error == EAGAIN) /* Correct errno to Posix */
++ error= ETIMEDOUT;
++ return error;
++}
++#endif
++
++
++#ifdef HAVE_POSIX1003_4a_MUTEX
++/*
++ In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations
++ pthread_mutex_trylock returns 1 on success, not 0 like
++ pthread_mutex_lock
++
++ From the HP-UX-10.20 man page:
++ RETURN VALUES
++ If the function fails, errno may be set to one of the following
++ values:
++ Return | Error | Description
++ _______|__________|_________________________________________
++ 1 | | Successful completion.
++ 0 | | The mutex is locked; therefore, it was
++ | | not acquired.
++ -1 | [EINVAL] | The value specified by mutex is invalid.
++
++*/
++
++/*
++ Convert pthread_mutex_trylock to return values according to latest POSIX
++
++ RETURN VALUES
++ 0 If we are able successfully lock the mutex.
++ EBUSY Mutex was locked by another thread
++ # Other error number returned by pthread_mutex_trylock()
++ (Not likely)
++*/
++
++int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
++{
++ int error= pthread_mutex_trylock(mutex);
++ if (error == 1)
++ return 0; /* Got lock on mutex */
++ if (error == 0) /* Someon else is locking mutex */
++ return EBUSY;
++ if (error == -1) /* Safety if the lib is fixed */
++ error= errno; /* Probably invalid parameter */
++ return error;
++}
++#endif /* HAVE_POSIX1003_4a_MUTEX */
++
++/* Some help functions */
++
++int pthread_no_free(void *not_used __attribute__((unused)))
++{
++ return 0;
++}
++
++int pthread_dummy(int ret)
++{
++ return ret;
++}
++#endif /* THREAD */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_read.c mariadb-native-client.trunk/libmariadb/my_read.c
+--- mariadb/libmariadb/my_read.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_read.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,66 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <errno.h>
++
++
++ /* Read a chunk of bytes from a file */
++
+uint my_read(File Filedes, unsigned char *Buffer, uint Count, myf MyFlags)
- /* File descriptor */
- /* Buffer must be at least count bytes */
- /* Max number of bytes returnd */
-
-=== modified file 'libmariadb/my_static.c'
---- mariadb/libmysql/my_static.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/my_static.c 2013-03-14 21:01:43 +0000
-@@ -73,8 +73,8 @@
- size_t lCurMemory = 0L; /* Current memory usage */
- size_t lMaxMemory = 0L; /* Maximum memory usage */
- uint cNewCount = 0; /* Number of times NEW() was called */
--byte *sf_min_adress= (byte*) ~(unsigned long) 0L,
-- *sf_max_adress= (byte*) 0L;
++ /* File descriptor */
++ /* Buffer must be at least count bytes */
++ /* Max number of bytes returnd */
++ /* Flags on what to do on error */
++{
++ uint readbytes;
++ DBUG_ENTER("my_read");
++ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
++ Filedes, Buffer, Count, MyFlags));
++
++ for (;;)
++ {
++ errno=0; /* Linux doesn't reset this */
++ if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
++ {
++ my_errno=errno ? errno : -1;
++ DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
++ readbytes,Count,Filedes,my_errno));
++#ifdef THREAD
++ if (readbytes == 0 && errno == EINTR)
++ continue; /* Interrupted */
++#endif
++ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
++ {
++ if ((int) readbytes == -1)
++ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(Filedes),my_errno);
++ else if (MyFlags & (MY_NABP | MY_FNABP))
++ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(Filedes),my_errno);
++ }
++ if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
++ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
++ }
++
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ readbytes=0; /* Ok on read */
++ break;
++ }
++ DBUG_RETURN(readbytes);
++} /* my_read */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_realloc.c mariadb-native-client.trunk/libmariadb/my_realloc.c
+--- mariadb/libmariadb/my_realloc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_realloc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,65 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
++#undef SAFEMALLOC
++#endif
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++
++ /* My memory re allocator */
++
++gptr my_realloc(gptr oldpoint, size_t Size, myf MyFlags)
++{
++ gptr point;
++ DBUG_ENTER("my_realloc");
++ DBUG_PRINT("my",("ptr: %lx Size: %u MyFlags: %d",oldpoint, Size, MyFlags));
++
++ if (!oldpoint && (MyFlags & MY_ALLOW_ZERO_PTR))
++ DBUG_RETURN(my_malloc(Size,MyFlags));
++#ifdef USE_HALLOC
++ if (!(point = malloc(Size)))
++ {
++ if (MyFlags & MY_FREE_ON_ERROR)
++ my_free(oldpoint,MyFlags);
++ if (MyFlags & MY_HOLD_ON_ERROR)
++ DBUG_RETURN(oldpoint);
++ my_errno=errno;
++ if (MyFlags & MY_FAE+MY_WME)
++ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
++ }
++ else
++ {
++ memcpy(point,oldpoint,Size);
++ free(oldpoint);
++ }
++#else
++ if ((point = (char*)realloc(oldpoint,Size)) == NULL)
++ {
++ if (MyFlags & MY_FREE_ON_ERROR)
++ my_free(oldpoint,MyFLAGS);
++ if (MyFlags & MY_HOLD_ON_ERROR)
++ DBUG_RETURN(oldpoint);
++ my_errno=errno;
++ if (MyFlags & (MY_FAE+MY_WME))
++ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), Size);
++ }
++#endif
++ DBUG_PRINT("exit",("ptr: %lx",point));
++ DBUG_RETURN(point);
++} /* my_realloc */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_seek.c mariadb-native-client.trunk/libmariadb/my_seek.c
+--- mariadb/libmariadb/my_seek.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_seek.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,58 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++
++ /* Seek to position in file */
++ /*ARGSUSED*/
++
++my_off_t my_seek(File fd, my_off_t pos, int whence,
++ myf MyFlags __attribute__((unused)))
++{
++ reg1 os_off_t newpos;
++ DBUG_ENTER("my_seek");
++ DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
++ fd, ((ulonglong) pos) >> 32, (ulong) pos, whence, MyFlags));
++ newpos=lseek(fd, pos, whence);
++ if (newpos == (os_off_t) -1)
++ {
++ my_errno=errno;
++ DBUG_PRINT("error",("lseek: %lu, errno: %d",newpos,errno));
++ DBUG_RETURN(MY_FILEPOS_ERROR);
++ }
++ DBUG_RETURN((my_off_t) newpos);
++} /* my_seek */
++
++
++ /* Tell current position of file */
++ /* ARGSUSED */
++
++my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
++{
++ os_off_t pos;
++ DBUG_ENTER("my_tell");
++ DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
++#ifdef HAVE_TELL
++ pos=tell(fd);
++#else
++ pos=lseek(fd, 0L, MY_SEEK_CUR);
++#endif
++ if (pos == (os_off_t) -1)
++ my_errno=errno;
++ DBUG_PRINT("exit",("pos: %lu",pos));
++ DBUG_RETURN((my_off_t) pos);
++} /* my_tell */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_static.c mariadb-native-client.trunk/libmariadb/my_static.c
+--- mariadb/libmariadb/my_static.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_static.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,101 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Static variables for mysys library. All definied here for easy making of
++ a shared library
++*/
++
++#if !defined(stdin) || defined(OS2)
++#include "mysys_priv.h"
++#include "my_static.h"
++#include "my_alarm.h"
++#endif
++
++ /* from my_init */
++my_string home_dir=0,my_progname=0;
++char NEAR curr_dir[FN_REFLEN]= {0},
++ NEAR home_dir_buff[FN_REFLEN]= {0};
++ulong my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
++int NEAR my_umask=0664, NEAR my_umask_dir=0777;
++#ifndef THREAD
++int NEAR my_errno=0;
++#endif
++struct my_file_info my_file_info[MY_NFILE]= {{0,UNOPEN}};
++
++ /* From mf_brkhant */
++int NEAR my_dont_interrupt=0;
++volatile int _my_signals=0;
++struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
++#ifdef THREAD
++sigset_t my_signals; /* signals blocked by mf_brkhant */
++#endif
++
++ /* from mf_keycache.c */
++my_bool key_cache_inited=0;
++
++ /* from mf_reccache.c */
++ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
++
++ /* from soundex.c */
++ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
++ /* :::::::::::::::::::::::::: */
++const char *soundex_map= "01230120022455012623010202";
++
++ /* from my_malloc */
++USED_MEM* my_once_root_block=0; /* pointer to first block */
++uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
++
++ /* from my_tempnam */
++#if !defined(HAVE_TEMPNAM) || defined(HPUX11)
++int _my_tempnam_used=0;
++#endif
++
++ /* from safe_malloc */
++uint sf_malloc_prehunc=0, /* If you have problem with core- */
++ sf_malloc_endhunc=0, /* dump when malloc-message.... */
++ /* set theese to 64 or 128 */
++ sf_malloc_quick=0; /* set if no calls to sanity */
++size_t lCurMemory = 0L; /* Current memory usage */
++size_t lMaxMemory = 0L; /* Maximum memory usage */
++uint cNewCount = 0; /* Number of times NEW() was called */
+unsigned char *sf_min_adress= (unsigned char*) ~(unsigned long) 0L,
+ *sf_max_adress= (unsigned char*) 0L;
-
- /* Root of the linked list of remembers */
- struct remember *pRememberRoot = NULL;
-
-=== modified file 'libmariadb/my_static.h'
---- mariadb/libmysql/my_static.h 2011-10-10 11:01:17 +0000
-+++ mariadb/libmariadb/my_static.h 2013-03-14 21:01:43 +0000
-@@ -61,7 +61,7 @@
- extern int _my_tempnam_used;
- #endif
-
--extern byte *sf_min_adress,*sf_max_adress;
++
++/* Root of the linked list of remembers */
++struct remember *pRememberRoot = NULL;
++
++ /* from my_alarm */
++int volatile my_have_got_alarm=0; /* declare variable to reset */
++ulong my_time_to_wait_for_lock=2; /* In seconds */
++
++ /* from errors.c */
++#ifdef SHARED_LIBRARY
++char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
++#endif
++void (*my_abort_hook)(int) = (void(*)(int)) exit;
++int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
++ my_message_no_curses;
++int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
++ my_message_no_curses;
++
++ /* How to disable options */
++my_bool NEAR my_disable_locking=0;
++my_bool NEAR my_disable_async_io=0;
++my_bool NEAR my_disable_flush_key_blocks=0;
++my_bool NEAR my_disable_symlinks=0;
++my_bool NEAR mysys_uses_curses=0;
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_static.h mariadb-native-client.trunk/libmariadb/my_static.h
+--- mariadb/libmariadb/my_static.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_static.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,70 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Static variables for mysys library. All definied here for easy making of
++ a shared library
++*/
++
++#include "mysys_priv.h"
++#include <signal.h>
++
++#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
++#define MIN_KEYBLOCK (min(IO_SIZE,1024))
++#define MAX_KEYBLOCK 8192 /* Max keyblocklength == 8*IO_SIZE */
++#define MAX_BLOCK_TYPES MAX_KEYBLOCK/MIN_KEYBLOCK
++
++struct st_remember {
++ int number;
++ sig_handler (*func)(int number);
++};
++
++struct irem {
++ struct remember *_pNext; /* Linked list of structures */
++ struct remember *_pPrev; /* Other link */
++ my_string _sFileName; /* File in which memory was new'ed */
++ uint _uLineNum; /* Line number in above file */
++ uint _uDataSize; /* Size requested */
++ long _lSpecialValue; /* Underrun marker value */
++};
++
++struct remember {
++ struct irem tInt;
++ char aData[1];
++};
++
++extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN];
++
++extern volatile int _my_signals;
++extern struct st_remember _my_sig_remember[MAX_SIGNALS];
++
++extern const char *soundex_map;
++
++extern USED_MEM* my_once_root_block;
++extern uint my_once_extra;
++
++#if !defined(HAVE_TEMPNAM) || defined(HPUX11)
++extern int _my_tempnam_used;
++#endif
++
+extern unsigned char *sf_min_adress,*sf_max_adress;
- extern uint cNewCount;
- extern struct remember *pRememberRoot;
-
-
-=== modified file 'libmariadb/my_stmt.c'
---- mariadb/libmysql/my_stmt.c 2012-11-27 08:57:10 +0000
-+++ mariadb/libmariadb/my_stmt.c 2013-03-14 21:01:43 +0000
-@@ -15,6 +15,9 @@
- License along with this library; if not see <http://www.gnu.org/licenses>
- or write to the Free Software Foundation, Inc.,
- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++extern uint cNewCount;
++extern struct remember *pRememberRoot;
+
-+ Part of this code includes code from the PHP project which
-+ is freely available from http://www.php.net
- *****************************************************************************/
-
- /* The implementation for prepared statements was ported from PHP's mysqlnd
-@@ -54,13 +57,12 @@
- #include <sys/stat.h>
- #include <signal.h>
- #include <time.h>
++#if defined(THREAD) && !defined(__WIN__)
++extern sigset_t my_signals; /* signals blocked by mf_brkhant */
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_stmt.c mariadb-native-client.trunk/libmariadb/my_stmt.c
+--- mariadb/libmariadb/my_stmt.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_stmt.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,1847 @@
++/****************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++
++ Part of this code includes code from the PHP project which
++ is freely available from http://www.php.net
++ *****************************************************************************/
++
++/* The implementation for prepared statements was ported from PHP's mysqlnd
++ extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
++
++ Original file header:
++ +----------------------------------------------------------------------+
++ | PHP Version 5 |
++ +----------------------------------------------------------------------+
++ | Copyright (c) 2006-2011 The PHP Group |
++ +----------------------------------------------------------------------+
++ | This source file is subject to version 3.01 of the PHP license, |
++ | that is bundled with this package in the file LICENSE, and is |
++ | available through the world-wide-web at the following url: |
++ | http://www.php.net/license/3_01.txt |
++ | If you did not receive a copy of the PHP license and are unable to |
++ | obtain it through the world-wide-web, please send a note to |
++ | license@php.net so we can mail you a copy immediately. |
++ +----------------------------------------------------------------------+
++ | Authors: Georg Richter <georg@mysql.com> |
++ | Andrey Hristov <andrey@mysql.com> |
++ | Ulf Wendel <uwendel@mysql.com> |
++ +----------------------------------------------------------------------+
++ */
++
++#include "my_global.h"
++#include <my_sys.h>
++#include <mysys_err.h>
++#include <m_string.h>
++#include <m_ctype.h>
++#include "mysql.h"
++#include "mysql_priv.h"
++#include "mysql_version.h"
++#include "mysqld_error.h"
++#include "errmsg.h"
++#include <violite.h>
++#include <sys/stat.h>
++#include <signal.h>
++#include <time.h>
+#include <mysql/client_plugin.h>
-
- static my_bool is_not_null= 0;
- static my_bool is_null= 1;
-
--const char * const mysql_stmt_not_prepared = "Statement not prepared";
--
--my_bool is_supported_buffer_type(enum enum_field_types type)
++
++#define MADB_RESET_ERROR 1
++#define MADB_RESET_LONGDATA 2
++#define MADB_RESET_SERVER 4
++#define MADB_RESET_BUFFER 8
++#define MADB_RESET_STORED 16
++
++typedef struct
++{
++ MEM_ROOT fields_alloc_root;
++} MADB_STMT_EXTENSION;
++
++static my_bool is_not_null= 0;
++static my_bool is_null= 1;
++
+my_bool mthd_supported_buffer_type(enum enum_field_types type)
- {
- switch (type) {
- case MYSQL_TYPE_BIT:
-@@ -142,7 +144,7 @@
- return 0;
- }
-
--static int stmt_read_all_rows(MYSQL_STMT *stmt)
++{
++ switch (type) {
++ case MYSQL_TYPE_BIT:
++ case MYSQL_TYPE_BLOB:
++ case MYSQL_TYPE_DATE:
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_DECIMAL:
++ case MYSQL_TYPE_DOUBLE:
++ case MYSQL_TYPE_FLOAT:
++ case MYSQL_TYPE_GEOMETRY:
++ case MYSQL_TYPE_INT24:
++ case MYSQL_TYPE_LONG:
++ case MYSQL_TYPE_LONG_BLOB:
++ case MYSQL_TYPE_LONGLONG:
++ case MYSQL_TYPE_MEDIUM_BLOB:
++ case MYSQL_TYPE_NEWDATE:
++ case MYSQL_TYPE_NEWDECIMAL:
++ case MYSQL_TYPE_NULL:
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_STRING:
++ case MYSQL_TYPE_TIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ case MYSQL_TYPE_TINY:
++ case MYSQL_TYPE_TINY_BLOB:
++ case MYSQL_TYPE_VAR_STRING:
++ case MYSQL_TYPE_YEAR:
++ return 1;
++ break;
++ default:
++ return 0;
++ break;
++ }
++}
++
++static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags);
++
++static int stmt_unbuffered_eof(MYSQL_STMT *stmt, uchar **row)
++{
++ return MYSQL_NO_DATA;
++}
++
++static int stmt_unbuffered_fetch(MYSQL_STMT *stmt, uchar **row)
++{
++ ulong pkt_len;
++
++ DBUG_ENTER("stmt_unbuffered_fetch");
++
++ pkt_len= net_safe_read(stmt->mysql);
++ DBUG_PRINT("info",("packet_length= %ld",pkt_len));
++
++ if (pkt_len == packet_error)
++ {
++ stmt->fetch_row_func= stmt_unbuffered_eof;
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->mysql->net.read_pos[0] == 254)
++ {
++ *row = NULL;
++ stmt->fetch_row_func= stmt_unbuffered_eof;
++ DBUG_RETURN(MYSQL_NO_DATA);
++ }
++ else
++ *row = stmt->mysql->net.read_pos;
++ stmt->result.rows++;
++ DBUG_RETURN(0);
++}
++
++static int stmt_buffered_fetch(MYSQL_STMT *stmt, uchar **row)
++{
++ if (!stmt->result_cursor)
++ {
++ *row= NULL;
++ stmt->state= MYSQL_STMT_FETCH_DONE;
++ return MYSQL_NO_DATA;
++ }
++ stmt->state= MYSQL_STMT_USER_FETCHING;
++ *row= (uchar *)stmt->result_cursor->data;
++
++ stmt->result_cursor= stmt->result_cursor->next;
++ return 0;
++}
++
+int mthd_stmt_read_all_rows(MYSQL_STMT *stmt)
- {
- MYSQL_DATA *result= &stmt->result;
- MYSQL_ROWS *current, **pprevious;
-@@ -250,7 +252,7 @@
- int4store(buf, stmt->stmt_id);
- int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
-
-- if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, (char *)buf, sizeof(buf), 1))
++{
++ MYSQL_DATA *result= &stmt->result;
++ MYSQL_ROWS *current, **pprevious;
++ ulong packet_len;
++ unsigned char *p;
++
++ DBUG_ENTER("stmt_read_all_rows");
++
++ pprevious= &result->data;
++
++ while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
++ {
++ p= stmt->mysql->net.read_pos;
++ if (packet_len > 7 || p[0] != 254)
++ {
++ /* allocate space for rows */
++ if (!(current= (MYSQL_ROWS *)alloc_root(&result->alloc, sizeof(MYSQL_ROWS) + packet_len)))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ current->data= (MYSQL_ROW)(current + 1);
++ *pprevious= current;
++ pprevious= &current->next;
++
++ /* copy binary row, we will encode it during mysql_stmt_fetch */
++ memcpy((char *)current->data, (char *)p, packet_len);
++
++ if (stmt->update_max_length)
++ {
++ uchar *null_ptr, bit_offset= 4;
++ uchar *cp= p;
++ uint i;
++
++ cp++; /* skip first byte */
++ null_ptr= cp;
++ cp+= (stmt->field_count + 9) / 8;
++
++ for (i=0; i < stmt->field_count; i++)
++ {
++ if (!(*null_ptr & bit_offset))
++ {
++ switch(mysql_ps_fetch_functions[stmt->fields[i].type].max_len) {
++ case -1:
++ {
++ size_t len= net_field_length(&cp);
++ cp+= len;
++ if (len > stmt->fields[i].max_length)
++ stmt->fields[i].max_length= (ulong)len;
++ break;
++ }
++ default:
++ if (!stmt->fields[i].max_length)
++ stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len;
++ cp+= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len;
++ break;
++ }
++ }
++ if (!((bit_offset <<=1) & 255))
++ {
++ bit_offset= 1; /* To next byte */
++ null_ptr++;
++ }
++ }
++ }
++
++
++ current->length= packet_len;
++ result->rows++;
++ } else /* end of stream */
++ {
++ *pprevious= 0;
++ /* sace status info */
++ p++;
++ stmt->upsert_status.warning_count= stmt->mysql->warning_count= uint2korr(p);
++ p+=2;
++ stmt->mysql->server_status= uint2korr(p);
++ stmt->result_cursor= result->data;
++ DBUG_RETURN(0);
++ }
++ }
++ stmt->result_cursor= 0;
++ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
++ stmt->mysql->net.last_error);
++ DBUG_RETURN(1);
++}
++
++static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
++{
++ uchar buf[STMT_ID_LENGTH + 4];
++ MYSQL_DATA *result= &stmt->result;
++
++ DBUG_ENTER("stmt_cursor_fetch");
++
++ if (stmt->state < MYSQL_STMT_USE_OR_STORE_CALLED)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ /* do we have some prefetched rows available ? */
++ if (stmt->result_cursor)
++ DBUG_RETURN(stmt_buffered_fetch(stmt, row));
++
++ int4store(buf, stmt->stmt_id);
++ int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
++
+ if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, (char *)buf, sizeof(buf), 1, stmt))
- DBUG_RETURN(1);
-
- /* free previously allocated buffer */
-@@ -258,13 +260,13 @@
- result->data= 0;
- result->rows= 0;
-
-- if (stmt_read_all_rows(stmt))
++ DBUG_RETURN(1);
++
++ /* free previously allocated buffer */
++ free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
++ result->data= 0;
++ result->rows= 0;
++
+ if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
- DBUG_RETURN(1);
-
- DBUG_RETURN(stmt_buffered_fetch(stmt, row));
- }
-
--static void stmt_flush_unbuffered(MYSQL_STMT *stmt)
++ DBUG_RETURN(1);
++
++ DBUG_RETURN(stmt_buffered_fetch(stmt, row));
++}
++
+void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt)
- {
- ulong packet_len;
- while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
-@@ -272,7 +274,7 @@
- return;
- }
-
--static int stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
++{
++ ulong packet_len;
++ while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
++ if (packet_len < 8 && stmt->mysql->net.read_pos[0] == 254)
++ return;
++}
++
+int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
- {
- uint i;
- size_t truncations= 0;
-@@ -477,7 +479,7 @@
- break;
- default:
- /* unsupported parameter type */
-- SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, "");
-+ SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-@@ -637,7 +639,7 @@
-
- mem_error:
- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
-- my_free((gptr)start, MYF(ALLOW_ZERO_PTR));
++{
++ uint i;
++ size_t truncations= 0;
++ unsigned char *null_ptr, bit_offset= 4;
++
++ DBUG_ENTER("stmt_fetch_to_bind");
++
++ if (!stmt->bind_result_done) /* nothing to do */
++ DBUG_RETURN(0);
++
++ row++; /* skip status byte */
++ null_ptr= row;
++ row+= (stmt->field_count + 9) / 8;
++
++ for (i=0; i < stmt->field_count; i++)
++ {
++ /* save row position for fetching values in pieces */
++ if (*null_ptr & bit_offset)
++ {
++ *stmt->bind[i].is_null= 1;
++ stmt->bind[i].row_ptr= NULL;
++ } else
++ {
++ if (!stmt->bind[i].length)
++ stmt->bind[i].length= &stmt->bind[i].length_value;
++ if (!stmt->bind[i].is_null)
++ stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
++ *stmt->bind[i].is_null= 0;
++ stmt->bind[i].row_ptr= row;
++ mysql_ps_fetch_functions[stmt->fields[i].type].func(&stmt->bind[i], &stmt->fields[i], &row);
++ if (stmt->mysql->options.report_data_truncation)
++ truncations+= *stmt->bind[i].error;
++ }
++
++ if (!((bit_offset <<=1) & 255)) {
++ bit_offset= 1; /* To next byte */
++ null_ptr++;
++ }
++ }
++ DBUG_RETURN((truncations) ? MYSQL_DATA_TRUNCATED : 0);
++}
++
++MYSQL_RES *_mysql_stmt_use_result(MYSQL_STMT *stmt)
++{
++ MYSQL *mysql= stmt->mysql;
++
++ DBUG_ENTER("mysql_stmt_use_result");
++
++ if (!stmt->field_count ||
++ (!stmt->cursor_exists && mysql->status != MYSQL_STATUS_GET_RESULT) ||
++ (stmt->cursor_exists && mysql->status != MYSQL_STATUS_READY) ||
++ (stmt->state != MYSQL_STMT_WAITING_USE_OR_STORE))
++ {
++ SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(NULL);
++ }
++
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++
++ stmt->state = MYSQL_STMT_USE_OR_STORE_CALLED;
++ if (!stmt->cursor_exists)
++ stmt->fetch_row_func= stmt_unbuffered_fetch; //mysql_stmt_fetch_unbuffered_row;
++ else
++ stmt->fetch_row_func= stmt_cursor_fetch;
++
++ DBUG_RETURN(NULL);
++}
++
++unsigned char *mysql_net_store_length(unsigned char *packet, size_t length)
++{
++ if (length < (my_ulonglong) L64(251)) {
++ *packet = (unsigned char) length;
++ return packet + 1;
++ }
++
++ if (length < (my_ulonglong) L64(65536)) {
++ *packet++ = 252;
++ int2store(packet,(uint) length);
++ return packet + 2;
++ }
++
++ if (length < (my_ulonglong) L64(16777216)) {
++ *packet++ = 253;
++ int3store(packet,(ulong) length);
++ return packet + 3;
++ }
++ *packet++ = 254;
++ int8store(packet, length);
++ return packet + 8;
++}
++
++int store_param(MYSQL_STMT *stmt, int column, unsigned char **p)
++{
++ DBUG_ENTER("store_param");
++ DBUG_PRINT("info", ("column: %d type: x%x", column, stmt->params[column].buffer_type));
++ switch (stmt->params[column].buffer_type) {
++ case MYSQL_TYPE_TINY:
++ int1store(*p, *(uchar *)stmt->params[column].buffer);
++ (*p) += 1;
++ break;
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_YEAR:
++ int2store(*p, *(short *)stmt->params[column].buffer);
++ (*p) += 2;
++ break;
++ case MYSQL_TYPE_FLOAT:
++ float4store(*p, *(float *)stmt->params[column].buffer);
++ (*p) += 4;
++ break;
++ case MYSQL_TYPE_DOUBLE:
++ float8store(*p, *(double *)stmt->params[column].buffer);
++ (*p) += 8;
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ int8store(*p, *(my_ulonglong *)stmt->params[column].buffer);
++ (*p) += 8;
++ break;
++ case MYSQL_TYPE_LONG:
++ case MYSQL_TYPE_INT24:
++ int4store(*p, *(int32 *)stmt->params[column].buffer);
++ (*p) += 4;
++ break;
++ case MYSQL_TYPE_TIME:
++ {
++ /* binary encoding:
++ Offset Length Field
++ 0 1 Length
++ 1 1 negative
++ 2-5 4 day
++ 6 1 hour
++ 7 1 ninute
++ 8 1 second;
++ 9-13 4 second_part
++ */
++ MYSQL_TIME *t= (MYSQL_TIME *)stmt->params[column].buffer;
++ char t_buffer[14];
++ uint len= *stmt->params[column].length;
++
++ t_buffer[0]= len;
++ t_buffer[1]= t->neg ? 1 : 0;
++ int4store(t_buffer + 2, t->day);
++ t_buffer[6]= (uchar) t->hour;
++ t_buffer[7]= (uchar) t->minute;
++ t_buffer[8]= (uchar) t->second;
++ int4store(t_buffer + 9, t->second_part);
++ memcpy(*p, t_buffer, len);
++ len++;
++ (*p)+= len;
++ break;
++ }
++ case MYSQL_TYPE_DATE:
++ case MYSQL_TYPE_TIMESTAMP:
++ case MYSQL_TYPE_DATETIME:
++ {
++ /* binary format for date, timestamp and datetime
++ Offset Length Field
++ 0 1 Length
++ 1-2 2 Year
++ 3 1 Month
++ 4 1 Day
++ 5 1 Hour
++ 6 1 minute
++ 7 1 second
++ 8-11 4 secondpart
++ */
++ MYSQL_TIME *t= (MYSQL_TIME *)stmt->params[column].buffer;
++ char t_buffer[12];
++ uint len= *stmt->params[column].length;
++
++ t_buffer[0]= len;
++ int2store(t_buffer + 1, t->year);
++ t_buffer[3]= (char) t->month;
++ t_buffer[4]= (char) t->day;
++ t_buffer[5]= (char) t->hour;
++ t_buffer[6]= (char) t->minute;
++ t_buffer[7]= (char) t->second;
++ int4store(t_buffer + 8, t->second_part);
++ memcpy(*p, t_buffer, len);
++ len++;
++ (*p)+= len;
++ break;
++ }
++ case MYSQL_TYPE_TINY_BLOB:
++ case MYSQL_TYPE_MEDIUM_BLOB:
++ case MYSQL_TYPE_LONG_BLOB:
++ case MYSQL_TYPE_BLOB:
++ case MYSQL_TYPE_VARCHAR:
++ case MYSQL_TYPE_VAR_STRING:
++ case MYSQL_TYPE_STRING:
++ case MYSQL_TYPE_DECIMAL:
++ case MYSQL_TYPE_NEWDECIMAL:
++ {
++ ulong len= (ulong)*stmt->params[column].length;
++ /* to is after p. The latter hasn't been moved */
++ uchar *to = mysql_net_store_length(*p, len);
++ DBUG_PRINT("info", ("len=x%x", len));
++ if (len)
++ memcpy(to, stmt->params[column].buffer, len);
++ (*p) = to + len;
++ break;
++ }
++
++ default:
++ /* unsupported parameter type */
++ SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++/* {{{ mysqlnd_stmt_execute_generate_request */
++unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *request_len)
++{
++ /* execute packet has the following format:
++ Offset Length Description
++ -----------------------------------------
++ 0 4 Statement id
++ 4 1 Flags (cursor type)
++ 5 4 Iteration count
++ -----------------------------------------
++ if (stmt->param_count):
++ 6 (paramcount+7)/8 null bitmap
++ ------------------------------------------
++ if (stmt->send_types_to_server):
++ param_count*2 parameter types
++ ------------------------------------------
++ n data from bind_buffer
++ */
++
++ size_t length= 1024;
++ size_t free_bytes= 0;
++ size_t data_size= 0;
++ uint i;
++
++ uchar *start= NULL, *p;
++
++ DBUG_ENTER("mysql_stmt_execute_generate_request");
++
++ /* preallocate length bytes */
++ if (!(start= p= (uchar *)my_malloc(length, MYF(MY_WME | MY_ZEROFILL))))
++ goto mem_error;
++
++ int4store(p, stmt->stmt_id);
++ p += STMT_ID_LENGTH;
++
++ /* flags is 4 bytes, we store just 1 */
++ int1store(p, (unsigned char) stmt->flags);
++ p++;
++
++ int1store(p, 1); /* and send 1 for iteration count */
++ p+= 4;
++
++ if (stmt->param_count)
++ {
++ size_t null_byte_offset,
++ null_count= (stmt->param_count + 7) / 8;
++
++ free_bytes= length - (p - start);
++ if (null_count + 20 > free_bytes)
++ {
++ size_t offset= p - start;
++ length+= offset + null_count + 20;
++ if (!(start= (uchar *)my_realloc((gptr)start, length, MYF(MY_WME | MY_ZEROFILL))))
++ goto mem_error;
++ p= start + offset;
++ }
++
++ null_byte_offset = p - start;
++ memset(p, 0, null_count);
++ p += null_count;
++
++
++ int1store(p, stmt->send_types_to_server);
++ p++;
++
++ free_bytes= length - (p - start);
++
++ /* Store type information:
++ 2 bytes per type
++ */
++ if (stmt->send_types_to_server)
++ {
++ if (free_bytes < stmt->param_count * 2 + 20)
++ {
++ size_t offset= p - start;
++ length= offset + stmt->param_count * 2 + 20;
++ if (!(start= (uchar *)my_realloc((gptr)start, length, MYF(MY_WME | MY_ZEROFILL))))
++ goto mem_error;
++ p= start + offset;
++ }
++ for (i = 0; i < stmt->param_count; i++)
++ {
++ /* this differs from mysqlnd, c api supports unsinged !! */
++ uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0);
++ int2store(p, buffer_type);
++ p+= 2;
++ }
++ }
++ /* calculate data size */
++ for (i = 0; i < stmt->param_count; i++) {
++ if (stmt->params[i].buffer && !stmt->params[i].is_null)
++ stmt->params[i].is_null = &is_not_null;
++ if (!stmt->params[i].length)
++ stmt->params[i].length= &stmt->params[i].length_value;
++ if (!(stmt->params[i].is_null && *stmt->params[i].is_null) && !stmt->params[i].long_data_used)
++ {
++ switch (stmt->params[i].buffer_type) {
++ case MYSQL_TYPE_NULL:
++ stmt->params[i].is_null = &is_null;
++ break;
++ case MYSQL_TYPE_TINY_BLOB:
++ case MYSQL_TYPE_MEDIUM_BLOB:
++ case MYSQL_TYPE_LONG_BLOB:
++ case MYSQL_TYPE_BLOB:
++ case MYSQL_TYPE_VARCHAR:
++ case MYSQL_TYPE_VAR_STRING:
++ case MYSQL_TYPE_STRING:
++ case MYSQL_TYPE_DECIMAL:
++ case MYSQL_TYPE_NEWDECIMAL:
++ case MYSQL_TYPE_GEOMETRY:
++ case MYSQL_TYPE_NEWDATE:
++ case MYSQL_TYPE_ENUM:
++ case MYSQL_TYPE_BIT:
++ case MYSQL_TYPE_SET:
++ data_size+= 5; /* max 8 bytes for size */
++ data_size+= (size_t)*stmt->params[i].length;
++ break;
++ default:
++ data_size+= mysql_ps_fetch_functions[stmt->params[i].buffer_type].pack_len;
++ break;
++ }
++ }
++ }
++
++ /* store data */
++ free_bytes= length - (p - start);
++ if (free_bytes < data_size + 20)
++ {
++ size_t offset= p - start;
++ length= offset + data_size + 20;
++ if (!(start= (uchar *)my_realloc((gptr)start, length, MYF(MY_WME | MY_ZEROFILL))))
++ goto mem_error;
++ p= start + offset;
++ }
++ for (i = 0; i < stmt->param_count; i++)
++ {
++ if (stmt->params[i].long_data_used) {
++ stmt->params[i].long_data_used= 0;
++ }
++ else {
++ if (!stmt->params[i].buffer || *stmt->params[i].is_null || stmt->params[i].buffer_type == MYSQL_TYPE_NULL) {
++ (start + null_byte_offset)[i/8] |= (unsigned char) (1 << (i & 7));
++ } else {
++ DBUG_PRINT("info", ("storing parameter %d at offset %d", i, p - start));
++ store_param(stmt, i, &p);
++ }
++ }
++ }
++ }
++ stmt->send_types_to_server= 0;
++ *request_len = (p - start);
++ DBUG_RETURN(start);
++
++
++mem_error:
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+ my_free((gptr)start, MYF(MY_ALLOW_ZERO_PTR));
- *request_len= 0;
- DBUG_RETURN(NULL);
- }
-@@ -689,7 +691,7 @@
- case STMT_ATTR_CURSOR_TYPE: {
- if (*(ulong *)value > (unsigned long) CURSOR_TYPE_READ_ONLY)
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, "Not implemented");
-+ SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
- stmt->flags = *(ulong *)value;
-@@ -703,7 +705,7 @@
- break;
- }
- default:
-- SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, "Not implemented");
++ *request_len= 0;
++ DBUG_RETURN(NULL);
++}
++/* }}} */
++
++/*!
++ *******************************************************************************
++
++ \fn my_ulonglong mysql_stmt_affected_rows
++ \brief returns the number of affected rows from last mysql_stmt_execute
++ call
++
++ \param[in] stmt The statement handle
++ *******************************************************************************
++ */
++my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
++{
++ return stmt->upsert_status.affected_rows;
++}
++
++my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *value)
++{
++ DBUG_ENTER("mysql_stmt_attr_get");
++
++ switch (attr_type) {
++ case STMT_ATTR_UPDATE_MAX_LENGTH:
++ *(my_bool *)value= stmt->update_max_length;
++ break;
++ case STMT_ATTR_CURSOR_TYPE:
++ *(unsigned long *)value= stmt->flags;
++ break;
++ case STMT_ATTR_PREFETCH_ROWS:
++ *(unsigned long *)value= stmt->prefetch_rows;
++ break;
++ default:
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *value)
++{
++ DBUG_ENTER("mysql_stmt_attr_get");
++
++ switch (attr_type) {
++ case STMT_ATTR_UPDATE_MAX_LENGTH:
++ stmt->update_max_length= *(my_bool *)value;
++ break;
++ case STMT_ATTR_CURSOR_TYPE:
++ if (*(ulong *)value > (unsigned long) CURSOR_TYPE_READ_ONLY)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-@@ -714,7 +716,7 @@
- DBUG_ENTER("mysql_stmt_bind_param");
-
- if (stmt->state < MYSQL_STMT_PREPARED) {
-- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
++ DBUG_RETURN(1);
++ }
++ stmt->flags = *(ulong *)value;
++ break;
++ case STMT_ATTR_PREFETCH_ROWS:
++ if (*(ulong *)value == 0)
++ *(long *)value= MYSQL_DEFAULT_PREFETCH_ROWS;
++ else
++ stmt->prefetch_rows= *(long *)value;
++ break;
++ default:
++ SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
++{
++ DBUG_ENTER("mysql_stmt_bind_param");
++
++ if (stmt->state < MYSQL_STMT_PREPARED) {
+ SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
-@@ -727,6 +729,12 @@
-
- for (i=0; i < stmt->param_count; i++)
- {
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->param_count && bind)
++ {
++ uint i;
++
++ memcpy(stmt->params, bind, sizeof(MYSQL_BIND) * stmt->param_count);
++ stmt->send_types_to_server= 1;
++
++ for (i=0; i < stmt->param_count; i++)
++ {
+ if (stmt->mysql->methods->db_supported_buffer_type &&
+ !stmt->mysql->methods->db_supported_buffer_type(stmt->params[i].buffer_type))
+ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
+ DBUG_RETURN(1);
+ }
- if (!stmt->params[i].is_null)
- stmt->params[i].is_null= &is_not_null;
-
-@@ -794,26 +802,39 @@
-
- if (stmt->state < MYSQL_STMT_PREPARED)
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
++ if (!stmt->params[i].is_null)
++ stmt->params[i].is_null= &is_not_null;
++
++ if (stmt->params[i].long_data_used)
++ stmt->params[i].long_data_used= 0;
++
++ if (!stmt->params[i].length)
++ stmt->params[i].length= &stmt->params[i].buffer_length;
++
++ switch(stmt->params[i].buffer_type) {
++ case MYSQL_TYPE_NULL:
++ stmt->params[i].is_null= &is_null;
++ break;
++ case MYSQL_TYPE_TINY:
++ stmt->params[i].buffer_length= 1;
++ break;
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_YEAR:
++ stmt->params[i].buffer_length= 2;
++ break;
++ case MYSQL_TYPE_LONG:
++ case MYSQL_TYPE_FLOAT:
++ stmt->params[i].buffer_length= 4;
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ case MYSQL_TYPE_DOUBLE:
++ stmt->params[i].buffer_length= 8;
++ break;
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ stmt->params[i].buffer_length= 12;
++ break;
++ case MYSQL_TYPE_TIME:
++ stmt->params[i].buffer_length= 13;
++ break;
++ case MYSQL_TYPE_DATE:
++ stmt->params[i].buffer_length= 5;
++ break;
++ case MYSQL_TYPE_STRING:
++ case MYSQL_TYPE_VAR_STRING:
++ case MYSQL_TYPE_BLOB:
++ case MYSQL_TYPE_TINY_BLOB:
++ case MYSQL_TYPE_MEDIUM_BLOB:
++ case MYSQL_TYPE_LONG_BLOB:
++ case MYSQL_TYPE_DECIMAL:
++ case MYSQL_TYPE_NEWDECIMAL:
++ break;
++ default:
++ SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ break;
++ }
++ }
++ }
++ stmt->bind_param_done= stmt->send_types_to_server= 1;
++
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++ DBUG_RETURN(0);
++}
++
++my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
++{
++ uint i;
++ DBUG_ENTER("mysql_stmt_bind_result");
++
++ if (stmt->state < MYSQL_STMT_PREPARED)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
- if (!stmt->field_count)
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_NO_STMT_METADATA, SQLSTATE_UNKNOWN, "todo: metadata error");
++ DBUG_RETURN(1);
++ }
++
++ if (!stmt->field_count)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_NO_STMT_METADATA, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
- if (!bind)
- DBUG_RETURN(1);
-
++ DBUG_RETURN(1);
++ }
++
++ if (!bind)
++ DBUG_RETURN(1);
++
+ /* In case of a stored procedure we don't allocate memory for bind
+ in mysql_stmt_prepare
-+ */
++ */
++
+ if (stmt->field_count && !stmt->bind)
+ {
-+ if (!(stmt->bind= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->field_count * sizeof(MYSQL_BIND))))
++ MEM_ROOT *fields_alloc_root=
++ &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++// free_root(fields_alloc_root, MYF(0));
++ if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
+ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+ DBUG_RETURN(1);
+ }
+ }
+
- memcpy(stmt->bind, bind, sizeof(MYSQL_BIND) * stmt->field_count);
-
- for (i=0; i < stmt->field_count; i++)
- {
-- if (!is_supported_buffer_type(bind[i].buffer_type))
++ memcpy(stmt->bind, bind, sizeof(MYSQL_BIND) * stmt->field_count);
++
++ for (i=0; i < stmt->field_count; i++)
++ {
+ if (stmt->mysql->methods->db_supported_buffer_type &&
+ !stmt->mysql->methods->db_supported_buffer_type(bind[i].buffer_type))
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, "");
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
-@@ -879,13 +900,13 @@
- /* check if all data are fetched */
- if (stmt->mysql->status != MYSQL_STATUS_READY)
- {
-- stmt_flush_unbuffered(stmt);
-+ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
- stmt->mysql->status= MYSQL_STATUS_READY;
- }
- if (stmt->state > MYSQL_STMT_INITTED)
- {
- int4store(stmt_id, stmt->stmt_id);
-- if (simple_command(stmt->mysql,MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
++ DBUG_RETURN(1);
++ }
++
++ if (!stmt->bind[i].is_null)
++ stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
++ if (!stmt->bind[i].length)
++ stmt->bind[i].length= &stmt->bind[i].length_value;
++ if (!stmt->bind[i].error)
++ stmt->bind[i].error= &stmt->bind[i].error_value;
++
++ /* set length values for numeric types */
++ switch(bind[i].buffer_type) {
++ case MYSQL_TYPE_NULL:
++ *stmt->bind[i].length= stmt->bind[i].length_value= 0;
++ break;
++ case MYSQL_TYPE_TINY:
++ *stmt->bind[i].length= stmt->bind[i].length_value= 1;
++ break;
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_YEAR:
++ *stmt->bind[i].length= stmt->bind[i].length_value= 2;
++ break;
++ case MYSQL_TYPE_INT24:
++ case MYSQL_TYPE_LONG:
++ case MYSQL_TYPE_FLOAT:
++ *stmt->bind[i].length= stmt->bind[i].length_value= 4;
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ case MYSQL_TYPE_DOUBLE:
++ *stmt->bind[i].length= stmt->bind[i].length_value= 8;
++ break;
++ case MYSQL_TYPE_TIME:
++ case MYSQL_TYPE_DATE:
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ *stmt->bind[i].length= stmt->bind[i].length_value= sizeof(MYSQL_TIME);
++ break;
++ default:
++ break;
++ }
++ }
++ stmt->bind_result_done= 1;
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++
++ DBUG_RETURN(0);
++}
++
++my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
++{
++ char stmt_id[STMT_ID_LENGTH];
++ MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++
++ /* clear memory */
++ free_root(&stmt->result.alloc, MYF(0)); /* allocated in mysql_stmt_store_result */
++ free_root(&stmt->mem_root,MYF(0));
++ free_root(fields_alloc_root, MYF(0));
++
++ if (stmt->mysql)
++ {
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++
++ /* remove from stmt list */
++ if (remove)
++ stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list);
++
++ /* check if all data are fetched */
++ if (stmt->mysql->status != MYSQL_STATUS_READY)
++ {
++ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ }
++ if (stmt->state > MYSQL_STMT_INITTED)
++ {
++ int4store(stmt_id, stmt->stmt_id);
+ if (simple_command(stmt->mysql,MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
- {
- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, stmt->mysql->net.last_error);
- return 1;
-@@ -931,6 +952,11 @@
- return (const char *)stmt->last_error;
- }
-
++ {
++ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, stmt->mysql->net.last_error);
++ return 1;
++ }
++ }
++ }
++ return 0;
++}
++
++my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
++{
++ DBUG_ENTER("mysql_stmt_close");
++
++ if (stmt && stmt->mysql && stmt->mysql->net.vio)
++ mysql_stmt_reset(stmt);
++ net_stmt_close(stmt, 1);
++
++ my_free((char *)stmt->extension, MYF(MY_ALLOW_ZERO_PTR));
++ my_free((char *)stmt, MYF(MY_WME));
++
++ DBUG_RETURN(0);
++}
++
++void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset)
++{
++ my_ulonglong i= offset;
++ MYSQL_ROWS *ptr= stmt->result.data;
++ DBUG_ENTER("mysql_stmt_data_seek");
++
++ DBUG_PRINT("info", ("total rows: %llu offset: %llu", stmt->result.rows, offset));
++
++ while(i-- && ptr)
++ ptr= ptr->next;
++
++ stmt->result_cursor= ptr;
++ stmt->state= MYSQL_STMT_USER_FETCHING;
++
++ DBUG_VOID_RETURN;
++}
++
++unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT *stmt)
++{
++ return stmt->last_errno;
++}
++
++const char * STDCALL mysql_stmt_error(MYSQL_STMT *stmt)
++{
++ return (const char *)stmt->last_error;
++}
++
+int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row)
+{
+ return stmt->fetch_row_func(stmt, row);
+}
+
- int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
- {
- unsigned char *row;
-@@ -940,6 +966,7 @@
-
- if (stmt->state <= MYSQL_STMT_EXECUTED)
- {
++int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
++{
++ unsigned char *row;
++ int rc;
++
++ DBUG_ENTER("mysql_stmt_fetch");
++
++ if (stmt->state <= MYSQL_STMT_EXECUTED)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
-@@ -953,11 +980,9 @@
- }
-
- if (stmt->state == MYSQL_STMT_FETCH_DONE)
-- {
- DBUG_RETURN(MYSQL_NO_DATA);
-- }
--
-- if ((rc= stmt->fetch_row_func(stmt, &row)))
-+
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->state < MYSQL_STMT_WAITING_USE_OR_STORE || !stmt->field_count)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ } else if (stmt->state== MYSQL_STMT_WAITING_USE_OR_STORE)
++ {
++ stmt->default_rset_handler(stmt);
++ }
++
++ if (stmt->state == MYSQL_STMT_FETCH_DONE)
++ DBUG_RETURN(MYSQL_NO_DATA);
++
+ if ((rc= stmt->mysql->methods->db_stmt_fetch(stmt, &row)))
- {
- stmt->state= MYSQL_STMT_FETCH_DONE;
- stmt->mysql->status= MYSQL_STATUS_READY;
-@@ -965,10 +990,11 @@
- DBUG_RETURN(MYSQL_NO_DATA);
- }
-
-- if ((rc= stmt_fetch_to_bind(stmt, row)))
++ {
++ stmt->state= MYSQL_STMT_FETCH_DONE;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ /* to fetch data again, stmt must be executed again */
++ DBUG_RETURN(rc);
++ }
++
+ if ((rc= stmt->mysql->methods->db_stmt_fetch_to_bind(stmt, row)))
- {
- DBUG_RETURN(rc);
-- }
++ {
++ DBUG_RETURN(rc);
++ }
++
++ stmt->state= MYSQL_STMT_USER_FETCHING;
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++ DBUG_RETURN(0);
++}
++
++int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset)
++{
++ DBUG_ENTER("mysql_stmt_fetch");
++
++ if (stmt->state < MYSQL_STMT_USER_FETCHING || column >= stmt->field_count ||
++ stmt->state == MYSQL_STMT_FETCH_DONE) {
++ SET_CLIENT_STMT_ERROR(stmt, CR_NO_DATA, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (!stmt->bind[column].row_ptr)
++ {
++ /* we set row_ptr only for columns which contain data, so this must be a NULL column */
++ if (bind[0].is_null)
++ *bind[0].is_null= 1;
++ }
++ else
++ {
++ unsigned char *save_ptr;
++ if (bind[0].length)
++ *bind[0].length= stmt->bind[column].length_value;
++ else
++ *bind[0].length= *stmt->bind[column].length;
++ if (bind[0].is_null)
++ *bind[0].is_null= 0;
++ else
++ bind[0].is_null= &bind[0].is_null_value;
++ if (!bind[0].error)
++ bind[0].error= &bind[0].error_value;
++ *bind[0].error= 0;
++ bind[0].offset= offset;
++ save_ptr= stmt->bind[column].row_ptr;
++ mysql_ps_fetch_functions[stmt->fields[column].type].func(&bind[0], &stmt->fields[column], &stmt->bind[column].row_ptr);
++ stmt->bind[column].row_ptr= save_ptr;
++ }
++ DBUG_RETURN(0);
++}
++
++unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
++{
++ return stmt->field_count;
++}
++
++my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
++{
++ return madb_reset_stmt(stmt, MADB_RESET_LONGDATA | MADB_RESET_STORED |
++ MADB_RESET_BUFFER | MADB_RESET_ERROR);
++}
++
++MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql)
++{
++
++ MYSQL_STMT *stmt;
++ DBUG_ENTER("mysql_stmt_init");
++
++ if (!(stmt= (MYSQL_STMT *)my_malloc(sizeof(MYSQL_STMT), MYF(MY_WME | MY_ZEROFILL))) ||
++ !(stmt->extension= (MADB_STMT_EXTENSION *)my_malloc(sizeof(MADB_STMT_EXTENSION),
++ MYF(MY_WME | MY_ZEROFILL))))
++ {
++ my_free((gptr)stmt, MYF(MY_ALLOW_ZERO_PTR));
++ SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(NULL);
+ }
+
- stmt->state= MYSQL_STMT_USER_FETCHING;
- CLEAR_CLIENT_ERROR(stmt->mysql);
- CLEAR_CLIENT_STMT_ERROR(stmt);
-@@ -1052,7 +1078,7 @@
- DBUG_RETURN(stmt);
- }
-
--my_bool stmt_read_prepare_response(MYSQL_STMT *stmt)
++
++ /* fill mysql's stmt list */
++ stmt->list.data= stmt;
++ stmt->mysql= mysql;
++ mysql->stmts= list_add(mysql->stmts, &stmt->list);
++
++
++ /* clear flags */
++ strcpy(stmt->sqlstate, "00000");
++
++ stmt->state= MYSQL_STMT_INITTED;
++
++ /* set default */
++ stmt->prefetch_rows= 1;
++
++ init_alloc_root(&stmt->mem_root, 2048, 0);
++ init_alloc_root(&stmt->result.alloc, 4096, 0);
++ init_alloc_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root, 2048, 0);
++
++ DBUG_RETURN(stmt);
++}
++
+my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt)
- {
- ulong packet_length;
- uchar *p;
-@@ -1085,25 +1111,25 @@
- DBUG_RETURN(0);
- }
-
--my_bool stmt_get_param_metadata(MYSQL_STMT *stmt)
++{
++ ulong packet_length;
++ uchar *p;
++
++ DBUG_ENTER("read_prepare_response");
++
++ if ((packet_length= net_safe_read(stmt->mysql)) == packet_error)
++ DBUG_RETURN(1);
++
++ DBUG_PRINT("info",("packet_length= %ld",packet_length));
++
++ p= (uchar *)stmt->mysql->net.read_pos;
++
++ if (0xFF == p[0]) /* Error occured */
++ {
++ DBUG_RETURN(1);
++ }
++
++ p++;
++ stmt->stmt_id= uint4korr(p);
++ p+= 4;
++ stmt->field_count= uint2korr(p);
++ p+= 2;
++ stmt->param_count= uint2korr(p);
++
++ /* filler */
++ p++;
++ stmt->upsert_status.warning_count= uint2korr(p);
++
++ DBUG_RETURN(0);
++}
++
+my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt)
- {
- MYSQL_DATA *result;
-
- DBUG_ENTER("stmt_get_param_metadata");
-
-- if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
++{
++ MYSQL_DATA *result;
++
++ DBUG_ENTER("stmt_get_param_metadata");
++
+ if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
- DBUG_RETURN(1);
-
- free_rows(result);
- DBUG_RETURN(0);
- }
-
--my_bool stmt_read_result_metadata(MYSQL_STMT *stmt)
++ DBUG_RETURN(1);
++
++ free_rows(result);
++ DBUG_RETURN(0);
++}
++
+my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt)
- {
- MYSQL_DATA *result;
- DBUG_ENTER("stmt_read_result_metadata");
-
-- if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
++{
++ MYSQL_DATA *result;
++ MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++ DBUG_ENTER("stmt_read_result_metadata");
++
+ if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
- DBUG_RETURN(1);
- if (!(stmt->fields= unpack_fields(result,&stmt->mem_root,
- stmt->field_count, 0,
-@@ -1143,28 +1169,30 @@
- stmt->field_count= 0;
-
- int4store(stmt_id, stmt->stmt_id);
-- if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
++ DBUG_RETURN(1);
++ if (!(stmt->fields= unpack_fields(result,fields_alloc_root,
++ stmt->field_count, 0,
++ stmt->mysql->server_capabilities & CLIENT_LONG_FLAG)))
++ DBUG_RETURN(1);
++ DBUG_RETURN(0);
++}
++
++int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
++{
++ int rc= 1;
++ DBUG_ENTER("mysql_stmt_prepare");
++
++ if (!stmt->mysql)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ /* clear flags */
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++ stmt->upsert_status.affected_rows= stmt->mysql->affected_rows= (my_ulonglong) ~0;
++
++ /* check if we have to clear results */
++ if (stmt->state > MYSQL_STMT_INITTED)
++ {
++ /* We need to semi-close the prepared statement:
++ reset stmt and free all buffers and close the statement
++ on server side. Statment handle will get a new stmt_id */
++ char stmt_id[STMT_ID_LENGTH];
++
++ mysql_stmt_reset(stmt);
++
++ free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
++ free_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root, MYF(0));
++
++ stmt->param_count= 0;
++ stmt->field_count= 0;
++
++ int4store(stmt_id, stmt->stmt_id);
+ if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
- goto fail;
- }
--
-- if (simple_command(stmt->mysql,MYSQL_COM_STMT_PREPARE, query, length, 1))
++ goto fail;
++ }
+ if (simple_command(stmt->mysql, MYSQL_COM_STMT_PREPARE, query, length, 1, stmt))
- goto fail;
-
-- if (stmt_read_prepare_response(stmt))
++ goto fail;
++
+ if (stmt->mysql->methods->db_read_prepare_response &&
+ stmt->mysql->methods->db_read_prepare_response(stmt))
- goto fail;
-
- /* metadata not supported yet */
-- if (stmt->param_count && stmt_get_param_metadata(stmt))
-- {
-- goto fail;
-- }
--
-- if (stmt->field_count && stmt_read_result_metadata(stmt))
-- {
-- goto fail;
-- }
--
-+
++ goto fail;
++
++ /* metadata not supported yet */
++
+ if (stmt->param_count &&
+ stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
+ {
+ goto fail;
+ }
-+
- /* allocated bind buffer for parameters */
++
++ /* allocated bind buffer for parameters */
+ if (stmt->field_count &&
+ stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
+ {
+ goto fail;
+ }
- if (stmt->param_count)
- {
- if (!(stmt->params= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
-@@ -1223,7 +1251,7 @@
- int4store(buff, stmt->stmt_id);
- int4store(buff + STMT_ID_LENGTH, (int)~0);
-
-- if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, buff, sizeof(buff), 1))
++ if (stmt->param_count)
++ {
++ if (!(stmt->params= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ goto fail;
++ }
++ memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
++ }
++ /* allocated bind buffer for result */
++ if (stmt->field_count)
++ {
++ MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++ if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ goto fail;
++ }
++ }
++ stmt->state = MYSQL_STMT_PREPARED;
++ DBUG_RETURN(0);
++
++fail:
++ stmt->state= MYSQL_STMT_INITTED;
++ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
++ stmt->mysql->net.last_error);
++ DBUG_RETURN(rc);
++}
++
++int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
++{
++ unsigned int last_server_status;
++ DBUG_ENTER("mysql_stmt_store_result");
++
++ if (!stmt->mysql)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (!stmt->field_count)
++ DBUG_RETURN(0);
++
++ /* test_pure_coverage requires checking of error_no */
++ if (stmt->last_errno)
++ DBUG_RETURN(1);
++
++ if (stmt->state < MYSQL_STMT_EXECUTED)
++ {
++ SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ last_server_status= stmt->mysql->server_status;
++
++ /* if stmt is a cursor, we need to tell server to send all rows */
++ if (stmt->cursor_exists && stmt->mysql->status == MYSQL_STATUS_READY)
++ {
++ char buff[STMT_ID_LENGTH + 4];
++ int4store(buff, stmt->stmt_id);
++ int4store(buff + STMT_ID_LENGTH, (int)~0);
++
+ if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, buff, sizeof(buff), 1, stmt))
- DBUG_RETURN(1);
- /* todo: cursor */
- }
-@@ -1234,7 +1262,7 @@
- DBUG_RETURN(1);
- }
-
-- if (stmt_read_all_rows(stmt))
++ DBUG_RETURN(1);
++ /* todo: cursor */
++ }
++ else if (stmt->mysql->status != MYSQL_STATUS_GET_RESULT)
++ {
++ SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
+ if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
- {
- /* error during read - reset stmt->data */
- free_root(&stmt->result.alloc, 0);
-@@ -1279,8 +1307,7 @@
-
- if (stmt->param_count && !stmt->bind_param_done)
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN,
-- "No data supplied for parameters in prepared statement");
++ {
++ /* error during read - reset stmt->data */
++ free_root(&stmt->result.alloc, 0);
++ stmt->result.data= NULL;
++ stmt->result.rows= 0;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ DBUG_RETURN(1);
++ }
++
++ /* workaround for MDEV 6304:
++ more results not set if the resultset has
++ SERVER_PS_OUT_PARAMS set
++ */
++ if (last_server_status & SERVER_PS_OUT_PARAMS &&
++ !(stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST))
++ stmt->mysql->server_status|= SERVER_MORE_RESULTS_EXIST;
++
++ stmt->result_cursor= stmt->result.data;
++ stmt->fetch_row_func= stmt_buffered_fetch;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ stmt->state= MYSQL_STMT_USE_OR_STORE_CALLED;
++
++ /* set affected rows: see bug 2247 */
++ stmt->upsert_status.affected_rows= stmt->result.rows;
++ stmt->mysql->affected_rows= stmt->result.rows;
++
++ DBUG_RETURN(0);
++}
++
++static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
++{
++ uint i;
++ MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++
++ DBUG_ENTER("madb_alloc_stmt_fields");
++
++ if (stmt->mysql->field_count)
++ {
++ free_root(fields_alloc_root, MYF(0));
++ if (!(stmt->fields= (MYSQL_FIELD *)alloc_root(fields_alloc_root,
++ sizeof(MYSQL_FIELD) * stmt->mysql->field_count)))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ stmt->field_count= stmt->mysql->field_count;
++
++ for (i=0; i < stmt->field_count; i++)
++ {
++ if (stmt->mysql->fields[i].db)
++ stmt->fields[i].db= strdup_root(fields_alloc_root, stmt->mysql->fields[i].db);
++ if (stmt->mysql->fields[i].table)
++ stmt->fields[i].table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].table);
++ if (stmt->mysql->fields[i].org_table)
++ stmt->fields[i].org_table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_table);
++ if (stmt->mysql->fields[i].name)
++ stmt->fields[i].name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].name);
++ if (stmt->mysql->fields[i].org_name)
++ stmt->fields[i].org_name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_name);
++ if (stmt->mysql->fields[i].catalog)
++ stmt->fields[i].catalog= strdup_root(fields_alloc_root, stmt->mysql->fields[i].catalog);
++ stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(fields_alloc_root, stmt->mysql->fields[i].def) : NULL;
++ stmt->fields[i].type= stmt->mysql->fields[i].type;
++ stmt->fields[i].length= stmt->mysql->fields[i].length;
++ stmt->fields[i].flags= stmt->mysql->fields[i].flags;
++ stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
++ stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
++ stmt->fields[i].max_length= stmt->mysql->fields[i].max_length;
++ }
++ if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ bzero(stmt->bind, stmt->field_count * sizeof(MYSQL_BIND));
++ stmt->bind_result_done= 0;
++ }
++ DBUG_RETURN(0);
++}
++
++
++int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
++{
++ char *request;
++ int ret;
++ size_t request_len= 0;
++
++
++ DBUG_ENTER("mysql_stmt_execute");
++
++ if (!stmt->mysql)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->state < MYSQL_STMT_PREPARED)
++ {
++ SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->param_count && !stmt->bind_param_done)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
-@@ -1291,7 +1318,7 @@
- }
- if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
- {
-- stmt_flush_unbuffered(stmt);
-+ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
- stmt->state= MYSQL_STMT_PREPARED;
- stmt->mysql->status= MYSQL_STATUS_READY;
- }
-@@ -1303,12 +1330,11 @@
- stmt->result_cursor= stmt->result.data= 0;
- stmt->result.rows= 0;
- }
--
- request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
- DBUG_PRINT("info",("request_len=%ld", request_len));
-
-- ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1) ||
-- mysql_read_query_result(stmt->mysql));
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
++ {
++ stmt->default_rset_handler = _mysql_stmt_use_result;
++ stmt->default_rset_handler(stmt);
++ }
++ if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
++ {
++ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
++ stmt->state= MYSQL_STMT_PREPARED;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ }
++
++ /* clear data, in case mysql_stmt_store_result was called */
++ if (stmt->result.data)
++ {
++ free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
++ stmt->result_cursor= stmt->result.data= 0;
++ stmt->result.rows= 0;
++ }
++ request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
++ DBUG_PRINT("info",("request_len=%ld", request_len));
++
+ ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1, stmt) ||
-+ (stmt->mysql->methods->db_read_stmt_result && stmt->mysql->methods->db_read_stmt_result(stmt->mysql)));
-
- if (request)
- my_free(request, MYF(0));
-@@ -1354,12 +1380,19 @@
-
- for (i=0; i < stmt->field_count; i++)
- {
-- stmt->fields[i].db= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].db);
-- stmt->fields[i].table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].table);
-- stmt->fields[i].org_table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_table);
-- stmt->fields[i].name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].name);
-- stmt->fields[i].org_name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_name);
-- stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(&stmt->mem_root, stmt->mysql->fields[i].def) : NULL;
++ (stmt->mysql && stmt->mysql->methods->db_read_stmt_result && stmt->mysql->methods->db_read_stmt_result(stmt->mysql)));
++ if (request)
++ my_free(request, MYF(0));
++
++ /* if a reconnect occured, our connection handle is invalid */
++ if (!stmt->mysql)
++ DBUG_RETURN(1);
++
++ /* update affected rows, also if an error occured */
++ stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
++
++ if (ret)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
++ stmt->mysql->net.last_error);
++ stmt->state= MYSQL_STMT_PREPARED;
++ DBUG_RETURN(1);
++ }
++ stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
++ stmt->upsert_status.server_status= stmt->mysql->server_status;
++ stmt->upsert_status.warning_count= stmt->mysql->warning_count;
++
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++
++ stmt->execute_count++;
++ stmt->send_types_to_server= 0;
++
++ stmt->state= MYSQL_STMT_EXECUTED;
++
++ if (stmt->mysql->field_count)
++ {
++ if (!stmt->field_count ||
++ stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST) /* fix for ps_bug: test_misc */
++ {
++ MEM_ROOT *fields_alloc_root=
++ &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
++ uint i;
++
++ free_root(fields_alloc_root, MYF(0));
++ if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root,
++ sizeof(MYSQL_BIND) * stmt->mysql->field_count)) ||
++ !(stmt->fields= (MYSQL_FIELD *)alloc_root(fields_alloc_root,
++ sizeof(MYSQL_FIELD) * stmt->mysql->field_count)))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ stmt->field_count= stmt->mysql->field_count;
++
++ for (i=0; i < stmt->field_count; i++)
++ {
+ if (stmt->mysql->fields[i].db)
-+ stmt->fields[i].db= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].db);
++ stmt->fields[i].db= strdup_root(fields_alloc_root, stmt->mysql->fields[i].db);
+ if (stmt->mysql->fields[i].table)
-+ stmt->fields[i].table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].table);
++ stmt->fields[i].table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].table);
+ if (stmt->mysql->fields[i].org_table)
-+ stmt->fields[i].org_table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_table);
++ stmt->fields[i].org_table= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_table);
+ if (stmt->mysql->fields[i].name)
-+ stmt->fields[i].name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].name);
++ stmt->fields[i].name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].name);
+ if (stmt->mysql->fields[i].org_name)
-+ stmt->fields[i].org_name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_name);
++ stmt->fields[i].org_name= strdup_root(fields_alloc_root, stmt->mysql->fields[i].org_name);
+ if (stmt->mysql->fields[i].catalog)
-+ stmt->fields[i].catalog= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].catalog);
-+ stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(&stmt->mem_root, stmt->mysql->fields[i].def) : NULL;
- }
- }
-
-@@ -1441,7 +1474,7 @@
-
- if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count)
- {
-- stmt_flush_unbuffered(stmt);
-+ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
- stmt->mysql->status= MYSQL_STATUS_READY;
- }
-
-@@ -1449,7 +1482,7 @@
- if (stmt->mysql->status == MYSQL_STATUS_READY)
- {
- int4store(cmd_buf, stmt->stmt_id);
-- if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0)))
-+ if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt)))
- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
- stmt->mysql->net.last_error);
-
-@@ -1529,7 +1562,7 @@
-
- if (stmt->state < MYSQL_STMT_PREPARED || !stmt->params)
- {
-- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
++ stmt->fields[i].catalog= strdup_root(fields_alloc_root, stmt->mysql->fields[i].catalog);
++ stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(fields_alloc_root, stmt->mysql->fields[i].def) : NULL;
++ }
++ }
++
++ if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS)
++ {
++ stmt->cursor_exists = TRUE;
++ stmt->mysql->status = MYSQL_STATUS_READY;
++
++ /* Only cursor read */
++ stmt->default_rset_handler = _mysql_stmt_use_result;
++
++ } else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
++ {
++ /*
++ We have asked for CURSOR but got no cursor, because the condition
++ above is not fulfilled. Then...
++ This is a single-row result set, a result set with no rows, EXPLAIN,
++ SHOW VARIABLES, or some other command which either a) bypasses the
++ cursors framework in the server and writes rows directly to the
++ network or b) is more efficient if all (few) result set rows are
++ precached on client and server's resources are freed.
++ */
++
++ /* preferred is buffered read */
++ mysql_stmt_store_result(stmt);
++ } else
++ {
++ /* preferred is unbuffered read */
++ stmt->default_rset_handler = _mysql_stmt_use_result;
++ }
++ stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE;
++ /* in certain cases parameter types can change: For example see bug
++ 4026 (SELECT ?), so we need to update field information */
++ if (stmt->mysql->field_count == stmt->field_count)
++ {
++ uint i;
++ for (i=0; i < stmt->field_count; i++)
++ {
++ stmt->fields[i].type= stmt->mysql->fields[i].type;
++ stmt->fields[i].length= stmt->mysql->fields[i].length;
++ stmt->fields[i].flags= stmt->mysql->fields[i].flags;
++ stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
++ stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
++ stmt->fields[i].max_length= stmt->mysql->fields[i].max_length;
++ }
++ } else
++ {
++ /* table was altered, see test_wl4166_2 */
++ SET_CLIENT_STMT_ERROR(stmt, CR_NEW_STMT_METADATA, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++ }
++ DBUG_RETURN(0);
++}
++
++static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
++{
++ my_bool ret= 0;
++
++ DBUG_ENTER("madb_stmt_reset");
++ if (!stmt->mysql)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ /* clear error */
++ if (flags & MADB_RESET_ERROR)
++ {
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++ }
++
++ if (stmt->stmt_id)
++ {
++ /* free buffered resultset, previously allocated
++ * by mysql_stmt_store_result
++ */
++ if (flags & MADB_RESET_STORED &&
++ stmt->result_cursor)
++ {
++ free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
++ stmt->result.data= NULL;
++ stmt->result.rows= 0;
++ stmt->result_cursor= NULL;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ }
++
++ /* if there is a pending result set, we will flush it */
++ if (flags & MADB_RESET_BUFFER)
++ {
++ if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
++ {
++ stmt->default_rset_handler(stmt);
++ stmt->state = MYSQL_STMT_USER_FETCHING;
++ }
++
++ if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count)
++ {
++ stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ }
++ }
++
++
++ if (flags & MADB_RESET_SERVER)
++ {
++ /* reset statement on server side */
++ if (stmt->mysql->status == MYSQL_STATUS_READY)
++ {
++ unsigned char cmd_buf[STMT_ID_LENGTH];
++ int4store(cmd_buf, stmt->stmt_id);
++ if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt)))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
++ stmt->mysql->net.last_error);
++ DBUG_RETURN(ret);
++ }
++ }
++ }
++
++ if (flags & MADB_RESET_LONGDATA)
++ {
++ if (stmt->params)
++ {
++ ulonglong i;
++ for (i=0; i < stmt->param_count; i++)
++ if (stmt->params[i].long_data_used)
++ stmt->params[i].long_data_used= 0;
++ }
++ }
++
++ }
++ DBUG_RETURN(ret);
++}
++
++my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
++{
++ my_bool ret= 1;
++ unsigned int flags= MADB_RESET_LONGDATA | MADB_RESET_BUFFER | MADB_RESET_ERROR;
++
++ DBUG_ENTER("mysql_stmt_reset");
++
++ if (stmt->state >= MYSQL_STMT_USER_FETCHING &&
++ stmt->fetch_row_func == stmt_unbuffered_fetch)
++ flags|= MADB_RESET_BUFFER;
++
++ ret= madb_reset_stmt(stmt, flags);
++
++ if (stmt->stmt_id)
++ {
++ if ((stmt->state > MYSQL_STMT_EXECUTED &&
++ stmt->mysql->status != MYSQL_STATUS_READY) ||
++ stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST)
++ {
++ /* flush any pending (multiple) result sets */
++ if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
++ {
++ stmt->default_rset_handler(stmt);
++ stmt->state = MYSQL_STMT_USER_FETCHING;
++ }
++
++ if (stmt->field_count)
++ {
++ while (mysql_stmt_next_result(stmt) == 0);
++ stmt->mysql->status= MYSQL_STATUS_READY;
++ }
++ }
++ ret= madb_reset_stmt(stmt, MADB_RESET_SERVER);
++ }
++ stmt->state= MYSQL_STMT_PREPARED;
++ stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
++ stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
++ stmt->upsert_status.server_status= stmt->mysql->server_status;
++ stmt->upsert_status.warning_count= stmt->mysql->warning_count;
++ stmt->mysql->status= MYSQL_STATUS_READY;
++
++ DBUG_RETURN(ret);
++}
++
++MYSQL_RES * STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt)
++{
++ MYSQL_RES *res;
++
++ DBUG_ENTER("mysql_stmt_result_metadata");
++
++ if (!stmt->field_count)
++ DBUG_RETURN(NULL);
++
++ /* aloocate result set structutr and copy stmt information */
++ if (!(res= (MYSQL_RES *)my_malloc(sizeof(MYSQL_RES), MYF(MY_WME | MY_ZEROFILL))))
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(NULL);
++ }
++
++ res->eof= 1;
++ res->fields= stmt->fields;
++ res->field_count= stmt->field_count;
++ DBUG_RETURN(res);}
++
++const char * STDCALL mysql_stmt_sqlstate(MYSQL_STMT *stmt)
++{
++ return stmt->sqlstate;
++}
++
++MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt)
++{
++ DBUG_ENTER("mysql_stmt_row_tell");
++ DBUG_RETURN(stmt->result_cursor);
++}
++
++unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT *stmt)
++{
++ return stmt->param_count;
++}
++
++MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET new_row)
++{
++ MYSQL_ROW_OFFSET old_row; /* for returning old position */
++ DBUG_ENTER("mysql_stmt_row_seek");
++
++ old_row= stmt->result_cursor;
++ stmt->result_cursor= new_row;
++
++ DBUG_RETURN(old_row);
++}
++
++my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
++ const char *data, ulong length)
++{
++ DBUG_ENTER("mysql_stmt_send_long_data");
++
++ CLEAR_CLIENT_ERROR(stmt->mysql);
++ CLEAR_CLIENT_STMT_ERROR(stmt);
++
++ if (stmt->state < MYSQL_STMT_PREPARED || !stmt->params)
++ {
+ SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
- DBUG_RETURN(1);
- }
-
-@@ -1548,7 +1581,7 @@
- int2store(cmd_buff + STMT_ID_LENGTH, param_number);
- memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
- stmt->params[param_number].long_data_used= 1;
-- ret= simple_command(stmt->mysql,MYSQL_COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1);
++ DBUG_RETURN(1);
++ }
++
++ if (param_number >= stmt->param_count)
++ {
++ SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
++ DBUG_RETURN(1);
++ }
++
++ if (stmt->mysql->status== MYSQL_STATUS_READY && (length || !stmt->params[param_number].long_data_used))
++ {
++ int ret;
++ size_t packet_len;
++ uchar *cmd_buff= (uchar *)my_malloc(packet_len= STMT_ID_LENGTH + 2 + length, MYF(MY_WME | MY_ZEROFILL));
++ int4store(cmd_buff, stmt->stmt_id);
++ int2store(cmd_buff + STMT_ID_LENGTH, param_number);
++ memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
++ stmt->params[param_number].long_data_used= 1;
+ ret= simple_command(stmt->mysql,MYSQL_COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1, stmt);
- my_free((gptr)cmd_buff, MYF(MY_WME));
- DBUG_RETURN(ret);
- }
-@@ -1565,3 +1598,51 @@
- return stmt->result.rows;
- }
-
++ my_free((gptr)cmd_buff, MYF(MY_WME));
++ DBUG_RETURN(ret);
++ }
++ DBUG_RETURN(1);
++}
++
++my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
++{
++ return stmt->upsert_status.last_insert_id;
++}
++
++my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
++{
++ return stmt->result.rows;
++}
++
+MYSQL_RES* STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt)
+{
+ DBUG_ENTER("mysql_stmt_param_metadata");
+ /* server doesn't deliver any information yet,
+ so we just return NULL
-+ */
++ */
+ DBUG_RETURN(NULL);
+}
+
++my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt)
++{
++ /* MDEV 4604: Server doesn't set MORE_RESULT flag for
++ OutParam result set, so we need to check
++ for SERVER_MORE_RESULTS_EXIST and for
++ SERVER_PS_OUT_PARAMS)
++ */
++ return (stmt &&
++ stmt->mysql &&
++ ((stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST) ||
++ (stmt->mysql->server_status & SERVER_PS_OUT_PARAMS)));
++}
++
+int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
+{
++ int rc= 0;
+ DBUG_ENTER("mysql_stmt_next_result");
+
+ if (!stmt->mysql)
@@ -4472,124 +28238,2594 @@
+ DBUG_RETURN(1);
+ }
+
-+ if (!mysql_more_results(stmt->mysql))
++ if (!mysql_stmt_more_results(stmt))
+ DBUG_RETURN(-1);
+
-+ mysql_stmt_reset(stmt);
++ if (stmt->state > MYSQL_STMT_EXECUTED &&
++ stmt->state < MYSQL_STMT_FETCH_DONE)
++ madb_reset_stmt(stmt, MADB_RESET_ERROR | MADB_RESET_BUFFER | MADB_RESET_LONGDATA);
+ stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE;
+
+ if (mysql_next_result(stmt->mysql))
+ {
+ SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
-+ stmt->mysql->net.last_error);
++ stmt->mysql->net.last_error);
+ DBUG_RETURN(1);
+ }
+
-+ if (stmt->field_count != stmt->mysql->field_count)
++ if (stmt->mysql->field_count)
++ rc= madb_alloc_stmt_fields(stmt);
++ else
+ {
-+ if (stmt->bind)
-+ stmt->bind= NULL;
-+ stmt->field_count= stmt->mysql->field_count;
++ stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
++ stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
++ stmt->upsert_status.server_status= stmt->mysql->server_status;
++ stmt->upsert_status.warning_count= stmt->mysql->warning_count;
+ }
+
-+ DBUG_RETURN(0);
++ stmt->field_count= stmt->mysql->field_count;
++
++ DBUG_RETURN(rc);
+}
-
-=== modified file 'libmariadb/my_stmt_codec.c'
---- mariadb/libmysql/my_stmt_codec.c 2012-11-27 08:57:10 +0000
-+++ mariadb/libmariadb/my_stmt_codec.c 2013-03-14 21:01:43 +0000
-@@ -15,6 +15,9 @@
- License along with this library; if not see <http://www.gnu.org/licenses>
- or write to the Free Software Foundation, Inc.,
- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_stmt_codec.c mariadb-native-client.trunk/libmariadb/my_stmt_codec.c
+--- mariadb/libmariadb/my_stmt_codec.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_stmt_codec.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,949 @@
++/****************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+
+ Part of this code includes code from the PHP project which
+ is freely available from http://www.php.net
- *****************************************************************************/
-
- /* The implementation for prepared statements was ported from PHP's mysqlnd
-@@ -75,7 +78,7 @@
-
- #define YY_PART_YEAR 70
-
--struct st_mysql_perm_bind mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
++*****************************************************************************/
++
++/* The implementation for prepared statements was ported from PHP's mysqlnd
++ extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
++
++ Original file header:
++ +----------------------------------------------------------------------+
++ | PHP Version 5 |
++ +----------------------------------------------------------------------+
++ | Copyright (c) 2006-2011 The PHP Group |
++ +----------------------------------------------------------------------+
++ | This source file is subject to version 3.01 of the PHP license, |
++ | that is bundled with this package in the file LICENSE, and is |
++ | available through the world-wide-web at the following url: |
++ | http://www.php.net/license/3_01.txt |
++ | If you did not receive a copy of the PHP license and are unable to |
++ | obtain it through the world-wide-web, please send a note to |
++ | license@php.net so we can mail you a copy immediately. |
++ +----------------------------------------------------------------------+
++ | Authors: Georg Richter <georg@mysql.com> |
++ | Andrey Hristov <andrey@mysql.com> |
++ | Ulf Wendel <uwendel@mysql.com> |
++ +----------------------------------------------------------------------+
++*/
++
++#include "my_global.h"
++#include <my_sys.h>
++#include <mysys_err.h>
++#include <m_string.h>
++#include <m_ctype.h>
++#include "mysql.h"
++
++#define MYSQL_SILENT
++
++/* ranges for C-binding */
++#define UINT_MAX32 0xFFFFFFFFL
++#define UINT_MAX24 0x00FFFFFF
++#define UINT_MAX16 0xFFFF
++#ifndef INT_MIN8
++#define INT_MIN8 (~0x7F)
++#define INT_MAX8 0x7F
++#endif
++#define UINT_MAX8 0xFF
++
++#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN)
++#define LONGLONG_MIN ((long long) 0x8000000000000000LL)
++#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
++#endif
++
++#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)
++/* First check for ANSI C99 definition: */
++#ifdef ULLONG_MAX
++#define ULONGLONG_MAX ULLONG_MAX
++#else
++#define ULONGLONG_MAX ((unsigned long long)(~0ULL))
++#endif
++#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/
++
++#define YY_PART_YEAR 70
++
+MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
- my_bool mysql_ps_subsystem_initialized= 0;
-
-
-@@ -571,7 +574,6 @@
-
- length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length);
-
-- /* TODO: move this to a header shared between client and server. */
- if (field->decimals >= NOT_FIXED_DEC)
- {
- sprintf(buff, "%-*.*g", (int) length-1, DBL_DIG, val);
-
-=== modified file 'libmariadb/my_write.c'
---- mariadb/libmysql/my_write.c 2011-10-10 11:01:17 +0000
-+++ mariadb/libmariadb/my_write.c 2013-03-14 21:01:43 +0000
-@@ -22,7 +22,7 @@
-
- /* Write a chunk of bytes to a file */
-
--uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
++my_bool mysql_ps_subsystem_initialized= 0;
++
++
++#define NUMERIC_TRUNCATION(val,min_range, max_range)\
++ ((((val) > (max_range)) || ((val) < (min_range)) ? 1 : 0))
++
++
++/* {{{ ps_fetch_from_1_to_8_bytes */
++void ps_fetch_from_1_to_8_bytes(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
++ unsigned char **row, unsigned int byte_count)
++{
++ my_bool is_unsigned= test(field->flags & UNSIGNED_FLAG);
++ r_param->buffer_length= byte_count;
++ switch (byte_count) {
++ case 1:
++ *(uchar *)r_param->buffer= **row;
++ *r_param->error= is_unsigned != r_param->is_unsigned && *(uchar *)r_param->buffer > INT_MAX8;
++ break;
++ case 2:
++ shortstore(r_param->buffer, ((ushort) sint2korr(*row)));
++ *r_param->error= is_unsigned != r_param->is_unsigned && *(ushort *)r_param->buffer > INT_MAX16;
++ break;
++ case 4:
++ {
++ longstore(r_param->buffer, ((uint32)sint4korr(*row)));
++ *r_param->error= is_unsigned != r_param->is_unsigned && *(uint32 *)r_param->buffer > INT_MAX32;
++ }
++ break;
++ case 8:
++ {
++ ulonglong val= (ulonglong)sint8korr(*row);
++ longlongstore(r_param->buffer, val);
++ *r_param->error= is_unsigned != r_param->is_unsigned && val > LONGLONG_MAX ;
++ }
++ break;
++ default:
++ r_param->buffer_length= 0;
++ break;
++ }
++ (*row)+= byte_count;
++}
++/* }}} */
++
++static longlong my_atoll(const char *number, const char *end, int *error)
++{
++ char buffer[255];
++ longlong llval= 0;
++ size_t i;
++ /* set error at the following conditions:
++ - string contains invalid character(s)
++ - length > 254
++ - strtoll returns invalid range
++ */
++
++ memcpy(buffer, number, MIN((uint)(end - number), 254));
++ buffer[(uint)(end - number)]= 0;
++
++ llval= strtoll(buffer, NULL, 10);
++
++ /* check size */
++ if ((uint)(end - number) > 254)
++ {
++ *error= 1;
++ return llval;
++ }
++
++ /* check characters */
++ for (i=0; i < strlen(buffer); i++)
++ {
++ if (buffer[i] < '0' || buffer[i] > '9')
++ {
++ *error= 1;
++ return llval;
++ }
++ }
++
++ /* check strtoll result */
++ if (errno == ERANGE)
++ *error= errno;
++ return llval;
++}
++
++double my_atod(const char *number, const char *end, int *error)
++{
++ double val= 0.0;
++ char buffer[255];
++ int len= (int)(end - number);
++
++ if (len > 254)
++ *error= 1;
++
++ len= MIN(len, 254);
++ memcpy(&buffer, number, len);
++ buffer[len]= '\0';
++
++ val= strtod(buffer, NULL);
++/* if (!*error)
++ *error= errno; */
++ return val;
++}
++
++my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
++{
++ my_bool is_time=0, is_date=0, has_time_frac=0;
++ char *p= (char *)str;
++
++ if ((p= strchr(str, '-')) && p <= str + length)
++ is_date= 1;
++ if ((p= strchr(str, ':')) && p <= str + length)
++ is_time= 1;
++ if ((p= strchr(str, '.')) && p <= str + length)
++ has_time_frac= 1;
++
++ p= (char *)str;
++
++ memset(tm, 0, sizeof(MYSQL_TIME));
++
++ if (is_date)
++ {
++ sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day);
++ p= strchr(str, ' ');
++ if (!p)
++ {
++ tm->time_type= MYSQL_TIMESTAMP_DATE;
++ return 0;
++ }
++ }
++ if (has_time_frac)
++ {
++ sscanf(p, "%d:%d:%d.%ld", &tm->hour, &tm->minute, &tm->second, &tm->second_part);
++ tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
++ return 0;
++ }
++ if (is_time)
++ {
++ sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second);
++ tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
++ return 0;
++ }
++ return 1;
++}
++
++
++static void convert_from_string(MYSQL_BIND *r_param, char *buffer, size_t len)
++{
++ int error= 0;
++ switch (r_param->buffer_type)
++ {
++ case MYSQL_TYPE_TINY:
++ {
++ longlong val= my_atoll(buffer, buffer + len, &error);
++ *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0;
++ int1store(r_param->buffer, (uchar) val);
++ r_param->buffer_length= sizeof(uchar);
++ }
++ break;
++ case MYSQL_TYPE_YEAR:
++ case MYSQL_TYPE_SHORT:
++ {
++ longlong val= my_atoll(buffer, buffer + len, &error);
++ *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0;
++ shortstore(r_param->buffer, (short)val);
++ r_param->buffer_length= sizeof(short);
++ }
++ break;
++ case MYSQL_TYPE_LONG:
++ {
++ longlong val= my_atoll(buffer, buffer + len, &error);
++ *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0;
++ longstore(r_param->buffer, (int32)val);
++ r_param->buffer_length= sizeof(uint32);
++ }
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ {
++ longlong val= my_atoll(buffer, buffer + len, &error);
++ *r_param->error= error > 0; /* no need to check for truncation */
++ longlongstore(r_param->buffer, val);
++ r_param->buffer_length= sizeof(longlong);
++ }
++ break;
++ case MYSQL_TYPE_DOUBLE:
++ {
++ double val= my_atod(buffer, buffer + len, &error);
++ *r_param->error= error > 0; /* no need to check for truncation */
++ float8store(r_param->buffer, val);
++ r_param->buffer_length= sizeof(double);
++ }
++ break;
++ case MYSQL_TYPE_FLOAT:
++ {
++ float val= (float)my_atod(buffer, buffer + len, &error);
++ *r_param->error= error > 0; /* no need to check for truncation */
++ float4store(r_param->buffer, val);
++ r_param->buffer_length= sizeof(float);
++ }
++ break;
++ case MYSQL_TYPE_TIME:
++ case MYSQL_TYPE_DATE:
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ {
++ MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer;
++ str_to_TIME(buffer, len, tm);
++ break;
++ }
++ break;
++ case MYSQL_TYPE_TINY_BLOB:
++ case MYSQL_TYPE_MEDIUM_BLOB:
++ case MYSQL_TYPE_LONG_BLOB:
++ case MYSQL_TYPE_BLOB:
++ case MYSQL_TYPE_DECIMAL:
++ case MYSQL_TYPE_NEWDECIMAL:
++ default:
++ {
++ char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */
++ char *end= buffer + len;
++ size_t copylen= 0;
++
++ if (start < end)
++ {
++ copylen= end - start;
++ if (r_param->buffer_length)
++ memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length));
++ }
++ if (copylen < r_param->buffer_length)
++ ((char *)r_param->buffer)[copylen]= '\0';
++ *r_param->error= (copylen > r_param->buffer_length);
++
++ *r_param->length= (ulong)len;
++ }
++ break;
++ }
++}
++
++static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, longlong val, my_bool is_unsigned)
++{
++ switch (r_param->buffer_type) {
++ case MYSQL_TYPE_TINY:
++ *(uchar *)r_param->buffer= (uchar)val;
++ *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8);
++ r_param->buffer_length= 1;
++ break;
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_YEAR:
++ shortstore(r_param->buffer, (short)val);
++ *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16);
++ r_param->buffer_length= 2;
++ break;
++ case MYSQL_TYPE_LONG:
++ longstore(r_param->buffer, (int32)val);
++ *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32);
++ r_param->buffer_length= 4;
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ *r_param->error= (val < 0 && r_param->is_unsigned != is_unsigned);
++ longlongstore(r_param->buffer, val);
++ r_param->buffer_length= 8;
++ break;
++ case MYSQL_TYPE_DOUBLE:
++ {
++ volatile double dbl;
++
++ dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val;
++ doublestore(r_param->buffer, dbl);
++ *r_param->error= is_unsigned ? (ulonglong )dbl != (ulonglong)val : (longlong)dbl != (longlong)val;
++ r_param->buffer_length= 8;
++ break;
++ }
++ case MYSQL_TYPE_FLOAT:
++ {
++ float fval;
++ fval= is_unsigned ? (float)(ulonglong)(val) : (float)val;
++ float4store(r_param->buffer, fval);
++ *r_param->error= is_unsigned ? (ulonglong)fval != (ulonglong)val : (longlong)fval != val;
++ r_param->buffer_length= 4;
++ }
++ break;
++ default:
++ {
++ char buffer[22];
++ char *endptr;
++ uint len;
++
++ endptr= longlong10_to_str(val, buffer, is_unsigned ? 10 : -10);
++ len= (uint)(endptr - buffer);
++
++ /* check if field flag is zerofill */
++
++ convert_from_string(r_param, buffer, len);
++ }
++ break;
++ }
++}
++
++
++/* {{{ ps_fetch_null */
++static
++void ps_fetch_null(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row)
++{
++ /* do nothing */
++}
++/* }}} */
++
++#define GET_LVALUE_FROM_ROW(is_unsigned, data, ucast, scast)\
++ (is_unsigned) ? (longlong)(ucast) *(longlong *)(data) : (longlong)(scast) *(longlong *)(data)
++/* {{{ ps_fetch_int8 */
++static
++void ps_fetch_int8(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
++ unsigned char **row)
++{
++ switch(r_param->buffer_type) {
++ case MYSQL_TYPE_TINY:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
++ break;
++ default:
++ {
++ uchar val= **row;
++ longlong lval= field->flags & UNSIGNED_FLAG ? (longlong) val : (longlong)(signed char)val;
++ convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
++ (*row) += 1;
++ }
++ break;
++ }
++}
++/* }}} */
++
++
++/* {{{ ps_fetch_int16 */
++static
++void ps_fetch_int16(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
++ unsigned char **row)
++{
++ switch (r_param->buffer_type) {
++ case MYSQL_TYPE_YEAR:
++ case MYSQL_TYPE_SHORT:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
++ break;
++ default:
++ {
++ short sval= sint2korr(*row);
++ longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ushort) sval : (longlong)sval;
++ convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
++ (*row) += 2;
++ }
++ break;
++ }
++}
++/* }}} */
++
++
++/* {{{ ps_fetch_int32 */
++static
++void ps_fetch_int32(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
++ unsigned char **row)
++{
++ switch (r_param->buffer_type) {
++/* case MYSQL_TYPE_TINY:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
++ break;
++ case MYSQL_TYPE_YEAR:
++ case MYSQL_TYPE_SHORT:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
++ break; */
++ case MYSQL_TYPE_INT24:
++ case MYSQL_TYPE_LONG:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
++ break;
++ default:
++ {
++ int32 sval= sint4korr(*row);
++ longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(uint32) sval : (longlong)sval;
++ convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
++ (*row) += 4;
++ }
++ break;
++ }
++}
++/* }}} */
++
++
++/* {{{ ps_fetch_int64 */
++static
++void ps_fetch_int64(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
++ unsigned char **row)
++{
++ switch(r_param->buffer_type)
++ {
++/* case MYSQL_TYPE_TINY:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
++ break;
++ case MYSQL_TYPE_YEAR:
++ case MYSQL_TYPE_SHORT:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
++ break;
++ case MYSQL_TYPE_INT24:
++ case MYSQL_TYPE_LONG:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
++ break; */
++ case MYSQL_TYPE_LONGLONG:
++ ps_fetch_from_1_to_8_bytes(r_param, field, row, 8);
++ break;
++ default:
++ {
++ longlong sval= (longlong)sint8korr(*row);
++ longlong lval= field->flags & UNSIGNED_FLAG ? (ulonglong) sval : (longlong)sval;
++ convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
++ (*row) += 8;
++ }
++ break;
++ }
++}
++/* }}} */
++
++static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size)
++{
++ double check_trunc_val= (val > 0) ? floor(val) : -floor(-val);
++ char *buf= (char *)r_param->buffer;
++ switch (r_param->buffer_type)
++ {
++ case MYSQL_TYPE_TINY:
++ *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val;
++ *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) :
++ (double)((int8)*buf));
++ r_param->buffer_length= 1;
++ break;
++ case MYSQL_TYPE_SHORT:
++ case MYSQL_TYPE_YEAR:
++ {
++ if (r_param->is_unsigned)
++ {
++ ushort sval= (ushort)val;
++ shortstore(buf, sval);
++ *r_param->error= check_trunc_val != (double)sval;
++ } else {
++ short sval= (short)val;
++ shortstore(buf, sval);
++ *r_param->error= check_trunc_val != (double)sval;
++ }
++ r_param->buffer_length= 2;
++ }
++ break;
++ case MYSQL_TYPE_LONG:
++ {
++ if (r_param->is_unsigned)
++ {
++ uint32 lval= (uint32)val;
++ longstore(buf, lval);
++ *r_param->error= (check_trunc_val != (double)lval);
++ } else {
++ int32 lval= (int32)val;
++ longstore(buf, lval);
++ *r_param->error= (check_trunc_val != (double)lval);
++ }
++ r_param->buffer_length= 4;
++ }
++ break;
++ case MYSQL_TYPE_LONGLONG:
++ {
++ if (r_param->is_unsigned)
++ {
++ ulonglong llval= (ulonglong)val;
++ longlongstore(buf, llval);
++ *r_param->error= (check_trunc_val != (double)llval);
++ } else {
++ longlong llval= (longlong)val;
++ longlongstore(buf, llval);
++ *r_param->error= (check_trunc_val != (double)llval);
++ }
++ r_param->buffer_length= 8;
++ }
++ break;
++ case MYSQL_TYPE_FLOAT:
++ {
++ float fval= (float)val;
++ memcpy(buf, &fval, sizeof(float));
++ *r_param->error= (*(float*)buf != fval);
++ r_param->buffer_length= 4;
++ }
++ break;
++ case MYSQL_TYPE_DOUBLE:
++ {
++ memcpy(buf, &val, sizeof(double));
++ r_param->buffer_length= 8;
++ }
++ break;
++ default:
++ {
++ #define MAX_DOUBLE_STRING_REP_LENGTH 300
++ char buff[MAX_DOUBLE_STRING_REP_LENGTH];
++ char *end;
++ size_t length;
++
++ length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length);
++
++ if (field->decimals >= NOT_FIXED_DEC)
++ {
++ sprintf(buff, "%-*.*g", (int) length-1, DBL_DIG, val);
++ length= strlen(buff);
++ }
++ else
++ {
++ sprintf(buff, "%.*f", field->decimals, val);
++ length= strlen(buff);
++ }
++
++ /* remove possible trailing blanks */
++ if ((end= strcend(buff, ' ')))
++ *end= 0;
++
++ /* check if ZEROFILL flag is active */
++ if (field->flags & ZEROFILL_FLAG)
++ {
++ /* enough space available ? */
++ if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1)
++ break;
++ bmove_upp(buff + field->length, buff + length, length);
++ bfill((char*) buff, field->length - length, '0');
++ }
++ convert_from_string(r_param, buff, strlen(buff));
++ }
++ break;
++ }
++}
++
++
++/* {{{ ps_fetch_float */
++static
++void ps_fetch_float(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row)
++{
++ switch(r_param->buffer_type)
++ {
++ case MYSQL_TYPE_FLOAT:
++ {
++ float *value= (float *)r_param->buffer;
++ float4get(*value, *row);
++ r_param->buffer_length= 4;
++ *r_param->error= 0;
++ }
++ break;
++ default:
++ {
++ float value;
++ memcpy(&value, *row, sizeof(float));
++ float4get(value, (char *)*row);
++ convert_from_float(r_param, field, value, sizeof(float));
++ }
++ break;
++ }
++ (*row)+= 4;
++}
++/* }}} */
++
++
++/* {{{ ps_fetch_double */
++static
++void ps_fetch_double(MYSQL_BIND *r_param, const MYSQL_FIELD * field , unsigned char **row)
++{
++ switch (r_param->buffer_type)
++ {
++ case MYSQL_TYPE_DOUBLE:
++ {
++ double *value= (double *)r_param->buffer;
++ float8get(*value, *row);
++ r_param->buffer_length= 8;
++ }
++ break;
++ default:
++ {
++ double value;
++ float8get(value, *row);
++ convert_from_float(r_param, field, value, sizeof(double));
++ }
++ break;
++ }
++ (*row)+= 8;
++}
++/* }}} */
++
++
++static void convert_to_datetime(MYSQL_TIME *t, unsigned char **row, uint len, enum enum_field_types type)
++{
++ memset(t, 0, sizeof(MYSQL_TIME));
++
++ /* binary protocol for datetime:
++ 4-bytes: DATE
++ 7-bytes: DATE + TIME
++ >7 bytes: DATE + TIME with second_part
++ */
++
++ if (len)
++ {
++ unsigned char *to= *row;
++ int has_date= 0;
++ uint offset= 7;
++
++ if (type == MYSQL_TYPE_TIME)
++ {
++ t->neg= to[0];
++ t->day= (ulong) sint4korr(to + 1);
++ t->time_type= MYSQL_TIMESTAMP_TIME;
++ offset= 8;
++ to++;
++ } else
++ {
++ t->year= (uint) sint2korr(to);
++ t->month= (uint) to[2];
++ t->day= (uint) to[3];
++ t->time_type= MYSQL_TIMESTAMP_DATE;
++ if (type == MYSQL_TYPE_DATE)
++ return;
++ has_date= 1;
++ }
++
++ if (len > 4)
++ {
++ t->hour= (uint) to[4];
++ t->minute= (uint) to[5];
++ t->second= (uint) to[6];
++ if (has_date)
++ t->time_type= MYSQL_TIMESTAMP_DATETIME;
++ }
++ if (len > offset)
++ {
++ t->second_part= (ulong)sint4korr(to+7);
++ }
++ }
++}
++
++
++/* {{{ ps_fetch_datetime */
++static
++void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field,
++ unsigned char **row)
++{
++ MYSQL_TIME *t= (MYSQL_TIME *)r_param->buffer;
++ unsigned int len= net_field_length(row);
++
++ switch (r_param->buffer_type) {
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ convert_to_datetime(t, row, len, field->type);
++ break;
++ case MYSQL_TYPE_DATE:
++ convert_to_datetime(t, row, len, field->type);
++ break;
++ case MYSQL_TYPE_TIME:
++ convert_to_datetime(t, row, len, field->type);
++ if (t->day)
++ {
++ t->hour+= t->day * 24;
++ t->day= 0;
++ }
++ t->year= t->day= t->month= 0;
++ break;
++ case MYSQL_TYPE_YEAR:
++ {
++ MYSQL_TIME tm;
++ convert_to_datetime(&tm, row, len, field->type);
++ shortstore(r_param->buffer, tm.year);
++ break;
++ }
++ default:
++ {
++ char dtbuffer[60];
++ MYSQL_TIME tm;
++ unsigned int length;
++ convert_to_datetime(&tm, row, len, field->type);
++
++ if (tm.time_type== MYSQL_TIMESTAMP_TIME && tm.day)
++ {
++ tm.hour+= tm.day * 24;
++ tm.day=0;
++ }
++ switch(field->type) {
++ case MYSQL_TYPE_DATE:
++ length= sprintf(dtbuffer, "%04u-%02u-%02u", tm.year, tm.month, tm.day);
++ break;
++ case MYSQL_TYPE_TIME:
++ length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second);
++ if (tm.second_part)
++ {
++ char helper[16];
++ sprintf(helper, ".%%0%du", field->decimals);
++ length+= sprintf(dtbuffer + length, helper, tm.second_part);
++ }
++ break;
++ case MYSQL_TYPE_DATETIME:
++ case MYSQL_TYPE_TIMESTAMP:
++ length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
++ if (tm.second_part)
++ {
++ char helper[16];
++ sprintf(helper, ".%%0%du", field->decimals);
++ length+= sprintf(dtbuffer + length, helper, tm.second_part);
++ }
++ break;
++ default:
++ dtbuffer[0]= 0;
++ length= 0;
++ break;
++ }
++ convert_from_string(r_param, dtbuffer, length);
++ break;
++ }
++ }
++ (*row) += len;
++}
++/* }}} */
++
++/* {{{ ps_fetch_string */
++static
++void ps_fetch_string(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
++ unsigned char **row)
++{
++ /* C-API differs from PHP. While PHP just converts string to string,
++ C-API needs to convert the string to the defined type with in
++ the result bind buffer.
++ */
++ ulong field_length= net_field_length(row);
++
++ convert_from_string(r_param, (char *)*row, field_length);
++ (*row) += field_length;
++}
++/* }}} */
++
++/* {{{ ps_fetch_bin */
++static
++void ps_fetch_bin(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
++ unsigned char **row)
++{
++ ulong field_length= net_field_length(row);
++ size_t copylen;
++
++ copylen= MIN(field_length, r_param->buffer_length);
++ memcpy(r_param->buffer, *row, copylen);
++ *r_param->error= copylen < field_length;
++ *r_param->length= field_length;
++
++ (*row) += field_length;
++}
++/* }}} */
++
++/* {{{ _mysqlnd_init_ps_subsystem */
++void mysql_init_ps_subsystem(void)
++{
++ memset(mysql_ps_fetch_functions, 0, sizeof(mysql_ps_fetch_functions));
++ mysql_ps_fetch_functions[MYSQL_TYPE_NULL].func= ps_fetch_null;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NULL].max_len = 0;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY].max_len = 4;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
++ mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
++ mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].max_len = 6;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
++ mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
++ mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].max_len = 6;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
++ mysql_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
++ mysql_ps_fetch_functions[MYSQL_TYPE_INT24].max_len = 9;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG].max_len = 11;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].max_len = 21;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
++ mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
++ mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
++ mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = 13;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 15;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = 5;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= 12;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= 12;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_bin;
++ mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_bin;
++ mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_bin;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bin;
++ mysql_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
++ mysql_ps_fetch_functions[MYSQL_TYPE_BIT].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_STRING].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_SET].max_len = -1;
++
++ mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
++ mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQL_PS_SKIP_RESULT_STR;
++ mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].max_len = -1;
++
++ mysql_ps_subsystem_initialized= 1;
++}
++/* }}} */
++
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: noet sw=4 ts=4 fdm=marker
++ * vim<600: noet sw=4 ts=4
++ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_symlink.c mariadb-native-client.trunk/libmariadb/my_symlink.c
+--- mariadb/libmariadb/my_symlink.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_symlink.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,138 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <m_string.h>
++#include <errno.h>
++#ifdef HAVE_REALPATH
++#include <sys/param.h>
++#include <sys/stat.h>
++#endif
++
++/*
++ Reads the content of a symbolic link
++ If the file is not a symbolic link, return the original file name in to.
++ Returns: 0 if table was a symlink,
++ 1 if table was a normal file
++ -1 on error.
++*/
++
++int my_readlink(char *to, const char *filename, myf MyFlags)
++{
++#ifndef HAVE_READLINK
++ strmov(to,filename);
++ return 1;
++#else
++ int result=0;
++ int length;
++ DBUG_ENTER("my_readlink");
++
++ if ((length=readlink(filename, to, FN_REFLEN-1)) < 0)
++ {
++ /* Don't give an error if this wasn't a symlink */
++ if ((my_errno=errno) == EINVAL)
++ {
++ result= 1;
++ strmov(to,filename);
++ }
++ else
++ {
++ if (MyFlags & MY_WME)
++ my_error(EE_CANT_READLINK, MYF(0), filename, errno);
++ result= -1;
++ }
++ }
++ else
++ to[length]=0;
++ DBUG_RETURN(result);
++#endif /* HAVE_READLINK */
++}
++
++
++/* Create a symbolic link */
++
++int my_symlink(const char *content, const char *linkname, myf MyFlags)
++{
++#ifndef HAVE_READLINK
++ return 0;
++#else
++ int result;
++ DBUG_ENTER("my_symlink");
++
++ result= 0;
++ if (symlink(content, linkname))
++ {
++ result= -1;
++ my_errno=errno;
++ if (MyFlags & MY_WME)
++ my_error(EE_CANT_SYMLINK, MYF(0), linkname, content, errno);
++ }
++ DBUG_RETURN(result);
++#endif /* HAVE_READLINK */
++}
++
++/*
++ Resolve all symbolic links in path
++ 'to' may be equal to 'filename'
++
++ Because purify gives a lot of UMR errors when using realpath(),
++ this code is disabled when using purify.
++
++ If MY_RESOLVE_LINK is given, only do realpath if the file is a link.
++*/
++
++#if defined(SCO)
++#define BUFF_LEN 4097
++#elif defined(MAXPATHLEN)
++#define BUFF_LEN MAXPATHLEN
++#else
++#define BUFF_LEN FN_LEN
++#endif
++
++int my_realpath(char *to, const char *filename, myf MyFlags)
++{
++#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
++ int result=0;
++ char buff[BUFF_LEN];
++ struct stat stat_buff;
++ DBUG_ENTER("my_realpath");
++
++ if (!(MyFlags & MY_RESOLVE_LINK) ||
++ (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
++ {
++ char *ptr;
++ if ((ptr=realpath(filename,buff)))
++ strmake(to,ptr,FN_REFLEN-1);
++ else
++ {
++ /* Realpath didn't work; Use original name */
++ my_errno=errno;
++ if (MyFlags & MY_WME)
++ my_error(EE_REALPATH, MYF(0), filename, my_errno);
++ if (to != filename)
++ strmov(to,filename);
++ result= -1;
++ }
++ }
++ DBUG_RETURN(result);
++#else
++ if (to != filename)
++ strmov(to,filename);
++ return 0;
++#endif
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/mysys_priv.h mariadb-native-client.trunk/libmariadb/mysys_priv.h
+--- mariadb/libmariadb/mysys_priv.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/mysys_priv.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,32 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include <my_global.h>
++#include <my_sys.h>
++
++#ifdef USE_SYSTEM_WRAPPERS
++#include "system_wrappers.h"
++#endif
++
++#ifdef THREAD
++#include <my_pthread.h>
++extern pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
++ THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_net,THR_LOCK_charset;
++extern pthread_mutex_t LOCK_bitmap;
++#else
++#include <my_no_pthread.h>
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_thr_init.c mariadb-native-client.trunk/libmariadb/my_thr_init.c
+--- mariadb/libmariadb/my_thr_init.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_thr_init.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,241 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++** Functions to handle initializating and allocationg of all mysys & debug
++** thread variables.
++*/
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#include <dbug.h>
++
++#ifdef THREAD
++#ifdef USE_TLS
++pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
++#else
++pthread_key(struct st_my_thread_var, THR_KEY_mysys);
++#endif /* USE_TLS */
++pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
++ THR_LOCK_lock, THR_LOCK_net, THR_LOCK_mysys;
++#ifdef HAVE_OPENSSL
++pthread_mutex_t LOCK_ssl_config;
++#endif
++#ifndef HAVE_LOCALTIME_R
++pthread_mutex_t LOCK_localtime_r;
++#endif
++#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
++pthread_mutexattr_t my_fast_mutexattr;
++#endif
++#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
++pthread_mutexattr_t my_errchk_mutexattr;
++#endif
++my_bool THR_KEY_mysys_initialized= FALSE;
++
++/* FIXME Note. TlsAlloc does not set an auto destructor, so
++ the function my_thread_global_free must be called from
++ somewhere before final exit of the library */
++
++my_bool my_thread_global_init(void)
++{
++ if (pthread_key_create(&THR_KEY_mysys,free))
++ {
++ fprintf(stderr,"Can't initialize threads: error %d\n",errno);
++ exit(1);
++ }
++#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
++ pthread_mutexattr_init(&my_fast_mutexattr);
++ pthread_mutexattr_setkind_np(&my_fast_mutexattr,PTHREAD_MUTEX_ADAPTIVE_NP);
++#endif
++#ifdef PPTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
++ pthread_mutexattr_init(&my_errchk_mutexattr);
++ pthread_mutexattr_setkind_np(&my_errchk_mutexattr,
++ PTHREAD_MUTEX_ERRORCHECK_NP);
++#endif
++ THR_KEY_mysys_initialized= TRUE;
++#ifdef HAVE_OPENSSL
++ pthread_mutex_init(&LOCK_ssl_config,MY_MUTEX_INIT_FAST);
++#endif
++ pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
++ pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
++ pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
++ pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
++#ifdef _WIN32
++ /* win_pthread_init(); */
++#endif
++#ifndef HAVE_LOCALTIME_R
++ pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
++#endif
++ return my_thread_init();
++}
++
++void my_thread_global_end(void)
++{
++#if defined(USE_TLS)
++ (void) TlsFree(THR_KEY_mysys);
++#endif
++#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
++ pthread_mutexattr_destroy(&my_fast_mutexattr);
++#endif
++#ifdef PPTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
++ pthread_mutexattr_destroy(&my_errchk_mutexattr);
++#endif
++#ifdef HAVE_OPENSSL
++ pthread_mutex_destroy(&LOCK_ssl_config);
++#endif
++}
++
++static long thread_id=0;
++
++/*
++ We can't use mutex_locks here if we are using windows as
++ we may have compiled the program with SAFE_MUTEX, in which
++ case the checking of mutex_locks will not work until
++ the pthread_self thread specific variable is initialized.
++*/
++
++my_bool my_thread_init(void)
++{
++ struct st_my_thread_var *tmp;
++ if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
++ {
++ DBUG_PRINT("info", ("my_thread_init was already called. Thread id: %lu",
++ pthread_self()));
++ return 0; /* Safequard */
++ }
++ /* We must have many calloc() here because these are freed on
++ pthread_exit */
++ if (!(tmp=(struct st_my_thread_var *)
++ calloc(1,sizeof(struct st_my_thread_var))))
++ {
++ return 1;
++ }
++ pthread_setspecific(THR_KEY_mysys,tmp);
++
++ if (tmp->initialized) /* Already initialized */
++ {
++ return 0;
++ }
++
++ pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
++ pthread_cond_init(&tmp->suspend, NULL);
++ pthread_mutex_lock(&THR_LOCK_lock);
++ tmp->id= ++thread_id;
++ pthread_mutex_unlock(&THR_LOCK_lock);
++ tmp->initialized= TRUE;
++ return 0;
++}
++
++void my_thread_end(void)
++{
++ struct st_my_thread_var *tmp=
++ my_pthread_getspecific(struct st_my_thread_var *, THR_KEY_mysys);
++
++ if (tmp && tmp->initialized)
++ {
++#ifdef HAVE_OPENSSL
++ ERR_remove_thread_state(NULL);
++#endif
++#if !defined(DBUG_OFF)
++ if (tmp->dbug)
++ {
++ DBUG_POP();
++ free(tmp->dbug);
++ tmp->dbug=0;
++ }
++#endif
++#if !defined(__bsdi__) || defined(HAVE_mit_thread) /* bsdi dumps core here */
++ pthread_cond_destroy(&tmp->suspend);
++#endif
++ pthread_mutex_destroy(&tmp->mutex);
++ free(tmp);
++ pthread_setspecific(THR_KEY_mysys,0);
++ }
++ else
++ pthread_setspecific(THR_KEY_mysys,0);
++}
++
++struct st_my_thread_var *_my_thread_var(void)
++{
++ struct st_my_thread_var *tmp=
++ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
++#if defined(USE_TLS)
++ if (!tmp)
++ {
++ my_thread_init();
++ tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
++ }
++#endif
++ return tmp;
++}
++
++/****************************************************************************
++** Get name of current thread.
++****************************************************************************/
++
++#define UNKNOWN_THREAD -1
++
++long my_thread_id()
++{
++#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
++ return pthread_getsequence_np(pthread_self());
++#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) && !defined(HAVE_mit_thread)
++ return pthread_self();
++#else
++ return my_thread_var->id;
++#endif
++}
++
++#ifdef DBUG_OFF
++const char *my_thread_name(void)
++{
++ return "no_name";
++}
++
++#else
++
++const char *my_thread_name(void)
++{
++ char name_buff[100];
++ struct st_my_thread_var *tmp=my_thread_var;
++ if (!tmp->name[0])
++ {
++ long id=my_thread_id();
++ sprintf(name_buff,"T@%ld", id);
++ strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
++ }
++ return tmp->name;
++}
++
++extern void **my_thread_var_dbug()
++{
++ struct st_my_thread_var *tmp;
++ /*
++ Instead of enforcing DBUG_ASSERT(THR_KEY_mysys_initialized) here,
++ which causes any DBUG_ENTER and related traces to fail when
++ used in init / cleanup code, we are more tolerant:
++ using DBUG_ENTER / DBUG_PRINT / DBUG_RETURN
++ when the dbug instrumentation is not in place will do nothing.
++ */
++ if (! THR_KEY_mysys_initialized)
++ return NULL;
++ tmp= _my_thread_var();
++ return tmp && tmp->initialized ? (void **)&tmp->dbug : 0;
++}
++#endif /* DBUG_OFF */
++
++#endif /* THREAD */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_vsnprintf.c mariadb-native-client.trunk/libmariadb/my_vsnprintf.c
+--- mariadb/libmariadb/my_vsnprintf.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_vsnprintf.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,119 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <m_string.h>
++#include <stdarg.h>
++#include <m_ctype.h>
++
++
++int my_snprintf(char* to, size_t n, const char* fmt, ...)
++{
++ int result;
++ va_list args;
++ va_start(args,fmt);
++ result= my_vsnprintf(to, n, fmt, args);
++ va_end(args);
++ return result;
++}
++
++
++int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
++{
++ char *start=to, *end=to+n-1;
++ for (; *fmt ; fmt++)
++ {
++ if (fmt[0] != '%')
++ {
++ if (to == end) /* End of buffer */
++ break;
++ *to++= *fmt; /* Copy ordinary char */
++ continue;
++ }
++ /* Skipp if max size is used (to be compatible with printf) */
++ fmt++;
++ while (isdigit(*fmt) || *fmt == '.' || *fmt == '-')
++ fmt++;
++ if (*fmt == 'l')
++ fmt++;
++ if (*fmt == 's') /* String parameter */
++ {
++ reg2 char *par = va_arg(ap, char *);
++ uint plen;
++ if (!par) par = (char*)"(null)";
++ plen = (uint) strlen(par);
++ if ((uint) (end-to) > plen) /* Replace if possible */
++ {
++ to=strmov(to,par);
++ continue;
++ }
++ }
++ else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
++ {
++ register int iarg;
++ if ((uint) (end-to) < 16)
++ break;
++ iarg = va_arg(ap, int);
++ if (*fmt == 'd')
++ to=int10_to_str((long) iarg,to, -10);
++ else
++ to=int10_to_str((long) (uint) iarg,to,10);
++ continue;
++ }
++ /* We come here on '%%', unknown code or too long parameter */
++ if (to == end)
++ break;
++ *to++='%'; /* % used as % or unknown code */
++ }
++ *to='\0'; /* End of errmessage */
++ return (uint) (to - start);
++}
++
++
++#ifdef MAIN
++static void my_printf(const char * fmt, ...)
++{
++ char buf[32];
++ int n;
++ va_list ar;
++ va_start(ar, fmt);
++ n = my_vsnprintf(buf, sizeof(buf),fmt, ar);
++ printf(buf);
++ printf("n=%d, strlen=%d\n", n, strlen(buf));
++ va_end(ar);
++}
++
++
++int main()
++{
++
++ my_printf("Hello\n");
++ my_printf("Hello int, %d\n", 1);
++ my_printf("Hello string '%s'\n", "I am a string");
++ my_printf("Hello hack hack hack hack hack hack hack %d\n", 1);
++ my_printf("Hello %d hack %d\n", 1, 4);
++ my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4);
++ my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
++ my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
++ my_printf("Hello %u\n", 1);
++ my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\
++ `%-.64s' (%-.64s)", 1, 0,0,0,0);
++ return 0;
++}
++#endif
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/my_write.c mariadb-native-client.trunk/libmariadb/my_write.c
+--- mariadb/libmariadb/my_write.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/my_write.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,90 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++#include "mysys_priv.h"
++#include "mysys_err.h"
++#include <errno.h>
++
++
++ /* Write a chunk of bytes to a file */
++
+uint my_write(int Filedes, const unsigned char *Buffer, uint Count, myf MyFlags)
- {
- uint writenbytes,errors;
- ulong written;
-
-=== modified file 'libmariadb/net.c'
---- mariadb/libmysql/net.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/net.c 2013-03-14 21:01:43 +0000
-@@ -341,7 +341,7 @@
- }
- memcpy(b+header_length,packet,len);
-
-- if (my_compress((byte*) b+header_length,&len,&complen))
++{
++ uint writenbytes,errors;
++ ulong written;
++ DBUG_ENTER("my_write");
++ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %d MyFlags: %d",
++ Filedes, Buffer, Count, MyFlags));
++ errors=0; written=0L;
++
++ for (;;)
++ {
++ if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
++ break;
++ if ((int) writenbytes != -1)
++ { /* Safeguard */
++ written+=writenbytes;
++ Buffer+=writenbytes;
++ Count-=writenbytes;
++ }
++ my_errno=errno;
++ DBUG_PRINT("error",("Write only %d bytes, error: %d",
++ writenbytes,my_errno));
++#ifndef NO_BACKGROUND
++#ifdef THREAD
++ if (my_thread_var->abort)
++ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
++#endif
++ if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL) &&
++ (uint) writenbytes != (uint) -1)
++ {
++ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
++ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
++ my_filename(Filedes));
++ VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
++ continue;
++ }
++ if (!writenbytes)
++ {
++ /* We may come here on an interrupt or if the file quote is exeeded */
++ if (my_errno == EINTR)
++ continue;
++ if (!errors++) /* Retry once */
++ {
++ errno=EFBIG; /* Assume this is the error */
++ continue;
++ }
++ }
++ else if ((uint) writenbytes != (uint) -1)
++ continue; /* Retry */
++#endif
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ {
++ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
++ {
++ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
++ my_filename(Filedes),my_errno);
++ }
++ DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
++ }
++ else
++ break; /* Return bytes written */
++ }
++ if (MyFlags & (MY_NABP | MY_FNABP))
++ DBUG_RETURN(0); /* Want only errors */
++ DBUG_RETURN(writenbytes+written);
++} /* my_write */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/net.c mariadb-native-client.trunk/libmariadb/net.c
+--- mariadb/libmariadb/net.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/net.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,770 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Write and read of logical packets to/from socket
++** Writes are cached into net_buffer_length big packets.
++** Read packets are reallocated dynamicly when reading big packets.
++** Each logical packet has the following pre-info:
++** 3 byte length & 1 byte package-number.
++*/
++
++#include <my_global.h>
++#include <violite.h>
++#include <my_sys.h>
++#include <m_string.h>
++#include "mysql.h"
++#include "mysqld_error.h"
++#include <signal.h>
++#include <errno.h>
++#include <sys/types.h>
++#ifdef MYSQL_SERVER
++#include <violite.h>
++#endif
++
++#define MAX_PACKET_LENGTH (256L*256L*256L-1)
++
++/* net_buffer_length and max_allowec_packet are defined in mysql.h
++ See bug conc-57
++*/
++#undef net_buffer_length
++#undef max_allowed_packet
++ulong max_allowed_packet=1024L * 1024L * 1024L;
++ulong net_read_timeout= NET_READ_TIMEOUT;
++ulong net_write_timeout= NET_WRITE_TIMEOUT;
++ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
++
++#if !defined(_WIN32) && !defined(MSDOS)
++#include <sys/socket.h>
++#else
++#undef MYSQL_SERVER /* Win32 can't handle interrupts */
++#endif
++#if !defined(MSDOS) && !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
++#include <netinet/in_systm.h>
++#include <netinet/in.h>
++#include <netinet/ip.h>
++#if !defined(alpha_linux_port)
++#include <netinet/tcp.h>
++#endif
++#endif
++#include "mysqld_error.h"
++#ifdef MYSQL_SERVER
++#include "my_pthread.h"
++#include "thr_alarm.h"
++void sql_print_error(const char *format,...);
++#define RETRY_COUNT mysqld_net_retry_count
++extern ulong mysqld_net_retry_count;
++#else
++
++#ifdef OS2 /* avoid name conflict */
++#define thr_alarm_t thr_alarm_t_net
++#define ALARM ALARM_net
++#endif
++
++typedef my_bool thr_alarm_t;
++typedef my_bool ALARM;
++#define thr_alarm_init(A) (*(A))=0
++#define thr_alarm_in_use(A) (*(A))
++#define thr_end_alarm(A)
++#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
++static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
++{
++ *A=1;
++ return 0;
++}
++#define thr_got_alarm(A) 0
++#define RETRY_COUNT 1
++#endif
++
++#ifdef MYSQL_SERVER
++extern ulong bytes_sent, bytes_received;
++extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
++#else
++#undef statistic_add
++#define statistic_add(A,B,C)
++#endif
++
++/*
++** Give error if a too big packet is found
++** The server can change this with the -O switch, but because the client
++** can't normally do this the client should have a bigger max-buffer.
++*/
++
++#define TEST_BLOCKING 8
++static int net_write_buff(NET *net,const char *packet, size_t len);
++
++
++ /* Init with packet info */
++
++int my_net_init(NET *net, Vio* vio)
++{
++ if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
++ return 1;
++ if (net_buffer_length > max_allowed_packet)
++ max_allowed_packet=net_buffer_length;
++ net->max_packet_size= 0xFFFFFF;
++ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
++ net->vio = vio;
++ net->error=0; net->return_status=0;
++ net->read_timeout=(uint) net_read_timeout; /* Timeout for read */
++ net->compress_pkt_nr= net->pkt_nr= 0;
++ net->write_pos=net->read_pos = net->buff;
++ net->last_error[0]= net->sqlstate[0] =0;
++
++ net->compress=0; net->reading_or_writing=0;
++ net->where_b = net->remain_in_buf=0;
++ net->last_errno=0;
++
++ if (vio != 0) /* If real connection */
++ {
++ net->fd = vio_fd(vio); /* For perl DBI/DBD */
++#if defined(MYSQL_SERVER) && !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
++ if (!(test_flags & TEST_BLOCKING))
++ vio_blocking(vio, FALSE);
++#endif
++ vio_fastsend(vio);
++ }
++ return 0;
++}
++
++void net_end(NET *net)
++{
++ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
++ net->buff=0;
++}
++
++/* Realloc the packet buffer */
++
++static my_bool net_realloc(NET *net, size_t length)
++{
++ uchar *buff;
++ size_t pkt_length;
++
++ DBUG_ENTER("net_realloc");
++ DBUG_PRINT("info", ("length: %lu max_allowed_packet: %lu",
++ (ulong)length, max_allowed_packet));
++
++ if (length >= net->max_packet_size)
++ {
++ DBUG_PRINT("error",("Packet too large (%lu)", length));
++ net->error=1;
++ net->last_errno=ER_NET_PACKET_TOO_LARGE;
++ DBUG_RETURN(1);
++ }
++ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
++ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
++ {
++ DBUG_PRINT("info", ("Out of memory"));
++ net->error=1;
++#ifdef MYSQL_SERVER
++ net->last_errno=ER_OUT_OF_RESOURCES;
++#endif
++ DBUG_RETURN(1);
++ }
++ net->buff=net->write_pos=buff;
++ net->buff_end=buff+(net->max_packet=pkt_length);
++ DBUG_RETURN(0);
++}
++
++#ifdef DEBUG_SOCKET
++static ssize_t net_check_if_data_available(Vio *vio)
++{
++ ssize_t length= 0;
++
++ if (vio->type != VIO_TYPE_SOCKET &&
++ vio->type != VIO_TYPE_TCPIP)
++ return 0;
++
++ if (vio_read_peek(vio, (size_t *)&length))
++ return -1;
++
++ return length;
++}
++#endif
++
++ /* Remove unwanted characters from connection */
++
++void net_clear(NET *net)
++{
++ DBUG_ENTER("net_clear");
++
++#ifdef DEBUG_SOCKET
++ DBUG_ASSERT(net_check_if_data_available(net->vio) < 2);
++#endif
++
++ net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
++ net->write_pos=net->buff;
++ DBUG_VOID_RETURN;
++}
++
++
++ /* Flush write_buffer if not empty. */
++
++int net_flush(NET *net)
++{
++ int error=0;
++ DBUG_ENTER("net_flush");
++ if (net->buff != net->write_pos)
++ {
++ error=net_real_write(net,(char*) net->buff,
++ (uint) (net->write_pos - net->buff));
++ net->write_pos=net->buff;
++ }
++ if (net->compress)
++ net->pkt_nr= net->compress_pkt_nr;
++ DBUG_RETURN(error);
++}
++
++
++/*****************************************************************************
++** Write something to server/client buffer
++*****************************************************************************/
++
++
++/*
++** Write a logical packet with packet header
++** Format: Packet length (3 bytes), packet number(1 byte)
++** When compression is used a 3 byte compression length is added
++** NOTE: If compression is used the original package is destroyed!
++*/
++
++int
++my_net_write(NET *net, const char *packet, size_t len)
++{
++ uchar buff[NET_HEADER_SIZE];
++ while (len >= MAX_PACKET_LENGTH)
++ {
++ const ulong max_len= MAX_PACKET_LENGTH;
++ int3store(buff,max_len);
++ buff[3]= (uchar)net->pkt_nr++;
++ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
++ net_write_buff(net, packet, max_len))
++ return 1;
++ packet+= max_len;
++ len-= max_len;
++ }
++ /* write last remaining packet, size can be zero */
++ int3store(buff, len);
++ buff[3]= (uchar)net->pkt_nr++;
++ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
++ net_write_buff(net, packet, len))
++ return 1;
++ return 0;
++}
++
++int
++net_write_command(NET *net, uchar command,
++ const char *packet, size_t len)
++{
++ uchar buff[NET_HEADER_SIZE+1];
++ size_t buff_size= NET_HEADER_SIZE + 1;
++ size_t length= 1 + len; /* 1 extra byte for command */
++ int rc;
++
++ buff[4]=command;
++
++ if (length >= MAX_PACKET_LENGTH)
++ {
++ len= MAX_PACKET_LENGTH - 1;
++ do
++ {
++ int3store(buff, MAX_PACKET_LENGTH);
++ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
++
++ if (net_write_buff(net, (char *)buff, buff_size) ||
++ net_write_buff(net, packet, len))
++ return(1);
++ packet+= len;
++ length-= MAX_PACKET_LENGTH;
++ len= MAX_PACKET_LENGTH;
++ buff_size= NET_HEADER_SIZE; /* don't send command for further packets */
++ } while (length >= MAX_PACKET_LENGTH);
++ len= length;
++ }
++ int3store(buff,length);
++ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
++ rc= test (net_write_buff(net,(char *)buff, buff_size) ||
++ net_write_buff(net,packet,len) ||
++ net_flush(net));
++ return rc;
++}
++
++
++static int
++net_write_buff(NET *net,const char *packet, size_t len)
++{
++ size_t left_length;
++
++ if (net->max_packet > MAX_PACKET_LENGTH &&
++ net->compress)
++ left_length= (size_t)(MAX_PACKET_LENGTH - (net->write_pos - net->buff));
++ else
++ left_length=(size_t) (net->buff_end - net->write_pos);
++
++ if (len > left_length)
++ {
++ if (net->write_pos != net->buff)
++ {
++ memcpy((char*) net->write_pos,packet,left_length);
++ if (net_real_write(net,(char*) net->buff,
++ (size_t)(net->write_pos - net->buff) + left_length))
++ return 1;
++ packet+=left_length;
++ len-=left_length;
++ net->write_pos= net->buff;
++ }
++ if (net->compress)
++ {
++ /* uncompressed length is stored in 3 bytes,so
++ packet can't be > 0xFFFFFF */
++ left_length= MAX_PACKET_LENGTH;
++ while (len > left_length)
++ {
++ if (net_real_write(net, packet, left_length))
++ return 1;
++ packet+= left_length;
++ len-= left_length;
++ }
++ }
++ if (len > net->max_packet)
++ return(test(net_real_write(net, packet, len)));
++ }
++ memcpy((char*) net->write_pos,packet,len);
++ net->write_pos+=len;
++ return 0;
++}
++
++/* Read and write using timeouts */
++
++int
++net_real_write(NET *net,const char *packet,size_t len)
++{
++ size_t length;
++ char *pos,*end;
++ thr_alarm_t alarmed;
++#if !defined(_WIN32) && !defined(__EMX__) && !defined(OS2)
++ ALARM alarm_buff;
++#endif
++ uint retry_count=0;
++ my_bool net_blocking = vio_is_blocking(net->vio);
++ DBUG_ENTER("net_real_write");
++
++ if (net->error == 2)
++ DBUG_RETURN(-1); /* socket can't be used */
++
++ net->reading_or_writing=2;
++#ifdef HAVE_COMPRESS
++ if (net->compress)
++ {
++ size_t complen;
++ uchar *b;
++ uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
++ if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
++ MYF(MY_WME))))
++ {
++ net->last_errno=ER_OUT_OF_RESOURCES;
++ net->error=2;
++ net->reading_or_writing=0;
++ DBUG_RETURN(1);
++ }
++ memcpy(b+header_length,packet,len);
++
+ if (my_compress((unsigned char*) b+header_length,&len,&complen))
- {
- DBUG_PRINT("warning",
- ("Compression error; Continuing without compression"));
-@@ -710,7 +710,7 @@
-
- if ((len = my_real_read(net,(size_t *)&complen)) == packet_error)
- break;
-- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
-+ if (my_uncompress((unsigned char*) net->buff + net->where_b, &len, &complen))
- {
- len= packet_error;
- net->error=2; /* caller will close socket */
-
-=== modified file 'libmariadb/password.c'
---- mariadb/libmysql/password.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/password.c 2013-03-14 21:01:43 +0000
-@@ -179,31 +179,30 @@
- * Genererate a new message based on message and password
- * The same thing is done in client and server and the results are checked.
- */
--
--char *scramble_323(char *to,const char *message,const char *password)
++ {
++ DBUG_PRINT("warning",
++ ("Compression error; Continuing without compression"));
++ complen=0;
++ }
++ int3store(&b[NET_HEADER_SIZE],complen);
++ int3store(b,len);
++ b[3]=(uchar) (net->compress_pkt_nr++);
++ len+= header_length;
++ packet= (char*) b;
++ }
++#endif /* HAVE_COMPRESS */
++
++ alarmed=0;
++
++ pos=(char*) packet; end=pos+len;
++ while (pos != end)
++ {
++ if ((long) (length=vio_write(net->vio,pos,(int) (end-pos))) <= 0)
++ {
++ my_bool interrupted = vio_should_retry(net->vio);
++#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2))
++ if ((interrupted || length==0) && !thr_alarm_in_use(&alarmed))
++ {
++ if (!thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff))
++ { /* Always true for client */
++ if (!vio_is_blocking(net->vio))
++ {
++ while (vio_blocking(net->vio, TRUE) < 0)
++ {
++ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
++ continue;
++#ifdef EXTRA_DEBUG
++ fprintf(stderr,
++ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
++ my_progname,vio_errno(net->vio));
++#endif /* EXTRA_DEBUG */
++ net->error=2; /* Close socket */
++ net->last_errno= (interrupted ?
++ ER_NET_WRITE_INTERRUPTED : ER_NET_ERROR_ON_WRITE);
++ goto end;
++ }
++ }
++ retry_count=0;
++ continue;
++ }
++ }
++ else
++#endif /* (!defined(_WIN32) && !defined(__EMX__)) */
++ if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
++ interrupted)
++ {
++ if (retry_count++ < RETRY_COUNT)
++ continue;
++#ifdef EXTRA_DEBUG
++ fprintf(stderr, "%s: write looped, aborting thread\n",
++ my_progname);
++#endif /* EXTRA_DEBUG */
++ }
++#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
++ if (vio_errno(net->vio) == SOCKET_EINTR)
++ {
++ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
++ continue;
++ }
++#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
++ net->error=2; /* Close socket */
++ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
++ ER_NET_ERROR_ON_WRITE);
++ break;
++ }
++ pos+=length;
++ statistic_add(bytes_sent,length,&LOCK_bytes_sent);
++ }
++#ifndef _WIN32
++ end:
++#endif
++#ifdef HAVE_COMPRESS
++ if (net->compress)
++ my_free((char*) packet,MYF(0));
++#endif
++ if (thr_alarm_in_use(&alarmed))
++ {
++ thr_end_alarm(&alarmed);
++ vio_blocking(net->vio, net_blocking);
++ }
++ net->reading_or_writing=0;
++ DBUG_RETURN(((int) (pos != end)));
++}
++
++
++/*****************************************************************************
++** Read something from server/clinet
++*****************************************************************************/
++
++#ifdef MYSQL_SERVER
++
++/*
++ Help function to clear the commuication buffer when we get a too
++ big packet
++*/
++
++static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed,
++ ALARM *alarm_buff)
++{
++ uint retry_count=0;
++ if (!thr_alarm_in_use(alarmed))
++ {
++ if (thr_alarm(alarmed,net->timeout,alarm_buff) ||
++ (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
++ return; /* Can't setup, abort */
++ }
++ while (remain > 0)
++ {
++ ulong length;
++ if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
++ {
++ my_bool interrupted = vio_should_retry(net->vio);
++ if (!thr_got_alarm(alarmed) && interrupted)
++ { /* Probably in MIT threads */
++ if (retry_count++ < RETRY_COUNT)
++ continue;
++ }
++ return;
++ }
++ remain -=(ulong) length;
++ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
++ }
++}
++#endif /* MYSQL_SERVER */
++
++
++static ulong
++my_real_read(NET *net, size_t *complen)
++{
++ uchar *pos;
++ size_t length;
++ uint i,retry_count=0;
++ ulong len=packet_error;
++ thr_alarm_t alarmed;
++#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
++ ALARM alarm_buff;
++#endif
++ my_bool net_blocking=vio_is_blocking(net->vio);
++ size_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
++ NET_HEADER_SIZE);
++ *complen = 0;
++
++ net->reading_or_writing=1;
++ thr_alarm_init(&alarmed);
++#ifdef MYSQL_SERVER
++ if (net_blocking)
++ thr_alarm(&alarmed,net->timeout,&alarm_buff);
++#endif /* MYSQL_SERVER */
++
++ pos = net->buff + net->where_b; /* net->packet -4 */
++ for (i=0 ; i < 2 ; i++)
++ {
++ while (remain > 0)
++ {
++ /* First read is done with non blocking mode */
++ if ((long) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
++ {
++ my_bool interrupted = vio_should_retry(net->vio);
++
++ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
++ length, vio_errno(net->vio)));
++#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
++ /*
++ We got an error that there was no data on the socket. We now set up
++ an alarm to not 'read forever', change the socket to non blocking
++ mode and try again
++ */
++ if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
++ {
++ if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
++ {
++ if (!vio_is_blocking(net->vio))
++ {
++ while (vio_blocking(net->vio,TRUE) < 0)
++ {
++ if (vio_should_retry(net->vio) &&
++ retry_count++ < RETRY_COUNT)
++ continue;
++ DBUG_PRINT("error",
++ ("fcntl returned error %d, aborting thread",
++ vio_errno(net->vio)));
++#ifdef EXTRA_DEBUG
++ fprintf(stderr,
++ "%s: read: fcntl returned error %d, aborting thread\n",
++ my_progname,vio_errno(net->vio));
++#endif /* EXTRA_DEBUG */
++ len= packet_error;
++ net->error=2; /* Close socket */
++#ifdef MYSQL_SERVER
++ net->last_errno=ER_NET_FCNTL_ERROR;
++#endif
++ goto end;
++ }
++ }
++ retry_count=0;
++ continue;
++ }
++ }
++#endif /* (!defined(_WIN32) && !defined(__EMX__)) || defined(MYSQL_SERVER) */
++ if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
++ interrupted)
++ { /* Probably in MIT threads */
++ if (retry_count++ < RETRY_COUNT)
++ continue;
++#ifdef EXTRA_DEBUG
++ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
++ my_progname,vio_errno(net->vio));
++#endif /* EXTRA_DEBUG */
++ }
++#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
++ if (vio_should_retry(net->vio))
++ {
++ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
++ continue;
++ }
++#endif
++ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
++ len= packet_error;
++ net->error=2; /* Close socket */
++ goto end;
++ }
++ remain -= (ulong) length;
++ pos+= (ulong) length;
++ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
++ }
++ if (i == 0)
++ { /* First parts is packet length */
++ ulong helping;
++ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
++ {
++ if (net->buff[net->where_b] != (uchar) 255)
++ {
++ DBUG_PRINT("error",
++ ("Packets out of order (Found: %d, expected %d)",
++ (int) net->buff[net->where_b + 3],
++ (uint) (uchar) net->pkt_nr));
++#ifdef EXTRA_DEBUG
++ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
++ (int) net->buff[net->where_b + 3],
++ (uint) (uchar) net->pkt_nr);
++#endif
++ }
++ len= packet_error;
++#ifdef MYSQL_SERVER
++ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
++#endif
++ goto end;
++ }
++ net->compress_pkt_nr= ++net->pkt_nr;
++#ifdef HAVE_COMPRESS
++ if (net->compress)
++ {
++ /* complen is > 0 if package is really compressed */
++ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
++ }
++#endif
++
++ len=uint3korr(net->buff+net->where_b);
++ if (!len)
++ goto end;
++ helping = max(len,(ulong)*complen) + net->where_b;
++ /* The necessary size of net->buff */
++ if (helping >= net->max_packet)
++ {
++ /* We must allocate one extra byte for the end null */
++ if (net_realloc(net,helping + 1))
++ {
++#ifdef MYSQL_SERVER
++ if (i == 1)
++ my_net_skip_rest(net, len, &alarmed, &alarm_buff);
++#endif
++ len= packet_error; /* Return error */
++ goto end;
++ }
++ }
++ pos=net->buff + net->where_b;
++ remain = len;
++ }
++ }
++
++end:
++ if (thr_alarm_in_use(&alarmed))
++ {
++ thr_end_alarm(&alarmed);
++ vio_blocking(net->vio, net_blocking);
++ }
++ net->reading_or_writing=0;
++ return(len);
++}
++
++ulong my_net_read(NET *net)
++{
++ size_t len,complen;
++
++#ifdef HAVE_COMPRESS
++ if (!net->compress)
++ {
++#endif
++ len = my_real_read (net,(size_t *)&complen);
++ if (len == MAX_PACKET_LENGTH)
++ {
++ /* multi packet read */
++ size_t length= 0;
++ ulong last_pos= net->where_b;
++
++ do
++ {
++ length+= len;
++ net->where_b+= (unsigned long)len;
++ } while (len == MAX_PACKET_LENGTH);
++ net->where_b= last_pos;
++ if (len != packet_error)
++ len+= length;
++ }
++ net->read_pos = net->buff + net->where_b;
++ if (len != packet_error)
++ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
++ return (ulong)len;
++#ifdef HAVE_COMPRESS
++ }
++ else
++ {
++ if (net->remain_in_buf)
++ {
++ /* restore 0 character */
++ net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
++ }
++ for (;;)
++ {
++ if (net->remain_in_buf)
++ {
++ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
++ if (net->remain_in_buf >= 4)
++ {
++ net->length = uint3korr(pos);
++ if (net->length <= net->remain_in_buf - 4)
++ {
++ /* We have a full packet */
++ len=net->length;
++ net->remain_in_buf -= net->length + 4;
++ net->read_pos=pos + 4;
++ break; /* We have a full packet */
++ }
++ }
++ /* Move data down to read next data packet after current one */
++ if (net->buf_length != net->remain_in_buf)
++ {
++ memmove(net->buff,pos,net->remain_in_buf);
++ net->buf_length=net->remain_in_buf;
++ }
++ net->where_b=net->buf_length;
++ }
++ else
++ {
++ net->where_b=0;
++ net->buf_length=0;
++ }
++
++ if ((len = my_real_read(net,(size_t *)&complen)) == packet_error)
++ break;
++ if (my_uncompress((unsigned char*) net->buff + net->where_b, &len, &complen))
++ {
++ len= packet_error;
++ net->error=2; /* caller will close socket */
++ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
++ break;
++ }
++ net->buf_length+=(unsigned long)len;
++ net->remain_in_buf+=(unsigned long)len;
++ }
++ if (len != packet_error)
++ {
++ net->save_char= net->read_pos[len]; /* Must be saved */
++ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
++ }
++ }
++#endif
++ return (ulong)len;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/password.c mariadb-native-client.trunk/libmariadb/password.c
+--- mariadb/libmariadb/password.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/password.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,234 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* password checking routines */
++/*****************************************************************************
++ The main idea is that no password are sent between client & server on
++ connection and that no password are saved in mysql in a decodable form.
++
++ On connection a random string is generated and sent to the client.
++ The client generates a new string with a random generator inited with
++ the hash values from the password and the sent string.
++ This 'check' string is sent to the server where it is compared with
++ a string generated from the stored hash_value of the password and the
++ random string.
++
++ The password is saved (in user.password) by using the PASSWORD() function in
++ mysql.
++
++ Example:
++ update user set password=PASSWORD("hello") where user="test"
++ This saves a hashed number as a string in the password field.
++*****************************************************************************/
++
++#include <my_global.h>
++#include <my_sys.h>
++#include <m_string.h>
++#include <sha1.h>
++#include "mysql.h"
++
++
++void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
++{ /* For mysql 3.21.# */
++#ifdef HAVE_purify
++ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
++#endif
++ rand_st->max_value= 0x3FFFFFFFL;
++ rand_st->max_value_dbl=(double) rand_st->max_value;
++ rand_st->seed1=seed1%rand_st->max_value ;
++ rand_st->seed2=seed2%rand_st->max_value;
++}
++
++static void old_randominit(struct rand_struct *rand_st,ulong seed1)
++{ /* For mysql 3.20.# */
++ rand_st->max_value= 0x01FFFFFFL;
++ rand_st->max_value_dbl=(double) rand_st->max_value;
++ seed1%=rand_st->max_value;
++ rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
++}
++
++double rnd(struct rand_struct *rand_st)
++{
++ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
++ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
++ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
++}
++
++void hash_password(ulong *result, const char *password, size_t len)
++{
++ register ulong nr=1345345333L, add=7, nr2=0x12345671L;
++ ulong tmp;
++ const char *password_end= password + len;
++ for (; password < password_end; password++)
++ {
++ if (*password == ' ' || *password == '\t')
++ continue; /* skipp space in password */
++ tmp= (ulong) (uchar) *password;
++ nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
++ nr2+=(nr2 << 8) ^ nr;
++ add+=tmp;
++ }
++ result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
++ result[1]=nr2 & (((ulong) 1L << 31) -1L);
++ return;
++}
++
++static inline unsigned int char_val(char X)
++{
++ return (uint) (X >= '0' && X <= '9' ? X-'0' :
++ X >= 'A' && X <= 'Z' ? X-'A'+10 :
++ X-'a'+10);
++}
++
++/*
++ * Genererate a new message based on message and password
++ * The same thing is done in client and server and the results are checked.
++ */
++
++/* scramble for 4.1 servers
++ * Code based on php_nysqlnd_scramble function from PHP's mysqlnd extension,
++ * written by Andrey Hristov (andrey@php.net)
++ * License: PHP License 3.0
++ */
++void my_crypt(unsigned char *buffer, const unsigned char *s1, const unsigned char *s2, size_t len)
++{
++ const unsigned char *s1_end= s1 + len;
++ while (s1 < s1_end) {
++ *buffer++= *s1++ ^ *s2++;
++ }
++}
++
++void my_scramble_41(const unsigned char *buffer, const char *scramble, const char *password)
++{
++ MYSQL_SHA1_CTX context;
++ unsigned char sha1[SHA1_MAX_LENGTH];
++ unsigned char sha2[SHA1_MAX_LENGTH];
++
++
++ /* Phase 1: hash password */
++ MYSQL_SHA1Init(&context);
++ MYSQL_SHA1Update(&context, (unsigned char *)password, strlen((char *)password));
++ MYSQL_SHA1Final(sha1, &context);
++
++ /* Phase 2: hash sha1 */
++ MYSQL_SHA1Init(&context);
++ MYSQL_SHA1Update(&context, (unsigned char*)sha1, SHA1_MAX_LENGTH);
++ MYSQL_SHA1Final(sha2, &context);
++
++ /* Phase 3: hash scramble + sha2 */
++ MYSQL_SHA1Init(&context);
++ MYSQL_SHA1Update(&context, (unsigned char *)scramble, SCRAMBLE_LENGTH);
++ MYSQL_SHA1Update(&context, (unsigned char*)sha2, SHA1_MAX_LENGTH);
++ MYSQL_SHA1Final((unsigned char *)buffer, &context);
++
++ /* let's crypt buffer now */
++ my_crypt((uchar *)buffer, (const unsigned char *)buffer, (const unsigned char *)sha1, SHA1_MAX_LENGTH);
++}
++/* }}} */
++
++void make_scrambled_password(char *to,const char *password)
++{
++ ulong hash_res[2];
++ hash_password(hash_res,password, strlen(password));
++ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
++}
++
++/*
++** This code assumes that len(password) is divideable with 8 and that
++** res is big enough (2 in mysql)
++*/
++
++void get_salt_from_password(ulong *res,const char *password)
++{
++ res[0]=res[1]=0;
++ if (password)
++ {
++ while (*password)
++ {
++ ulong val=0;
++ uint i;
++ for (i=0 ; i < 8 ; i++)
++ val=(val << 4)+char_val(*password++);
++ *res++=val;
++ }
++ }
++ return;
++}
++
++void make_password_from_salt(char *to, ulong *hash_res)
++{
++ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
++}
++
++
++/*
++ * Genererate a new message based on message and password
++ * The same thing is done in client and server and the results are checked.
++ */
+char *scramble_323(char *to, const char *message, const char *password)
- {
- struct rand_struct rand_st;
-- ulong hash_pass[2],hash_message[2];
++{
++ struct rand_struct rand_st;
+ ulong hash_pass[2], hash_message[2];
+
- if (password && password[0])
- {
-- char *to_start=to;
-- hash_password(hash_pass, password, strlen(password));
-- hash_password(hash_message, message, strlen(message));
-- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
-- hash_pass[1] ^ hash_message[1]);
-- while (*message++)
-- *to++= (char) (floor(rnd(&rand_st)*31)+64);
-- { /* Make it harder to break */
-- char extra=(char) (floor(rnd(&rand_st)*31));
-- while (to_start != to)
-- *(to_start++)^=extra;
-- }
++ if (password && password[0])
++ {
+ char extra, *to_start=to;
+ const char *end_scramble323= message + SCRAMBLE_LENGTH_323;
+ hash_password(hash_pass,password, (uint) strlen(password));
@@ -4602,135 +30838,18369 @@
+ extra=(char) (floor(rnd(&rand_st) * 31));
+ while (to_start != to)
+ *(to_start++)^= extra;
- }
-- *to=0;
++ }
+ *to= 0;
- return to;
- }
-
--
- my_bool check_scramble(const char *scrambled, const char *message,
- ulong *hash_pass, my_bool old_ver)
- {
-
-=== modified file 'libmariadb/safemalloc.c'
---- mariadb/libmysql/safemalloc.c 2012-11-14 17:43:45 +0000
-+++ mariadb/libmariadb/safemalloc.c 2013-03-14 21:01:43 +0000
-@@ -84,7 +84,7 @@
-
- /* Static functions prototypes */
-
--static int check_ptr(const char *where, byte *ptr, const char *sFile,
-+static int check_ptr(const char *where, unsigned char *ptr, const char *sFile,
- uint uLine);
- static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
-
-@@ -199,9 +199,9 @@
- (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
- /* Return a pointer to the real data */
- DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
-- if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
-+ if (sf_min_adress > (unsigned char *)&(pTmp -> aData[sf_malloc_prehunc]))
- sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
-- if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
-+ if (sf_max_adress < (unsigned char *)&(pTmp -> aData[sf_malloc_prehunc]))
- sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
- DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
- }
-@@ -224,7 +224,7 @@
- if (!sf_malloc_quick)
- (void) _sanity (sFile, uLine);
-
-- if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
-+ if (check_ptr("Reallocating",(unsigned char*) pPtr,sFile,uLine))
- DBUG_RETURN((gptr) NULL);
-
- pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)-
-@@ -243,7 +243,7 @@
- if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
- {
- uSize=min(uSize,pRec->uDataSize); /* Move as much as possibly */
-- memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */
-+ memcpy((unsigned char*) ptr,pPtr,(size_t) uSize); /* Copy old data */
- _myfree(pPtr,sFile,uLine,0); /* Free not needed area */
- }
- else
-@@ -272,11 +272,11 @@
- (void) _sanity (sFile, uLine);
-
- if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
-- check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
-+ check_ptr("Freeing",(unsigned char*) pPtr,sFile,uLine))
- DBUG_VOID_RETURN;
-
- /* Calculate the address of the remember structure */
-- pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
-+ pRec = (struct remember *) ((unsigned char*) pPtr-sizeof(struct irem)-
- sf_malloc_prehunc);
-
- /* Check to make sure that we have a real remember structure */
-@@ -325,7 +325,7 @@
-
- /* Check if we have a wrong pointer */
-
--static int check_ptr(const char *where, byte *ptr, const char *sFile,
-+static int check_ptr(const char *where, unsigned char *ptr, const char *sFile,
- uint uLine)
- {
- if (!ptr)
-@@ -502,12 +502,12 @@
-
- /* malloc and copy */
-
--gptr _my_memdup(const byte *from, size_t length, const char *sFile, uint uLine,
-+gptr _my_memdup(const unsigned char *from, size_t length, const char *sFile, uint uLine,
- myf MyFlags)
- {
- gptr ptr;
- if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
-- memcpy((byte*) ptr, (byte*) from, length);
-+ memcpy((unsigned char*) ptr, (unsigned char*) from, length);
- return(ptr);
- } /*_my_memdup */
-
-@@ -518,6 +518,6 @@
- gptr ptr;
- size_t length= strlen(from)+1;
- if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
-- memcpy((byte*) ptr, (byte*) from,(size_t) length);
-+ memcpy((unsigned char*) ptr, (unsigned char*) from,(size_t) length);
- return((my_string) ptr);
- } /* _my_strdup */
-
-=== modified file 'libmariadb/version_script.txt'
---- mariadb/libmysql/version_script.txt 2012-11-28 22:13:00 +0000
-+++ mariadb/libmariadb/version_script.txt 2013-03-14 21:01:43 +0000
-@@ -102,6 +102,8 @@
- mysql_server_end;
- mysql_set_character_set;
- mysql_get_character_set_info;
++ return to;
++}
++
++my_bool check_scramble(const char *scrambled, const char *message,
++ ulong *hash_pass, my_bool old_ver)
++{
++ struct rand_struct rand_st;
++ ulong hash_message[2];
++ char buff[16],*to,extra; /* Big enough for check */
++ const char *pos;
++
++ hash_password(hash_message,message, strlen(message));
++ if (old_ver)
++ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
++ else
++ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
++ hash_pass[1] ^ hash_message[1]);
++ to=buff;
++ for (pos=scrambled ; *pos ; pos++)
++ *to++=(char) (floor(rnd(&rand_st)*31)+64);
++ if (old_ver)
++ extra=0;
++ else
++ extra=(char) (floor(rnd(&rand_st)*31));
++ to=buff;
++ while (*scrambled)
++ {
++ if (*scrambled++ != (char) (*to++ ^ extra))
++ return 1; /* Wrong password */
++ }
++ return 0;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/sha1.c mariadb-native-client.trunk/libmariadb/sha1.c
+--- mariadb/libmariadb/sha1.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/sha1.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,325 @@
++/****************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++*****************************************************************************/
++
++/* This code came from the PHP project, initially written by
++ Stefan Esser */
++
++
++#include "my_global.h"
++#include "string.h"
++
++/* This code is heavily based on the PHP md5 implementation */
++
++#include "sha1.h"
++
++
++static void SHA1Transform(uint32[5], const unsigned char[64]);
++static void SHA1Encode(unsigned char *, uint32 *, unsigned int);
++static void SHA1Decode(uint32 *, const unsigned char *, unsigned int);
++
++static unsigned char PADDING[64] =
++{
++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/* F, G, H and I are basic SHA1 functions.
++ */
++#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
++#define G(x, y, z) ((x) ^ (y) ^ (z))
++#define H(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
++#define I(x, y, z) ((x) ^ (y) ^ (z))
++
++/* ROTATE_LEFT rotates x left n bits.
++ */
++#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
++
++/* W[i]
++ */
++#define W(i) ( tmp=x[(i-3)&15]^x[(i-8)&15]^x[(i-14)&15]^x[i&15], \
++ (x[i&15]=ROTATE_LEFT(tmp, 1)) )
++
++/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
++ */
++#define FF(a, b, c, d, e, w) { \
++ (e) += F ((b), (c), (d)) + (w) + (uint32)(0x5A827999); \
++ (e) += ROTATE_LEFT ((a), 5); \
++ (b) = ROTATE_LEFT((b), 30); \
++ }
++#define GG(a, b, c, d, e, w) { \
++ (e) += G ((b), (c), (d)) + (w) + (uint32)(0x6ED9EBA1); \
++ (e) += ROTATE_LEFT ((a), 5); \
++ (b) = ROTATE_LEFT((b), 30); \
++ }
++#define HH(a, b, c, d, e, w) { \
++ (e) += H ((b), (c), (d)) + (w) + (uint32)(0x8F1BBCDC); \
++ (e) += ROTATE_LEFT ((a), 5); \
++ (b) = ROTATE_LEFT((b), 30); \
++ }
++#define II(a, b, c, d, e, w) { \
++ (e) += I ((b), (c), (d)) + (w) + (uint32)(0xCA62C1D6); \
++ (e) += ROTATE_LEFT ((a), 5); \
++ (b) = ROTATE_LEFT((b), 30); \
++ }
++
++
++/* {{{ MYSQL_SHA1Init
++ * SHA1 initialization. Begins an SHA1 operation, writing a new context.
++ */
++void MYSQL_SHA1Init(MYSQL_SHA1_CTX * context)
++{
++ context->count[0] = context->count[1] = 0;
++ /* Load magic initialization constants.
++ */
++ context->state[0] = 0x67452301;
++ context->state[1] = 0xefcdab89;
++ context->state[2] = 0x98badcfe;
++ context->state[3] = 0x10325476;
++ context->state[4] = 0xc3d2e1f0;
++}
++/* }}} */
++
++/* {{{ MYSQL_SHA1Update
++ SHA1 block update operation. Continues an SHA1 message-digest
++ operation, processing another message block, and updating the
++ context.
++ */
++void MYSQL_SHA1Update(MYSQL_SHA1_CTX * context, const unsigned char *input,
++ size_t inputLen)
++{
++ unsigned int i, index, partLen;
++
++ /* Compute number of bytes mod 64 */
++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
++
++ /* Update number of bits */
++ if ((context->count[0] += ((uint32) inputLen << 3))
++ < ((uint32) inputLen << 3))
++ context->count[1]++;
++ context->count[1] += ((uint32) inputLen >> 29);
++
++ partLen = 64 - index;
++
++ /* Transform as many times as possible.
++ */
++ if (inputLen >= partLen) {
++ memcpy
++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
++ SHA1Transform(context->state, context->buffer);
++
++ for (i = partLen; i + 63 < inputLen; i += 64)
++ SHA1Transform(context->state, &input[i]);
++
++ index = 0;
++ } else
++ i = 0;
++
++ /* Buffer remaining input */
++ memcpy
++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i],
++ inputLen - i);
++}
++/* }}} */
++
++/* {{{ MYSQL_SHA1Final
++ SHA1 finalization. Ends an SHA1 message-digest operation, writing the
++ the message digest and zeroizing the context.
++ */
++void MYSQL_SHA1Final(unsigned char digest[20], MYSQL_SHA1_CTX * context)
++{
++ unsigned char bits[8];
++ unsigned int index, padLen;
++
++ /* Save number of bits */
++ bits[7] = context->count[0] & 0xFF;
++ bits[6] = (context->count[0] >> 8) & 0xFF;
++ bits[5] = (context->count[0] >> 16) & 0xFF;
++ bits[4] = (context->count[0] >> 24) & 0xFF;
++ bits[3] = context->count[1] & 0xFF;
++ bits[2] = (context->count[1] >> 8) & 0xFF;
++ bits[1] = (context->count[1] >> 16) & 0xFF;
++ bits[0] = (context->count[1] >> 24) & 0xFF;
++
++ /* Pad out to 56 mod 64.
++ */
++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
++ padLen = (index < 56) ? (56 - index) : (120 - index);
++ MYSQL_SHA1Update(context, PADDING, padLen);
++
++ /* Append length (before padding) */
++ MYSQL_SHA1Update(context, bits, 8);
++
++ /* Store state in digest */
++ SHA1Encode(digest, context->state, 20);
++
++ /* Zeroize sensitive information.
++ */
++ memset((unsigned char*) context, 0, sizeof(*context));
++}
++/* }}} */
++
++/* {{{ SHA1Transform
++ * SHA1 basic transformation. Transforms state based on block.
++ */
++static void SHA1Transform(uint32 state[5], const unsigned char block[64])
++{
++ uint32 a = state[0], b = state[1], c = state[2];
++ uint32 d = state[3], e = state[4], x[16], tmp;
++
++ SHA1Decode(x, block, 64);
++
++ /* Round 1 */
++ FF(a, b, c, d, e, x[0]); /* 1 */
++ FF(e, a, b, c, d, x[1]); /* 2 */
++ FF(d, e, a, b, c, x[2]); /* 3 */
++ FF(c, d, e, a, b, x[3]); /* 4 */
++ FF(b, c, d, e, a, x[4]); /* 5 */
++ FF(a, b, c, d, e, x[5]); /* 6 */
++ FF(e, a, b, c, d, x[6]); /* 7 */
++ FF(d, e, a, b, c, x[7]); /* 8 */
++ FF(c, d, e, a, b, x[8]); /* 9 */
++ FF(b, c, d, e, a, x[9]); /* 10 */
++ FF(a, b, c, d, e, x[10]); /* 11 */
++ FF(e, a, b, c, d, x[11]); /* 12 */
++ FF(d, e, a, b, c, x[12]); /* 13 */
++ FF(c, d, e, a, b, x[13]); /* 14 */
++ FF(b, c, d, e, a, x[14]); /* 15 */
++ FF(a, b, c, d, e, x[15]); /* 16 */
++ FF(e, a, b, c, d, W(16)); /* 17 */
++ FF(d, e, a, b, c, W(17)); /* 18 */
++ FF(c, d, e, a, b, W(18)); /* 19 */
++ FF(b, c, d, e, a, W(19)); /* 20 */
++
++ /* Round 2 */
++ GG(a, b, c, d, e, W(20)); /* 21 */
++ GG(e, a, b, c, d, W(21)); /* 22 */
++ GG(d, e, a, b, c, W(22)); /* 23 */
++ GG(c, d, e, a, b, W(23)); /* 24 */
++ GG(b, c, d, e, a, W(24)); /* 25 */
++ GG(a, b, c, d, e, W(25)); /* 26 */
++ GG(e, a, b, c, d, W(26)); /* 27 */
++ GG(d, e, a, b, c, W(27)); /* 28 */
++ GG(c, d, e, a, b, W(28)); /* 29 */
++ GG(b, c, d, e, a, W(29)); /* 30 */
++ GG(a, b, c, d, e, W(30)); /* 31 */
++ GG(e, a, b, c, d, W(31)); /* 32 */
++ GG(d, e, a, b, c, W(32)); /* 33 */
++ GG(c, d, e, a, b, W(33)); /* 34 */
++ GG(b, c, d, e, a, W(34)); /* 35 */
++ GG(a, b, c, d, e, W(35)); /* 36 */
++ GG(e, a, b, c, d, W(36)); /* 37 */
++ GG(d, e, a, b, c, W(37)); /* 38 */
++ GG(c, d, e, a, b, W(38)); /* 39 */
++ GG(b, c, d, e, a, W(39)); /* 40 */
++
++ /* Round 3 */
++ HH(a, b, c, d, e, W(40)); /* 41 */
++ HH(e, a, b, c, d, W(41)); /* 42 */
++ HH(d, e, a, b, c, W(42)); /* 43 */
++ HH(c, d, e, a, b, W(43)); /* 44 */
++ HH(b, c, d, e, a, W(44)); /* 45 */
++ HH(a, b, c, d, e, W(45)); /* 46 */
++ HH(e, a, b, c, d, W(46)); /* 47 */
++ HH(d, e, a, b, c, W(47)); /* 48 */
++ HH(c, d, e, a, b, W(48)); /* 49 */
++ HH(b, c, d, e, a, W(49)); /* 50 */
++ HH(a, b, c, d, e, W(50)); /* 51 */
++ HH(e, a, b, c, d, W(51)); /* 52 */
++ HH(d, e, a, b, c, W(52)); /* 53 */
++ HH(c, d, e, a, b, W(53)); /* 54 */
++ HH(b, c, d, e, a, W(54)); /* 55 */
++ HH(a, b, c, d, e, W(55)); /* 56 */
++ HH(e, a, b, c, d, W(56)); /* 57 */
++ HH(d, e, a, b, c, W(57)); /* 58 */
++ HH(c, d, e, a, b, W(58)); /* 59 */
++ HH(b, c, d, e, a, W(59)); /* 60 */
++
++ /* Round 4 */
++ II(a, b, c, d, e, W(60)); /* 61 */
++ II(e, a, b, c, d, W(61)); /* 62 */
++ II(d, e, a, b, c, W(62)); /* 63 */
++ II(c, d, e, a, b, W(63)); /* 64 */
++ II(b, c, d, e, a, W(64)); /* 65 */
++ II(a, b, c, d, e, W(65)); /* 66 */
++ II(e, a, b, c, d, W(66)); /* 67 */
++ II(d, e, a, b, c, W(67)); /* 68 */
++ II(c, d, e, a, b, W(68)); /* 69 */
++ II(b, c, d, e, a, W(69)); /* 70 */
++ II(a, b, c, d, e, W(70)); /* 71 */
++ II(e, a, b, c, d, W(71)); /* 72 */
++ II(d, e, a, b, c, W(72)); /* 73 */
++ II(c, d, e, a, b, W(73)); /* 74 */
++ II(b, c, d, e, a, W(74)); /* 75 */
++ II(a, b, c, d, e, W(75)); /* 76 */
++ II(e, a, b, c, d, W(76)); /* 77 */
++ II(d, e, a, b, c, W(77)); /* 78 */
++ II(c, d, e, a, b, W(78)); /* 79 */
++ II(b, c, d, e, a, W(79)); /* 80 */
++
++ state[0] += a;
++ state[1] += b;
++ state[2] += c;
++ state[3] += d;
++ state[4] += e;
++
++ /* Zeroize sensitive information. */
++ memset((unsigned char*) x, 0, sizeof(x));
++}
++/* }}} */
++
++/* {{{ SHA1Encode
++ Encodes input (uint32) into output (unsigned char). Assumes len is
++ a multiple of 4.
++ */
++static void SHA1Encode(unsigned char *output, uint32 *input, unsigned int len)
++{
++ unsigned int i, j;
++
++ for (i = 0, j = 0; j < len; i++, j += 4) {
++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff);
++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff);
++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff);
++ output[j + 3] = (unsigned char) (input[i] & 0xff);
++ }
++}
++/* }}} */
++
++/* {{{ SHA1Decode
++ Decodes input (unsigned char) into output (uint32). Assumes len is
++ a multiple of 4.
++ */
++static void SHA1Decode(uint32 *output, const unsigned char * input, unsigned int len)
++{
++ unsigned int i, j;
++
++ for (i = 0, j = 0; j < len; i++, j += 4)
++ output[i] = ((uint32) input[j + 3]) | (((uint32) input[j + 2]) << 8) |
++ (((uint32) input[j + 1]) << 16) | (((uint32) input[j]) << 24);
++}
++/* }}} */
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: sw=4 ts=4 fdm=marker
++ * vim<600: sw=4 ts=4
++ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/str2int.c mariadb-native-client.trunk/libmariadb/str2int.c
+--- mariadb/libmariadb/str2int.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/str2int.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,202 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ str2int(src, radix, lower, upper, &val)
++ converts the string pointed to by src to an integer and stores it in
++ val. It skips leading spaces and tabs (but not newlines, formfeeds,
++ backspaces), then it accepts an optional sign and a sequence of digits
++ in the specified radix. The result should satisfy lower <= *val <= upper.
++ The result is a pointer to the first character after the number;
++ trailing spaces will NOT be skipped.
++
++ If an error is detected, the result will be NullS, the value put
++ in val will be 0, and errno will be set to
++ EDOM if there are no digits
++ ERANGE if the result would overflow or otherwise fail to lie
++ within the specified bounds.
++ Check that the bounds are right for your machine.
++ This looks amazingly complicated for what you probably thought was an
++ easy task. Coping with integer overflow and the asymmetric range of
++ twos complement machines is anything but easy.
++
++ So that users of atoi and atol can check whether an error occured,
++ I have taken a wholly unprecedented step: errno is CLEARED if this
++ call has no problems.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++#include "m_ctype.h"
++#include "my_sys.h" /* defines errno */
++#include <errno.h>
++
++#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
++ X >= 'A' && X <= 'Z' ? X-'A'+10 :\
++ X >= 'a' && X <= 'z' ? X-'a'+10 :\
++ '\177')
++
++char *str2int(register const char *src, register int radix, long int lower, long int upper, long int *val)
++{
++ int sign; /* is number negative (+1) or positive (-1) */
++ int n; /* number of digits yet to be converted */
++ long limit; /* "largest" possible valid input */
++ long scale; /* the amount to multiply next digit by */
++ long sofar; /* the running value */
++ register int d; /* (negative of) next digit */
++ char *start;
++ int digits[32]; /* Room for numbers */
++
++ /* Make sure *val is sensible in case of error */
++
++ *val = 0;
++
++ /* Check that the radix is in the range 2..36 */
++
++#ifndef DBUG_OFF
++ if (radix < 2 || radix > 36) {
++ errno=EDOM;
++ return NullS;
++ }
++#endif
++
++ /* The basic problem is: how do we handle the conversion of
++ a number without resorting to machine-specific code to
++ check for overflow? Obviously, we have to ensure that
++ no calculation can overflow. We are guaranteed that the
++ "lower" and "upper" arguments are valid machine integers.
++ On sign-and-magnitude, twos-complement, and ones-complement
++ machines all, if +|n| is representable, so is -|n|, but on
++ twos complement machines the converse is not true. So the
++ "maximum" representable number has a negative representative.
++ Limit is set to min(-|lower|,-|upper|); this is the "largest"
++ number we are concerned with. */
++
++ /* Calculate Limit using Scale as a scratch variable */
++
++ if ((limit = lower) > 0) limit = -limit;
++ if ((scale = upper) > 0) scale = -scale;
++ if (scale < limit) limit = scale;
++
++ /* Skip leading spaces and check for a sign.
++ Note: because on a 2s complement machine MinLong is a valid
++ integer but |MinLong| is not, we have to keep the current
++ converted value (and the scale!) as *negative* numbers,
++ so the sign is the opposite of what you might expect.
++ */
++ while (isspace(*src)) src++;
++ sign = -1;
++ if (*src == '+') src++; else
++ if (*src == '-') src++, sign = 1;
++
++ /* Skip leading zeros so that we never compute a power of radix
++ in scale that we won't have a need for. Otherwise sticking
++ enough 0s in front of a number could cause the multiplication
++ to overflow when it neededn't.
++ */
++ start=(char*) src;
++ while (*src == '0') src++;
++
++ /* Move over the remaining digits. We have to convert from left
++ to left in order to avoid overflow. Answer is after last digit.
++ */
++
++ for (n = 0; (digits[n]=char_val(*src)) < radix && n < 20; n++,src++) ;
++
++ /* Check that there is at least one digit */
++
++ if (start == src) {
++ errno=EDOM;
++ return NullS;
++ }
++
++ /* The invariant we want to maintain is that src is just
++ to the right of n digits, we've converted k digits to
++ sofar, scale = -radix**k, and scale < sofar < 0. Now
++ if the final number is to be within the original
++ Limit, we must have (to the left)*scale+sofar >= Limit,
++ or (to the left)*scale >= Limit-sofar, i.e. the digits
++ to the left of src must form an integer <= (Limit-sofar)/(scale).
++ In particular, this is true of the next digit. In our
++ incremental calculation of Limit,
++
++ IT IS VITAL that (-|N|)/(-|D|) = |N|/|D|
++ */
++
++ for (sofar = 0, scale = -1; --n >= 1;)
++ {
++ if ((long) -(d=digits[n]) < limit) {
++ errno=ERANGE;
++ return NullS;
++ }
++ limit = (limit+d)/radix, sofar += d*scale; scale *= radix;
++ }
++ if (n == 0)
++ {
++ if ((long) -(d=digits[n]) < limit) /* get last digit */
++ {
++ errno=ERANGE;
++ return NullS;
++ }
++ sofar+=d*scale;
++ }
++
++ /* Now it might still happen that sofar = -32768 or its equivalent,
++ so we can't just multiply by the sign and check that the result
++ is in the range lower..upper. All of this caution is a right
++ pain in the neck. If only there were a standard routine which
++ says generate thus and such a signal on integer overflow...
++ But not enough machines can do it *SIGH*.
++ */
++ if (sign < 0)
++ {
++ if (sofar < -LONG_MAX || (sofar= -sofar) > upper)
++ {
++ errno=ERANGE;
++ return NullS;
++ }
++ }
++ else if (sofar < lower)
++ {
++ errno=ERANGE;
++ return NullS;
++ }
++ *val = sofar;
++ errno=0; /* indicate that all went well */
++ return (char*) src;
++}
++
++ /* Theese are so slow compared with ordinary, optimized atoi */
++
++#ifdef WANT_OUR_ATOI
++
++int atoi(const char *src)
++{
++ long val;
++ str2int(src, 10, (long) INT_MIN, (long) INT_MAX, &val);
++ return (int) val;
++}
++
++
++long atol(const char *src)
++{
++ long val;
++ str2int(src, 10, LONG_MIN, LONG_MAX, &val);
++ return val;
++}
++
++#endif /* WANT_OUR_ATOI */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strcend.c mariadb-native-client.trunk/libmariadb/strcend.c
+--- mariadb/libmariadb/strcend.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strcend.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,48 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strcend.c
++ Author : Michael Widenius: ifdef MC68000
++ Updated: 20 April 1984
++ Defines: strcend()
++
++ strcend(s, c) returns a pointer to the first place in s where c
++ occurs, or a pointer to the end-null of s if c does not occur in s.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++/**
++ \fn char *strcend
++ \brief returns a pointer to the first occurence of specified stopchar
++ \param str char *
++ \param stopchar char
++
++ returns a poimter to the first occurence of stopchar or to null char,
++ if stopchar wasn't found.
++*/
++char *strcend(register const char *str, register char stopchar)
++{
++ for (;;)
++ {
++ if (*str == stopchar)
++ return (char*) str;
++ if (!*str++)
++ return (char*) str-1;
++ }
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strcont.c mariadb-native-client.trunk/libmariadb/strcont.c
+--- mariadb/libmariadb/strcont.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strcont.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,46 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strcont.c
++ Author : Monty
++ Updated: 1988.07.27
++ Defines: strcont()
++
++ strcont(str, set) if str contanies any character in the string set.
++ The result is the position of the first found character in str, or NullS
++ if there isn't anything found.
++
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++my_string strcont(reg1 const char *str,reg2 const char *set)
++{
++ reg3 my_string start = (my_string) set;
++
++ while (*str)
++ {
++ while (*set)
++ {
++ if (*set++ == *str)
++ return ((char*) str);
++ }
++ set=start; str++;
++ }
++ return (NullS);
++} /* strcont */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strend.c mariadb-native-client.trunk/libmariadb/strend.c
+--- mariadb/libmariadb/strend.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strend.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,50 @@
++/* Copyright (C) 2002 MySQL AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strend.c
++ Author : Richard A. O'Keefe.
++ Updated: 23 April 1984
++ Defines: strend()
++
++ strend(s) returns a character pointer to the NUL which ends s. That
++ is, strend(s)-s == strlen(s). This is useful for adding things at
++ the end of strings. It is redundant, because strchr(s,'\0') could
++ be used instead, but this is clearer and faster.
++ Beware: the asm version works only if strlen(s) < 65535.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#if VaxAsm
++
++char *strend(s)
++const char *s;
++{
++ asm("locc $0,$65535,*4(ap)");
++ asm("movl r1,r0");
++}
++
++#else /* ~VaxAsm */
++
++char *strend(register const char *s)
++{
++ while (*s++);
++ return (char*) (s-1);
++}
++
++#endif /* VaxAsm */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strfill.c mariadb-native-client.trunk/libmariadb/strfill.c
+--- mariadb/libmariadb/strfill.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strfill.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strfill.c
++ Author : Monty
++ Updated: 1987.04.16
++ Defines: strfill()
++
++ strfill(dest, len, fill) makes a string of fill-characters. The result
++ string is of length == len. The des+len character is allways set to NULL.
++ strfill() returns pointer to dest+len;
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++my_string strfill(my_string s, size_t len, pchar fill)
++{
++ while (len--) *s++ = fill;
++ *(s) = '\0';
++ return(s);
++} /* strfill */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/string.c mariadb-native-client.trunk/libmariadb/string.c
+--- mariadb/libmariadb/string.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/string.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,127 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Code for handling strings with can grow dynamicly.
++ Copyright Monty Program KB.
++ By monty.
++*/
++
++#include "mysys_priv.h"
++#include <m_string.h>
++
++my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
++ size_t init_alloc, size_t alloc_increment)
++{
++ uint length;
++ DBUG_ENTER("init_dynamic_string");
++
++ if (!alloc_increment)
++ alloc_increment=128;
++ length=1;
++ if (init_str && (length= (uint) strlen(init_str)+1) < init_alloc)
++ init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
++ if (!init_alloc)
++ init_alloc=alloc_increment;
++
++ if (!(str->str=(char*) my_malloc(init_alloc,MYF(MY_WME))))
++ DBUG_RETURN(TRUE);
++ str->length=length-1;
++ if (init_str)
++ memcpy(str->str,init_str,length);
++ str->max_length=init_alloc;
++ str->alloc_increment=alloc_increment;
++ DBUG_RETURN(FALSE);
++}
++
++
++my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
++{
++ uint length;
++ DBUG_ENTER("dynstr_set");
++
++ if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length)
++ {
++ str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)*
++ str->alloc_increment;
++ if (!str->max_length)
++ str->max_length=str->alloc_increment;
++ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
++ DBUG_RETURN(TRUE);
++ }
++ if (init_str)
++ {
++ str->length=length-1;
++ memcpy(str->str,init_str,length);
++ }
++ else
++ str->length=0;
++ DBUG_RETURN(FALSE);
++}
++
++
++my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size)
++{
++ DBUG_ENTER("dynstr_realloc");
++
++ if (!additional_size) DBUG_RETURN(FALSE);
++ if (str->length + additional_size > str->max_length)
++ {
++ str->max_length=((str->length + additional_size+str->alloc_increment-1)/
++ str->alloc_increment)*str->alloc_increment;
++ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
++ DBUG_RETURN(TRUE);
++ }
++ DBUG_RETURN(FALSE);
++}
++
++
++my_bool dynstr_append(DYNAMIC_STRING *str, const char *append)
++{
++ return dynstr_append_mem(str,append,strlen(append));
++}
++
++
++my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
++ size_t length)
++{
++ char *new_ptr;
++ if (str->length+length >= str->max_length)
++ {
++ size_t new_length=(str->length+length+str->alloc_increment)/
++ str->alloc_increment;
++ new_length*=str->alloc_increment;
++ if (!(new_ptr=(char*) my_realloc(str->str,new_length,MYF(MY_WME))))
++ return TRUE;
++ str->str=new_ptr;
++ str->max_length=new_length;
++ }
++ memcpy(str->str + str->length,append,length);
++ str->length+=length;
++ str->str[str->length]=0; /* Safety for C programs */
++ return FALSE;
++}
++
++
++void dynstr_free(DYNAMIC_STRING *str)
++{
++ if (str->str)
++ {
++ my_free(str->str,MYF(MY_WME));
++ str->str=0;
++ }
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strinstr.c mariadb-native-client.trunk/libmariadb/strinstr.c
+--- mariadb/libmariadb/strinstr.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strinstr.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,50 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strinstr.c
++ Author : Monty & David
++ Updated: 1986.12.08
++ Defines: strinstr()
++
++ strinstr(src, pat) looks for an instance of pat in src. pat is not a
++ regex(3) pattern, it is a literal string which must be matched exactly.
++ The result 0 if the pattern was not found else it is the start char of
++ the pattern counted from the beginning of the string, where the first
++ char is 1.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++uint strinstr(reg1 const char *str,reg4 const char *search)
++{
++ reg2 my_string i,j;
++ my_string start = (my_string) str;
++
++ skipp:
++ while (*str != '\0')
++ {
++ if (*str++ == *search)
++ {
++ i=(my_string) str; j= (my_string) search+1;
++ while (*j)
++ if (*i++ != *j++) goto skipp;
++ return ((uint) (str - start));
++ }
++ }
++ return (0);
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strmake.c mariadb-native-client.trunk/libmariadb/strmake.c
+--- mariadb/libmariadb/strmake.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strmake.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,54 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strmake.c
++ Author : Michael Widenius
++ Updated: 20 Jul 1984
++ Defines: strmake()
++
++ strmake(dst,src,length) moves length characters, or until end, of src to
++ dst and appends a closing NUL to dst.
++ Note that is strlen(src) >= length then dst[length] will be set to \0
++ strmake() returns pointer to closing null
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#ifdef BAD_STRING_COMPILER
++
++char *strmake(char *dst,const char *src, size_t length)
++{
++ reg1 char *res;
++
++ if ((res=memccpy(dst,src,0,length)))
++ return res-1;
++ dst[length]=0;
++ return dst+length;
++}
++
++#define strmake strmake_overlapp /* Use orginal for overlapping str */
++#endif
++
++char *strmake(register char *dst, register const char *src, size_t length)
++{
++ while (length--)
++ if (! (*dst++ = *src++))
++ return dst-1;
++ *dst=0;
++ return dst;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strmov.c mariadb-native-client.trunk/libmariadb/strmov.c
+--- mariadb/libmariadb/strmov.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strmov.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,59 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ strmov(dst, src) moves all the characters of src (including the
++ closing NUL) to dst, and returns a pointer to the new closing NUL in
++ dst. The similar UNIX routine strcpy returns the old value of dst,
++ which I have never found useful. strmov(strmov(dst,a),b) moves a//b
++ into dst, which seems useful.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#ifdef BAD_STRING_COMPILER
++#undef strmov
++#define strmov strmov_overlapp
++#endif
++
++#ifndef strmov
++
++#if !defined(MC68000) && !defined(DS90)
++
++char *strmov(register char *dst, register const char *src)
++{
++ while ((*dst++ = *src++)) ;
++ return dst-1;
++}
++
++#else
++
++char *strmov(dst, src)
++ char *dst, *src;
++{
++ asm(" movl 4(a7),a1 ");
++ asm(" movl 8(a7),a0 ");
++ asm(".L4: movb (a0)+,(a1)+ ");
++ asm(" jne .L4 ");
++ asm(" movl a1,d0 ");
++ asm(" subql #1,d0 ");
++}
++
++#endif
++
++#endif /* strmov */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strnlen.c mariadb-native-client.trunk/libmariadb/strnlen.c
+--- mariadb/libmariadb/strnlen.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strnlen.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strnlen.c
++ Author : Michael Widenius
++ Updated: 20 April 1984
++ Defines: strnlen.
++ strnlen(s, len) returns the length of s or len if s is longer than len.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++#ifndef HAVE_STRNLEN
++
++uint strnlen(register const char *s, register uint maxlen)
++{
++ const char *end= (const char *)memchr(s, '\0', maxlen);
++ return end ? (uint) (end - s) : maxlen;
++}
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strnmov.c mariadb-native-client.trunk/libmariadb/strnmov.c
+--- mariadb/libmariadb/strnmov.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strnmov.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,36 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ strnmov(dst,src,length) moves length characters, or until end, of src to
++ dst and appends a closing NUL to dst if src is shorter than length.
++ The result is a pointer to the first NUL in dst, or is dst+n if dst was
++ truncated.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++
++char *strnmov(register char *dst, register const char *src, uint n)
++{
++ while (n-- != 0) {
++ if (!(*dst++ = *src++)) {
++ return (char*) dst-1;
++ }
++ }
++ return dst;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strto.c mariadb-native-client.trunk/libmariadb/strto.c
+--- mariadb/libmariadb/strto.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strto.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,210 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ strtol,strtoul,strtoll,strtoull
++ convert string to long, unsigned long, long long or unsigned long long.
++ strtoxx(char *src,char **ptr,int base)
++ converts the string pointed to by src to an long of appropriate long and
++ returnes it. It skips leading spaces and tabs (but not newlines, formfeeds,
++ backspaces), then it accepts an optional sign and a sequence of digits
++ in the specified radix.
++ If the value of ptr is not (char **)NULL, a pointer to the character
++ terminating the scan is returned in the location pointed to by ptr.
++ Trailing spaces will NOT be skipped.
++
++ If an error is detected, the result will be LONG_MIN, 0 or LONG_MAX,
++ (or LONGLONG..) and errno will be set to
++ EDOM if there are no digits
++ ERANGE if the result would overflow.
++ the ptr will be set to src.
++ This file is based on the strtol from the the GNU C Library.
++ it can be compiled with the UNSIGNED and/or LONGLONG flag set
++*/
++
++#define strtoll glob_strtoll /* Fix for True64 */
++
++#include <global.h>
++#include "m_string.h"
++#include "m_ctype.h"
++#include "my_sys.h" /* defines errno */
++#include <errno.h>
++
++#undef strtoull
++#undef strtoll
++#undef strtoul
++#undef strtol
++#ifdef USE_LONGLONG
++#define UTYPE_MAX (~(ulonglong) 0)
++#define TYPE_MIN LONGLONG_MIN
++#define TYPE_MAX LONGLONG_MAX
++#define longtype longlong
++#define ulongtype ulonglong
++#ifdef USE_UNSIGNED
++#define function ulongtype strtoull
++#else
++#define function longtype strtoll
++#endif
++#else
++#define UTYPE_MAX (ulong) ~0L
++#define TYPE_MIN LONG_MIN
++#define TYPE_MAX LONG_MAX
++#define longtype long
++#define ulongtype unsigned long
++#ifdef USE_UNSIGNED
++#define function ulongtype strtoul
++#else
++#define function longtype strtol
++#endif
++#endif
++
++
++/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
++ If BASE is 0 the base is determined by the presence of a leading
++ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
++ If BASE is < 2 or > 36, it is reset to 10.
++ If ENDPTR is not NULL, a pointer to the character after the last
++ one converted is stored in *ENDPTR. */
++
++
++function (const char *nptr,char **endptr,int base)
++{
++ int negative;
++ register ulongtype cutoff;
++ register unsigned int cutlim;
++ register ulongtype i;
++ register const char *s;
++ register unsigned char c;
++ const char *save;
++ int overflow;
++
++ if (base < 0 || base == 1 || base > 36)
++ base = 10;
++
++ s = nptr;
++
++ /* Skip white space. */
++ while (isspace (*s))
++ ++s;
++ if (*s == '\0')
++ {
++ goto noconv;
++ }
++
++ /* Check for a sign. */
++ if (*s == '-')
++ {
++ negative = 1;
++ ++s;
++ }
++ else if (*s == '+')
++ {
++ negative = 0;
++ ++s;
++ }
++ else
++ negative = 0;
++
++ if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
++ s += 2;
++
++ /* If BASE is zero, figure it out ourselves. */
++ if (base == 0)
++ {
++ if (*s == '0')
++ {
++ if (toupper (s[1]) == 'X')
++ {
++ s += 2;
++ base = 16;
++ }
++ else
++ base = 8;
++ }
++ else
++ base = 10;
++ }
++
++ /* Save the pointer so we can check later if anything happened. */
++ save = s;
++
++ cutoff = UTYPE_MAX / (unsigned long int) base;
++ cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
++
++ overflow = 0;
++ i = 0;
++ for (c = *s; c != '\0'; c = *++s)
++ {
++ if (isdigit (c))
++ c -= '0';
++ else if (isalpha (c))
++ c = toupper (c) - 'A' + 10;
++ else
++ break;
++ if (c >= base)
++ break;
++ /* Check for overflow. */
++ if (i > cutoff || (i == cutoff && c > cutlim))
++ overflow = 1;
++ else
++ {
++ i *= (ulongtype) base;
++ i += c;
++ }
++ }
++
++ /* Check if anything actually happened. */
++ if (s == save)
++ goto noconv;
++
++ /* Store in ENDPTR the address of one character
++ past the last character we converted. */
++ if (endptr != NULL)
++ *endptr = (char *) s;
++
++#ifndef USE_UNSIGNED
++ /* Check for a value that is within the range of
++ `unsigned long int', but outside the range of `long int'. */
++ if (negative)
++ {
++ if (i > (ulongtype) TYPE_MIN)
++ overflow = 1;
++ }
++ else if (i > (ulongtype) TYPE_MAX)
++ overflow = 1;
++#endif
++
++ if (overflow)
++ {
++ my_errno=ERANGE;
++#ifdef USE_UNSIGNED
++ return UTYPE_MAX;
++#else
++ return negative ? TYPE_MIN : TYPE_MAX;
++#endif
++ }
++
++ /* Return the result of the appropriate sign. */
++ return (negative ? -((longtype) i) : (longtype) i);
++
++noconv:
++ /* There was no number to convert. */
++ my_errno=EDOM;
++ if (endptr != NULL)
++ *endptr = (char *) nptr;
++ return 0L;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strtoll.c mariadb-native-client.trunk/libmariadb/strtoll.c
+--- mariadb/libmariadb/strtoll.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strtoll.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,199 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* This is defines strtoll() if neaded */
++
++#include <my_global.h>
++#include <m_string.h>
++#if !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
++#define USE_LONGLONG
++
++#define strtoll glob_strtoll /* Fix for True64 */
++
++#include <global.h>
++#include "m_string.h"
++#include "m_ctype.h"
++#include "my_sys.h" /* defines errno */
++#include <errno.h>
++
++#undef strtoull
++#undef strtoll
++#undef strtoul
++#undef strtol
++#ifdef USE_LONGLONG
++#define UTYPE_MAX (~(ulonglong) 0)
++#define TYPE_MIN LONGLONG_MIN
++#define TYPE_MAX LONGLONG_MAX
++#define longtype longlong
++#define ulongtype ulonglong
++#ifdef USE_UNSIGNED
++#define function ulongtype strtoull
++#else
++#define function longtype strtoll
++#endif
++#else
++#define UTYPE_MAX (ulong) ~0L
++#define TYPE_MIN LONG_MIN
++#define TYPE_MAX LONG_MAX
++#define longtype long
++#define ulongtype unsigned long
++#ifdef USE_UNSIGNED
++#define function ulongtype strtoul
++#else
++#define function longtype strtol
++#endif
++#endif
++
++
++/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
++ If BASE is 0 the base is determined by the presence of a leading
++ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
++ If BASE is < 2 or > 36, it is reset to 10.
++ If ENDPTR is not NULL, a pointer to the character after the last
++ one converted is stored in *ENDPTR. */
++
++
++function (const char *nptr,char **endptr,int base)
++{
++ int negative;
++ register ulongtype cutoff;
++ register unsigned int cutlim;
++ register ulongtype i;
++ register const char *s;
++ register unsigned char c;
++ const char *save;
++ int overflow;
++
++ if (base < 0 || base == 1 || base > 36)
++ base = 10;
++
++ s = nptr;
++
++ /* Skip white space. */
++ while (isspace (*s))
++ ++s;
++ if (*s == '\0')
++ {
++ goto noconv;
++ }
++
++ /* Check for a sign. */
++ if (*s == '-')
++ {
++ negative = 1;
++ ++s;
++ }
++ else if (*s == '+')
++ {
++ negative = 0;
++ ++s;
++ }
++ else
++ negative = 0;
++
++ if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
++ s += 2;
++
++ /* If BASE is zero, figure it out ourselves. */
++ if (base == 0)
++ {
++ if (*s == '0')
++ {
++ if (toupper (s[1]) == 'X')
++ {
++ s += 2;
++ base = 16;
++ }
++ else
++ base = 8;
++ }
++ else
++ base = 10;
++ }
++
++ /* Save the pointer so we can check later if anything happened. */
++ save = s;
++
++ cutoff = UTYPE_MAX / (unsigned long int) base;
++ cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
++
++ overflow = 0;
++ i = 0;
++ for (c = *s; c != '\0'; c = *++s)
++ {
++ if (isdigit (c))
++ c -= '0';
++ else if (isalpha (c))
++ c = toupper (c) - 'A' + 10;
++ else
++ break;
++ if (c >= base)
++ break;
++ /* Check for overflow. */
++ if (i > cutoff || (i == cutoff && c > cutlim))
++ overflow = 1;
++ else
++ {
++ i *= (ulongtype) base;
++ i += c;
++ }
++ }
++
++ /* Check if anything actually happened. */
++ if (s == save)
++ goto noconv;
++
++ /* Store in ENDPTR the address of one character
++ past the last character we converted. */
++ if (endptr != NULL)
++ *endptr = (char *) s;
++
++#ifndef USE_UNSIGNED
++ /* Check for a value that is within the range of
++ `unsigned long int', but outside the range of `long int'. */
++ if (negative)
++ {
++ if (i > (ulongtype) TYPE_MIN)
++ overflow = 1;
++ }
++ else if (i > (ulongtype) TYPE_MAX)
++ overflow = 1;
++#endif
++
++ if (overflow)
++ {
++ my_errno=ERANGE;
++#ifdef USE_UNSIGNED
++ return UTYPE_MAX;
++#else
++ return negative ? TYPE_MIN : TYPE_MAX;
++#endif
++ }
++
++ /* Return the result of the appropriate sign. */
++ return (negative ? -((longtype) i) : (longtype) i);
++
++noconv:
++ /* There was no number to convert. */
++ my_errno=EDOM;
++ if (endptr != NULL)
++ *endptr = (char *) nptr;
++ return 0L;
++}
++
++
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strtoull.c mariadb-native-client.trunk/libmariadb/strtoull.c
+--- mariadb/libmariadb/strtoull.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strtoull.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,26 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* This is defines strtoull() */
++
++#include <my_global.h>
++#include <m_string.h>
++#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
++#define USE_UNSIGNED
++#define USE_LONGLONG
++#include "strto.c"
++#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strxmov.c mariadb-native-client.trunk/libmariadb/strxmov.c
+--- mariadb/libmariadb/strxmov.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strxmov.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,50 @@
++/* Copyright (C) 2002 MySQL AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* File : strxmov.c
++ Author : Richard A. O'Keefe.
++ Updated: 25 may 1984
++ Defines: strxmov()
++
++ strxmov(dst, src1, ..., srcn, NullS)
++ moves the concatenation of src1,...,srcn to dst, terminates it
++ with a NUL character, and returns a pointer to the terminating NUL.
++ It is just like strmov except that it concatenates multiple sources.
++ Beware: the last argument should be the null character pointer.
++ Take VERY great care not to omit it! Also be careful to use NullS
++ and NOT to use 0, as on some machines 0 is not the same size as a
++ character pointer, or not the same bit pattern as NullS.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++#include <stdarg.h>
++
++char *strxmov(char *dst,const char *src, ...)
++{
++ va_list pvar;
++
++ va_start(pvar,src);
++ while (src != NullS) {
++ while ((*dst++ = *src++)) ;
++ dst--;
++ src = va_arg(pvar, char *);
++ }
++ va_end(pvar);
++ *dst = 0; /* there might have been no sources! */
++ return dst;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/strxnmov.c mariadb-native-client.trunk/libmariadb/strxnmov.c
+--- mariadb/libmariadb/strxnmov.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/strxnmov.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,48 @@
++/* File : strxnmov.c
++ Author : Richard A. O'Keefe.
++ Updated: 2 June 1984
++ Defines: strxnmov()
++
++ strxnmov(dst, len, src1, ..., srcn, NullS)
++ moves the first len characters of the concatenation of src1,...,srcn
++ to dst. If there aren't that many characters, a NUL character will
++ be added to the end of dst to terminate it properly. This gives the
++ same effect as calling strxcpy(buff, src1, ..., srcn, NullS) with a
++ large enough buffer, and then calling strnmov(dst, buff, len).
++ It is just like strnmov except that it concatenates multiple sources.
++ Beware: the last argument should be the null character pointer.
++ Take VERY great care not to omit it! Also be careful to use NullS
++ and NOT to use 0, as on some machines 0 is not the same size as a
++ character pointer, or not the same bit pattern as NullS.
++
++ Note: strxnmov is like strnmov in that it moves up to len
++ characters; dst will be padded on the right with one NUL characters if
++ needed.
++*/
++
++#include <my_global.h>
++#include "m_string.h"
++#include <stdarg.h>
++
++char *strxnmov(char *dst, size_t len, const char *src, ...)
++{
++ va_list pvar;
++ char *end_of_dst=dst+len;
++
++ va_start(pvar,src);
++ while (src != NullS)
++ {
++ do
++ {
++ if (dst == end_of_dst)
++ goto end;
++ }
++ while ((*dst++ = *src++));
++ dst--;
++ src = va_arg(pvar, char *);
++ }
++ *dst=0;
++end:
++ va_end(pvar);
++ return dst;
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/thr_mutex.c mariadb-native-client.trunk/libmariadb/thr_mutex.c
+--- mariadb/libmariadb/thr_mutex.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/thr_mutex.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,231 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* This makes a wrapper for mutex handling to make it easier to debug mutex */
++
++#include <my_global.h>
++#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98)
++#define __USE_UNIX98 /* To get rw locks under Linux */
++#endif
++#include <m_string.h>
++#if defined(THREAD) && defined(SAFE_MUTEX)
++#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
++#include <my_pthread.h>
++
++#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
++/* Remove wrappers */
++#undef pthread_mutex_init
++#undef pthread_mutex_lock
++#undef pthread_mutex_unlock
++#undef pthread_mutex_destroy
++#undef pthread_cond_wait
++#undef pthread_cond_timedwait
++#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
++#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
++#endif
++#endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */
++
++int safe_mutex_init(safe_mutex_t *mp,
++ const pthread_mutexattr_t *attr __attribute__((unused)))
++{
++ bzero((char*) mp,sizeof(*mp));
++ pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
++ pthread_mutex_init(&mp->mutex,attr);
++ return 0;
++}
++
++int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
++{
++ int error;
++ pthread_mutex_lock(&mp->global);
++ if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
++ {
++ fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d\n",
++ file,line,mp->file,mp->line);
++ fflush(stderr);
++ abort();
++ }
++ pthread_mutex_unlock(&mp->global);
++ error=pthread_mutex_lock(&mp->mutex);
++ if (error || (error=pthread_mutex_lock(&mp->global)))
++ {
++ fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
++ error, file, line);
++ fflush(stderr);
++ abort();
++ }
++ if (mp->count++)
++ {
++ fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, line %d more than 1 time\n", file,line);
++ fflush(stderr);
++ abort();
++ }
++ mp->thread=pthread_self();
++ mp->file= (char*) file;
++ mp->line=line;
++ pthread_mutex_unlock(&mp->global);
++ return error;
++}
++
++
++int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
++{
++ int error;
++ pthread_mutex_lock(&mp->global);
++ if (mp->count == 0)
++ {
++ fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n Last used at %s, line: %d\n",
++ file,line,mp->file ? mp->file : "",mp->line);
++ fflush(stderr);
++ abort();
++ }
++ if (!pthread_equal(pthread_self(),mp->thread))
++ {
++ fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
++ file,line,mp->file,mp->line);
++ fflush(stderr);
++ abort();
++ }
++ mp->count--;
++#ifdef _WIN32
++ pthread_mutex_unlock(&mp->mutex);
++ error=0;
++#else
++ error=pthread_mutex_unlock(&mp->mutex);
++ if (error)
++ {
++ fprintf(stderr,"safe_mutex: Got error: %d when trying to unlock mutex at %s, line %d\n", error, file, line);
++ fflush(stderr);
++ abort();
++ }
++#endif /* _WIN32 */
++ pthread_mutex_unlock(&mp->global);
++ return error;
++}
++
++
++int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
++ uint line)
++{
++ int error;
++ pthread_mutex_lock(&mp->global);
++ if (mp->count == 0)
++ {
++ fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
++ fflush(stderr);
++ abort();
++ }
++ if (!pthread_equal(pthread_self(),mp->thread))
++ {
++ fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
++ file,line,mp->file,mp->line);
++ fflush(stderr);
++ abort();
++ }
++
++ if (mp->count-- != 1)
++ {
++ fprintf(stderr,"safe_mutex: Count was %d on locked mutex at %s, line %d\n",
++ mp->count+1, file, line);
++ fflush(stderr);
++ abort();
++ }
++ pthread_mutex_unlock(&mp->global);
++ error=pthread_cond_wait(cond,&mp->mutex);
++ pthread_mutex_lock(&mp->global);
++ if (error)
++ {
++ fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_wait at %s, line %d\n", error, file, line);
++ fflush(stderr);
++ abort();
++ }
++ if (mp->count++)
++ {
++ fprintf(stderr,
++ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d\n",
++ mp->count-1, my_thread_id(), file, line);
++ fflush(stderr);
++ abort();
++ }
++ mp->thread=pthread_self();
++ mp->file= (char*) file;
++ mp->line=line;
++ pthread_mutex_unlock(&mp->global);
++ return error;
++}
++
++
++int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
++ struct timespec *abstime,
++ const char *file, uint line)
++{
++ int error;
++ pthread_mutex_lock(&mp->global);
++ if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
++ {
++ fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
++ fflush(stderr);
++ abort();
++ }
++ mp->count--; /* Mutex will be released */
++ pthread_mutex_unlock(&mp->global);
++ error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
++#ifdef EXTRA_DEBUG
++ if (error && (error != EINTR && error != ETIMEDOUT))
++ {
++ fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_timedwait at %s, line %d\n", error, file, line);
++ }
++#endif
++ pthread_mutex_lock(&mp->global);
++ if (mp->count++)
++ {
++ fprintf(stderr,
++ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d (error: %d)\n",
++ mp->count-1, my_thread_id(), file, line, error);
++ fflush(stderr);
++ abort();
++ }
++ mp->thread=pthread_self();
++ mp->file= (char*) file;
++ mp->line=line;
++ pthread_mutex_unlock(&mp->global);
++ return error;
++}
++
++int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
++{
++ int error=0;
++ if (mp->count != 0)
++ {
++ fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
++ mp->file,mp->line, file, line);
++ fflush(stderr);
++ abort();
++ }
++#ifdef _WIN32
++ pthread_mutex_destroy(&mp->global);
++ pthread_mutex_destroy(&mp->mutex);
++#else
++ if (pthread_mutex_destroy(&mp->global))
++ error=1;
++ if (pthread_mutex_destroy(&mp->mutex))
++ error=1;
++#endif
++ return error;
++}
++
++#endif /* THREAD && SAFE_MUTEX */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/typelib.c mariadb-native-client.trunk/libmariadb/typelib.c
+--- mariadb/libmariadb/typelib.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/typelib.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,106 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/* Functions to handle typelib */
++
++#include "mysys_priv.h"
++#include <m_string.h>
++#include <m_ctype.h>
++
++/***************************************************************************
++** Search after a fieldtype. Endspace in x is not compared.
++** If part, uniq field is found and full_name == 0 then x is expanded
++** to full field.
++** full_name has the following bit values:
++** If & 1 accept only whole names
++** If & 2 don't expand if half field
++** If & 4 allow #number# as type
++****************************************************************************/
++
++int find_type(my_string x, TYPELIB *typelib, uint full_name)
++{
++ int find,pos,findpos= 0;
++ reg1 my_string i;
++ reg2 const char *j;
++ DBUG_ENTER("find_type");
++ DBUG_PRINT("enter",("x: '%s' lib: %lx",x,typelib));
++
++ if (!typelib->count)
++ {
++ DBUG_PRINT("exit",("no count"));
++ DBUG_RETURN(0);
++ }
++ LINT_INIT(findpos);
++ find=0;
++ for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
++ {
++ for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
++ if (! *j)
++ {
++ while (*i == ' ')
++ i++; /* skipp_end_space */
++ if (! *i)
++ DBUG_RETURN(pos+1);
++ }
++ if (! *i && (!*j || !(full_name & 1)))
++ {
++ find++;
++ findpos=pos;
++ }
++ }
++ if (find == 0 && (full_name & 4) && x[0] == '#' && strend(x)[-1] == '#' &&
++ (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
++ find=1;
++ else if (find == 0 || ! x[0])
++ {
++ DBUG_PRINT("exit",("Couldn't find type"));
++ DBUG_RETURN(0);
++ }
++ else if (find != 1 || (full_name & 1))
++ {
++ DBUG_PRINT("exit",("Too many possybilities"));
++ DBUG_RETURN(-1);
++ }
++ if (!(full_name & 2))
++ (void) strmov(x,typelib->type_names[findpos]);
++ DBUG_RETURN(findpos+1);
++} /* find_type */
++
++
++ /* Get name of type nr 'nr' */
++ /* Warning first type is 1, 0 = empty field */
++
++void make_type(register my_string to, register uint nr, register TYPELIB *typelib)
++{
++ DBUG_ENTER("make_type");
++ if (!nr)
++ to[0]=0;
++ else
++ (void) strmov(to,get_type(typelib,nr-1));
++ DBUG_VOID_RETURN;
++} /* make_type */
++
++
++ /* Get type */
++ /* Warning first type is 0 */
++
++const char *get_type(TYPELIB *typelib, uint nr)
++{
++ if (nr < (uint) typelib->count && typelib->type_names)
++ return(typelib->type_names[nr]);
++ return "?";
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/version_script.txt mariadb-native-client.trunk/libmariadb/version_script.txt
+--- mariadb/libmariadb/version_script.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/version_script.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,137 @@
++{
++global:
++ get_tty_password;
++ load_defaults;
++ mysql_thread_end;
++ mysql_thread_init;
++ myodbc_remove_escape;
++ mysql_affected_rows;
++ mysql_autocommit;
++ mysql_stmt_bind_param;
++ mysql_stmt_bind_result;
++ mysql_change_user;
++ mysql_character_set_name;
++ mysql_close;
++ mysql_commit;
++ mysql_data_seek;
++ mysql_debug;
++ mysql_dump_debug_info;
++ mysql_eof;
++ mysql_errno;
++ mysql_error;
++ mysql_escape_string;
++ mysql_hex_string;
++ mysql_stmt_execute;
++ mysql_stmt_fetch;
++ mysql_stmt_fetch_column;
++ mysql_fetch_field;
++ mysql_fetch_field_direct;
++ mysql_fetch_fields;
++ mysql_fetch_lengths;
++ mysql_fetch_row;
++ mysql_field_count;
++ mysql_field_seek;
++ mysql_field_tell;
++ mysql_free_result;
++ mysql_get_client_info;
++ mysql_get_host_info;
++ mysql_get_proto_info;
++ mysql_get_parameters;
++ mysql_get_server_info;
++ mysql_get_client_version;
++ mysql_get_ssl_cipher;
++ mysql_info;
++ mysql_init;
++ mysql_insert_id;
++ mysql_kill;
++ mysql_set_server_option;
++ mysql_list_dbs;
++ mysql_list_fields;
++ mysql_list_processes;
++ mysql_list_tables;
++ mysql_more_results;
++ mysql_next_result;
++ mysql_num_fields;
++ mysql_num_rows;
++ mysql_options;
++ mysql_stmt_param_count;
++ mysql_ping;
++ mysql_stmt_result_metadata;
++ mysql_query;
++ mysql_read_query_result;
++ mysql_real_connect;
++ mysql_real_escape_string;
++ mysql_real_query;
++ mysql_refresh;
++ mysql_rollback;
++ mysql_row_seek;
++ mysql_row_tell;
++ mysql_select_db;
++ mysql_stmt_send_long_data;
++ mysql_send_query;
++ mysql_shutdown;
++ mysql_ssl_set;
++ mysql_stat;
++ mysql_stmt_affected_rows;
++ mysql_stmt_close;
++ mysql_stmt_reset;
++ mysql_stmt_data_seek;
++ mysql_stmt_errno;
++ mysql_stmt_error;
++ mysql_stmt_free_result;
++ mysql_stmt_num_rows;
++ mysql_stmt_row_seek;
++ mysql_stmt_row_tell;
++ mysql_stmt_store_result;
++ mysql_store_result;
++ mysql_thread_id;
++ mysql_thread_safe;
++ mysql_use_result;
++ mysql_warning_count;
++ mysql_stmt_sqlstate;
++ mysql_sqlstate;
++ mysql_get_server_version;
++ mysql_stmt_prepare;
++ mysql_stmt_init;
++ mysql_stmt_insert_id;
++ mysql_stmt_attr_get;
++ mysql_stmt_attr_set;
++ mysql_stmt_field_count;
++ mysql_set_local_infile_default;
++ mysql_set_local_infile_handler;
++ mysql_server_init;
++ mysql_server_end;
++ mysql_set_character_set;
++ mysql_get_character_set_info;
+ mysql_stmt_param_metadata;
+ mysql_stmt_next_result;
- local:
- *;
- };
-
-=== modified file 'libmariadb/violite.c'
---- mariadb/libmysql/violite.c 2012-11-27 23:53:08 +0000
-+++ mariadb/libmariadb/violite.c 2013-03-14 21:01:43 +0000
-@@ -42,7 +42,7 @@
- #endif
-
- #ifdef HAVE_OPENSSL
--#include <my_secure.h>
++ mysql_stmt_more_results;
++ mariadb_connection;
++ mysql_get_server_name;
++ mysql_get_charset_by_name;
++ mysql_get_charset_by_nr;
++ mariadb_convert_string;
++ mariadb_dyncol_free;
++ mariadb_dyncol_create_many_num;
++ mariadb_dyncol_create_many_named;
++ mariadb_dyncol_update_many_num;
++ mariadb_dyncol_update_many_named;
++ mariadb_dyncol_exists_num;
++ mariadb_dyncol_exists_named;
++ mariadb_dyncol_list_num;
++ mariadb_dyncol_list_named;
++ mariadb_dyncol_get_num;
++ mariadb_dyncol_get_named;
++ mariadb_dyncol_has_names;
++ mariadb_dyncol_check;
++ mariadb_dyncol_val_str;
++ mariadb_dyncol_val_long;
++ mariadb_dyncol_val_double;
++ mariadb_dyncol_unpack;
++ mariadb_dyncol_column_cmp_named;
++ mariadb_dyncol_column_count;
++ mariadb_dyncol_json;
++local:
++ *;
++};
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmariadb/violite.c mariadb-native-client.trunk/libmariadb/violite.c
+--- mariadb/libmariadb/violite.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/libmariadb/violite.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,508 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA */
++
++/*
++ Note that we can't have assertion on file descriptors; The reason for
++ this is that during mysql shutdown, another thread can close a file
++ we are working on. In this case we should just return read errors from
++ the file descriptior.
++*/
++
++#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
++
++#include <my_global.h>
++#include <errno.h>
++#include <assert.h>
++#include <violite.h>
++#include <my_sys.h>
++#include <my_net.h>
++#include <m_string.h>
++#ifdef HAVE_POLL
++#include <sys/poll.h>
++#endif
++#ifdef HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++
++#ifdef HAVE_OPENSSL
+#include <ma_secure.h>
- #endif
-
- #ifdef _WIN32
-
-=== removed file 'libmysql/mysql_io.c'
---- mariadb/libmysql/mysql_io.c 2011-10-10 11:01:17 +0000
-+++ mariadb/libmysql/mysql_io.c 1970-01-01 00:00:00 +0000
++#endif
++
++#ifdef _WIN32
++#define socklen_t int
++#pragma comment (lib, "ws2_32")
++#endif
++
++#if !defined(MSDOS) && !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__FreeBSD__)
++#include <netinet/in_systm.h>
++#include <netinet/ip.h>
++#if !defined(alpha_linux_port)
++#include <netinet/tcp.h>
++#endif
++#endif
++
++#if defined(__EMX__) || defined(OS2)
++#define ioctlsocket ioctl
++#endif /* defined(__EMX__) */
++
++#if defined(MSDOS) || defined(_WIN32)
++#define O_NONBLOCK 1 /* For emulation of fcntl() */
++#endif
++#ifndef EWOULDBLOCK
++#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN
++#endif
++
++
++typedef void *vio_ptr;
++typedef char *vio_cstring;
++
++/*
++ * 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)
++{
++ bzero((char*) vio, sizeof(*vio));
++ vio->type= type;
++ vio->sd= sd;
++ vio->hPipe= hPipe;
++ vio->localhost= localhost;
++}
++
++void vio_timeout(Vio *vio, int type, uint seconds)
++{
++#ifdef _WIN32
++ uint timeout= seconds * 1000; /* milli secs */
++#else
++ struct timeval timeout;
++ timeout.tv_sec= seconds;
++ timeout.tv_usec= 0;
++#endif
++
++ if (setsockopt(vio->sd, SOL_SOCKET, type,
++#ifdef _WIN32
++ (const char *)&timeout,
++#else
++ (const void *)&timeout,
++#endif
++ sizeof(timeout)))
++ {
++ DBUG_PRINT("error", ("setsockopt failed. Errno: %d", errno));
++ }
++}
++
++void vio_read_timeout(Vio *vio, uint seconds)
++{
++ vio_timeout(vio, SO_RCVTIMEO, seconds);
++}
++
++void vio_write_timeout(Vio *vio, uint seconds)
++{
++ vio_timeout(vio, SO_SNDTIMEO, seconds);
++}
++
++/* 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;
++ 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);
++ sprintf(vio->desc,
++ (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
++ vio->sd);
++#if !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
++#if !defined(NO_FCNTL_NONBLOCK)
++ vio->fcntl_mode = fcntl(sd, F_GETFL);
++#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
++ /* Non blocking sockets doesn't work good on HPUX 11.0 */
++ (void) ioctl(sd,FIOSNBIO,0);
++#endif
++#else /* !defined(_WIN32) && !defined(__EMX__) */
++ {
++ /* set to blocking mode by default */
++ ulong arg=0, r;
++ r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
++ }
++#endif
++ }
++ DBUG_RETURN(vio);
++}
++
++
++#ifdef _WIN32
++
++Vio *vio_new_win32pipe(HANDLE hPipe)
++{
++ Vio *vio;
++ DBUG_ENTER("vio_new_handle");
++ if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
++ {
++ vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
++ strmov(vio->desc, "named pipe");
++ }
++ DBUG_RETURN(vio);
++}
++
++#endif
++
++void vio_delete(Vio * vio)
++{
++ /* It must be safe to delete null pointers. */
++ /* This matches the semantics of C++'s delete operator. */
++ if (vio)
++ {
++ if (vio->type != VIO_CLOSED)
++ vio_close(vio);
++ my_free((gptr) vio,MYF(0));
++ }
++}
++
++int vio_errno(Vio *vio __attribute__((unused)))
++{
++ return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
++}
++
++
++size_t vio_read(Vio * vio, gptr buf, size_t size)
++{
++ size_t r;
++ DBUG_ENTER("vio_read");
++ DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
++
++#ifdef HAVE_OPENSSL
++ if (vio->type == VIO_TYPE_SSL)
++ {
++ r= my_ssl_read(vio, (uchar *)buf, size);
++ DBUG_RETURN(r);
++ }
++#endif
++
++#if defined( _WIN32) || defined(OS2)
++ if (vio->type == VIO_TYPE_NAMEDPIPE)
++ {
++ DWORD length;
++#ifdef OS2
++ if (!DosRead((HFILE)vio->hPipe, buf, size, &length))
++ DBUG_RETURN(-1);
++#else
++ if (!ReadFile(vio->hPipe, buf, (DWORD)size, &length, NULL))
++ DBUG_RETURN(-1);
++#endif
++ DBUG_RETURN(length);
++ }
++ r = recv(vio->sd, buf, (int)size,0);
++#else
++ errno=0; /* For linux */
++ r = read(vio->sd, buf, size);
++#endif /* _WIN32 */
++#ifndef DBUG_OFF
++ if ((size_t)r == -1)
++ {
++ DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno));
++ }
++#endif /* DBUG_OFF */
++ DBUG_PRINT("exit", ("%u", (uint)r));
++ DBUG_RETURN(r);
++}
++
++/*
++ Return data from the beginning of the receive queue without removing
++ that data from the queue. A subsequent receive call will return the same data.
++*/
++my_bool vio_read_peek(Vio *vio, size_t *bytes)
++{
++#ifdef _WIN32
++ if (ioctlsocket(vio->sd, FIONREAD, (unsigned long)bytes))
++ return TRUE;
++#else
++ char buffer[1024];
++ ssize_t length;
++
++ vio_blocking(vio, 0);
++ length= recv(vio->sd, &buffer, sizeof(buffer), MSG_PEEK);
++ if (length < 0)
++ return TRUE;
++ *bytes= length;
++#endif
++ return FALSE;
++}
++
++
++size_t vio_write(Vio * vio, const gptr buf, size_t size)
++{
++ size_t r;
++ DBUG_ENTER("vio_write");
++ DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
++#ifdef HAVE_OPENSSL
++ if (vio->type == VIO_TYPE_SSL)
++ {
++ r= my_ssl_write(vio, (uchar *)buf, size);
++ DBUG_RETURN(r);
++ }
++#endif
++#if defined( _WIN32) || defined(OS2)
++ if ( vio->type == VIO_TYPE_NAMEDPIPE)
++ {
++ DWORD length;
++#ifdef OS2
++ if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length))
++ DBUG_RETURN(-1);
++#else
++ if (!WriteFile(vio->hPipe, (char*) buf, (DWORD)size, &length, NULL))
++ DBUG_RETURN(-1);
++#endif
++ DBUG_RETURN(length);
++ }
++ r = send(vio->sd, buf, (int)size,0);
++#else
++ r = write(vio->sd, buf, size);
++#endif /* _WIN32 */
++#ifndef DBUG_OFF
++ if ((size_t)r == -1)
++ {
++ DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno));
++ }
++#endif /* DBUG_OFF */
++ DBUG_PRINT("exit", ("%u", (uint)r));
++ DBUG_RETURN(r);
++}
++
++
++int vio_blocking(Vio * vio, my_bool set_blocking_mode)
++{
++ int r=0;
++ DBUG_ENTER("vio_blocking");
++ DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
++
++#if !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
++#if !defined(NO_FCNTL_NONBLOCK)
++
++ if (vio->sd >= 0)
++ {
++ int old_fcntl=vio->fcntl_mode;
++ if (set_blocking_mode)
++ vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
++ else
++ vio->fcntl_mode |= O_NONBLOCK; /* set bit */
++ if (old_fcntl != vio->fcntl_mode)
++ r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
++ }
++#endif /* !defined(NO_FCNTL_NONBLOCK) */
++#else /* !defined(_WIN32) && !defined(__EMX__) */
++#ifndef __EMX__
++ if (vio->type != VIO_TYPE_NAMEDPIPE)
++#endif
++ {
++ ulong arg;
++ int old_fcntl=vio->fcntl_mode;
++ if (set_blocking_mode)
++ {
++ arg = 0;
++ vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
++ }
++ else
++ {
++ arg = 1;
++ vio->fcntl_mode |= O_NONBLOCK; /* set bit */
++ }
++ if (old_fcntl != vio->fcntl_mode)
++ r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
++ }
++#endif /* !defined(_WIN32) && !defined(__EMX__) */
++ DBUG_RETURN(r);
++}
++
++my_bool
++vio_is_blocking(Vio * vio)
++{
++ my_bool r;
++ DBUG_ENTER("vio_is_blocking");
++ r = !(vio->fcntl_mode & O_NONBLOCK);
++ DBUG_PRINT("exit", ("%d", (int) r));
++ DBUG_RETURN(r);
++}
++
++
++int vio_fastsend(Vio * vio __attribute__((unused)))
++{
++ int r=0;
++ DBUG_ENTER("vio_fastsend");
++
++#ifdef IPTOS_THROUGHPUT
++ {
++#ifndef __EMX__
++ int tos = IPTOS_THROUGHPUT;
++ if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
++#endif /* !__EMX__ */
++ {
++ int nodelay = 1;
++ if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
++ sizeof(nodelay))) {
++ DBUG_PRINT("warning",
++ ("Couldn't set socket option for fast send"));
++ r= -1;
++ }
++ }
++ }
++#endif /* IPTOS_THROUGHPUT */
++ DBUG_PRINT("exit", ("%d", r));
++ DBUG_RETURN(r);
++}
++
++int vio_keepalive(Vio* vio, my_bool set_keep_alive)
++{
++ int r=0;
++ uint opt = 0;
++ DBUG_ENTER("vio_keepalive");
++ DBUG_PRINT("enter", ("sd=%d set_keep_alive=%d", vio->sd, (int)
++ set_keep_alive));
++ if (vio->type != VIO_TYPE_NAMEDPIPE)
++ {
++ if (set_keep_alive)
++ opt = 1;
++ r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
++ sizeof(opt));
++ }
++ DBUG_RETURN(r);
++}
++
++
++my_bool
++vio_should_retry(Vio * vio __attribute__((unused)))
++{
++ int en = socket_errno;
++ return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK;
++}
++
++
++int vio_close(Vio * vio)
++{
++ int r;
++ DBUG_ENTER("vio_close");
++#ifdef HAVE_OPENSSL
++ if (vio->type == VIO_TYPE_SSL)
++ {
++ r = my_ssl_close(vio);
++ }
++#endif
++#ifdef _WIN32
++ if (vio->type == VIO_TYPE_NAMEDPIPE)
++ {
++ r=CloseHandle(vio->hPipe);
++ }
++ else if (vio->type != VIO_CLOSED)
++#endif /* _WIN32 */
++ {
++ r=0;
++ if (shutdown(vio->sd,2))
++ r= -1;
++ if (closesocket(vio->sd))
++ r= -1;
++ }
++ if (r)
++ {
++ DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno));
++ /* FIXME: error handling (not critical for MySQL) */
++ }
++ vio->type= VIO_CLOSED;
++ vio->sd= -1;
++ DBUG_RETURN(r);
++}
++
++
++const char *vio_description(Vio * vio)
++{
++ return vio->desc;
++}
++
++enum enum_vio_type vio_type(Vio* vio)
++{
++ return vio->type;
++}
++
++my_socket vio_fd(Vio* vio)
++{
++ return vio->sd;
++}
++
++
++my_bool vio_peer_addr(Vio * vio, char *buf)
++{
++ DBUG_ENTER("vio_peer_addr");
++ DBUG_PRINT("enter", ("sd=%d", vio->sd));
++ if (vio->localhost)
++ {
++ strmov(buf,"127.0.0.1");
++ }
++ else
++ {
++ socklen_t addrLen = sizeof(struct sockaddr);
++ if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
++ &addrLen) != 0)
++ {
++ DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno));
++ DBUG_RETURN(1);
++ }
++ my_inet_ntoa(vio->remote.sin_addr,buf);
++ }
++ DBUG_PRINT("exit", ("addr=%s", buf));
++ DBUG_RETURN(0);
++}
++
++
++void vio_in_addr(Vio *vio, struct in_addr *in)
++{
++ DBUG_ENTER("vio_in_addr");
++ if (vio->localhost)
++ bzero((char*) in, sizeof(*in)); /* This should never be executed */
++ else
++ *in=vio->remote.sin_addr;
++ DBUG_VOID_RETURN;
++}
++
++
++/* Return 0 if there is data to be read */
++
++my_bool vio_poll_read(Vio *vio,uint timeout)
++{
++#ifndef HAVE_POLL
++ return 0;
++#else
++ struct pollfd fds;
++ int res;
++ DBUG_ENTER("vio_poll");
++ fds.fd=vio->sd;
++ fds.events=POLLIN;
++ fds.revents=0;
++ if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
++ {
++ DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */
++ }
++ DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
++#endif
++}
++
++#endif /* HAVE_VIO */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/acinclude.m4 mariadb-native-client.trunk/libmysql/acinclude.m4
+--- mariadb/libmysql/acinclude.m4 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/acinclude.m4 1970-01-01 01:00:00.000000000 +0100
+@@ -1,91 +0,0 @@
+-# Local macros for automake & autoconf
+-
+-AC_DEFUN(MYSQL_TYPE_ACCEPT,
+-[ac_save_CXXFLAGS="$CXXFLAGS"
+-AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
+-AC_LANG_SAVE
+-AC_LANG_CPLUSPLUS
+-if test "$ac_cv_prog_gxx" = "yes"
+-then
+- CXXFLAGS="$CXXFLAGS -Werror"
+-fi
+-mysql_cv_btype_last_arg_accept=none
+-[AC_TRY_COMPILE([#include <stdlib.h>
+-#include <sys/types.h>
+-#include <sys/socket.h>
+-],
+-[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0);],
+-mysql_cv_btype_last_arg_accept=socklen_t)]
+-if test $mysql_cv_btype_last_arg_accept = none; then
+-[AC_TRY_COMPILE([#include <stdlib.h>
+-#include <sys/types.h>
+-#include <sys/socket.h>
+-],
+-[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0);],
+-mysql_cv_btype_last_arg_accept=size_t)]
+-fi
+-if test $mysql_cv_btype_last_arg_accept = none; then
+-mysql_cv_btype_last_arg_accept=int
+-fi)
+-AC_LANG_RESTORE
+-AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $mysql_cv_btype_last_arg_accept)
+-CXXFLAGS="$ac_save_CXXFLAGS"
+-])
+-
+-
+-#---START: Used in for client configure
+-AC_DEFUN(MYSQL_CHECK_ULONG,
+-[AC_MSG_CHECKING(for type ulong)
+-AC_CACHE_VAL(ac_cv_ulong,
+-[AC_TRY_RUN([#include <stdio.h>
+-#include <sys/types.h>
+-main()
+-{
+- ulong foo;
+- foo++;
+- exit(0);
+-}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
+-AC_MSG_RESULT($ac_cv_ulong)
+-if test "$ac_cv_ulong" = "yes"
+-then
+- AC_DEFINE(HAVE_ULONG)
+-fi
+-])
+-
+-AC_DEFUN(MYSQL_CHECK_UCHAR,
+-[AC_MSG_CHECKING(for type uchar)
+-AC_CACHE_VAL(ac_cv_uchar,
+-[AC_TRY_RUN([#include <stdio.h>
+-#include <sys/types.h>
+-main()
+-{
+- uchar foo;
+- foo++;
+- exit(0);
+-}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
+-AC_MSG_RESULT($ac_cv_uchar)
+-if test "$ac_cv_uchar" = "yes"
+-then
+- AC_DEFINE(HAVE_UCHAR)
+-fi
+-])
+-
+-AC_DEFUN(MYSQL_CHECK_UINT,
+-[AC_MSG_CHECKING(for type uint)
+-AC_CACHE_VAL(ac_cv_uint,
+-[AC_TRY_RUN([#include <stdio.h>
+-#include <sys/types.h>
+-main()
+-{
+- uint foo;
+- foo++;
+- exit(0);
+-}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
+-AC_MSG_RESULT($ac_cv_uint)
+-if test "$ac_cv_uint" = "yes"
+-then
+- AC_DEFINE(HAVE_UINT)
+-fi
+-])
+-
+-#---END:
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/array.c mariadb-native-client.trunk/libmysql/array.c
+--- mariadb/libmysql/array.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/array.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,177 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Handling of arrays that can grow dynamicly. */
+-
+-#ifdef _WIN32
+-#undef SAFEMALLOC /* Problems with threads */
+-#endif
+-
+-#include "mysys_priv.h"
+-#include "m_string.h"
+-
+-/*
+- Initiate array and alloc space for init_alloc elements. Array is usable
+- even if space allocation failed
+-*/
+-
+-my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
+- uint init_alloc, uint alloc_increment CALLER_INFO_PROTO)
+-{
+- DBUG_ENTER("init_dynamic_array");
+- if (!alloc_increment)
+- {
+- alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
+- if (init_alloc > 8 && alloc_increment > init_alloc * 2)
+- alloc_increment=init_alloc*2;
+- }
+-
+- if (!init_alloc)
+- init_alloc=alloc_increment;
+- array->elements=0;
+- array->max_element=init_alloc;
+- array->alloc_increment=alloc_increment;
+- array->size_of_element=element_size;
+- if (!(array->buffer=(char*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
+- {
+- array->max_element=0;
+- DBUG_RETURN(TRUE);
+- }
+- DBUG_RETURN(FALSE);
+-}
+-
+-
+-my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
+-{
+- gptr buffer;
+- if (array->elements == array->max_element)
+- { /* Call only when nessesary */
+- if (!(buffer=alloc_dynamic(array)))
+- return TRUE;
+- }
+- else
+- {
+- buffer=array->buffer+(array->elements * array->size_of_element);
+- array->elements++;
+- }
+- memcpy(buffer,element,(size_t) array->size_of_element);
+- return FALSE;
+-}
+-
+-
+- /* Alloc room for one element */
+-
+-byte *alloc_dynamic(DYNAMIC_ARRAY *array)
+-{
+- if (array->elements == array->max_element)
+- {
+- char *new_ptr;
+- if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
+- array->alloc_increment)*
+- array->size_of_element,
+- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+- return 0;
+- array->buffer=new_ptr;
+- array->max_element+=array->alloc_increment;
+- }
+- return array->buffer+(array->elements++ * array->size_of_element);
+-}
+-
+-
+- /* remove last element from array and return it */
+-
+-byte *pop_dynamic(DYNAMIC_ARRAY *array)
+-{
+- if (array->elements)
+- return array->buffer+(--array->elements * array->size_of_element);
+- return 0;
+-}
+-
+-
+-my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+-{
+- if (idx >= array->elements)
+- {
+- if (idx >= array->max_element)
+- {
+- uint size;
+- char *new_ptr;
+- size=(idx+array->alloc_increment)/array->alloc_increment;
+- size*= array->alloc_increment;
+- if (!(new_ptr=(char*) my_realloc(array->buffer,size*
+- array->size_of_element,
+- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+- return TRUE;
+- array->buffer=new_ptr;
+- array->max_element=size;
+- }
+- bzero((gptr) (array->buffer+array->elements*array->size_of_element),
+- (idx - array->elements)*array->size_of_element);
+- array->elements=idx+1;
+- }
+- memcpy(array->buffer+(idx * array->size_of_element),element,
+- (size_t) array->size_of_element);
+- return FALSE;
+-}
+-
+-
+-void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+-{
+- if (idx >= array->elements)
+- {
+- DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
+- idx,array->elements));
+- bzero(element,array->size_of_element);
+- return;
+- }
+- memcpy(element,array->buffer+idx*array->size_of_element,
+- (size_t) array->size_of_element);
+-}
+-
+-
+-void delete_dynamic(DYNAMIC_ARRAY *array)
+-{
+- if (array->buffer)
+- {
+- my_free(array->buffer,MYF(MY_WME));
+- array->buffer=0;
+- array->elements=array->max_element=0;
+- }
+-}
+-
+-
+-void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
+-{
+- char *ptr=array->buffer+array->size_of_element*idx;
+- array->elements--;
+- memmove(ptr,ptr+array->size_of_element,
+- (array->elements-idx)*array->size_of_element);
+-}
+-
+-
+-void freeze_size(DYNAMIC_ARRAY *array)
+-{
+- uint elements=max(array->elements,1);
+-
+- if (array->buffer && array->max_element != elements)
+- {
+- array->buffer=(char*) my_realloc(array->buffer,
+- elements*array->size_of_element,
+- MYF(MY_WME));
+- array->max_element=elements;
+- }
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/bchange.c mariadb-native-client.trunk/libmysql/bchange.c
+--- mariadb/libmysql/bchange.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/bchange.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,39 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : bchange.c
+- Author : Michael widenius
+- Updated: 1987-03-20
+- Defines: bchange()
+-
+- bchange(dst, old_length, src, new_length, tot_length)
+- replaces old_length characters at dst to new_length characters from
+- src in a buffer with tot_length bytes.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-void bchange(register char *dst, size_t old_length, register const char *src, size_t new_length, size_t tot_length)
+-{
+- size_t rest=tot_length-old_length;
+- if (old_length < new_length)
+- bmove_upp(dst+rest+new_length,dst+tot_length,rest);
+- else
+- bmove(dst+new_length,dst+old_length,rest);
+- memcpy(dst,src,new_length);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/bmove.c mariadb-native-client.trunk/libmysql/bmove.c
+--- mariadb/libmysql/bmove.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/bmove.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,80 +0,0 @@
+-/* Copyright (C) 2002 MySQL AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : bmove.c
+- Author : Richard A. O'Keefe.
+- Michael Widenius; ifdef MC68000
+- Updated: 23 April 1984
+- Defines: bmove()
+-
+- bmove(dst, src, len) moves exactly "len" bytes from the source "src"
+- to the destination "dst". It does not check for NUL characters as
+- strncpy() and strnmov() do. Thus if your C compiler doesn't support
+- structure assignment, you can simulate it with
+- bmove(&to, &from, sizeof from);
+- The standard 4.2bsd routine for this purpose is bcopy. But as bcopy
+- has its first two arguments the other way around you may find this a
+- bit easier to get right.
+- No value is returned.
+-
+- Note: the "b" routines are there to exploit certain VAX order codes,
+- but the MOVC3 instruction will only move 65535 characters. The asm
+- code is presented for your interest and amusement.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#if !defined(HAVE_BMOVE) && !defined(bmove)
+-
+-#if VaxAsm
+-
+-void bmove(dst, src, len)
+- char *dst, *src;
+- uint len;
+- {
+- asm("movc3 12(ap),*8(ap),*4(ap)");
+- }
+-
+-#else
+-#if defined(MC68000) && defined(DS90)
+-
+-void bmove(dst, src, len)
+-char *dst,*src;
+-uint len; /* 0 <= len <= 65535 */
+-{
+-asm(" movl 12(a7),d0 ");
+-asm(" subql #1,d0 ");
+-asm(" blt .L5 ");
+-asm(" movl 4(a7),a1 ");
+-asm(" movl 8(a7),a0 ");
+-asm(".L4: movb (a0)+,(a1)+ ");
+-asm(" dbf d0,.L4 ");
+-asm(".L5: ");
+-}
+-#else
+-
+-void bmove(dst, src, len)
+-register char *dst;
+-register const char *src;
+-register uint len;
+-{
+- while (len-- != 0) *dst++ = *src++;
+-}
+-#endif
+-#endif
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/bmove_upp.c mariadb-native-client.trunk/libmysql/bmove_upp.c
+--- mariadb/libmysql/bmove_upp.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/bmove_upp.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,51 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : bmove.c
+- Author : Michael widenius
+- Updated: 1987-03-20
+- Defines: bmove_upp()
+-
+- bmove_upp(dst, src, len) moves exactly "len" bytes from the source
+- "src-len" to the destination "dst-len" counting downwards.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#if defined(MC68000) && defined(DS90)
+-
+-/* 0 <= len <= 65535 */
+-void bmove_upp(byte *dst, const byte *src, size_t len)
+-{
+-asm(" movl 12(a7),d0 ");
+-asm(" subql #1,d0 ");
+-asm(" blt .L5 ");
+-asm(" movl 4(a7),a1 ");
+-asm(" movl 8(a7),a0 ");
+-asm(".L4: movb -(a0),-(a1) ");
+-asm(" dbf d0,.L4 ");
+-asm(".L5: ");
+-}
+-#else
+-
+-void bmove_upp(register char *dst, register const char *src, register size_t len)
+-{
+- while (len-- != 0) *--dst = *--src;
+-}
+-
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/charset.c mariadb-native-client.trunk/libmysql/charset.c
+--- mariadb/libmysql/charset.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/charset.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,75 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <m_ctype.h>
+-#include <m_string.h>
+-#include <my_dir.h>
+-
+-CHARSET_INFO *default_charset_info = (CHARSET_INFO *)&compiled_charsets[5];
+-
+-CHARSET_INFO *get_charset_by_nr(uint cs_number)
+-{
+- int i= 0;
+-
+- while (compiled_charsets[i].nr && cs_number != compiled_charsets[i].nr)
+- i++;
+-
+- return (compiled_charsets[i].nr) ? (CHARSET_INFO *)&compiled_charsets[i] : NULL;
+-}
+-
+-my_bool set_default_charset(uint cs, myf flags)
+-{
+- CHARSET_INFO *new_charset;
+- DBUG_ENTER("set_default_charset");
+- DBUG_PRINT("enter",("character set: %d",(int) cs));
+- new_charset = get_charset_by_nr(cs);
+- if (!new_charset)
+- {
+- DBUG_PRINT("error",("Couldn't set default character set"));
+- DBUG_RETURN(TRUE); /* error */
+- }
+- default_charset_info = new_charset;
+- DBUG_RETURN(FALSE);
+-}
+-
+-CHARSET_INFO *get_charset_by_name(const char *cs_name)
+-{
+- int i= 0;
+-
+- while (compiled_charsets[i].nr && strcmp(cs_name, compiled_charsets[i].name) != 0)
+- i++;
+-
+- return (compiled_charsets[i].nr) ? (CHARSET_INFO *)&compiled_charsets[i] : NULL;
+-}
+-
+-my_bool set_default_charset_by_name(const char *cs_name, myf flags)
+-{
+- CHARSET_INFO *new_charset;
+- DBUG_ENTER("set_default_charset_by_name");
+- DBUG_PRINT("enter",("character set: %s", cs_name));
+- new_charset = get_charset_by_name(cs_name);
+- if (!new_charset)
+- {
+- DBUG_PRINT("error",("Couldn't set default character set"));
+- DBUG_RETURN(TRUE); /* error */
+- }
+-
+- default_charset_info = new_charset;
+- DBUG_RETURN(FALSE);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/client_plugin.c mariadb-native-client.trunk/libmysql/client_plugin.c
+--- mariadb/libmysql/client_plugin.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/client_plugin.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,459 +0,0 @@
+-/* Copyright (C) 2010 - 2012 Sergei Golubchik and Monty Program Ab
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA */
+-
+-/**
+- @file
+-
+- Support code for the client side (libmysql) plugins
+-
+- Client plugins are somewhat different from server plugins, they are simpler.
+-
+- They do not need to be installed or in any way explicitly loaded on the
+- client, they are loaded automatically on demand.
+- One client plugin per shared object, soname *must* match the plugin name.
+-
+- There is no reference counting and no unloading either.
+-*/
+-
+-#if _MSC_VER
+-/* Silence warnings about variable 'unused' being used. */
+-#define FORCE_INIT_OF_VARS 1
+-#endif
+-
+-#include <my_global.h>
+-#include "mysql.h"
+-#include <my_sys.h>
+-#include <m_string.h>
+-#ifdef THREAD
+-#include <my_pthread.h>
+-#else
+-#include <my_no_pthread.h>
+-#endif
+-
+-#include "errmsg.h"
+-#include <mysql/client_plugin.h>
+-
+-struct st_client_plugin_int {
+- struct st_client_plugin_int *next;
+- void *dlhandle;
+- struct st_mysql_client_plugin *plugin;
+-};
+-
+-static my_bool initialized= 0;
+-static MEM_ROOT mem_root;
+-
+-#define plugin_declarations_sym "_mysql_client_plugin_declaration_"
+-
+-static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
+-{
+- 0, /* these two are taken by Connector/C */
+- 0, /* these two are taken by Connector/C */
+- MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
+-};
+-
+-/*
+- Loaded plugins are stored in a linked list.
+- The list is append-only, the elements are added to the head (like in a stack).
+- The elements are added under a mutex, but the list can be read and traversed
+- without any mutex because once an element is added to the list, it stays
+- there. The main purpose of a mutex is to prevent two threads from
+- loading the same plugin twice in parallel.
+-*/
+-struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS];
+-#ifdef THREAD
+-static pthread_mutex_t LOCK_load_client_plugin;
+-#endif
+-
+-static int is_not_initialized(MYSQL *mysql, const char *name)
+-{
+- if (initialized)
+- return 0;
+-
+- my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
+- SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
+- name, "not initialized");
+- return 1;
+-}
+-
+-
+-/**
+- finds a plugin in the list
+-
+- @param name plugin name to search for
+- @param type plugin type
+-
+- @note this does NOT necessarily need a mutex, take care!
+-
+- @retval a pointer to a found plugin or 0
+-*/
+-
+-static struct st_mysql_client_plugin *find_plugin(const char *name, int type)
+-{
+- struct st_client_plugin_int *p;
+-
+- DBUG_ASSERT(initialized);
+- DBUG_ASSERT(type >= 0 && type < MYSQL_CLIENT_MAX_PLUGINS);
+- if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
+- return 0;
+-
+- for (p= plugin_list[type]; p; p= p->next)
+- {
+- if (strcmp(p->plugin->name, name) == 0)
+- return p->plugin;
+- }
+- return NULL;
+-}
+-
+-
+-/**
+- verifies the plugin and adds it to the list
+-
+- @param mysql MYSQL structure (for error reporting)
+- @param plugin plugin to install
+- @param dlhandle a handle to the shared object (returned by dlopen)
+- or 0 if the plugin was not dynamically loaded
+- @param argc number of arguments in the 'va_list args'
+- @param args arguments passed to the plugin initialization function
+-
+- @retval a pointer to an installed plugin or 0
+-*/
+-
+-static struct st_mysql_client_plugin *
+-add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
+- int argc, va_list args)
+-{
+- const char *errmsg;
+- struct st_client_plugin_int plugin_int, *p;
+- char errbuf[1024];
+-
+- DBUG_ASSERT(initialized);
+-
+- plugin_int.plugin= plugin;
+- plugin_int.dlhandle= dlhandle;
+-
+- if (plugin->type >= MYSQL_CLIENT_MAX_PLUGINS)
+- {
+- errmsg= "Unknown client plugin type";
+- goto err1;
+- }
+-
+- if (plugin->interface_version < plugin_version[plugin->type] ||
+- (plugin->interface_version >> 8) >
+- (plugin_version[plugin->type] >> 8))
+- {
+- errmsg= "Incompatible client plugin interface";
+- goto err1;
+- }
+-
+- /* Call the plugin initialization function, if any */
+- if (plugin->init && plugin->init(errbuf, sizeof(errbuf), argc, args))
+- {
+- errmsg= errbuf;
+- goto err1;
+- }
+-
+- p= (struct st_client_plugin_int *)
+- memdup_root(&mem_root, (char *)&plugin_int, sizeof(plugin_int));
+-
+- if (!p)
+- {
+- errmsg= "Out of memory";
+- goto err2;
+- }
+-
+- safe_mutex_assert_owner(&LOCK_load_client_plugin);
+-
+- p->next= plugin_list[plugin->type];
+- plugin_list[plugin->type]= p;
+-
+- return plugin;
+-
+-err2:
+- if (plugin->deinit)
+- plugin->deinit();
+-err1:
+- if (dlhandle)
+- (void)dlclose(dlhandle);
+- my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
+- ER(CR_AUTH_PLUGIN_CANNOT_LOAD), plugin->name, errmsg);
+- return NULL;
+-}
+-
+-
+-/**
+- Loads plugins which are specified in the environment variable
+- LIBMYSQL_PLUGINS.
+-
+- Multiple plugins must be separated by semicolon. This function doesn't
+- return or log an error.
+-
+- The function is be called by mysql_client_plugin_init
+-
+- @todo
+- Support extended syntax, passing parameters to plugins, for example
+- LIBMYSQL_PLUGINS="plugin1(param1,param2);plugin2;..."
+- or
+- LIBMYSQL_PLUGINS="plugin1=int:param1,str:param2;plugin2;..."
+-*/
+-
+-static void load_env_plugins(MYSQL *mysql)
+-{
+- char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
+-
+- /* no plugins to load */
+- if (!s)
+- return;
+-
+- free_env= plugs= my_strdup(s, MYF(MY_WME));
+-
+- do {
+- if ((s= strchr(plugs, ';')))
+- *s= '\0';
+- mysql_load_plugin(mysql, plugs, -1, 0);
+- plugs= s + 1;
+- } while (s);
+-
+- my_free(free_env, MYF(0));
+-}
+-
+-/********** extern functions to be used by libmysql *********************/
+-
+-/**
+- Initializes the client plugin layer.
+-
+- This function must be called before any other client plugin function.
+-
+- @retval 0 successful
+- @retval != 0 error occured
+-*/
+-
+-int mysql_client_plugin_init()
+-{
+- MYSQL mysql;
+- struct st_mysql_client_plugin **builtin;
+- va_list unused;
+- LINT_INIT_STRUCT(unused);
+-
+- if (initialized)
+- return 0;
+-
+- bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
+-
+- pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
+- init_alloc_root(&mem_root, 128, 128);
+-
+- bzero(&plugin_list, sizeof(plugin_list));
+-
+- initialized= 1;
+-
+- pthread_mutex_lock(&LOCK_load_client_plugin);
+-
+- for (builtin= mysql_client_builtins; *builtin; builtin++)
+- add_plugin(&mysql, *builtin, 0, 0, unused);
+-
+- pthread_mutex_unlock(&LOCK_load_client_plugin);
+-
+- load_env_plugins(&mysql);
+-
+- return 0;
+-}
+-
+-
+-/**
+- Deinitializes the client plugin layer.
+-
+- Unloades all client plugins and frees any associated resources.
+-*/
+-
+-void mysql_client_plugin_deinit()
+-{
+- int i;
+- struct st_client_plugin_int *p;
+-
+- if (!initialized)
+- return;
+-
+- for (i=0; i < MYSQL_CLIENT_MAX_PLUGINS; i++)
+- for (p= plugin_list[i]; p; p= p->next)
+- {
+- if (p->plugin->deinit)
+- p->plugin->deinit();
+- if (p->dlhandle)
+- (void)dlclose(p->dlhandle);
+- }
+-
+- bzero(&plugin_list, sizeof(plugin_list));
+- initialized= 0;
+- free_root(&mem_root, MYF(0));
+- pthread_mutex_destroy(&LOCK_load_client_plugin);
+-}
+-
+-/************* public facing functions, for client consumption *********/
+-
+-/* see <mysql/client_plugin.h> for a full description */
+-struct st_mysql_client_plugin *
+-mysql_client_register_plugin(MYSQL *mysql,
+- struct st_mysql_client_plugin *plugin)
+-{
+- va_list unused;
+- LINT_INIT_STRUCT(unused);
+-
+- if (is_not_initialized(mysql, plugin->name))
+- return NULL;
+-
+- pthread_mutex_lock(&LOCK_load_client_plugin);
+-
+- /* make sure the plugin wasn't loaded meanwhile */
+- if (find_plugin(plugin->name, plugin->type))
+- {
+- my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
+- SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
+- plugin->name, "it is already loaded");
+- plugin= NULL;
+- }
+- else
+- plugin= add_plugin(mysql, plugin, 0, 0, unused);
+-
+- pthread_mutex_unlock(&LOCK_load_client_plugin);
+- return plugin;
+-}
+-
+-
+-/* see <mysql/client_plugin.h> for a full description */
+-struct st_mysql_client_plugin *
+-mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
+- int argc, va_list args)
+-{
+- const char *errmsg;
+-#ifdef _WIN32
+- char errbuf[255];
+-#endif
+- char dlpath[FN_REFLEN+1];
+- void *sym, *dlhandle;
+- struct st_mysql_client_plugin *plugin;
+-
+- if (is_not_initialized(mysql, name))
+- return NULL;
+-
+- pthread_mutex_lock(&LOCK_load_client_plugin);
+-
+- /* make sure the plugin wasn't loaded meanwhile */
+- if (type >= 0 && find_plugin(name, type))
+- {
+- errmsg= "it is already loaded";
+- goto err;
+- }
+-
+- /* Compile dll path */
+- strxnmov(dlpath, sizeof(dlpath) - 1,
+- mysql->options.extension && mysql->options.extension->plugin_dir ?
+- mysql->options.extension->plugin_dir : PLUGINDIR, "/",
+- name, SO_EXT, NullS);
+-
+- /* Open new dll handle */
+- if (!(dlhandle= dlopen(dlpath, RTLD_NOW)))
+- {
+-#ifdef _WIN32
+- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+- NULL,
+- GetLastError(),
+- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+- (LPTSTR)&errbuf, 255, NULL);
+- errmsg= errbuf;
+-#else
+- errmsg= dlerror();
+-#endif
+- goto err;
+- }
+-
+- if (!(sym= dlsym(dlhandle, plugin_declarations_sym)))
+- {
+- errmsg= "not a plugin";
+- (void)dlclose(dlhandle);
+- goto err;
+- }
+-
+- plugin= (struct st_mysql_client_plugin*)sym;
+-
+- if (type >=0 && type != plugin->type)
+- {
+- errmsg= "type mismatch";
+- goto err;
+- }
+-
+- if (strcmp(name, plugin->name))
+- {
+- errmsg= "name mismatch";
+- goto err;
+- }
+-
+- if (type < 0 && find_plugin(name, plugin->type))
+- {
+- errmsg= "it is already loaded";
+- goto err;
+- }
+-
+- plugin= add_plugin(mysql, plugin, dlhandle, argc, args);
+-
+- pthread_mutex_unlock(&LOCK_load_client_plugin);
+-
+- return plugin;
+-
+-err:
+- pthread_mutex_unlock(&LOCK_load_client_plugin);
+- my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
+- ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg);
+- return NULL;
+-}
+-
+-
+-/* see <mysql/client_plugin.h> for a full description */
+-struct st_mysql_client_plugin *
+-mysql_load_plugin(MYSQL *mysql, const char *name, int type, int argc, ...)
+-{
+- struct st_mysql_client_plugin *p;
+- va_list args;
+- va_start(args, argc);
+- p= mysql_load_plugin_v(mysql, name, type, argc, args);
+- va_end(args);
+- return p;
+-}
+-
+-
+-/* see <mysql/client_plugin.h> for a full description */
+-struct st_mysql_client_plugin *
+-mysql_client_find_plugin(MYSQL *mysql, const char *name, int type)
+-{
+- struct st_mysql_client_plugin *p;
+-
+- if (is_not_initialized(mysql, name))
+- return NULL;
+-
+- if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS)
+- {
+- my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
+- ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, "invalid type");
+- }
+-
+- if ((p= find_plugin(name, type)))
+- return p;
+-
+- /* not found, load it */
+- return mysql_load_plugin(mysql, name, type, 0);
+-}
+-
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/CMakeLists.txt mariadb-native-client.trunk/libmysql/CMakeLists.txt
+--- mariadb/libmysql/CMakeLists.txt 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+@@ -1,179 +0,0 @@
+-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+- ${ZLIB_INC}
+- ${CMAKE_SOURCE_DIR}/libmysql)
+-
+-IF(OPENSSL_FOUND)
+- INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
+-ENDIF()
+-
+-
+-ADD_DEFINITIONS(-D ENABLED_LOCAL_INFILE)
+-ADD_DEFINITIONS(-D HAVE_COMPRESS)
+-ADD_DEFINITIONS(-D THREAD)
+-
+-SET(LIBMYSQL_SOURCES
+-array.c
+-bchange.c
+-bmove.c
+-bmove_upp.c
+-my_charset.c
+-violite.c
+-net.c
+-charset.c
+-dbug.c
+-default.c
+-errmsg.c
+-my_vsnprintf.c
+-errors.c
+-getopt1.c
+-getopt.c
+-get_password.c
+-int2str.c
+-is_prefix.c
+-libmysql.c
+-list.c
+-llstr.c
+-longlong2str.c
+-mf_dirname.c
+-mf_fn_ext.c
+-mf_format.c
+-mf_loadpath.c
+-mf_pack.c
+-mf_path.c
+-mf_tempfile.c
+-mf_unixpath.c
+-mf_wcomp.c
+-mulalloc.c
+-my_alloc.c
+-my_compress.c
+-my_create.c
+-my_delete.c
+-my_div.c
+-my_error.c
+-my_fopen.c
+-my_fstream.c
+-my_gethostbyname.c
+-my_getwd.c
+-my_init.c
+-my_lib.c
+-my_malloc.c
+-my_messnc.c
+-my_net.c
+-my_once.c
+-my_open.c
+-my_port.c
+-my_pthread.c
+-my_read.c
+-my_realloc.c
+-my_seek.c
+-my_static.c
+-my_symlink.c
+-my_thr_init.c
+-my_write.c
+-password.c
+-safemalloc.c
+-str2int.c
+-strcend.c
+-strcont.c
+-strend.c
+-strfill.c
+-string.c
+-strinstr.c
+-strmake.c
+-strmov.c
+-strnmov.c
+-strtoll.c
+-strtoull.c
+-strxmov.c
+-strxnmov.c
+-thr_mutex.c
+-typelib.c
+-sha1.c
+-my_stmt.c
+-my_loaddata.c
+-my_stmt_codec.c
+-client_plugin.c
+-my_auth.c
+-my_secure.c
+-libmysql_exports.def
+-)
+-
+-
+-
+-IF(ZLIB_FOUND)
+- INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+- LINK_LIBRARIES(${ZLIB_LIBRARY})
+-ELSE()
+- SET(ZLIB_SOURCES
+- ../zlib/adler32.c
+- ../zlib/compress.c
+- ../zlib/crc32.c
+- ../zlib/deflate.c
+- ../zlib/example.c
+- ../zlib/gzclose.c
+- ../zlib/gzlib.c
+- ../zlib/gzread.c
+- ../zlib/gzwrite.c
+- ../zlib/infback.c
+- ../zlib/inffast.c
+- ../zlib/inflate.c
+- ../zlib/inftrees.c
+- ../zlib/trees.c
+- ../zlib/uncompr.c
+- ../zlib/zutil.c
+- )
+- SET(LIBMYSQL_SOURCES ${LIBMYSQL_SOURCES} ${ZLIB_SOURCES})
+- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib)
+-ENDIF()
+-
+-
+-ADD_LIBRARY(mariadbclient STATIC ${LIBMYSQL_SOURCES})
+-TARGET_LINK_LIBRARIES(mariadbclient ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
+-IF(OPENSSL_FOUND)
+- TARGET_LINK_LIBRARIES(mariadbclient ${OPENSSL_LIBRARIES})
+-ENDIF()
+-
+-ADD_LIBRARY(libmariadb SHARED ${LIBMYSQL_SOURCES})
+-TARGET_LINK_LIBRARIES(libmariadb ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
+-
+-IF(OPENSSL_FOUND)
+- TARGET_LINK_LIBRARIES(libmariadb ${OPENSSL_LIBRARIES})
+-ENDIF()
+-
+-
+-IF(WIN32)
+- TARGET_LINK_LIBRARIES(libmariadb ws2_32)
+- TARGET_LINK_LIBRARIES(mariadbclient ws2_32)
+-ELSE()
+- TARGET_LINK_LIBRARIES(libmariadb m)
+- TARGET_LINK_LIBRARIES(mariadbclient m)
+-ENDIF()
+-
+-IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
+- TARGET_LINK_LIBRARIES (libmariadb "-Wl,--no-undefined")
+- TARGET_LINK_LIBRARIES (libmariadb "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.txt")
+-ENDIF()
+-
+-SET_TARGET_PROPERTIES(libmariadb PROPERTIES PREFIX "")
+-
+-SET_TARGET_PROPERTIES(libmariadb PROPERTIES VERSION
+- ${CPACK_PACKAGE_VERSION_MAJOR}
+- SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
+-
+-#
+-# Installation
+-#
+-
+-INSTALL(TARGETS
+- libmariadb mariadbclient
+- RUNTIME DESTINATION "lib"
+- LIBRARY DESTINATION "lib"
+- ARCHIVE DESTINATION "lib")
+-
+-INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include
+- DESTINATION mariadbclient)
+-INSTALL(FILES
+- ${CMAKE_BINARY_DIR}/include/my_config.h
+- ${CMAKE_BINARY_DIR}/include/mysql_version.h
+- DESTINATION mariadbclient/include
+-)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/dbug.c mariadb-native-client.trunk/libmysql/dbug.c
+--- mariadb/libmysql/dbug.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/dbug.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,2069 +0,0 @@
+-/******************************************************************************
+- * *
+- * N O T I C E *
+- * *
+- * Copyright Abandoned, 1987, Fred Fish *
+- * *
+- * *
+- * This previously copyrighted work has been placed into the public *
+- * domain by the author and may be freely used for any purpose, *
+- * private or commercial. *
+- * *
+- * Because of the number of inquiries I was receiving about the use *
+- * of this product in commercially developed works I have decided to *
+- * simply make it public domain to further its unrestricted use. I *
+- * specifically would be most happy to see this material become a *
+- * part of the standard Unix distributions by AT&T and the Berkeley *
+- * Computer Science Research Group, and a standard part of the GNU *
+- * system from the Free Software Foundation. *
+- * *
+- * I would appreciate it, as a courtesy, if this notice is left in *
+- * all copies and derivative works. Thank you. *
+- * *
+- * The author makes no warranty of any kind with respect to this *
+- * product and explicitly disclaims any implied warranties of mer- *
+- * chantability or fitness for any particular purpose. *
+- * *
+- ******************************************************************************
+- */
+-
+-
+-/*
+- * FILE
+- *
+- * dbug.c runtime support routines for dbug package
+- *
+- * SCCS
+- *
+- * @(#)dbug.c 1.25 7/25/89
+- *
+- * DESCRIPTION
+- *
+- * These are the runtime support routines for the dbug package.
+- * The dbug package has two main components; the user include
+- * file containing various macro definitions, and the runtime
+- * support routines which are called from the macro expansions.
+- *
+- * Externally visible functions in the runtime support module
+- * use the naming convention pattern "_db_xx...xx_", thus
+- * they are unlikely to collide with user defined function names.
+- *
+- * AUTHOR(S)
+- *
+- * Fred Fish (base code)
+- * Enhanced Software Technologies, Tempe, AZ
+- * asuvax!mcdphx!estinc!fnf
+- *
+- * Binayak Banerjee (profiling enhancements)
+- * seismo!bpa!sjuvax!bbanerje
+- *
+- * Michael Widenius:
+- * DBUG_DUMP - To dump a pice of memory.
+- * PUSH_FLAG "O" - To be used insted of "o" if we don't
+- * want flushing (for slow systems)
+- * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
+- * of creating a new one.
+- * Check of malloc on entry/exit (option "S")
+- */
+-
+-#ifdef DBUG_OFF
+-#undef DBUG_OFF
+-#endif
+-#include <my_global.h>
+-#include <m_string.h>
+-#include <errno.h>
+-#if defined(MSDOS) || defined(_WIN32)
+-#include <process.h>
+-#endif
+-
+-#ifdef _DBUG_CONDITION_
+-#define _DBUG_START_CONDITION_ "d:t"
+-#else
+-#define _DBUG_START_CONDITION_ ""
+-#endif
+-
+-/*
+- * Manifest constants that should not require any changes.
+- */
+-
+-#define EOS '\000' /* End Of String marker */
+-
+-/*
+- * Manifest constants which may be "tuned" if desired.
+- */
+-
+-#define PRINTBUF 1024 /* Print buffer size */
+-#define INDENT 2 /* Indentation per trace level */
+-#define MAXDEPTH 200 /* Maximum trace depth default */
+-
+-/*
+- * The following flags are used to determine which
+- * capabilities the user has enabled with the state
+- * push macro.
+- */
+-
+-#define TRACE_ON 000001 /* Trace enabled */
+-#define DEBUG_ON 000002 /* Debug enabled */
+-#define FILE_ON 000004 /* File name print enabled */
+-#define LINE_ON 000010 /* Line number print enabled */
+-#define DEPTH_ON 000020 /* Function nest level print enabled */
+-#define PROCESS_ON 000040 /* Process name print enabled */
+-#define NUMBER_ON 000100 /* Number each line of output */
+-#define PROFILE_ON 000200 /* Print out profiling code */
+-#define PID_ON 000400 /* Identify each line with process id */
+-#define SANITY_CHECK_ON 001000 /* Check safemalloc on DBUG_ENTER */
+-#define FLUSH_ON_WRITE 002000 /* Flush on every write */
+-
+-#define TRACING (stack -> flags & TRACE_ON)
+-#define DEBUGGING (stack -> flags & DEBUG_ON)
+-#define PROFILING (stack -> flags & PROFILE_ON)
+-#define STREQ(a,b) (strcmp(a,b) == 0)
+-
+-/*
+- * Typedefs to make things more obvious.
+- */
+-
+-#ifndef _WIN32
+-typedef int BOOLEAN;
+-#else
+-#define BOOLEAN BOOL
+-#endif
+-
+-/*
+- * Make it easy to change storage classes if necessary.
+- */
+-
+-#define IMPORT extern /* Names defined externally */
+-#define EXPORT /* Allocated here, available globally */
+-#define AUTO auto /* Names to be allocated on stack */
+-#define REGISTER register /* Names to be placed in registers */
+-
+-/*
+- * The default file for profiling. Could also add another flag
+- * (G?) which allowed the user to specify this.
+- *
+- * If the automatic variables get allocated on the stack in
+- * reverse order from their declarations, then define AUTOS_REVERSE.
+- * This is used by the code that keeps track of stack usage. For
+- * forward allocation, the difference in the dbug frame pointers
+- * represents stack used by the callee function. For reverse allocation,
+- * the difference represents stack used by the caller function.
+- *
+- */
+-
+-#define PROF_FILE "dbugmon.out"
+-#define PROF_EFMT "E\t%ld\t%s\n"
+-#define PROF_SFMT "S\t%lx\t%lx\t%s\n"
+-#define PROF_XFMT "X\t%ld\t%s\n"
+-
+-#ifdef M_I386 /* predefined by xenix 386 compiler */
+-#define AUTOS_REVERSE 1
+-#endif
+-
+-/*
+- * Variables which are available externally but should only
+- * be accessed via the macro package facilities.
+- */
+-
+-EXPORT FILE *_db_fp_ = (FILE *) 0; /* Output stream, default stderr */
+-EXPORT char *_db_process_ = (char*) "dbug"; /* Pointer to process name; argv[0] */
+-EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */
+-EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */
+-EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if profile currently on */
+-EXPORT BOOLEAN _no_db_ = FALSE; /* TRUE if no debugging at all */
+-
+-/*
+- * Externally supplied functions.
+- */
+-
+-#ifndef HAVE_PERROR
+-static void perror (); /* Fake system/library error print routine */
+-#endif
+-
+-IMPORT int _sanity(const char *file,uint line);
+-
+-/*
+- * The user may specify a list of functions to trace or
+- * debug. These lists are kept in a linear linked list,
+- * a very simple implementation.
+- */
+-
+-struct link {
+- char *str; /* Pointer to link's contents */
+- struct link *next_link; /* Pointer to the next link */
+-};
+-
+-/*
+- * Debugging states can be pushed or popped off of a
+- * stack which is implemented as a linked list. Note
+- * that the head of the list is the current state and the
+- * stack is pushed by adding a new state to the head of the
+- * list or popped by removing the first link.
+- */
+-
+-struct state {
+- int flags; /* Current state flags */
+- int maxdepth; /* Current maximum trace depth */
+- uint delay; /* Delay after each output line */
+- int sub_level; /* Sub this from code_state->level */
+- FILE *out_file; /* Current output stream */
+- FILE *prof_file; /* Current profiling stream */
+- char name[FN_REFLEN]; /* Name of output file */
+- struct link *functions; /* List of functions */
+- struct link *p_functions; /* List of profiled functions */
+- struct link *keywords; /* List of debug keywords */
+- struct link *processes; /* List of process names */
+- struct state *next_state; /* Next state in the list */
+-};
+-
+-
+-/*
+- * Local variables not seen by user.
+- */
+-
+-
+-static my_bool init_done = FALSE; /* Set to TRUE when initialization done */
+-static struct state *stack=0;
+-
+-typedef struct st_code_state {
+- int lineno; /* Current debugger output line number */
+- int level; /* Current function nesting level */
+- const char *func; /* Name of current user function */
+- const char *file; /* Name of current user file */
+- char **framep; /* Pointer to current frame */
+- int jmplevel; /* Remember nesting level at setjmp () */
+- const char *jmpfunc; /* Remember current function for setjmp */
+- const char *jmpfile; /* Remember current file for setjmp */
+-
+-/*
+- * The following variables are used to hold the state information
+- * between the call to _db_pargs_() and _db_doprnt_(), during
+- * expansion of the DBUG_PRINT macro. This is the only macro
+- * that currently uses these variables.
+- *
+- * These variables are currently used only by _db_pargs_() and
+- * _db_doprnt_().
+- */
+-
+- uint u_line; /* User source code line number */
+- const char *u_keyword; /* Keyword for current macro */
+- int locked; /* If locked with _db_lock_file */
+-} CODE_STATE;
+-
+- /* Parse a debug command string */
+-static struct link *ListParse(char *ctlp);
+- /* Make a fresh copy of a string */
+-static char *StrDup(const char *str);
+- /* Open debug output stream */
+-static void DBUGOpenFile(const char *name, int append);
+-#ifndef THREAD
+- /* Open profile output stream */
+-static FILE *OpenProfile(const char *name);
+- /* Profile if asked for it */
+-static BOOLEAN DoProfile(void);
+-#endif
+- /* Return current user time (ms) */
+-#ifndef THREAD
+-static unsigned long Clock (void);
+-#endif
+- /* Close debug output stream */
+-static void CloseFile(FILE *fp);
+- /* Push current debug state */
+-static void PushState(void);
+- /* Test for tracing enabled */
+-static BOOLEAN DoTrace(CODE_STATE *state);
+- /* Test to see if file is writable */
+-#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
+-static BOOLEAN Writable(char *pathname);
+-#endif
+- /* Allocate memory for runtime support */
+-static char *DbugMalloc(int size);
+- /* Remove leading pathname components */
+-static char *BaseName(const char *pathname);
+-static void DoPrefix(uint line);
+-static void FreeList(struct link *linkp);
+-static void Indent(int indent);
+-static BOOLEAN InList(struct link *linkp,const char *cp);
+-static void dbug_flush(CODE_STATE *);
+-static void DbugExit(const char *why);
+-static int DelayArg(int value);
+- /* Supplied in Sys V runtime environ */
+- /* Break string into tokens */
+-static char *static_strtok(char *s1,pchar chr);
+-
+-/*
+- * Miscellaneous printf format strings.
+- */
+-
+-#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
+-#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
+-#define ERR_CLOSE "%s: can't close debug file: "
+-#define ERR_ABORT "%s: debugger aborting because %s\n"
+-#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "
+-
+-/*
+- * Macros and defines for testing file accessibility under UNIX and MSDOS.
+- */
+-
+-#undef EXISTS
+-#if !defined(HAVE_ACCESS) || defined(MSDOS)
+-#define EXISTS(pathname) (FALSE) /* Assume no existance */
+-#define Writable(name) (TRUE)
+-#else
+-#define EXISTS(pathname) (access (pathname, F_OK) == 0)
+-#define WRITABLE(pathname) (access (pathname, W_OK) == 0)
+-#endif
+-#ifndef MSDOS
+-#define ChangeOwner(name)
+-#else
+-static void ChangeOwner(char *pathname);
+-#endif
+-
+-/*
+- * Translate some calls among different systems.
+- */
+-
+-#if defined(unix) || defined(xenix) || defined(VMS) || defined(__NetBSD__)
+-# define Delay(A) sleep((uint) A)
+-#elif defined(AMIGA)
+-IMPORT int Delay (); /* Pause for given number of ticks */
+-#else
+-static int Delay(int ticks);
+-#endif
+-
+-
+-/*
+-** Macros to allow dbugging with threads
+-*/
+-
+-#ifdef THREAD
+-#include <my_pthread.h>
+-pthread_mutex_t THR_LOCK_dbug;
+-
+-static void init_dbug_state(void)
+-{
+- pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
+-}
+-
+-static CODE_STATE *code_state(void)
+-{
+- CODE_STATE *state=0;
+- struct st_my_thread_var *tmp=my_thread_var;
+- if (tmp)
+- {
+- if (!(state=(CODE_STATE *) tmp->dbug))
+- {
+- state=(CODE_STATE*) DbugMalloc(sizeof(*state));
+- bzero((char*) state,sizeof(*state));
+- state->func="?func";
+- state->file="?file";
+- tmp->dbug=(gptr) state;
+- }
+- }
+- return state;
+-}
+-
+-#else /* !THREAD */
+-
+-#define init_dbug_state()
+-#define code_state() (&static_code_state)
+-#define pthread_mutex_lock(A) {}
+-#define pthread_mutex_unlock(A) {}
+-static CODE_STATE static_code_state = { 0,0,"?func","?file",NULL,0,NULL,
+- NULL,0,"?",0};
+-#endif
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_push_ push current debugger state and set up new one
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_push_ (control)
+- * char *control;
+- *
+- * DESCRIPTION
+- *
+- * Given pointer to a debug control string in "control", pushes
+- * the current debug state, parses the control string, and sets
+- * up a new debug state.
+- *
+- * The only attribute of the new state inherited from the previous
+- * state is the current function nesting level. This can be
+- * overridden by using the "r" flag in the control string.
+- *
+- * The debug control string is a sequence of colon separated fields
+- * as follows:
+- *
+- * <field_1>:<field_2>:...:<field_N>
+- *
+- * Each field consists of a mandatory flag character followed by
+- * an optional "," and comma separated list of modifiers:
+- *
+- * flag[,modifier,modifier,...,modifier]
+- *
+- * The currently recognized flag characters are:
+- *
+- * d Enable output from DBUG_<N> macros for
+- * for the current state. May be followed
+- * by a list of keywords which selects output
+- * only for the DBUG macros with that keyword.
+- * A null list of keywords implies output for
+- * all macros.
+- *
+- * D Delay after each debugger output line.
+- * The argument is the number of tenths of seconds
+- * to delay, subject to machine capabilities.
+- * I.E. -#D,20 is delay two seconds.
+- *
+- * f Limit debugging and/or tracing, and profiling to the
+- * list of named functions. Note that a null list will
+- * disable all functions. The appropriate "d" or "t"
+- * flags must still be given, this flag only limits their
+- * actions if they are enabled.
+- *
+- * F Identify the source file name for each
+- * line of debug or trace output.
+- *
+- * i Identify the process with the pid for each line of
+- * debug or trace output.
+- *
+- * g Enable profiling. Create a file called 'dbugmon.out'
+- * containing information that can be used to profile
+- * the program. May be followed by a list of keywords
+- * that select profiling only for the functions in that
+- * list. A null list implies that all functions are
+- * considered.
+- *
+- * L Identify the source file line number for
+- * each line of debug or trace output.
+- *
+- * n Print the current function nesting depth for
+- * each line of debug or trace output.
+- *
+- * N Number each line of dbug output.
+- *
+- * o Redirect the debugger output stream to the
+- * specified file. The default output is stderr.
+- *
+- * O As O but the file is really flushed between each
+- * write. When neaded the file is closed and reopened
+- * between each write.
+- *
+- * p Limit debugger actions to specified processes.
+- * A process must be identified with the
+- * DBUG_PROCESS macro and match one in the list
+- * for debugger actions to occur.
+- *
+- * P Print the current process name for each
+- * line of debug or trace output.
+- *
+- * r When pushing a new state, do not inherit
+- * the previous state's function nesting level.
+- * Useful when the output is to start at the
+- * left margin.
+- *
+- * S Do function _sanity(_file_,_line_) at each
+- * debugged function until _sanity() returns
+- * something that differs from 0.
+- * (Moustly used with safemalloc)
+- *
+- * t Enable function call/exit trace lines.
+- * May be followed by a list (containing only
+- * one modifier) giving a numeric maximum
+- * trace level, beyond which no output will
+- * occur for either debugging or tracing
+- * macros. The default is a compile time
+- * option.
+- *
+- * Some examples of debug control strings which might appear
+- * on a shell command line (the "-#" is typically used to
+- * introduce a control string to an application program) are:
+- *
+- * -#d:t
+- * -#d:f,main,subr1:F:L:t,20
+- * -#d,input,output,files:n
+- *
+- * For convenience, any leading "-#" is stripped off.
+- *
+- */
+-
+-void _db_push_ (const char *control)
+-{
+- reg1 char *scan;
+- reg2 struct link *temp;
+- CODE_STATE *state;
+- char *new_str;
+-
+- if (! _db_fp_)
+- _db_fp_= stderr; /* Output stream, default stderr */
+-
+- if (control && *control == '-')
+- {
+- if (*++control == '#')
+- control++;
+- }
+- if (*control)
+- _no_db_=0; /* We are using dbug after all */
+-
+- new_str = StrDup (control);
+- PushState ();
+- state=code_state();
+-
+- scan = static_strtok (new_str, ':');
+- for (; scan != NULL; scan = static_strtok ((char *)NULL, ':')) {
+- switch (*scan++) {
+- case 'd':
+- _db_on_ = TRUE;
+- stack -> flags |= DEBUG_ON;
+- if (*scan++ == ',') {
+- stack -> keywords = ListParse (scan);
+- }
+- break;
+- case 'D':
+- stack -> delay = 0;
+- if (*scan++ == ',') {
+- temp = ListParse (scan);
+- stack -> delay = DelayArg (atoi (temp -> str));
+- FreeList (temp);
+- }
+- break;
+- case 'f':
+- if (*scan++ == ',') {
+- stack -> functions = ListParse (scan);
+- }
+- break;
+- case 'F':
+- stack -> flags |= FILE_ON;
+- break;
+- case 'i':
+- stack -> flags |= PID_ON;
+- break;
+-#ifndef THREAD
+- case 'g':
+- _db_pon_ = TRUE;
+- if (OpenProfile(PROF_FILE))
+- {
+- stack -> flags |= PROFILE_ON;
+- if (*scan++ == ',')
+- stack -> p_functions = ListParse (scan);
+- }
+- break;
+-#endif
+- case 'L':
+- stack -> flags |= LINE_ON;
+- break;
+- case 'n':
+- stack -> flags |= DEPTH_ON;
+- break;
+- case 'N':
+- stack -> flags |= NUMBER_ON;
+- break;
+- case 'A':
+- case 'O':
+- stack -> flags |= FLUSH_ON_WRITE;
+- case 'a':
+- case 'o':
+- if (*scan++ == ',') {
+- temp = ListParse (scan);
+- DBUGOpenFile(temp -> str, (int) (scan[-2] == 'A' || scan[-2] == 'a'));
+- FreeList (temp);
+- } else {
+- DBUGOpenFile ("-",0);
+- }
+- break;
+- case 'p':
+- if (*scan++ == ',') {
+- stack -> processes = ListParse (scan);
+- }
+- break;
+- case 'P':
+- stack -> flags |= PROCESS_ON;
+- break;
+- case 'r':
+- stack->sub_level= state->level;
+- break;
+- case 't':
+- stack -> flags |= TRACE_ON;
+- if (*scan++ == ',') {
+- temp = ListParse (scan);
+- stack -> maxdepth = atoi (temp -> str);
+- FreeList (temp);
+- }
+- break;
+- case 'S':
+- stack -> flags |= SANITY_CHECK_ON;
+- break;
+- }
+- }
+- free (new_str);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_pop_ pop the debug stack
+- *
+- * DESCRIPTION
+- *
+- * Pops the debug stack, returning the debug state to its
+- * condition prior to the most recent _db_push_ invocation.
+- * Note that the pop will fail if it would remove the last
+- * valid state from the stack. This prevents user errors
+- * in the push/pop sequence from screwing up the debugger.
+- * Maybe there should be some kind of warning printed if the
+- * user tries to pop too many states.
+- *
+- */
+-
+-void _db_pop_ ()
+-{
+- reg1 struct state *discard;
+- discard = stack;
+- if (discard != NULL && discard -> next_state != NULL) {
+- stack = discard -> next_state;
+- _db_fp_ = stack -> out_file;
+- _db_pfp_ = stack -> prof_file;
+- if (discard -> keywords != NULL) {
+- FreeList (discard -> keywords);
+- }
+- if (discard -> functions != NULL) {
+- FreeList (discard -> functions);
+- }
+- if (discard -> processes != NULL) {
+- FreeList (discard -> processes);
+- }
+- if (discard -> p_functions != NULL) {
+- FreeList (discard -> p_functions);
+- }
+- CloseFile (discard -> out_file);
+- if (discard -> prof_file)
+- CloseFile (discard -> prof_file);
+- free ((char *) discard);
+- if (!(stack->flags & DEBUG_ON))
+- _db_on_=0;
+- }
+- else
+- {
+- _db_on_=0;
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_enter_ process entry point to user function
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_enter_ (_func_, _file_, _line_,
+- * _sfunc_, _sfile_, _slevel_, _sframep_)
+- * char *_func_; points to current function name
+- * char *_file_; points to current file name
+- * int _line_; called from source line number
+- * char **_sfunc_; save previous _func_
+- * char **_sfile_; save previous _file_
+- * int *_slevel_; save previous nesting level
+- * char ***_sframep_; save previous frame pointer
+- *
+- * DESCRIPTION
+- *
+- * Called at the beginning of each user function to tell
+- * the debugger that a new function has been entered.
+- * Note that the pointers to the previous user function
+- * name and previous user file name are stored on the
+- * caller's stack (this is why the ENTER macro must be
+- * the first "executable" code in a function, since it
+- * allocates these storage locations). The previous nesting
+- * level is also stored on the callers stack for internal
+- * self consistency checks.
+- *
+- * Also prints a trace line if tracing is enabled and
+- * increments the current function nesting depth.
+- *
+- * Note that this mechanism allows the debugger to know
+- * what the current user function is at all times, without
+- * maintaining an internal stack for the function names.
+- *
+- */
+-
+-void _db_enter_ (
+-const char *_func_,
+-const char *_file_,
+-uint _line_,
+-const char **_sfunc_,
+-const char **_sfile_,
+-uint *_slevel_,
+-char ***_sframep_ __attribute__((unused)))
+-{
+- reg1 CODE_STATE *state;
+-
+- if (!_no_db_)
+- {
+- int save_errno=errno;
+- if (!init_done)
+- _db_push_ (_DBUG_START_CONDITION_);
+- state=code_state();
+-
+- *_sfunc_ = state->func;
+- *_sfile_ = state->file;
+- state->func =(char*) _func_;
+- state->file = (char*) _file_; /* BaseName takes time !! */
+- *_slevel_ = ++state->level;
+-#ifndef THREAD
+- *_sframep_ = state->framep;
+- state->framep = (char **) _sframep_;
+- if (DoProfile ())
+- {
+- long stackused;
+- if (*state->framep == NULL) {
+- stackused = 0;
+- } else {
+- stackused = ((long)(*state->framep)) - ((long)(state->framep));
+- stackused = stackused > 0 ? stackused : -stackused;
+- }
+- (void) fprintf (_db_pfp_, PROF_EFMT , Clock (), state->func);
+-#ifdef AUTOS_REVERSE
+- (void) fprintf (_db_pfp_, PROF_SFMT, state->framep, stackused, *_sfunc_);
+-#else
+- (void) fprintf (_db_pfp_, PROF_SFMT, (ulong) state->framep, stackused,
+- state->func);
+-#endif
+- (void) fflush (_db_pfp_);
+- }
+-#endif
+- if (DoTrace (state))
+- {
+- if (!state->locked)
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- DoPrefix (_line_);
+- Indent (state -> level);
+- (void) fprintf (_db_fp_, ">%s\n", state->func);
+- dbug_flush (state); /* This does a unlock */
+- }
+-#ifdef SAFEMALLOC
+- if (stack -> flags & SANITY_CHECK_ON)
+- if (_sanity(_file_,_line_)) /* Check of safemalloc */
+- stack -> flags &= ~SANITY_CHECK_ON;
+-#endif
+- errno=save_errno;
+- }
+-}
+-
+-/*
+- * FUNCTION
+- *
+- * _db_return_ process exit from user function
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
+- * int _line_; current source line number
+- * char **_sfunc_; where previous _func_ is to be retrieved
+- * char **_sfile_; where previous _file_ is to be retrieved
+- * int *_slevel_; where previous level was stashed
+- *
+- * DESCRIPTION
+- *
+- * Called just before user function executes an explicit or implicit
+- * return. Prints a trace line if trace is enabled, decrements
+- * the current nesting level, and restores the current function and
+- * file names from the defunct function's stack.
+- *
+- */
+-
+-void _db_return_ (
+-uint _line_,
+-const char **_sfunc_,
+-const char **_sfile_,
+-uint *_slevel_)
+-{
+- CODE_STATE *state;
+-
+- if (!_no_db_)
+- {
+- int save_errno=errno;
+- if (!init_done)
+- _db_push_ ("");
+- if (!(state=code_state()))
+- return; /* Only happens at end of program */
+- if (stack->flags & (TRACE_ON | DEBUG_ON | PROFILE_ON))
+- {
+- if (!state->locked)
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- if (state->level != (int) *_slevel_)
+- (void) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_,
+- state->func);
+- else
+- {
+-#ifdef SAFEMALLOC
+- if (stack -> flags & SANITY_CHECK_ON)
+- if (_sanity(*_sfile_,_line_))
+- stack->flags &= ~SANITY_CHECK_ON;
+-#endif
+-#ifndef THREAD
+- if (DoProfile ())
+- (void) fprintf (_db_pfp_, PROF_XFMT, Clock(), state->func);
+-#endif
+- if (DoTrace (state))
+- {
+- DoPrefix (_line_);
+- Indent (state->level);
+- (void) fprintf (_db_fp_, "<%s\n", state->func);
+- }
+- }
+- dbug_flush(state);
+- }
+- state->level = *_slevel_-1;
+- state->func = *_sfunc_;
+- state->file = *_sfile_;
+-#ifndef THREAD
+- if (state->framep != NULL)
+- state->framep = (char **) *state->framep;
+-#endif
+- errno=save_errno;
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_pargs_ log arguments for subsequent use by _db_doprnt_()
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_pargs_ (_line_, keyword)
+- * int _line_;
+- * char *keyword;
+- *
+- * DESCRIPTION
+- *
+- * The new universal printing macro DBUG_PRINT, which replaces
+- * all forms of the DBUG_N macros, needs two calls to runtime
+- * support routines. The first, this function, remembers arguments
+- * that are used by the subsequent call to _db_doprnt_().
+- *
+- */
+-
+-void _db_pargs_ (
+-uint _line_,
+-const char *keyword)
+-{
+- CODE_STATE *state=code_state();
+- state->u_line = _line_;
+- state->u_keyword = (char*) keyword;
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_doprnt_ handle print of debug lines
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_doprnt_ (format, va_alist)
+- * char *format;
+- * va_dcl;
+- *
+- * DESCRIPTION
+- *
+- * When invoked via one of the DBUG macros, tests the current keyword
+- * set by calling _db_pargs_() to see if that macro has been selected
+- * for processing via the debugger control string, and if so, handles
+- * printing of the arguments via the format string. The line number
+- * of the DBUG macro in the source is found in u_line.
+- *
+- * Note that the format string SHOULD NOT include a terminating
+- * newline, this is supplied automatically.
+- *
+- */
+-
+-#include <stdarg.h>
+-
+-void _db_doprnt_ (const char *format,...)
+-{
+- va_list args;
+- CODE_STATE *state;
+- state=code_state();
+-
+- va_start(args,format);
+-
+- if (_db_keyword_ (state->u_keyword)) {
+- int save_errno=errno;
+- if (!state->locked)
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- DoPrefix (state->u_line);
+- if (TRACING) {
+- Indent (state->level + 1);
+- } else {
+- (void) fprintf (_db_fp_, "%s: ", state->func);
+- }
+- (void) fprintf (_db_fp_, "%s: ", state->u_keyword);
+- (void) vfprintf (_db_fp_, format, args);
+- va_end(args);
+- (void) fputc('\n',_db_fp_);
+- dbug_flush(state);
+- errno=save_errno;
+- }
+- va_end(args);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_dump_ dump a string until '\0' is found
+- *
+- * SYNOPSIS
+- *
+- * void _db_dump_ (_line_,keyword,memory,length)
+- * int _line_; current source line number
+- * char *keyword;
+- * char *memory; Memory to print
+- * int length; Bytes to print
+- *
+- * DESCRIPTION
+- * Dump N characters in a binary array.
+- * Is used to examine corrputed memory or arrays.
+- */
+-
+-void _db_dump_(
+-uint _line_,
+-const char *keyword,
+-const char *memory,
+-uint length)
+-{
+- int pos;
+- char dbuff[90];
+- CODE_STATE *state;
+- state=code_state();
+-
+- if (_db_keyword_ ((char*) keyword))
+- {
+- if (!state->locked)
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- DoPrefix (_line_);
+- if (TRACING)
+- {
+- Indent (state->level + 1);
+- pos= min(max(state->level-stack->sub_level,0)*INDENT,80);
+- }
+- else
+- {
+- fprintf(_db_fp_, "%s: ", state->func);
+- }
+- sprintf(dbuff,"%s: Memory: %lx Bytes: (%d)\n",
+- keyword,(ulong) memory, length);
+- (void) fputs(dbuff,_db_fp_);
+-
+- pos=0;
+- while (length-- > 0)
+- {
+- uint tmp= *((unsigned char*) memory++);
+- if ((pos+=3) >= 80)
+- {
+- fputc('\n',_db_fp_);
+- pos=3;
+- }
+- fputc(_dig_vec[((tmp >> 4) & 15)], _db_fp_);
+- fputc(_dig_vec[tmp & 15], _db_fp_);
+- fputc(' ',_db_fp_);
+- }
+- (void) fputc('\n',_db_fp_);
+- dbug_flush(state);
+- }
+-}
+-
+-/*
+- * FUNCTION
+- *
+- * ListParse parse list of modifiers in debug control string
+- *
+- * SYNOPSIS
+- *
+- * static struct link *ListParse (ctlp)
+- * char *ctlp;
+- *
+- * DESCRIPTION
+- *
+- * Given pointer to a comma separated list of strings in "cltp",
+- * parses the list, building a list and returning a pointer to it.
+- * The original comma separated list is destroyed in the process of
+- * building the linked list, thus it had better be a duplicate
+- * if it is important.
+- *
+- * Note that since each link is added at the head of the list,
+- * the final list will be in "reverse order", which is not
+- * significant for our usage here.
+- *
+- */
+-
+-static struct link *ListParse (
+-char *ctlp)
+-{
+- REGISTER char *start;
+- REGISTER struct link *new_malloc;
+- REGISTER struct link *head;
+-
+- head = NULL;
+- while (*ctlp != EOS) {
+- start = ctlp;
+- while (*ctlp != EOS && *ctlp != ',') {
+- ctlp++;
+- }
+- if (*ctlp == ',') {
+- *ctlp++ = EOS;
+- }
+- new_malloc = (struct link *) DbugMalloc (sizeof (struct link));
+- new_malloc -> str = StrDup (start);
+- new_malloc -> next_link = head;
+- head = new_malloc;
+- }
+- return (head);
+-}
+-
+-/*
+- * FUNCTION
+- *
+- * InList test a given string for member of a given list
+- *
+- * SYNOPSIS
+- *
+- * static BOOLEAN InList (linkp, cp)
+- * struct link *linkp;
+- * char *cp;
+- *
+- * DESCRIPTION
+- *
+- * Tests the string pointed to by "cp" to determine if it is in
+- * the list pointed to by "linkp". Linkp points to the first
+- * link in the list. If linkp is NULL then the string is treated
+- * as if it is in the list (I.E all strings are in the null list).
+- * This may seem rather strange at first but leads to the desired
+- * operation if no list is given. The net effect is that all
+- * strings will be accepted when there is no list, and when there
+- * is a list, only those strings in the list will be accepted.
+- *
+- */
+-
+-static BOOLEAN InList (
+-struct link *linkp,
+-const char *cp)
+-{
+- REGISTER struct link *scan;
+- REGISTER BOOLEAN result;
+-
+- if (linkp == NULL) {
+- result = TRUE;
+- } else {
+- result = FALSE;
+- for (scan = linkp; scan != NULL; scan = scan -> next_link) {
+- if (STREQ (scan -> str, cp)) {
+- result = TRUE;
+- break;
+- }
+- }
+- }
+- return (result);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * PushState push current state onto stack and set up new one
+- *
+- * SYNOPSIS
+- *
+- * static VOID PushState ()
+- *
+- * DESCRIPTION
+- *
+- * Pushes the current state on the state stack, and initializes
+- * a new state. The only parameter inherited from the previous
+- * state is the function nesting level. This action can be
+- * inhibited if desired, via the "r" flag.
+- *
+- * The state stack is a linked list of states, with the new
+- * state added at the head. This allows the stack to grow
+- * to the limits of memory if necessary.
+- *
+- */
+-
+-static void PushState ()
+-{
+- REGISTER struct state *new_malloc;
+-
+- if (!init_done)
+- {
+- init_dbug_state();
+- init_done=TRUE;
+- }
+- (void) code_state(); /* Alloc memory */
+- new_malloc = (struct state *) DbugMalloc (sizeof (struct state));
+- new_malloc -> flags = 0;
+- new_malloc -> delay = 0;
+- new_malloc -> maxdepth = MAXDEPTH;
+- new_malloc -> sub_level=0;
+- new_malloc -> out_file = stderr;
+- new_malloc -> prof_file = (FILE*) 0;
+- new_malloc -> functions = NULL;
+- new_malloc -> p_functions = NULL;
+- new_malloc -> keywords = NULL;
+- new_malloc -> processes = NULL;
+- new_malloc -> next_state = stack;
+- stack=new_malloc;
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DoTrace check to see if tracing is current enabled
+- *
+- * SYNOPSIS
+- *
+- * static BOOLEAN DoTrace (stack)
+- *
+- * DESCRIPTION
+- *
+- * Checks to see if tracing is enabled based on whether the
+- * user has specified tracing, the maximum trace depth has
+- * not yet been reached, the current function is selected,
+- * and the current process is selected. Returns TRUE if
+- * tracing is enabled, FALSE otherwise.
+- *
+- */
+-
+-static BOOLEAN DoTrace (CODE_STATE *state)
+-{
+- reg2 BOOLEAN trace=FALSE;
+-
+- if (TRACING &&
+- state->level <= stack -> maxdepth &&
+- InList (stack -> functions, state->func) &&
+- InList (stack -> processes, _db_process_))
+- trace = TRUE;
+- return (trace);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DoProfile check to see if profiling is current enabled
+- *
+- * SYNOPSIS
+- *
+- * static BOOLEAN DoProfile ()
+- *
+- * DESCRIPTION
+- *
+- * Checks to see if profiling is enabled based on whether the
+- * user has specified profiling, the maximum trace depth has
+- * not yet been reached, the current function is selected,
+- * and the current process is selected. Returns TRUE if
+- * profiling is enabled, FALSE otherwise.
+- *
+- */
+-
+-#ifndef THREAD
+-static BOOLEAN DoProfile ()
+-{
+- REGISTER BOOLEAN profile;
+- CODE_STATE *state;
+- state=code_state();
+-
+- profile = FALSE;
+- if (PROFILING &&
+- state->level <= stack -> maxdepth &&
+- InList (stack -> p_functions, state->func) &&
+- InList (stack -> processes, _db_process_))
+- profile = TRUE;
+- return (profile);
+-}
+-#endif
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_keyword_ test keyword for member of keyword list
+- *
+- * SYNOPSIS
+- *
+- * BOOLEAN _db_keyword_ (keyword)
+- * char *keyword;
+- *
+- * DESCRIPTION
+- *
+- * Test a keyword to determine if it is in the currently active
+- * keyword list. As with the function list, a keyword is accepted
+- * if the list is null, otherwise it must match one of the list
+- * members. When debugging is not on, no keywords are accepted.
+- * After the maximum trace level is exceeded, no keywords are
+- * accepted (this behavior subject to change). Additionally,
+- * the current function and process must be accepted based on
+- * their respective lists.
+- *
+- * Returns TRUE if keyword accepted, FALSE otherwise.
+- *
+- */
+-
+-BOOLEAN _db_keyword_ (
+-const char *keyword)
+-{
+- REGISTER BOOLEAN result;
+- CODE_STATE *state;
+-
+- if (!init_done)
+- _db_push_ ("");
+- state=code_state();
+- result = FALSE;
+- if (DEBUGGING &&
+- state->level <= stack -> maxdepth &&
+- InList (stack -> functions, state->func) &&
+- InList (stack -> keywords, keyword) &&
+- InList (stack -> processes, _db_process_))
+- result = TRUE;
+- return (result);
+-}
+-
+-/*
+- * FUNCTION
+- *
+- * Indent indent a line to the given indentation level
+- *
+- * SYNOPSIS
+- *
+- * static VOID Indent (indent)
+- * int indent;
+- *
+- * DESCRIPTION
+- *
+- * Indent a line to the given level. Note that this is
+- * a simple minded but portable implementation.
+- * There are better ways.
+- *
+- * Also, the indent must be scaled by the compile time option
+- * of character positions per nesting level.
+- *
+- */
+-
+-static void Indent (
+-int indent)
+-{
+- REGISTER int count;
+-
+- indent= max(indent-1-stack->sub_level,0)*INDENT;
+- for (count = 0; count < indent ; count++)
+- {
+- if ((count % INDENT) == 0)
+- fputc('|',_db_fp_);
+- else
+- fputc(' ',_db_fp_);
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * FreeList free all memory associated with a linked list
+- *
+- * SYNOPSIS
+- *
+- * static VOID FreeList (linkp)
+- * struct link *linkp;
+- *
+- * DESCRIPTION
+- *
+- * Given pointer to the head of a linked list, frees all
+- * memory held by the list and the members of the list.
+- *
+- */
+-
+-static void FreeList (
+-struct link *linkp)
+-{
+- REGISTER struct link *old;
+-
+- while (linkp != NULL) {
+- old = linkp;
+- linkp = linkp -> next_link;
+- if (old -> str != NULL) {
+- free (old -> str);
+- }
+- free ((char *) old);
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * StrDup make a duplicate of a string in new memory
+- *
+- * SYNOPSIS
+- *
+- * static char *StrDup (my_string)
+- * char *string;
+- *
+- * DESCRIPTION
+- *
+- * Given pointer to a string, allocates sufficient memory to make
+- * a duplicate copy, and copies the string to the newly allocated
+- * memory. Failure to allocated sufficient memory is immediately
+- * fatal.
+- *
+- */
+-
+-
+-static char *StrDup (
+-const char *str)
+-{
+- reg1 char *new_malloc;
+- new_malloc = DbugMalloc ((int) strlen (str) + 1);
+- (void) strcpy (new_malloc, str);
+- return (new_malloc);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DoPrefix print debugger line prefix prior to indentation
+- *
+- * SYNOPSIS
+- *
+- * static VOID DoPrefix (_line_)
+- * int _line_;
+- *
+- * DESCRIPTION
+- *
+- * Print prefix common to all debugger output lines, prior to
+- * doing indentation if necessary. Print such information as
+- * current process name, current source file name and line number,
+- * and current function nesting depth.
+- *
+- */
+-
+-static void DoPrefix (
+-uint _line_)
+-{
+- CODE_STATE *state;
+- state=code_state();
+-
+- state->lineno++;
+- if (stack -> flags & PID_ON) {
+-#ifdef THREAD
+- (void) fprintf (_db_fp_, "%-7s: ", my_thread_name());
+-#else
+- (void) fprintf (_db_fp_, "%5d: ", (int) getpid ());
+-#endif
+- }
+- if (stack -> flags & NUMBER_ON) {
+- (void) fprintf (_db_fp_, "%5d: ", state->lineno);
+- }
+- if (stack -> flags & PROCESS_ON) {
+- (void) fprintf (_db_fp_, "%s: ", _db_process_);
+- }
+- if (stack -> flags & FILE_ON) {
+- (void) fprintf (_db_fp_, "%14s: ", BaseName(state->file));
+- }
+- if (stack -> flags & LINE_ON) {
+- (void) fprintf (_db_fp_, "%5d: ", _line_);
+- }
+- if (stack -> flags & DEPTH_ON) {
+- (void) fprintf (_db_fp_, "%4d: ", state->level);
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DBUGOpenFile open new output stream for debugger output
+- *
+- * SYNOPSIS
+- *
+- * static VOID DBUGOpenFile (name)
+- * char *name;
+- *
+- * DESCRIPTION
+- *
+- * Given name of a new file (or "-" for stdout) opens the file
+- * and sets the output stream to the new file.
+- *
+- */
+-
+-static void DBUGOpenFile (const char *name,int append)
+-{
+- REGISTER FILE *fp;
+- REGISTER BOOLEAN newfile;
+-
+- if (name != NULL)
+- {
+- strmov(stack->name,name);
+- if (strcmp (name, "-") == 0)
+- {
+- _db_fp_ = stdout;
+- stack -> out_file = _db_fp_;
+- stack -> flags |= FLUSH_ON_WRITE;
+- }
+- else
+- {
+- if (!Writable((char*)name))
+- {
+- (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
+- perror ("");
+- fflush(stderr);
+- }
+- else
+- {
+- newfile= !EXISTS (name);
+- if (!(fp = fopen(name, append ? "a+" : "w")))
+- {
+- (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
+- perror ("");
+- fflush(stderr);
+- }
+- else
+- {
+- _db_fp_ = fp;
+- stack -> out_file = fp;
+- if (newfile) {
+- ChangeOwner (name);
+- }
+- }
+- }
+- }
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * OpenProfile open new output stream for profiler output
+- *
+- * SYNOPSIS
+- *
+- * static FILE *OpenProfile (name)
+- * char *name;
+- *
+- * DESCRIPTION
+- *
+- * Given name of a new file, opens the file
+- * and sets the profiler output stream to the new file.
+- *
+- * It is currently unclear whether the prefered behavior is
+- * to truncate any existing file, or simply append to it.
+- * The latter behavior would be desirable for collecting
+- * accumulated runtime history over a number of separate
+- * runs. It might take some changes to the analyzer program
+- * though, and the notes that Binayak sent with the profiling
+- * diffs indicated that append was the normal mode, but this
+- * does not appear to agree with the actual code. I haven't
+- * investigated at this time [fnf; 24-Jul-87].
+- */
+-
+-#ifndef THREAD
+-static FILE *OpenProfile (const char *name)
+-{
+- REGISTER FILE *fp;
+- REGISTER BOOLEAN newfile;
+-
+- fp=0;
+- if (!Writable (name))
+- {
+- (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+- perror ("");
+- dbug_flush(0);
+- (void) Delay (stack -> delay);
+- }
+- else
+- {
+- newfile= !EXISTS (name);
+- if (!(fp = fopen (name, "w")))
+- {
+- (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+- perror ("");
+- dbug_flush(0);
+- }
+- else
+- {
+- _db_pfp_ = fp;
+- stack -> prof_file = fp;
+- if (newfile)
+- {
+- ChangeOwner (name);
+- }
+- }
+- }
+- return fp;
+-}
+-#endif
+-
+-/*
+- * FUNCTION
+- *
+- * CloseFile close the debug output stream
+- *
+- * SYNOPSIS
+- *
+- * static VOID CloseFile (fp)
+- * FILE *fp;
+- *
+- * DESCRIPTION
+- *
+- * Closes the debug output stream unless it is standard output
+- * or standard error.
+- *
+- */
+-
+-static void CloseFile (
+-FILE *fp)
+-{
+- if (fp != stderr && fp != stdout) {
+- if (fclose (fp) == EOF) {
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- (void) fprintf (_db_fp_, ERR_CLOSE, _db_process_);
+- perror ("");
+- dbug_flush(0);
+- }
+- }
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DbugExit print error message and exit
+- *
+- * SYNOPSIS
+- *
+- * static VOID DbugExit (why)
+- * char *why;
+- *
+- * DESCRIPTION
+- *
+- * Prints error message using current process name, the reason for
+- * aborting (typically out of memory), and exits with status 1.
+- * This should probably be changed to use a status code
+- * defined in the user's debugger include file.
+- *
+- */
+-
+-static void DbugExit (const char *why)
+-{
+- (void) fprintf (stderr, ERR_ABORT, _db_process_, why);
+- (void) fflush (stderr);
+- exit (1);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * DbugMalloc allocate memory for debugger runtime support
+- *
+- * SYNOPSIS
+- *
+- * static long *DbugMalloc (size)
+- * int size;
+- *
+- * DESCRIPTION
+- *
+- * Allocate more memory for debugger runtime support functions.
+- * Failure to to allocate the requested number of bytes is
+- * immediately fatal to the current process. This may be
+- * rather unfriendly behavior. It might be better to simply
+- * print a warning message, freeze the current debugger state,
+- * and continue execution.
+- *
+- */
+-
+-static char *DbugMalloc (
+-int size)
+-{
+- register char *new_malloc;
+-
+- if (!(new_malloc = (char*) malloc ((unsigned int) size)))
+- DbugExit ("out of memory");
+- return (new_malloc);
+-}
+-
+-
+-/*
+- * As strtok but two separators in a row are changed to one
+- * separator (to allow directory-paths in dos).
+- */
+-
+-static char *static_strtok (
+-char *s1,
+-pchar separator)
+-{
+- static char *end = NULL;
+- reg1 char *rtnval,*cpy;
+-
+- rtnval = NULL;
+- if (s1 != NULL)
+- end = s1;
+- if (end != NULL && *end != EOS)
+- {
+- rtnval=cpy=end;
+- do
+- {
+- if ((*cpy++ = *end++) == separator)
+- {
+- if (*end != separator)
+- {
+- cpy--; /* Point at separator */
+- break;
+- }
+- end++; /* Two separators in a row, skipp one */
+- }
+- } while (*end != EOS);
+- *cpy=EOS; /* Replace last separator */
+- }
+- return (rtnval);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * BaseName strip leading pathname components from name
+- *
+- * SYNOPSIS
+- *
+- * static char *BaseName (pathname)
+- * char *pathname;
+- *
+- * DESCRIPTION
+- *
+- * Given pointer to a complete pathname, locates the base file
+- * name at the end of the pathname and returns a pointer to
+- * it.
+- *
+- */
+-
+-static char *BaseName (const char *pathname)
+-{
+- register const char *base;
+-
+- base = strrchr (pathname, FN_LIBCHAR);
+- if (base++ == NullS)
+- base = pathname;
+- return ((char*) base);
+-}
+-
+-
+-/*
+- * FUNCTION
+- *
+- * Writable test to see if a pathname is writable/creatable
+- *
+- * SYNOPSIS
+- *
+- * static BOOLEAN Writable (pathname)
+- * char *pathname;
+- *
+- * DESCRIPTION
+- *
+- * Because the debugger might be linked in with a program that
+- * runs with the set-uid-bit (suid) set, we have to be careful
+- * about opening a user named file for debug output. This consists
+- * of checking the file for write access with the real user id,
+- * or checking the directory where the file will be created.
+- *
+- * Returns TRUE if the user would normally be allowed write or
+- * create access to the named file. Returns FALSE otherwise.
+- *
+- */
+-
+-
+-#ifndef Writable
+-
+-static BOOLEAN Writable (
+-char *pathname)
+-{
+- REGISTER BOOLEAN granted;
+- REGISTER char *lastslash;
+-
+- granted = FALSE;
+- if (EXISTS (pathname)) {
+- if (WRITABLE (pathname)) {
+- granted = TRUE;
+- }
+- } else {
+- lastslash = strrchr (pathname, '/');
+- if (lastslash != NULL) {
+- *lastslash = EOS;
+- } else {
+- pathname = ".";
+- }
+- if (WRITABLE (pathname)) {
+- granted = TRUE;
+- }
+- if (lastslash != NULL) {
+- *lastslash = '/';
+- }
+- }
+- return (granted);
+-}
+-#endif
+-
+-
+-/*
+- * FUNCTION
+- *
+- * ChangeOwner change owner to real user for suid programs
+- *
+- * SYNOPSIS
+- *
+- * static VOID ChangeOwner (pathname)
+- *
+- * DESCRIPTION
+- *
+- * For unix systems, change the owner of the newly created debug
+- * file to the real owner. This is strictly for the benefit of
+- * programs that are running with the set-user-id bit set.
+- *
+- * Note that at this point, the fact that pathname represents
+- * a newly created file has already been established. If the
+- * program that the debugger is linked to is not running with
+- * the suid bit set, then this operation is redundant (but
+- * harmless).
+- *
+- */
+-
+-#ifndef ChangeOwner
+-static void ChangeOwner (
+-char *pathname)
+-{
+- if (chown (pathname, getuid (), getgid ()) == -1)
+- {
+- (void) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
+- perror ("");
+- (void) fflush (stderr);
+- }
+-}
+-#endif
+-
+-
+-/*
+- * FUNCTION
+- *
+- * _db_setjmp_ save debugger environment
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_setjmp_ ()
+- *
+- * DESCRIPTION
+- *
+- * Invoked as part of the user's DBUG_SETJMP macro to save
+- * the debugger environment in parallel with saving the user's
+- * environment.
+- *
+- */
+-
+-#ifdef HAVE_LONGJMP
+-
+-EXPORT void _db_setjmp_ ()
+-{
+- CODE_STATE *state;
+- state=code_state();
+-
+- state->jmplevel = state->level;
+- state->jmpfunc = state->func;
+- state->jmpfile = state->file;
+-}
+-
+-/*
+- * FUNCTION
+- *
+- * _db_longjmp_ restore previously saved debugger environment
+- *
+- * SYNOPSIS
+- *
+- * VOID _db_longjmp_ ()
+- *
+- * DESCRIPTION
+- *
+- * Invoked as part of the user's DBUG_LONGJMP macro to restore
+- * the debugger environment in parallel with restoring the user's
+- * previously saved environment.
+- *
+- */
+-
+-EXPORT void _db_longjmp_ ()
+-{
+- CODE_STATE *state;
+- state=code_state();
+-
+- state->level = state->jmplevel;
+- if (state->jmpfunc) {
+- state->func = state->jmpfunc;
+- }
+- if (state->jmpfile) {
+- state->file = state->jmpfile;
+- }
+-}
+-#endif
+-
+-/*
+- * FUNCTION
+- *
+- * DelayArg convert D flag argument to appropriate value
+- *
+- * SYNOPSIS
+- *
+- * static int DelayArg (value)
+- * int value;
+- *
+- * DESCRIPTION
+- *
+- * Converts delay argument, given in tenths of a second, to the
+- * appropriate numerical argument used by the system to delay
+- * that that many tenths of a second. For example, on the
+- * amiga, there is a system call "Delay()" which takes an
+- * argument in ticks (50 per second). On unix, the sleep
+- * command takes seconds. Thus a value of "10", for one
+- * second of delay, gets converted to 50 on the amiga, and 1
+- * on unix. Other systems will need to use a timing loop.
+- *
+- */
+-
+-#ifdef AMIGA
+-#define HZ (50) /* Probably in some header somewhere */
+-#endif
+-
+-static int DelayArg (
+-int value)
+-{
+- uint delayarg = 0;
+-
+-#if (unix || xenix)
+- delayarg = value / 10; /* Delay is in seconds for sleep () */
+-#endif
+-#ifdef AMIGA
+- delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */
+-#endif
+- return (delayarg);
+-}
+-
+-
+-/*
+- * A dummy delay stub for systems that do not support delays.
+- * With a little work, this can be turned into a timing loop.
+- */
+-
+-#if ! defined(Delay) && ! defined(AMIGA)
+-static int Delay (
+-int ticks)
+-{
+- return ticks;
+-}
+-#endif
+-
+-
+-/*
+- * FUNCTION
+- *
+- * perror perror simulation for systems that don't have it
+- *
+- * SYNOPSIS
+- *
+- * static VOID perror (s)
+- * char *s;
+- *
+- * DESCRIPTION
+- *
+- * Perror produces a message on the standard error stream which
+- * provides more information about the library or system error
+- * just encountered. The argument string s is printed, followed
+- * by a ':', a blank, and then a message and a newline.
+- *
+- * An undocumented feature of the unix perror is that if the string
+- * 's' is a null string (NOT a NULL pointer!), then the ':' and
+- * blank are not printed.
+- *
+- * This version just complains about an "unknown system error".
+- *
+- */
+-
+-#ifndef HAVE_PERROR
+-static void perror (s)
+-char *s;
+-{
+- if (s && *s != EOS) {
+- (void) fprintf (stderr, "%s: ", s);
+- }
+- (void) fprintf (stderr, "<unknown system error>\n");
+-}
+-#endif /* HAVE_PERROR */
+-
+-
+- /* flush dbug-stream, free mutex lock & wait delay */
+- /* This is because some systems (MSDOS!!) dosn't flush fileheader */
+- /* and dbug-file isn't readable after a system crash !! */
+-
+-static void dbug_flush(CODE_STATE *state)
+-{
+-#ifndef THREAD
+- if (stack->flags & FLUSH_ON_WRITE)
+-#endif
+- {
+-#if defined(MSDOS) || defined(_WIN32)
+- if (_db_fp_ != stdout && _db_fp_ != stderr)
+- {
+- if (!(freopen(stack->name,"a",_db_fp_)))
+- {
+- (void) fprintf(stderr, ERR_OPEN, _db_process_);
+- fflush(stderr);
+- _db_fp_ = stdout;
+- stack -> out_file = _db_fp_;
+- stack -> flags|=FLUSH_ON_WRITE;
+- }
+- }
+- else
+-#endif
+- {
+- (void) fflush (_db_fp_);
+- if (stack->delay)
+- (void) Delay (stack->delay);
+- }
+- }
+- if (!state || !state->locked)
+- pthread_mutex_unlock(&THR_LOCK_dbug);
+-} /* dbug_flush */
+-
+-
+-void _db_lock_file()
+-{
+- CODE_STATE *state;
+- state=code_state();
+- pthread_mutex_lock(&THR_LOCK_dbug);
+- state->locked=1;
+-}
+-
+-void _db_unlock_file()
+-{
+- CODE_STATE *state;
+- state=code_state();
+- state->locked=0;
+- pthread_mutex_unlock(&THR_LOCK_dbug);
+-}
+-
+-/*
+- * Here we need the definitions of the clock routine. Add your
+- * own for whatever system that you have.
+- */
+-
+-#ifndef THREAD
+-#if defined(HAVE_GETRUSAGE)
+-
+-#include <sys/param.h>
+-#include <sys/resource.h>
+-
+-/* extern int getrusage(int, struct rusage *); */
+-
+-/*
+- * Returns the user time in milliseconds used by this process so
+- * far.
+- */
+-
+-static unsigned long Clock ()
+-{
+- struct rusage ru;
+-
+- (void) getrusage (RUSAGE_SELF, &ru);
+- return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
+-}
+-
+-#elif defined(MSDOS) || defined(_WIN32) || defined(OS2)
+-
+-static ulong Clock()
+-{
+- return clock()*(1000/CLOCKS_PER_SEC);
+-}
+-#elif defined (amiga)
+-
+-struct DateStamp { /* Yes, this is a hack, but doing it right */
+- long ds_Days; /* is incredibly ugly without splitting this */
+- long ds_Minute; /* off into a separate file */
+- long ds_Tick;
+-};
+-
+-static int first_clock = TRUE;
+-static struct DateStamp begin;
+-static struct DateStamp elapsed;
+-
+-static unsigned long Clock ()
+-{
+- register struct DateStamp *now;
+- register unsigned long millisec = 0;
+- extern VOID *AllocMem ();
+-
+- now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
+- if (now != NULL) {
+- if (first_clock == TRUE) {
+- first_clock = FALSE;
+- (void) DateStamp (now);
+- begin = *now;
+- }
+- (void) DateStamp (now);
+- millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
+- millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
+- millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
+- (void) FreeMem (now, (long) sizeof (struct DateStamp));
+- }
+- return (millisec);
+-}
+-#else
+-static unsigned long Clock ()
+-{
+- return (0);
+-}
+-#endif /* RUSAGE */
+-#endif /* THREADS */
+-
+-#ifdef NO_VARARGS
+-
+-/*
+- * Fake vfprintf for systems that don't support it. If this
+- * doesn't work, you are probably SOL...
+- */
+-
+-static int vfprintf (stream, format, ap)
+-FILE *stream;
+-char *format;
+-va_list ap;
+-{
+- int rtnval;
+- ARGS_DCL;
+-
+- ARG0 = va_arg (ap, ARGS_TYPE);
+- ARG1 = va_arg (ap, ARGS_TYPE);
+- ARG2 = va_arg (ap, ARGS_TYPE);
+- ARG3 = va_arg (ap, ARGS_TYPE);
+- ARG4 = va_arg (ap, ARGS_TYPE);
+- ARG5 = va_arg (ap, ARGS_TYPE);
+- ARG6 = va_arg (ap, ARGS_TYPE);
+- ARG7 = va_arg (ap, ARGS_TYPE);
+- ARG8 = va_arg (ap, ARGS_TYPE);
+- ARG9 = va_arg (ap, ARGS_TYPE);
+- rtnval = fprintf (stream, format, ARGS_LIST);
+- return (rtnval);
+-}
+-
+-#endif /* NO_VARARGS */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/default.c mariadb-native-client.trunk/libmysql/default.c
+--- mariadb/libmysql/default.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/default.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,414 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/****************************************************************************
+-** Add all options from files named "group".cnf from the default_directories
+-** before the command line arguments.
+-** On Windows defaults will also search in the Windows directory for a file
+-** called 'group'.ini
+-** As long as the program uses the last argument for conflicting
+-** options one only have to add a call to "load_defaults" to enable
+-** use of default values.
+-** pre- and end 'blank space' are removed from options and values. The
+-** following escape sequences are recognized in values: \b \t \n \r \\
+-**
+-** The following arguments are handled automaticly; If used, they must be
+-** first argument on the command line!
+-** --no-defaults ; no options are read.
+-** --defaults-file=full-path-to-default-file ; Only this file will be read.
+-** --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
+-** --print-defaults ; Print the modified command line and exit
+-****************************************************************************/
+-
+-#undef SAFEMALLOC /* safe_malloc is not yet initailized */
+-
+-#include "mysys_priv.h"
+-#include "m_string.h"
+-#include <ctype.h>
+-#include "m_ctype.h"
+-#include <my_dir.h>
+-
+-char *defaults_extra_file=0;
+-
+-/* Which directories are searched for options (and in which order) */
+-
+-const char *default_directories[]= {
+-#ifdef _WIN32
+-"C:/",
+-#else
+-"/etc/",
+-#endif
+-#ifdef DATADIR
+-DATADIR,
+-#endif
+-"", /* Place for defaults_extra_dir */
+-#ifndef _WIN32
+-"~/",
+-#endif
+-NullS,
+-};
+-
+-#define default_ext ".cnf" /* extension for config file */
+-#ifdef _WIN32
+-#include <winbase.h>
+-#define windows_ext ".ini"
+-#endif
+-
+-static my_bool search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc,
+- const char *dir, const char *config_file,
+- const char *ext, TYPELIB *group);
+-
+-
+-void load_defaults(const char *conf_file, const char **groups,
+- int *argc, char ***argv)
+-{
+- DYNAMIC_ARRAY args;
+- const char **dirs, *forced_default_file;
+- TYPELIB group;
+- my_bool found_print_defaults=0;
+- uint args_used=0;
+- MEM_ROOT alloc;
+- char *ptr,**res;
+- DBUG_ENTER("load_defaults");
+-
+- init_alloc_root(&alloc,128,0);
+- if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
+- {
+- /* remove the --no-defaults argument and return only the other arguments */
+- uint i;
+- if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+- (*argc + 1)*sizeof(char*))))
+- goto err;
+- res= (char**) (ptr+sizeof(alloc));
+- res[0]= **argv; /* Copy program name */
+- for (i=2 ; i < (uint) *argc ; i++)
+- res[i-1]=argv[0][i];
+- (*argc)--;
+- *argv=res;
+- *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+- DBUG_VOID_RETURN;
+- }
+-
+- /* Check if we want to force the use a specific default file */
+- forced_default_file=0;
+- if (*argc >= 2)
+- {
+- if (is_prefix(argv[0][1],"--defaults-file="))
+- {
+- forced_default_file=strchr(argv[0][1],'=')+1;
+- args_used++;
+- }
+- else if (is_prefix(argv[0][1],"--defaults-extra-file="))
+- {
+- defaults_extra_file=strchr(argv[0][1],'=')+1;
+- args_used++;
+- }
+- }
+-
+- group.count=0;
+- group.name= "defaults";
+- group.type_names= groups;
+- for (; *groups ; groups++)
+- group.count++;
+-
+- if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
+- goto err;
+- if (forced_default_file)
+- {
+- if (search_default_file(&args, &alloc, "", forced_default_file, "",
+- &group))
+- goto err;
+- }
+- else if (dirname_length(conf_file))
+- {
+- if (search_default_file(&args, &alloc, NullS, conf_file, default_ext,
+- &group))
+- goto err;
+- }
+- else
+- {
+-#ifdef _WIN32
+- char system_dir[FN_REFLEN];
+- GetWindowsDirectory(system_dir,sizeof(system_dir));
+- if (search_default_file(&args, &alloc, system_dir, conf_file, windows_ext,
+- &group))
+- goto err;
+-#endif
+-#if defined(__EMX__) || defined(OS2)
+- if (getenv("ETC") &&
+- search_default_file(&args, &alloc, getenv("ETC"), conf_file,
+- default_ext, &group))
+- goto err;
+-#endif
+- for (dirs=default_directories ; *dirs; dirs++)
+- {
+- int error=0;
+- if (**dirs)
+- error=search_default_file(&args, &alloc, *dirs, conf_file,
+- default_ext, &group);
+- else if (defaults_extra_file)
+- error=search_default_file(&args, &alloc, NullS, defaults_extra_file,
+- default_ext, &group);
+- if (error)
+- goto err;
+- }
+- }
+- if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+- (args.elements + *argc +1) *sizeof(char*))))
+- goto err;
+- res= (char**) (ptr+sizeof(alloc));
+-
+- /* copy name + found arguments + command line arguments to new array */
+- res[0]=argv[0][0];
+- memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
+- /* Skipp --defaults-file and --defaults-extra-file */
+- (*argc)-= args_used;
+- (*argv)+= args_used;
+-
+- /* Check if we wan't to see the new argument list */
+- if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
+- {
+- found_print_defaults=1;
+- --*argc; ++*argv; /* skipp argument */
+- }
+-
+- memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
+- (*argc-1)*sizeof(char*));
+- res[args.elements+ *argc]=0; /* last null */
+-
+- (*argc)+=args.elements;
+- *argv= (char**) res;
+- *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+- delete_dynamic(&args);
+- if (found_print_defaults)
+- {
+- int i;
+- printf("%s would have been started with the following arguments:\n",
+- **argv);
+- for (i=1 ; i < *argc ; i++)
+- printf("%s ", (*argv)[i]);
+- puts("");
+- exit(1);
+- }
+- DBUG_VOID_RETURN;
+-
+- err:
+- fprintf(stderr,"Program aborted\n");
+- exit(1);
+-}
+-
+-
+-void free_defaults(char **argv)
+-{
+- MEM_ROOT ptr;
+- memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
+- free_root(&ptr,MYF(0));
+-}
+-
+-
+-static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+- const char *dir, const char *config_file,
+- const char *ext, TYPELIB *group)
+-{
+- char name[FN_REFLEN+10],buff[4096],*ptr,*end,*value,*tmp;
+- FILE *fp;
+- uint line=0;
+- my_bool read_values=0,found_group=0;
+-
+- if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
+- return 0; /* Ignore wrong paths */
+- if (dir)
+- {
+- strmov(name,dir);
+- convert_dirname(name);
+- if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
+- strcat(name,".");
+- strxmov(strend(name),config_file,ext,NullS);
+- }
+- else
+- {
+- strmov(name,config_file);
+- }
+- fn_format(name,name,"","",4);
+-#if !defined(_WIN32) && !defined(OS2)
+- {
+- MY_STAT stat_info;
+- if (!my_stat(name,&stat_info,MYF(0)))
+- return 0;
+- if (stat_info.st_mode & S_IWOTH) /* ignore world-writeable files */
+- {
+- fprintf(stderr, "warning: World-writeable config file %s is ignored\n",
+- name);
+- return 0;
+- }
+- }
+-#endif
+- if (!(fp = my_fopen(fn_format(name,name,"","",4),O_RDONLY,MYF(0))))
+- return 0; /* Ignore wrong files */
+-
+- while (fgets(buff,sizeof(buff)-1,fp))
+- {
+- line++;
+- /* Ignore comment and empty lines */
+- for (ptr=buff ; isspace(*ptr) ; ptr++ ) ;
+- if (*ptr == '#' || *ptr == ';' || !*ptr)
+- continue;
+- if (*ptr == '[') /* Group name */
+- {
+- found_group=1;
+- if (!(end=(char *) strchr(++ptr,']')))
+- {
+- fprintf(stderr,
+- "error: Wrong group definition in config file: %s at line %d\n",
+- name,line);
+- goto err;
+- }
+- for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
+- end[0]=0;
+- read_values=find_type(ptr,group,3) > 0;
+- continue;
+- }
+- if (!found_group)
+- {
+- fprintf(stderr,
+- "error: Found option without preceding group in config file: %s at line: %d\n",
+- name,line);
+- goto err;
+- }
+- if (!read_values)
+- continue;
+- if (!(end=value=strchr(ptr,'=')))
+- end=strend(ptr); /* Option without argument */
+- for ( ; isspace(end[-1]) ; end--) ;
+- if (!value)
+- {
+- if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
+- goto err;
+- strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+- if (insert_dynamic(args,(gptr) &tmp))
+- goto err;
+- }
+- else
+- {
+- /* Remove pre- and end space */
+- char *value_end;
+- for (value++ ; isspace(*value); value++) ;
+- value_end=strend(value);
+- for ( ; isspace(value_end[-1]) ; value_end--) ;
+- if (value_end < value) /* Empty string */
+- value_end=value;
+- if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
+- (uint) (value_end-value)+1)))
+- goto err;
+- if (insert_dynamic(args,(gptr) &tmp))
+- goto err;
+- ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+- *ptr++= '=';
+- for ( ; value != value_end; value++)
+- {
+- if (*value == '\\' && value != value_end-1)
+- {
+- switch(*++value) {
+- case 'n':
+- *ptr++='\n';
+- break;
+- case 't':
+- *ptr++= '\t';
+- break;
+- case 'r':
+- *ptr++ = '\r';
+- break;
+- case 'b':
+- *ptr++ = '\b';
+- break;
+- case 's':
+- *ptr++= ' '; /* space */
+- break;
+- case '\\':
+- *ptr++= '\\';
+- break;
+- default: /* Unknown; Keep '\' */
+- *ptr++= '\\';
+- *ptr++= *value;
+- break;
+- }
+- }
+- else
+- *ptr++= *value;
+- }
+- *ptr=0;
+- }
+- }
+- my_fclose(fp,MYF(0));
+- return(0);
+-
+- err:
+- my_fclose(fp,MYF(0));
+- return 1;
+-}
+-
+-
+-void print_defaults(const char *conf_file, const char **groups)
+-{
+-#ifdef _WIN32
+- bool have_ext=fn_ext(conf_file)[0] != 0;
+-#endif
+- char name[FN_REFLEN];
+- const char **dirs;
+- puts("\nDefault options are read from the following files in the given order:");
+-
+- if (dirname_length(conf_file))
+- fputs(conf_file,stdout);
+- else
+- {
+-#ifdef _WIN32
+- GetWindowsDirectory(name,sizeof(name));
+- printf("%s\\%s%s ",name,conf_file,have_ext ? "" : windows_ext);
+-#endif
+-#if defined(__EMX__) || defined(OS2)
+- if (getenv("ETC"))
+- printf("%s\\%s%s ", getenv("ETC"), conf_file, default_ext);
+-#endif
+- for (dirs=default_directories ; *dirs; dirs++)
+- {
+- if (**dirs)
+- strmov(name,*dirs);
+- else if (defaults_extra_file)
+- strmov(name,defaults_extra_file);
+- else
+- continue;
+- convert_dirname(name);
+- if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
+- strcat(name,".");
+- strxmov(strend(name),conf_file,default_ext," ",NullS);
+- fputs(name,stdout);
+- }
+- puts("");
+- }
+- fputs("The following groups are read:",stdout);
+- for ( ; *groups ; groups++)
+- {
+- fputc(' ',stdout);
+- fputs(*groups,stdout);
+- }
+- puts("\nThe following options may be given as the first argument:\n\
+---print-defaults Print the program argument list and exit\n\
+---no-defaults Don't read default options from any options file\n\
+---defaults-file=# Only read default options from the given file #\n\
+---defaults-extra-file=# Read this file after the global files are read");
+-}
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/errmsg.c mariadb-native-client.trunk/libmysql/errmsg.c
+--- mariadb/libmysql/errmsg.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/errmsg.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,151 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Error messages for MySQL clients */
+-/* error messages for the demon is in share/language/errmsg.sys */
+-
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include "errmsg.h"
+-#include <stdarg.h>
+-
+-#ifdef GERMAN
+-const char *client_errors[]=
+-{
+- "Unbekannter MySQL Fehler",
+- "Kann UNIX-Socket nicht anlegen (%d)",
+- "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
+- "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
+- "Kann TCP/IP-Socket nicht anlegen (%d)",
+- "Unbekannter MySQL Server Host (%-.64s) (%d)",
+- "MySQL Server nicht vorhanden",
+- "Protokolle ungleich. Server Version = % d Client Version = %d",
+- "MySQL client got out of memory",
+- "Wrong host info",
+- "Localhost via UNIX socket",
+- "%-.64s via TCP/IP",
+- "Error in server handshake",
+- "Lost connection to MySQL server during query",
+- "Commands out of sync; you can't run this command now",
+- "Verbindung ueber Named Pipe; Host: %-.64s",
+- "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)",
+- "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
+- "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)",
+- "Can't initialize character set %-.64s (path: %-.64s)",
+- "Got packet bigger than 'max_allowed_packet'"
+-};
+-
+-/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
+-
+-#elif defined PORTUGUESE
+-const char *client_errors[]=
+-{
+- "Erro desconhecido do MySQL",
+- "No pode criar 'UNIX socket' (%d)",
+- "No pode se conectar ao servidor MySQL local atravs do 'socket' '%-.64s' (%d)",
+- "No pode se conectar ao servidor MySQL em '%-.64s' (%d)",
+- "No pode criar 'socket TCP/IP' (%d)",
+- "'Host' servidor MySQL '%-.64s' (%d) desconhecido",
+- "Servidor MySQL desapareceu",
+- "Incompatibilidade de protocolos. Verso do Servidor: %d - Verso do Cliente: %d",
+- "Cliente do MySQL com falta de memria",
+- "Informao invlida de 'host'",
+- "Localhost via 'UNIX socket'",
+- "%-.64s via 'TCP/IP'",
+- "Erro na negociao de acesso ao servidor",
+- "Conexo perdida com servidor MySQL durante 'query'",
+- "Comandos fora de sincronismo. Voc no pode executar este comando agora",
+- "%-.64s via 'named pipe'",
+- "No pode esperar pelo 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
+- "No pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
+- "No pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
+- "No pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)",
+- "Obteve pacote maior do que 'max_allowed_packet'"
+-};
+-
+-#else /* ENGLISH */
+-const char *client_errors[]=
+-{
+-/* 2000 */ "Unknown MySQL error",
+-/* 2001 */ "Can't create UNIX socket (%d)",
+-/* 2002 */ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+-/* 2003 */ "Can't connect to MySQL server on '%-.64s' (%d)",
+-/* 2004 */ "Can't create TCP/IP socket (%d)",
+-/* 2005 */ "Unknown MySQL Server Host '%-.64s' (%d)",
+-/* 2006 */ "MySQL server has gone away",
+-/* 2007 */ "Protocol mismatch. Server Version = %d Client Version = %d",
+-/* 2008 */ "MySQL client run out of memory",
+-/* 2009 */ "Wrong host info",
+-/* 2010 */ "Localhost via UNIX socket",
+-/* 2011 */ "%-.64s via TCP/IP",
+-/* 2012 */ "Error in server handshake",
+-/* 2013 */ "Lost connection to MySQL server during query",
+-/* 2014 */ "Commands out of sync; you can't run this command now",
+-/* 2015 */ "%-.64s via named pipe",
+-/* 2016 */ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
+-/* 2017 */ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
+-/* 2018 */ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
+-/* 2019 */ "Can't initialize character set %-.64s (path: %-.64s)",
+-/* 2020 */ "Got packet bigger than 'max_allowed_packet'",
+-/* 2021 */ "",
+-/* 2022 */ "",
+-/* 2023 */ "",
+-/* 2024 */ "",
+-/* 2025 */ "",
+-/* 2026 */ "SSL connection error",
+-/* 2027 */ "received malformed packet",
+-/* 2028 */ "",
+-/* 2029 */ "",
+-/* 2030 */ "",
+-/* 2031 */ "",
+-/* 2032 */ "",
+-/* 2033 */ "",
+-/* 2034 */ "",
+-/* 2035 */ "",
+-/* 2036 */ "",
+-/* 2037 */ "",
+-/* 2038 */ "",
+-/* 2039 */ "",
+-/* 2040 */ "",
+-/* 2041 */ "",
+-/* 2042 */ "",
+-/* 2043 */ "",
+-/* 2044 */ "",
+-/* 2045 */ "",
+-/* 2046 */ "",
+-/* 2047 */ "",
+-/* 2048 */ "",
+-/* 2049 */ "",
+-/* 2050 */ "",
+-/* 2051 */ "",
+-/* 2052 */ "",
+-/* 2053 */ "",
+-/* 2054 */ "",
+-/* 2055 */ "",
+-/* 2056 */ "",
+-/* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
+-/* 2058 */ "Can't connect twice. Already connected",
+-/* 2059 */ "Plugin %s could not be loaded: %s",
+- ""
+-};
+-#endif
+-
+-
+-void init_client_errs(void)
+-{
+- my_errmsg[CLIENT_ERRMAP] = &client_errors[0];
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/errors.c mariadb-native-client.trunk/libmysql/errors.c
+--- mariadb/libmysql/errors.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/errors.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,92 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-
+-#ifndef SHARED_LIBRARY
+-
+-const char * NEAR globerrs[GLOBERRS]=
+-{
+- "File '%s' not found (Errcode: %d)",
+- "Can't create/write to file '%s' (Errcode: %d)",
+- "Error reading file '%s' (Errcode: %d)",
+- "Error writing file '%s' (Errcode: %d)",
+- "Error on close of '%s' (Errcode: %d)",
+- "Out of memory (Needed %u bytes)",
+- "Error on delete of '%s' (Errcode: %d)",
+- "Error on rename of '%s' to '%s' (Errcode: %d)",
+- "",
+- "Unexpected eof found when reading file '%s' (Errcode: %d)",
+- "Can't lock file (Errcode: %d)",
+- "Can't unlock file (Errcode: %d)",
+- "Can't read dir of '%s' (Errcode: %d)",
+- "Can't get stat of '%s' (Errcode: %d)",
+- "Can't change size of file (Errcode: %d)",
+- "Can't open stream from handle (Errcode: %d)",
+- "Can't get working dirctory (Errcode: %d)",
+- "Can't change dir to '%s' (Errcode: %d)",
+- "Warning: '%s' had %d links",
+- "%d files and %d streams is left open\n",
+- "Disk is full writing '%s'. Waiting for someone to free space...",
+- "Can't create directory '%s' (Errcode: %d)",
+- "Character set '%s' is not a compiled character set and is not specified in the '%s' file",
+- "Out of resources when opening file '%s' (Errcode: %d)",
+- "Can't read value for symlink '%s' (Error %d)",
+- "Can't create symlink '%s' pointing at '%s' (Error %d)",
+- "Error on realpath() on '%s' (Error %d)",
+-};
+-
+-void init_glob_errs(void)
+-{
+- my_errmsg[GLOB] = & globerrs[0];
+-} /* init_glob_errs */
+-
+-#else
+-
+-void init_glob_errs()
+-{
+- my_errmsg[GLOB] = & globerrs[0];
+-
+- EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
+- EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
+- EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
+- EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
+- EE(EE_BADCLOSE) = "Error on close of '%'s (Errcode: %d)";
+- EE(EE_OUTOFMEMORY) = "Out of memory (Needed %u bytes)";
+- EE(EE_DELETE) = "Error on delete of '%s' (Errcode: %d)";
+- EE(EE_LINK) = "Error on rename of '%s' to '%s' (Errcode: %d)";
+- EE(EE_EOFERR) = "Unexpected eof found when reading file '%s' (Errcode: %d)";
+- EE(EE_CANTLOCK) = "Can't lock file (Errcode: %d)";
+- EE(EE_CANTUNLOCK) = "Can't unlock file (Errcode: %d)";
+- EE(EE_DIR) = "Can't read dir of '%s' (Errcode: %d)";
+- EE(EE_STAT) = "Can't get stat of '%s' (Errcode: %d)";
+- EE(EE_CANT_CHSIZE) = "Can't change size of file (Errcode: %d)";
+- EE(EE_CANT_OPEN_STREAM)= "Can't open stream from handle (Errcode: %d)";
+- EE(EE_GETWD) = "Can't get working dirctory (Errcode: %d)";
+- EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
+- EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
+- EE(EE_OPEN_WARNING) = "%d files and %d streams is left open\n";
+- EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
+- EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
+- EE(EE_UNKNOWN_CHARSET)= "Character set is not a compiled character set and is not specified in the %s file";
+- EE(EE_OUT_OF_FILERESOURCES)="Out of resources when opening file '%s' (Errcode: %d)";
+- EE(EE_CANT_READLINK)="Can't read value for symlink '%s' (Error %d)";
+- EE(EE_CANT_SYMLINK)="Can't create symlink '%s' pointing at '%s' (Error %d)";
+- EE(EE_REALPATH)="Error on realpath() on '%s' (Error %d)";
+-}
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/getopt1.c mariadb-native-client.trunk/libmysql/getopt1.c
+--- mariadb/libmysql/getopt1.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/getopt1.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,170 +0,0 @@
+-/* getopt_long and getopt_long_only entry points for GNU getopt.
+- Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+- Free Software Foundation, Inc.
+-
+-This file is part of the GNU C Library. Its master source is NOT part of
+-the C library, however. The master source lives in /gd/gnu/lib.
+-
+-The GNU C Library is free software; you can redistribute it and/or
+-modify it under the terms of the GNU Library General Public License as
+-published by the Free Software Foundation; either version 2 of the
+-License, or (at your option) any later version.
+-
+-The GNU C Library is distributed in the hope that it will be useful,
+-but WITHOUT ANY WARRANTY; without even the implied warranty of
+-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-Library General Public License for more details.
+-
+-You should have received a copy of the GNU Library General Public
+-License along with the GNU C Library; see the file COPYING.LIB. If
+-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+-Cambridge, MA 02139, USA. */
+-
+-#ifdef HAVE_CONFIG_H
+-#include <config.h>
+-#endif
+-
+-#include <my_global.h>
+-#include "getopt.h"
+-
+-#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
+-/* This is a separate conditional since some stdc systems
+- reject `defined (const)'. */
+-#ifndef const
+-#define const
+-#endif
+-#endif
+-
+-#include <stdio.h>
+-
+-/* Comment out all this code if we are using the GNU C Library, and are not
+- actually compiling the library itself. This code is part of the GNU C
+- Library, but also included in many other GNU distributions. Compiling
+- and linking in this code is a waste when using the GNU C library
+- (especially if it is a shared library). Rather than having every GNU
+- program understand `configure --with-gnu-libc' and omit the object files,
+- it is simpler to just do this in the source for each such file. */
+-
+-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+-
+-#ifndef _WIN32
+-#include <stdlib.h>
+-#endif /* _WIN32 */
+-
+-#ifndef NULL
+-#define NULL 0
+-#endif
+-
+-int
+-getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+-{
+- return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+-}
+-
+-/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+- If an option that starts with '-' (not '--') doesn't match a long option,
+- but does match a short option, it is parsed as a short option
+- instead. */
+-
+-int
+-getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+-{
+- return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+-}
+-
+-
+-#endif /* _LIBC or not __GNU_LIBRARY__. */
+-
+-#ifdef TEST
+-
+-#include <stdio.h>
+-
+-int
+-main (argc, argv)
+- int argc;
+- char **argv;
+-{
+- int c;
+- int digit_optind = 0;
+-
+- while (1)
+- {
+- int this_option_optind = optind ? optind : 1;
+- int option_index = 0;
+- static struct option long_options[] =
+- {
+- {"add", 1, 0, 0},
+- {"append", 0, 0, 0},
+- {"delete", 1, 0, 0},
+- {"verbose", 0, 0, 0},
+- {"create", 0, 0, 0},
+- {"file", 1, 0, 0},
+- {0, 0, 0, 0}
+- };
+-
+- c = getopt_long (argc, argv, "abc:d:0123456789",
+- long_options, &option_index);
+- if (c == EOF)
+- break;
+-
+- switch (c)
+- {
+- case 0:
+- printf ("option %s", long_options[option_index].name);
+- if (optarg)
+- printf (" with arg %s", optarg);
+- printf ("\n");
+- break;
+-
+- case '0':
+- case '1':
+- case '2':
+- case '3':
+- case '4':
+- case '5':
+- case '6':
+- case '7':
+- case '8':
+- case '9':
+- if (digit_optind != 0 && digit_optind != this_option_optind)
+- printf ("digits occur in two different argv-elements.\n");
+- digit_optind = this_option_optind;
+- printf ("option %c\n", c);
+- break;
+-
+- case 'a':
+- printf ("option a\n");
+- break;
+-
+- case 'b':
+- printf ("option b\n");
+- break;
+-
+- case 'c':
+- printf ("option c with value `%s'\n", optarg);
+- break;
+-
+- case 'd':
+- printf ("option d with value `%s'\n", optarg);
+- break;
+-
+- case '?':
+- break;
+-
+- default:
+- printf ("?? getopt returned character code 0%o ??\n", c);
+- }
+- }
+-
+- if (optind < argc)
+- {
+- printf ("non-option ARGV-elements: ");
+- while (optind < argc)
+- printf ("%s ", argv[optind++]);
+- printf ("\n");
+- }
+-
+- exit (0);
+-}
+-
+-#endif /* TEST */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/getopt.c mariadb-native-client.trunk/libmysql/getopt.c
+--- mariadb/libmysql/getopt.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/getopt.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,746 +0,0 @@
+-/* Getopt for GNU.
+- NOTE: getopt is now part of the C library, so if you don't know what
+- "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+- before changing it!
+-
+- Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+- Free Software Foundation, Inc.
+-
+-Changes by monty:
+-- Added include of string.h when nessessary.
+-- Removed two warnings from gcc.
+-
+-This file is part of the GNU C Library. Its master source is NOT part of
+-the C library, however. The master source lives in /gd/gnu/lib.
+-
+-The GNU C Library is free software; you can redistribute it and/or
+-modify it under the terms of the GNU Library General Public License as
+-published by the Free Software Foundation; either version 2 of the
+-License, or (at your option) any later version.
+-
+-The GNU C Library is distributed in the hope that it will be useful,
+-but WITHOUT ANY WARRANTY; without even the implied warranty of
+-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-Library General Public License for more details.
+-
+-You should have received a copy of the GNU Library General Public
+-License along with the GNU C Library; see the file COPYING.LIB. If
+-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+-Cambridge, MA 02139, USA. */
+-
+-/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+- Ditto for AIX 3.2 and <stdlib.h>. */
+-#ifndef _NO_PROTO
+-#define _NO_PROTO
+-#endif
+-
+-#ifdef HAVE_CONFIG_H
+-#include <config.h>
+-#endif
+-
+-#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
+-/* This is a separate conditional since some stdc systems
+- reject `defined (const)'. */
+-#ifndef const
+-#define const
+-#endif
+-#endif
+-
+-#include <my_global.h> /* Changes for mysys */
+-#include <m_string.h>
+-
+-/* Comment out all this code if we are using the GNU C Library, and are not
+- actually compiling the library itself. This code is part of the GNU C
+- Library, but also included in many other GNU distributions. Compiling
+- and linking in this code is a waste when using the GNU C library
+- (especially if it is a shared library). Rather than having every GNU
+- program understand `configure --with-gnu-libc' and omit the object files,
+- it is simpler to just do this in the source for each such file. */
+-
+-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+-
+-
+-/* This needs to come after some library #include
+- to get __GNU_LIBRARY__ defined. */
+-#ifdef __GNU_LIBRARY__
+-/* Don't include stdlib.h for non-GNU C libraries because some of them
+- contain conflicting prototypes for getopt. */
+-#include <stdlib.h>
+-#endif /* GNU C library. */
+-
+-/* This version of `getopt' appears to the caller like standard Unix `getopt'
+- but it behaves differently for the user, since it allows the user
+- to intersperse the options with the other arguments.
+-
+- As `getopt' works, it permutes the elements of ARGV so that,
+- when it is done, all the options precede everything else. Thus
+- all application programs are extended to handle flexible argument order.
+-
+- Setting the environment variable POSIXLY_CORRECT disables permutation.
+- Then the behavior is completely standard.
+-
+- GNU application programs can use a third alternative mode in which
+- they can distinguish the relative order of options and other arguments. */
+-
+-#include "getopt.h"
+-
+-/* For communication from `getopt' to the caller.
+- When `getopt' finds an option that takes an argument,
+- the argument value is returned here.
+- Also, when `ordering' is RETURN_IN_ORDER,
+- each non-option ARGV-element is returned here. */
+-
+-char *optarg = NULL;
+-
+-/* Index in ARGV of the next element to be scanned.
+- This is used for communication to and from the caller
+- and for communication between successive calls to `getopt'.
+-
+- On entry to `getopt', zero means this is the first call; initialize.
+-
+- When `getopt' returns EOF, this is the index of the first of the
+- non-option elements that the caller should itself scan.
+-
+- Otherwise, `optind' communicates from one call to the next
+- how much of ARGV has been scanned so far. */
+-
+-/* XXX 1003.2 says this must be 1 before any call. */
+-int optind = 1;
+-
+-/* The next char to be scanned in the option-element
+- in which the last option character we returned was found.
+- This allows us to pick up the scan where we left off.
+-
+- If this is zero, or a null string, it means resume the scan
+- by advancing to the next ARGV-element. */
+-
+-static char *nextchar;
+-
+-/* Callers store zero here to inhibit the error message
+- for unrecognized options. */
+-
+-int opterr = 1;
+-
+-/* Set to an option character which was unrecognized.
+- This must be initialized on some systems to avoid linking in the
+- system's own getopt implementation. */
+-
+-int optopt = '?';
+-
+-/* Describe how to deal with options that follow non-option ARGV-elements.
+-
+- If the caller did not specify anything,
+- the default is REQUIRE_ORDER if the environment variable
+- POSIXLY_CORRECT is defined, PERMUTE otherwise.
+-
+- REQUIRE_ORDER means don't recognize them as options;
+- stop option processing when the first non-option is seen.
+- This is what Unix does.
+- This mode of operation is selected by either setting the environment
+- variable POSIXLY_CORRECT, or using `+' as the first character
+- of the list of option characters.
+-
+- PERMUTE is the default. We permute the contents of ARGV as we scan,
+- so that eventually all the non-options are at the end. This allows options
+- to be given in any order, even with programs that were not written to
+- expect this.
+-
+- RETURN_IN_ORDER is an option available to programs that were written
+- to expect options and other ARGV-elements in any order and that care about
+- the ordering of the two. We describe each non-option ARGV-element
+- as if it were the argument of an option with character code 1.
+- Using `-' as the first character of the list of option characters
+- selects this mode of operation.
+-
+- The special argument `--' forces an end of option-scanning regardless
+- of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+- `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+-
+-static enum
+-{
+- REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+-} ordering;
+-
+-/* Value of POSIXLY_CORRECT environment variable. */
+-static char *posixly_correct;
+-
+-#ifdef __GNU_LIBRARY__
+-/* We want to avoid inclusion of string.h with non-GNU libraries
+- because there are many ways it can cause trouble.
+- On some systems, it contains special magic macros that don't work
+- in GCC. */
+-#include <string.h>
+-#define my_index strchr
+-#else
+-
+-/* Avoid depending on library functions or files
+- whose names are inconsistent. */
+-
+-static char *
+-my_index (const char *str, int chr)
+-{
+- while (*str)
+- {
+- if (*str == chr)
+- return (char *) str;
+- str++;
+- }
+- return 0;
+-}
+-
+-/* If using GCC, we can safely declare strlen this way.
+- If not using GCC, it is ok not to declare it. */
+-#ifdef __GNUC__
+-/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+- That was relevant to code that was here before. */
+-#if !defined (__STDC__) || !__STDC__
+-/* gcc with -traditional declares the built-in strlen to return int,
+- and has done so at least since version 2.4.5. -- rms. */
+-extern int strlen (const char *);
+-#endif /* not __STDC__ */
+-#endif /* __GNUC__ */
+-
+-#endif /* not __GNU_LIBRARY__ */
+-
+-/* Handle permutation of arguments. */
+-
+-/* Describe the part of ARGV that contains non-options that have
+- been skipped. `first_nonopt' is the index in ARGV of the first of them;
+- `last_nonopt' is the index after the last of them. */
+-
+-static int first_nonopt;
+-static int last_nonopt;
+-
+-/* Exchange two adjacent subsequences of ARGV.
+- One subsequence is elements [first_nonopt,last_nonopt)
+- which contains all the non-options that have been skipped so far.
+- The other is elements [last_nonopt,optind), which contains all
+- the options processed since those non-options were skipped.
+-
+- `first_nonopt' and `last_nonopt' are relocated so that they describe
+- the new indices of the non-options in ARGV after they are moved. */
+-
+-static void
+-exchange (char **argv)
+-{
+- int bottom = first_nonopt;
+- int middle = last_nonopt;
+- int top = optind;
+- char *tem;
+-
+- /* Exchange the shorter segment with the far end of the longer segment.
+- That puts the shorter segment into the right place.
+- It leaves the longer segment in the right place overall,
+- but it consists of two parts that need to be swapped next. */
+-
+- while (top > middle && middle > bottom)
+- {
+- if (top - middle > middle - bottom)
+- {
+- /* Bottom segment is the short one. */
+- int len = middle - bottom;
+- register int i;
+-
+- /* Swap it with the top part of the top segment. */
+- for (i = 0; i < len; i++)
+- {
+- tem = argv[bottom + i];
+- argv[bottom + i] = argv[top - (middle - bottom) + i];
+- argv[top - (middle - bottom) + i] = tem;
+- }
+- /* Exclude the moved bottom segment from further swapping. */
+- top -= len;
+- }
+- else
+- {
+- /* Top segment is the short one. */
+- int len = top - middle;
+- register int i;
+-
+- /* Swap it with the bottom part of the bottom segment. */
+- for (i = 0; i < len; i++)
+- {
+- tem = argv[bottom + i];
+- argv[bottom + i] = argv[middle + i];
+- argv[middle + i] = tem;
+- }
+- /* Exclude the moved top segment from further swapping. */
+- bottom += len;
+- }
+- }
+-
+- /* Update records for the slots the non-options now occupy. */
+-
+- first_nonopt += (optind - last_nonopt);
+- last_nonopt = optind;
+-}
+-
+-/* Initialize the internal data when the first call is made. */
+-
+-static const char *
+-_getopt_initialize (const char *optstring)
+-{
+- /* Start processing options with ARGV-element 1 (since ARGV-element 0
+- is the program name); the sequence of previously skipped
+- non-option ARGV-elements is empty. */
+-
+- first_nonopt = last_nonopt = optind = 1;
+-
+- nextchar = NULL;
+-
+- posixly_correct = getenv ("POSIXLY_CORRECT");
+-
+- /* Determine how to handle the ordering of options and nonoptions. */
+-
+- if (optstring[0] == '-')
+- {
+- ordering = RETURN_IN_ORDER;
+- ++optstring;
+- }
+- else if (optstring[0] == '+')
+- {
+- ordering = REQUIRE_ORDER;
+- ++optstring;
+- }
+- else if (posixly_correct != NULL)
+- ordering = REQUIRE_ORDER;
+- else
+- ordering = PERMUTE;
+-
+- return optstring;
+-}
+-
+-/* Scan elements of ARGV (whose length is ARGC) for option characters
+- given in OPTSTRING.
+-
+- If an element of ARGV starts with '-', and is not exactly "-" or "--",
+- then it is an option element. The characters of this element
+- (aside from the initial '-') are option characters. If `getopt'
+- is called repeatedly, it returns successively each of the option characters
+- from each of the option elements.
+-
+- If `getopt' finds another option character, it returns that character,
+- updating `optind' and `nextchar' so that the next call to `getopt' can
+- resume the scan with the following option character or ARGV-element.
+-
+- If there are no more option characters, `getopt' returns `EOF'.
+- Then `optind' is the index in ARGV of the first ARGV-element
+- that is not an option. (The ARGV-elements have been permuted
+- so that those that are not options now come last.)
+-
+- OPTSTRING is a string containing the legitimate option characters.
+- If an option character is seen that is not listed in OPTSTRING,
+- return '?' after printing an error message. If you set `opterr' to
+- zero, the error message is suppressed but we still return '?'.
+-
+- If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+- so the following text in the same ARGV-element, or the text of the following
+- ARGV-element, is returned in `optarg'. Two colons mean an option that
+- wants an optional arg; if there is text in the current ARGV-element,
+- it is returned in `optarg', otherwise `optarg' is set to zero.
+-
+- If OPTSTRING starts with `-' or `+', it requests different methods of
+- handling the non-option ARGV-elements.
+- See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+-
+- Long-named options begin with `--' instead of `-'.
+- Their names may be abbreviated as long as the abbreviation is unique
+- or is an exact match for some defined option. If they have an
+- argument, it follows the option name in the same ARGV-element, separated
+- from the option name by a `=', or else the in next ARGV-element.
+- When `getopt' finds a long-named option, it returns 0 if that option's
+- `flag' field is nonzero, the value of the option's `val' field
+- if the `flag' field is zero.
+-
+- The elements of ARGV aren't really const, because we permute them.
+- But we pretend they're const in the prototype to be compatible
+- with other systems.
+-
+- LONGOPTS is a vector of `struct option' terminated by an
+- element containing a name which is zero.
+-
+- LONGIND returns the index in LONGOPT of the long-named option found.
+- It is only valid when a long-named option has been found by the most
+- recent call.
+-
+- If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+- long-named options. */
+-
+-int
+-_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
+-{
+- optarg = NULL;
+-
+- if (optind == 0)
+- optstring = _getopt_initialize (optstring);
+-
+- if (nextchar == NULL || *nextchar == '\0')
+- {
+- /* Advance to the next ARGV-element. */
+-
+- if (ordering == PERMUTE)
+- {
+- /* If we have just processed some options following some non-options,
+- exchange them so that the options come first. */
+-
+- if (first_nonopt != last_nonopt && last_nonopt != optind)
+- exchange ((char **) argv);
+- else if (last_nonopt != optind)
+- first_nonopt = optind;
+-
+- /* Skip any additional non-options
+- and extend the range of non-options previously skipped. */
+-
+- while (optind < argc
+- && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+- optind++;
+- last_nonopt = optind;
+- }
+-
+- /* The special ARGV-element `--' means premature end of options.
+- Skip it like a null option,
+- then exchange with previous non-options as if it were an option,
+- then skip everything else like a non-option. */
+-
+- if (optind != argc && !strcmp (argv[optind], "--"))
+- {
+- optind++;
+-
+- if (first_nonopt != last_nonopt && last_nonopt != optind)
+- exchange ((char **) argv);
+- else if (first_nonopt == last_nonopt)
+- first_nonopt = optind;
+- last_nonopt = argc;
+-
+- optind = argc;
+- }
+-
+- /* If we have done all the ARGV-elements, stop the scan
+- and back over any non-options that we skipped and permuted. */
+-
+- if (optind == argc)
+- {
+- /* Set the next-arg-index to point at the non-options
+- that we previously skipped, so the caller will digest them. */
+- if (first_nonopt != last_nonopt)
+- optind = first_nonopt;
+- return EOF;
+- }
+-
+- /* If we have come to a non-option and did not permute it,
+- either stop the scan or describe it to the caller and pass it by. */
+-
+- if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+- {
+- if (ordering == REQUIRE_ORDER)
+- return EOF;
+- optarg = argv[optind++];
+- return 1;
+- }
+-
+- /* We have found another option-ARGV-element.
+- Skip the initial punctuation. */
+-
+- nextchar = (argv[optind] + 1
+- + (longopts != NULL && argv[optind][1] == '-'));
+- }
+-
+- /* Decode the current option-ARGV-element. */
+-
+- /* Check whether the ARGV-element is a long option.
+-
+- If long_only and the ARGV-element has the form "-f", where f is
+- a valid short option, don't consider it an abbreviated form of
+- a long option that starts with f. Otherwise there would be no
+- way to give the -f short option.
+-
+- On the other hand, if there's a long option "fubar" and
+- the ARGV-element is "-fu", do consider that an abbreviation of
+- the long option, just like "--fu", and not "-f" with arg "u".
+-
+- This distinction seems to be the most useful approach. */
+-
+- if (longopts != NULL
+- && (argv[optind][1] == '-'
+- || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+- {
+- char *nameend;
+- const struct option *p;
+- const struct option *pfound = NULL;
+- int exact = 0;
+- int ambig = 0;
+- int indfound=0; /* Keep gcc happy */
+- int option_index;
+-
+- for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+- /* Do nothing. */ ;
+-
+- /* Test all long options for either exact match
+- or abbreviated matches. */
+- for (p = longopts, option_index = 0; p->name; p++, option_index++)
+- if (!strncmp (p->name, nextchar, nameend - nextchar))
+- {
+- if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
+- {
+- /* Exact match found. */
+- pfound = p;
+- indfound = option_index;
+- exact = 1;
+- break;
+- }
+- else if (pfound == NULL)
+- {
+- /* First nonexact match found. */
+- pfound = p;
+- indfound = option_index;
+- }
+- else
+- /* Second or later nonexact match found. */
+- ambig = 1;
+- }
+-
+- if (ambig && !exact)
+- {
+- if (opterr)
+- fprintf (stderr, "%s: option `%s' is ambiguous\n",
+- argv[0], argv[optind]);
+- nextchar += strlen (nextchar);
+- optind++;
+- return '?';
+- }
+-
+- if (pfound != NULL)
+- {
+- option_index = indfound;
+- optind++;
+- if (*nameend)
+- {
+- /* Don't test has_arg with >, because some C compilers don't
+- allow it to be used on enums. */
+- if (pfound->has_arg)
+- optarg = nameend + 1;
+- else
+- {
+- if (opterr)
+- {
+- if (argv[optind - 1][1] == '-')
+- /* --option */
+- fprintf (stderr,
+- "%s: option `--%s' doesn't allow an argument\n",
+- argv[0], pfound->name);
+- else
+- /* +option or -option */
+- fprintf (stderr,
+- "%s: option `%c%s' doesn't allow an argument\n",
+- argv[0], argv[optind - 1][0], pfound->name);
+- }
+- nextchar += strlen (nextchar);
+- return '?';
+- }
+- }
+- else if (pfound->has_arg == 1)
+- {
+- if (optind < argc)
+- optarg = argv[optind++];
+- else
+- {
+- if (opterr)
+- fprintf (stderr, "%s: option `%s' requires an argument\n",
+- argv[0], argv[optind - 1]);
+- nextchar += strlen (nextchar);
+- return optstring[0] == ':' ? ':' : '?';
+- }
+- }
+- nextchar += strlen (nextchar);
+- if (longind != NULL)
+- *longind = option_index;
+- if (pfound->flag)
+- {
+- *(pfound->flag) = pfound->val;
+- return 0;
+- }
+- return pfound->val;
+- }
+-
+- /* Can't find it as a long option. If this is not getopt_long_only,
+- or the option starts with '--' or is not a valid short
+- option, then it's an error.
+- Otherwise interpret it as a short option. */
+- if (!long_only || argv[optind][1] == '-'
+- || my_index (optstring, *nextchar) == NULL)
+- {
+- if (opterr)
+- {
+- if (argv[optind][1] == '-')
+- /* --option */
+- fprintf (stderr, "%s: unrecognized option `--%s'\n",
+- argv[0], nextchar);
+- else
+- /* +option or -option */
+- fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+- argv[0], argv[optind][0], nextchar);
+- }
+- nextchar = (char *) "";
+- optind++;
+- return '?';
+- }
+- }
+-
+- /* Look at and handle the next short option-character. */
+-
+- {
+- char c = *nextchar++;
+- char *temp = my_index (optstring, c);
+-
+- /* Increment `optind' when we start to process its last character. */
+- if (*nextchar == '\0')
+- ++optind;
+-
+- if (temp == NULL || c == ':')
+- {
+- if (opterr)
+- {
+- if (posixly_correct)
+- /* 1003.2 specifies the format of this message. */
+- fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+- else
+- fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+- }
+- optopt = c;
+- return '?';
+- }
+- if (temp[1] == ':')
+- {
+- if (temp[2] == ':')
+- {
+- /* This is an option that accepts an argument optionally. */
+- if (*nextchar != '\0')
+- {
+- optarg = nextchar;
+- optind++;
+- }
+- else
+- optarg = NULL;
+- nextchar = NULL;
+- }
+- else
+- {
+- /* This is an option that requires an argument. */
+- if (*nextchar != '\0')
+- {
+- optarg = nextchar;
+- /* If we end this ARGV-element by taking the rest as an arg,
+- we must advance to the next element now. */
+- optind++;
+- }
+- else if (optind == argc)
+- {
+- if (opterr)
+- {
+- /* 1003.2 specifies the format of this message. */
+- fprintf (stderr, "%s: option requires an argument -- %c\n",
+- argv[0], c);
+- }
+- optopt = c;
+- if (optstring[0] == ':')
+- c = ':';
+- else
+- c = '?';
+- }
+- else
+- /* We already incremented `optind' once;
+- increment it again when taking next ARGV-elt as argument. */
+- optarg = argv[optind++];
+- nextchar = NULL;
+- }
+- }
+- return c;
+- }
+-}
+-
+-#ifdef __EMX__
+-int getopt (int argc, char **argv, __const__ char *optstring)
+-#else
+-int
+-getopt (int argc, char *const *argv, const char *optstring)
+-#endif
+-{
+- return _getopt_internal (argc, argv, optstring,
+- (const struct option *) 0,
+- (int *) 0,
+- 0);
+-}
+-
+-#endif /* _LIBC or not __GNU_LIBRARY__. */
+-
+-#ifdef TEST
+-
+-/* Compile with -DTEST to make an executable for use in testing
+- the above definition of `getopt'. */
+-
+-int
+-main (argc, argv)
+- int argc;
+- char **argv;
+-{
+- int c;
+- int digit_optind = 0;
+-
+- while (1)
+- {
+- int this_option_optind = optind ? optind : 1;
+-
+- c = getopt (argc, argv, "abc:d:0123456789");
+- if (c == EOF)
+- break;
+-
+- switch (c)
+- {
+- case '0':
+- case '1':
+- case '2':
+- case '3':
+- case '4':
+- case '5':
+- case '6':
+- case '7':
+- case '8':
+- case '9':
+- if (digit_optind != 0 && digit_optind != this_option_optind)
+- printf ("digits occur in two different argv-elements.\n");
+- digit_optind = this_option_optind;
+- printf ("option %c\n", c);
+- break;
+-
+- case 'a':
+- printf ("option a\n");
+- break;
+-
+- case 'b':
+- printf ("option b\n");
+- break;
+-
+- case 'c':
+- printf ("option c with value `%s'\n", optarg);
+- break;
+-
+- case '?':
+- break;
+-
+- default:
+- printf ("?? getopt returned character code 0%o ??\n", c);
+- }
+- }
+-
+- if (optind < argc)
+- {
+- printf ("non-option ARGV-elements: ");
+- while (optind < argc)
+- printf ("%s ", argv[optind++]);
+- printf ("\n");
+- }
+-
+- exit (0);
+-}
+-
+-#endif /* TEST */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/get_password.c mariadb-native-client.trunk/libmysql/get_password.c
+--- mariadb/libmysql/get_password.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/get_password.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,211 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+-** Ask for a password from tty
+-** This is an own file to avoid conflicts with curses
+-*/
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include "mysql.h"
+-#include <m_string.h>
+-#include <m_ctype.h>
+-#include <dbug.h>
+-
+-#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
+-#undef HAVE_GETPASS
+-#endif
+-
+-#ifdef HAVE_GETPASS
+-#ifdef HAVE_PWD_H
+-#include <pwd.h>
+-#endif /* HAVE_PWD_H */
+-#else /* ! HAVE_GETPASS */
+-#if !defined( _WIN32) && !defined(OS2)
+-#include <sys/ioctl.h>
+-#ifdef HAVE_TERMIOS_H /* For tty-password */
+-#include <termios.h>
+-#define TERMIO struct termios
+-#else
+-#ifdef HAVE_TERMIO_H /* For tty-password */
+-#include <termio.h>
+-#define TERMIO struct termio
+-#else
+-#include <sgtty.h>
+-#define TERMIO struct sgttyb
+-#endif
+-#endif
+-#ifdef alpha_linux_port
+-#include <asm/ioctls.h> /* QQ; Fix this in configure */
+-#include <asm/termiobits.h>
+-#endif
+-#else
+-#include <conio.h>
+-#endif /* _WIN32 */
+-#endif /* HAVE_GETPASS */
+-
+-#ifdef HAVE_GETPASSPHRASE /* For Solaris */
+- #define getpass(A) getpassphrase(A)
+-#endif
+-
+-#if defined( _WIN32) || defined(OS2)
+-/* were just going to fake it here and get input from the keyboard */
+-
+-char *get_tty_password(char *opt_message)
+-{
+- char to[80];
+- char *pos=to,*end=to+sizeof(to)-1;
+- int i=0;
+- DBUG_ENTER("get_tty_password");
+- fprintf(stdout,opt_message ? opt_message : "Enter password: ");
+- for (;;)
+- {
+- char tmp;
+- tmp=_getch();
+- if (tmp == '\b' || (int) tmp == 127)
+- {
+- if (pos != to)
+- {
+- _cputs("\b \b");
+- pos--;
+- continue;
+- }
+- }
+- if (tmp == '\n' || tmp == '\r' || tmp == 3)
+- break;
+- if (iscntrl(tmp) || pos == end)
+- continue;
+- _cputs("*");
+- *(pos++) = tmp;
+- }
+- while (pos != to && isspace(pos[-1]) == ' ')
+- pos--; /* Allow dummy space at end */
+- *pos=0;
+- _cputs("\n");
+- DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
+-}
+-
+-#else
+-
+-
+-#ifndef HAVE_GETPASS
+-/*
+-** Can't use fgets, because readline will get confused
+-** length is max number of chars in to, not counting \0
+-* to will not include the eol characters.
+-*/
+-
+-static void get_password(char *to,uint length,int fd,bool echo)
+-{
+- char *pos=to,*end=to+length;
+-
+- for (;;)
+- {
+- char tmp;
+- if (my_read(fd,&tmp,1,MYF(0)) != 1)
+- break;
+- if (tmp == '\b' || (int) tmp == 127)
+- {
+- if (pos != to)
+- {
+- if (echo)
+- {
+- fputs("\b \b",stdout);
+- fflush(stdout);
+- }
+- pos--;
+- continue;
+- }
+- }
+- if (tmp == '\n' || tmp == '\r' || tmp == 3)
+- break;
+- if (iscntrl(tmp) || pos == end)
+- continue;
+- if (echo)
+- {
+- fputc('*',stdout);
+- fflush(stdout);
+- }
+- *(pos++) = tmp;
+- }
+- while (pos != to && isspace(pos[-1]) == ' ')
+- pos--; /* Allow dummy space at end */
+- *pos=0;
+- return;
+-}
+-#endif /* ! HAVE_GETPASS */
+-
+-
+-char *get_tty_password(char *opt_message)
+-{
+-#ifdef HAVE_GETPASS
+- char *passbuff;
+-#else /* ! HAVE_GETPASS */
+- TERMIO org,tmp;
+-#endif /* HAVE_GETPASS */
+- char buff[80];
+-
+- DBUG_ENTER("get_tty_password");
+-
+-#ifdef HAVE_GETPASS
+- passbuff = getpass(opt_message ? opt_message : "Enter password: ");
+-
+- /* copy the password to buff and clear original (static) buffer */
+- strnmov(buff, passbuff, sizeof(buff) - 1);
+-#ifdef _PASSWORD_LEN
+- memset(passbuff, 0, _PASSWORD_LEN);
+-#endif
+-#else
+- if (isatty(fileno(stdout)))
+- {
+- fputs(opt_message ? opt_message : "Enter password: ",stdout);
+- fflush(stdout);
+- }
+-#if defined(HAVE_TERMIOS_H)
+- tcgetattr(fileno(stdin), &org);
+- tmp = org;
+- tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+- tmp.c_cc[VMIN] = 1;
+- tmp.c_cc[VTIME] = 0;
+- tcsetattr(fileno(stdin), TCSADRAIN, &tmp);
+- get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout)));
+- tcsetattr(fileno(stdin), TCSADRAIN, &org);
+-#elif defined(HAVE_TERMIO_H)
+- ioctl(fileno(stdin), (int) TCGETA, &org);
+- tmp=org;
+- tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+- tmp.c_cc[VMIN] = 1;
+- tmp.c_cc[VTIME]= 0;
+- ioctl(fileno(stdin),(int) TCSETA, &tmp);
+- get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+- ioctl(fileno(stdin),(int) TCSETA, &org);
+-#else
+- gtty(fileno(stdin), &org);
+- tmp=org;
+- tmp.sg_flags &= ~ECHO;
+- tmp.sg_flags |= RAW;
+- stty(fileno(stdin), &tmp);
+- get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+- stty(fileno(stdin), &org);
+-#endif
+- if (isatty(fileno(stdout)))
+- fputc('\n',stdout);
+-#endif /* HAVE_GETPASS */
+-
+- DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
+-}
+-#endif /*_WIN32*/
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/int2str.c mariadb-native-client.trunk/libmysql/int2str.c
+--- mariadb/libmysql/int2str.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/int2str.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,153 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Defines: int2str(), itoa(), ltoa()
+-
+- int2str(dst, radix, val)
+- converts the (long) integer "val" to character form and moves it to
+- the destination string "dst" followed by a terminating NUL. The
+- result is normally a pointer to this NUL character, but if the radix
+- is dud the result will be NullS and nothing will be changed.
+-
+- If radix is -2..-36, val is taken to be SIGNED.
+- If radix is 2.. 36, val is taken to be UNSIGNED.
+- That is, val is signed if and only if radix is. You will normally
+- use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
+- unsigned is what you generally want.
+-
+- _dig_vec is public just in case someone has a use for it.
+- The definitions of itoa and ltoa are actually macros in m_string.h,
+- but this is where the code is.
+-
+- Note: The standard itoa() returns a pointer to the argument, when int2str
+- returns the pointer to the end-null.
+- itoa assumes that 10 -base numbers are allways signed and other arn't.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-char NEAR _dig_vec[] =
+- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+-
+-
+-char *int2str(register long int val, register char *dst, register int radix)
+-{
+- char buffer[65];
+- register char *p;
+- long int new_val;
+-
+- if (radix < 0) {
+- if (radix < -36 || radix > -2) return NullS;
+- if (val < 0) {
+- *dst++ = '-';
+- val = -val;
+- }
+- radix = -radix;
+- } else {
+- if (radix > 36 || radix < 2) return NullS;
+- }
+- /* The slightly contorted code which follows is due to the
+- fact that few machines directly support unsigned long / and %.
+- Certainly the VAX C compiler generates a subroutine call. In
+- the interests of efficiency (hollow laugh) I let this happen
+- for the first digit only; after that "val" will be in range so
+- that signed integer division will do. Sorry 'bout that.
+- CHECK THE CODE PRODUCED BY YOUR C COMPILER. The first % and /
+- should be unsigned, the second % and / signed, but C compilers
+- tend to be extraordinarily sensitive to minor details of style.
+- This works on a VAX, that's all I claim for it.
+- */
+- p = &buffer[sizeof(buffer)-1];
+- *p = '\0';
+- new_val=(ulong) val / (ulong) radix;
+- *--p = _dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)];
+- val = new_val;
+-#ifdef HAVE_LDIV
+- while (val != 0)
+- {
+- ldiv_t res;
+- res=ldiv(val,radix);
+- *--p = _dig_vec[res.rem];
+- val= res.quot;
+- }
+-#else
+- while (val != 0)
+- {
+- new_val=val/radix;
+- *--p = _dig_vec[(uchar) (val-new_val*radix)];
+- val= new_val;
+- }
+-#endif
+- while ((*dst++ = *p++) != 0) ;
+- return dst-1;
+-}
+-
+-
+-/*
+- This is a faster version of the above optimized for the normal case of
+- radix 10 / -10
+-*/
+-
+-char *int10_to_str(long int val, char *dst, int radix)
+-{
+- char buffer[65];
+- register char *p;
+- long int new_val;
+- unsigned long int uval= (unsigned long int)val;
+-
+- if (radix < 0 && val < 0) /* -10 */
+- {
+- *dst++ = '-';
+- uval = (unsigned long int)0-uval;
+- }
+-
+- p = &buffer[sizeof(buffer)-1];
+- *p = '\0';
+- new_val= (long)(uval / 10);
+- *--p = '0'+ (char)(uval - (unsigned long)new_val * 10);
+- val = new_val;
+-
+- while (val != 0)
+- {
+- new_val=val/10;
+- *--p = '0' + (char) (val-new_val*10);
+- val= new_val;
+- }
+- while ((*dst++ = *p++) != 0) ;
+- return dst-1;
+-}
+-
+-
+-#ifdef USE_MY_ITOA
+-
+- /* Change to less general itoa interface */
+-
+-char *my_itoa(int val, char *dst, int radix)
+-{
+- VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
+- return dst;
+-}
+-
+-char *my_ltoa(long int val, char *dst, int radix)
+-{
+- VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
+- return dst;
+-}
+-
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/is_prefix.c mariadb-native-client.trunk/libmysql/is_prefix.c
+--- mariadb/libmysql/is_prefix.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/is_prefix.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,34 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : is_prefix.c
+- Author : Michael Widenius
+- Defines: is_prefix()
+-
+- is_prefix(s, t) returns 1 if s starts with t.
+- A empty t is allways a prefix.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-int is_prefix(register const char *s, register const char *t)
+-{
+- while (*t)
+- if (*s++ != *t++) return 0;
+- return 1; /* WRONG */
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/libmysql.c mariadb-native-client.trunk/libmysql/libmysql.c
+--- mariadb/libmysql/libmysql.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/libmysql.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,2988 +0,0 @@
+-/************************************************************************************
+- Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
+- Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-
+- Part of this code includes code from the PHP project which
+- is freely available from http://www.php.net
+-*************************************************************************************/
+-
+-#include <my_global.h>
+-
+-#include <my_sys.h>
+-#include <mysys_err.h>
+-#include <m_string.h>
+-#include <m_ctype.h>
+-#include "mysql.h"
+-#include "mysql_version.h"
+-#include "mysqld_error.h"
+-#include "errmsg.h"
+-#include <sys/stat.h>
+-#include <signal.h>
+-#include <time.h>
+-#ifdef HAVE_PWD_H
+-#include <pwd.h>
+-#endif
+-#if !defined(MSDOS) && !defined(_WIN32)
+-#include <sys/socket.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+-#include <netdb.h>
+-#ifdef HAVE_SELECT_H
+-# include <select.h>
+-#endif
+-#ifdef HAVE_SYS_SELECT_H
+-#include <sys/select.h>
+-#endif
+-#endif
+-#ifdef HAVE_SYS_UN_H
+-# include <sys/un.h>
+-#endif
+-#if defined(THREAD) && !defined(_WIN32)
+-#include <my_pthread.h> /* because of signal() */
+-#endif
+-#ifndef INADDR_NONE
+-#define INADDR_NONE -1
+-#endif
+-#include <sha1.h>
+-#include <violite.h>
+-#ifdef HAVE_OPENSSL
+-#include <my_secure.h>
+-#endif
+-
+-static my_bool mysql_client_init=0;
+-extern my_bool my_init_done;
+-extern my_bool mysql_ps_subsystem_initialized;
+-extern my_bool mysql_handle_local_infile(MYSQL *mysql, const char *filename);
+-extern const CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
+-extern const CHARSET_INFO * mysql_find_charset_name(const char * const name);
+-extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
+- const char *data_plugin, const char *db);
+-uint mysql_port=0;
+-my_string mysql_unix_port=0;
+-
+-#ifdef _WIN32
+-#define CONNECT_TIMEOUT 20
+-#else
+-#define CONNECT_TIMEOUT 0
+-#endif
+-
+-#if defined(MSDOS) || defined(_WIN32)
+-// socket_errno is defined in my_global.h for all platforms
+-#define perror(A)
+-#else
+-#include <errno.h>
+-#define SOCKET_ERROR -1
+-#endif /* _WIN32 */
+-
+-#include <mysql/client_plugin.h>
+-
+-#define native_password_plugin_name "mysql_native_password"
+-const char *unknown_sqlstate= "HY000";
+-
+-MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
+- uint field_count);
+-static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+- ulong *lengths);
+-static void end_server(MYSQL *mysql);
+-static void mysql_close_memory(MYSQL *mysql);
+-void read_user_name(char *name);
+-static void append_wild(char *to,char *end,const char *wild);
+-static my_bool mysql_reconnect(MYSQL *mysql);
+-static sig_handler pipe_sig_handler(int sig);
+-static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
+-
+-extern int mysql_client_plugin_init();
+-extern void mysql_client_plugin_deinit();
+-
+-/*
+- Let the user specify that we don't want SIGPIPE; This doesn't however work
+- with threaded applications as we can have multiple read in progress.
+-*/
+-
+-#if !defined(_WIN32) && defined(SIGPIPE) && !defined(THREAD)
+-#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
+-#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+-#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+-#else
+-#define init_sigpipe_variables
+-#define set_sigpipe(mysql)
+-#define reset_sigpipe(mysql)
+-#endif
+-
+-
+-/****************************************************************************
+-* A modified version of connect(). connect2() allows you to specify
+-* a timeout value, in seconds, that we should wait until we
+-* derermine we can't connect to a particular host. If timeout is 0,
+-* connect2() will behave exactly like connect().
+-*
+-* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+-*****************************************************************************/
+-
+-static int connect2(my_socket s, const struct sockaddr *name, uint namelen,
+- uint timeout)
+-{
+-#if defined(_WIN32) || defined(OS2)
+- return connect(s, (struct sockaddr*) name, namelen);
+-#else
+- int flags, res, s_err;
+- socklen_t s_err_size = sizeof(uint);
+- fd_set sfds;
+- struct timeval tv;
+- time_t start_time, now_time;
+-
+- /*
+- If they passed us a timeout of zero, we should behave
+- exactly like the normal connect() call does.
+- */
+-
+- if (timeout == 0)
+- return connect(s, (struct sockaddr*) name, namelen);
+-
+- flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
+-#ifdef O_NONBLOCK
+- fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
+-#endif
+-
+- res = connect(s, (struct sockaddr*) name, namelen);
+- s_err = errno; /* Save the error... */
+- fcntl(s, F_SETFL, flags);
+- if ((res != 0) && (s_err != EINPROGRESS))
+- {
+- errno = s_err; /* Restore it */
+- return(-1);
+- }
+- if (res == 0) /* Connected quickly! */
+- return(0);
+-
+- /*
+- Otherwise, our connection is "in progress." We can use
+- the select() call to wait up to a specified period of time
+- for the connection to suceed. If select() returns 0
+- (after waiting howevermany seconds), our socket never became
+- writable (host is probably unreachable.) Otherwise, if
+- select() returns 1, then one of two conditions exist:
+-
+- 1. An error occured. We use getsockopt() to check for this.
+- 2. The connection was set up sucessfully: getsockopt() will
+- return 0 as an error.
+-
+- Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
+- who posted this method of timing out a connect() in
+- comp.unix.programmer on August 15th, 1997.
+- */
+-
+- FD_ZERO(&sfds);
+- FD_SET(s, &sfds);
+- /*
+- select could be interrupted by a signal, and if it is,
+- the timeout should be adjusted and the select restarted
+- to work around OSes that don't restart select and
+- implementations of select that don't adjust tv upon
+- failure to reflect the time remaining
+- */
+- start_time = time(NULL);
+- for (;;)
+- {
+- tv.tv_sec = (long) timeout;
+- tv.tv_usec = 0;
+-#if defined(HPUX) && defined(THREAD)
+- if ((res = select(s+1, NULL, (int*) &sfds, NULL, &tv)) > 0)
+- break;
+-#else
+- if ((res = select(s+1, NULL, &sfds, NULL, &tv)) > 0)
+- break;
+-#endif
+- if (res == 0) /* timeout */
+- return -1;
+- now_time=time(NULL);
+- timeout-= (uint) (now_time - start_time);
+- if (errno != EINTR || (int) timeout <= 0)
+- return -1;
+- }
+-
+- /*
+- select() returned something more interesting than zero, let's
+- see if we have any errors. If the next two statements pass,
+- we've got an open socket!
+- */
+-
+- s_err=0;
+- if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+- return(-1);
+-
+- if (s_err)
+- { /* getsockopt could succeed */
+- errno = s_err;
+- return(-1); /* but return an error... */
+- }
+- return (0); /* ok */
+-
+-#endif
+-}
+-
+-/*
+-** Create a named pipe connection
+-*/
+-
+-#ifdef _WIN32
+-
+-HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+- char **arg_unix_socket)
+-{
+- HANDLE hPipe=INVALID_HANDLE_VALUE;
+- char szPipeName [ 257 ];
+- DWORD dwMode;
+- int i;
+- my_bool testing_named_pipes=0;
+- char *host= *arg_host, *unix_socket= *arg_unix_socket;
+-
+- if ( ! unix_socket || (unix_socket)[0] == 0x00)
+- unix_socket = mysql_unix_port;
+- if (!host || !strcmp(host,LOCAL_HOST))
+- host=LOCAL_HOST_NAMEDPIPE;
+-
+- sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+- DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+- host, unix_socket));
+-
+- for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+- {
+- if ((hPipe = CreateFile(szPipeName,
+- GENERIC_READ | GENERIC_WRITE,
+- 0,
+- NULL,
+- OPEN_EXISTING,
+- 0,
+- NULL )) != INVALID_HANDLE_VALUE)
+- break;
+- if (GetLastError() != ERROR_PIPE_BUSY)
+- {
+- net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+- sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+- (ulong) GetLastError());
+- return INVALID_HANDLE_VALUE;
+- }
+- /* wait for for an other instance */
+- if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+- {
+- net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+- sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+- (ulong) GetLastError());
+- return INVALID_HANDLE_VALUE;
+- }
+- }
+- if (hPipe == INVALID_HANDLE_VALUE)
+- {
+- net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+- sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+- (ulong) GetLastError());
+- return INVALID_HANDLE_VALUE;
+- }
+- dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+- if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+- {
+- CloseHandle( hPipe );
+- net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+- sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+- (ulong) GetLastError());
+- return INVALID_HANDLE_VALUE;
+- }
+- *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+- return (hPipe);
+-}
+-#endif
+-
+-/* net_get_error */
+-void net_get_error(char *buf, size_t buf_len,
+- char *error, size_t error_len,
+- unsigned int *error_no,
+- char *sqlstate)
+-{
+- char *p= buf;
+- size_t error_msg_len= 0;
+-
+- if (buf_len > 2)
+- {
+- *error_no= uint2korr(p);
+- p+= 2;
+-
+- /* since 4.1 sqlstate is following */
+- if (*p == '#')
+- {
+- memcpy(sqlstate, ++p, SQLSTATE_LENGTH);
+- p+= SQLSTATE_LENGTH;
+- }
+- error_msg_len= buf_len - (p - buf);
+- error_msg_len= MIN(error_msg_len, error_len - 1);
+- memcpy(error, p, error_msg_len);
+- }
+- else
+- {
+- *error_no= CR_UNKNOWN_ERROR;
+- memcpy(sqlstate, unknown_sqlstate, SQLSTATE_LENGTH);
+- }
+-}
+-
+-
+-/*****************************************************************************
+-** read a packet from server. Give error message if socket was down
+-** or packet is an error message
+-*****************************************************************************/
+-
+-ulong
+-net_safe_read(MYSQL *mysql)
+-{
+- NET *net= &mysql->net;
+- ulong len=0;
+- init_sigpipe_variables
+-
+-restart:
+- /* Don't give sigpipe errors if the client doesn't want them */
+- set_sigpipe(mysql);
+- if (net->vio != 0)
+- len=my_net_read(net);
+- reset_sigpipe(mysql);
+-
+- if (len == packet_error || len == 0)
+- {
+- end_server(mysql);
+- my_set_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
+- CR_NET_PACKET_TOO_LARGE:
+- CR_SERVER_LOST,
+- SQLSTATE_UNKNOWN, 0);
+- return(packet_error);
+- }
+- if (net->read_pos[0] == 255)
+- {
+- if (len > 3)
+- {
+- char *pos=(char*) net->read_pos+1;
+- uint last_errno=uint2korr(pos);
+- pos+=2;
+- len-=2;
+-
+- if (last_errno== 65535 &&
+- (mysql->server_capabilities & CLIENT_PROGRESS))
+- {
+- if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1)))
+- {
+- /* Wrong packet */
+- my_set_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate, 0);
+- return (packet_error);
+- }
+- goto restart;
+- }
+- net->last_errno= last_errno;
+- if (pos[0]== '#')
+- {
+- strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
+- pos+= SQLSTATE_LENGTH + 1;
+- }
+- else
+- {
+- strmov(net->sqlstate, SQLSTATE_UNKNOWN);
+- }
+- (void) strmake(net->last_error,(char*) pos,
+- min(len,sizeof(net->last_error)-1));
+- }
+- else
+- {
+- my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
+- }
+-
+- mysql->server_status= ~SERVER_MORE_RESULTS_EXIST;
+-
+- DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
+- net->last_error));
+- return(packet_error);
+- }
+- return len;
+-}
+-
+-/*
+- Report progress to the client
+-
+- RETURN VALUES
+- 0 ok
+- 1 error
+-*/
+-static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length)
+-{
+- uint stage, max_stage, proc_length;
+- double progress;
+- uchar *start= packet;
+-
+- if (length < 5)
+- return 1; /* Wrong packet */
+-
+- if (!(mysql->options.extension && mysql->options.extension->report_progress))
+- return 0; /* No callback, ignore packet */
+-
+- packet++; /* Ignore number of strings */
+- stage= (uint) *packet++;
+- max_stage= (uint) *packet++;
+- progress= uint3korr(packet)/1000.0;
+- packet+= 3;
+- proc_length= net_field_length(&packet);
+- if (packet + proc_length > start + length)
+- return 1; /* Wrong packet */
+- (*mysql->options.extension->report_progress)(mysql, stage, max_stage,
+- progress, (char*) packet,
+- proc_length);
+- return 0;
+-}
+-
+-/* Get the length of next field. Change parameter to point at fieldstart */
+-ulong
+-net_field_length(uchar **packet)
+-{
+- reg1 uchar *pos= *packet;
+- if (*pos < 251)
+- {
+- (*packet)++;
+- return (ulong) *pos;
+- }
+- if (*pos == 251)
+- {
+- (*packet)++;
+- return NULL_LENGTH;
+- }
+- if (*pos == 252)
+- {
+- (*packet)+=3;
+- return (ulong) uint2korr(pos+1);
+- }
+- if (*pos == 253)
+- {
+- (*packet)+=4;
+- return (ulong) uint3korr(pos+1);
+- }
+- (*packet)+=9; /* Must be 254 when here */
+- return (ulong) uint4korr(pos+1);
+-}
+-
+-/* Same as above, but returns ulonglong values */
+-
+-static my_ulonglong
+-net_field_length_ll(uchar **packet)
+-{
+- reg1 uchar *pos= *packet;
+- if (*pos < 251)
+- {
+- (*packet)++;
+- return (my_ulonglong) *pos;
+- }
+- if (*pos == 251)
+- {
+- (*packet)++;
+- return (my_ulonglong) NULL_LENGTH;
+- }
+- if (*pos == 252)
+- {
+- (*packet)+=3;
+- return (my_ulonglong) uint2korr(pos+1);
+- }
+- if (*pos == 253)
+- {
+- (*packet)+=4;
+- return (my_ulonglong) uint3korr(pos+1);
+- }
+- (*packet)+=9; /* Must be 254 when here */
+-#ifdef NO_CLIENT_LONGLONG
+- return (my_ulonglong) uint4korr(pos+1);
+-#else
+- return (my_ulonglong) uint8korr(pos+1);
+-#endif
+-}
+-
+-
+-void free_rows(MYSQL_DATA *cur)
+-{
+- if (cur)
+- {
+- free_root(&cur->alloc,MYF(0));
+- my_free((gptr) cur,MYF(0));
+- }
+-}
+-
+-
+-int
+-simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+- size_t length, my_bool skipp_check)
+-{
+- NET *net= &mysql->net;
+- int result= -1;
+- init_sigpipe_variables
+-
+- DBUG_ENTER("simple_command");
+-
+- DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
+-
+- /* Don't give sigpipe errors if the client doesn't want them */
+- set_sigpipe(mysql);
+- if (mysql->net.vio == 0)
+- { /* Do reconnect if possible */
+- if (mysql_reconnect(mysql))
+- {
+- DBUG_PRINT("info", ("reconnect failed"));
+- DBUG_RETURN(1);
+- }
+- }
+- if (mysql->status != MYSQL_STATUS_READY ||
+- mysql->server_status & SERVER_MORE_RESULTS_EXIST)
+- {
+- SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
+- goto end;
+- }
+-
+- mysql->net.last_error[0]=0;
+- mysql->net.last_errno=0;
+- strmov(mysql->net.sqlstate, "00000");
+-
+- mysql->info=0;
+- mysql->affected_rows= ~(my_ulonglong) 0;
+- net_clear(net); /* Clear receive buffer */
+- if (!arg)
+- arg="";
+-
+- if (net_write_command(net,(uchar) command,arg,
+- length ? length : (ulong) strlen(arg)))
+- {
+- DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno));
+- if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
+- {
+- my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
+- goto end;
+- }
+- end_server(mysql);
+- if (mysql_reconnect(mysql))
+- goto end;
+- if (net_write_command(net,(uchar) command,arg,
+- length ? length : (ulong) strlen(arg)))
+- {
+- my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
+- goto end;
+- }
+- }
+- result=0;
+- if (!skipp_check) {
+- result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+- -1 : 0);
+- DBUG_PRINT("info", ("packet_length=%llu", mysql->packet_length));
+- }
+- end:
+- reset_sigpipe(mysql);
+- DBUG_RETURN(result);
+-}
+-
+-
+-static void free_old_query(MYSQL *mysql)
+-{
+- DBUG_ENTER("free_old_query");
+- if (mysql->fields)
+- free_root(&mysql->field_alloc,MYF(0));
+- init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
+- mysql->fields=0;
+- mysql->field_count=0; /* For API */
+- DBUG_VOID_RETURN;
+-}
+-
+-#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
+-struct passwd *getpwuid(uid_t);
+-char* getlogin(void);
+-#endif
+-
+-#if !defined(MSDOS) && ! defined(VMS) && !defined(_WIN32) && !defined(OS2)
+-void read_user_name(char *name)
+-{
+- DBUG_ENTER("read_user_name");
+- if (geteuid() == 0)
+- (void) strmov(name,"root"); /* allow use of surun */
+- else
+- {
+-#ifdef HAVE_GETPWUID
+- struct passwd *skr;
+- const char *str;
+- if ((str=getlogin()) == NULL)
+- {
+- if ((skr=getpwuid(geteuid())) != NULL)
+- str=skr->pw_name;
+- else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
+- !(str=getenv("LOGIN")))
+- str="UNKNOWN_USER";
+- }
+- (void) strmake(name,str,USERNAME_LENGTH);
+-#elif HAVE_CUSERID
+- (void) cuserid(name);
+-#else
+- strmov(name,"UNKNOWN_USER");
+-#endif
+- }
+- DBUG_VOID_RETURN;
+-}
+-
+-#else /* If MSDOS || VMS */
+-
+-void read_user_name(char *name)
+-{
+- char *str=getenv("USERNAME"); /* ODBC will send user variable */
+- strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
+-}
+-
+-#endif
+-
+-#ifdef _WIN32
+-static my_bool is_NT(void)
+-{
+- char *os=getenv("OS");
+- return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+-}
+-#endif
+-
+-/*
+-** Expand wildcard to a sql string
+-*/
+-
+-static void
+-append_wild(char *to, char *end, const char *wild)
+-{
+- end-=5; /* Some extra */
+- if (wild && wild[0])
+- {
+- to=strmov(to," like '");
+- while (*wild && to < end)
+- {
+- if (*wild == '\\' || *wild == '\'')
+- *to++='\\';
+- *to++= *wild++;
+- }
+- if (*wild) /* Too small buffer */
+- *to++='%'; /* Nicer this way */
+- to[0]='\'';
+- to[1]=0;
+- }
+-}
+-
+-
+-
+-/**************************************************************************
+-** Init debugging if MYSQL_DEBUG environment variable is found
+-**************************************************************************/
+-void STDCALL mysql_debug_end()
+-{
+- if (_db_on_)
+- {
+- DEBUGGER_OFF;
+- DBUG_POP();
+- }
+-}
+-
+-void STDCALL
+-mysql_debug(const char *debug __attribute__((unused)))
+-{
+-#ifndef DBUG_OFF
+- char *env;
+- if (_db_on_)
+- return; /* Already using debugging */
+- if (debug)
+- {
+- DEBUGGER_ON;
+- DBUG_PUSH(debug);
+- }
+- else if ((env = getenv("MYSQL_DEBUG")))
+- {
+- DEBUGGER_ON;
+- DBUG_PUSH(env);
+-#if !defined(_WINVER) && !defined(WINVER)
+- puts("\n-------------------------------------------------------");
+- puts("MYSQL_DEBUG found. libmysql started with the following:");
+- puts(env);
+- puts("-------------------------------------------------------\n");
+-#else
+- {
+- char buff[80];
+- strmov(strmov(buff,"libmysql: "),env);
+- MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
+- }
+-#endif
+- }
+-#endif
+-}
+-
+-
+-/**************************************************************************
+-** Close the server connection if we get a SIGPIPE
+- ARGSUSED
+-**************************************************************************/
+-
+-static sig_handler
+-pipe_sig_handler(int sig __attribute__((unused)))
+-{
+- DBUG_PRINT("info",("Hit by signal %d",sig));
+-#ifdef DONT_REMEMBER_SIGNAL
+- (void) signal(SIGPIPE,pipe_sig_handler);
+-#endif
+-}
+-
+-
+-/**************************************************************************
+-** Shut down connection
+-**************************************************************************/
+-
+-static void
+-end_server(MYSQL *mysql)
+-{
+- DBUG_ENTER("end_server");
+- if (mysql->net.vio != 0)
+- {
+- init_sigpipe_variables
+- set_sigpipe(mysql);
+- vio_delete(mysql->net.vio);
+- reset_sigpipe(mysql);
+- mysql->net.vio= 0; /* Marker */
+- }
+- net_end(&mysql->net);
+- free_old_query(mysql);
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-void STDCALL
+-mysql_free_result(MYSQL_RES *result)
+-{
+- DBUG_ENTER("mysql_free_result");
+- DBUG_PRINT("enter",("mysql_res: %lx",result));
+- if (result)
+- {
+- if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+- {
+- ulong pkt_len;
+- DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
+-
+- do {
+- pkt_len= net_safe_read(result->handle);
+- if (pkt_len == packet_error)
+- break;
+- } while (pkt_len > 8 || result->handle->net.read_pos[0] != 254);
+- result->handle->status=MYSQL_STATUS_READY;
+- }
+- free_rows(result->data);
+- if (result->fields)
+- free_root(&result->field_alloc,MYF(0));
+- if (result->row)
+- my_free((gptr) result->row,MYF(0));
+- my_free((gptr) result,MYF(0));
+- }
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-/****************************************************************************
+-** Get options from my.cnf
+-****************************************************************************/
+-
+-static const char *default_options[]=
+-{
+- "port","socket","compress","password","pipe", "timeout", "user",
+- "init-command", "host", "database", "debug", "return-found-rows",
+- "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
+- "character-sets-dir", "default-character-set", "interactive-timeout",
+- "connect-timeout", "local-infile", "disable-local-infile",
+- "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
+- "multi-results", "multi-statements", "multi-queries", "secure-auth",
+- "report-data-truncation", "plugin-dir", "default-auth",
+- NULL
+-};
+-
+-enum option_val
+-{
+- OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe,
+- OPT_timeout, OPT_user, OPT_init_command, OPT_host, OPT_database,
+- OPT_debug, OPT_return_found_rows, OPT_ssl_key, OPT_ssl_cert,
+- OPT_ssl_ca, OPT_ssl_capath, OPT_charset_dir,
+- OPT_charset_name, OPT_interactive_timeout,
+- OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
+- OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
+- OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
+- OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth
+-};
+-
+-static TYPELIB option_types={array_elements(default_options)-1,
+- "options",default_options};
+-
+-#define extension_set(OPTS, X, VAL) \
+- if (!(OPTS)->extension) \
+- (OPTS)->extension= (struct st_mysql_options_extention *) \
+- my_malloc(sizeof(struct st_mysql_options_extention), \
+- MYF(MY_WME | MY_ZEROFILL)); \
+- (OPTS)->extension->X= VAL;
+-
+-#define extension_set_string(OPTS, X, STR) \
+- if ((OPTS)->extension) \
+- my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR)); \
+- extension_set(OPTS, X, my_strdup((STR), MYF(MY_WME)));
+-
+-const char *protocol_names[]= {"TCP", "SOCKED", "PIPE", "MEMORY", NULL};
+-static TYPELIB protocol_types= {array_elements(protocol_names)-1,
+- "protocol names",
+- protocol_names};
+-
+-static void mysql_read_default_options(struct st_mysql_options *options,
+- const char *filename,const char *group)
+-{
+- int argc;
+- char *argv_buff[1],**argv;
+- const char *groups[3];
+- DBUG_ENTER("mysql_read_default_options");
+- DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
+-
+- argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
+- groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
+-
+- load_defaults(filename, groups, &argc, &argv);
+- if (argc != 1) /* If some default option */
+- {
+- char **option=argv;
+- while (*++option)
+- {
+- /* DBUG_PRINT("info",("option: %s",option[0])); */
+- if (option[0][0] == '-' && option[0][1] == '-')
+- {
+- char *end=strcend(*option,'=');
+- char *opt_arg=0;
+- if (*end)
+- {
+- opt_arg=end+1;
+- *end=0; /* Remove '=' */
+- }
+- /* Change all '_' in variable name to '-' */
+- for (end= *option ; *(end= strcend(end,'_')) ; )
+- *end= '-';
+- switch (find_type(*option+2,&option_types,2)) {
+- case OPT_port:
+- if (opt_arg)
+- options->port=atoi(opt_arg);
+- break;
+- case OPT_socket:
+- if (opt_arg)
+- {
+- my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+- options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
+- }
+- break;
+- case OPT_compress:
+- options->compress=1;
+- break;
+- case OPT_password:
+- if (opt_arg)
+- {
+- my_free(options->password,MYF(MY_ALLOW_ZERO_PTR));
+- options->password=my_strdup(opt_arg,MYF(MY_WME));
+- }
+- break;
+- case OPT_pipe:
+- options->named_pipe=1; /* Force named pipe */
+- break;
+- case OPT_connect_timeout:
+- case OPT_timeout:
+- if (opt_arg)
+- options->connect_timeout=atoi(opt_arg);
+- break;
+- case OPT_user:
+- if (opt_arg)
+- {
+- my_free(options->user,MYF(MY_ALLOW_ZERO_PTR));
+- options->user=my_strdup(opt_arg,MYF(MY_WME));
+- }
+- break;
+- case OPT_init_command:
+- if (opt_arg)
+- {
+- /* todo
+- my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
+- options->init_command=my_strdup(opt_arg,MYF(MY_WME));
+- */
+- }
+- break;
+- case OPT_host:
+- if (opt_arg)
+- {
+- my_free(options->host,MYF(MY_ALLOW_ZERO_PTR));
+- options->host=my_strdup(opt_arg,MYF(MY_WME));
+- }
+- break;
+- case OPT_database:
+- if (opt_arg)
+- {
+- my_free(options->db,MYF(MY_ALLOW_ZERO_PTR));
+- options->db=my_strdup(opt_arg,MYF(MY_WME));
+- }
+- break;
+- case OPT_debug:
+- mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
+- break;
+- case OPT_return_found_rows:
+- options->client_flag|=CLIENT_FOUND_ROWS;
+- break;
+-#ifdef HAVE_OPENSSL
+- case OPT_ssl_key:
+- my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+- options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_ssl_cert:
+- my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+- options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_ssl_ca:
+- my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+- options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_ssl_capath:
+- my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+- options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_ssl_cipher:
+- break;
+-#else
+- case OPT_ssl_key:
+- case OPT_ssl_cert:
+- case OPT_ssl_ca:
+- case OPT_ssl_capath:
+- case OPT_ssl_cipher:
+- break;
+-#endif /* HAVE_OPENSSL */
+- case OPT_charset_dir:
+- my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+- options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_charset_name:
+- my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
+- options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
+- break;
+- case OPT_interactive_timeout:
+- options->client_flag|= CLIENT_INTERACTIVE;
+- break;
+- case OPT_local_infile:
+- if (!opt_arg || atoi(opt_arg) != 0)
+- options->client_flag|= CLIENT_LOCAL_FILES;
+- else
+- options->client_flag&= ~CLIENT_LOCAL_FILES;
+- break;
+- case OPT_disable_local_infile:
+- options->client_flag&= CLIENT_LOCAL_FILES;
+- break;
+- case OPT_max_allowed_packet:
+- if(opt_arg)
+- options->max_allowed_packet= atoi(opt_arg);
+- case OPT_protocol:
+- options->protocol= find_type(opt_arg, &protocol_types, 0);
+-#ifndef _WIN32
+- if (options->protocol < 0 || options->protocol > 1)
+-#else
+- if (options->protocol < 0)
+-#endif
+- {
+- fprintf(stderr,
+- "Unknown or unsupported protocol %s",
+- opt_arg);
+- }
+- break;
+- case OPT_shared_memory_base_name:
+- /* todo */
+- break;
+- case OPT_multi_results:
+- options->client_flag|= CLIENT_MULTI_RESULTS;
+- break;
+- case OPT_multi_statements:
+- case OPT_multi_queries:
+- options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
+- break;
+- case OPT_report_data_truncation:
+- if (opt_arg)
+- options->report_data_truncation= atoi(opt_arg);
+- else
+- options->report_data_truncation= 1;
+- break;
+- case OPT_secure_auth:
+- case OPT_plugin_dir:
+- case OPT_default_auth:
+- /* todo */
+- break;
+- default:
+- DBUG_PRINT("warning",("unknown option: %s",option[0]));
+- }
+- }
+- }
+- }
+- free_defaults(argv);
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-/***************************************************************************
+-** Change field rows to field structs
+-***************************************************************************/
+-
+-static size_t rset_field_offsets[]= {
+- OFFSET(MYSQL_FIELD, catalog),
+- OFFSET(MYSQL_FIELD, catalog_length),
+- OFFSET(MYSQL_FIELD, db),
+- OFFSET(MYSQL_FIELD, db_length),
+- OFFSET(MYSQL_FIELD, table),
+- OFFSET(MYSQL_FIELD, table_length),
+- OFFSET(MYSQL_FIELD, org_table),
+- OFFSET(MYSQL_FIELD, org_table_length),
+- OFFSET(MYSQL_FIELD, name),
+- OFFSET(MYSQL_FIELD, name_length),
+- OFFSET(MYSQL_FIELD, org_name),
+- OFFSET(MYSQL_FIELD, org_name_length)
+-};
+-
+-MYSQL_FIELD *
+-unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+- my_bool default_value, my_bool long_flag_protocol)
+-{
+- MYSQL_ROWS *row;
+- MYSQL_FIELD *field,*result;
+- char *p;
+- unsigned int i, field_count= sizeof(rset_field_offsets)/sizeof(size_t)/2;
+-
+- DBUG_ENTER("unpack_fields");
+- field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+- if (!result)
+- DBUG_RETURN(0);
+-
+- for (row=data->data; row ; row = row->next,field++)
+- {
+- for (i=0; i < field_count; i++)
+- {
+- switch(row->data[i][0]) {
+- case 0:
+- *(char **)(((char *)field) + rset_field_offsets[i*2])= strdup_root(alloc, "");
+- *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= 0;
+- break;
+- default:
+- *(char **)(((char *)field) + rset_field_offsets[i*2])=
+- strdup_root(alloc, (char *)row->data[i]);
+- *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])=
+- (uint)(row->data[i+1] - row->data[i] - 1);
+- break;
+- }
+- }
+-
+- p= (char *)row->data[6];
+- /* filler */
+- field->charsetnr= uint2korr(p);
+- p+= 2;
+- field->length= (uint) uint4korr(p);
+- p+= 4;
+- field->type= (enum enum_field_types)uint1korr(p);
+- p++;
+- field->flags= uint2korr(p);
+- p+= 2;
+- field->decimals= (uint) p[0];
+- p++;
+-
+- /* filler */
+- p+= 2;
+-
+- if (INTERNAL_NUM_FIELD(field))
+- field->flags|= NUM_FLAG;
+-
+- if (default_value && row->data[7])
+- {
+- field->def=strdup_root(alloc,(char*) row->data[7]);
+- }
+- else
+- field->def=0;
+- field->max_length= 0;
+- }
+- free_rows(data); /* Free old data */
+- DBUG_RETURN(result);
+-}
+-
+-
+-/* Read all rows (fields or data) from server */
+-
+-MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+- uint fields)
+-{
+- uint field;
+- ulong pkt_len;
+- ulong len;
+- uchar *cp;
+- char *to, *end_to;
+- MYSQL_DATA *result;
+- MYSQL_ROWS **prev_ptr,*cur;
+- NET *net = &mysql->net;
+- DBUG_ENTER("read_rows");
+-
+- if ((pkt_len= net_safe_read(mysql)) == packet_error)
+- DBUG_RETURN(0);
+- if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
+- MYF(MY_WME | MY_ZEROFILL))))
+- {
+- SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
+- result->alloc.min_malloc=sizeof(MYSQL_ROWS);
+- prev_ptr= &result->data;
+- result->rows=0;
+- result->fields=fields;
+-
+- while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
+- {
+- result->rows++;
+- if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
+- sizeof(MYSQL_ROWS))) ||
+- !(cur->data= ((MYSQL_ROW)
+- alloc_root(&result->alloc,
+- (fields+1)*sizeof(char *)+pkt_len))))
+- {
+- free_rows(result);
+- SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- *prev_ptr=cur;
+- prev_ptr= &cur->next;
+- to= (char*) (cur->data+fields+1);
+- end_to=to+pkt_len-1;
+- for (field=0 ; field < fields ; field++)
+- {
+- if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
+- { /* null field */
+- cur->data[field] = 0;
+- }
+- else
+- {
+- cur->data[field] = to;
+- if (len > (ulong) (end_to - to))
+- {
+- free_rows(result);
+- SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- memcpy(to,(char*) cp,len); to[len]=0;
+- to+=len+1;
+- cp+=len;
+- if (mysql_fields)
+- {
+- if (mysql_fields[field].max_length < len)
+- mysql_fields[field].max_length=len;
+- }
+- }
+- }
+- cur->data[field]=to; /* End of last field */
+- if ((pkt_len=net_safe_read(mysql)) == packet_error)
+- {
+- free_rows(result);
+- DBUG_RETURN(0);
+- }
+- }
+- *prev_ptr=0; /* last pointer is null */
+- /* save status */
+- if (pkt_len > 1)
+- {
+- cp++;
+- mysql->warning_count= uint2korr(cp);
+- cp+= 2;
+- mysql->server_status= uint2korr(cp);
+- }
+- DBUG_PRINT("exit",("Got %d rows",result->rows));
+- DBUG_RETURN(result);
+-}
+-
+-
+-/*
+-** Read one row. Uses packet buffer as storage for fields.
+-** When next packet is read, the previous field values are destroyed
+-*/
+-
+-
+-static int
+-read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
+-{
+- uint field;
+- ulong pkt_len,len;
+- uchar *pos,*prev_pos, *end_pos;
+-
+- if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+- return -1;
+-
+- if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
+- {
+- mysql->warning_count= uint2korr(mysql->net.read_pos + 1);
+- mysql->server_status= uint2korr(mysql->net.read_pos + 3);
+- return 1; /* End of data */
+- }
+- prev_pos= 0; /* allowed to write at packet[-1] */
+- pos=mysql->net.read_pos;
+- end_pos=pos+pkt_len;
+- for (field=0 ; field < fields ; field++)
+- {
+- if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
+- { /* null field */
+- row[field] = 0;
+- *lengths++=0;
+- }
+- else
+- {
+- if (len > (ulong) (end_pos - pos))
+- {
+- mysql->net.last_errno=CR_UNKNOWN_ERROR;
+- strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+- return -1;
+- }
+- row[field] = (char*) pos;
+- pos+=len;
+- *lengths++=len;
+- }
+- if (prev_pos)
+- *prev_pos=0; /* Terminate prev field */
+- prev_pos=pos;
+- }
+- row[field]=(char*) prev_pos+1; /* End of last field */
+- *prev_pos=0; /* Terminate last field */
+- return 0;
+-}
+-
+-/****************************************************************************
+-** Init MySQL structure or allocate one
+-****************************************************************************/
+-
+-MYSQL * STDCALL
+-mysql_init(MYSQL *mysql)
+-{
+- if (mysql_server_init(0, NULL, NULL))
+- return NULL;
+- if (!mysql)
+- {
+- if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
+- return 0;
+- mysql->free_me=1;
+- mysql->net.vio= 0;
+- }
+- else
+- bzero((char*) (mysql),sizeof(*(mysql)));
+- mysql->options.connect_timeout=CONNECT_TIMEOUT;
+- mysql->charset= default_charset_info;
+- strmov(mysql->net.sqlstate, "00000");
+- mysql->net.last_error[0]= mysql->net.last_errno= 0;
+-#if defined(SIGPIPE) && defined(THREAD) && !defined(_WIN32)
+- if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
+- (void) signal(SIGPIPE,pipe_sig_handler);
+-#endif
+-
+-/*
+- Only enable LOAD DATA INFILE by default if configured with
+- --enable-local-infile
+-*/
+-#ifdef ENABLED_LOCAL_INFILE
+- mysql->options.client_flag|= CLIENT_LOCAL_FILES;
+-#endif
+- return mysql;
+-}
+-
+-
+-
+-//#ifdef HAVE_OPENSSL
+-/**************************************************************************
+-** Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
+-** NB! Errors are not reported until you do mysql_real_connect.
+-**************************************************************************/
+-
+-int STDCALL
+-mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert,
+- const char *ca, const char *capath)
+-{
+- mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0));
+- mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0));
+- mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0));
+- mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0));
+- mysql->options.use_ssl = 1;
+- //mysql->connector_fd = new_VioSSLConnectorFd(key, cert, ca, capath);
+- return 0;
+-}
+-
+-/**************************************************************************
+-**************************************************************************/
+-
+-const char * STDCALL
+-mysql_get_ssl_cipher(MYSQL *mysql)
+-{
+-#ifdef HAVE_OPENSSL
+- if (mysql->net.vio && mysql->net.vio->ssl)
+- {
+- return SSL_get_cipher_name(mysql->net.vio->ssl);
+- }
+-#endif
+- return(NULL);
+-}
+-
+-/**************************************************************************
+-** Free strings in the SSL structure and clear 'use_ssl' flag.
+-** NB! Errors are not reported until you do mysql_real_connect.
+-**************************************************************************/
+-
+-//#endif /* HAVE_OPENSSL */
+-
+-/**************************************************************************
+-** Connect to sql server
+-** If host == 0 then use localhost
+-**************************************************************************/
+-
+-MYSQL * STDCALL
+-mysql_connect(MYSQL *mysql,const char *host,
+- const char *user, const char *passwd)
+-{
+- MYSQL *res;
+- mysql=mysql_init(mysql); /* Make it thread safe */
+- {
+- DBUG_ENTER("mysql_connect");
+- if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
+- {
+- if (mysql->free_me)
+- my_free((gptr) mysql,MYF(0));
+- }
+- DBUG_RETURN(res);
+- }
+-}
+-
+-
+-/*
+-** Note that the mysql argument must be initialized with mysql_init()
+-** before calling mysql_real_connect !
+-*/
+-
+-MYSQL * STDCALL
+-mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+- const char *passwd, const char *db,
+- uint port, const char *unix_socket,unsigned long client_flag)
+-{
+- char buff[NAME_LEN+USERNAME_LENGTH+100];
+- char *end, *end_pkt, *host_info,
+- *charset_name= NULL;
+- my_socket sock;
+- char *scramble_data;
+- const char * scramble_plugin;
+- uint32 ip_addr;
+- struct sockaddr_in sock_addr;
+- uint pkt_length, scramble_len, pkt_scramble_len= 0;
+- NET *net= &mysql->net;
+-#ifdef _WIN32
+- HANDLE hPipe=INVALID_HANDLE_VALUE;
+-#endif
+-#ifdef HAVE_SYS_UN_H
+- struct sockaddr_un UNIXaddr;
+-#endif
+- init_sigpipe_variables
+- DBUG_ENTER("mysql_real_connect");
+-
+- DBUG_PRINT("enter",("host: %s db: %s user: %s",
+- host ? host : "(Null)",
+- db ? db : "(Null)",
+- user ? user : "(Null)"));
+-
+- if (net->vio) /* check if we are already connected */
+- {
+- SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(NULL);
+- }
+-
+- /* Don't give sigpipe errors if the client doesn't want them */
+- set_sigpipe(mysql);
+-
+- /* use default options */
+- if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
+- {
+- mysql_read_default_options(&mysql->options,
+- (mysql->options.my_cnf_file ?
+- mysql->options.my_cnf_file : "my"),
+- mysql->options.my_cnf_group);
+- my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
+- }
+-
+- /* Some empty-string-tests are done because of ODBC */
+- if (!host || !host[0])
+- host=mysql->options.host;
+- if (!user || !user[0])
+- user=mysql->options.user;
+- if (!passwd)
+- {
+- passwd=mysql->options.password;
+-#ifndef DONT_USE_MYSQL_PWD
+- if (!passwd)
+- passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
+-#endif
+- }
+- if (!db || !db[0])
+- db=mysql->options.db;
+- if (!port)
+- port=mysql->options.port;
+- if (!unix_socket)
+- unix_socket=mysql->options.unix_socket;
+-
+-
+- /* Since 5.0.3 reconnect is not enabled by default!!
+- mysql->reconnect=1; */
+- mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
+-
+- /*
+- ** Grab a socket and connect it to the server
+- */
+-
+-#if defined(HAVE_SYS_UN_H)
+- if ((!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
+- {
+- host=LOCAL_HOST;
+- if (!unix_socket)
+- unix_socket=mysql_unix_port;
+- host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+- DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+- if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+- {
+- net->last_errno=CR_SOCKET_CREATE_ERROR;
+- sprintf(net->last_error,ER(net->last_errno),socket_errno);
+- goto error;
+- }
+- net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+- bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+- UNIXaddr.sun_family = AF_UNIX;
+- strmov(UNIXaddr.sun_path, unix_socket);
+- if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+- mysql->options.connect_timeout) <0)
+- {
+- DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno));
+- my_set_error(mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_CONNECTION_ERROR),
+- unix_socket, socket_errno);
+- goto error;
+- }
+- }
+- else
+-#elif defined(_WIN32)
+- {
+- if ((unix_socket ||
+- !host && is_NT() ||
+- host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+- mysql->options.named_pipe || !have_tcpip))
+- {
+- sock=0;
+- if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+- (char**) &host, (char**) &unix_socket)) ==
+- INVALID_HANDLE_VALUE)
+- {
+- DBUG_PRINT("error",
+- ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+- host ? host : "<null>",
+- unix_socket ? unix_socket : "<null>",
+- (int) mysql->options.named_pipe,
+- (int) have_tcpip));
+- if (mysql->options.named_pipe ||
+- (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+- (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+- goto error; /* User only requested named pipes */
+- /* Try also with TCP/IP */
+- }
+- else
+- {
+- net->vio=vio_new_win32pipe(hPipe);
+- sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+- unix_socket);
+- }
+- }
+- }
+- if (hPipe == INVALID_HANDLE_VALUE)
+-#endif
+- {
+- unix_socket=0; /* This is not used */
+- if (!port)
+- port=mysql_port;
+- if (!host)
+- host=LOCAL_HOST;
+- sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+- DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+- /* _WIN64 ; Assume that the (int) range is enough for socket() */
+- if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+- {
+- my_set_error(mysql, CR_IPSOCK_ERROR, SQLSTATE_UNKNOWN, ER(CR_IPSOCK_ERROR),
+- socket_errno);
+- goto error;
+- }
+- net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+- bzero((char*) &sock_addr,sizeof(sock_addr));
+- sock_addr.sin_family = AF_INET;
+-
+- /*
+- ** The server name may be a host name or IP address
+- */
+-
+- if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
+- {
+- memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
+- }
+- else
+- {
+- int tmp_errno;
+- struct hostent tmp_hostent,*hp;
+- char buff2[GETHOSTBYNAME_BUFF_SIZE];
+- hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
+- &tmp_errno);
+- if (!hp)
+- {
+- my_set_error(mysql, CR_UNKNOWN_HOST, SQLSTATE_UNKNOWN, ER(CR_UNKNOWN_HOST),
+- host, tmp_errno);
+- my_gethostbyname_r_free();
+- goto error;
+- }
+- memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+- my_gethostbyname_r_free();
+- }
+- sock_addr.sin_port = (ushort) htons((ushort) port);
+- if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+- mysql->options.connect_timeout) <0)
+- {
+- DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,host));
+- my_set_error(mysql, CR_CONN_HOST_ERROR, SQLSTATE_UNKNOWN,
+- ER(CR_CONN_HOST_ERROR), host, socket_errno);
+- goto error;
+- }
+- }
+-
+- if (!net->vio || my_net_init(net, net->vio))
+- {
+- vio_delete(net->vio);
+- net->vio = 0;
+- SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
+- goto error;
+- }
+- vio_keepalive(net->vio,TRUE);
+- strmov(mysql->net.sqlstate, "00000");
+-
+-
+- /* set read timeout */
+- if (mysql->options.read_timeout)
+- vio_read_timeout(net->vio, mysql->options.read_timeout);
+-
+- /* set write timeout */
+- if (mysql->options.write_timeout)
+- vio_write_timeout(net->vio, mysql->options.read_timeout);
+-
+-
+- /* Get version info */
+- mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+- if (mysql->options.connect_timeout &&
+- vio_poll_read(net->vio, mysql->options.connect_timeout))
+- {
+- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- goto error;
+- }
+- if ((pkt_length=net_safe_read(mysql)) == packet_error)
+- goto error;
+-
+- end= (char *)net->read_pos;
+- end_pkt= (char *)net->read_pos + pkt_length;
+-
+- /* Check if version of protocoll matches current one */
+-
+- mysql->protocol_version= end[0];
+- end++;
+-
+- /* Check if server sends an error */
+- if (mysql->protocol_version == 0XFF)
+- {
+- net_get_error(end, pkt_length - 1, net->last_error, sizeof(net->last_error),
+- &net->last_errno, net->sqlstate);
+- /* fix for bug #26426 */
+- if (net->last_errno == 1040)
+- memcpy(net->sqlstate, "08004", SQLSTATE_LENGTH);
+- goto error;
+- }
+-
+- DBUG_DUMP("packet",(char*) net->read_pos,10);
+- DBUG_PRINT("info",("mysql protocol version %d, server=%d",
+- PROTOCOL_VERSION, mysql->protocol_version));
+- if (mysql->protocol_version < PROTOCOL_VERSION)
+- {
+- net->last_errno= CR_VERSION_ERROR;
+- sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
+- PROTOCOL_VERSION);
+- goto error;
+- }
+- /* Save connection information */
+- if (!user) user="";
+- if (!passwd) passwd="";
+-
+- if (!my_multi_malloc(MYF(0),
+- &mysql->host_info, (uint) strlen(host_info)+1,
+- &mysql->host, (uint) strlen(host)+1,
+- &mysql->unix_socket,unix_socket ?
+- (uint) strlen(unix_socket)+1 : (uint) 1,
+- &mysql->server_version, (uint) (end - (char*) net->read_pos),
+- NullS) ||
+- !(mysql->user=my_strdup(user,MYF(0))) ||
+- !(mysql->passwd=my_strdup(passwd,MYF(0))))
+- {
+- SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
+- goto error;
+- }
+- strmov(mysql->host_info,host_info);
+- strmov(mysql->host,host);
+- if (unix_socket)
+- strmov(mysql->unix_socket,unix_socket);
+- else
+- mysql->unix_socket=0;
+- mysql->port=port;
+- client_flag|=mysql->options.client_flag;
+-
+- mysql->server_version= my_strdup(end, MYF(0));
+- end+= strlen(mysql->server_version) + 1;
+-
+- mysql->thread_id=uint4korr(end);
+- end+=4;
+-
+- /* This is the first part of scramble packet. In 4.1 and later
+- a second package will follow later */
+- scramble_data= end;
+- scramble_len= SCRAMBLE_LENGTH_323 + 1;
+- scramble_plugin= old_password_plugin_name;
+- end+= SCRAMBLE_LENGTH_323;
+-
+- /* 1st pad */
+- end++;
+-
+- if (end + 1<= end_pkt)
+- {
+- mysql->server_capabilities=uint2korr(end);
+- }
+-
+- /* mysql 5.5 protocol */
+- if (end + 18 <= end_pkt)
+- {
+- mysql->server_language= uint1korr(end + 2);
+- mysql->server_status= uint2korr(end + 3);
+- mysql->server_capabilities|= uint2korr(end + 5) << 16;
+- pkt_scramble_len= uint1korr(end + 7);
+- }
+- /* pad 2 */
+- end+= 18;
+-
+- /* second scramble package */
+- if (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 <= end_pkt)
+- {
+- memcpy(end - SCRAMBLE_LENGTH_323, scramble_data, SCRAMBLE_LENGTH_323);
+- scramble_data= end - SCRAMBLE_LENGTH_323;
+- if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
+- {
+- scramble_len= pkt_scramble_len;
+- scramble_plugin= scramble_data + scramble_len;
+- if (scramble_data + scramble_len > end_pkt)
+- scramble_len= end_pkt - scramble_data;
+- } else
+- {
+- scramble_len= end_pkt - scramble_data;
+- scramble_plugin= native_password_plugin_name;
+- }
+- } else
+- mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
+-
+- /* Set character set */
+- if (mysql->options.charset_name)
+- mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
+- else if (mysql->server_language)
+- mysql->charset= mysql_find_charset_nr(mysql->server_language);
+- else
+- mysql->charset=default_charset_info;
+-
+- if (!mysql->charset)
+- {
+- net->last_errno=CR_CANT_READ_CHARSET;
+- sprintf(net->last_error,ER(net->last_errno),
+- charset_name ? charset_name : "unknown",
+- "compiled_in");
+- goto error;
+- }
+-
+- mysql->client_flag= client_flag;
+-
+- if (run_plugin_auth(mysql, scramble_data, scramble_len,
+- scramble_plugin, db))
+- goto error;
+-
+- if (mysql->client_flag & CLIENT_COMPRESS)
+- net->compress= 1;
+-
+- /* last part: select default db */
+- if (db && !mysql->db)
+- {
+- if (mysql_select_db(mysql, db))
+- {
+- my_set_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "Setting intital database",
+- errno);
+- goto error;
+- }
+- }
+-
+- DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d",
+- mysql->server_version,mysql->server_capabilities,
+- mysql->server_status, client_flag));
+-
+- if (mysql->options.init_command)
+- {
+- MYSQL_RES *res;
+- int status;
+- /* Avoid reconnect in mysql_real_connect */
+- my_bool save_reconnect= mysql->reconnect;
+-
+- mysql->reconnect= 0;
+-
+- if (mysql_query(mysql, mysql->options.init_command))
+- goto error;
+-
+- /* handle possible multi results */
+- do {
+- if ((res= mysql_use_result(mysql)))
+- mysql_free_result(res);
+- status= mysql_next_result(mysql);
+- } while (status == 0);
+- mysql->reconnect= save_reconnect;
+- }
+-
+- strmov(mysql->net.sqlstate, "00000");
+-
+- DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
+- reset_sigpipe(mysql);
+- DBUG_RETURN(mysql);
+-
+-error:
+- reset_sigpipe(mysql);
+- DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
+- {
+- /* Free alloced memory */
+- end_server(mysql);
+- /* only free the allocated memory, user needs to call mysql_close */
+- mysql_close_memory(mysql);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-
+-static my_bool mysql_reconnect(MYSQL *mysql)
+-{
+- MYSQL tmp_mysql;
+- LIST *li_stmt= mysql->stmts;
+- DBUG_ENTER("mysql_reconnect");
+-
+- if (!mysql->reconnect ||
+- (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
+- {
+- /* Allov reconnect next time */
+- mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
+- my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+- mysql_init(&tmp_mysql);
+- tmp_mysql.options=mysql->options;
+- bzero((char*) &mysql->options,sizeof(mysql->options));
+- if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+- mysql->db, mysql->port, mysql->unix_socket,
+- mysql->client_flag))
+- {
+- my_set_error(mysql, tmp_mysql.net.last_errno,
+- tmp_mysql.net.sqlstate,
+- tmp_mysql.net.last_error);
+- DBUG_RETURN(1);
+- }
+- tmp_mysql.free_me=mysql->free_me;
+- mysql->free_me=0;
+- mysql_close(mysql);
+- *mysql=tmp_mysql;
+- net_clear(&mysql->net);
+- mysql->affected_rows= ~(my_ulonglong) 0;
+-
+- /* reset the connection in all active statements
+- todo: check stmt->mysql in mysql_stmt* functions ! */
+- for (;li_stmt;li_stmt= li_stmt->next)
+- {
+- MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
+- stmt->mysql= NULL;
+- stmt->state= MYSQL_STMT_INITTED;
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-
+-/**************************************************************************
+-** Change user and database
+-**************************************************************************/
+-
+-my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
+- const char *passwd, const char *db)
+-{
+- const CHARSET_INFO *s_cs= mysql->charset;
+- char *s_user= mysql->user,
+- *s_passwd= mysql->passwd,
+- *s_db= mysql->db;
+- int rc;
+-
+- DBUG_ENTER("mysql_change_user");
+-
+- if (!user)
+- user="";
+- if (!passwd)
+- passwd="";
+- if (!db)
+- db="";
+-
+- if (mysql->options.charset_name)
+- mysql->charset =mysql_find_charset_name(mysql->options.charset_name);
+- else if (mysql->server_language)
+- mysql->charset=mysql_find_charset_nr(mysql->server_language);
+- else
+- mysql->charset=default_charset_info;
+-
+- mysql->user= (char *)user;
+- mysql->passwd= (char *)passwd;
+- mysql->db= (char *)db;
+- rc= run_plugin_auth(mysql, 0, 0, 0, db);
+-
+- if (rc==0)
+- {
+- LIST *li_stmt= mysql->stmts;
+- my_free(s_user,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(s_passwd,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(s_db,MYF(MY_ALLOW_ZERO_PTR));
+-
+- mysql->user= my_strdup(user,MYF(MY_WME));
+- mysql->passwd=my_strdup(passwd,MYF(MY_WME));
+- mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
+-
+- for (;li_stmt;li_stmt= li_stmt->next)
+- {
+- MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
+- stmt->mysql= NULL;
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- }/* detach stmts */
+- mysql->stmts= NULL;
+-
+- } else
+- {
+- mysql->user= s_user;
+- mysql->passwd= s_passwd;
+- mysql->db= s_db;
+- mysql->charset= s_cs;
+- }
+- DBUG_RETURN(rc);
+-}
+-
+-
+-/**************************************************************************
+-** Set current database
+-**************************************************************************/
+-
+-int STDCALL
+-mysql_select_db(MYSQL *mysql, const char *db)
+-{
+- int error;
+- DBUG_ENTER("mysql_select_db");
+- DBUG_PRINT("enter",("db: '%s'",db));
+-
+- if ((error=simple_command(mysql,MYSQL_COM_INIT_DB,db,(uint) strlen(db),0)))
+- DBUG_RETURN(error);
+- my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->db=my_strdup(db,MYF(MY_WME));
+- DBUG_RETURN(0);
+-}
+-
+-
+-/*************************************************************************
+-** Send a QUIT to the server and close the connection
+-** If handle is alloced by mysql connect free it.
+-*************************************************************************/
+-
+-static void mysql_close_options(MYSQL *mysql)
+-{
+-/* todo
+- my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+-*/
+- my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+-#ifdef HAVE_OPENSSL
+- my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+-#endif /* HAVE_OPENSSL */
+-}
+-
+-static void mysql_close_memory(MYSQL *mysql)
+-{
+- my_free(mysql->host_info, MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+- my_free(mysql->server_version,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->host_info= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
+- mysql_close_options(mysql);
+-}
+-
+-
+-
+-void my_set_error(MYSQL *mysql,
+- unsigned int error_nr,
+- const char *sqlstate,
+- const char *format,
+- ...)
+-{
+- va_list ap;
+-
+- DBUG_ENTER("my_set_error");
+-
+- mysql->net.last_errno= error_nr;
+- strncpy(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
+- va_start(ap, format);
+- my_vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE,
+- format ? format : ER(error_nr), ap);
+- DBUG_PRINT("info", ("error(%d) %s", error_nr, mysql->net.last_error));
+- va_end(ap);
+- DBUG_VOID_RETURN;
+-}
+-
+-void STDCALL
+-mysql_close(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_close");
+- if (mysql) /* Some simple safety */
+- {
+- LIST *li_stmt= mysql->stmts;
+- if (mysql->net.vio)
+- {
+- free_old_query(mysql);
+- mysql->status=MYSQL_STATUS_READY; /* Force command */
+- mysql->reconnect=0;
+- simple_command(mysql,MYSQL_COM_QUIT,NullS,0,1);
+- end_server(mysql);
+- }
+-
+- /* reset the connection in all active statements
+- todo: check stmt->mysql in mysql_stmt* functions ! */
+- for (;li_stmt;li_stmt= li_stmt->next)
+- {
+- MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
+- stmt->mysql= NULL;
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- }
+- mysql_close_memory(mysql);
+- mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+-
+- /* Clear pointers for better safety */
+- bzero((char*) &mysql->options,sizeof(mysql->options));
+- mysql->net.vio= 0;
+- if (mysql->free_me)
+- my_free((gptr) mysql,MYF(0));
+- }
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-/**************************************************************************
+-** Do a query. If query returned rows, free old rows.
+-** Read data by mysql_store_result or by repeat call of mysql_fetch_row
+-**************************************************************************/
+-
+-int STDCALL
+-mysql_query(MYSQL *mysql, const char *query)
+-{
+- return mysql_real_query(mysql,query, (uint) strlen(query));
+-}
+-
+-/*
+- Send the query and return so we can do something else.
+- Needs to be followed by mysql_read_query_result() when we want to
+- finish processing it.
+-*/
+-
+-int STDCALL
+-mysql_send_query(MYSQL* mysql, const char* query, uint length)
+-{
+- return simple_command(mysql, MYSQL_COM_QUERY, query, length, 1);
+-}
+-
+-int STDCALL mysql_read_query_result(MYSQL *mysql)
+-{
+- uchar *pos;
+- ulong field_count;
+- MYSQL_DATA *fields;
+- ulong length;
+- DBUG_ENTER("mysql_read_query_result");
+-
+- if (!mysql || (length = net_safe_read(mysql)) == packet_error)
+- DBUG_RETURN(1);
+- free_old_query(mysql); /* Free old result */
+-get_info:
+- pos=(uchar*) mysql->net.read_pos;
+- if ((field_count= net_field_length(&pos)) == 0)
+- {
+- mysql->affected_rows= net_field_length_ll(&pos);
+- mysql->insert_id= net_field_length_ll(&pos);
+- mysql->server_status=uint2korr(pos);
+- pos+=2;
+- mysql->warning_count=uint2korr(pos);
+- pos+=2;
+- if (pos < mysql->net.read_pos+length && net_field_length(&pos))
+- mysql->info=(char*) pos;
+- DBUG_RETURN(0);
+- }
+- if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+- {
+- int error=mysql_handle_local_infile(mysql, (char *)pos);
+-
+- if ((length=net_safe_read(mysql)) == packet_error || error)
+- DBUG_RETURN(-1);
+- goto get_info; /* Get info packet */
+- }
+- if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
+- mysql->server_status|= SERVER_STATUS_IN_TRANS;
+-
+- mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+- if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,8)))
+- DBUG_RETURN(-1);
+- if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
+- (uint) field_count,1,
+- (my_bool) test(mysql->server_capabilities &
+- CLIENT_LONG_FLAG))))
+- DBUG_RETURN(-1);
+- mysql->status=MYSQL_STATUS_GET_RESULT;
+- mysql->field_count=field_count;
+- DBUG_RETURN(0);
+-}
+-
+-int STDCALL
+-mysql_real_query(MYSQL *mysql, const char *query, uint length)
+-{
+- DBUG_ENTER("mysql_real_query");
+- DBUG_PRINT("enter",("handle: %lx",mysql));
+- DBUG_PRINT("query",("Query = \"%.255s\" length=%u",query, length));
+-
+- if (simple_command(mysql,MYSQL_COM_QUERY,query,length,1))
+- DBUG_RETURN(-1);
+- DBUG_RETURN(mysql_read_query_result(mysql));
+-}
+-
+-/**************************************************************************
+-** Alloc result struct for buffered results. All rows are read to buffer.
+-** mysql_data_seek may be used.
+-**************************************************************************/
+-
+-MYSQL_RES * STDCALL
+-mysql_store_result(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- DBUG_ENTER("mysql_store_result");
+-
+- if (!mysql->fields)
+- DBUG_RETURN(0);
+- if (mysql->status != MYSQL_STATUS_GET_RESULT)
+- {
+- SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- mysql->status=MYSQL_STATUS_READY; /* server is ready */
+- if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
+- sizeof(ulong)*mysql->field_count,
+- MYF(MY_WME | MY_ZEROFILL))))
+- {
+- SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- result->eof=1; /* Marker for buffered */
+- result->lengths=(ulong*) (result+1);
+- if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
+- {
+- my_free((gptr) result,MYF(0));
+- DBUG_RETURN(0);
+- }
+- mysql->affected_rows= result->row_count= result->data->rows;
+- result->data_cursor= result->data->data;
+- result->fields= mysql->fields;
+- result->field_alloc= mysql->field_alloc;
+- result->field_count= mysql->field_count;
+- result->current_field=0;
+- result->current_row=0; /* Must do a fetch first */
+- mysql->fields=0; /* fields is now in result */
+- DBUG_RETURN(result); /* Data fetched */
+-}
+-
+-
+-/**************************************************************************
+-** Alloc struct for use with unbuffered reads. Data is fetched by domand
+-** when calling to mysql_fetch_row.
+-** mysql_data_seek is a noop.
+-**
+-** No other queries may be specified with the same MYSQL handle.
+-** There shouldn't be much processing per row because mysql server shouldn't
+-** have to wait for the client (and will not wait more than 30 sec/packet).
+-**************************************************************************/
+-
+-MYSQL_RES * STDCALL
+-mysql_use_result(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- DBUG_ENTER("mysql_use_result");
+-
+- if (!mysql->fields)
+- DBUG_RETURN(0);
+- if (mysql->status != MYSQL_STATUS_GET_RESULT)
+- {
+- SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
+- DBUG_RETURN(0);
+- }
+- if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
+- sizeof(ulong)*mysql->field_count,
+- MYF(MY_WME | MY_ZEROFILL))))
+- DBUG_RETURN(0);
+- result->lengths=(ulong*) (result+1);
+- if (!(result->row=(MYSQL_ROW)
+- my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
+- { /* Ptrs: to one row */
+- my_free((gptr) result,MYF(0));
+- DBUG_RETURN(0);
+- }
+- result->fields= mysql->fields;
+- result->field_alloc= mysql->field_alloc;
+- result->field_count= mysql->field_count;
+- result->current_field=0;
+- result->handle= mysql;
+- result->current_row= 0;
+- mysql->fields=0; /* fields is now in result */
+- mysql->status=MYSQL_STATUS_USE_RESULT;
+- DBUG_RETURN(result); /* Data is read to be fetched */
+-}
+-
+-/**************************************************************************
+-** Return next field of the query results
+-**************************************************************************/
+-MYSQL_FIELD * STDCALL
+-mysql_fetch_field(MYSQL_RES *result)
+-{
+- if (result->current_field >= result->field_count)
+- return(NULL);
+- return &result->fields[result->current_field++];
+-}
+-
+-/**************************************************************************
+-** Return next row of the query results
+-**************************************************************************/
+-MYSQL_ROW STDCALL
+-mysql_fetch_row(MYSQL_RES *res)
+-{
+- DBUG_ENTER("mysql_fetch_row");
+- if (!res->data)
+- { /* Unbufferred fetch */
+- if (!res->eof)
+- {
+- if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+- {
+- res->row_count++;
+- DBUG_RETURN(res->current_row=res->row);
+- }
+- else
+- {
+- DBUG_PRINT("info",("end of data"));
+- res->eof=1;
+- res->handle->status=MYSQL_STATUS_READY;
+- /* Don't clear handle in mysql_free_results */
+- res->handle=0;
+- }
+- }
+- DBUG_RETURN((MYSQL_ROW) NULL);
+- }
+- {
+- MYSQL_ROW tmp;
+- if (!res->data_cursor)
+- {
+- DBUG_PRINT("info",("end of data"));
+- DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+- }
+- tmp = res->data_cursor->data;
+- res->data_cursor = res->data_cursor->next;
+- DBUG_RETURN(res->current_row=tmp);
+- }
+-}
+-
+-/**************************************************************************
+-** 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)
+-{
+- ulong *lengths,*prev_length;
+- char *start;
+- MYSQL_ROW column,end;
+-
+- if (!(column=res->current_row))
+- return 0; /* Something is wrong */
+- if (res->data)
+- {
+- start=0;
+- prev_length=0; /* Keep gcc happy */
+- lengths=res->lengths;
+- for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
+- {
+- if (!*column)
+- {
+- *lengths=0; /* Null */
+- continue;
+- }
+- if (start) /* Found end of prev string */
+- *prev_length= (uint) (*column-start-1);
+- start= *column;
+- prev_length=lengths;
+- }
+- }
+- return res->lengths;
+-}
+-
+-/**************************************************************************
+-** Move to a specific row and column
+-**************************************************************************/
+-
+-void STDCALL
+-mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
+-{
+- MYSQL_ROWS *tmp=0;
+- DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
+- if (result->data)
+- for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+- result->current_row=0;
+- result->data_cursor = tmp;
+-}
+-
+-/*************************************************************************
+-** put the row or field cursor one a position one got from mysql_row_tell()
+-** This doesn't restore any data. The next mysql_fetch_row or
+-** mysql_fetch_field will return the next row or field after the last used
+-*************************************************************************/
+-
+-MYSQL_ROW_OFFSET STDCALL
+-mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
+-{
+- MYSQL_ROW_OFFSET return_value=result->data_cursor;
+- result->current_row= 0;
+- result->data_cursor= row;
+- return return_value;
+-}
+-
+-
+-MYSQL_FIELD_OFFSET STDCALL
+-mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
+-{
+- MYSQL_FIELD_OFFSET return_value=result->current_field;
+- result->current_field=field_offset;
+- return return_value;
+-}
+-
+-/*****************************************************************************
+-** List all databases
+-*****************************************************************************/
+-
+-MYSQL_RES * STDCALL
+-mysql_list_dbs(MYSQL *mysql, const char *wild)
+-{
+- char buff[255];
+- DBUG_ENTER("mysql_list_dbs");
+-
+- append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
+- if (mysql_query(mysql,buff))
+- DBUG_RETURN(0);
+- DBUG_RETURN (mysql_store_result(mysql));
+-}
+-
+-
+-/*****************************************************************************
+-** List all tables in a database
+-** If wild is given then only the tables matching wild is returned
+-*****************************************************************************/
+-
+-MYSQL_RES * STDCALL
+-mysql_list_tables(MYSQL *mysql, const char *wild)
+-{
+- char buff[255];
+- DBUG_ENTER("mysql_list_tables");
+-
+- append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
+- if (mysql_query(mysql,buff))
+- DBUG_RETURN(0);
+- DBUG_RETURN (mysql_store_result(mysql));
+-}
+-
+-
+-/**************************************************************************
+-** List all fields in a table
+-** If wild is given then only the fields matching wild is returned
+-** Instead of this use query:
+-** show fields in 'table' like "wild"
+-**************************************************************************/
+-
+-MYSQL_RES * STDCALL
+-mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
+-{
+- MYSQL_RES *result;
+- MYSQL_DATA *query;
+- char buff[257],*end;
+- DBUG_ENTER("mysql_list_fields");
+- DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : ""));
+-
+- LINT_INIT(query);
+-
+- end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+- if (simple_command(mysql,MYSQL_COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+- !(query = read_rows(mysql,(MYSQL_FIELD*) 0,8)))
+- DBUG_RETURN(NULL);
+-
+- free_old_query(mysql);
+- if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
+- MYF(MY_WME | MY_ZEROFILL))))
+- {
+- free_rows(query);
+- DBUG_RETURN(NULL);
+- }
+- result->field_alloc=mysql->field_alloc;
+- mysql->fields=0;
+- result->field_count = (uint) query->rows;
+- result->fields= unpack_fields(query,&result->field_alloc,
+- result->field_count,1,
+- (my_bool) test(mysql->server_capabilities &
+- CLIENT_LONG_FLAG));
+- result->eof=1;
+- DBUG_RETURN(result);
+-}
+-
+-/* List all running processes (threads) in server */
+-
+-MYSQL_RES * STDCALL
+-mysql_list_processes(MYSQL *mysql)
+-{
+- MYSQL_DATA *fields;
+- uint field_count;
+- uchar *pos;
+- DBUG_ENTER("mysql_list_processes");
+-
+- LINT_INIT(fields);
+- if (simple_command(mysql,MYSQL_COM_PROCESS_INFO,0,0,0))
+- DBUG_RETURN(0);
+- free_old_query(mysql);
+- pos=(uchar*) mysql->net.read_pos;
+- field_count=(uint) net_field_length(&pos);
+- if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+- DBUG_RETURN(NULL);
+- if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
+- (my_bool) test(mysql->server_capabilities &
+- CLIENT_LONG_FLAG))))
+- DBUG_RETURN(0);
+- mysql->status=MYSQL_STATUS_GET_RESULT;
+- mysql->field_count=field_count;
+- DBUG_RETURN(mysql_store_result(mysql));
+-}
+-
+-
+-int STDCALL
+-mysql_create_db(MYSQL *mysql, const char *db)
+-{
+- DBUG_ENTER("mysql_createdb");
+- DBUG_PRINT("enter",("db: %s",db));
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_CREATE_DB,db, (uint) strlen(db),0));
+-}
+-
+-
+-int STDCALL
+-mysql_drop_db(MYSQL *mysql, const char *db)
+-{
+- DBUG_ENTER("mysql_drop_db");
+- DBUG_PRINT("enter",("db: %s",db));
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_DROP_DB,db,(uint) strlen(db),0));
+-}
+-
+-
+-int STDCALL
+-mysql_shutdown(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_shutdown");
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_SHUTDOWN,0,0,0));
+-}
+-
+-
+-int STDCALL
+-mysql_refresh(MYSQL *mysql,uint options)
+-{
+- uchar bits[1];
+- DBUG_ENTER("mysql_refresh");
+- bits[0]= (uchar) options;
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_REFRESH,(char*) bits,1,0));
+-}
+-
+-int STDCALL
+-mysql_kill(MYSQL *mysql,ulong pid)
+-{
+- char buff[12];
+- DBUG_ENTER("mysql_kill");
+- int4store(buff,pid);
+- /* if we kill our own thread, reading the response packet will fail */
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_PROCESS_KILL,buff,4,0));
+-}
+-
+-
+-int STDCALL
+-mysql_dump_debug_info(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_dump_debug_info");
+- DBUG_RETURN(simple_command(mysql,MYSQL_COM_DEBUG,0,0,0));
+-}
+-
+-char * STDCALL
+-mysql_stat(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_stat");
+- if (simple_command(mysql,MYSQL_COM_STATISTICS,0,0,0))
+- return mysql->net.last_error;
+- mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
+- if (!mysql->net.read_pos[0])
+- {
+- SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , unknown_sqlstate, 0);
+- return mysql->net.last_error;
+- }
+- DBUG_RETURN((char*) mysql->net.read_pos);
+-}
+-
+-
+-int STDCALL
+-mysql_ping(MYSQL *mysql)
+-{
+- int rc;
+- DBUG_ENTER("mysql_ping");
+- rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
+-
+- /* if connection was terminated and reconnect is true, try again */
+- if (rc!=0 && mysql->reconnect)
+- rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
+- return rc;
+-}
+-
+-
+-char * STDCALL
+-mysql_get_server_info(MYSQL *mysql)
+-{
+- return((char*) mysql->server_version);
+-}
+-
+-unsigned long STDCALL mysql_get_server_version(MYSQL *mysql)
+-{
+- long major, minor, patch;
+- char *p;
+-
+- if (!(p = mysql->server_version)) {
+- return 0;
+- }
+-
+- major = strtol(p, &p, 10);
+- p += 1; /* consume the dot */
+- minor = strtol(p, &p, 10);
+- p += 1; /* consume the dot */
+- patch = strtol(p, &p, 10);
+-
+- return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch));
+-}
+-
+-
+-
+-char * STDCALL
+-mysql_get_host_info(MYSQL *mysql)
+-{
+- return(mysql->host_info);
+-}
+-
+-
+-uint STDCALL
+-mysql_get_proto_info(MYSQL *mysql)
+-{
+- return (mysql->protocol_version);
+-}
+-
+-const char * STDCALL
+-mysql_get_client_info(void)
+-{
+- return (char*) MYSQL_CLIENT_VERSION;
+-}
+-
+-
+-int STDCALL
+-mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
+-{
+- DBUG_ENTER("mysql_option");
+- DBUG_PRINT("enter",("option: %d",(int) option));
+- switch (option) {
+- case MYSQL_OPT_CONNECT_TIMEOUT:
+- mysql->options.connect_timeout= *(uint*) arg;
+- break;
+- case MYSQL_OPT_COMPRESS:
+- mysql->options.compress= 1; /* Remember for connect */
+- mysql->options.client_flag|= CLIENT_COMPRESS;
+- break;
+- case MYSQL_OPT_NAMED_PIPE:
+- mysql->options.named_pipe=1; /* Force named pipe */
+- break;
+- case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
+- if (!arg || test(*(uint*) arg))
+- mysql->options.client_flag|= CLIENT_LOCAL_FILES;
+- else
+- mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
+- break;
+- case MYSQL_INIT_COMMAND:
+- my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
+- break;
+- case MYSQL_READ_DEFAULT_FILE:
+- my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
+- break;
+- case MYSQL_READ_DEFAULT_GROUP:
+- my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
+- break;
+- case MYSQL_SET_CHARSET_DIR:
+- /* not supported in this version. Since all character sets
+- are internally available, we don't throw an error */
+- break;
+- case MYSQL_SET_CHARSET_NAME:
+- my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+- mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
+- break;
+- case MYSQL_OPT_RECONNECT:
+- mysql->reconnect= *(uint *)arg;
+- break;
+- case MYSQL_OPT_PROTOCOL:
+-#ifdef _WIN32
+- if (*(uint *)arg > MYSQL_PROTOCOL_PIPE)
+-#else
+- if (*(uint *)arg > MYSQL_PROTOCOL_SOCKET)
+-#endif
+- DBUG_RETURN(-1);
+- mysql->options.protocol= *(uint *)arg;
+- break;
+- case MYSQL_OPT_READ_TIMEOUT:
+- mysql->options.read_timeout= *(uint *)arg;
+- break;
+- case MYSQL_OPT_WRITE_TIMEOUT:
+- mysql->options.write_timeout= *(uint *)arg;
+- break;
+- case MYSQL_REPORT_DATA_TRUNCATION:
+- mysql->options.report_data_truncation= *(uint *)arg;
+- break;
+- case MYSQL_OPT_PROGRESS_CALLBACK:
+- if (!mysql->options.extension)
+- mysql->options.extension= (struct st_mysql_options_extention *)
+- my_malloc(sizeof(struct st_mysql_options_extention),
+- MYF(MY_WME | MY_ZEROFILL));
+- if (mysql->options.extension)
+- mysql->options.extension->report_progress=
+- (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
+- break;
+- default:
+- DBUG_RETURN(-1);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-/****************************************************************************
+-** Functions to get information from the MySQL structure
+-** These are functions to make shared libraries more usable.
+-****************************************************************************/
+-
+-/* MYSQL_RES */
+-my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
+-{
+- return res->row_count;
+-}
+-
+-unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
+-{
+- return res->field_count;
+-}
+-
+-/* deprecated */
+-my_bool STDCALL mysql_eof(MYSQL_RES *res)
+-{
+- return res->eof;
+-}
+-
+-MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+-{
+- return &(res)->fields[fieldnr];
+-}
+-
+-MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
+-{
+- return (res)->fields;
+-}
+-
+-MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
+-{
+- return res->data_cursor;
+-}
+-
+-uint STDCALL mysql_field_tell(MYSQL_RES *res)
+-{
+- return (res)->current_field;
+-}
+-
+-/* MYSQL */
+-
+-unsigned int STDCALL mysql_field_count(MYSQL *mysql)
+-{
+- return mysql->field_count;
+-}
+-
+-my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
+-{
+- return (mysql)->affected_rows;
+-}
+-
+-my_bool STDCALL mysql_autocommit(MYSQL *mysql, my_bool mode)
+-{
+- DBUG_ENTER("mysql_autocommit");
+- DBUG_RETURN((my_bool) mysql_real_query(mysql, (mode) ? "SET autocommit=1" :
+- "SET autocommit=0", 16));
+-}
+-
+-my_bool STDCALL mysql_commit(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_commit");
+- DBUG_RETURN((my_bool)mysql_real_query(mysql, "COMMIT", sizeof("COMMIT")));
+-}
+-
+-my_bool STDCALL mysql_rollback(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_rollback");
+- DBUG_RETURN((my_bool)mysql_real_query(mysql, "ROLLBACK", sizeof("ROLLBACK")));
+-}
+-
+-my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
+-{
+- return (mysql)->insert_id;
+-}
+-
+-uint STDCALL mysql_errno(MYSQL *mysql)
+-{
+- return (mysql)->net.last_errno;
+-}
+-
+-char * STDCALL mysql_error(MYSQL *mysql)
+-{
+- return (mysql)->net.last_error;
+-}
+-
+-char *STDCALL mysql_info(MYSQL *mysql)
+-{
+- return (mysql)->info;
+-}
+-
+-my_bool STDCALL mysql_more_results(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_more_results");
+- DBUG_RETURN(test(mysql->server_status & SERVER_MORE_RESULTS_EXIST));
+-}
+-
+-int STDCALL mysql_next_result(MYSQL *mysql)
+-{
+- DBUG_ENTER("mysql_next_result");
+-
+- /* make sure communication is not blocking */
+- if (mysql->status != MYSQL_STATUS_READY)
+- {
+- SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0);
+- DBUG_RETURN(1);
+- }
+-
+- /* clear error, and mysql status variables */
+- CLEAR_CLIENT_ERROR(mysql);
+- mysql->affected_rows = (ulonglong) ~0;
+-
+- if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
+- {
+- DBUG_RETURN(mysql_read_query_result(mysql));
+- }
+-
+- DBUG_RETURN(-1);
+-}
+-
+-ulong STDCALL mysql_thread_id(MYSQL *mysql)
+-{
+- return (mysql)->thread_id;
+-}
+-
+-const char * STDCALL mysql_character_set_name(MYSQL *mysql)
+-{
+- return mysql->charset->csname;
+-}
+-
+-
+-uint STDCALL mysql_thread_safe(void)
+-{
+-#ifdef THREAD
+- return 1;
+-#else
+- return 0;
+-#endif
+-}
+-
+-/****************************************************************************
+-** Some support functions
+-****************************************************************************/
+-
+-/*
+-** Add escape characters to a string (blob?) to make it suitable for a insert
+-** to should at least have place for length*2+1 chars
+-** Returns the length of the to string
+-*/
+-
+-ulong STDCALL
+-mysql_escape_string(char *to,const char *from, ulong length)
+-{
+- return (ulong)mysql_cset_escape_slashes(default_charset_info, to, from, length);
+-}
+-
+-ulong STDCALL
+-mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
+- ulong length)
+-{
+- if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
+- return (ulong)mysql_cset_escape_quotes(mysql->charset, to, from, length);
+- else
+- return (ulong)mysql_cset_escape_slashes(mysql->charset, to, from, length);
+-}
+-
+-void STDCALL
+-myodbc_remove_escape(MYSQL *mysql,char *name)
+-{
+- char *to;
+- my_bool use_mb_flag= (mysql->charset->char_maxlen > 1);
+- char *end= 0;
+- if (use_mb_flag)
+- for (end=name; *end ; end++) ;
+-
+- for (to=name ; *name ; name++)
+- {
+- int l;
+- if (use_mb_flag && (l = mysql->charset->mb_valid(name , end)))
+- {
+- while (l--)
+- *to++ = *name++;
+- name--;
+- continue;
+- }
+- if (*name == '\\' && name[1])
+- name++;
+- *to++= *name;
+- }
+- *to=0;
+-}
+-
+-void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
+-{
+- DBUG_ENTER("mysql_get_character_set_info");
+-
+- if (!cs)
+- DBUG_VOID_RETURN;
+-
+- cs->number= mysql->charset->nr;
+- cs->csname= mysql->charset->csname;
+- cs->name= mysql->charset->name;
+- cs->state= 0;
+- cs->comment= NULL;
+- cs->dir= NULL;
+- cs->mbminlen= mysql->charset->char_minlen;
+- cs->mbmaxlen= mysql->charset->char_maxlen;
+-
+- DBUG_VOID_RETURN;
+-}
+-
+-int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname)
+-{
+- const CHARSET_INFO *cs;
+- DBUG_ENTER("mysql_set_character_set");
+-
+- if (!csname)
+- goto error;
+-
+- if ((cs= mysql_find_charset_name(csname)))
+- {
+- char buff[64];
+-
+- my_snprintf(buff, 63, "SET NAMES %s", cs->csname);
+- if (!mysql_real_query(mysql, buff, (uint)strlen(buff)))
+- {
+- mysql->charset= cs;
+- DBUG_RETURN(0);
+- }
+- }
+-
+-error:
+- my_set_error(mysql, CR_CANT_READ_CHARSET, SQLSTATE_UNKNOWN,
+- 0, csname, "compiled_in");
+- DBUG_RETURN(mysql->net.last_errno);
+-}
+-
+-unsigned int STDCALL mysql_warning_count(MYSQL *mysql)
+-{
+- return mysql->warning_count;
+-}
+-
+-const char * STDCALL mysql_sqlstate(MYSQL *mysql)
+-{
+- return mysql->net.sqlstate;
+-}
+-
+-int STDCALL mysql_server_init(int argc __attribute__((unused)),
+- char **argv __attribute__((unused)),
+- char **groups __attribute__((unused)))
+-{
+- int rc= 0;
+-
+- if (!mysql_client_init)
+- {
+- mysql_client_init=1;
+- my_init(); /* Will init threads */
+- init_client_errs();
+- if (mysql_client_plugin_init())
+- return 1;
+- if (!mysql_port)
+- {
+- struct servent *serv_ptr;
+- char *env;
+-
+- mysql_port = MYSQL_PORT;
+- if ((serv_ptr = getservbyname("mysql", "tcp")))
+- mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
+- if ((env = getenv("MYSQL_TCP_PORT")))
+- mysql_port =(uint) atoi(env);
+- }
+- if (!mysql_unix_port)
+- {
+- char *env;
+-#ifdef _WIN32
+- mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+-#else
+- mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+-#endif
+- if ((env = getenv("MYSQL_UNIX_PORT")))
+- mysql_unix_port = env;
+- }
+- mysql_debug(NullS);
+-#if defined(SIGPIPE) && !defined(THREAD) && !defined(_WIN32)
+- (void) signal(SIGPIPE,SIG_IGN);
+-#endif
+- }
+-#ifdef THREAD
+- else
+- rc= mysql_thread_init();
+-#endif
+- if (!mysql_ps_subsystem_initialized)
+- mysql_init_ps_subsystem();
+- return(rc);
+-}
+-
+-void STDCALL mysql_server_end()
+-{
+- if (!mysql_client_init)
+- return;
+-#ifdef HAVE_OPENSSL
+- my_ssl_end();
+-#endif
+-
+- mysql_client_plugin_deinit();
+-
+- if (my_init_done)
+- my_end(0);
+-#ifdef THREAD
+- else
+- mysql_thread_end();
+-#endif
+- mysql_client_init= 0;
+- my_init_done= 0;
+-}
+-
+-my_bool STDCALL mysql_thread_init()
+-{
+-#ifdef THREAD
+- return my_thread_init();
+-#endif
+- return 0;
+-}
+-
+-void STDCALL mysql_thread_end()
+-{
+- #ifdef THREAD
+- my_thread_end();
+- #endif
+-}
+-
+-int STDCALL mysql_set_server_option(MYSQL *mysql,
+- enum enum_mysql_set_option option)
+-{
+- char buffer[2];
+- DBUG_ENTER("mysql_set_server_option");
+- int2store(buffer, (uint)option);
+- DBUG_RETURN(simple_command(mysql, MYSQL_COM_SET_OPTION, buffer, sizeof(buffer), 0));
+-}
+-
+-ulong STDCALL mysql_get_client_version(void)
+-{
+- return MYSQL_VERSION_ID;
+-}
+-
+-ulong STDCALL mysql_hex_string(char *to, const char *from,
+- unsigned long len)
+-{
+- char *start= to;
+- char hexdigits[]= "012345679ABCDEF";
+-
+- while (len--)
+- {
+- *to++= hexdigits[*from >> 4];
+- *to++= hexdigits[*from & 0x0F];
+- from++;
+- }
+- *to= 0;
+- return (to - start);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/libmysql_exports.def mariadb-native-client.trunk/libmysql/libmysql_exports.def
+--- mariadb/libmysql/libmysql_exports.def 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/libmysql_exports.def 1970-01-01 01:00:00.000000000 +0100
+@@ -1,107 +0,0 @@
+-EXPORTS
+- get_tty_password
+- load_defaults
+- mysql_thread_end
+- mysql_thread_init
+- myodbc_remove_escape
+- mysql_affected_rows
+- mysql_autocommit
+- mysql_stmt_bind_param
+- mysql_stmt_bind_result
+- mysql_change_user
+- mysql_character_set_name
+- mysql_close
+- mysql_commit
+- mysql_data_seek
+- mysql_debug
+- mysql_dump_debug_info
+- mysql_eof
+- mysql_errno
+- mysql_error
+- mysql_escape_string
+- mysql_hex_string
+- mysql_stmt_execute
+- mysql_stmt_fetch
+- mysql_stmt_fetch_column
+- mysql_fetch_field
+- mysql_fetch_field_direct
+- mysql_fetch_fields
+- mysql_fetch_lengths
+- mysql_fetch_row
+- mysql_field_count
+- mysql_field_seek
+- mysql_field_tell
+- mysql_free_result
+- mysql_get_client_info
+- mysql_get_host_info
+- mysql_get_proto_info
+- mysql_get_server_info
+- mysql_get_client_version
+- mysql_get_ssl_cipher
+- mysql_info
+- mysql_init
+- mysql_insert_id
+- mysql_kill
+- mysql_set_server_option
+- mysql_list_dbs
+- mysql_list_fields
+- mysql_list_processes
+- mysql_list_tables
+- mysql_more_results
+- mysql_next_result
+- mysql_num_fields
+- mysql_num_rows
+- mysql_options
+- mysql_stmt_param_count
+- ;mysql_stmt_param_metadata
+- mysql_ping
+- mysql_stmt_result_metadata
+- mysql_query
+- mysql_read_query_result
+- mysql_real_connect
+- mysql_real_escape_string
+- mysql_real_query
+- mysql_refresh
+- mysql_rollback
+- mysql_row_seek
+- mysql_row_tell
+- mysql_select_db
+- mysql_stmt_send_long_data
+- mysql_send_query
+- mysql_shutdown
+- mysql_ssl_set
+- mysql_stat
+- mysql_stmt_affected_rows
+- mysql_stmt_close
+- mysql_stmt_reset
+- mysql_stmt_data_seek
+- mysql_stmt_errno
+- mysql_stmt_error
+- mysql_stmt_free_result
+- mysql_stmt_num_rows
+- mysql_stmt_row_seek
+- mysql_stmt_row_tell
+- mysql_stmt_store_result
+- mysql_store_result
+- mysql_thread_id
+- mysql_thread_safe
+- mysql_use_result
+- mysql_warning_count
+- mysql_stmt_sqlstate
+- mysql_sqlstate
+- mysql_get_server_version
+- mysql_stmt_prepare
+- mysql_stmt_init
+- mysql_stmt_insert_id
+- mysql_stmt_attr_get
+- mysql_stmt_attr_set
+- mysql_stmt_field_count
+- mysql_set_local_infile_default
+- mysql_set_local_infile_handler
+- mysql_server_init
+- mysql_server_end
+- mysql_set_character_set
+- mysql_get_character_set_info
+- ;mysql_stmt_next_result
+-
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/list.c mariadb-native-client.trunk/libmysql/list.c
+--- mariadb/libmysql/list.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/list.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,116 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Code for handling dubble-linked lists in C
+-*/
+-
+-#include "mysys_priv.h"
+-#include <my_list.h>
+-
+-
+-
+- /* Add a element to start of list */
+-
+-LIST *list_add(LIST *root, LIST *element)
+-{
+- DBUG_ENTER("list_add");
+- DBUG_PRINT("enter",("root: %lx element: %lx", root, element));
+- if (root)
+- {
+- if (root->prev) /* If add in mid of list */
+- root->prev->next= element;
+- element->prev=root->prev;
+- root->prev=element;
+- }
+- else
+- element->prev=0;
+- element->next=root;
+- DBUG_RETURN(element); /* New root */
+-}
+-
+-
+-LIST *list_delete(LIST *root, LIST *element)
+-{
+- if (element->prev)
+- element->prev->next=element->next;
+- else
+- root=element->next;
+- if (element->next)
+- element->next->prev=element->prev;
+- return root;
+-}
+-
+-
+-void list_free(LIST *root, unsigned int free_data)
+-{
+- LIST *next;
+- while (root)
+- {
+- next=root->next;
+- if (free_data)
+- my_free((gptr) root->data,MYF(0));
+- my_free((gptr) root,MYF(0));
+- root=next;
+- }
+-}
+-
+-
+-LIST *list_cons(void *data, LIST *list)
+-{
+- LIST *new_charset=(LIST*) my_malloc(sizeof(LIST),MYF(MY_FAE));
+- if (!new_charset)
+- return 0;
+- new_charset->data=data;
+- return list_add(list,new_charset);
+-}
+-
+-
+-LIST *list_reverse(LIST *root)
+-{
+- LIST *last;
+-
+- last=root;
+- while (root)
+- {
+- last=root;
+- root=root->next;
+- last->next=last->prev;
+- last->prev=root;
+- }
+- return last;
+-}
+-
+-uint list_length(LIST *list)
+-{
+- uint count;
+- for (count=0 ; list ; list=list->next, count++) ;
+- return count;
+-}
+-
+-
+-int list_walk(LIST *list, list_walk_action action, gptr argument)
+-{
+- int error=0;
+- while (list)
+- {
+- if ((error = (*action)(list->data,argument)))
+- return error;
+- list=rest(list);
+- }
+- return 0;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/llstr.c mariadb-native-client.trunk/libmysql/llstr.c
+--- mariadb/libmysql/llstr.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/llstr.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Defines: llstr();
+-
+- llstr(value, buff);
+-
+- This function saves a longlong value in a buffer and returns the pointer to
+- the buffer. This is useful when trying to portable print longlong
+- variables with printf() as there is no usable printf() standard one can use.
+-*/
+-
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-char *llstr(longlong value,char *buff)
+-{
+- longlong2str(value,buff,-10);
+- return buff;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/longlong2str.c mariadb-native-client.trunk/libmysql/longlong2str.c
+--- mariadb/libmysql/longlong2str.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/longlong2str.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,143 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Defines: longlong2str();
+-
+- longlong2str(dst, radix, val)
+- converts the (longlong) integer "val" to character form and moves it to
+- the destination string "dst" followed by a terminating NUL. The
+- result is normally a pointer to this NUL character, but if the radix
+- is dud the result will be NullS and nothing will be changed.
+-
+- If radix is -2..-36, val is taken to be SIGNED.
+- If radix is 2.. 36, val is taken to be UNSIGNED.
+- That is, val is signed if and only if radix is. You will normally
+- use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
+- unsigned is what you generally want.
+-
+- _dig_vec is public just in case someone has a use for it.
+- The definitions of itoa and ltoa are actually macros in m_string.h,
+- but this is where the code is.
+-
+- Note: The standard itoa() returns a pointer to the argument, when int2str
+- returns the pointer to the end-null.
+- itoa assumes that 10 -base numbers are allways signed and other arn't.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#if defined(HAVE_LONG_LONG) && !defined(longlong2str) && !defined(HAVE_LONGLONG2STR)
+-
+-extern char NEAR _dig_vec[];
+-
+-/*
+- This assumes that longlong multiplication is faster than longlong division.
+-*/
+-
+-char *longlong2str(longlong val,char *dst,int radix)
+-{
+- char buffer[65];
+- register char *p;
+- long long_val;
+-
+- if (radix < 0)
+- {
+- if (radix < -36 || radix > -2) return (char*) 0;
+- if (val < 0) {
+- *dst++ = '-';
+- val = -val;
+- }
+- radix = -radix;
+- }
+- else
+- {
+- if (radix > 36 || radix < 2) return (char*) 0;
+- }
+- if (val == 0)
+- {
+- *dst++='0';
+- *dst='\0';
+- return dst;
+- }
+- p = &buffer[sizeof(buffer)-1];
+- *p = '\0';
+-
+- while ((ulonglong) val > (ulonglong) LONG_MAX)
+- {
+- ulonglong quo=(ulonglong) val/(uint) radix;
+- uint rem= (uint) (val- quo* (uint) radix);
+- *--p = _dig_vec[rem];
+- val= quo;
+- }
+- long_val= (long) val;
+- while (long_val != 0)
+- {
+- long quo= long_val/radix;
+- *--p = _dig_vec[(uchar) (long_val - quo*radix)];
+- long_val= quo;
+- }
+- while ((*dst++ = *p++) != 0) ;
+- return dst-1;
+-}
+-
+-#endif
+-
+-#ifndef longlong10_to_str
+-char *longlong10_to_str(longlong val,char *dst,int radix)
+-{
+- char buffer[65];
+- register char *p;
+- long long_val;
+-
+- if (radix < 0)
+- {
+- if (val < 0)
+- {
+- *dst++ = '-';
+- val = -val;
+- }
+- }
+-
+- if (val == 0)
+- {
+- *dst++='0';
+- *dst='\0';
+- return dst;
+- }
+- p = &buffer[sizeof(buffer)-1];
+- *p = '\0';
+-
+- while ((ulonglong) val > (ulonglong) LONG_MAX)
+- {
+- ulonglong quo=(ulonglong) val/(uint) 10;
+- uint rem= (uint) (val- quo* (uint) 10);
+- *--p = _dig_vec[rem];
+- val= quo;
+- }
+- long_val= (long) val;
+- while (long_val != 0)
+- {
+- long quo= long_val/10;
+- *--p = _dig_vec[(uchar) (long_val - quo*10)];
+- long_val= quo;
+- }
+- while ((*dst++ = *p++) != 0) ;
+- return dst-1;
+-}
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_dirname.c mariadb-native-client.trunk/libmysql/mf_dirname.c
+--- mariadb/libmysql/mf_dirname.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_dirname.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,100 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+- /* Functions definied in this file */
+-
+-uint dirname_length(const char *name)
+-{
+- register my_string pos,gpos;
+-#ifdef FN_DEVCHAR
+- if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0)
+-#endif
+- pos=(char*) name-1;
+-
+- gpos= pos++;
+- for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
+- if (*pos == FN_LIBCHAR || *pos == '/'
+-#ifdef FN_C_AFTER_DIR
+- || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
+-#endif
+- )
+- gpos=pos;
+- return ((uint) (uint) (gpos+1-(char*) name));
+-}
+-
+-
+- /* Gives directory part of filename. Directory ends with '/' */
+- /* Returns length of directory part */
+-
+-uint dirname_part(my_string to, const char *name)
+-{
+- uint length;
+- DBUG_ENTER("dirname_part");
+- DBUG_PRINT("enter",("'%s'",name));
+-
+- length=dirname_length(name);
+- (void) strmake(to,(char*) name,min(length,FN_REFLEN-2));
+- convert_dirname(to); /* Convert chars */
+- DBUG_RETURN(length);
+-} /* dirname */
+-
+-
+- /* convert dirname to use under this system */
+- /* If MSDOS converts '/' to '\' */
+- /* If VMS converts '<' to '[' and '>' to ']' */
+- /* Adds a '/' to end if there isn't one and the last isn't a dev_char */
+- /* ARGSUSED */
+-
+-#ifndef FN_DEVCHAR
+-#define FN_DEVCHAR '\0' /* For easier code */
+-#endif
+-
+-char *convert_dirname(my_string to)
+-{
+- reg1 char *pos;
+-#if FN_LIBCHAR != '/'
+- {
+- pos=to-1; /* Change from '/' */
+- while ((pos=strchr(pos+1,'/')) != 0)
+- *pos=FN_LIBCHAR;
+- }
+-#endif
+-#ifdef FN_C_BEFORE_DIR_2
+- {
+- for (pos=to ; *pos ; pos++)
+- {
+- if (*pos == FN_C_BEFORE_DIR_2)
+- *pos=FN_C_BEFORE_DIR;
+- if (*pos == FN_C_AFTER_DIR_2)
+- *pos=FN_C_AFTER_DIR;
+- }
+- }
+-#else
+- { /* Append FN_LIBCHAR if not there */
+- pos=strend(to);
+- if (pos != to && (pos[-1] != FN_LIBCHAR && pos[-1] != FN_DEVCHAR))
+- {
+- *pos++=FN_LIBCHAR;
+- *pos=0;
+- }
+- }
+-#endif
+- return pos; /* Pointer to end of dir */
+-} /* convert_dirname */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_fn_ext.c mariadb-native-client.trunk/libmysql/mf_fn_ext.c
+--- mariadb/libmysql/mf_fn_ext.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_fn_ext.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,46 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Returnerar en pekare till filnamnets extension. */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+- /* Return a pointerto the extension of the filename
+- The pointer points at the extension character (normally '.'))
+- If there isn't any extension, the pointer points at the end
+- NULL of the filename
+- */
+-
+-my_string fn_ext(const char *name)
+-{
+- register my_string pos,gpos;
+- DBUG_ENTER("fn_ext");
+- DBUG_PRINT("mfunkt",("name: '%s'",name));
+-
+-#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR)
+- {
+- char buff[FN_REFLEN];
+- gpos=(my_string) name+dirname_part(buff,(char*) name);
+- }
+-#else
+- if (!(gpos=strrchr(name,FNLIBCHAR)))
+- gpos=name;
+-#endif
+- pos=strrchr(gpos,FN_EXTCHAR);
+- DBUG_RETURN (pos ? pos : strend(gpos));
+-} /* fn_ext */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_format.c mariadb-native-client.trunk/libmysql/mf_format.c
+--- mariadb/libmysql/mf_format.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_format.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,156 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#ifdef HAVE_REALPATH
+-#include <sys/param.h>
+-#include <sys/stat.h>
+-#endif
+-
+- /* format a filename with replace of library and extension */
+- /* params to and name may be identicall */
+- /* function doesn't change name if name != to */
+- /* Flag may be: 1 replace filenames library with 'dsk' */
+- /* 2 replace extension with 'form' */
+- /* 4 Unpack filename (replace ~ with home) */
+- /* 8 Pack filename as short as possibly */
+- /* 16 Resolve symbolic links for filename */
+- /* 32 Resolve filename to full path */
+- /* 64 Return NULL if too long path */
+-
+-#ifdef SCO
+-#define BUFF_LEN 4097
+-#else
+-#ifdef MAXPATHLEN
+-#define BUFF_LEN MAXPATHLEN
+-#else
+-#define BUFF_LEN FN_LEN
+-#endif
+-#endif
+-
+-my_string fn_format(my_string to, const char *name, const char *dsk,
+- const char *form, int flag)
+-{
+- reg1 uint length;
+- char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos;
+- const char *ext;
+- DBUG_ENTER("fn_format");
+- DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d",
+- name,dsk,form,flag));
+-
+- /* Kopiera & skippa enheten */
+- name+=(length=dirname_part(dev,(startpos=(my_string) name)));
+- if (length == 0 || flag & 1)
+- {
+- (void) strmake(dev,dsk, sizeof(dev) - 2);
+- /* Use given directory */
+- convert_dirname(dev); /* Fix to this OS */
+- }
+- if (flag & 8)
+- pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
+- if (flag & 4)
+- (void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
+- if ((pos=(char*)strchr(name,FN_EXTCHAR)) != NullS)
+- {
+- if ((flag & 2) == 0) /* Skall vi byta extension ? */
+- {
+- length=strlength(name); /* Old extension */
+- ext = "";
+- }
+- else
+- {
+- length=(uint) (pos-(char*) name); /* Change extension */
+- ext= form;
+- }
+- }
+- else
+- {
+- length=strlength(name); /* Har ingen ext- tag nya */
+- ext=form;
+- }
+-
+- if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
+- { /* To long path, return original */
+- uint tmp_length;
+- if (flag & 64)
+- return 0;
+- tmp_length=strlength(startpos);
+- DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %d",dev,ext,length));
+- (void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
+- }
+- else
+- {
+- if (to == startpos)
+- {
+- bmove(buff,(char*) name,length); /* Save name for last copy */
+- name=buff;
+- }
+- pos=strmake(strmov(to,dev),name,length);
+-#ifdef FN_UPPER_CASE
+- caseup_str(to);
+-#endif
+-#ifdef FN_LOWER_CASE
+- casedn_str(to);
+-#endif
+- (void) strmov(pos,ext); /* Don't convert extension */
+- }
+- /* Purify gives a lot of UMR errors when using realpath */
+-#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
+- if (flag & 16)
+- {
+- struct stat stat_buff;
+- if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+- {
+- if (realpath(to,buff))
+- strmake(to,buff,FN_REFLEN-1);
+- }
+- }
+-#endif
+- DBUG_RETURN (to);
+-} /* fn_format */
+-
+-
+- /*
+- strlength(const string str)
+- Return length of string with end-space:s not counted.
+- */
+-
+-size_s strlength(const char *str)
+-{
+- reg1 my_string pos;
+- reg2 my_string found;
+- DBUG_ENTER("strlength");
+-
+- pos=found=(char*) str;
+-
+- while (*pos)
+- {
+- if (*pos != ' ')
+- {
+- while (*++pos && *pos != ' ') {};
+- if (!*pos)
+- {
+- found=pos; /* String ends here */
+- break;
+- }
+- }
+- found=pos;
+- while (*++pos == ' ') {};
+- }
+- DBUG_RETURN((size_s) (found-(char*) str));
+-} /* strlength */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_loadpath.c mariadb-native-client.trunk/libmysql/mf_loadpath.c
+--- mariadb/libmysql/mf_loadpath.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_loadpath.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,54 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+- /* Returns full load-path for a file. to may be = path */
+- /* if path is a hard-path return path */
+- /* if path starts with home-dir return path */
+- /* if path starts with current dir or parent-dir unpack path */
+- /* if there is no path, prepend with own_path_prefix if given */
+- /* else unpack path according to current dir */
+-
+-my_string my_load_path(my_string to, const char *path,
+- const char *own_path_prefix)
+-{
+- char buff[FN_REFLEN];
+- DBUG_ENTER("my_load_path");
+- DBUG_PRINT("enter",("path: %s prefix: %s",path,
+- own_path_prefix ? own_path_prefix : ""));
+-
+- if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
+- test_if_hard_path(path))
+- VOID(strmov(buff,path));
+- else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) ||
+- (is_prefix((gptr) path,FN_PARENTDIR) &&
+- path[strlen(FN_PARENTDIR)] == FN_LIBCHAR) ||
+- ! own_path_prefix)
+- {
+- if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
+- VOID(strcat(buff,path));
+- else
+- VOID(strmov(buff,path));
+- }
+- else
+- VOID(strxmov(buff,own_path_prefix,path,NullS));
+- strmov(to,buff);
+- DBUG_PRINT("exit",("to: %s",to));
+- DBUG_RETURN(to);
+-} /* my_load_path */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_pack.c mariadb-native-client.trunk/libmysql/mf_pack.c
+--- mariadb/libmysql/mf_pack.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_pack.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,532 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#ifdef HAVE_PWD_H
+-#include <pwd.h>
+-#endif
+-#ifdef VMS
+-#include <rms.h>
+-#include <iodef.h>
+-#include <descrip.h>
+-#endif /* VMS */
+-
+-static my_string NEAR_F expand_tilde(my_string *path);
+-
+- /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
+- /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
+- /* to may be == from */
+-
+-void pack_dirname(my_string to, const char *from)
+-{
+- int cwd_err;
+- uint d_length,length,buff_length= 0;
+- my_string start;
+- char buff[FN_REFLEN];
+- DBUG_ENTER("pack_dirname");
+-
+- (void) intern_filename(to,from); /* Change to intern name */
+-
+-#ifdef FN_DEVCHAR
+- if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skipp device part */
+- start++;
+- else
+-#endif
+- start=to;
+-
+- LINT_INIT(buff_length);
+- if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
+- {
+- buff_length= (uint) strlen(buff);
+- d_length=(uint) (start-to);
+- if ((start == to ||
+- (buff_length == d_length && !bcmp(buff,start,d_length))) &&
+- *start != FN_LIBCHAR && *start)
+- { /* Put current dir before */
+- bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
+- }
+- }
+-
+- if ((d_length= cleanup_dirname(to,to)) != 0)
+- {
+- length=0;
+- if (home_dir)
+- {
+- length= (uint) strlen(home_dir);
+- if (home_dir[length-1] == FN_LIBCHAR)
+- length--; /* Don't test last '/' */
+- }
+- if (length > 1 && length < d_length)
+- { /* test if /xx/yy -> ~/yy */
+- if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
+- {
+- to[0]=FN_HOMELIB; /* Filename begins with ~ */
+- (void) strmov_overlapp(to+1,to+length);
+- }
+- }
+- if (! cwd_err)
+- { /* Test if cwd is ~/... */
+- if (length > 1 && length < buff_length)
+- {
+- if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
+- {
+- buff[0]=FN_HOMELIB;
+- (void) strmov_overlapp(buff+1,buff+length);
+- }
+- }
+- if (is_prefix(to,buff))
+- {
+- length= (uint) strlen(buff);
+- if (to[length])
+- (void) strmov_overlapp(to,to+length); /* Remove everything before */
+- else
+- {
+- to[0]= FN_CURLIB; /* Put ./ instead of cwd */
+- to[1]= FN_LIBCHAR;
+- to[2]= '\0';
+- }
+- }
+- }
+- }
+- DBUG_PRINT("exit",("to: '%s'",to));
+- DBUG_VOID_RETURN;
+-} /* pack_dirname */
+-
+-
+- /* remove unwanted chars from dirname */
+- /* if "/../" removes prev dir; "/~/" removes all before ~ */
+- /* "//" is same as "/", except on Win32 at start of a file */
+- /* "/./" is removed */
+- /* Unpacks home_dir if "~/.." used */
+- /* Unpacks current dir if if "./.." used */
+-
+-uint cleanup_dirname(register my_string to, const char *from)
+- /* to may be == from */
+-
+-{
+- reg5 uint length;
+- reg2 my_string pos;
+- reg3 my_string from_ptr;
+- reg4 my_string start;
+- char parent[5], /* for "FN_PARENTDIR" */
+- buff[FN_REFLEN+1],*end_parentdir;
+- DBUG_ENTER("cleanup_dirname");
+- DBUG_PRINT("enter",("from: '%s'",from));
+-
+- start=buff;
+- from_ptr=(my_string) from;
+-#ifdef FN_DEVCHAR
+- if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
+- { /* Skipp device part */
+- length=(uint) (pos-from_ptr)+1;
+- start=strnmov(buff,from_ptr,length); from_ptr+=length;
+- }
+-#endif
+-
+- parent[0]=FN_LIBCHAR;
+- length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
+- for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
+- {
+- if (*pos == '/')
+- *pos = FN_LIBCHAR;
+- if (*pos == FN_LIBCHAR)
+- {
+- if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
+- { /* If .../../; skipp prev */
+- pos-=length;
+- if (pos != start)
+- { /* not /../ */
+- pos--;
+- if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
+- {
+- if (!home_dir)
+- {
+- pos+=length+1; /* Don't unpack ~/.. */
+- continue;
+- }
+- pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
+- if (*pos == FN_LIBCHAR)
+- pos--; /* home ended with '/' */
+- }
+- if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
+- {
+- if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+- {
+- pos+=length+1; /* Don't unpack ./.. */
+- continue;
+- }
+- pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
+- if (*pos == FN_LIBCHAR)
+- pos--; /* home ended with '/' */
+- }
+- end_parentdir=pos;
+- while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
+- pos--;
+- if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
+- { /* Don't remove ~user/ */
+- pos=strmov(end_parentdir+1,parent);
+- *pos=FN_LIBCHAR;
+- continue;
+- }
+- }
+- }
+- else if ((uint) (pos-start) == length-1 &&
+- !bcmp(start,parent+1,length-1))
+- start=pos; /* Starts with "../" */
+- else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
+- {
+-#ifdef FN_NETWORK_DRIVES
+- if (pos-start != 1)
+-#endif
+- pos--; /* Remove dupplicate '/' */
+- }
+- else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
+- pos-=2; /* Skipp /./ */
+- else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
+- { /* Found ..../~/ */
+- buff[0]=FN_HOMELIB;
+- buff[1]=FN_LIBCHAR;
+- start=buff; pos=buff+1;
+- }
+- }
+- }
+- (void) strmov(to,buff);
+- DBUG_PRINT("exit",("to: '%s'",to));
+- DBUG_RETURN((uint) (pos-buff));
+-} /* cleanup_dirname */
+-
+-
+- /*
+- On system where you don't have symbolic links, the following
+- code will allow you to create a file:
+- directory-name.lnk that should contain the real path
+- to the directory. This will be used if the directory name
+- doesn't exists
+- */
+-
+-
+-my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
+-
+-#ifdef USE_SYMDIR
+-void symdirget(char *dir)
+-{
+- char buff[FN_REFLEN];
+- char *pos=strend(dir);
+- if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK))
+- {
+- FILE *fp;
+- char temp= *(--pos); /* May be "/" or "\" */
+- strmov(pos,".sym");
+- fp = my_fopen(dir, O_RDONLY,MYF(0));
+- *pos++=temp; *pos=0; /* Restore old filename */
+- if (fp)
+- {
+- if (fgets(buff, sizeof(buff)-1, fp))
+- {
+- for (pos=strend(buff);
+- pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
+- pos --);
+-
+- /* Ensure that the symlink ends with the directory symbol */
+- if (pos == buff || pos[-1] != FN_LIBCHAR)
+- *pos++=FN_LIBCHAR;
+-
+- strmake(dir,buff, (uint) (pos-buff));
+- }
+- my_fclose(fp,MYF(0));
+- }
+- }
+-}
+-#endif /* USE_SYMDIR */
+-
+- /* Unpacks dirname to name that can be used by open... */
+- /* Make that last char of to is '/' if from not empty and
+- from doesn't end in FN_DEVCHAR */
+- /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */
+- /* Returns length of new directory */
+-
+-uint unpack_dirname(my_string to, const char *from)
+-
+- /* to may be == from */
+-{
+- uint length,h_length;
+- char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
+- DBUG_ENTER("unpack_dirname");
+-
+- (void) intern_filename(buff,from); /* Change to intern name */
+- length= (uint) strlen(buff); /* Fix that '/' is last */
+- if (length &&
+-#ifdef FN_DEVCHAR
+- buff[length-1] != FN_DEVCHAR &&
+-#endif
+- buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
+- {
+- buff[length]=FN_LIBCHAR;
+- buff[length+1]= '\0';
+- }
+-
+- length=cleanup_dirname(buff,buff);
+- if (buff[0] == FN_HOMELIB)
+- {
+- suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
+- if (tilde_expansion)
+- {
+- length-=(uint) (suffix-buff)-1;
+- if (length+(h_length= (uint) strlen(tilde_expansion)) <= FN_REFLEN)
+- {
+- if (tilde_expansion[h_length-1] == FN_LIBCHAR)
+- h_length--;
+- if (buff+h_length < suffix)
+- bmove(buff+h_length,suffix,length);
+- else
+- bmove_upp(buff+h_length+length,suffix+length,length);
+- bmove(buff,tilde_expansion,h_length);
+- }
+- }
+- }
+-#ifdef USE_SYMDIR
+- if (my_use_symdir)
+- symdirget(buff);
+-#endif
+- DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
+-} /* unpack_dirname */
+-
+-
+- /* Expand tilde to home or user-directory */
+- /* Path is reset to point at FN_LIBCHAR after ~xxx */
+-
+-static my_string NEAR_F expand_tilde(my_string *path)
+-{
+- if (path[0][0] == FN_LIBCHAR)
+- return home_dir; /* ~/ expanded to home */
+-#ifdef HAVE_GETPWNAM
+- {
+- char *str,save;
+- struct passwd *user_entry;
+-
+- if (!(str=strchr(*path,FN_LIBCHAR)))
+- str=strend(*path);
+- save= *str; *str= '\0';
+- user_entry=getpwnam(*path);
+- *str=save;
+- endpwent();
+- if (user_entry)
+- {
+- *path=str;
+- return user_entry->pw_dir;
+- }
+- }
+-#endif
+- return (my_string) 0;
+-}
+-
+- /* fix filename so it can be used by open, create .. */
+- /* to may be == from */
+- /* Returns to */
+-
+-my_string unpack_filename(my_string to, const char *from)
+-{
+- uint length,n_length;
+- char buff[FN_REFLEN];
+- DBUG_ENTER("unpack_filename");
+-
+- length=dirname_part(buff,from); /* copy & convert dirname */
+- n_length=unpack_dirname(buff,buff);
+- if (n_length+strlen(from+length) < FN_REFLEN)
+- {
+- (void) strmov(buff+n_length,from+length);
+- (void) system_filename(to,buff); /* Fix to usably filename */
+- }
+- else
+- (void) system_filename(to,from); /* Fix to usably filename */
+- DBUG_RETURN(to);
+-} /* unpack_filename */
+-
+-
+- /* Convert filename (unix standard) to system standard */
+- /* Used before system command's like open(), create() .. */
+- /* Returns to */
+-
+-uint system_filename(my_string to, const char *from)
+-{
+-#ifndef FN_C_BEFORE_DIR
+- return (uint) (strmake(to,from,FN_REFLEN-1)-to);
+-#else /* VMS */
+-
+- /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
+- /* change 'dev:xxx' to 'dev:xxx' */
+- /* change './xxx' to 'xxx' */
+- /* change './lib/' or lib/ to '[.lib]' */
+- /* change '/x/y/z to '[x.y]x' */
+- /* change 'dev:/x' to 'dev:[000000]x' */
+-
+- int libchar_found,length;
+- my_string to_pos,from_pos,pos;
+- char buff[FN_REFLEN];
+- DBUG_ENTER("system_filename");
+-
+- libchar_found=0;
+- (void) strmov(buff,from); /* If to == from */
+- from_pos= buff;
+- if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+- {
+- pos++;
+- to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+- from_pos=pos;
+- }
+- else
+- to_pos=to;
+-
+- if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
+- from_pos+=2; /* Skipp './' */
+- if (strchr(from_pos,FN_LIBCHAR))
+- {
+- *(to_pos++) = FN_C_BEFORE_DIR;
+- if (strinstr(from_pos,FN_ROOTDIR) == 1)
+- {
+- from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
+- if (! strchr(from_pos,FN_LIBCHAR))
+- { /* No dir, use [000000] */
+- to_pos=strmov(to_pos,FN_C_ROOT_DIR);
+- libchar_found++;
+- }
+- }
+- else
+- *(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
+-
+- while ((pos=strchr(from_pos,FN_LIBCHAR)))
+- {
+- if (libchar_found++)
+- *(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
+- if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
+- from_pos+strlen(FN_PARENTDIR) == pos)
+- to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
+- else
+- to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+- from_pos=pos+1;
+- }
+- *(to_pos++)=FN_C_AFTER_DIR;
+- }
+- length=(int) (strmov(to_pos,from_pos)-to);
+- DBUG_PRINT("exit",("name: '%s'",to));
+- DBUG_RETURN((uint) length);
+-#endif
+-} /* system_filename */
+-
+-
+- /* Fix a filename to intern (UNIX format) */
+-
+-my_string intern_filename(my_string to, const char *from)
+-{
+-#ifndef VMS
+- {
+- uint length;
+- char buff[FN_REFLEN];
+- if (from == to)
+- { /* Dirname may destroy from */
+- strmov(buff,from);
+- from=buff;
+- }
+- length=dirname_part(to,from); /* Copy dirname & fix chars */
+- (void) strcat(to,from+length);
+- return (to);
+- }
+-#else /* VMS */
+-
+- /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
+- /* change 'dev:xxx' to 'dev:xxx' */
+- /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
+- /* change '[.lib]' to './lib/' */
+- /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
+- /* change '[000000.x] or [x.000000]' to '/x/' */
+-
+- int par_length,root_length;
+- my_string pos,from_pos,to_pos,end_pos;
+- char buff[FN_REFLEN];
+-
+- (void) strmov(buff,from);
+- convert_dirname(buff); /* change '<>' to '[]' */
+- from_pos=buff;
+- if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+- {
+- pos++;
+- to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+- from_pos=pos;
+- }
+- else
+- to_pos=to;
+-
+- root_length=strlen(FN_C_ROOT_DIR);
+- if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
+- (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
+- {
+- to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+- /* Copy all between ':' and '[' */
+- from_pos=pos+1;
+- if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
+- (from_pos[root_length] == FN_C_DIR_SEP ||
+- from_pos[root_length] == FN_C_AFTER_DIR))
+- {
+- from_pos+=root_length+1;
+- }
+- else if (*from_pos == FN_C_DIR_SEP)
+- *(to_pos++) = FN_CURLIB; /* Set ./ first */
+- *(to_pos++) = FN_LIBCHAR;
+-
+- par_length=strlen(FN_C_PARENT_DIR);
+- pos=to_pos;
+- for (; from_pos <= end_pos ; from_pos++)
+- {
+- switch (*from_pos) {
+- case FN_C_DIR_SEP:
+- case FN_C_AFTER_DIR:
+- if (pos != to_pos)
+- {
+- if ((int) (to_pos-pos) == root_length &&
+- is_suffix(pos,FN_C_ROOT_DIR))
+- to_pos=pos; /* remove root-pos */
+- else
+- {
+- *(to_pos++)=FN_LIBCHAR; /* Find lib */
+- pos=to_pos;
+- }
+- }
+- break;
+- case FN_C_BEFORE_DIR:
+- break;
+- case '-': /* *(FN_C_PARENT_DIR): */
+- if (to_pos[-1] == FN_LIBCHAR &&
+- strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
+- { /* Change '-' to '..' */
+- to_pos=strmov(to_pos,FN_PARENTDIR);
+- *(to_pos++)=FN_LIBCHAR;
+- pos=to_pos;
+- from_pos+=par_length-1;
+- break;
+- }
+- /* Fall through */
+- default:
+- *(to_pos++)= *from_pos;
+- break;
+- }
+- }
+- }
+- (void) strmov(to_pos,from_pos);
+- return (to);
+-#endif /* VMS */
+-} /* intern_filename */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_path.c mariadb-native-client.trunk/libmysql/mf_path.c
+--- mariadb/libmysql/mf_path.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_path.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,120 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+-static char *find_file_in_path(char *to,const char *name);
+-
+- /* Finds where program can find it's files.
+- pre_pathname is found by first locking at progname (argv[0]).
+- if progname contains path the path is returned.
+- else if progname is found in path, return it
+- else if progname is given and POSIX environment variable "_" is set
+- then path is taken from "_".
+- If filename doesn't contain a path append MY_BASEDIR_VERSION or
+- MY_BASEDIR if defined, else append "/my/running".
+- own_path_name_part is concatinated to result.
+- my_path puts result in to and returns to */
+-
+-my_string my_path(my_string to, const char *progname,
+- const char *own_pathname_part)
+-{
+- my_string start,end,prog;
+- DBUG_ENTER("my_path");
+-
+- start=to; /* Return this */
+- if (progname && (dirname_part(to, progname) ||
+- find_file_in_path(to,progname) ||
+- ((prog=getenv("_")) != 0 && dirname_part(to,prog))))
+- {
+- VOID(intern_filename(to,to));
+- if (!test_if_hard_path(to))
+- {
+- if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+- bchange(to,0,curr_dir, (uint) strlen(curr_dir), (uint) strlen(to)+1);
+- }
+- }
+- else
+- {
+- if ((end = getenv("MY_BASEDIR_VERSION")) == 0 &&
+- (end = getenv("MY_BASEDIR")) == 0)
+- {
+-#ifdef DEFAULT_BASEDIR
+- end= (char*) DEFAULT_BASEDIR;
+-#else
+- end= (char*) "/my/";
+-#endif
+- }
+- VOID(intern_filename(to,end));
+- to=strend(to);
+- if (to != start && to[-1] != FN_LIBCHAR)
+- *to++ = FN_LIBCHAR;
+- VOID(strmov(to,own_pathname_part));
+- }
+- DBUG_PRINT("exit",("to: '%s'",start));
+- DBUG_RETURN(start);
+-} /* my_path */
+-
+-
+- /* test if file without filename is found in path */
+- /* Returns to if found and to has dirpart if found, else NullS */
+-
+-#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
+-#define F_OK 0
+-#define PATH_SEP ';'
+-#define PROGRAM_EXTENSION ".exe"
+-#else
+-#define PATH_SEP ':'
+-#endif
+-
+-static char *find_file_in_path(char *to, const char *name)
+-{
+- char *path,*pos,dir[2];
+- const char *ext="";
+-
+- if (!(path=getenv("PATH")))
+- return NullS;
+- dir[0]=FN_LIBCHAR; dir[1]=0;
+-#ifdef PROGRAM_EXTENSION
+- if (!fn_ext(name)[0])
+- ext=PROGRAM_EXTENSION;
+-#endif
+-
+- for (pos=path ; (pos=strchr(pos,PATH_SEP)) ; path= ++pos)
+- {
+- if (path != pos)
+- {
+- strxmov(strnmov(to,path,(uint) (pos-path)),dir,name,ext,NullS);
+- if (!access(to,F_OK))
+- {
+- to[(uint) (pos-path)+1]=0; /* Return path only */
+- return to;
+- }
+- }
+- }
+-#ifdef _WIN32
+- to[0]=FN_CURLIB;
+- strxmov(to+1,dir,name,ext,NullS);
+- if (!access(to,F_OK)) /* Test in current dir */
+- {
+- to[2]=0; /* Leave ".\" */
+- return to;
+- }
+-#endif
+- return NullS; /* File not found */
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_tempfile.c mariadb-native-client.trunk/libmysql/mf_tempfile.c
+--- mariadb/libmysql/mf_tempfile.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/mf_tempfile.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,198 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#include "my_static.h"
+-#include "mysys_err.h"
+-#include <errno.h>
+-#ifdef HAVE_PATHS_H
+-#include <paths.h>
+-#endif
+-
+-#ifdef HAVE_TEMPNAM
+-#if !defined( MSDOS) && !defined(OS2)
+-extern char **environ;
+-#endif
+-#endif
+-
+-/*
+- Create a temporary file in a given directory
+- This function should be used instead of my_tempnam() !
+-*/
+-
+-File create_temp_file(char *to, const char *dir, const char *prefix,
+- int mode __attribute__((unused)),
+- myf MyFlags __attribute__((unused)))
+-{
+- File file= -1;
+- DBUG_ENTER("create_temp_file");
+-#if defined(_MSC_VER)
+- {
+- char temp[FN_REFLEN],*end,*res,**old_env,*temp_env[1];
+- old_env=environ;
+- if (dir)
+- {
+- end=strend(dir)-1;
+- if (!dir[0])
+- { /* Change empty string to current dir */
+- to[0]= FN_CURLIB;
+- to[1]= 0;
+- dir=to;
+- }
+- else if (*end == FN_DEVCHAR)
+- { /* Get current dir for drive */
+- _fullpath(temp,dir,FN_REFLEN);
+- dir=to;
+- }
+- else if (*end == FN_LIBCHAR && dir < end && end[-1] != FN_DEVCHAR)
+- {
+- strmake(to,dir,(uint) (end-dir)); /* Copy and remove last '\' */
+- dir=to;
+- }
+- environ=temp_env; /* Force use of dir (dir not checked) */
+- temp_env[0]=0;
+- }
+- if ((res=tempnam((char*) dir,(char *) prefix)))
+- {
+- strmake(to,res,FN_REFLEN-1);
+- (*free)(res);
+- file=my_create(to,0, mode, MyFlags);
+- }
+- environ=old_env;
+- }
+-#elif defined(_ZTC__)
+- if (!dir)
+- dir=getenv("TMPDIR");
+- if ((res=tempnam((char*) dir,(char *) prefix)))
+- {
+- strmake(to,res,FN_REFLEN-1);
+- (*free)(res);
+- file=my_create(to, 0, mode, MyFlags);
+- }
+-#elif defined(HAVE_MKSTEMP)
+- {
+- char prefix_buff[30];
+- uint pfx_len;
+- File org_file;
+-
+- pfx_len=(strmov(strnmov(prefix_buff,
+- prefix ? prefix : "tmp.",
+- sizeof(prefix_buff)-7),"XXXXXX") - prefix_buff);
+- if (!dir && ! (dir =getenv("TMPDIR")))
+- dir=P_tmpdir;
+- if (strlen(dir)+ pfx_len > FN_REFLEN-2)
+- {
+- errno=my_errno= ENAMETOOLONG;
+- return 1;
+- }
+- strmov(to,dir);
+- strmov(convert_dirname(to),prefix_buff);
+- org_file=mkstemp(to);
+- file=my_register_filename(org_file, to, FILE_BY_MKSTEMP,
+- EE_CANTCREATEFILE, MyFlags);
+- /* If we didn't manage to register the name, remove the temp file */
+- if (org_file >= 0 && file < 0)
+- {
+- int tmp=my_errno;
+- (void) my_delete(to, MYF(MY_WME | ME_NOINPUT));
+- my_errno=tmp;
+- }
+- }
+-#elif defined(HAVE_TEMPNAM)
+- {
+- char *res,**old_env,*temp_env[1];
+- if (dir && !dir[0])
+- { /* Change empty string to current dir */
+- to[0]= FN_CURLIB;
+- to[1]= 0;
+- dir=to;
+- }
+-#ifdef OS2
+- // changing environ variable doesn't work with VACPP
+- char buffer[256];
+- sprintf( buffer, "TMP=%s", dir);
+- // remove ending backslash
+- if (buffer[strlen(buffer)-1] == '\\')
+- buffer[strlen(buffer)-1] = '\0';
+- putenv( buffer);
+-#else
+- old_env= (char**) environ;
+- if (dir)
+- { /* Don't use TMPDIR if dir is given */
+- environ=(const char**) temp_env;
+- temp_env[0]=0;
+- }
+-#endif
+- if ((res=tempnam((char*) dir, (char*) prefix)))
+- {
+- strmake(to,res,FN_REFLEN-1);
+- (*free)(res);
+- file=my_create(to,0,
+- (int) (O_RDWR | O_BINARY | O_TRUNC |
+- O_TEMPORARY | O_SHORT_LIVED),
+- MYF(MY_WME));
+-
+- }
+- else
+- {
+- DBUG_PRINT("error",("Got error: %d from tempnam",errno));
+- }
+-#ifndef OS2
+- environ=(const char**) old_env;
+-#endif
+- }
+-#else
+- {
+- register long uniq;
+- register int length;
+- my_string pos,end_pos;
+- /* Make an unique number */
+- pthread_mutex_lock(&THR_LOCK_open);
+- uniq= ((long) getpid() << 20) + (long) _my_tempnam_used++ ;
+- pthread_mutex_unlock(&THR_LOCK_open);
+- if (!dir && !(dir=getenv("TMPDIR"))) /* Use this if possibly */
+- dir=P_tmpdir; /* Use system default */
+- length=strlen(dir)+strlen(pfx)+1;
+-
+- DBUG_PRINT("test",("mallocing %d byte",length+8+sizeof(TMP_EXT)+1));
+- if (length+8+sizeof(TMP_EXT)+1 > FN_REFLENGTH)
+- errno=my_errno= ENAMETOOLONG;
+- else
+- {
+- end_pos=strmov(to,dir);
+- if (end_pos != to && end_pos[-1] != FN_LIBCHAR)
+- *end_pos++=FN_LIBCHAR;
+- end_pos=strmov(end_pos,pfx);
+-
+- for (length=0 ; length < 8 && uniq ; length++)
+- {
+- *end_pos++= _dig_vec[(int) (uniq & 31)];
+- uniq >>= 5;
+- }
+- (void) strmov(end_pos,TMP_EXT);
+- file=my_create(to,0,
+- (int) (O_RDWR | O_BINARY | O_TRUNC |
+- O_TEMPORARY | O_SHORT_LIVED),
+- MYF(MY_WME));
+- }
+- }
+-#endif
+- if (file >= 0)
+- thread_safe_increment(my_tmp_file_created,&THR_LOCK_open);
+- DBUG_RETURN(file);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_unixpath.c mariadb-native-client.trunk/libmysql/mf_unixpath.c
+--- mariadb/libmysql/mf_unixpath.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_unixpath.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,33 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+- /* convert filename to unix style filename */
+- /* If MSDOS converts '\' to '/' */
+-
+-void to_unix_path(my_string to __attribute__((unused)))
+-{
+-#if FN_LIBCHAR != '/'
+- {
+- to--;
+- while ((to=strchr(to+1,FN_LIBCHAR)) != 0)
+- *to='/';
+- }
+-#endif
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mf_wcomp.c mariadb-native-client.trunk/libmysql/mf_wcomp.c
+--- mariadb/libmysql/mf_wcomp.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mf_wcomp.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,68 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Funktions for comparing with wild-cards */
+-
+-#include "mysys_priv.h"
+-
+- /* Test if a string is "comparable" to a wild-card string */
+- /* returns 0 if the strings are "comparable" */
+-
+-char wild_many='*';
+-char wild_one='?';
+-char wild_prefix=0;
+-
+-int wild_compare(register const char *str, register const char *wildstr)
+-{
+- reg3 int flag;
+- DBUG_ENTER("wild_compare");
+-
+- while (*wildstr)
+- {
+- while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
+- {
+- if (*wildstr == wild_prefix && wildstr[1])
+- wildstr++;
+- if (*wildstr++ != *str++) DBUG_RETURN(1);
+- }
+- if (! *wildstr ) DBUG_RETURN (*str != 0);
+- if (*wildstr++ == wild_one)
+- {
+- if (! *str++) DBUG_RETURN (1); /* One char; skipp */
+- }
+- else
+- { /* Found '*' */
+- if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
+- flag=(*wildstr != wild_many && *wildstr != wild_one);
+- do
+- {
+- if (flag)
+- {
+- char cmp;
+- if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+- cmp=wildstr[1];
+- while (*str && *str != cmp)
+- str++;
+- if (!*str) DBUG_RETURN (1);
+- }
+- if (wild_compare(str,wildstr) == 0) DBUG_RETURN (0);
+- } while (*str++ && wildstr[0] != wild_many);
+- DBUG_RETURN(1);
+- }
+- }
+- DBUG_RETURN (*str != '\0');
+-} /* wild_compare */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mulalloc.c mariadb-native-client.trunk/libmysql/mulalloc.c
+--- mariadb/libmysql/mulalloc.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mulalloc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,53 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+- /* Malloc many pointers at the same time */
+- /* format myFlags,ptr,length,ptr,length ... until null ptr */
+-
+-#include "mysys_priv.h"
+-#include <stdarg.h>
+-
+-gptr my_multi_malloc(myf myFlags, ...)
+-{
+- va_list args;
+- char **ptr,*start,*res;
+- uint tot_length,length;
+- DBUG_ENTER("my_multi_malloc");
+-
+- va_start(args,myFlags);
+- tot_length=0;
+- while ((ptr=va_arg(args, char **)))
+- {
+- length=va_arg(args,uint);
+- tot_length+=ALIGN_SIZE(length);
+- }
+- va_end(args);
+-
+- if (!(start=(char *) my_malloc(tot_length,myFlags)))
+- DBUG_RETURN(0); /* purecov: inspected */
+-
+- va_start(args,myFlags);
+- res=start;
+- while ((ptr=va_arg(args, char **)))
+- {
+- *ptr=res;
+- length=va_arg(args,uint);
+- res+=ALIGN_SIZE(length);
+- }
+- va_end(args);
+- DBUG_RETURN((gptr) start);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_alloc.c mariadb-native-client.trunk/libmysql/my_alloc.c
+--- mariadb/libmysql/my_alloc.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_alloc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,154 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Routines to handle mallocing of results which will be freed the same time */
+-
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <m_string.h>
+-
+-void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size)
+-{
+- mem_root->free=mem_root->used=0;
+- mem_root->min_malloc=32;
+- mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
+- mem_root->error_handler=0;
+-#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
+- if (pre_alloc_size)
+- {
+- if ((mem_root->free = mem_root->pre_alloc=
+- (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
+- MYF(0))))
+- {
+- mem_root->free->size=pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
+- mem_root->free->left=pre_alloc_size;
+- mem_root->free->next=0;
+- }
+- }
+-#endif
+-}
+-
+-gptr alloc_root(MEM_ROOT *mem_root, size_t Size)
+-{
+-#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
+- reg1 USED_MEM *next;
+- Size+=ALIGN_SIZE(sizeof(USED_MEM));
+-
+- if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
+- {
+- if (mem_root->error_handler)
+- (*mem_root->error_handler)();
+- return((gptr) 0); /* purecov: inspected */
+- }
+- next->next=mem_root->used;
+- mem_root->used=next;
+- return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
+-#else
+- size_t get_size,max_left;
+- gptr point;
+- reg1 USED_MEM *next;
+- reg2 USED_MEM **prev;
+-
+- Size= ALIGN_SIZE(Size);
+- prev= &mem_root->free;
+- max_left=0;
+- for (next= *prev ; next && next->left < Size ; next= next->next)
+- {
+- if (next->left > max_left)
+- max_left=next->left;
+- prev= &next->next;
+- }
+- if (! next)
+- { /* Time to alloc new block */
+- get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+- if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
+- get_size=mem_root->block_size; /* Normal alloc */
+-
+- if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
+- {
+- if (mem_root->error_handler)
+- (*mem_root->error_handler)();
+- return((gptr) 0); /* purecov: inspected */
+- }
+- next->next= *prev;
+- next->size= get_size;
+- next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+- *prev=next;
+- }
+- point= (gptr) ((char*) next+ (next->size-next->left));
+- if ((next->left-= Size) < mem_root->min_malloc)
+- { /* Full block */
+- *prev=next->next; /* Remove block from list */
+- next->next=mem_root->used;
+- mem_root->used=next;
+- }
+- return(point);
+-#endif
+-}
+-
+- /* deallocate everything used by alloc_root */
+-
+-void free_root(MEM_ROOT *root, myf MyFlags)
+-{
+- reg1 USED_MEM *next,*old;
+- DBUG_ENTER("free_root");
+-
+- if (!root)
+- DBUG_VOID_RETURN; /* purecov: inspected */
+- if (!(MyFlags & MY_KEEP_PREALLOC))
+- root->pre_alloc=0;
+-
+- for ( next=root->used; next ;)
+- {
+- old=next; next= next->next ;
+- if (old != root->pre_alloc)
+- my_free((gptr) old,MYF(0));
+- }
+- for (next= root->free ; next ; )
+- {
+- old=next; next= next->next ;
+- if (old != root->pre_alloc)
+- my_free((gptr) old,MYF(0));
+- }
+- root->used=root->free=0;
+- if (root->pre_alloc)
+- {
+- root->free=root->pre_alloc;
+- root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
+- root->free->next=0;
+- }
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-char *strdup_root(MEM_ROOT *root,const char *str)
+-{
+- size_t len= strlen(str)+1;
+- char *pos;
+- if ((pos=alloc_root(root,len)))
+- memcpy(pos,str,len);
+- return pos;
+-}
+-
+-
+-char *memdup_root(MEM_ROOT *root, const char *str, size_t len)
+-{
+- char *pos;
+- if ((pos=alloc_root(root,len)))
+- memcpy(pos,str,len);
+- return pos;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_auth.c mariadb-native-client.trunk/libmysql/my_auth.c
+--- mariadb/libmysql/my_auth.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_auth.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,714 +0,0 @@
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <m_string.h>
+-#include <errmsg.h>
+-#include <mysql.h>
+-#include <mysql/client_plugin.h>
+-#include <violite.h>
+-#ifdef HAVE_OPENSSL
+-#include <my_secure.h>
+-#endif
+-
+-typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
+-static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t);
+-static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+-static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+-extern void read_user_name(char *name);
+-
+-#define compile_time_assert(A) \
+-do {\
+- typedef char constraint[(A) ? 1 : -1];\
+-} while (0);
+-
+-static auth_plugin_t native_password_client_plugin=
+-{
+- MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+- MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+- native_password_plugin_name,
+- "R.J.Silk, Sergei Golubchik",
+- "Native MySQL authentication",
+- {1, 0, 0},
+- NULL,
+- NULL,
+- native_password_auth_client
+-};
+-
+-static auth_plugin_t old_password_client_plugin=
+-{
+- MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+- MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+- old_password_plugin_name,
+- "R.J.Silk, Sergei Golubchik",
+- "Old MySQL-3.23 authentication",
+- {1, 0, 0},
+- NULL,
+- NULL,
+- old_password_auth_client
+-};
+-
+-struct st_mysql_client_plugin *mysql_client_builtins[]=
+-{
+- (struct st_mysql_client_plugin *)&native_password_client_plugin,
+- 0
+-};
+-
+-/* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
+-typedef struct {
+- int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
+- int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, size_t pkt_len);
+- void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
+- /* -= end of MYSQL_PLUGIN_VIO =- */
+- MYSQL *mysql;
+- auth_plugin_t *plugin; /**< what plugin we're under */
+- const char *db;
+- struct {
+- uchar *pkt; /**< pointer into NET::buff */
+- uint pkt_len;
+- } cached_server_reply;
+- uint packets_read, packets_written; /**< counters for send/received packets */
+- my_bool mysql_change_user; /**< if it's mysql_change_user() */
+- int last_read_packet_len; /**< the length of the last *read* packet */
+-} MCPVIO_EXT;
+-
+-static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+-{
+- int pkt_len;
+- uchar *pkt;
+-
+- if (((MCPVIO_EXT *)vio)->mysql_change_user)
+- {
+- /*
+- in mysql_change_user() the client sends the first packet.
+- we use the old scramble.
+- */
+- pkt= (uchar*)mysql->scramble_buff;
+- pkt_len= SCRAMBLE_LENGTH + 1;
+- }
+- else
+- {
+- /* read the scramble */
+- if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+- return CR_ERROR;
+-
+- if (pkt_len != SCRAMBLE_LENGTH + 1)
+- return CR_SERVER_HANDSHAKE_ERR;
+-
+- /* save it in MYSQL */
+- memcpy(mysql->scramble_buff, pkt, SCRAMBLE_LENGTH);
+- mysql->scramble_buff[SCRAMBLE_LENGTH] = 0;
+- }
+-
+- if (mysql->passwd[0])
+- {
+- char scrambled[SCRAMBLE_LENGTH + 1];
+- my_scramble_41((uchar *)scrambled, (char*)pkt, mysql->passwd);
+- if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH))
+- return CR_ERROR;
+- }
+- else
+- if (vio->write_packet(vio, 0, 0)) /* no password */
+- return CR_ERROR;
+-
+- return CR_OK;
+-}
+-
+-
+-/**
+- client authentication plugin that does old MySQL authentication
+- using an 8-byte (4.0-) scramble
+-*/
+-
+-static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+-{
+- uchar *pkt;
+- int pkt_len;
+-
+- if (((MCPVIO_EXT *)vio)->mysql_change_user)
+- {
+- /*
+- in mysql_change_user() the client sends the first packet.
+- we use the old scramble.
+- */
+- pkt= (uchar*)mysql->scramble_buff;
+- pkt_len= SCRAMBLE_LENGTH_323 + 1;
+- }
+- else
+- {
+- /* read the scramble */
+- if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+- return CR_ERROR;
+-
+- if (pkt_len != SCRAMBLE_LENGTH_323 + 1 &&
+- pkt_len != SCRAMBLE_LENGTH + 1)
+- return CR_SERVER_HANDSHAKE_ERR;
+-
+- /* save it in MYSQL */
+- memcpy(mysql->scramble_buff, pkt, pkt_len);
+- mysql->scramble_buff[pkt_len] = 0;
+- }
+-
+- if (mysql->passwd[0])
+- {
+- char scrambled[SCRAMBLE_LENGTH_323 + 1];
+- scramble_323(scrambled, (char*)pkt, mysql->passwd);
+- if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1))
+- return CR_ERROR;
+- }
+- else
+- if (vio->write_packet(vio, 0, 0)) /* no password */
+- return CR_ERROR;
+-
+- return CR_OK;
+-}
+-
+-/**
+- sends a COM_CHANGE_USER command with a caller provided payload
+-
+- Packet format:
+-
+- Bytes Content
+- ----- ----
+- n user name - \0-terminated string
+- n password
+- 3.23 scramble - \0-terminated string (9 bytes)
+- otherwise - length (1 byte) coded
+- n database name - \0-terminated string
+- 2 character set number (if the server >= 4.1.x)
+- n client auth plugin name - \0-terminated string,
+- (if the server supports plugin auth)
+-
+- @retval 0 ok
+- @retval 1 error
+-*/
+-
+-static int send_change_user_packet(MCPVIO_EXT *mpvio,
+- const uchar *data, int data_len)
+-{
+- MYSQL *mysql= mpvio->mysql;
+- char *buff, *end;
+- int res= 1;
+-
+- buff= my_alloca(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1);
+-
+- end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
+-
+- if (!data_len)
+- *end++= 0;
+- else
+- {
+- if (mysql->client_flag & CLIENT_SECURE_CONNECTION)
+- {
+- DBUG_ASSERT(data_len <= 255);
+- if (data_len > 255)
+- {
+- my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0);
+- goto error;
+- }
+- *end++= data_len;
+- }
+- else
+- {
+- DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1);
+- DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0);
+- }
+- memcpy(end, data, data_len);
+- end+= data_len;
+- }
+- end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
+-
+- if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
+- {
+- int2store(end, (ushort) mysql->charset->nr);
+- end+= 2;
+- }
+-
+- if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
+- end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
+-
+- res= simple_command(mysql, MYSQL_COM_CHANGE_USER,
+- buff, (ulong)(end-buff), 1);
+-
+-error:
+- my_afree(buff);
+- return res;
+-}
+-
+-
+-/**
+- sends a client authentication packet (second packet in the 3-way handshake)
+-
+- Packet format (when the server is 4.0 or earlier):
+-
+- Bytes Content
+- ----- ----
+- 2 client capabilities
+- 3 max packet size
+- n user name, \0-terminated
+- 9 scramble_323, \0-terminated
+-
+- Packet format (when the server is 4.1 or newer):
+-
+- Bytes Content
+- ----- ----
+- 4 client capabilities
+- 4 max packet size
+- 1 charset number
+- 23 reserved (always 0)
+- n user name, \0-terminated
+- n plugin auth data (e.g. scramble), length (1 byte) coded
+- n database name, \0-terminated
+- (if CLIENT_CONNECT_WITH_DB is set in the capabilities)
+- n client auth plugin name - \0-terminated string,
+- (if CLIENT_PLUGIN_AUTH is set in the capabilities)
+-
+- @retval 0 ok
+- @retval 1 error
+-*/
+-
+-static int send_client_reply_packet(MCPVIO_EXT *mpvio,
+- const uchar *data, int data_len)
+-{
+- MYSQL *mysql= mpvio->mysql;
+- NET *net= &mysql->net;
+- char *buff, *end;
+-
+- /* see end= buff+32 below, fixed size of the packet is 32 bytes */
+- buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN);
+-
+- mysql->client_flag|= mysql->options.client_flag;
+- mysql->client_flag|= CLIENT_CAPABILITIES;
+-
+- if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
+- mysql->client_flag|= CLIENT_MULTI_RESULTS;
+-
+-#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+- if (mysql->options.ssl_key || mysql->options.ssl_cert ||
+- mysql->options.ssl_ca || mysql->options.ssl_capath ||
+- mysql->options.ssl_cipher)
+- mysql->options.use_ssl= 1;
+- if (mysql->options.use_ssl)
+- mysql->client_flag|= CLIENT_SSL;
+-#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
+- if (mpvio->db)
+- mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
+-
+- /* Remove options that server doesn't support */
+- mysql->client_flag= mysql->client_flag &
+- (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
+- | mysql->server_capabilities);
+-
+-#ifndef HAVE_COMPRESS
+- mysql->client_flag&= ~CLIENT_COMPRESS;
+-#endif
+-
+- if (mysql->client_flag & CLIENT_PROTOCOL_41)
+- {
+- /* 4.1 server and 4.1 client has a 32 byte option flag */
+- int4store(buff,mysql->client_flag);
+- int4store(buff+4, net->max_packet_size);
+- buff[8]= (char) mysql->charset->nr;
+- bzero(buff+9, 32-9);
+- end= buff+32;
+- }
+- else
+- {
+- int2store(buff, mysql->client_flag);
+- int3store(buff+2, net->max_packet_size);
+- end= buff+5;
+- }
+-#ifdef HAVE_OPENSSL
+- if (mysql->client_flag & CLIENT_SSL)
+- {
+- SSL *ssl;
+- /*
+- Send mysql->client_flag, max_packet_size - unencrypted otherwise
+- the server does not know we want to do SSL
+- */
+- if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net))
+- {
+- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "sending connection information to server",
+- errno);
+- goto error;
+- }
+-
+- /* Create SSL */
+- if (!(ssl= my_ssl_init(mysql)))
+- goto error;
+-
+- /* Connect to the server */
+- if (my_ssl_connect(ssl))
+- {
+- SSL_free(ssl);
+- goto error;
+- }
+- /* todo: server certification verification */
+- }
+-#endif /* HAVE_OPENSSL */
+-
+- DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
+- mysql->server_version, mysql->server_capabilities,
+- mysql->server_status, mysql->client_flag));
+-
+- compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
+-
+- /* This needs to be changed as it's not useful with big packets */
+- if (mysql->user[0])
+- strmake(end, mysql->user, USERNAME_LENGTH);
+- else
+- read_user_name(end);
+-
+- /* We have to handle different version of handshake here */
+- DBUG_PRINT("info",("user: %s",end));
+- end= strend(end) + 1;
+- if (data_len)
+- {
+- if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+- {
+- *end++= data_len;
+- memcpy(end, data, data_len);
+- end+= data_len;
+- }
+- else
+- {
+- DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
+- memcpy(end, data, data_len);
+- end+= data_len;
+- }
+- }
+- else
+- *end++= 0;
+-
+- /* Add database if needed */
+- if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
+- {
+- end= strmake(end, mpvio->db, NAME_LEN) + 1;
+- mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
+- }
+-
+- if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
+- end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
+-
+- /* Write authentication package */
+- if (my_net_write(net, buff, (size_t) (end-buff)) || net_flush(net))
+- {
+- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "sending authentication information",
+- errno);
+- goto error;
+- }
+- my_afree(buff);
+- return 0;
+-
+-error:
+- my_afree(buff);
+- return 1;
+-}
+-
+-/**
+- vio->read_packet() callback method for client authentication plugins
+-
+- This function is called by a client authentication plugin, when it wants
+- to read data from the server.
+-*/
+-
+-static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
+-{
+- MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
+- MYSQL *mysql= mpvio->mysql;
+- ulong pkt_len;
+-
+- /* there are cached data left, feed it to a plugin */
+- if (mpvio->cached_server_reply.pkt)
+- {
+- *buf= mpvio->cached_server_reply.pkt;
+- mpvio->cached_server_reply.pkt= 0;
+- mpvio->packets_read++;
+- return mpvio->cached_server_reply.pkt_len;
+- }
+-
+- if (mpvio->packets_read == 0)
+- {
+- /*
+- the server handshake packet came from the wrong plugin,
+- or it's mysql_change_user(). Either way, there is no data
+- for a plugin to read. send a dummy packet to the server
+- to initiate a dialog.
+- */
+- if (client_mpvio_write_packet(mpv, 0, 0))
+- return (int)packet_error;
+- }
+-
+- /* otherwise read the data */
+- pkt_len= net_safe_read(mysql);
+- mpvio->last_read_packet_len= pkt_len;
+- *buf= mysql->net.read_pos;
+-
+- /* was it a request to change plugins ? */
+- if (**buf == 254)
+- return (int)packet_error; /* if yes, this plugin shan't continue */
+-
+- /*
+- the server sends \1\255 or \1\254 instead of just \255 or \254 -
+- for us to not confuse it with an error or "change plugin" packets.
+- We remove this escaping \1 here.
+-
+- See also server_mpvio_write_packet() where the escaping is done.
+- */
+- if (pkt_len && **buf == 1)
+- {
+- (*buf)++;
+- pkt_len--;
+- }
+- mpvio->packets_read++;
+- return pkt_len;
+-}
+-
+-/**
+- vio->write_packet() callback method for client authentication plugins
+-
+- This function is called by a client authentication plugin, when it wants
+- to send data to the server.
+-
+- It transparently wraps the data into a change user or authentication
+- handshake packet, if neccessary.
+-*/
+-
+-static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
+- const uchar *pkt, size_t pkt_len)
+-{
+- int res;
+- MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
+-
+- if (mpvio->packets_written == 0)
+- {
+- if (mpvio->mysql_change_user)
+- res= send_change_user_packet(mpvio, pkt, pkt_len);
+- else
+- res= send_client_reply_packet(mpvio, pkt, pkt_len);
+- }
+- else
+- {
+- NET *net= &mpvio->mysql->net;
+- if (mpvio->mysql->thd)
+- res= 1; /* no chit-chat in embedded */
+- else
+- res= my_net_write(net, (char *)pkt, pkt_len) || net_flush(net);
+- if (res)
+- my_set_error(mpvio->mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "sending authentication information",
+- errno);
+- }
+- mpvio->packets_written++;
+- return res;
+-}
+-
+-/**
+- fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
+- connection
+-*/
+-
+-void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
+-{
+- bzero(info, sizeof(*info));
+- switch (vio->type) {
+- case VIO_TYPE_TCPIP:
+- info->protocol= MYSQL_VIO_TCP;
+- info->socket= vio->sd;
+- return;
+- case VIO_TYPE_SOCKET:
+- info->protocol= MYSQL_VIO_SOCKET;
+- info->socket= vio->sd;
+- return;
+- case VIO_TYPE_SSL:
+- {
+- struct sockaddr addr;
+- SOCKET_SIZE_TYPE addrlen= sizeof(addr);
+- if (getsockname(vio->sd, &addr, &addrlen))
+- return;
+- info->protocol= addr.sa_family == AF_UNIX ?
+- MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
+- info->socket= vio->sd;
+- return;
+- }
+-#ifdef _WIN32
+- case VIO_TYPE_NAMEDPIPE:
+- info->protocol= MYSQL_VIO_PIPE;
+- info->handle= vio->hPipe;
+- return;
+-/* not supported yet
+- case VIO_TYPE_SHARED_MEMORY:
+- info->protocol= MYSQL_VIO_MEMORY;
+- info->handle= vio->handle_file_map;
+- return;
+-*/
+-#endif
+- default: DBUG_ASSERT(0);
+- }
+-}
+-
+-static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
+- MYSQL_PLUGIN_VIO_INFO *info)
+-{
+- MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio;
+- mpvio_info(mpvio->mysql->net.vio, info);
+-}
+-
+-/**
+- Client side of the plugin driver authentication.
+-
+- @note this is used by both the mysql_real_connect and mysql_change_user
+-
+- @param mysql mysql
+- @param data pointer to the plugin auth data (scramble) in the
+- handshake packet
+- @param data_len the length of the data
+- @param data_plugin a plugin that data were prepared for
+- or 0 if it's mysql_change_user()
+- @param db initial db to use, can be 0
+-
+- @retval 0 ok
+- @retval 1 error
+-*/
+-
+-int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
+- const char *data_plugin, const char *db)
+-{
+- const char *auth_plugin_name;
+- auth_plugin_t *auth_plugin;
+- MCPVIO_EXT mpvio;
+- ulong pkt_length;
+- int res;
+-
+- /* determine the default/initial plugin to use */
+- if (mysql->options.extension && mysql->options.extension->default_auth &&
+- mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
+- {
+- auth_plugin_name= mysql->options.extension->default_auth;
+- if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
+- auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
+- return 1; /* oops, not found */
+- }
+- else
+- {
+- auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
+- &native_password_client_plugin : &old_password_client_plugin;
+- auth_plugin_name= auth_plugin->name;
+- }
+-
+- mysql->net.last_errno= 0; /* just in case */
+-
+- if (data_plugin && strcmp(data_plugin, auth_plugin_name))
+- {
+- /* data was prepared for a different plugin, don't show it to this one */
+- data= 0;
+- data_len= 0;
+- }
+-
+- mpvio.mysql_change_user= data_plugin == 0;
+- mpvio.cached_server_reply.pkt= (uchar*)data;
+- mpvio.cached_server_reply.pkt_len= data_len;
+- mpvio.read_packet= client_mpvio_read_packet;
+- mpvio.write_packet= client_mpvio_write_packet;
+- mpvio.info= client_mpvio_info;
+- mpvio.mysql= mysql;
+- mpvio.packets_read= mpvio.packets_written= 0;
+- mpvio.db= db;
+- mpvio.plugin= auth_plugin;
+-
+- res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+-
+- compile_time_assert(CR_OK == -1);
+- compile_time_assert(CR_ERROR == 0);
+- if (res > CR_OK && mysql->net.read_pos[0] != 254)
+- {
+- /*
+- the plugin returned an error. write it down in mysql,
+- unless the error code is CR_ERROR and mysql->net.last_errno
+- is already set (the plugin has done it)
+- */
+- if (res > CR_ERROR)
+- my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0);
+- else
+- if (!mysql->net.last_errno)
+- my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
+- return 1;
+- }
+-
+- /* read the OK packet (or use the cached value in mysql->net.read_pos */
+- if (res == CR_OK)
+- pkt_length= net_safe_read(mysql);
+- else /* res == CR_OK_HANDSHAKE_COMPLETE */
+- pkt_length= mpvio.last_read_packet_len;
+-
+- if (pkt_length == packet_error)
+- {
+- if (mysql->net.last_errno == CR_SERVER_LOST)
+- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "reading authorization packet",
+- errno);
+- return 1;
+- }
+-
+- if (mysql->net.read_pos[0] == 254)
+- {
+- /* The server asked to use a different authentication plugin */
+- if (pkt_length == 1)
+- {
+- /* old "use short scramble" packet */
+- auth_plugin_name= old_password_plugin_name;
+- mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble_buff;
+- mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
+- }
+- else
+- {
+- /* new "use different plugin" packet */
+- uint len;
+- auth_plugin_name= (char*)mysql->net.read_pos + 1;
+- len= strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
+- mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
+- mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
+- }
+-
+- if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql,
+- auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
+- return 1;
+-
+- mpvio.plugin= auth_plugin;
+- res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+-
+- if (res > CR_OK)
+- {
+- if (res > CR_ERROR)
+- my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0);
+- else
+- if (!mysql->net.last_errno)
+- my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
+- return 1;
+- }
+-
+- if (res != CR_OK_HANDSHAKE_COMPLETE)
+- {
+- /* Read what server thinks about out new auth message report */
+- if (net_safe_read(mysql) == packet_error)
+- {
+- if (mysql->net.last_errno == CR_SERVER_LOST)
+- my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
+- ER(CR_SERVER_LOST_EXTENDED),
+- "reading final connect information",
+- errno);
+- return 1;
+- }
+- }
+- }
+- /*
+- net->read_pos[0] should always be 0 here if the server implements
+- the protocol correctly
+- */
+- return mysql->net.read_pos[0] != 0;
+-}
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_charset.c mariadb-native-client.trunk/libmysql/my_charset.c
+--- mariadb/libmysql/my_charset.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_charset.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,828 +0,0 @@
+-/****************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-*****************************************************************************/
+-
+-/* The implementation for character set support was ported from PHP's mysqlnd
+- extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
+-
+- Original file header:
+- +----------------------------------------------------------------------+
+- | PHP Version 5 |
+- +----------------------------------------------------------------------+
+- | Copyright (c) 2006-2011 The PHP Group |
+- +----------------------------------------------------------------------+
+- | This source file is subject to version 3.01 of the PHP license, |
+- | that is bundled with this package in the file LICENSE, and is |
+- | available through the world-wide-web at the following url: |
+- | http://www.php.net/license/3_01.txt |
+- | If you did not receive a copy of the PHP license and are unable to |
+- | obtain it through the world-wide-web, please send a note to |
+- | license@php.net so we can mail you a copy immediately. |
+- +----------------------------------------------------------------------+
+- | Authors: Georg Richter <georg@mysql.com> |
+- | Andrey Hristov <andrey@mysql.com> |
+- | Ulf Wendel <uwendel@mysql.com> |
+- +----------------------------------------------------------------------+
+-*/
+-
+-#ifndef _WIN32
+-#include <strings.h>
+-#include <string.h>
+-#else
+-#include <string.h>
+-#endif
+-#include <my_global.h>
+-#include <m_ctype.h>
+-
+-/*
+- +----------------------------------------------------------------------+
+- | PHP Version 5 |
+- +----------------------------------------------------------------------+
+- | Copyright (c) 2006-2011 The PHP Group |
+- +----------------------------------------------------------------------+
+- | This source file is subject to version 3.01 of the PHP license, |
+- | that is bundled with this package in the file LICENSE, and is |
+- | available through the world-wide-web at the following url: |
+- | http://www.php.net/license/3_01.txt |
+- | If you did not receive a copy of the PHP license and are unable to |
+- | obtain it through the world-wide-web, please send a note to |
+- | license@php.net so we can mail you a copy immediately. |
+- +----------------------------------------------------------------------+
+- | Authors: Georg Richter <georg@mysql.com> |
+- | Andrey Hristov <andrey@mysql.com> |
+- | Ulf Wendel <uwendel@mysql.com> |
+- +----------------------------------------------------------------------+
+-*/
+-
+-/* {{{ utf8 functions */
+-static unsigned int check_mb_utf8mb3_sequence(const char *start, const char *end)
+-{
+- uchar c;
+-
+- if (start >= end) {
+- return 0;
+- }
+-
+- c = (uchar) start[0];
+-
+- if (c < 0x80) {
+- return 1; /* single byte character */
+- }
+- if (c < 0xC2) {
+- return 0; /* invalid mb character */
+- }
+- if (c < 0xE0) {
+- if (start + 2 > end) {
+- return 0; /* too small */
+- }
+- if (!(((uchar)start[1] ^ 0x80) < 0x40)) {
+- return 0;
+- }
+- return 2;
+- }
+- if (c < 0xF0) {
+- if (start + 3 > end) {
+- return 0; /* too small */
+- }
+- if (!(((uchar)start[1] ^ 0x80) < 0x40 && ((uchar)start[2] ^ 0x80) < 0x40 &&
+- (c >= 0xE1 || (uchar)start[1] >= 0xA0))) {
+- return 0; /* invalid utf8 character */
+- }
+- return 3;
+- }
+- return 0;
+-}
+-
+-
+-static unsigned int check_mb_utf8_sequence(const char *start, const char *end)
+-{
+- uchar c;
+-
+- if (start >= end) {
+- return 0;
+- }
+-
+- c = (uchar) start[0];
+-
+- if (c < 0x80) {
+- return 1; /* single byte character */
+- }
+- if (c < 0xC2) {
+- return 0; /* invalid mb character */
+- }
+- if (c < 0xE0) {
+- if (start + 2 > end) {
+- return 0; /* too small */
+- }
+- if (!(((uchar)start[1] ^ 0x80) < 0x40)) {
+- return 0;
+- }
+- return 2;
+- }
+- if (c < 0xF0) {
+- if (start + 3 > end) {
+- return 0; /* too small */
+- }
+- if (!(((uchar)start[1] ^ 0x80) < 0x40 && ((uchar)start[2] ^ 0x80) < 0x40 &&
+- (c >= 0xE1 || (uchar)start[1] >= 0xA0))) {
+- return 0; /* invalid utf8 character */
+- }
+- return 3;
+- }
+- if (c < 0xF5) {
+- if (start + 4 > end) { /* We need 4 characters */
+- return 0; /* too small */
+- }
+-
+- /*
+- UTF-8 quick four-byte mask:
+- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+- Encoding allows to encode U+00010000..U+001FFFFF
+-
+- The maximum character defined in the Unicode standard is U+0010FFFF.
+- Higher characters U+00110000..U+001FFFFF are not used.
+-
+- 11110000.10010000.10xxxxxx.10xxxxxx == F0.90.80.80 == U+00010000 (min)
+- 11110100.10001111.10111111.10111111 == F4.8F.BF.BF == U+0010FFFF (max)
+-
+- Valid codes:
+- [F0][90..BF][80..BF][80..BF]
+- [F1][80..BF][80..BF][80..BF]
+- [F2][80..BF][80..BF][80..BF]
+- [F3][80..BF][80..BF][80..BF]
+- [F4][80..8F][80..BF][80..BF]
+- */
+-
+- if (!(((uchar)start[1] ^ 0x80) < 0x40 &&
+- ((uchar)start[2] ^ 0x80) < 0x40 &&
+- ((uchar)start[3] ^ 0x80) < 0x40 &&
+- (c >= 0xf1 || (uchar)start[1] >= 0x90) &&
+- (c <= 0xf3 || (uchar)start[1] <= 0x8F)))
+- {
+- return 0; /* invalid utf8 character */
+- }
+- return 4;
+- }
+- return 0;
+-}
+-
+-static unsigned int check_mb_utf8mb3_valid(const char *start, const char *end)
+-{
+- unsigned int len = check_mb_utf8mb3_sequence(start, end);
+- return (len > 1)? len:0;
+-}
+-
+-static unsigned int check_mb_utf8_valid(const char *start, const char *end)
+-{
+- unsigned int len = check_mb_utf8_sequence(start, end);
+- return (len > 1)? len:0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_utf8mb3(unsigned int utf8)
+-{
+- if (utf8 < 0x80) {
+- return 1; /* single byte character */
+- }
+- if (utf8 < 0xC2) {
+- return 0; /* invalid multibyte header */
+- }
+- if (utf8 < 0xE0) {
+- return 2; /* double byte character */
+- }
+- if (utf8 < 0xF0) {
+- return 3; /* triple byte character */
+- }
+- return 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_utf8(unsigned int utf8)
+-{
+- if (utf8 < 0x80) {
+- return 1; /* single byte character */
+- }
+- if (utf8 < 0xC2) {
+- return 0; /* invalid multibyte header */
+- }
+- if (utf8 < 0xE0) {
+- return 2; /* double byte character */
+- }
+- if (utf8 < 0xF0) {
+- return 3; /* triple byte character */
+- }
+- if (utf8 < 0xF8) {
+- return 4; /* four byte character */
+- }
+- return 0;
+-}
+-/* }}} */
+-
+-
+-/* {{{ big5 functions */
+-#define valid_big5head(c) (0xA1 <= (unsigned int)(c) && (unsigned int)(c) <= 0xF9)
+-#define valid_big5tail(c) ((0x40 <= (unsigned int)(c) && (unsigned int)(c) <= 0x7E) || \
+- (0xA1 <= (unsigned int)(c) && (unsigned int)(c) <= 0xFE))
+-
+-#define isbig5code(c,d) (isbig5head(c) && isbig5tail(d))
+-
+-static unsigned int check_mb_big5(const char *start, const char *end)
+-{
+- return (valid_big5head(*(start)) && (end - start) > 1 && valid_big5tail(*(start + 1)) ? 2 : 0);
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_big5(unsigned int big5)
+-{
+- return (valid_big5head(big5)) ? 2 : 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ cp932 functions */
+-#define valid_cp932head(c) ((0x81 <= (c) && (c) <= 0x9F) || (0xE0 <= (c) && c <= 0xFC))
+-#define valid_cp932tail(c) ((0x40 <= (c) && (c) <= 0x7E) || (0x80 <= (c) && c <= 0xFC))
+-
+-
+-static unsigned int check_mb_cp932(const char *start, const char *end)
+-{
+- return (valid_cp932head((uchar)start[0]) && (end - start > 1) &&
+- valid_cp932tail((uchar)start[1])) ? 2 : 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_cp932(unsigned int cp932)
+-{
+- return (valid_cp932head((uchar)cp932)) ? 2 : 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ euckr functions */
+-#define valid_euckr(c) ((0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE))
+-
+-static unsigned int check_mb_euckr(const char *start, const char *end)
+-{
+- if (end - start <= 1) {
+- return 0; /* invalid length */
+- }
+- if (*(uchar *)start < 0x80) {
+- return 0; /* invalid euckr character */
+- }
+- if (valid_euckr(start[1])) {
+- return 2;
+- }
+- return 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_euckr(unsigned int kr)
+-{
+- return (valid_euckr(kr)) ? 2 : 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ eucjpms functions */
+-#define valid_eucjpms(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xFE)
+-#define valid_eucjpms_kata(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xDF)
+-#define valid_eucjpms_ss2(c) (((c) & 0xFF) == 0x8E)
+-#define valid_eucjpms_ss3(c) (((c) & 0xFF) == 0x8F)
+-
+-static unsigned int check_mb_eucjpms(const char *start, const char *end)
+-{
+- if (*((uchar *)start) < 0x80) {
+- return 0; /* invalid eucjpms character */
+- }
+- if (valid_eucjpms(start[0]) && (end - start) > 1 && valid_eucjpms(start[1])) {
+- return 2;
+- }
+- if (valid_eucjpms_ss2(start[0]) && (end - start) > 1 && valid_eucjpms_kata(start[1])) {
+- return 2;
+- }
+- if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) &&
+- valid_eucjpms(start[2])) {
+- return 2;
+- }
+- return 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_eucjpms(unsigned int jpms)
+-{
+- if (valid_eucjpms(jpms) || valid_eucjpms_ss2(jpms)) {
+- return 2;
+- }
+- if (valid_eucjpms_ss3(jpms)) {
+- return 3;
+- }
+- return 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ gb2312 functions */
+-#define valid_gb2312_head(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xF7)
+-#define valid_gb2312_tail(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE)
+-
+-
+-static unsigned int check_mb_gb2312(const char *start, const char *end)
+-{
+- return (valid_gb2312_head((unsigned int)start[0]) && end - start > 1 &&
+- valid_gb2312_tail((unsigned int)start[1])) ? 2 : 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_gb2312(unsigned int gb)
+-{
+- return (valid_gb2312_head(gb)) ? 2 : 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ gbk functions */
+-#define valid_gbk_head(c) (0x81<=(uchar)(c) && (uchar)(c)<=0xFE)
+-#define valid_gbk_tail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7E) || (0x80<=(uchar)(c) && (uchar)(c)<=0xFE))
+-
+-static unsigned int check_mb_gbk(const char *start, const char *end)
+-{
+- return (valid_gbk_head(start[0]) && (end) - (start) > 1 && valid_gbk_tail(start[1])) ? 2 : 0;
+-}
+-
+-static unsigned int mysql_mbcharlen_gbk(unsigned int gbk)
+-{
+- return (valid_gbk_head(gbk) ? 2 : 1);
+-}
+-/* }}} */
+-
+-
+-/* {{{ sjis functions */
+-#define valid_sjis_head(c) ((0x81 <= (c) && (c) <= 0x9F) || (0xE0 <= (c) && (c) <= 0xFC))
+-#define valid_sjis_tail(c) ((0x40 <= (c) && (c) <= 0x7E) || (0x80 <= (c) && (c) <= 0xFC))
+-
+-
+-static unsigned int check_mb_sjis(const char *start, const char *end)
+-{
+- return (valid_sjis_head((uchar)start[0]) && (end - start) > 1 && valid_sjis_tail((uchar)start[1])) ? 2 : 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_sjis(unsigned int sjis)
+-{
+- return (valid_sjis_head((uchar)sjis)) ? 2 : 1;
+-}
+-/* }}} */
+-
+-
+-/* {{{ ucs2 functions */
+-static unsigned int check_mb_ucs2(const char *start __attribute((unused)), const char *end __attribute((unused)))
+-{
+- return 2; /* always 2 */
+-}
+-
+-static unsigned int mysql_mbcharlen_ucs2(unsigned int ucs2 __attribute((unused)))
+-{
+- return 2; /* always 2 */
+-}
+-/* }}} */
+-
+-
+-/* {{{ ujis functions */
+-#define valid_ujis(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xFE))
+-#define valid_ujis_kata(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xDF))
+-#define valid_ujis_ss2(c) (((c)&0xFF) == 0x8E)
+-#define valid_ujis_ss3(c) (((c)&0xFF) == 0x8F)
+-
+-static unsigned int check_mb_ujis(const char *start, const char *end)
+-{
+- if (*(uchar*)start < 0x80) {
+- return 0; /* invalid ujis character */
+- }
+- if (valid_ujis(*(start)) && valid_ujis(*((start)+1))) {
+- return 2;
+- }
+- if (valid_ujis_ss2(*(start)) && valid_ujis_kata(*((start)+1))) {
+- return 2;
+- }
+- if (valid_ujis_ss3(*(start)) && (end-start) > 2 && valid_ujis(*((start)+1)) && valid_ujis(*((start)+2))) {
+- return 3;
+- }
+- return 0;
+-}
+-
+-
+-static unsigned int mysql_mbcharlen_ujis(unsigned int ujis)
+-{
+- return (valid_ujis(ujis)? 2: valid_ujis_ss2(ujis)? 2: valid_ujis_ss3(ujis)? 3: 1);
+-}
+-/* }}} */
+-
+-
+-
+-/* {{{ utf16 functions */
+-#define UTF16_HIGH_HEAD(x) ((((uchar) (x)) & 0xFC) == 0xD8)
+-#define UTF16_LOW_HEAD(x) ((((uchar) (x)) & 0xFC) == 0xDC)
+-
+-static unsigned int check_mb_utf16(const char *start, const char *end)
+-{
+- if (start + 2 > end) {
+- return 0;
+- }
+-
+- if (UTF16_HIGH_HEAD(*start)) {
+- return (start + 4 <= end) && UTF16_LOW_HEAD(start[2]) ? 4 : 0;
+- }
+-
+- if (UTF16_LOW_HEAD(*start)) {
+- return 0;
+- }
+- return 2;
+-}
+-
+-
+-static uint mysql_mbcharlen_utf16(unsigned int utf16)
+-{
+- return UTF16_HIGH_HEAD(utf16) ? 4 : 2;
+-}
+-/* }}} */
+-
+-
+-/* {{{ utf32 functions */
+-static uint
+-check_mb_utf32(const char *start __attribute((unused)), const char *end __attribute((unused)))
+-{
+- return 4;
+-}
+-
+-
+-static uint
+-mysql_mbcharlen_utf32(unsigned int utf32 __attribute((unused)))
+-{
+- return 4;
+-}
+-/* }}} */
+-
+-/*
+- The server compiles sometimes the full utf-8 (the mb4) as utf8m4, and the old as utf8,
+- for BC reasons. Sometimes, utf8mb4 is just utf8 but the old charsets are utf8mb3.
+- Change easily now, with a macro, could be made compilastion dependable.
+-*/
+-
+-#define UTF8_MB4 "utf8mb4"
+-#define UTF8_MB3 "utf8"
+-
+-/* {{{ mysql_charsets */
+-const CHARSET_INFO compiled_charsets[] =
+-{
+- { 1, 1, "big5","big5_chinese_ci", "", "", 1, 2, mysql_mbcharlen_big5, check_mb_big5},
+- { 3, 1, "dec8", "dec8_swedisch_ci", "", "", 1, 1, NULL, NULL},
+- { 4, 1, "cp850", "cp850_general_ci", "", "", 1, 1, NULL, NULL},
+- { 6, 1, "hp8", "hp8_english_ci", "", "", 1, 1, NULL, NULL},
+- { 7, 1, "koi8r", "koi8r_general_ci", "", "", 1, 1, NULL, NULL},
+- { 8, 1, "latin1", "latin1_swedish_ci", "", "", 1, 1, NULL, NULL},
+- { 9, 1, "latin2", "latin2_general_ci", "", "", 1, 1, NULL, NULL},
+- { 10, 1, "swe7", "swe7_swedish_ci", "", "", 1, 1, NULL, NULL},
+- { 11, 1, "ascii", "ascii_general_ci", "", "", 1, 1, NULL, NULL},
+- { 12, 1, "ujis", "ujis_japanese_ci", "", "", 1, 3, mysql_mbcharlen_ujis, check_mb_ujis},
+- { 13, 1, "sjis", "sjis_japanese_ci", "", "", 1, 2, mysql_mbcharlen_sjis, check_mb_sjis},
+- { 16, 1, "hebrew", "hebrew_general_ci", "", "", 1, 1, NULL, NULL},
+- { 18, 1, "tis620", "tis620_thai_ci", "", "", 1, 1, NULL, NULL},
+- { 19, 1, "euckr", "euckr_korean_ci", "", "", 1, 2, mysql_mbcharlen_euckr, check_mb_euckr},
+- { 22, 1, "koi8u", "koi8u_general_ci", "", "", 1, 1, NULL, NULL},
+- { 24, 1, "gb2312", "gb2312_chinese_ci", "", "", 1, 2, mysql_mbcharlen_gb2312, check_mb_gb2312},
+- { 25, 1, "greek", "greek_general_ci", "", "", 1, 1, NULL, NULL},
+- { 26, 1, "cp1250", "cp1250_general_ci", "", "", 1, 1, NULL, NULL},
+- { 28, 1, "gbk", "gbk_chinese_ci", "", "", 1, 2, mysql_mbcharlen_gbk, check_mb_gbk},
+- { 30, 1, "latin5", "latin5_turkish_ci", "", "", 1, 1, NULL, NULL},
+- { 32, 1, "armscii8", "armscii8_general_ci", "", "", 1, 1, NULL, NULL},
+- { 33, 1, UTF8_MB3, UTF8_MB3"_general_ci", "UTF-8 Unicode", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 35, 1, "ucs2", "ucs2_general_ci", "UCS-2 Unicode", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 36, 1, "cp866", "cp866_general_ci", "", "", 1, 1, NULL, NULL},
+- { 37, 1, "keybcs2", "keybcs2_general_ci", "", "", 1, 1, NULL, NULL},
+- { 38, 1, "macce", "macce_general_ci", "", "", 1, 1, NULL, NULL},
+- { 39, 1, "macroman", "macroman_general_ci", "", "", 1, 1, NULL, NULL},
+- { 40, 1, "cp852", "cp852_general_ci", "", "", 1, 1, NULL, NULL},
+- { 41, 1, "latin7", "latin7_general_ci", "", "", 1, 1, NULL, NULL},
+- { 51, 1, "cp1251", "cp1251_general_ci", "", "", 1, 1, NULL, NULL},
+- { 57, 1, "cp1256", "cp1256_general_ci", "", "", 1, 1, NULL, NULL},
+- { 59, 1, "cp1257", "cp1257_general_ci", "", "", 1, 1, NULL, NULL},
+- { 63, 1, "binary", "binary", "", "", 1, 1, NULL, NULL},
+- { 92, 1, "geostd8", "geostd8_general_ci", "", "", 1, 1, NULL, NULL},
+- { 95, 1, "cp932", "cp932_japanese_ci", "", "", 1, 2, mysql_mbcharlen_cp932, check_mb_cp932},
+- { 97, 1, "eucjpms", "eucjpms_japanese_ci", "", "", 1, 3, mysql_mbcharlen_eucjpms, check_mb_eucjpms},
+- { 2, 1, "latin2", "latin2_czech_cs", "", "", 1, 1, NULL, NULL},
+- { 5, 1, "latin1", "latin1_german_ci", "", "", 1, 1, NULL, NULL},
+- { 14, 1, "cp1251", "cp1251_bulgarian_ci", "", "", 1, 1, NULL, NULL},
+- { 15, 1, "latin1", "latin1_danish_ci", "", "", 1, 1, NULL, NULL},
+- { 17, 1, "filename", "filename", "", "", 1, 5, NULL, NULL},
+- { 20, 1, "latin7", "latin7_estonian_cs", "", "", 1, 1, NULL, NULL},
+- { 21, 1, "latin2", "latin2_hungarian_ci", "", "", 1, 1, NULL, NULL},
+- { 23, 1, "cp1251", "cp1251_ukrainian_ci", "", "", 1, 1, NULL, NULL},
+- { 27, 1, "latin2", "latin2_croatian_ci", "", "", 1, 1, NULL, NULL},
+- { 29, 1, "cp1257", "cp1257_lithunian_ci", "", "", 1, 1, NULL, NULL},
+- { 31, 1, "latin1", "latin1_german2_ci", "", "", 1, 1, NULL, NULL},
+- { 34, 1, "cp1250", "cp1250_czech_cs", "", "", 1, 1, NULL, NULL},
+- { 42, 1, "latin7", "latin7_general_cs", "", "", 1, 1, NULL, NULL},
+- { 43, 1, "macce", "macce_bin", "", "", 1, 1, NULL, NULL},
+- { 44, 1, "cp1250", "cp1250_croatian_ci", "", "", 1, 1, NULL, NULL},
+- { 45, 1, UTF8_MB4, UTF8_MB4"_general_ci", "UTF-8 Unicode", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 46, 1, UTF8_MB4, UTF8_MB4"_bin", "UTF-8 Unicode", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 47, 1, "latin1", "latin1_bin", "", "", 1, 1, NULL, NULL},
+- { 48, 1, "latin1", "latin1_general_ci", "", "", 1, 1, NULL, NULL},
+- { 49, 1, "latin1", "latin1_general_cs", "", "", 1, 1, NULL, NULL},
+- { 50, 1, "cp1251", "cp1251_bin", "", "", 1, 1, NULL, NULL},
+- { 52, 1, "cp1251", "cp1251_general_cs", "", "", 1, 1, NULL, NULL},
+- { 53, 1, "macroman", "macroman_bin", "", "", 1, 1, NULL, NULL},
+- { 54, 1, "utf16", "utf16_general_ci", "UTF_16 Unicode", "", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
+- { 55, 1, "utf16", "utf16_bin", "UTF-16 Unicode", "", 2, 4, mysql_mbcharlen_utf16, check_mb_utf16},
+- { 58, 1, "cp1257", "cp1257_bin", "", "", 1, 1, NULL, NULL},
+-#ifdef USED_TO_BE_SO_BEFORE_MYSQL_5_5
+- { 60, 1, "armascii8", "armascii8_bin", "", "", 1, 1, NULL, NULL},
+-#endif
+- { 60, 1, "utf32", "utf32_general_ci", "UTF-32 Unicode", "", 4, 4, mysql_mbcharlen_utf32, check_mb_utf32},
+- { 61, 1, "utf32", "utf32_bin", "UTF-32 Unicode", "", 4, 4, mysql_mbcharlen_utf32, check_mb_utf32},
+- { 65, 1, "ascii", "ascii_bin", "", "", 1, 1, NULL, NULL},
+- { 66, 1, "cp1250", "cp1250_bin", "", "", 1, 1, NULL, NULL},
+- { 67, 1, "cp1256", "cp1256_bin", "", "", 1, 1, NULL, NULL},
+- { 68, 1, "cp866", "cp866_bin", "", "", 1, 1, NULL, NULL},
+- { 69, 1, "dec8", "dec8_bin", "", "", 1, 1, NULL, NULL},
+- { 70, 1, "greek", "greek_bin", "", "", 1, 1, NULL, NULL},
+- { 71, 1, "hebew", "hebrew_bin", "", "", 1, 1, NULL, NULL},
+- { 72, 1, "hp8", "hp8_bin", "", "", 1, 1, NULL, NULL},
+- { 73, 1, "keybcs2", "keybcs2_bin", "", "", 1, 1, NULL, NULL},
+- { 74, 1, "koi8r", "koi8r_bin", "", "", 1, 1, NULL, NULL},
+- { 75, 1, "koi8u", "koi8u_bin", "", "", 1, 1, NULL, NULL},
+- { 77, 1, "latin2", "latin2_bin", "", "", 1, 1, NULL, NULL},
+- { 78, 1, "latin5", "latin5_bin", "", "", 1, 1, NULL, NULL},
+- { 79, 1, "latin7", "latin7_bin", "", "", 1, 1, NULL, NULL},
+- { 80, 1, "cp850", "cp850_bin", "", "", 1, 1, NULL, NULL},
+- { 81, 1, "cp852", "cp852_bin", "", "", 1, 1, NULL, NULL},
+- { 82, 1, "swe7", "swe7_bin", "", "", 1, 1, NULL, NULL},
+- { 93, 1, "geostd8", "geostd8_bin", "", "", 1, 1, NULL, NULL},
+- { 83, 1, UTF8_MB3, UTF8_MB3"_bin", "UTF-8 Unicode", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 84, 1, "big5", "big5_bin", "", "", 1, 2, mysql_mbcharlen_big5, check_mb_big5},
+- { 85, 1, "euckr", "euckr_bin", "", "", 1, 2, mysql_mbcharlen_euckr, check_mb_euckr},
+- { 86, 1, "gb2312", "gb2312_bin", "", "", 1, 2, mysql_mbcharlen_gb2312, check_mb_gb2312},
+- { 87, 1, "gbk", "gbk_bin", "", "", 1, 2, mysql_mbcharlen_gbk, check_mb_gbk},
+- { 88, 1, "sjis", "sjis_bin", "", "", 1, 2, mysql_mbcharlen_sjis, check_mb_sjis},
+- { 89, 1, "tis620", "tis620_bin", "", "", 1, 1, NULL, NULL},
+- { 90, 1, "ucs2", "ucs2_bin", "UCS-2 Unicode", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 91, 1, "ujis", "ujis_bin", "", "", 1, 3, mysql_mbcharlen_ujis, check_mb_ujis},
+- { 94, 1, "latin1", "latin1_spanish_ci", "", "", 1, 1, NULL, NULL},
+- { 96, 1, "cp932", "cp932_bin", "", "", 1, 2, mysql_mbcharlen_cp932, check_mb_cp932},
+- { 99, 1, "cp1250", "cp1250_polish_ci", "", "", 1, 1, NULL, NULL},
+- { 98, 1, "eucjpms", "eucjpms_bin", "", "", 1, 3, mysql_mbcharlen_eucjpms, check_mb_eucjpms},
+- { 128, 1, "ucs2", "ucs2_unicode_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 129, 1, "ucs2", "ucs2_icelandic_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 130, 1, "ucs2", "ucs2_latvian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 131, 1, "ucs2", "ucs2_romanian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 132, 1, "ucs2", "ucs2_slovenian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 133, 1, "ucs2", "ucs2_polish_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 134, 1, "ucs2", "ucs2_estonian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 135, 1, "ucs2", "ucs2_spanish_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 136, 1, "ucs2", "ucs2_swedish_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 137, 1, "ucs2", "ucs2_turkish_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 138, 1, "ucs2", "ucs2_czech_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 139, 1, "ucs2", "ucs2_danish_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 140, 1, "ucs2", "ucs2_lithunian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 141, 1, "ucs2", "ucs2_slovak_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 142, 1, "ucs2", "ucs2_spanish2_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 143, 1, "ucs2", "ucs2_roman_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 144, 1, "ucs2", "ucs2_persian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 145, 1, "ucs2", "ucs2_esperanto_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 146, 1, "ucs2", "ucs2_hungarian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 147, 1, "ucs2", "ucs2_sinhala_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2},
+- { 149, 1, "ucs2", "ucs2_croatian_ci", "", "", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2}, /* MDB */
+-
+- { 192, 1, UTF8_MB3, UTF8_MB3"_general_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 193, 1, UTF8_MB3, UTF8_MB3"_icelandic_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 194, 1, UTF8_MB3, UTF8_MB3"_latvian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 195, 1, UTF8_MB3, UTF8_MB3"_romanian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 196, 1, UTF8_MB3, UTF8_MB3"_slovenian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 197, 1, UTF8_MB3, UTF8_MB3"_polish_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 198, 1, UTF8_MB3, UTF8_MB3"_estonian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 119, 1, UTF8_MB3, UTF8_MB3"_spanish_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 200, 1, UTF8_MB3, UTF8_MB3"_swedish_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 201, 1, UTF8_MB3, UTF8_MB3"_turkish_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 202, 1, UTF8_MB3, UTF8_MB3"_czech_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 203, 1, UTF8_MB3, UTF8_MB3"_danish_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid },
+- { 204, 1, UTF8_MB3, UTF8_MB3"_lithunian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid },
+- { 205, 1, UTF8_MB3, UTF8_MB3"_slovak_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 206, 1, UTF8_MB3, UTF8_MB3"_spanish2_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 207, 1, UTF8_MB3, UTF8_MB3"_roman_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 208, 1, UTF8_MB3, UTF8_MB3"_persian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 209, 1, UTF8_MB3, UTF8_MB3"_esperanto_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 210, 1, UTF8_MB3, UTF8_MB3"_hungarian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 211, 1, UTF8_MB3, UTF8_MB3"_sinhala_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid},
+- { 213, 1, UTF8_MB3, UTF8_MB3"_croatian_ci", "", "", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/
+-
+- { 224, 1, UTF8_MB4, UTF8_MB4"_unicode_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 225, 1, UTF8_MB4, UTF8_MB4"_icelandic_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 226, 1, UTF8_MB4, UTF8_MB4"_latvian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 227, 1, UTF8_MB4, UTF8_MB4"_romanian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 228, 1, UTF8_MB4, UTF8_MB4"_slovenian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 229, 1, UTF8_MB4, UTF8_MB4"_polish_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 230, 1, UTF8_MB4, UTF8_MB4"_estonian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 231, 1, UTF8_MB4, UTF8_MB4"_spanish_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 232, 1, UTF8_MB4, UTF8_MB4"_swedish_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 233, 1, UTF8_MB4, UTF8_MB4"_turkish_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 234, 1, UTF8_MB4, UTF8_MB4"_czech_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 235, 1, UTF8_MB4, UTF8_MB4"_danish_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 236, 1, UTF8_MB4, UTF8_MB4"_lithuanian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 237, 1, UTF8_MB4, UTF8_MB4"_slovak_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 238, 1, UTF8_MB4, UTF8_MB4"_spanish2_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 239, 1, UTF8_MB4, UTF8_MB4"_roman_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 240, 1, UTF8_MB4, UTF8_MB4"_persian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 241, 1, UTF8_MB4, UTF8_MB4"_esperanto_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 242, 1, UTF8_MB4, UTF8_MB4"_hungarian_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 243, 1, UTF8_MB4, UTF8_MB4"_sinhala_ci", "", "", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+-
+- { 254, 1, UTF8_MB3, UTF8_MB3"_general_cs", "", "", 1, 3, mysql_mbcharlen_utf8, check_mb_utf8_valid},
+- { 0, 0, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL}
+-};
+-/* }}} */
+-
+-
+-/* {{{ mysql_find_charset_nr */
+-const CHARSET_INFO * mysql_find_charset_nr(unsigned int charsetnr)
+-{
+- const CHARSET_INFO * c = compiled_charsets;
+- DBUG_ENTER("mysql_find_charset_nr");
+-
+- do {
+- if (c->nr == charsetnr) {
+- DBUG_PRINT("info", ("found character set %d %s", c->nr, c->csname));
+- DBUG_RETURN(c);
+- }
+- ++c;
+- } while (c[0].nr != 0);
+- DBUG_RETURN(NULL);
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_find_charset_name */
+-CHARSET_INFO * mysql_find_charset_name(const char *name)
+-{
+- CHARSET_INFO *c = (CHARSET_INFO *)compiled_charsets;
+- DBUG_ENTER("mysql_find_charset_nr");
+-
+- do {
+- if (!strcasecmp(c->csname, name)) {
+- DBUG_PRINT("info", ("found character set %d %s", c->nr, c->csname));
+- DBUG_RETURN(c);
+- }
+- ++c;
+- } while (c[0].nr != 0);
+- return NULL;
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_cset_escape_quotes */
+-size_t mysql_cset_escape_quotes(const CHARSET_INFO *cset, char *newstr,
+- const char * escapestr, size_t escapestr_len )
+-{
+- const char *newstr_s = newstr;
+- const char *newstr_e = newstr + 2 * escapestr_len;
+- const char *end = escapestr + escapestr_len;
+- my_bool escape_overflow = FALSE;
+-
+- DBUG_ENTER("mysql_cset_escape_quotes");
+-
+- for (;escapestr < end; escapestr++) {
+- unsigned int len = 0;
+- /* check unicode characters */
+-
+- if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
+-
+- /* check possible overflow */
+- if ((newstr + len) > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- /* copy mb char without escaping it */
+- while (len--) {
+- *newstr++ = *escapestr++;
+- }
+- escapestr--;
+- continue;
+- }
+- if (*escapestr == '\'') {
+- if (newstr + 2 > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- *newstr++ = '\'';
+- *newstr++ = '\'';
+- } else {
+- if (newstr + 1 > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- *newstr++ = *escapestr;
+- }
+- }
+- *newstr = '\0';
+-
+- if (escape_overflow) {
+- DBUG_RETURN((size_t)~0);
+- }
+- DBUG_RETURN((size_t)(newstr - newstr_s));
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_cset_escape_slashes */
+-size_t mysql_cset_escape_slashes(const CHARSET_INFO * cset, char *newstr,
+- const char * escapestr, size_t escapestr_len )
+-{
+- const char *newstr_s = newstr;
+- const char *newstr_e = newstr + 2 * escapestr_len;
+- const char *end = escapestr + escapestr_len;
+- my_bool escape_overflow = FALSE;
+-
+- DBUG_ENTER("mysql_cset_escape_slashes");
+- DBUG_PRINT("info", ("charset=%s", cset->name));
+-
+- for (;escapestr < end; escapestr++) {
+- char esc = '\0';
+- unsigned int len = 0;
+-
+- /* check unicode characters */
+- if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
+- /* check possible overflow */
+- if ((newstr + len) > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- /* copy mb char without escaping it */
+- while (len--) {
+- *newstr++ = *escapestr++;
+- }
+- escapestr--;
+- continue;
+- }
+- if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
+- esc = *escapestr;
+- } else {
+- switch (*escapestr) {
+- case 0:
+- esc = '0';
+- break;
+- case '\n':
+- esc = 'n';
+- break;
+- case '\r':
+- esc = 'r';
+- break;
+- case '\\':
+- case '\'':
+- case '"':
+- esc = *escapestr;
+- break;
+- case '\032':
+- esc = 'Z';
+- break;
+- }
+- }
+- if (esc) {
+- if (newstr + 2 > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- /* copy escaped character */
+- *newstr++ = '\\';
+- *newstr++ = esc;
+- } else {
+- if (newstr + 1 > newstr_e) {
+- escape_overflow = TRUE;
+- break;
+- }
+- /* copy non escaped character */
+- *newstr++ = *escapestr;
+- }
+- }
+- *newstr = '\0';
+-
+- if (escape_overflow) {
+- DBUG_RETURN((size_t)~0);
+- }
+- DBUG_RETURN((size_t)(newstr - newstr_s));
+-}
+-/* }}} */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_compress.c mariadb-native-client.trunk/libmysql/my_compress.c
+--- mariadb/libmysql/my_compress.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_compress.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,88 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
+-
+-#include <my_global.h>
+-#ifdef HAVE_COMPRESS
+-#include <my_sys.h>
+-#include <m_string.h>
+-#include <zlib.h>
+-
+-/*
+-** This replaces the packet with a compressed packet
+-** Returns 1 on error
+-** *complen is 0 if the packet wasn't compressed
+-*/
+-
+-my_bool my_compress(byte *packet, ulong *len, ulong *complen)
+-{
+- if (*len < MIN_COMPRESS_LENGTH)
+- *complen=0;
+- else
+- {
+- byte *compbuf=my_compress_alloc(packet,len,complen);
+- if (!compbuf)
+- return *complen ? 0 : 1;
+- memcpy(packet,compbuf,*len);
+- my_free(compbuf,MYF(MY_WME)); }
+- return 0;
+-}
+-
+-
+-byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
+-{
+- byte *compbuf;
+- *complen = *len * 120 / 100 + 12;
+- if (!(compbuf = (byte *) my_malloc(*complen,MYF(MY_WME))))
+- return 0; /* Not enough memory */
+- if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
+- (uLong) *len ) != Z_OK)
+- {
+- my_free(compbuf,MYF(MY_WME));
+- return 0;
+- }
+- if (*complen >= *len)
+- {
+- *complen=0;
+- my_free(compbuf,MYF(MY_WME));
+- return 0;
+- }
+- swap(ulong,*len,*complen); /* *len is now packet length */
+- return compbuf;
+-}
+-
+-
+-my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
+-{
+- if (*complen) /* If compressed */
+- {
+- byte *compbuf = (byte *) my_malloc (*complen,MYF(MY_WME));
+- if (!compbuf)
+- return 1; /* Not enough memory */
+- if (uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len) != Z_OK)
+- { /* Probably wrong packet */
+- my_free (compbuf,MYF(MY_WME));
+- return 1;
+- }
+- *len = *complen;
+- memcpy(packet,compbuf,*len);
+- my_free(compbuf,MYF(MY_WME));
+- }
+- return 0;
+-}
+-#endif /* HAVE_COMPRESS */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_create.c mariadb-native-client.trunk/libmysql/my_create.c
+--- mariadb/libmysql/my_create.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_create.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,64 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#define USES_TYPES
+-#include "mysys_priv.h"
+-#include <my_dir.h>
+-#include "mysys_err.h"
+-#include <errno.h>
+-#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
+-#include <share.h>
+-#endif
+-
+- /*
+- ** Create a new file
+- ** Arguments:
+- ** Path-name of file
+- ** Read | write on file (umask value)
+- ** Read & Write on open file
+- ** Special flags
+- */
+-
+-
+-File my_create(const char *FileName, int CreateFlags, int access_flags,
+- myf MyFlags)
+-{
+- int fd;
+- DBUG_ENTER("my_create");
+- DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
+- FileName, CreateFlags, access_flags, MyFlags));
+-
+-#if !defined(NO_OPEN_3) && !defined(__EMX__)
+- fd = open((my_string) FileName, access_flags | O_CREAT,
+- CreateFlags ? CreateFlags : my_umask);
+-#elif defined(VMS)
+- fd = open((my_string) FileName, access_flags | O_CREAT, 0,
+- "ctx=stm","ctx=bin");
+-#elif defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
+- if (access_flags & O_SHARE)
+- fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+- SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
+- else
+- fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+- MY_S_IREAD | MY_S_IWRITE);
+-#else
+- fd = open(FileName, access_flags);
+-#endif
+-
+- DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_CREATE,
+- EE_CANTCREATEFILE, MyFlags));
+-} /* my_create */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_delete.c mariadb-native-client.trunk/libmysql/my_delete.c
+--- mariadb/libmysql/my_delete.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_delete.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-
+-#include "mysys_err.h"
+-
+-int my_delete(const char *name, myf MyFlags)
+-{
+- int err;
+- DBUG_ENTER("my_delete");
+- DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
+-
+- if ((err = unlink(name)) == -1)
+- {
+- my_errno=errno;
+- if (MyFlags & (MY_FAE+MY_WME))
+- my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
+- name,errno);
+- }
+- DBUG_RETURN(err);
+-} /* my_delete */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_div.c mariadb-native-client.trunk/libmysql/my_div.c
+--- mariadb/libmysql/my_div.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_div.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,31 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-
+-my_string my_filename(File fd)
+-{
+- DBUG_ENTER("my_filename");
+- if (fd >= MY_NFILE)
+- DBUG_RETURN((char*) "UNKNOWN");
+- if (fd >= 0 && my_file_info[fd].type != UNOPEN)
+- {
+- DBUG_RETURN(my_file_info[fd].name);
+- }
+- else
+- DBUG_RETURN((char*) "UNOPENED"); /* Debug message */
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_error.c mariadb-native-client.trunk/libmysql/my_error.c
+--- mariadb/libmysql/my_error.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_error.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,124 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <m_string.h>
+-#include <stdarg.h>
+-#include <m_ctype.h>
+-
+-/* Define some external variables for error handling */
+-
+-const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0};
+-char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
+-
+-/* Error message to user */
+-/*VARARGS2*/
+-
+-int my_error(int nr,myf MyFlags, ...)
+-{
+- va_list ap;
+- uint olen, plen;
+- reg1 const char *tpos;
+- reg2 char *endpos;
+- char * par;
+- char ebuff[ERRMSGSIZE+20];
+- DBUG_ENTER("my_error");
+-
+- va_start(ap,MyFlags);
+- DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
+-
+- if (nr / ERRMOD == GLOB && my_errmsg[GLOB] == 0)
+- init_glob_errs();
+-
+- olen=(uint) strlen(tpos=my_errmsg[nr / ERRMOD][nr % ERRMOD]);
+- endpos=ebuff;
+-
+- while (*tpos)
+- {
+- if (tpos[0] != '%')
+- {
+- *endpos++= *tpos++; /* Copy ordinary char */
+- olen++;
+- continue;
+- }
+- if (*++tpos == '%') /* test if %% */
+- {
+- olen--;
+- }
+- else
+- {
+- /* Skipp if max size is used (to be compatible with printf) */
+- while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
+- tpos++;
+- if (*tpos == 'l') /* Skipp 'l' argument */
+- tpos++;
+- if (*tpos == 's') /* String parameter */
+- {
+- par = va_arg(ap, char *);
+- plen = (uint) strlen(par);
+- if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
+- {
+- endpos=strmov(endpos,par);
+- tpos++;
+- olen+=plen-2;
+- continue;
+- }
+- }
+- else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
+- {
+- register int iarg;
+- iarg = va_arg(ap, int);
+- if (*tpos == 'd')
+- plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
+- else
+- plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
+- if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
+- {
+- endpos+=plen;
+- tpos++;
+- olen+=plen-2;
+- continue;
+- }
+- }
+- }
+- *endpos++='%'; /* % used as % or unknown code */
+- }
+- *endpos='\0'; /* End of errmessage */
+- va_end(ap);
+- DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
+-}
+-
+- /* Error as printf */
+-
+-int my_printf_error (uint error, const char *format, myf MyFlags, ...)
+-{
+- va_list args;
+- char ebuff[ERRMSGSIZE+20];
+-
+- va_start(args,MyFlags);
+- (void) vsprintf (ebuff,format,args);
+- va_end(args);
+- return (*error_handler_hook)(error, ebuff, MyFlags);
+-}
+-
+- /* Give message using error_handler_hook */
+-
+-int my_message(uint error, const char *str, register myf MyFlags)
+-{
+- return (*error_handler_hook)(error, str, MyFlags);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_fopen.c mariadb-native-client.trunk/libmysql/my_fopen.c
+--- mariadb/libmysql/my_fopen.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_fopen.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,174 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "my_static.h"
+-#include <errno.h>
+-#include "mysys_err.h"
+-
+-static void make_ftype(my_string to,int flag);
+-
+- /* Open a file as stream */
+-
+-FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
+- /* Path-name of file */
+- /* Read | write .. */
+- /* Special flags */
+-{
+- FILE *fd;
+- char type[5];
+- DBUG_ENTER("my_fopen");
+- DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+- FileName, Flags, MyFlags));
+-
+- make_ftype(type,Flags);
+- if ((fd = fopen(FileName, type)) != 0)
+- {
+- /*
+- The test works if MY_NFILE < 128. The problem is that fileno() is char
+- on some OS (SUNOS). Actually the filename save isn't that important
+- so we can ignore if this doesn't work.
+- */
+- if ((uint) fileno(fd) >= MY_NFILE)
+- {
+- thread_safe_increment(my_stream_opened,&THR_LOCK_open);
+- DBUG_RETURN(fd); /* safeguard */
+- }
+- pthread_mutex_lock(&THR_LOCK_open);
+- if ((my_file_info[fileno(fd)].name = (char*)
+- my_strdup(FileName,MyFlags)))
+- {
+- my_stream_opened++;
+- my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
+- pthread_mutex_unlock(&THR_LOCK_open);
+- DBUG_PRINT("exit",("stream: %lx",fd));
+- DBUG_RETURN(fd);
+- }
+- pthread_mutex_unlock(&THR_LOCK_open);
+- (void) my_fclose(fd,MyFlags);
+- my_errno=ENOMEM;
+- }
+- else
+- my_errno=errno;
+- DBUG_PRINT("error",("Got error %d on open",my_errno));
+- if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+- my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND :
+- EE_CANTCREATEFILE,
+- MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+- DBUG_RETURN((FILE*) 0);
+-} /* my_fopen */
+-
+-
+- /* Close a stream */
+-
+-int my_fclose(FILE *fd, myf MyFlags)
+-{
+- int err,file;
+- DBUG_ENTER("my_fclose");
+- DBUG_PRINT("my",("stream: %lx MyFlags: %d",fd, MyFlags));
+-
+- pthread_mutex_lock(&THR_LOCK_open);
+- file=fileno(fd);
+- if ((err = fclose(fd)) < 0)
+- {
+- my_errno=errno;
+- if (MyFlags & (MY_FAE | MY_WME))
+- my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(file),errno);
+- }
+- else
+- my_stream_opened--;
+- if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN)
+- {
+- my_file_info[file].type = UNOPEN;
+- my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR));
+- }
+- pthread_mutex_unlock(&THR_LOCK_open);
+- DBUG_RETURN(err);
+-} /* my_fclose */
+-
+-
+- /* Make a stream out of a file handle */
+- /* Name may be 0 */
+-
+-FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
+-{
+- FILE *fd;
+- char type[5];
+- DBUG_ENTER("my_fdopen");
+- DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
+- Filedes, Flags, MyFlags));
+-
+- make_ftype(type,Flags);
+- if ((fd = fdopen(Filedes, type)) == 0)
+- {
+- my_errno=errno;
+- if (MyFlags & (MY_FAE | MY_WME))
+- my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno);
+- }
+- else
+- {
+- pthread_mutex_lock(&THR_LOCK_open);
+- my_stream_opened++;
+- if (Filedes < MY_NFILE)
+- {
+- if (my_file_info[Filedes].type != UNOPEN)
+- {
+- my_file_opened--; /* File is opened with my_open ! */
+- }
+- else
+- {
+- my_file_info[Filedes].name= my_strdup(name,MyFlags);
+- }
+- my_file_info[Filedes].type = STREAM_BY_FDOPEN;
+- }
+- pthread_mutex_unlock(&THR_LOCK_open);
+- }
+-
+- DBUG_PRINT("exit",("stream: %lx",fd));
+- DBUG_RETURN(fd);
+-} /* my_fdopen */
+-
+-
+- /* Make a filehandler-open-typestring from ordinary inputflags */
+-
+-static void make_ftype(register my_string to, register int flag)
+-{
+-#if FILE_BINARY /* If we have binary-files */
+- reg3 int org_flag=flag;
+-#endif
+- flag&= ~FILE_BINARY; /* remove binary bit */
+- if (flag == O_RDONLY)
+- *to++= 'r';
+- else if (flag == O_WRONLY)
+- *to++= 'w';
+- else
+- { /* Add '+' after theese */
+- if (flag == O_RDWR)
+- *to++= 'r';
+- else if (flag & O_APPEND)
+- *to++= 'a';
+- else
+- *to++= 'w'; /* Create file */
+- *to++= '+';
+- }
+-#if FILE_BINARY /* If we have binary-files */
+- if (org_flag & FILE_BINARY)
+- *to++='b';
+-#endif
+- *to='\0';
+-} /* make_ftype */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_fstream.c mariadb-native-client.trunk/libmysql/my_fstream.c
+--- mariadb/libmysql/my_fstream.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_fstream.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,171 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <errno.h>
+-#include <stdio.h>
+-
+-#ifdef HAVE_FSEEKO
+-#undef ftell
+-#undef fseek
+-#define ftell(A) ftello(A)
+-#define fseek(A,B,C) fseeko((A),(B),(C))
+-#endif
+-
+- /* Read a chunk of bytes from a file */
+- /* Returns (uint) -1 if error as my_read() */
+-
+-uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
+- /* File descriptor */
+- /* Buffer must be at least count bytes */
+- /* Max number of bytes returnd */
+- /* Flags on what to do on error */
+-{
+- uint readbytes;
+- DBUG_ENTER("my_fread");
+- DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+- stream, Buffer, Count, MyFlags));
+-
+- if ((readbytes = (uint) fread(Buffer,sizeof(char),(size_t) Count,stream))
+- != Count)
+- {
+- DBUG_PRINT("error",("Read only %d bytes",readbytes));
+- if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+- {
+- if (ferror(stream))
+- my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(fileno(stream)),errno);
+- else
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(fileno(stream)),errno);
+- }
+- my_errno=errno ? errno : -1;
+- if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
+- DBUG_RETURN((uint) -1); /* Return with error */
+- }
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- DBUG_RETURN(0); /* Read ok */
+- DBUG_RETURN(readbytes);
+-} /* my_fread */
+-
+-
+-/*
+-** Write a chunk of bytes to a stream
+-** Returns (uint) -1 if error as my_write()
+-** Does retries if interrupted
+-*/
+-
+-uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
+-{
+- uint writenbytes=0;
+- off_t seekptr;
+-#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+- uint errors;
+-#endif
+- DBUG_ENTER("my_fwrite");
+- DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+- stream, Buffer, Count, MyFlags));
+-
+-#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+- errors=0;
+-#endif
+- seekptr=ftell(stream);
+- for (;;)
+- {
+- uint writen;
+- if ((writen = (uint) fwrite((char*) Buffer,sizeof(char),
+- (size_t) Count, stream)) != Count)
+- {
+- DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+- my_errno=errno;
+- if (writen != (uint) -1)
+- {
+- seekptr+=writen;
+- Buffer+=writen;
+- writenbytes+=writen;
+- Count-=writen;
+- }
+-#ifdef EINTR
+- if (errno == EINTR)
+- {
+- VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+- continue;
+- }
+-#endif
+-#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+-#ifdef THREAD
+- if (my_thread_var->abort)
+- MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+-#endif
+- if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+- {
+- if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+- my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH));
+- sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
+- VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+- continue;
+- }
+-#endif
+- if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP)))
+- {
+- if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+- {
+- my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(fileno(stream)),errno);
+- }
+- writenbytes=(uint) -1; /* Return that we got error */
+- break;
+- }
+- }
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- writenbytes=0; /* Everything OK */
+- else
+- writenbytes+=writen;
+- break;
+- }
+- DBUG_RETURN(writenbytes);
+-} /* my_fwrite */
+-
+- /* Seek to position in file */
+- /* ARGSUSED */
+-
+-my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
+-{
+- DBUG_ENTER("my_fseek");
+- DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d",
+- stream, pos, whence, MyFlags));
+- DBUG_RETURN(fseek(stream, (off_t) pos, whence) ?
+- MY_FILEPOS_ERROR : (my_off_t) ftell(stream));
+-} /* my_seek */
+-
+-
+- /* Tell current position of file */
+- /* ARGSUSED */
+-
+-my_off_t my_ftell(FILE *stream, myf MyFlags)
+-{
+- off_t pos;
+- DBUG_ENTER("my_ftell");
+- DBUG_PRINT("my",("stream: %lx MyFlags: %d",stream, MyFlags));
+- pos=ftell(stream);
+- DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
+- DBUG_RETURN((my_off_t) pos);
+-} /* my_ftell */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_gethostbyname.c mariadb-native-client.trunk/libmysql/my_gethostbyname.c
+--- mariadb/libmysql/my_gethostbyname.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_gethostbyname.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,113 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Thread safe version of gethostbyname_r() */
+-
+-#include "mysys_priv.h"
+-#include <assert.h>
+-#if !defined(MSDOS) && !defined(_WIN32)
+-#include <netdb.h>
+-#endif
+-#include <my_net.h>
+-
+-/* This file is not needed if my_gethostbyname_r is a macro */
+-#if !defined(my_gethostbyname_r)
+-
+-/*
+- Emulate SOLARIS style calls, not because it's better, but just to make the
+- usage of getbostbyname_r simpler.
+-*/
+-
+-#if defined(HAVE_GETHOSTBYNAME_R)
+-
+-#if defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
+-
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop)
+-{
+- struct hostent *hp;
+- dbug_assert((size_t) buflen >= sizeof(*result));
+- if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
+- return 0;
+- return hp;
+-}
+-
+-#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT)
+-
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop)
+-{
+- dbug_assert(buflen >= sizeof(struct hostent_data));
+- if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
+- {
+- *h_errnop= errno;
+- return 0;
+- }
+- return result;
+-}
+-
+-#else
+-
+-/* gethostbyname_r with similar interface as gethostbyname() */
+-
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop)
+-{
+- struct hostent *hp;
+- dbug_assert(buflen >= sizeof(struct hostent_data));
+- hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
+- *h_errnop= errno;
+- return hp;
+-}
+-#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
+-
+-#else /* !HAVE_GETHOSTBYNAME_R */
+-
+-#ifdef THREAD
+-extern pthread_mutex_t LOCK_gethostbyname_r;
+-#endif
+-
+-/*
+- No gethostbyname_r() function exists.
+- In this case we have to keep a mutex over the call to ensure that no
+- other thread is going to reuse the internal memory.
+-
+- The user is responsible to call my_gethostbyname_r_free() when he
+- is finished with the structure.
+-*/
+-
+-struct hostent *my_gethostbyname_r(const char *name,
+- struct hostent *result, char *buffer,
+- int buflen, int *h_errnop)
+-{
+- struct hostent *hp;
+- pthread_mutex_lock(&LOCK_gethostbyname_r);
+- hp= gethostbyname(name);
+- *h_errnop= h_errno;
+- return hp;
+-}
+-
+-void my_gethostbyname_r_free()
+-{
+- pthread_mutex_unlock(&LOCK_gethostbyname_r);
+-}
+-
+-#endif /* !HAVE_GETHOSTBYNAME_R */
+-#endif /* !my_gethostbyname_r */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_getwd.c mariadb-native-client.trunk/libmysql/my_getwd.c
+--- mariadb/libmysql/my_getwd.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_getwd.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,194 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* my_setwd() and my_getwd() works with intern_filenames !! */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#include "mysys_err.h"
+-#ifdef HAVE_GETWD
+-#include <sys/param.h>
+-#endif
+-#if defined(MSDOS) || defined(_WIN32)
+-#include <m_ctype.h>
+-#include <dos.h>
+-#include <direct.h>
+-#endif
+-#if defined(OS2)
+-#include <direct.h>
+-#endif
+-
+-#ifdef __EMX__
+-// chdir2 support also drive change
+-#define chdir _chdir2
+-#endif
+-
+- /* Gets current working directory in buff. Directory is allways ended
+- with FN_LIBCHAR */
+- /* One must pass a buffer to my_getwd. One can allways use
+- curr_dir[] */
+-
+-int my_getwd(my_string buf, uint size, myf MyFlags)
+-{
+- my_string pos;
+- DBUG_ENTER("my_getwd");
+- DBUG_PRINT("my",("buf: %lx size: %d MyFlags %d", buf,size,MyFlags));
+-
+-#if ! defined(MSDOS)
+- if (curr_dir[0]) /* Current pos is saved here */
+- VOID(strmake(buf,&curr_dir[0],size-1));
+- else
+-#endif
+- {
+-#if defined(HAVE_GETCWD)
+- if (!getcwd(buf,size-2) && MyFlags & MY_WME)
+- {
+- my_errno=errno;
+- my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+- return(-1);
+- }
+-#elif defined(HAVE_GETWD)
+- {
+- char pathname[MAXPATHLEN];
+- getwd(pathname);
+- strmake(buf,pathname,size-1);
+- }
+-#elif defined(VMS)
+- if (!getcwd(buf,size-2,1) && MyFlags & MY_WME)
+- {
+- my_errno=errno;
+- my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+- return(-1);
+- }
+- intern_filename(buf,buf);
+-#else
+-#error "No way to get current directory"
+-#endif
+- if (*((pos=strend(buf))-1) != FN_LIBCHAR) /* End with FN_LIBCHAR */
+- {
+- pos[0]= FN_LIBCHAR;
+- pos[1]=0;
+- }
+- (void) strmake(&curr_dir[0],buf,(size_s) (FN_REFLEN-1));
+- }
+- DBUG_RETURN(0);
+-} /* my_getwd */
+-
+-
+- /* Set new working directory */
+-
+-int my_setwd(const char *dir, myf MyFlags)
+-{
+- int res;
+- size_s length;
+- my_string start,pos;
+-#if defined(VMS) || defined(MSDOS) || defined(OS2)
+- char buff[FN_REFLEN];
+-#endif
+- DBUG_ENTER("my_setwd");
+- DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
+-
+- start=(my_string) dir;
+-#if defined(MSDOS) || defined(OS2) /* OS2/MSDOS chdir can't change drive */
+-#if !defined(_DDL) && !defined(WIN32)
+- if ((pos=(char*) strchr(dir,FN_DEVCHAR)) != 0)
+- {
+- uint drive,drives;
+-
+- pos++; /* Skipp FN_DEVCHAR */
+- drive=(uint) (toupper(dir[0])-'A'+1); drives= (uint) -1;
+- if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
+- {
+-#ifdef OS2
+- _chdrive(drive);
+- drives = _getdrive();
+-#else
+- _dos_setdrive(drive,&drives);
+- _dos_getdrive(&drives);
+-#endif
+- }
+- if (drive != drives)
+- {
+- *pos='\0'; /* Dir is now only drive */
+- my_errno=errno;
+- my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
+- DBUG_RETURN(-1);
+- }
+- dir=pos; /* drive changed, change now path */
+- }
+-#endif
+- if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
+- {
+- strmov(buff,dir)[-1]=0; /* Remove last '/' */
+- dir=buff;
+- }
+-#endif /* MSDOS*/
+- if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
+- dir=FN_ROOTDIR;
+-#ifdef VMS
+- {
+- pos=strmov(buff,dir);
+- if (pos[-1] != FN_LIBCHAR)
+- {
+- pos[0]=FN_LIBCHAR; /* Mark as directory */
+- pos[1]=0;
+- }
+- system_filename(buff,buff); /* Change to VMS format */
+- dir=buff;
+- }
+-#endif /* VMS */
+- if ((res=chdir((char*) dir)) != 0)
+- {
+- my_errno=errno;
+- if (MyFlags & MY_WME)
+- my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),start,errno);
+- }
+- else
+- {
+- if (test_if_hard_path(start))
+- { /* Hard pathname */
+- pos=strmake(&curr_dir[0],start,(size_s) FN_REFLEN-1);
+- if (pos[-1] != FN_LIBCHAR)
+- {
+- length=(uint) (pos-(char*) curr_dir);
+- curr_dir[length]=FN_LIBCHAR; /* must end with '/' */
+- curr_dir[length+1]='\0';
+- }
+- }
+- else
+- curr_dir[0]='\0'; /* Don't save name */
+- }
+- DBUG_RETURN(res);
+-} /* my_setwd */
+-
+-
+-
+- /* Test if hard pathname */
+- /* Returns 1 if dirname is a hard path */
+-
+-int test_if_hard_path(register const char *dir_name)
+-{
+- if (dir_name[0] == FN_HOMELIB && dir_name[1] == FN_LIBCHAR)
+- return (home_dir != NullS && test_if_hard_path(home_dir));
+- if (dir_name[0] == FN_LIBCHAR)
+- return (TRUE);
+-#ifdef FN_DEVCHAR
+- return (strchr(dir_name,FN_DEVCHAR) != 0);
+-#else
+- return FALSE;
+-#endif
+-} /* test_if_hard_path */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_init.c mariadb-native-client.trunk/libmysql/my_init.c
+--- mariadb/libmysql/my_init.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_init.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,327 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "my_static.h"
+-#include "mysys_err.h"
+-#include "m_ctype.h"
+-#include <m_string.h>
+-#include <m_ctype.h>
+-#ifdef HAVE_GETRUSAGE
+-#include <sys/resource.h>
+-/* extern int getrusage(int, struct rusage *); */
+-#endif
+-#include <signal.h>
+-#ifdef VMS
+-#include <my_static.c>
+-#include <m_ctype.h>
+-#endif
+-#ifdef _WIN32
+-#ifdef _MSC_VER
+-#include <locale.h>
+-#include <crtdbg.h>
+-#endif
+-my_bool have_tcpip=0;
+-static void my_win_init(void);
+-static my_bool win32_have_tcpip(void);
+-static my_bool win32_init_tcp_ip();
+-#else
+-#define my_win_init()
+-#endif
+-
+-my_bool my_init_done=0;
+-
+-
+-
+-static ulong atoi_octal(const char *str)
+-{
+- long int tmp;
+- while (*str && isspace(*str))
+- str++;
+- str2int(str,
+- (*str == '0' ? 8 : 10), /* Octalt or decimalt */
+- 0, INT_MAX, &tmp);
+- return (ulong) tmp;
+-}
+-
+-
+- /* Init my_sys functions and my_sys variabels */
+-
+-void my_init(void)
+-{
+- my_string str;
+- if (my_init_done)
+- return;
+- my_init_done=1;
+-#ifdef THREAD
+-#if defined(HAVE_PTHREAD_INIT)
+- pthread_init(); /* Must be called before DBUG_ENTER */
+-#endif
+- my_thread_global_init();
+-#ifndef _WIN32
+- sigfillset(&my_signals); /* signals blocked by mf_brkhant */
+-#endif
+-#endif /* THREAD */
+-#ifdef UNIXWARE_7
+- (void) isatty(0); /* Go around connect() bug in UW7 */
+-#endif
+- {
+- DBUG_ENTER("my_init");
+- DBUG_PROCESS(my_progname ? my_progname : (char*) "unknown");
+- if (!home_dir)
+- { /* Don't initialize twice */
+- my_win_init();
+- if ((home_dir=getenv("HOME")) != 0)
+- home_dir=intern_filename(home_dir_buff,home_dir);
+-#ifndef VMS
+- /* Default creation of new files */
+- if ((str=getenv("UMASK")) != 0)
+- my_umask=(int) (atoi_octal(str) | 0600);
+- /* Default creation of new dir's */
+- if ((str=getenv("UMASK_DIR")) != 0)
+- my_umask_dir=(int) (atoi_octal(str) | 0700);
+-#endif
+-#ifdef VMS
+- init_ctype(); /* Stupid linker don't link _ctype.c */
+-#endif
+- DBUG_PRINT("exit",("home: '%s'",home_dir));
+- }
+-#ifdef _WIN32
+- win32_init_tcp_ip();
+-#endif
+- DBUG_VOID_RETURN;
+- }
+-} /* my_init */
+-
+-
+- /* End my_sys */
+-
+-void my_end(int infoflag)
+-{
+- FILE *info_file;
+- if (!(info_file=DBUG_FILE))
+- info_file=stderr;
+- if (infoflag & MY_CHECK_ERROR || info_file != stderr)
+- { /* Test if some file is left open */
+- if (my_file_opened | my_stream_opened)
+- {
+- sprintf(errbuff[0],EE(EE_OPEN_WARNING),my_file_opened,my_stream_opened);
+- (void) my_message_no_curses(EE_OPEN_WARNING,errbuff[0],ME_BELL);
+- DBUG_PRINT("error",("%s",errbuff[0]));
+- }
+- }
+- if (infoflag & MY_GIVE_INFO || info_file != stderr)
+- {
+-#ifdef HAVE_GETRUSAGE
+- struct rusage rus;
+- if (!getrusage(RUSAGE_SELF, &rus))
+- fprintf(info_file,"\n\
+-User time %.2f, System time %.2f\n\
+-Maximum resident set size %ld, Integral resident set size %ld\n\
+-Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
+-Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
+-Voluntary context switches %ld, Involuntary context switches %ld\n",
+- (rus.ru_utime.tv_sec * SCALE_SEC +
+- rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
+- (rus.ru_stime.tv_sec * SCALE_SEC +
+- rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
+- rus.ru_maxrss, rus.ru_idrss,
+- rus.ru_minflt, rus.ru_majflt,
+- rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
+- rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
+- rus.ru_nvcsw, rus.ru_nivcsw);
+-#endif
+-#if defined(MSDOS) && !defined(_WIN32)
+- fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
+-#endif
+-#if defined(SAFEMALLOC)
+- TERMINATE(stderr); /* Give statistic on screen */
+-#elif defined(_WIN32) && defined(_MSC_VER)
+- _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
+- _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
+- _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+- _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
+- _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
+- _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
+- _CrtCheckMemory();
+- _CrtDumpMemoryLeaks();
+-#endif
+- }
+-#ifdef THREAD
+- pthread_mutex_destroy(&THR_LOCK_keycache);
+- pthread_mutex_destroy(&THR_LOCK_malloc);
+- pthread_mutex_destroy(&THR_LOCK_open);
+- DBUG_POP(); /* Must be done before my_thread_end */
+- my_thread_end();
+- my_thread_global_end();
+-#endif
+-#ifdef _WIN32
+- if (have_tcpip);
+- WSACleanup( );
+-#endif /* _WIN32 */
+- my_init_done=0;
+-} /* my_end */
+-
+-#ifdef _WIN32
+-
+-/*
+- This code is specially for running MySQL, but it should work in
+- other cases too.
+-
+- Inizializzazione delle variabili d'ambiente per Win a 32 bit.
+-
+- Vengono inserite nelle variabili d'ambiente (utilizzando cosi'
+- le funzioni getenv e putenv) i valori presenti nelle chiavi
+- del file di registro:
+-
+- HKEY_LOCAL_MACHINE\software\MySQL
+-
+- Se la kiave non esiste nonn inserisce nessun valore
+-*/
+-
+-/* Crea la stringa d'ambiente */
+-
+-void setEnvString(char *ret, const char *name, const char *value)
+-{
+- DBUG_ENTER("setEnvString");
+- strxmov(ret, name,"=",value,NullS);
+- DBUG_VOID_RETURN ;
+-}
+-
+-static void my_win_init(void)
+-{
+- HKEY hSoftMysql ;
+- DWORD dimName = 256 ;
+- DWORD dimData = 1024 ;
+- DWORD dimNameValueBuffer = 256 ;
+- DWORD dimDataValueBuffer = 1024 ;
+- DWORD indexValue = 0 ;
+- long retCodeEnumValue ;
+- char NameValueBuffer[256] ;
+- char DataValueBuffer[1024] ;
+- char EnvString[1271] ;
+- const char *targetKey = "Software\\MySQL" ;
+- DBUG_ENTER("my_win_init");
+-
+- setlocale(LC_CTYPE, ""); /* To get right sortorder */
+-
+- /* Clear the OS system variable TZ and avoid the 100% CPU usage */
+- _putenv( "TZ=" );
+- _tzset();
+-
+- /* apre la chiave HKEY_LOCAL_MACHINES\software\MySQL */
+- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,(LPCTSTR)targetKey,0,
+- KEY_READ,&hSoftMysql) != ERROR_SUCCESS)
+- DBUG_VOID_RETURN;
+-
+- /*
+- ** Ne legge i valori e li inserisce nell'ambiente
+- ** suppone che tutti i valori letti siano di tipo stringa + '\0'
+- ** Legge il valore con indice 0 e lo scarta
+- */
+- retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+- (LPTSTR)NameValueBuffer, &dimNameValueBuffer,
+- NULL, NULL, (LPBYTE)DataValueBuffer,
+- &dimDataValueBuffer) ;
+-
+- while (retCodeEnumValue != ERROR_NO_MORE_ITEMS)
+- {
+- char *my_env;
+- /* Crea la stringa d'ambiente */
+- setEnvString(EnvString, NameValueBuffer, DataValueBuffer) ;
+-
+- /* Inserisce i dati come variabili d'ambiente */
+- my_env=strdup(EnvString); /* variable for putenv must be allocated ! */
+- putenv(my_env) ;
+-
+- dimNameValueBuffer = dimName ;
+- dimDataValueBuffer = dimData ;
+-
+- retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+- NameValueBuffer, &dimNameValueBuffer,
+- NULL, NULL, (LPBYTE)DataValueBuffer,
+- &dimDataValueBuffer) ;
+- }
+-
+- /* chiude la chiave */
+- RegCloseKey(hSoftMysql) ;
+- DBUG_VOID_RETURN ;
+-}
+-
+-
+-/*------------------------------------------------------------------
+-** Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
+-** According to Microsoft Developers documentation the first registry
+-** entry should be enough to check if TCP/IP is installed, but as expected
+-** this doesn't work on all Win32 machines :(
+-------------------------------------------------------------------*/
+-
+-#define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+-#define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
+-#define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
+-
+-static my_bool win32_have_tcpip(void)
+-{
+- HKEY hTcpipRegKey;
+- if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
+- &hTcpipRegKey) != ERROR_SUCCESS)
+- {
+- if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
+- &hTcpipRegKey) != ERROR_SUCCESS)
+- {
+- if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
+- &hTcpipRegKey) != ERROR_SUCCESS)
+- if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
+- return (FALSE);
+- }
+- }
+- RegCloseKey ( hTcpipRegKey);
+- return (TRUE);
+-}
+-
+-static my_bool win32_init_tcp_ip()
+-{
+- if (win32_have_tcpip())
+- {
+- WORD wVersionRequested = MAKEWORD( 2, 0 );
+- WSADATA wsaData;
+- /* Be a good citizen: maybe another lib has already initialised
+- sockets, so dont clobber them unless necessary */
+- if (WSAStartup( wVersionRequested, &wsaData ))
+- {
+- /* Load failed, maybe because of previously loaded
+- incompatible version; try again */
+- WSACleanup( );
+- if (!WSAStartup( wVersionRequested, &wsaData ))
+- have_tcpip=1;
+- }
+- else
+- {
+- if (wsaData.wVersion != wVersionRequested)
+- {
+- /* Version is no good, try again */
+- WSACleanup( );
+- if (!WSAStartup( wVersionRequested, &wsaData ))
+- have_tcpip=1;
+- }
+- else
+- have_tcpip=1;
+- }
+- }
+- return(0);
+-}
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_lib.c mariadb-native-client.trunk/libmysql/my_lib.c
+--- mariadb/libmysql/my_lib.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_lib.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,614 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* TODO: check for overun of memory for names. */
+-/* Convert MSDOS-TIME to standar time_t */
+-
+-#define USES_TYPES /* sys/types is included */
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
+-#include "mysys_err.h"
+-#if defined(HAVE_DIRENT_H)
+-# include <dirent.h>
+-# define NAMLEN(dirent) strlen((dirent)->d_name)
+-#else
+-#ifndef OS2
+-# define dirent direct
+-#endif
+-# define NAMLEN(dirent) (dirent)->d_namlen
+-# if defined(HAVE_SYS_NDIR_H)
+-# include <sys/ndir.h>
+-# endif
+-# if defined(HAVE_SYS_DIR_H)
+-# include <sys/dir.h>
+-# endif
+-# if defined(HAVE_NDIR_H)
+-# include <ndir.h>
+-# endif
+-# if defined(MSDOS) || defined(_WIN32)
+-# include <dos.h>
+-# ifdef __BORLANDC__
+-# include <dir.h>
+-# endif
+-# endif
+-#endif
+-#ifdef VMS
+-#include <rms.h>
+-#include <iodef.h>
+-#include <descrip.h>
+-#endif
+-
+-#ifdef OS2
+-#include "my_os2dirsrch.h"
+-#endif
+-
+-#if defined(THREAD) && defined(HAVE_READDIR_R)
+-#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
+-#else
+-#define READDIR(A,B,C) (!(C=readdir(A)))
+-#endif
+-
+-
+-#define STARTSIZE ONCE_ALLOC_INIT*8 /* some mallocmargin */
+-
+-static int comp_names(struct fileinfo *a,struct fileinfo *b);
+-
+-
+- /* We need this because program don't know with malloc we used */
+-
+-void my_dirend(MY_DIR *buffer)
+-{
+- DBUG_ENTER("my_dirend");
+- if (buffer)
+- my_free((gptr) buffer,MYF(0));
+- DBUG_VOID_RETURN;
+-} /* my_dirend */
+-
+-
+- /* Compare in sort of filenames */
+-
+-static int comp_names(struct fileinfo *a, struct fileinfo *b)
+-{
+- return (strcmp(a->name,b->name));
+-} /* comp_names */
+-
+-
+-#if !defined(MSDOS) && !defined(_WIN32)
+-
+-MY_DIR *my_dir(const char *path, myf MyFlags)
+-{
+- DIR *dirp;
+- struct dirent *dp;
+- struct fileinfo *fnames;
+- char *buffer, *obuffer, *tempptr;
+- uint fcnt,i,size,firstfcnt, maxfcnt,length;
+- char tmp_path[FN_REFLEN+1],*tmp_file;
+- my_ptrdiff_t diff;
+- bool eof;
+-#ifdef THREAD
+- char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
+-#endif
+- DBUG_ENTER("my_dir");
+- DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+-
+-#if defined(THREAD) && !defined(HAVE_READDIR_R)
+- pthread_mutex_lock(&THR_LOCK_open);
+-#endif
+-
+- dirp = opendir(directory_file_name(tmp_path,(my_string) path));
+- size = STARTSIZE;
+- if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags)))
+- goto error;
+-
+- fcnt = 0;
+- tmp_file=strend(tmp_path);
+- firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+- (sizeof(struct fileinfo) + FN_LEN);
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr = (char *) (fnames + maxfcnt);
+-
+-#ifdef THREAD
+- dp= (struct dirent*) dirent_tmp;
+-#else
+- dp=0;
+-#endif
+- eof=0;
+- for (;;)
+- {
+- while (fcnt < maxfcnt &&
+- !(eof= READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
+- {
+- bzero((gptr) (fnames+fcnt),sizeof(fnames[0])); /* for purify */
+- fnames[fcnt].name = tempptr;
+- tempptr = strmov(tempptr,dp->d_name) + 1;
+- if (MyFlags & MY_WANT_STAT)
+- {
+- (void)strmov(tmp_file,dp->d_name);
+- (void)my_stat(tmp_path, &fnames[fcnt].mystat, MyFlags);
+- }
+- ++fcnt;
+- }
+- if (eof)
+- break;
+- size += STARTSIZE; obuffer = buffer;
+- if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+- MyFlags | MY_FREE_ON_ERROR)))
+- goto error; /* No memory */
+- length= (uint) (sizeof(struct fileinfo ) * firstfcnt);
+- diff= PTR_BYTE_DIFF(buffer , obuffer) + (int) length;
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr= ADD_TO_PTR(tempptr,diff,char*);
+- for (i = 0; i < maxfcnt; i++)
+- fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+-
+- /* move filenames upp a bit */
+- maxfcnt += firstfcnt;
+- bmove_upp(tempptr,tempptr-length,
+- (uint) (tempptr- (char*) (fnames+maxfcnt)));
+- }
+-
+- (void) closedir(dirp);
+- {
+- MY_DIR * s = (MY_DIR *) buffer;
+- s->number_off_files = (uint) fcnt;
+- s->dir_entry = fnames;
+- }
+- if (!(MyFlags & MY_DONT_SORT))
+- qsort((void *) fnames, (size_s) fcnt, sizeof(struct fileinfo),
+- (qsort_cmp) comp_names);
+-#if defined(THREAD) && !defined(HAVE_READDIR_R)
+- pthread_mutex_unlock(&THR_LOCK_open);
+-#endif
+- DBUG_RETURN((MY_DIR *) buffer);
+-
+- error:
+-#if defined(THREAD) && !defined(HAVE_READDIR_R)
+- pthread_mutex_unlock(&THR_LOCK_open);
+-#endif
+- my_errno=errno;
+- if (dirp)
+- (void) closedir(dirp);
+- if (MyFlags & (MY_FAE+MY_WME))
+- my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
+- DBUG_RETURN((MY_DIR *) NULL);
+-} /* my_dir */
+-
+-
+-/*
+- * Convert from directory name to filename.
+- * On VMS:
+- * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
+- * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
+- * On UNIX, it's simple: just make sure there is a terminating /
+-
+- * Returns pointer to dst;
+- */
+-
+-my_string directory_file_name (my_string dst, const char *src)
+-{
+-#ifndef VMS
+-
+- /* Process as Unix format: just remove test the final slash. */
+-
+- my_string end;
+-
+- if (src[0] == 0)
+- src= (char*) "."; /* Use empty as current */
+- end=strmov(dst, src);
+- if (end[-1] != FN_LIBCHAR)
+- {
+- end[0]=FN_LIBCHAR; /* Add last '/' */
+- end[1]='\0';
+- }
+- return dst;
+-
+-#else /* VMS */
+-
+- long slen;
+- long rlen;
+- my_string ptr, rptr;
+- char bracket;
+- struct FAB fab = cc$rms_fab;
+- struct NAM nam = cc$rms_nam;
+- char esa[NAM$C_MAXRSS];
+-
+- if (! src[0])
+- src="[.]"; /* Empty is == current dir */
+-
+- slen = strlen (src) - 1;
+- if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
+- src[slen] == FN_DEVCHAR)
+- {
+- /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
+- fab.fab$l_fna = src;
+- fab.fab$b_fns = slen + 1;
+- fab.fab$l_nam = &nam;
+- fab.fab$l_fop = FAB$M_NAM;
+-
+- nam.nam$l_esa = esa;
+- nam.nam$b_ess = sizeof esa;
+- nam.nam$b_nop |= NAM$M_SYNCHK;
+-
+- /* We call SYS$PARSE to handle such things as [--] for us. */
+- if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
+- {
+- slen = nam.nam$b_esl - 1;
+- if (esa[slen] == ';' && esa[slen - 1] == '.')
+- slen -= 2;
+- esa[slen + 1] = '\0';
+- src = esa;
+- }
+- if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+- {
+- /* what about when we have logical_name:???? */
+- if (src[slen] == FN_DEVCHAR)
+- { /* Xlate logical name and see what we get */
+- VOID(strmov(dst,src));
+- dst[slen] = 0; /* remove colon */
+- if (!(src = getenv (dst)))
+- return dst; /* Can't translate */
+-
+- /* should we jump to the beginning of this procedure?
+- Good points: allows us to use logical names that xlate
+- to Unix names,
+- Bad points: can be a problem if we just translated to a device
+- name...
+- For now, I'll punt and always expect VMS names, and hope for
+- the best! */
+-
+- slen = strlen (src) - 1;
+- if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+- { /* no recursion here! */
+- VOID(strmov(dst, src));
+- return(dst);
+- }
+- }
+- else
+- { /* not a directory spec */
+- VOID(strmov(dst, src));
+- return(dst);
+- }
+- }
+-
+- bracket = src[slen]; /* End char */
+- if (!(ptr = strchr (src, bracket - 2)))
+- { /* no opening bracket */
+- VOID(strmov (dst, src));
+- return dst;
+- }
+- if (!(rptr = strrchr (src, '.')))
+- rptr = ptr;
+- slen = rptr - src;
+- VOID(strmake (dst, src, slen));
+-
+- if (*rptr == '.')
+- { /* Put bracket and add */
+- dst[slen++] = bracket; /* (rptr+1) after this */
+- }
+- else
+- {
+- /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
+- then translate the device and recurse. */
+-
+- if (dst[slen - 1] == ':'
+- && dst[slen - 2] != ':' /* skip decnet nodes */
+- && strcmp(src + slen, "[000000]") == 0)
+- {
+- dst[slen - 1] = '\0';
+- if ((ptr = getenv (dst))
+- && (rlen = strlen (ptr) - 1) > 0
+- && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
+- && ptr[rlen - 1] == '.')
+- {
+- VOID(strmov(esa,ptr));
+- esa[rlen - 1] = FN_C_AFTER_DIR;
+- esa[rlen] = '\0';
+- return (directory_file_name (dst, esa));
+- }
+- else
+- dst[slen - 1] = ':';
+- }
+- VOID(strmov(dst+slen,"[000000]"));
+- slen += 8;
+- }
+- VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
+- return dst;
+- }
+- VOID(strmov(dst, src));
+- if (dst[slen] == '/' && slen > 1)
+- dst[slen] = 0;
+- return dst;
+-#endif /* VMS */
+-} /* directory_file_name */
+-
+-#elif defined(_WIN32)
+-
+-/*
+-*****************************************************************************
+-** Read long filename using windows rutines
+-*****************************************************************************
+-*/
+-
+-MY_DIR *my_dir(const char *path, myf MyFlags)
+-{
+- struct fileinfo *fnames;
+- char *buffer, *obuffer, *tempptr;
+- int eof,i,fcnt,firstfcnt,length,maxfcnt;
+- uint size;
+-#ifdef __BORLANDC__
+- struct ffblk find;
+-#else
+- struct _finddata_t find;
+-#endif
+- ushort mode;
+- char tmp_path[FN_REFLEN],*tmp_file,attrib;
+- my_ptrdiff_t diff;
+-#ifdef _WIN64
+- __int64 handle;
+-#else
+- long handle;
+-#endif
+- DBUG_ENTER("my_dir");
+- DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+-
+- /* Put LIB-CHAR as last path-character if not there */
+-
+- tmp_file=tmp_path;
+- if (!*path)
+- *tmp_file++ ='.'; /* From current dir */
+- tmp_file= strmov(tmp_file,path);
+- if (tmp_file[-1] == FN_DEVCHAR)
+- *tmp_file++= '.'; /* From current dev-dir */
+- if (tmp_file[-1] != FN_LIBCHAR)
+- *tmp_file++ =FN_LIBCHAR;
+- tmp_file[0]='*'; /* MSDOS needs this !??? */
+- tmp_file[1]='.';
+- tmp_file[2]='*';
+- tmp_file[3]='\0';
+-
+-#ifdef __BORLANDC__
+- if ((handle= findfirst(tmp_path,&find,0)) == -1L)
+- goto error;
+-#else
+- if ((handle=_findfirst(tmp_path,&find)) == -1L)
+- goto error;
+-#endif
+-
+- size = STARTSIZE;
+- firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+- (sizeof(struct fileinfo) + FN_LEN);
+- if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+- goto error;
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr = (char *) (fnames + maxfcnt);
+-
+- fcnt = 0;
+- for (;;)
+- {
+- do
+- {
+- fnames[fcnt].name = tempptr;
+-#ifdef __BORLANDC__
+- tempptr = strmov(tempptr,find.ff_name) + 1;
+- fnames[fcnt].mystat.st_size=find.ff_fsize;
+- fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+- mode=MY_S_IREAD; attrib=find.ff_attrib;
+-#else
+- tempptr = strmov(tempptr,find.name) + 1;
+- fnames[fcnt].mystat.st_size=find.size;
+- fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+- mode=MY_S_IREAD; attrib=find.attrib;
+-#endif
+- if (!(attrib & _A_RDONLY))
+- mode|=MY_S_IWRITE;
+- if (attrib & _A_SUBDIR)
+- mode|=MY_S_IFDIR;
+- fnames[fcnt].mystat.st_mode=mode;
+-#ifdef __BORLANDC__
+- fnames[fcnt].mystat.st_mtime=((uint32) find.ff_ftime);
+-#else
+- fnames[fcnt].mystat.st_mtime=((uint32) find.time_write);
+-#endif
+- ++fcnt;
+-#ifdef __BORLANDC__
+- } while ((eof= findnext(&find)) == 0 && fcnt < maxfcnt);
+-#else
+- } while ((eof= _findnext(handle,&find)) == 0 && fcnt < maxfcnt);
+-#endif
+-
+- DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+- if (eof)
+- break;
+- size += STARTSIZE; obuffer = buffer;
+- if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+- MyFlags | MY_FREE_ON_ERROR)))
+- goto error;
+- length= sizeof(struct fileinfo ) * firstfcnt;
+- diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr= ADD_TO_PTR(tempptr,diff,char*);
+- for (i = 0; i < maxfcnt; i++)
+- fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+-
+- /* move filenames upp a bit */
+- maxfcnt += firstfcnt;
+- bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+- (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+- }
+- {
+- MY_DIR * s = (MY_DIR *) buffer;
+- s->number_off_files = (uint) fcnt;
+- s->dir_entry = fnames;
+- }
+- if (!(MyFlags & MY_DONT_SORT))
+- qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+-#ifndef __BORLANDC__
+- _findclose(handle);
+-#endif
+- DBUG_RETURN((MY_DIR *) buffer);
+-
+-error:
+- my_errno=errno;
+-#ifndef __BORLANDC__
+- if (handle != -1)
+- _findclose(handle);
+-#endif
+- if (MyFlags & MY_FAE+MY_WME)
+- my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+- DBUG_RETURN((MY_DIR *) NULL);
+-} /* my_dir */
+-
+-#else /* MSDOS and not WIN32 */
+-
+-
+-/******************************************************************************
+-** At MSDOS you always get stat of files, but time is in packed MSDOS-format
+-******************************************************************************/
+-
+-MY_DIR *my_dir(const char* path, myf MyFlags)
+-{
+- struct fileinfo *fnames;
+- char *buffer, *obuffer, *tempptr;
+- int eof,i,fcnt,firstfcnt,length,maxfcnt;
+- uint size;
+- struct find_t find;
+- ushort mode;
+- char tmp_path[FN_REFLEN],*tmp_file,attrib;
+- my_ptrdiff_t diff;
+- DBUG_ENTER("my_dir");
+- DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+-
+- /* Put LIB-CHAR as last path-character if not there */
+-
+- tmp_file=tmp_path;
+- if (!*path)
+- *tmp_file++ ='.'; /* From current dir */
+- tmp_file= strmov(tmp_file,path);
+- if (tmp_file[-1] == FN_DEVCHAR)
+- *tmp_file++= '.'; /* From current dev-dir */
+- if (tmp_file[-1] != FN_LIBCHAR)
+- *tmp_file++ =FN_LIBCHAR;
+- tmp_file[0]='*'; /* MSDOS needs this !??? */
+- tmp_file[1]='.';
+- tmp_file[2]='*';
+- tmp_file[3]='\0';
+-
+- if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
+- goto error;
+-
+- size = STARTSIZE;
+- firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+- (sizeof(struct fileinfo) + FN_LEN);
+- if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+- goto error;
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr = (char *) (fnames + maxfcnt);
+-
+- fcnt = 0;
+- for (;;)
+- {
+- do
+- {
+- fnames[fcnt].name = tempptr;
+- tempptr = strmov(tempptr,find.name) + 1;
+- fnames[fcnt].mystat.st_size=find.size;
+- fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+- mode=MY_S_IREAD; attrib=find.attrib;
+- if (!(attrib & _A_RDONLY))
+- mode|=MY_S_IWRITE;
+- if (attrib & _A_SUBDIR)
+- mode|=MY_S_IFDIR;
+- fnames[fcnt].mystat.st_mode=mode;
+- fnames[fcnt].mystat.st_mtime=((uint32) find.wr_date << 16) +
+- find.wr_time;
+- ++fcnt;
+- } while ((eof= _dos_findnext(&find)) == 0 && fcnt < maxfcnt);
+-
+- DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+- if (eof)
+- break;
+- size += STARTSIZE; obuffer = buffer;
+- if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+- MyFlags | MY_FREE_ON_ERROR)))
+- goto error;
+- length= sizeof(struct fileinfo ) * firstfcnt;
+- diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+- fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+- tempptr= ADD_TO_PTR(tempptr,diff,char*);
+- for (i = 0; i < maxfcnt; i++)
+- fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+-
+- /* move filenames upp a bit */
+- maxfcnt += firstfcnt;
+- bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+- (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+- }
+- {
+- MY_DIR * s = (MY_DIR *) buffer;
+- s->number_off_files = (uint) fcnt;
+- s->dir_entry = fnames;
+- }
+- if (!(MyFlags & MY_DONT_SORT))
+- qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+- DBUG_RETURN((MY_DIR *) buffer);
+-
+-error:
+- if (MyFlags & MY_FAE+MY_WME)
+- my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+- DBUG_RETURN((MY_DIR *) NULL);
+-} /* my_dir */
+-
+-#endif /* WIN32 && MSDOS */
+-
+-/****************************************************************************
+-** File status
+-** Note that MY_STAT is assumed to be same as struct stat
+-****************************************************************************/
+-
+-int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags )
+-{
+- DBUG_ENTER("my_fstat");
+- DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
+- DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
+-}
+-
+-MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
+-{
+- int m_used;
+- DBUG_ENTER("my_stat");
+- DBUG_PRINT("my", ("path: '%s', stat_area: %lx, MyFlags: %d", path,
+- (byte *) stat_area, my_flags));
+-
+- if ((m_used= (stat_area == NULL)))
+- if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
+- goto error;
+- if ( ! stat((my_string) path, (struct stat *) stat_area) )
+- DBUG_RETURN(stat_area);
+- my_errno=errno;
+- if (m_used) /* Free if new area */
+- my_free((gptr) stat_area,MYF(0));
+-
+-error:
+- if (my_flags & (MY_FAE+MY_WME))
+- {
+- my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
+- DBUG_RETURN((MY_STAT *) NULL);
+- }
+- DBUG_RETURN((MY_STAT *) NULL);
+-} /* my_stat */
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_loaddata.c mariadb-native-client.trunk/libmysql/my_loaddata.c
+--- mariadb/libmysql/my_loaddata.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_loaddata.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,255 +0,0 @@
+-/************************************************************************************
+- Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
+- Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-
+- Part of this code includes code from the PHP project which
+- is freely available from http://www.php.net
+-*************************************************************************************/
+-/*
+- +----------------------------------------------------------------------+
+- | PHP Version 5 |
+- +----------------------------------------------------------------------+
+- | Copyright (c) 2006-2011 The PHP Group |
+- +----------------------------------------------------------------------+
+- | This source file is subject to version 3.01 of the PHP license, |
+- | that is bundled with this package in the file LICENSE, and is |
+- | available through the world-wide-web at the following url: |
+- | http://www.php.net/license/3_01.txt |
+- | If you did not receive a copy of the PHP license and are unable to |
+- | obtain it through the world-wide-web, please send a note to |
+- | license@php.net so we can mail you a copy immediately. |
+- +----------------------------------------------------------------------+
+- | Authors: Georg Richter <georg@mysql.com> |
+- | Andrey Hristov <andrey@mysql.com> |
+- | Ulf Wendel <uwendel@mysql.com> |
+- +----------------------------------------------------------------------+
+-*/
+-
+-#include "my_global.h"
+-#include <my_sys.h>
+-#include <mysys_err.h>
+-#include <m_string.h>
+-#include "errmsg.h"
+-#include "mysql.h"
+-#include <string.h>
+-
+-typedef struct st_mysql_infile_info
+-{
+- int fd;
+- int error_no;
+- char error_msg[MYSQL_ERRMSG_SIZE + 1];
+- const char *filename;
+-} MYSQL_INFILE_INFO;
+-
+-/* {{{ mysql_local_infile_init */
+-static
+-int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
+-{
+- MYSQL_INFILE_INFO *info;
+-
+- DBUG_ENTER("mysql_local_infile_init");
+-
+- info = (MYSQL_INFILE_INFO *)my_malloc(sizeof(MYSQL_INFILE_INFO), MYF(MY_ZEROFILL));
+- if (!info) {
+- DBUG_RETURN(1);
+- }
+-
+- *ptr = info;
+-
+- info->filename = filename;
+- info->fd = my_open(info->filename, O_RDONLY, MYF(0));
+-
+- if (info->fd < 0)
+- {
+- my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
+- "Can't open file '%-.64s'.", filename);
+- info->error_no = EE_FILENOTFOUND;
+- DBUG_RETURN(1);
+- }
+- DBUG_RETURN(0);
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_local_infile_read */
+-static
+-int mysql_local_infile_read(void *ptr, char * buf, unsigned int buf_len)
+-{
+- MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
+- int count;
+-
+- DBUG_ENTER("mysql_local_infile_read");
+-
+- count= my_read(info->fd, buf, buf_len, MYF(0));
+-
+- if (count < 0)
+- {
+- strcpy(info->error_msg, "Error reading file");
+- info->error_no = EE_READ;
+- }
+- DBUG_RETURN(count);
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_local_infile_error */
+-static
+-int mysql_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len)
+-{
+- MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
+-
+- DBUG_ENTER("mysql_local_infile_error");
+-
+- if (info) {
+- strncpy(error_buf, info->error_msg, error_buf_len);
+- DBUG_RETURN(info->error_no);
+- }
+-
+- strncpy(error_buf, "Unknown error", error_buf_len);
+- DBUG_RETURN(CR_UNKNOWN_ERROR);
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_local_infile_end */
+-static
+-void mysql_local_infile_end(void *ptr)
+-{
+- MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
+-
+- DBUG_ENTER("mysql_local_infile_end");
+-
+- if (info)
+- {
+- if (info->fd)
+- {
+- my_close(info->fd, MYF(0));
+- info->fd= 0;
+- }
+- my_free(ptr, MYF(0));
+- }
+- DBUG_VOID_RETURN;
+-}
+-/* }}} */
+-
+-
+-/* {{{ mysql_local_infile_default */
+-void mysql_set_local_infile_default(MYSQL *conn)
+-{
+- DBUG_ENTER("mysql_local_infile_default");
+- conn->options.local_infile_init = mysql_local_infile_init;
+- conn->options.local_infile_read = mysql_local_infile_read;
+- conn->options.local_infile_error = mysql_local_infile_error;
+- conn->options.local_infile_end = mysql_local_infile_end;
+- DBUG_VOID_RETURN;
+-}
+-/* }}} */
+-
+-/* {{{ mysql_set_local_infile_handler */
+-void STDCALL mysql_set_local_infile_handler(MYSQL *conn,
+- int (*local_infile_init)(void **, const char *, void *),
+- int (*local_infile_read)(void *, char *, uint),
+- void (*local_infile_end)(void *),
+- int (*local_infile_error)(void *, char *, uint),
+- void *userdata)
+-{
+- DBUG_ENTER("mysql_set_local_infile_handler");
+- conn->options.local_infile_init= local_infile_init;
+- conn->options.local_infile_read= local_infile_read;
+- conn->options.local_infile_end= local_infile_end;
+- conn->options.local_infile_error= local_infile_error;
+- conn->options.local_infile_userdata = userdata;
+- DBUG_VOID_RETURN;
+-}
+-/* }}} */
+-
+-/* {{{ mysql_handle_local_infile */
+-my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename)
+-{
+- unsigned int buflen= 4096;
+- unsigned int bufread;
+- unsigned char *buf= NULL;
+- void *info= NULL;
+- my_bool result= 1;
+-
+- DBUG_ENTER("mysql_handle_local_infile");
+-
+- if (!(conn->options.client_flag & CLIENT_LOCAL_FILES)) {
+- my_set_error(conn, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, "Load data local infile forbidden");
+- /* write empty packet to server */
+- my_net_write(&conn->net, "", 0);
+- net_flush(&conn->net);
+- goto infile_error;
+- }
+-
+- /* check if all callback functions exist */
+- if (!conn->options.local_infile_init || !conn->options.local_infile_end ||
+- !conn->options.local_infile_read || !conn->options.local_infile_error)
+- mysql_set_local_infile_default(conn);
+-
+- /* allocate buffer for reading data */
+- buf = (uchar *)my_malloc(buflen, MYF(0));
+-
+- /* init handler: allocate read buffer and open file */
+- if (conn->options.local_infile_init(&info, filename,
+- conn->options.local_infile_userdata))
+- {
+- char tmp_buf[MYSQL_ERRMSG_SIZE];
+- int tmp_errno;
+-
+- tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
+- my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
+- my_net_write(&conn->net, "", 0);
+- net_flush(&conn->net);
+- goto infile_error;
+- }
+-
+- /* read data */
+- while ((bufread= conn->options.local_infile_read(info, (char *)buf, buflen)) > 0)
+- {
+- if (my_net_write(&conn->net, (char *)buf, bufread))
+- {
+- my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
+- goto infile_error;
+- }
+- }
+-
+- /* send empty packet for eof */
+- if (my_net_write(&conn->net, "", 0) || net_flush(&conn->net))
+- {
+- my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
+- goto infile_error;
+- }
+-
+- /* error during read occured */
+- if (bufread < 0)
+- {
+- char tmp_buf[MYSQL_ERRMSG_SIZE];
+- int tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
+- my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
+- goto infile_error;
+- }
+-
+- result = 0;
+-
+-infile_error:
+- conn->options.local_infile_end(info);
+- my_free((char *)buf, MYF(0));
+- DBUG_RETURN(result);
+-}
+-/* }}} */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_malloc.c mariadb-native-client.trunk/libmysql/my_malloc.c
+--- mariadb/libmysql/my_malloc.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_malloc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,96 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+-#undef SAFEMALLOC
+-#endif
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <m_string.h>
+-
+- /* My memory allocator */
+-
+-gptr my_malloc(size_t Size, myf MyFlags)
+-{
+- gptr point;
+- DBUG_ENTER("my_malloc");
+- DBUG_PRINT("my",("Size: %u MyFlags: %d",Size, MyFlags));
+-
+- if (!Size)
+- Size=1; /* Safety */
+- if ((point = (char*)malloc(Size)) == NULL)
+- {
+- my_errno=errno;
+- if (MyFlags & MY_FAE)
+- error_handler_hook=fatal_error_handler_hook;
+- if (MyFlags & (MY_FAE+MY_WME))
+- my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+- if (MyFlags & MY_FAE)
+- exit(1);
+- }
+- else if (MyFlags & MY_ZEROFILL)
+- bzero(point,Size);
+- DBUG_PRINT("exit",("ptr: %lx",point));
+- DBUG_RETURN(point);
+-} /* my_malloc */
+-
+-
+- /* Free memory allocated with my_malloc */
+- /*ARGSUSED*/
+-
+-void my_no_flags_free(gptr ptr)
+-{
+- DBUG_ENTER("my_free");
+- DBUG_PRINT("my",("ptr: %lx",ptr));
+- if (ptr)
+- free(ptr);
+- DBUG_VOID_RETURN;
+-} /* my_free */
+-
+-
+- /* malloc and copy */
+-
+-gptr my_memdup(const byte *from, size_t length, myf MyFlags)
+-{
+- gptr ptr;
+- if ((ptr=my_malloc(length,MyFlags)) != 0)
+- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+- return(ptr);
+-}
+-
+-
+-my_string my_strdup(const char *from, myf MyFlags)
+-{
+- gptr ptr;
+- uint length=(uint) strlen(from)+1;
+- if ((ptr=my_malloc(length,MyFlags)) != 0)
+- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+- return((my_string) ptr);
+-}
+-
+-my_string my_strndup(const char *src, size_t length, myf MyFlags)
+-{
+- gptr ptr;
+-
+- if ((ptr= my_malloc(length+1, MyFlags))) {
+- memcpy(ptr, src, length);
+- ptr[length] = 0;
+- }
+- return ptr;
+-}
+-/* }}} */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_messnc.c mariadb-native-client.trunk/libmysql/my_messnc.c
+--- mariadb/libmysql/my_messnc.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_messnc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-
+-int my_message_no_curses(uint error __attribute__((unused)),
+- const char *str, myf MyFlags)
+-{
+- DBUG_ENTER("my_message_no_curses");
+- DBUG_PRINT("enter",("message: %s",str));
+- (void) fflush(stdout);
+- if (MyFlags & ME_BELL)
+- (void) fputc('\007',stderr); /* Bell */
+- if (my_progname)
+- {
+- (void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
+- }
+- (void)fputs(str,stderr);
+- (void)fputc('\n',stderr);
+- (void)fflush(stderr);
+- DBUG_RETURN(0);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_net.c mariadb-native-client.trunk/libmysql/my_net.c
+--- mariadb/libmysql/my_net.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_net.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,44 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* thread safe version of some common functions */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+-/* for thread safe my_inet_ntoa */
+-#if !defined(MSDOS) && !defined(_WIN32)
+-#include <netdb.h>
+-#ifdef HAVE_SYS_SOCKET_H
+-#include <sys/socket.h>
+-#endif
+-#ifdef HAVE_NETINET_IN_H
+-#include <netinet/in.h>
+-#endif
+-#ifdef HAVE_ARPA_INET_H
+-#include <arpa/inet.h>
+-#endif
+-#endif /* !defined(MSDOS) && !defined(_WIN32) */
+-
+-void my_inet_ntoa(struct in_addr in, char *buf)
+-{
+- char *ptr;
+- pthread_mutex_lock(&THR_LOCK_net);
+- ptr=inet_ntoa(in);
+- strmov(buf,ptr);
+- pthread_mutex_unlock(&THR_LOCK_net);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_once.c mariadb-native-client.trunk/libmysql/my_once.c
+--- mariadb/libmysql/my_once.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_once.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,88 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Not MT-SAFE */
+-
+-#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+-#undef SAFEMALLOC
+-#endif
+-
+-#include "mysys_priv.h"
+-#include "my_static.h"
+-#include "mysys_err.h"
+-
+- /* alloc for things we don't nead to free */
+- /* No DBUG_ENTER... here to get smaller dbug-startup */
+-
+-gptr my_once_alloc(unsigned int Size, myf MyFlags)
+-{
+- size_t get_size,max_left;
+- gptr point;
+- reg1 USED_MEM *next;
+- reg2 USED_MEM **prev;
+-
+- Size= ALIGN_SIZE(Size);
+- prev= &my_once_root_block;
+- max_left=0;
+- for (next=my_once_root_block ; next && next->left < Size ; next= next->next)
+- {
+- if (next->left > max_left)
+- max_left=next->left;
+- prev= &next->next;
+- }
+- if (! next)
+- { /* Time to alloc new block */
+- get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+- if (max_left*4 < my_once_extra && get_size < my_once_extra)
+- get_size=my_once_extra; /* Normal alloc */
+-
+- if ((next = (USED_MEM*) malloc(get_size)) == 0)
+- {
+- my_errno=errno;
+- if (MyFlags & (MY_FAE+MY_WME))
+- my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
+- return((gptr) 0);
+- }
+- DBUG_PRINT("test",("my_once_malloc %u byte malloced",get_size));
+- next->next= 0;
+- next->size= get_size;
+- next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+- *prev=next;
+- }
+- point= (gptr) ((char*) next+ (next->size-next->left));
+- next->left-= Size;
+-
+- return(point);
+-} /* my_once_alloc */
+-
+-
+- /* deallocate everything used by my_once_alloc */
+-
+-void my_once_free(void)
+-{
+- reg1 USED_MEM *next,*old;
+- DBUG_ENTER("my_once_free");
+-
+- for (next=my_once_root_block ; next ; )
+- {
+- old=next; next= next->next ;
+- free((gptr) old);
+- }
+- my_once_root_block=0;
+-
+- DBUG_VOID_RETURN;
+-} /* my_once_free */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_open.c mariadb-native-client.trunk/libmysql/my_open.c
+--- mariadb/libmysql/my_open.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_open.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,126 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#define USES_TYPES
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <my_dir.h>
+-#include <errno.h>
+-#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
+-#include <share.h>
+-#endif
+-
+- /* Open a file */
+-
+-File my_open(const char *FileName, int Flags, myf MyFlags)
+- /* Path-name of file */
+- /* Read | write .. */
+- /* Special flags */
+-{
+- File fd;
+- DBUG_ENTER("my_open");
+- DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+- FileName, Flags, MyFlags));
+-#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
+- if (Flags & O_SHARE)
+- fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
+- MY_S_IREAD | MY_S_IWRITE);
+- else
+- fd = open((my_string) FileName, Flags | O_BINARY,
+- MY_S_IREAD | MY_S_IWRITE);
+-#elif !defined(NO_OPEN_3)
+- fd = open(FileName, Flags, my_umask); /* Normal unix */
+-#else
+- fd = open((my_string) FileName, Flags);
+-#endif
+- DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_OPEN,
+- EE_FILENOTFOUND, MyFlags));
+-} /* my_open */
+-
+-
+- /* Close a file */
+-
+-int my_close(File fd, myf MyFlags)
+-{
+- int err;
+- DBUG_ENTER("my_close");
+- DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
+-
+- pthread_mutex_lock(&THR_LOCK_open);
+- if ((err = close(fd)))
+- {
+- DBUG_PRINT("error",("Got error %d on close",err));
+- my_errno=errno;
+- if (MyFlags & (MY_FAE | MY_WME))
+- my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
+- }
+- if ((uint) fd < MY_NFILE && my_file_info[fd].type != UNOPEN)
+- {
+- my_free(my_file_info[fd].name, MYF(0));
+-#if defined(THREAD) && !defined(HAVE_PREAD)
+- pthread_mutex_destroy(&my_file_info[fd].mutex);
+-#endif
+- my_file_info[fd].type = UNOPEN;
+- }
+- my_file_opened--;
+- pthread_mutex_unlock(&THR_LOCK_open);
+- DBUG_RETURN(err);
+-} /* my_close */
+-
+-
+-File my_register_filename(File fd, const char *FileName, enum file_type
+- type_of_file, uint error_message_number, myf MyFlags)
+-{
+- if ((int) fd >= 0)
+- {
+- if ((int) fd >= MY_NFILE)
+- {
+-#if defined(THREAD) && !defined(HAVE_PREAD)
+- (void) my_close(fd,MyFlags);
+- my_errno=EMFILE;
+- if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+- my_error(EE_OUT_OF_FILERESOURCES, MYF(ME_BELL+ME_WAITTANG),
+- FileName, my_errno);
+- return(-1);
+-#endif
+- thread_safe_increment(my_file_opened,&THR_LOCK_open);
+- return(fd); /* safeguard */
+- }
+- pthread_mutex_lock(&THR_LOCK_open);
+- if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+- {
+- my_file_opened++;
+- my_file_info[fd].type = type_of_file;
+-#if defined(THREAD) && !defined(HAVE_PREAD)
+- pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
+-#endif
+- pthread_mutex_unlock(&THR_LOCK_open);
+- DBUG_PRINT("exit",("fd: %d",fd));
+- return(fd);
+- }
+- pthread_mutex_unlock(&THR_LOCK_open);
+- (void) my_close(fd, MyFlags);
+- my_errno=ENOMEM;
+- }
+- else
+- my_errno=errno;
+- DBUG_PRINT("error",("Got error %d on open",my_errno));
+- if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+- my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
+- FileName, my_errno);
+- return(fd);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_port.c mariadb-native-client.trunk/libmysql/my_port.c
+--- mariadb/libmysql/my_port.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_port.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,40 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Small functions to make code portable
+-*/
+-
+-#include "mysys_priv.h"
+-
+-#ifdef _AIX
+-
+-/*
+- On AIX, at least with gcc 3.1, the expression
+- '(double) (ulonglong) var' doesn't always work for big unsigned
+- integers like '18446744073709551615'. The end result is that the
+- high bit is simply dropped. (probably bug in gcc optimizations)
+- Handling the conversion in a sub function seems to work.
+-*/
+-
+-
+-
+-double my_ulonglong2double(unsigned long long nr)
+-{
+- return (double) nr;
+-}
+-#endif /* _AIX */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_pthread.c mariadb-native-client.trunk/libmysql/my_pthread.c
+--- mariadb/libmysql/my_pthread.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_pthread.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,554 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Functions to get threads more portable */
+-
+-#define DONT_REMAP_PTHREAD_FUNCTIONS
+-
+-#include "mysys_priv.h"
+-#ifdef THREAD
+-#include <signal.h>
+-#include <m_string.h>
+-#include <thr_alarm.h>
+-#include <assert.h>
+-
+-#ifdef _WIN32
+-
+-int
+-pthread_cond_init (pthread_cond_t *cv, const pthread_condattr_t *attr)
+-{
+- DBUG_ENTER("pthread_cond_init");
+- /* Initialize the count to 0 */
+- cv->waiting = 0;
+-
+- /* Create an auto-reset and manual-reset event */
+- if (!(cv->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL)) ||
+- !(cv->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL)))
+- {
+- DBUG_RETURN(GetLastError());
+- }
+- DBUG_RETURN(0);
+-}
+-
+-int pthread_cond_timedwait(pthread_cond_t *cond,
+- pthread_mutex_t *mutex,
+- struct timespec *abstime)
+-{
+- int result= 0;
+- return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
+-}
+-
+-int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
+-{
+- return pthread_cond_timedwait(cv,mutex,NULL);
+-}
+-
+-int pthread_cond_destroy(pthread_cond_t *cv)
+-{
+- DeleteCriticalSection(&cv->waiters_count_lock);
+-
+- if (CloseHandle(cv->events[SIGNAL]) == 0 ||
+- CloseHandle(cv->events[BROADCAST]) == 0)
+- return EINVAL;
+- return 0;
+-}
+-
+-#endif
+-
+-#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
+-#define SCHED_POLICY SCHED_RR
+-#else
+-#define SCHED_POLICY SCHED_OTHER
+-#endif
+-
+-#ifndef my_pthread_setprio
+-void my_pthread_setprio(pthread_t thread_id,int prior)
+-{
+-#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+- struct sched_param tmp_sched_param;
+- bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+- tmp_sched_param.sched_priority=prior;
+- VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
+-#endif
+-}
+-#endif
+-
+-#ifndef my_pthread_getprio
+-int my_pthread_getprio(pthread_t thread_id)
+-{
+-#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+- struct sched_param tmp_sched_param;
+- int policy;
+- if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
+- {
+- DBUG_PRINT("thread",("policy: %d priority: %d",
+- policy,tmp_sched_param.sched_priority));
+- return tmp_sched_param.sched_priority;
+- }
+-#endif
+- return -1;
+-}
+-#endif
+-
+-#ifndef my_pthread_attr_setprio
+-void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
+-{
+-#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+- struct sched_param tmp_sched_param;
+- bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+- tmp_sched_param.sched_priority=priority;
+- VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
+-#endif
+-}
+-#endif
+-
+-
+-/* To allow use of pthread_getspecific with two arguments */
+-
+-#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
+-#undef pthread_getspecific
+-#ifdef HAVE_UNIXWARE7_THREADS
+-#define pthread_getspecific thr_getspecific
+-#endif
+-
+-void *my_pthread_getspecific_imp(pthread_key_t key)
+-{
+- void *value;
+- if (pthread_getspecific(key,(void *) &value))
+- return 0;
+- return value;
+-}
+-#endif
+-
+-
+-/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
+- (and DEC OSF/1 3.2 too) */
+-
+-int my_pthread_create_detached=1;
+-
+-#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
+-
+-int my_sigwait(const sigset_t *set,int *sig)
+-{
+- int signal=sigwait((sigset_t*) set);
+- if (signal < 0)
+- return errno;
+- *sig=signal;
+- return 0;
+-}
+-#endif
+-
+-/* localtime_r for SCO 3.2V4.2 */
+-
+-#ifndef HAVE_LOCALTIME_R
+-
+-extern pthread_mutex_t LOCK_localtime_r;
+-
+-struct tm *localtime_r(const time_t *clock, struct tm *res)
+-{
+- struct tm *tmp;
+- pthread_mutex_lock(&LOCK_localtime_r);
+- tmp=localtime(clock);
+- *res= *tmp;
+- pthread_mutex_unlock(&LOCK_localtime_r);
+- return res;
+-}
+-#endif
+-
+-
+-/****************************************************************************
+-** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+-**
+-** Note:
+-** This version of sigwait() is assumed to called in a loop so the signalmask
+-** is permanently modified to reflect the signal set. This is done to get
+-** a much faster implementation.
+-**
+-** This implementation isn't thread safe: It assumes that only one
+-** thread is using sigwait.
+-**
+-** If one later supplies a different signal mask, all old signals that
+-** was used before are unblocked and set to SIGDFL.
+-**
+-** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
+-****************************************************************************/
+-
+-#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(_WIN32) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(OS2)
+-
+-#if !defined(DONT_USE_SIGSUSPEND)
+-
+-static sigset_t sigwait_set,rev_sigwait_set,px_recd;
+-
+-void px_handle_sig(int sig)
+-{
+- sigaddset(&px_recd, sig);
+-}
+-
+-
+-void sigwait_setup(sigset_t *set)
+-{
+- int i;
+- struct sigaction sact,sact1;
+- sigset_t unblock_mask;
+-
+- sact.sa_flags = 0;
+- sact.sa_handler = px_handle_sig;
+- memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+- sigemptyset(&unblock_mask);
+- pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
+-
+- for (i = 1; i <= sizeof(sigwait_set)*8; i++)
+- {
+- if (sigismember(set,i))
+- {
+- sigdelset(&rev_sigwait_set,i);
+- if (!sigismember(&sigwait_set,i))
+- sigaction(i, &sact, (struct sigaction*) 0);
+- }
+- else
+- {
+- sigdelset(&px_recd,i); /* Don't handle this */
+- if (sigismember(&sigwait_set,i))
+- { /* Remove the old handler */
+- sigaddset(&unblock_mask,i);
+- sigdelset(&rev_sigwait_set,i);
+- sact1.sa_flags = 0;
+- sact1.sa_handler = SIG_DFL;
+- sigemptyset(&sact1.sa_mask);
+- sigaction(i, &sact1, 0);
+- }
+- }
+- }
+- memcpy_fixed(&sigwait_set,set,sizeof(*set));
+- pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
+- pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
+-}
+-
+-
+-int sigwait(sigset_t *setp, int *sigp)
+-{
+- if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
+- sigwait_setup(setp); /* Init or change of set */
+-
+- for (;;)
+- {
+- /*
+- This is a fast, not 100% portable implementation to find the signal.
+- Because the handler is blocked there should be at most 1 bit set, but
+- the specification on this is somewhat shady so we use a set instead a
+- single variable.
+- */
+-
+- ulong *ptr= (ulong*) &px_recd;
+- ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
+-
+- for ( ; ptr != end ; ptr++)
+- {
+- if (*ptr)
+- {
+- ulong set= *ptr;
+- int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
+- while (!(set & 1))
+- {
+- found++;
+- set>>=1;
+- }
+- *sigp=found;
+- sigdelset(&px_recd,found);
+- return 0;
+- }
+- }
+- sigsuspend(&rev_sigwait_set);
+- }
+- return 0;
+-}
+-#else /* !DONT_USE_SIGSUSPEND */
+-
+-/****************************************************************************
+-** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+-**
+-** Note:
+-** This version of sigwait() is assumed to called in a loop so the signalmask
+-** is permanently modified to reflect the signal set. This is done to get
+-** a much faster implementation.
+-**
+-** This implementation uses a extra thread to handle the signals and one
+-** must always call sigwait() with the same signal mask!
+-**
+-** BSDI 3.0 NOTE:
+-**
+-** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
+-** After adding the sleep to sigwait_thread, all signals are checked and
+-** delivered every second. This isn't that terrible performance vice, but
+-** someone should report this to BSDI and ask for a fix!
+-** Another problem is that when the sleep() ends, every select() in other
+-** threads are interrupted!
+-****************************************************************************/
+-
+-static sigset_t pending_set;
+-static bool inited=0;
+-static pthread_cond_t COND_sigwait;
+-static pthread_mutex_t LOCK_sigwait;
+-
+-
+-void sigwait_handle_sig(int sig)
+-{
+- pthread_mutex_lock(&LOCK_sigwait);
+- sigaddset(&pending_set, sig);
+- VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
+- pthread_mutex_unlock(&LOCK_sigwait);
+-}
+-
+-extern pthread_t alarm_thread;
+-
+-void *sigwait_thread(void *set_arg)
+-{
+- sigset_t *set=(sigset_t*) set_arg;
+-
+- int i;
+- struct sigaction sact;
+- sact.sa_flags = 0;
+- sact.sa_handler = sigwait_handle_sig;
+- memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+- sigemptyset(&pending_set);
+-
+- for (i = 1; i <= sizeof(pending_set)*8; i++)
+- {
+- if (sigismember(set,i))
+- {
+- sigaction(i, &sact, (struct sigaction*) 0);
+- }
+- }
+- sigaddset(set,THR_CLIENT_ALARM);
+- pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
+- alarm_thread=pthread_self(); /* For thr_alarm */
+-
+- for (;;)
+- { /* Wait for signals */
+-#ifdef HAVE_NOT_BROKEN_SELECT
+- fd_set fd;
+- FD_ZERO(&fd);
+- select(0,&fd,0,0,0);
+-#else
+- sleep(1); /* Because of broken BSDI */
+-#endif
+- }
+-}
+-
+-
+-int sigwait(sigset_t *setp, int *sigp)
+-{
+- if (!inited)
+- {
+- pthread_attr_t thr_attr;
+- pthread_t sigwait_thread_id;
+- inited=1;
+- sigemptyset(&pending_set);
+- pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST);
+- pthread_cond_init(&COND_sigwait,NULL);
+-
+- pthread_attr_init(&thr_attr);
+- pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+- pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+- pthread_attr_setstacksize(&thr_attr,8196);
+- my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+- VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
+- VOID(pthread_attr_destroy(&thr_attr));
+- }
+-
+- pthread_mutex_lock(&LOCK_sigwait);
+- for (;;)
+- {
+- ulong *ptr= (ulong*) &pending_set;
+- ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
+-
+- for ( ; ptr != end ; ptr++)
+- {
+- if (*ptr)
+- {
+- ulong set= *ptr;
+- int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
+- while (!(set & 1))
+- {
+- found++;
+- set>>=1;
+- }
+- *sigp=found;
+- sigdelset(&pending_set,found);
+- pthread_mutex_unlock(&LOCK_sigwait);
+- return 0;
+- }
+- }
+- VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
+- }
+- return 0;
+-}
+-
+-#endif /* DONT_USE_SIGSUSPEND */
+-#endif /* HAVE_SIGWAIT */
+-
+-/*****************************************************************************
+-** Implement pthread_signal for systems that can't use signal() with threads
+-** Currently this is only used with BSDI 3.0
+-*****************************************************************************/
+-
+-#ifdef USE_PTHREAD_SIGNAL
+-
+-int pthread_signal(int sig, void (*func)())
+-{
+- struct sigaction sact;
+- sact.sa_flags= 0;
+- sact.sa_handler= func;
+- sigemptyset(&sact.sa_mask);
+- sigaction(sig, &sact, (struct sigaction*) 0);
+- return 0;
+-}
+-#endif
+-
+-/****************************************************************************
+- The following functions fixes that all pthread functions should work
+- according to latest posix standard
+-****************************************************************************/
+-
+-/* Undefined wrappers set my_pthread.h so that we call os functions */
+-#undef pthread_mutex_init
+-#undef pthread_mutex_lock
+-#undef pthread_mutex_unlock
+-#undef pthread_mutex_destroy
+-#undef pthread_mutex_wait
+-#undef pthread_mutex_timedwait
+-#undef pthread_mutex_trylock
+-#undef pthread_mutex_t
+-#undef pthread_cond_init
+-#undef pthread_cond_wait
+-#undef pthread_cond_timedwait
+-#undef pthread_cond_t
+-
+-
+-/*****************************************************************************
+-** Patches for AIX and DEC OSF/1 3.2
+-*****************************************************************************/
+-
+-#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
+-
+-#include <netdb.h>
+-
+-int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
+-{
+- int error;
+- if (!attr)
+- error=pthread_mutex_init(mp,pthread_mutexattr_default);
+- else
+- error=pthread_mutex_init(mp,*attr);
+- return error;
+-}
+-
+-int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
+-{
+- int error;
+- if (!attr)
+- error=pthread_cond_init(mp,pthread_condattr_default);
+- else
+- error=pthread_cond_init(mp,*attr);
+- return error;
+-}
+-
+-#endif
+-
+-
+-/*****************************************************************************
+- Patches for HPUX
+- We need these because the pthread_mutex.. code returns -1 on error,
+- instead of the error code.
+-
+- Note that currently we only remap pthread_ functions used by MySQL.
+- If we are depending on the value for some other pthread_xxx functions,
+- this has to be added here.
+-****************************************************************************/
+-
+-#if defined(HPUX) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT)
+-
+-int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+- struct timespec *abstime)
+-{
+- int error=pthread_cond_timedwait(cond, mutex, abstime);
+- if (error == -1) /* Safety if the lib is fixed */
+- {
+- if (!(error=errno))
+- error= ETIMEDOUT; /* Can happen on HPUX */
+- }
+- if (error == EAGAIN) /* Correct errno to Posix */
+- error= ETIMEDOUT;
+- return error;
+-}
+-#endif
+-
+-
+-#ifdef HAVE_POSIX1003_4a_MUTEX
+-/*
+- In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations
+- pthread_mutex_trylock returns 1 on success, not 0 like
+- pthread_mutex_lock
+-
+- From the HP-UX-10.20 man page:
+- RETURN VALUES
+- If the function fails, errno may be set to one of the following
+- values:
+- Return | Error | Description
+- _______|__________|_________________________________________
+- 1 | | Successful completion.
+- 0 | | The mutex is locked; therefore, it was
+- | | not acquired.
+- -1 | [EINVAL] | The value specified by mutex is invalid.
+-
+-*/
+-
+-/*
+- Convert pthread_mutex_trylock to return values according to latest POSIX
+-
+- RETURN VALUES
+- 0 If we are able successfully lock the mutex.
+- EBUSY Mutex was locked by another thread
+- # Other error number returned by pthread_mutex_trylock()
+- (Not likely)
+-*/
+-
+-int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
+-{
+- int error= pthread_mutex_trylock(mutex);
+- if (error == 1)
+- return 0; /* Got lock on mutex */
+- if (error == 0) /* Someon else is locking mutex */
+- return EBUSY;
+- if (error == -1) /* Safety if the lib is fixed */
+- error= errno; /* Probably invalid parameter */
+- return error;
+-}
+-#endif /* HAVE_POSIX1003_4a_MUTEX */
+-
+-/* Some help functions */
+-
+-int pthread_no_free(void *not_used __attribute__((unused)))
+-{
+- return 0;
+-}
+-
+-int pthread_dummy(int ret)
+-{
+- return ret;
+-}
+-#endif /* THREAD */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_read.c mariadb-native-client.trunk/libmysql/my_read.c
+--- mariadb/libmysql/my_read.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_read.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,66 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <errno.h>
+-
+-
+- /* Read a chunk of bytes from a file */
+-
+-uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
+- /* File descriptor */
+- /* Buffer must be at least count bytes */
+- /* Max number of bytes returnd */
+- /* Flags on what to do on error */
+-{
+- uint readbytes;
+- DBUG_ENTER("my_read");
+- DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+- Filedes, Buffer, Count, MyFlags));
+-
+- for (;;)
+- {
+- errno=0; /* Linux doesn't reset this */
+- if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+- {
+- my_errno=errno ? errno : -1;
+- DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
+- readbytes,Count,Filedes,my_errno));
+-#ifdef THREAD
+- if (readbytes == 0 && errno == EINTR)
+- continue; /* Interrupted */
+-#endif
+- if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+- {
+- if ((int) readbytes == -1)
+- my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(Filedes),my_errno);
+- else if (MyFlags & (MY_NABP | MY_FNABP))
+- my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(Filedes),my_errno);
+- }
+- if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+- DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+- }
+-
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- readbytes=0; /* Ok on read */
+- break;
+- }
+- DBUG_RETURN(readbytes);
+-} /* my_read */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_realloc.c mariadb-native-client.trunk/libmysql/my_realloc.c
+--- mariadb/libmysql/my_realloc.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_realloc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,65 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+-#undef SAFEMALLOC
+-#endif
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-
+- /* My memory re allocator */
+-
+-gptr my_realloc(gptr oldpoint, size_t Size, myf MyFlags)
+-{
+- gptr point;
+- DBUG_ENTER("my_realloc");
+- DBUG_PRINT("my",("ptr: %lx Size: %u MyFlags: %d",oldpoint, Size, MyFlags));
+-
+- if (!oldpoint && (MyFlags & MY_ALLOW_ZERO_PTR))
+- DBUG_RETURN(my_malloc(Size,MyFlags));
+-#ifdef USE_HALLOC
+- if (!(point = malloc(Size)))
+- {
+- if (MyFlags & MY_FREE_ON_ERROR)
+- my_free(oldpoint,MyFlags);
+- if (MyFlags & MY_HOLD_ON_ERROR)
+- DBUG_RETURN(oldpoint);
+- my_errno=errno;
+- if (MyFlags & MY_FAE+MY_WME)
+- my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+- }
+- else
+- {
+- memcpy(point,oldpoint,Size);
+- free(oldpoint);
+- }
+-#else
+- if ((point = (char*)realloc(oldpoint,Size)) == NULL)
+- {
+- if (MyFlags & MY_FREE_ON_ERROR)
+- my_free(oldpoint,MyFLAGS);
+- if (MyFlags & MY_HOLD_ON_ERROR)
+- DBUG_RETURN(oldpoint);
+- my_errno=errno;
+- if (MyFlags & (MY_FAE+MY_WME))
+- my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), Size);
+- }
+-#endif
+- DBUG_PRINT("exit",("ptr: %lx",point));
+- DBUG_RETURN(point);
+-} /* my_realloc */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_secure.c mariadb-native-client.trunk/libmysql/my_secure.c
+--- mariadb/libmysql/my_secure.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_secure.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,425 +0,0 @@
+-/************************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-
+- *************************************************************************************/
+-#ifdef HAVE_OPENSSL
+-
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <my_secure.h>
+-#include <errmsg.h>
+-#include <violite.h>
+-
+-static my_bool my_ssl_initialized= FALSE;
+-static SSL_CTX *SSL_context= NULL;
+-
+-#define MAX_SSL_ERR_LEN 100
+-
+-#ifdef THREAD
+-extern pthread_mutex_t LOCK_ssl_config;
+-static pthread_mutex_t *LOCK_crypto;
+-#endif
+-
+-/*
+- SSL error handling
+-*/
+-static void my_SSL_error(MYSQL *mysql)
+-{
+- ulong ssl_errno= ERR_get_error();
+- char ssl_error[MAX_SSL_ERR_LEN];
+- const char *ssl_error_reason;
+-
+- DBUG_ENTER("my_SSL_error");
+-
+- if (!ssl_errno)
+- {
+- my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "No SSL error");
+- DBUG_VOID_RETURN;
+- }
+- if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
+- {
+- my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error_reason);
+- DBUG_VOID_RETURN;
+- }
+- my_snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno, mysql->charset);
+- my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error);
+- DBUG_VOID_RETURN;
+-}
+-
+-#ifdef THREAD
+-/*
+- thread safe callbacks for OpenSSL
+- Crypto call back functions will be
+- set during ssl_initialization
+- */
+-static unsigned long my_cb_threadid(void)
+-{
+- /* chast pthread_t to unsigned long */
+- return (unsigned long) pthread_self();
+-}
+-
+-static void
+-my_cb_locking(int mode, int n, const char *file, int line)
+-{
+- if (mode & CRYPTO_LOCK)
+- pthread_mutex_lock(&LOCK_crypto[n]);
+- else
+- pthread_mutex_unlock(&LOCK_crypto[n]);
+-}
+-#endif
+-
+-/*
+- Initializes SSL and allocate global
+- context SSL_context
+-
+- SYNOPSIS
+- my_ssl_start
+- mysql connection handle
+-
+- RETURN VALUES
+- 0 success
+- 1 error
+-*/
+-int my_ssl_start(MYSQL *mysql)
+-{
+- int rc= 0;
+- DBUG_ENTER("my_ssl_start");
+-#ifdef THREAD
+- /* lock mutex to prevent multiple initialization */
+- pthread_mutex_lock(&LOCK_ssl_config);
+-#endif
+-
+- if (!my_ssl_initialized)
+- {
+-#ifdef THREAD
+- if (!(LOCK_crypto=
+- (pthread_mutex_t *)my_malloc(sizeof(pthread_mutex_t) *
+- CRYPTO_num_locks(), MYF(0))))
+- {
+- rc= 1;
+- goto end;
+- } else
+- {
+- int i;
+-
+- for (i=0; i < CRYPTO_num_locks(); i++)
+- pthread_mutex_init(&LOCK_crypto[i], NULL);
+- CRYPTO_set_id_callback(my_cb_threadid);
+- CRYPTO_set_locking_callback(my_cb_locking);
+- }
+-#endif
+-#if SSLEAY_VERSION_NUMBER >= 0x00907000L
+- OPENSSL_config(NULL);
+-#endif
+-
+- /* always returns 1, so we can discard return code */
+- SSL_library_init();
+- /* load errors */
+- SSL_load_error_strings();
+- /* digests and ciphers */
+- OpenSSL_add_all_algorithms();
+-
+- if (!(SSL_context= SSL_CTX_new(TLSv1_client_method())))
+- {
+- my_SSL_error(mysql);
+- rc= 1;
+- goto end;
+- }
+- my_ssl_initialized= TRUE;
+- }
+-end:
+-#ifdef THREAD
+- pthread_mutex_unlock(&LOCK_ssl_config);
+-#endif
+- DBUG_RETURN(rc);
+-}
+-
+-/*
+- Release SSL and free resources
+- Will be automatically executed by
+- mysql_server_end() function
+-
+- SYNOPSIS
+- my_ssl_end()
+- void
+-
+- RETURN VALUES
+- void
+-*/
+-void my_ssl_end()
+-{
+- DBUG_ENTER("my_ssl_end");
+-#ifdef THREAD
+- pthread_mutex_lock(&LOCK_ssl_config);
+-#endif
+- if (my_ssl_initialized)
+- {
+-#ifdef THREAD
+- int i;
+- CRYPTO_set_locking_callback(NULL);
+- CRYPTO_set_id_callback(NULL);
+-
+- for (i=0; i < CRYPTO_num_locks(); i++)
+- pthread_mutex_destroy(&LOCK_crypto[i]);
+-
+- my_free((gptr)LOCK_crypto, MYF(0));
+-#endif
+- if (SSL_context)
+- {
+- SSL_CTX_free(SSL_context);
+- SSL_context= FALSE;
+- }
+- ERR_free_strings();
+- EVP_cleanup();
+- CONF_modules_unload(1);
+- CRYPTO_cleanup_all_ex_data();
+- my_ssl_initialized= FALSE;
+- }
+-#ifdef THREAD
+- pthread_mutex_unlock(&LOCK_ssl_config);
+-#endif
+- DBUG_VOID_RETURN;
+-}
+-
+-#ifdef THREAD
+-#endif
+-
+-/*
+- Set certification stuff.
+-*/
+-static int my_ssl_set_certs(SSL *ssl)
+-{
+- int have_cert= 0;
+- MYSQL *mysql;
+-
+- DBUG_ENTER("my_ssl_connect");
+-
+- /* Make sure that ssl was allocated and
+- ssl_system was initialized */
+- DBUG_ASSERT(ssl != NULL);
+- DBUG_ASSERT(my_ssl_initialized == TRUE);
+-
+- /* get connection for current ssl */
+- mysql= (MYSQL *)SSL_get_app_data(ssl);
+-
+- /* add cipher */
+- if ((mysql->options.ssl_cipher &&
+- mysql->options.ssl_cipher[0] != 0) &&
+- SSL_set_cipher_list(ssl, mysql->options.ssl_cipher) == 0)
+- goto error;
+-
+- /* set cert */
+- if (mysql->options.ssl_cert && mysql->options.ssl_cert[0] != 0)
+- {
+- if ((SSL_CTX_use_certificate_chain_file(SSL_context, mysql->options.ssl_cert) != 1) &&
+- (SSL_use_certificate_file(ssl, mysql->options.ssl_cert, SSL_FILETYPE_PEM) != 1))
+- goto error;
+- have_cert= 1;
+- }
+-
+- /* set key */
+- if (mysql->options.ssl_key && mysql->options.ssl_key[0])
+- {
+- if (SSL_use_PrivateKey_file(ssl, mysql->options.ssl_key, SSL_FILETYPE_PEM) != 1)
+- goto error;
+-
+- /* verify key */
+- if (have_cert && SSL_check_private_key(ssl) != 1)
+- goto error;
+- }
+- /* ca_file and ca_path */
+- if (SSL_CTX_load_verify_locations(SSL_context,
+- mysql->options.ssl_ca,
+- mysql->options.ssl_capath) == 0)
+- {
+- if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
+- goto error;
+- }
+- DBUG_RETURN(0);
+-
+-error:
+- my_SSL_error(mysql);
+- DBUG_RETURN(1);
+-}
+-
+-static int my_verify_callback(int ok, X509_STORE_CTX *ctx)
+-{
+- /* since we don't have access to the mysql structure, we just return */
+- return ok;
+-}
+-
+-/*
+- allocates a new ssl object
+-
+- SYNOPSIS
+- my_ssl_init
+- mysql connection object
+-
+- RETURN VALUES
+- NULL on error
+- SSL new SSL object
+-*/
+-SSL *my_ssl_init(MYSQL *mysql)
+-{
+- int verify;
+- SSL *ssl= NULL;
+-
+- DBUG_ENTER("my_get_ssl");
+-
+- DBUG_ASSERT(mysql->net.vio->ssl == NULL);
+-
+- if (!my_ssl_initialized)
+- my_ssl_start(mysql);
+-
+- if (!(ssl= SSL_new(SSL_context)))
+- goto error;
+-
+- if (!SSL_set_app_data(ssl, mysql))
+- goto error;
+-
+- if (my_ssl_set_certs(ssl))
+- goto error;
+-
+- verify= (!mysql->options.ssl_ca && !mysql->options.ssl_capath) ?
+- SSL_VERIFY_NONE : SSL_VERIFY_PEER;
+- SSL_set_verify(ssl, verify, my_verify_callback);
+-
+- DBUG_RETURN(ssl);
+-error:
+- if (ssl)
+- SSL_free(ssl);
+- DBUG_RETURN(NULL);
+-}
+-
+-/*
+- establish SSL connection between client
+- and server
+-
+- SYNOPSIS
+- my_ssl_connect
+- ssl ssl object
+-
+- RETURN VALUES
+- 0 success
+- 1 error
+-*/
+-int my_ssl_connect(SSL *ssl)
+-{
+- my_bool blocking;
+- MYSQL *mysql;
+-
+- DBUG_ENTER("my_ssl_connect");
+-
+- DBUG_ASSERT(ssl != NULL);
+-
+- mysql= (MYSQL *)SSL_get_app_data(ssl);
+-
+- /* Set socket to blocking if not already set */
+- if (!(blocking= vio_is_blocking(mysql->net.vio)))
+- vio_blocking(mysql->net.vio, TRUE);
+-
+- SSL_clear(ssl);
+- SSL_SESSION_set_timeout(SSL_get_session(ssl),
+- mysql->options.connect_timeout);
+- SSL_set_fd(ssl, mysql->net.vio->sd);
+-
+- if (SSL_connect(ssl) != 1)
+- {
+- my_SSL_error(mysql);
+- /* restore blocking mode */
+- if (!blocking)
+- vio_blocking(mysql->net.vio, FALSE);
+- DBUG_RETURN(1);
+- }
+-
+- vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0);
+- mysql->net.vio->ssl= ssl;
+- DBUG_RETURN(0);
+-}
+-
+-/*
+- write to ssl socket
+-
+- SYNOPSIS
+- my_ssl_write()
+- vio vio
+- buf write buffer
+- size size of buffer
+-
+- RETURN VALUES
+- bytes written
+-*/
+-size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size)
+-{
+- size_t written;
+- DBUG_ENTER("my_ssl_write");
+-
+- written= SSL_write((SSL*) vio->ssl, buf, size);
+- DBUG_RETURN(written);
+-}
+-
+-/*
+- read from ssl socket
+-
+- SYNOPSIS
+- my_ssl_read()
+- vio vio
+- buf read buffer
+- size_t max number of bytes to read
+-
+- RETURN VALUES
+- number of bytes read
+-*/
+-size_t my_ssl_read(Vio *vio, uchar* buf, size_t size)
+-{
+- size_t read;
+- DBUG_ENTER("my_ssl_read");
+-
+- read= SSL_read((SSL*) vio->ssl, buf, size);
+- DBUG_RETURN(read);
+-}
+-
+-/*
+- close ssl connection and free
+- ssl object
+-
+- SYNOPSIS
+- my_ssl_close()
+- vio vio
+-
+- RETURN VALUES
+- 1 ok
+- 0 or -1 on error
+-*/
+-int my_ssl_close(Vio *vio)
+-{
+- int i, rc;
+- DBUG_ENTER("my_ssl_close");
+-
+- /* 2 x pending + 2 * data = 4 */
+- for (i=0; i < 4; i++)
+- if ((rc= SSL_shutdown(vio->ssl)))
+- break;
+-
+- SSL_free(vio->ssl);
+- vio->ssl= NULL;
+-
+- return rc;
+-}
+-
+-#endif /* HAVE_OPENSSL */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_seek.c mariadb-native-client.trunk/libmysql/my_seek.c
+--- mariadb/libmysql/my_seek.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_seek.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,58 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-
+- /* Seek to position in file */
+- /*ARGSUSED*/
+-
+-my_off_t my_seek(File fd, my_off_t pos, int whence,
+- myf MyFlags __attribute__((unused)))
+-{
+- reg1 os_off_t newpos;
+- DBUG_ENTER("my_seek");
+- DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
+- fd, ((ulonglong) pos) >> 32, (ulong) pos, whence, MyFlags));
+- newpos=lseek(fd, pos, whence);
+- if (newpos == (os_off_t) -1)
+- {
+- my_errno=errno;
+- DBUG_PRINT("error",("lseek: %lu, errno: %d",newpos,errno));
+- DBUG_RETURN(MY_FILEPOS_ERROR);
+- }
+- DBUG_RETURN((my_off_t) newpos);
+-} /* my_seek */
+-
+-
+- /* Tell current position of file */
+- /* ARGSUSED */
+-
+-my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
+-{
+- os_off_t pos;
+- DBUG_ENTER("my_tell");
+- DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
+-#ifdef HAVE_TELL
+- pos=tell(fd);
+-#else
+- pos=lseek(fd, 0L, MY_SEEK_CUR);
+-#endif
+- if (pos == (os_off_t) -1)
+- my_errno=errno;
+- DBUG_PRINT("exit",("pos: %lu",pos));
+- DBUG_RETURN((my_off_t) pos);
+-} /* my_tell */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mysql_io.c mariadb-native-client.trunk/libmysql/mysql_io.c
+--- mariadb/libmysql/mysql_io.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/mysql_io.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,415 +0,0 @@
-/*
- +----------------------------------------------------------------------+
@@ -5147,69 +49617,8042 @@
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */
-
-=== renamed directory 'mysql_config' => 'mariadb_config'
-=== modified file 'mariadb_config/CMakeLists.txt'
---- mariadb/mysql_config/CMakeLists.txt 2012-11-28 22:13:00 +0000
-+++ mariadb/mariadb_config/CMakeLists.txt 2013-03-14 21:01:43 +0000
-@@ -2,8 +2,8 @@
-
- # Figure out additional libraries for use with
-
--FOREACH (dep ${libmysql_LIB_DEPENDS})
-- STRING(REGEX MATCH "^-.*$" out "${dep}")
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_static.c mariadb-native-client.trunk/libmysql/my_static.c
+--- mariadb/libmysql/my_static.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_static.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,101 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Static variables for mysys library. All definied here for easy making of
+- a shared library
+-*/
+-
+-#if !defined(stdin) || defined(OS2)
+-#include "mysys_priv.h"
+-#include "my_static.h"
+-#include "my_alarm.h"
+-#endif
+-
+- /* from my_init */
+-my_string home_dir=0,my_progname=0;
+-char NEAR curr_dir[FN_REFLEN]= {0},
+- NEAR home_dir_buff[FN_REFLEN]= {0};
+-ulong my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
+-int NEAR my_umask=0664, NEAR my_umask_dir=0777;
+-#ifndef THREAD
+-int NEAR my_errno=0;
+-#endif
+-struct my_file_info my_file_info[MY_NFILE]= {{0,UNOPEN}};
+-
+- /* From mf_brkhant */
+-int NEAR my_dont_interrupt=0;
+-volatile int _my_signals=0;
+-struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
+-#ifdef THREAD
+-sigset_t my_signals; /* signals blocked by mf_brkhant */
+-#endif
+-
+- /* from mf_keycache.c */
+-my_bool key_cache_inited=0;
+-
+- /* from mf_reccache.c */
+-ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
+-
+- /* from soundex.c */
+- /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
+- /* :::::::::::::::::::::::::: */
+-const char *soundex_map= "01230120022455012623010202";
+-
+- /* from my_malloc */
+-USED_MEM* my_once_root_block=0; /* pointer to first block */
+-uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
+-
+- /* from my_tempnam */
+-#if !defined(HAVE_TEMPNAM) || defined(HPUX11)
+-int _my_tempnam_used=0;
+-#endif
+-
+- /* from safe_malloc */
+-uint sf_malloc_prehunc=0, /* If you have problem with core- */
+- sf_malloc_endhunc=0, /* dump when malloc-message.... */
+- /* set theese to 64 or 128 */
+- sf_malloc_quick=0; /* set if no calls to sanity */
+-size_t lCurMemory = 0L; /* Current memory usage */
+-size_t lMaxMemory = 0L; /* Maximum memory usage */
+-uint cNewCount = 0; /* Number of times NEW() was called */
+-byte *sf_min_adress= (byte*) ~(unsigned long) 0L,
+- *sf_max_adress= (byte*) 0L;
+-
+-/* Root of the linked list of remembers */
+-struct remember *pRememberRoot = NULL;
+-
+- /* from my_alarm */
+-int volatile my_have_got_alarm=0; /* declare variable to reset */
+-ulong my_time_to_wait_for_lock=2; /* In seconds */
+-
+- /* from errors.c */
+-#ifdef SHARED_LIBRARY
+-char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
+-#endif
+-void (*my_abort_hook)(int) = (void(*)(int)) exit;
+-int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
+- my_message_no_curses;
+-int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
+- my_message_no_curses;
+-
+- /* How to disable options */
+-my_bool NEAR my_disable_locking=0;
+-my_bool NEAR my_disable_async_io=0;
+-my_bool NEAR my_disable_flush_key_blocks=0;
+-my_bool NEAR my_disable_symlinks=0;
+-my_bool NEAR mysys_uses_curses=0;
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_static.h mariadb-native-client.trunk/libmysql/my_static.h
+--- mariadb/libmysql/my_static.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_static.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,70 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Static variables for mysys library. All definied here for easy making of
+- a shared library
+-*/
+-
+-#include "mysys_priv.h"
+-#include <signal.h>
+-
+-#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
+-#define MIN_KEYBLOCK (min(IO_SIZE,1024))
+-#define MAX_KEYBLOCK 8192 /* Max keyblocklength == 8*IO_SIZE */
+-#define MAX_BLOCK_TYPES MAX_KEYBLOCK/MIN_KEYBLOCK
+-
+-struct st_remember {
+- int number;
+- sig_handler (*func)(int number);
+-};
+-
+-struct irem {
+- struct remember *_pNext; /* Linked list of structures */
+- struct remember *_pPrev; /* Other link */
+- my_string _sFileName; /* File in which memory was new'ed */
+- uint _uLineNum; /* Line number in above file */
+- uint _uDataSize; /* Size requested */
+- long _lSpecialValue; /* Underrun marker value */
+-};
+-
+-struct remember {
+- struct irem tInt;
+- char aData[1];
+-};
+-
+-extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN];
+-
+-extern volatile int _my_signals;
+-extern struct st_remember _my_sig_remember[MAX_SIGNALS];
+-
+-extern const char *soundex_map;
+-
+-extern USED_MEM* my_once_root_block;
+-extern uint my_once_extra;
+-
+-#if !defined(HAVE_TEMPNAM) || defined(HPUX11)
+-extern int _my_tempnam_used;
+-#endif
+-
+-extern byte *sf_min_adress,*sf_max_adress;
+-extern uint cNewCount;
+-extern struct remember *pRememberRoot;
+-
+-#if defined(THREAD) && !defined(__WIN__)
+-extern sigset_t my_signals; /* signals blocked by mf_brkhant */
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_stmt.c mariadb-native-client.trunk/libmysql/my_stmt.c
+--- mariadb/libmysql/my_stmt.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_stmt.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1567 +0,0 @@
+-/****************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-*****************************************************************************/
+-
+-/* The implementation for prepared statements was ported from PHP's mysqlnd
+- extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
+-
+- Original file header:
+- +----------------------------------------------------------------------+
+- | PHP Version 5 |
+- +----------------------------------------------------------------------+
+- | Copyright (c) 2006-2011 The PHP Group |
+- +----------------------------------------------------------------------+
+- | This source file is subject to version 3.01 of the PHP license, |
+- | that is bundled with this package in the file LICENSE, and is |
+- | available through the world-wide-web at the following url: |
+- | http://www.php.net/license/3_01.txt |
+- | If you did not receive a copy of the PHP license and are unable to |
+- | obtain it through the world-wide-web, please send a note to |
+- | license@php.net so we can mail you a copy immediately. |
+- +----------------------------------------------------------------------+
+- | Authors: Georg Richter <georg@mysql.com> |
+- | Andrey Hristov <andrey@mysql.com> |
+- | Ulf Wendel <uwendel@mysql.com> |
+- +----------------------------------------------------------------------+
+-*/
+-
+-#include "my_global.h"
+-#include <my_sys.h>
+-#include <mysys_err.h>
+-#include <m_string.h>
+-#include <m_ctype.h>
+-#include "mysql.h"
+-#include "mysql_priv.h"
+-#include "mysql_version.h"
+-#include "mysqld_error.h"
+-#include "errmsg.h"
+-#include <violite.h>
+-#include <sys/stat.h>
+-#include <signal.h>
+-#include <time.h>
+-
+-static my_bool is_not_null= 0;
+-static my_bool is_null= 1;
+-
+-const char * const mysql_stmt_not_prepared = "Statement not prepared";
+-
+-my_bool is_supported_buffer_type(enum enum_field_types type)
+-{
+- switch (type) {
+- case MYSQL_TYPE_BIT:
+- case MYSQL_TYPE_BLOB:
+- case MYSQL_TYPE_DATE:
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_DECIMAL:
+- case MYSQL_TYPE_DOUBLE:
+- case MYSQL_TYPE_FLOAT:
+- case MYSQL_TYPE_GEOMETRY:
+- case MYSQL_TYPE_INT24:
+- case MYSQL_TYPE_LONG:
+- case MYSQL_TYPE_LONG_BLOB:
+- case MYSQL_TYPE_LONGLONG:
+- case MYSQL_TYPE_MEDIUM_BLOB:
+- case MYSQL_TYPE_NEWDATE:
+- case MYSQL_TYPE_NEWDECIMAL:
+- case MYSQL_TYPE_NULL:
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_STRING:
+- case MYSQL_TYPE_TIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- case MYSQL_TYPE_TINY:
+- case MYSQL_TYPE_TINY_BLOB:
+- case MYSQL_TYPE_VAR_STRING:
+- case MYSQL_TYPE_YEAR:
+- return 1;
+- break;
+- default:
+- return 0;
+- break;
+-
+- }
+-}
+-
+-static int stmt_unbuffered_eof(MYSQL_STMT *stmt, uchar **row)
+-{
+- return MYSQL_NO_DATA;
+-}
+-
+-static int stmt_unbuffered_fetch(MYSQL_STMT *stmt, uchar **row)
+-{
+- ulong pkt_len;
+-
+- DBUG_ENTER("stmt_unbuffered_fetch");
+-
+- pkt_len= net_safe_read(stmt->mysql);
+- DBUG_PRINT("info",("packet_length= %ld",pkt_len));
+-
+- if (pkt_len == packet_error)
+- {
+- stmt->fetch_row_func= stmt_unbuffered_eof;
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->mysql->net.read_pos[0] == 254)
+- {
+- *row = NULL;
+- stmt->fetch_row_func= stmt_unbuffered_eof;
+- DBUG_RETURN(MYSQL_NO_DATA);
+- }
+- else
+- *row = stmt->mysql->net.read_pos;
+- DBUG_RETURN(0);
+-}
+-
+-static int stmt_buffered_fetch(MYSQL_STMT *stmt, uchar **row)
+-{
+- if (!stmt->result_cursor)
+- {
+- *row= NULL;
+- stmt->state= MYSQL_STMT_FETCH_DONE;
+- return MYSQL_NO_DATA;
+- }
+- stmt->state= MYSQL_STMT_USER_FETCHING;
+- *row= (uchar *)stmt->result_cursor->data;
+-
+- stmt->result_cursor= stmt->result_cursor->next;
+- return 0;
+-}
+-
+-static int stmt_read_all_rows(MYSQL_STMT *stmt)
+-{
+- MYSQL_DATA *result= &stmt->result;
+- MYSQL_ROWS *current, **pprevious;
+- ulong packet_len;
+- unsigned char *p;
+-
+- DBUG_ENTER("stmt_read_all_rows");
+-
+- pprevious= &result->data;
+-
+- while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
+- {
+- p= stmt->mysql->net.read_pos;
+- if (packet_len > 7 || p[0] != 254)
+- {
+- /* allocate space for rows */
+- if (!(current= (MYSQL_ROWS *)alloc_root(&result->alloc, sizeof(MYSQL_ROWS) + packet_len)))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+- current->data= (MYSQL_ROW)(current + 1);
+- *pprevious= current;
+- pprevious= &current->next;
+-
+- /* copy binary row, we will encode it during mysql_stmt_fetch */
+- memcpy((char *)current->data, (char *)p, packet_len);
+-
+- if (stmt->update_max_length)
+- {
+- uchar *null_ptr, bit_offset= 4;
+- uchar *cp= p;
+- uint i;
+-
+- cp++; /* skip first byte */
+- null_ptr= cp;
+- cp+= (stmt->field_count + 9) / 8;
+-
+- for (i=0; i < stmt->field_count; i++)
+- {
+- if (!(*null_ptr & bit_offset))
+- {
+- switch(mysql_ps_fetch_functions[stmt->fields[i].type].max_len) {
+- case -1:
+- {
+- size_t len= net_field_length(&cp);
+- cp+= len;
+- if (len > stmt->fields[i].max_length)
+- stmt->fields[i].max_length= (ulong)len;
+- }
+- break;
+- default:
+- if (!stmt->fields[i].max_length)
+- stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len;
+- cp+= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len;
+- break;
+- }
+- }
+- if (!((bit_offset <<=1) & 255))
+- {
+- bit_offset= 1; /* To next byte */
+- null_ptr++;
+- }
+- }
+- }
+-
+-
+- current->length= packet_len;
+- result->rows++;
+- } else /* end of stream */
+- {
+- *pprevious= 0;
+- /* sace status info */
+- p++;
+- stmt->upsert_status.warning_count= stmt->mysql->warning_count= uint2korr(p);
+- p+=2;
+- stmt->mysql->server_status= uint2korr(p);
+- stmt->result_cursor= result->data;
+- DBUG_RETURN(0);
+- }
+- }
+- stmt->result_cursor= 0;
+- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
+- stmt->mysql->net.last_error);
+- DBUG_RETURN(1);
+-}
+-
+-static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
+-{
+- uchar buf[STMT_ID_LENGTH + 4];
+- MYSQL_DATA *result= &stmt->result;
+-
+- DBUG_ENTER("stmt_cursor_fetch");
+-
+- if (stmt->state < MYSQL_STMT_USE_OR_STORE_CALLED)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- /* do we have some prefetched rows available ? */
+- if (stmt->result_cursor)
+- DBUG_RETURN(stmt_buffered_fetch(stmt, row));
+-
+- int4store(buf, stmt->stmt_id);
+- int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
+-
+- if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, (char *)buf, sizeof(buf), 1))
+- DBUG_RETURN(1);
+-
+- /* free previously allocated buffer */
+- free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
+- result->data= 0;
+- result->rows= 0;
+-
+- if (stmt_read_all_rows(stmt))
+- DBUG_RETURN(1);
+-
+- DBUG_RETURN(stmt_buffered_fetch(stmt, row));
+-}
+-
+-static void stmt_flush_unbuffered(MYSQL_STMT *stmt)
+-{
+- ulong packet_len;
+- while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
+- if (packet_len < 8 && stmt->mysql->net.read_pos[0] == 254)
+- return;
+-}
+-
+-static int stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
+-{
+- uint i;
+- size_t truncations= 0;
+- unsigned char *null_ptr, bit_offset= 4;
+-
+- DBUG_ENTER("stmt_fetch_to_bind");
+-
+- if (!stmt->bind_result_done) /* nothing to do */
+- DBUG_RETURN(0);
+-
+- row++; /* skip status byte */
+- null_ptr= row;
+- row+= (stmt->field_count + 9) / 8;
+-
+- for (i=0; i < stmt->field_count; i++)
+- {
+- /* save row position for fetching values in pieces */
+- if (*null_ptr & bit_offset)
+- {
+- *stmt->bind[i].is_null= 1;
+- stmt->bind[i].row_ptr= NULL;
+- } else
+- {
+- if (!stmt->bind[i].length)
+- stmt->bind[i].length= &stmt->bind[i].length_value;
+- if (!stmt->bind[i].is_null)
+- stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
+- *stmt->bind[i].is_null= 0;
+- stmt->bind[i].row_ptr= row;
+- mysql_ps_fetch_functions[stmt->fields[i].type].func(&stmt->bind[i], &stmt->fields[i], &row);
+- if (stmt->mysql->options.report_data_truncation)
+- truncations+= *stmt->bind[i].error;
+- }
+-
+- if (!((bit_offset <<=1) & 255)) {
+- bit_offset= 1; /* To next byte */
+- null_ptr++;
+- }
+- }
+- DBUG_RETURN((truncations) ? MYSQL_DATA_TRUNCATED : 0);
+-}
+-
+-MYSQL_RES *_mysql_stmt_use_result(MYSQL_STMT *stmt)
+-{
+- MYSQL *mysql= stmt->mysql;
+-
+- DBUG_ENTER("mysql_stmt_use_result");
+-
+- if (!stmt->field_count ||
+- (!stmt->cursor_exists && mysql->status != MYSQL_STATUS_GET_RESULT) ||
+- (stmt->cursor_exists && mysql->status != MYSQL_STATUS_READY) ||
+- (stmt->state != MYSQL_STMT_WAITING_USE_OR_STORE))
+- {
+- SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(NULL);
+- }
+-
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+-
+- stmt->state = MYSQL_STMT_USE_OR_STORE_CALLED;
+- if (!stmt->cursor_exists)
+- stmt->fetch_row_func= stmt_unbuffered_fetch; //mysql_stmt_fetch_unbuffered_row;
+- else
+- stmt->fetch_row_func= stmt_cursor_fetch;
+-
+- DBUG_RETURN(NULL);
+-}
+-
+-unsigned char *mysql_net_store_length(unsigned char *packet, my_ulonglong length)
+-{
+- if (length < (my_ulonglong) L64(251)) {
+- *packet = (unsigned char) length;
+- return packet + 1;
+- }
+-
+- if (length < (my_ulonglong) L64(65536)) {
+- *packet++ = 252;
+- int2store(packet,(uint) length);
+- return packet + 2;
+- }
+-
+- if (length < (my_ulonglong) L64(16777216)) {
+- *packet++ = 253;
+- int3store(packet,(ulong) length);
+- return packet + 3;
+- }
+- *packet++ = 254;
+- int8store(packet, length);
+- return packet + 8;
+-}
+-
+-int store_param(MYSQL_STMT *stmt, int column, unsigned char **p)
+-{
+- DBUG_ENTER("store_param");
+- DBUG_PRINT("info", ("column: %d type: x%x", column, stmt->params[column].buffer_type));
+- switch (stmt->params[column].buffer_type) {
+- case MYSQL_TYPE_TINY:
+- int1store(*p, *(uchar *)stmt->params[column].buffer);
+- (*p) += 1;
+- break;
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_YEAR:
+- int2store(*p, *(short *)stmt->params[column].buffer);
+- (*p) += 2;
+- break;
+- case MYSQL_TYPE_FLOAT:
+- float4store(*p, *(float *)stmt->params[column].buffer);
+- (*p) += 4;
+- break;
+- case MYSQL_TYPE_DOUBLE:
+- float8store(*p, *(double *)stmt->params[column].buffer);
+- (*p) += 8;
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- int8store(*p, *(my_ulonglong *)stmt->params[column].buffer);
+- (*p) += 8;
+- break;
+- case MYSQL_TYPE_LONG:
+- case MYSQL_TYPE_INT24:
+- int4store(*p, *(int32 *)stmt->params[column].buffer);
+- (*p) += 4;
+- break;
+- case MYSQL_TYPE_TIME:
+- {
+- /* binary encoding:
+- Offset Length Field
+- 0 1 Length
+- 1 1 negative
+- 2-5 4 day
+- 6 1 hour
+- 7 1 ninute
+- 8 1 second;
+- 9-13 4 second_part
+- */
+- MYSQL_TIME *t= (MYSQL_TIME *)stmt->params[column].buffer;
+- char t_buffer[14];
+- uint len= *stmt->params[column].length;
+-
+- t_buffer[0]= len;
+- t_buffer[1]= t->neg ? 1 : 0;
+- int4store(t_buffer + 2, t->day);
+- t_buffer[6]= (uchar) t->hour;
+- t_buffer[7]= (uchar) t->minute;
+- t_buffer[8]= (uchar) t->second;
+- int4store(t_buffer + 9, t->second_part);
+- memcpy(*p, t_buffer, len);
+- len++;
+- (*p)+= len;
+- }
+- break;
+- case MYSQL_TYPE_DATE:
+- case MYSQL_TYPE_TIMESTAMP:
+- case MYSQL_TYPE_DATETIME:
+- {
+- /* binary format for date, timestamp and datetime
+- Offset Length Field
+- 0 1 Length
+- 1-2 2 Year
+- 3 1 Month
+- 4 1 Day
+- 5 1 Hour
+- 6 1 minute
+- 7 1 second
+- 8-11 4 secondpart
+- */
+- MYSQL_TIME *t= (MYSQL_TIME *)stmt->params[column].buffer;
+- char t_buffer[12];
+- uint len= *stmt->params[column].length;
+-
+- t_buffer[0]= len;
+- int2store(t_buffer + 1, t->year);
+- t_buffer[3]= (char) t->month;
+- t_buffer[4]= (char) t->day;
+- t_buffer[5]= (char) t->hour;
+- t_buffer[6]= (char) t->minute;
+- t_buffer[7]= (char) t->second;
+- int4store(t_buffer + 8, t->second_part);
+- memcpy(*p, t_buffer, len);
+- len++;
+- (*p)+= len;
+- }
+- break;
+- case MYSQL_TYPE_TINY_BLOB:
+- case MYSQL_TYPE_MEDIUM_BLOB:
+- case MYSQL_TYPE_LONG_BLOB:
+- case MYSQL_TYPE_BLOB:
+- case MYSQL_TYPE_VARCHAR:
+- case MYSQL_TYPE_VAR_STRING:
+- case MYSQL_TYPE_STRING:
+- case MYSQL_TYPE_DECIMAL:
+- case MYSQL_TYPE_NEWDECIMAL:
+- {
+- ulong len= (ulong)*stmt->params[column].length;
+- /* to is after p. The latter hasn't been moved */
+- uchar *to = mysql_net_store_length(*p, len);
+- DBUG_PRINT("info", ("len=x%x", len));
+- if (len)
+- memcpy(to, stmt->params[column].buffer, len);
+- (*p) = to + len;
+- }
+-
+- break;
+- default:
+- /* unsupported parameter type */
+- SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, "");
+- DBUG_RETURN(1);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-/* {{{ mysqlnd_stmt_execute_generate_request */
+-unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *request_len)
+-{
+- /* execute packet has the following format:
+- Offset Length Description
+- -----------------------------------------
+- 0 4 Statement id
+- 4 1 Flags (cursor type)
+- 5 4 Iteration count
+- -----------------------------------------
+- if (stmt->param_count):
+- 6 (paramcount+7)/8 null bitmap
+- ------------------------------------------
+- if (stmt->send_types_to_server):
+- param_count*2 parameter types
+- ------------------------------------------
+- n data from bind_buffer
+- */
+-
+- size_t length= 9000;
+- size_t free_bytes= 0;
+- size_t data_size= 0;
+- uint i;
+-
+- uchar *start= NULL, *p;
+-
+- DBUG_ENTER("mysql_stmt_execute_generate_request");
+-
+- if (!(start= p= (uchar *)my_malloc(length, MYF(MY_WME | MY_ZEROFILL))))
+- goto mem_error;
+-
+- int4store(p, stmt->stmt_id);
+- p += STMT_ID_LENGTH;
+-
+- /* flags is 4 bytes, we store just 1 */
+- int1store(p, (unsigned char) stmt->flags);
+- p++;
+-
+- int1store(p, 1); /* and send 1 for iteration count */
+- p+= 4;
+-
+-
+- if (stmt->param_count)
+- {
+- size_t null_byte_offset,
+- null_count= (stmt->param_count + 7) / 8;
+-
+- null_byte_offset = p - start;
+- memset(p, 0, null_count);
+- p += null_count;
+-
+-
+- int1store(p, stmt->send_types_to_server);
+- p++;
+-
+- free_bytes= length - (p - start);
+-
+- /* Store type information:
+- 2 bytes per type
+- */
+- if (stmt->send_types_to_server)
+- {
+- if (free_bytes < stmt->param_count * 2 + 20)
+- {
+- uchar *buf;
+- size_t offset= p - start;
+- length= offset + stmt->param_count * 2 + 20;
+- if (!(buf= (uchar *)my_malloc(length, MYF(MY_WME | MY_ZEROFILL))))
+- goto mem_error;
+- memcpy(buf, start, offset);
+- my_free((gptr)start, MYF(0));
+- start= buf;
+- p= start + offset;
+- }
+- for (i = 0; i < stmt->param_count; i++)
+- {
+- /* this differs from mysqlnd, c api supports unsinged !! */
+- uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0);
+- int2store(p, buffer_type);
+- p+= 2;
+- }
+- }
+- /* calculate data size */
+- for (i = 0; i < stmt->param_count; i++) {
+- if (stmt->params[i].buffer && !stmt->params[i].is_null)
+- stmt->params[i].is_null = &is_not_null;
+- if (!stmt->params[i].length)
+- stmt->params[i].length= &stmt->params[i].length_value;
+- if (!*stmt->params[i].is_null && !stmt->params[i].long_data_used)
+- {
+- switch (stmt->params[i].buffer_type) {
+- case MYSQL_TYPE_NULL:
+- stmt->params[i].is_null = &is_null;
+- break;
+- case MYSQL_TYPE_TINY_BLOB:
+- case MYSQL_TYPE_MEDIUM_BLOB:
+- case MYSQL_TYPE_LONG_BLOB:
+- case MYSQL_TYPE_BLOB:
+- case MYSQL_TYPE_VARCHAR:
+- case MYSQL_TYPE_VAR_STRING:
+- case MYSQL_TYPE_STRING:
+- case MYSQL_TYPE_DECIMAL:
+- case MYSQL_TYPE_NEWDECIMAL:
+- case MYSQL_TYPE_GEOMETRY:
+- case MYSQL_TYPE_NEWDATE:
+- case MYSQL_TYPE_ENUM:
+- case MYSQL_TYPE_BIT:
+- case MYSQL_TYPE_SET:
+- data_size+= 5; /* max 8 bytes for size */
+- data_size+= *stmt->params[i].length;
+- break;
+- default:
+- data_size+= mysql_ps_fetch_functions[stmt->params[i].buffer_type].pack_len;
+- break;
+- }
+- }
+- }
+-
+- /* store data */
+- free_bytes= length - (p - start);
+- if (free_bytes < data_size + 20)
+- {
+- uchar *buf;
+- size_t offset= p - start;
+- length= offset + data_size + 20;
+- if (!(buf= (uchar *)my_malloc(length, MYF(MY_WME | MY_ZEROFILL))))
+- goto mem_error;
+- memcpy(buf, start, offset);
+- my_free((gptr)start, MYF(0));
+- start= buf;
+- p= start + offset;
+- }
+- for (i = 0; i < stmt->param_count; i++)
+- {
+- if (stmt->params[i].long_data_used) {
+- stmt->params[i].long_data_used= 0;
+- }
+- else {
+- if (!stmt->params[i].buffer || *stmt->params[i].is_null || stmt->params[i].buffer_type == MYSQL_TYPE_NULL) {
+- (start + null_byte_offset)[i/8] |= (unsigned char) (1 << (i & 7));
+- } else {
+- DBUG_PRINT("info", ("storing parameter %d at offset %d", i, p - start));
+- store_param(stmt, i, &p);
+- }
+- }
+- }
+- }
+- stmt->send_types_to_server= 0;
+- *request_len = (p - start);
+- DBUG_RETURN(start);
+-
+-
+-mem_error:
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- my_free((gptr)start, MYF(ALLOW_ZERO_PTR));
+- *request_len= 0;
+- DBUG_RETURN(NULL);
+-}
+-/* }}} */
+-
+-/*!
+- *******************************************************************************
+-
+- \fn my_ulonglong mysql_stmt_affected_rows
+- \brief returns the number of affected rows from last mysql_stmt_execute
+- call
+-
+- \param[in] stmt The statement handle
+- *******************************************************************************
+-*/
+-my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
+-{
+- return stmt->upsert_status.affected_rows;
+-}
+-
+-my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *value)
+-{
+- DBUG_ENTER("mysql_stmt_attr_get");
+-
+- switch (attr_type) {
+- case STMT_ATTR_UPDATE_MAX_LENGTH:
+- *(my_bool *)value= stmt->update_max_length;
+- break;
+- case STMT_ATTR_CURSOR_TYPE:
+- *(unsigned long *)value= stmt->flags;
+- break;
+- case STMT_ATTR_PREFETCH_ROWS:
+- *(unsigned long *)value= stmt->prefetch_rows;
+- break;
+- default:
+- DBUG_RETURN(1);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *value)
+-{
+- DBUG_ENTER("mysql_stmt_attr_get");
+-
+- switch (attr_type) {
+- case STMT_ATTR_UPDATE_MAX_LENGTH:
+- stmt->update_max_length= *(my_bool *)value;
+- break;
+- case STMT_ATTR_CURSOR_TYPE: {
+- if (*(ulong *)value > (unsigned long) CURSOR_TYPE_READ_ONLY)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, "Not implemented");
+- DBUG_RETURN(1);
+- }
+- stmt->flags = *(ulong *)value;
+- break;
+- }
+- case STMT_ATTR_PREFETCH_ROWS: {
+- if (*(ulong *)value == 0)
+- *(long *)value= MYSQL_DEFAULT_PREFETCH_ROWS;
+- else
+- stmt->prefetch_rows= *(long *)value;
+- break;
+- }
+- default:
+- SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, "Not implemented");
+- DBUG_RETURN(1);
+- }
+- DBUG_RETURN(0);
+-}
+-
+-my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
+-{
+- DBUG_ENTER("mysql_stmt_bind_param");
+-
+- if (stmt->state < MYSQL_STMT_PREPARED) {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->param_count && bind)
+- {
+- uint i;
+-
+- memcpy(stmt->params, bind, sizeof(MYSQL_BIND) * stmt->param_count);
+- stmt->send_types_to_server= 1;
+-
+- for (i=0; i < stmt->param_count; i++)
+- {
+- if (!stmt->params[i].is_null)
+- stmt->params[i].is_null= &is_not_null;
+-
+- if (stmt->params[i].long_data_used)
+- stmt->params[i].long_data_used= 0;
+-
+- if (!stmt->params[i].length)
+- stmt->params[i].length= &stmt->params[i].buffer_length;
+-
+- switch(stmt->params[i].buffer_type) {
+- case MYSQL_TYPE_NULL:
+- stmt->params[i].is_null= &is_null;
+- break;
+- case MYSQL_TYPE_TINY:
+- stmt->params[i].buffer_length= 1;
+- break;
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_YEAR:
+- stmt->params[i].buffer_length= 2;
+- break;
+- case MYSQL_TYPE_LONG:
+- case MYSQL_TYPE_FLOAT:
+- stmt->params[i].buffer_length= 4;
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- case MYSQL_TYPE_DOUBLE:
+- stmt->params[i].buffer_length= 8;
+- break;
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- stmt->params[i].buffer_length= 12;
+- break;
+- case MYSQL_TYPE_TIME:
+- stmt->params[i].buffer_length= 13;
+- break;
+- case MYSQL_TYPE_DATE:
+- stmt->params[i].buffer_length= 5;
+- break;
+- case MYSQL_TYPE_STRING:
+- case MYSQL_TYPE_VAR_STRING:
+- case MYSQL_TYPE_BLOB:
+- case MYSQL_TYPE_TINY_BLOB:
+- case MYSQL_TYPE_MEDIUM_BLOB:
+- case MYSQL_TYPE_LONG_BLOB:
+- case MYSQL_TYPE_DECIMAL:
+- case MYSQL_TYPE_NEWDECIMAL:
+- break;
+- default:
+- SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- break;
+- }
+- }
+- }
+- stmt->bind_param_done= stmt->send_types_to_server= 1;
+-
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+- DBUG_RETURN(0);
+-}
+-
+-my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
+-{
+- uint i;
+- DBUG_ENTER("mysql_stmt_bind_result");
+-
+- if (stmt->state < MYSQL_STMT_PREPARED)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
+- DBUG_RETURN(1);
+- }
+-
+- if (!stmt->field_count)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NO_STMT_METADATA, SQLSTATE_UNKNOWN, "todo: metadata error");
+- DBUG_RETURN(1);
+- }
+-
+- if (!bind)
+- DBUG_RETURN(1);
+-
+- memcpy(stmt->bind, bind, sizeof(MYSQL_BIND) * stmt->field_count);
+-
+- for (i=0; i < stmt->field_count; i++)
+- {
+- if (!is_supported_buffer_type(bind[i].buffer_type))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, "");
+- DBUG_RETURN(1);
+- }
+-
+- if (!stmt->bind[i].is_null)
+- stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
+- if (!stmt->bind[i].length)
+- stmt->bind[i].length= &stmt->bind[i].length_value;
+- if (!stmt->bind[i].error)
+- stmt->bind[i].error= &stmt->bind[i].error_value;
+-
+- /* set length values for numeric types */
+- switch(bind[i].buffer_type) {
+- case MYSQL_TYPE_NULL:
+- *stmt->bind[i].length= stmt->bind[i].length_value= 0;
+- break;
+- case MYSQL_TYPE_TINY:
+- *stmt->bind[i].length= stmt->bind[i].length_value= 1;
+- break;
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_YEAR:
+- *stmt->bind[i].length= stmt->bind[i].length_value= 2;
+- break;
+- case MYSQL_TYPE_INT24:
+- case MYSQL_TYPE_LONG:
+- case MYSQL_TYPE_FLOAT:
+- *stmt->bind[i].length= stmt->bind[i].length_value= 4;
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- case MYSQL_TYPE_DOUBLE:
+- *stmt->bind[i].length= stmt->bind[i].length_value= 8;
+- break;
+- case MYSQL_TYPE_TIME:
+- case MYSQL_TYPE_DATE:
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- *stmt->bind[i].length= stmt->bind[i].length_value= sizeof(MYSQL_TIME);
+- break;
+- default:
+- break;
+- }
+- }
+- stmt->bind_result_done= 1;
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+-
+- DBUG_RETURN(0);
+-}
+-
+-my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
+-{
+- char stmt_id[STMT_ID_LENGTH];
+- /* clear memory */
+- free_root(&stmt->result.alloc, MYF(00)); /* allocated in mysql_stmt_store_result */
+- free_root(&stmt->mem_root,MYF(0));
+-
+- if (stmt->mysql)
+- {
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+-
+- /* remove from stmt list */
+- if (remove)
+- stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list);
+-
+- /* check if all data are fetched */
+- if (stmt->mysql->status != MYSQL_STATUS_READY)
+- {
+- stmt_flush_unbuffered(stmt);
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- }
+- if (stmt->state > MYSQL_STMT_INITTED)
+- {
+- int4store(stmt_id, stmt->stmt_id);
+- if (simple_command(stmt->mysql,MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, stmt->mysql->net.last_error);
+- return 1;
+- }
+- }
+- }
+- return 0;
+-}
+-
+-my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
+-{
+- DBUG_ENTER("mysql_stmt_close");
+-
+- net_stmt_close(stmt, 1);
+-
+- my_free((char *)stmt, MYF(MY_WME));
+- DBUG_RETURN(0);
+-}
+-
+-void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset)
+-{
+- my_ulonglong i= offset;
+- MYSQL_ROWS *ptr= stmt->result.data;
+- DBUG_ENTER("mysql_stmt_data_seek");
+-
+- DBUG_PRINT("info", ("total rows: %llu offset: %llu", stmt->result.rows, offset));
+-
+- while(i-- && ptr)
+- ptr= ptr->next;
+-
+- stmt->result_cursor= ptr;
+-
+- DBUG_VOID_RETURN;
+-}
+-
+-unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT *stmt)
+-{
+- return stmt->last_errno;
+-}
+-
+-const char * STDCALL mysql_stmt_error(MYSQL_STMT *stmt)
+-{
+- return (const char *)stmt->last_error;
+-}
+-
+-int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
+-{
+- unsigned char *row;
+- int rc;
+-
+- DBUG_ENTER("mysql_stmt_fetch");
+-
+- if (stmt->state <= MYSQL_STMT_EXECUTED)
+- {
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->state < MYSQL_STMT_WAITING_USE_OR_STORE || !stmt->field_count)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- } else if (stmt->state== MYSQL_STMT_WAITING_USE_OR_STORE)
+- {
+- stmt->default_rset_handler(stmt);
+- }
+-
+- if (stmt->state == MYSQL_STMT_FETCH_DONE)
+- {
+- DBUG_RETURN(MYSQL_NO_DATA);
+- }
+-
+- if ((rc= stmt->fetch_row_func(stmt, &row)))
+- {
+- stmt->state= MYSQL_STMT_FETCH_DONE;
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- /* to fetch data again, stmt must be executed again */
+- DBUG_RETURN(MYSQL_NO_DATA);
+- }
+-
+- if ((rc= stmt_fetch_to_bind(stmt, row)))
+- {
+- DBUG_RETURN(rc);
+- }
+- stmt->state= MYSQL_STMT_USER_FETCHING;
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+- DBUG_RETURN(0);
+-}
+-
+-int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset)
+-{
+- DBUG_ENTER("mysql_stmt_fetch");
+-
+- if (stmt->state < MYSQL_STMT_USER_FETCHING || column >= stmt->field_count ||
+- stmt->state == MYSQL_STMT_FETCH_DONE) {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NO_DATA, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (!stmt->bind[column].row_ptr)
+- {
+- /* we set row_ptr only for columns which contain data, so this must be a NULL column */
+- if (bind[0].is_null)
+- *bind[0].is_null= 1;
+- }
+- else
+- {
+- unsigned char *save_ptr;
+- if (bind[0].length)
+- *bind[0].length= stmt->bind[column].length_value;
+- else
+- *bind[0].length= *stmt->bind[column].length;
+- if (bind[0].is_null)
+- *bind[0].is_null= 0;
+- else
+- bind[0].is_null= &bind[0].is_null_value;
+- if (!bind[0].error)
+- bind[0].error= &bind[0].error_value;
+- *bind[0].error= 0;
+- bind[0].offset= offset;
+- save_ptr= stmt->bind[column].row_ptr;
+- mysql_ps_fetch_functions[stmt->fields[column].type].func(&bind[0], &stmt->fields[column], &stmt->bind[column].row_ptr);
+- stmt->bind[column].row_ptr= save_ptr;
+- }
+- DBUG_RETURN(0);
+-}
+-
+-unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
+-{
+- return stmt->field_count;
+-}
+-
+-my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
+-{
+- return mysql_stmt_reset(stmt);
+-}
+-
+-MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql)
+-{
+-
+- MYSQL_STMT *stmt = (MYSQL_STMT *)my_malloc(sizeof(MYSQL_STMT), MYF(MY_WME | MY_ZEROFILL));
+- DBUG_ENTER("mysql_stmt_init");
+-
+- if (!stmt)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(NULL);
+- }
+-
+- /* fill mysql's stmt list */
+- stmt->list.data= stmt;
+- stmt->mysql= mysql;
+- mysql->stmts= list_add(mysql->stmts, &stmt->list);
+-
+-
+- /* clear flags */
+- strcpy(stmt->sqlstate, "00000");
+-
+- stmt->state= MYSQL_STMT_INITTED;
+-
+- /* set default */
+- stmt->prefetch_rows= 1;
+-
+- DBUG_RETURN(stmt);
+-}
+-
+-my_bool stmt_read_prepare_response(MYSQL_STMT *stmt)
+-{
+- ulong packet_length;
+- uchar *p;
+-
+- DBUG_ENTER("read_prepare_response");
+-
+- if ((packet_length= net_safe_read(stmt->mysql)) == packet_error)
+- DBUG_RETURN(1);
+-
+- DBUG_PRINT("info",("packet_length= %ld",packet_length));
+-
+- p= (uchar *)stmt->mysql->net.read_pos;
+-
+- if (0xFF == p[0]) /* Error occured */
+- {
+- DBUG_RETURN(1);
+- }
+-
+- p++;
+- stmt->stmt_id= uint4korr(p);
+- p+= 4;
+- stmt->field_count= uint2korr(p);
+- p+= 2;
+- stmt->param_count= uint2korr(p);
+-
+- /* filler */
+- p++;
+- stmt->upsert_status.warning_count= uint2korr(p);
+-
+- DBUG_RETURN(0);
+-}
+-
+-my_bool stmt_get_param_metadata(MYSQL_STMT *stmt)
+-{
+- MYSQL_DATA *result;
+-
+- DBUG_ENTER("stmt_get_param_metadata");
+-
+- if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
+- DBUG_RETURN(1);
+-
+- free_rows(result);
+- DBUG_RETURN(0);
+-}
+-
+-my_bool stmt_read_result_metadata(MYSQL_STMT *stmt)
+-{
+- MYSQL_DATA *result;
+- DBUG_ENTER("stmt_read_result_metadata");
+-
+- if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
+- DBUG_RETURN(1);
+- if (!(stmt->fields= unpack_fields(result,&stmt->mem_root,
+- stmt->field_count, 0,
+- stmt->mysql->server_capabilities & CLIENT_LONG_FLAG)))
+- DBUG_RETURN(1);
+- DBUG_RETURN(0);
+-}
+-
+-int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
+-{
+- int rc= 1;
+- DBUG_ENTER("mysql_stmt_prepare");
+-
+- if (!stmt->mysql)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- /* clear flags */
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+- stmt->upsert_status.affected_rows= stmt->mysql->affected_rows= (my_ulonglong) ~0;
+-
+- /* check if we have to clear results */
+- if (stmt->state > MYSQL_STMT_INITTED)
+- {
+- /* We need to semi-close the prepared statement:
+- reset stmt and free all buffers and close the statement
+- on server side. Statment handle will get a new stmt_id */
+- char stmt_id[STMT_ID_LENGTH];
+-
+- mysql_stmt_reset(stmt);
+-
+- free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
+- stmt->param_count= 0;
+- stmt->field_count= 0;
+-
+- int4store(stmt_id, stmt->stmt_id);
+- if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
+- goto fail;
+- }
+-
+- if (simple_command(stmt->mysql,MYSQL_COM_STMT_PREPARE, query, length, 1))
+- goto fail;
+-
+- if (stmt_read_prepare_response(stmt))
+- goto fail;
+-
+- /* metadata not supported yet */
+- if (stmt->param_count && stmt_get_param_metadata(stmt))
+- {
+- goto fail;
+- }
+-
+- if (stmt->field_count && stmt_read_result_metadata(stmt))
+- {
+- goto fail;
+- }
+-
+- /* allocated bind buffer for parameters */
+- if (stmt->param_count)
+- {
+- if (!(stmt->params= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- goto fail;
+- }
+- }
+- /* allocated bind buffer for result */
+- if (stmt->field_count)
+- {
+- if (!(stmt->bind= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->field_count * sizeof(MYSQL_BIND))))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- goto fail;
+- }
+- }
+- stmt->state = MYSQL_STMT_PREPARED;
+- DBUG_RETURN(0);
+-
+-fail:
+- stmt->state= MYSQL_STMT_INITTED;
+- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
+- stmt->mysql->net.last_error);
+- DBUG_RETURN(rc);
+-}
+-
+-int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
+-{
+- DBUG_ENTER("mysql_stmt_store_result");
+-
+- if (!stmt->mysql)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (!stmt->field_count)
+- DBUG_RETURN(0);
+-
+- /* test_pure_coverage requires checking of error_no */
+- if (stmt->last_errno)
+- DBUG_RETURN(1);
+-
+- if (stmt->state < MYSQL_STMT_EXECUTED)
+- {
+- SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- /* if stmt is a cursor, we need to tell server to send all rows */
+- if (stmt->cursor_exists && stmt->mysql->status == MYSQL_STATUS_READY)
+- {
+- char buff[STMT_ID_LENGTH + 4];
+- int4store(buff, stmt->stmt_id);
+- int4store(buff + STMT_ID_LENGTH, (int)~0);
+-
+- if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, buff, sizeof(buff), 1))
+- DBUG_RETURN(1);
+- /* todo: cursor */
+- }
+- else if (stmt->mysql->status != MYSQL_STATUS_GET_RESULT)
+- {
+- SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt_read_all_rows(stmt))
+- {
+- /* error during read - reset stmt->data */
+- free_root(&stmt->result.alloc, 0);
+- stmt->result.data= NULL;
+- stmt->result.rows= 0;
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- DBUG_RETURN(1);
+- }
+- stmt->result_cursor= stmt->result.data;
+- stmt->fetch_row_func= stmt_buffered_fetch;
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- stmt->state= MYSQL_STMT_USE_OR_STORE_CALLED;
+-
+- /* set affected rows: see bug 2247 */
+- stmt->upsert_status.affected_rows= stmt->result.rows;
+- stmt->mysql->affected_rows= stmt->result.rows;
+-
+- DBUG_RETURN(0);
+-}
+-
+-int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
+-{
+- char *request;
+- int ret;
+- size_t request_len= 0;
+-
+-
+- DBUG_ENTER("mysql_stmt_execute");
+-
+- if (!stmt->mysql)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->state < MYSQL_STMT_PREPARED)
+- {
+- SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->param_count && !stmt->bind_param_done)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN,
+- "No data supplied for parameters in prepared statement");
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
+- {
+- stmt->default_rset_handler = _mysql_stmt_use_result;
+- stmt->default_rset_handler(stmt);
+- }
+- if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
+- {
+- stmt_flush_unbuffered(stmt);
+- stmt->state= MYSQL_STMT_PREPARED;
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- }
+-
+- /* clear data, in case mysql_stmt_store_result was called */
+- if (stmt->result.data)
+- {
+- free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
+- stmt->result_cursor= stmt->result.data= 0;
+- stmt->result.rows= 0;
+- }
+-
+- request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
+- DBUG_PRINT("info",("request_len=%ld", request_len));
+-
+- ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1) ||
+- mysql_read_query_result(stmt->mysql));
+-
+- if (request)
+- my_free(request, MYF(0));
+-
+- /* if a reconnect occured, our connection handle is invalid */
+- if (!stmt->mysql)
+- DBUG_RETURN(1);
+-
+- /* update affected rows, also if an error occured */
+- stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
+-
+- if (ret)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
+- stmt->mysql->net.last_error);
+- stmt->state= MYSQL_STMT_PREPARED;
+- DBUG_RETURN(1);
+- }
+- stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
+- stmt->upsert_status.server_status= stmt->mysql->server_status;
+- stmt->upsert_status.warning_count= stmt->mysql->warning_count;
+-
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+-
+- stmt->execute_count++;
+- stmt->send_types_to_server= 0;
+-
+- stmt->state= MYSQL_STMT_EXECUTED;
+-
+- if (stmt->mysql->field_count)
+- {
+- if (!stmt->field_count) /* fix for ps_bug: test_misc */
+- {
+- uint i;
+- if (!(stmt->fields= (MYSQL_FIELD *)alloc_root(&stmt->mem_root,
+- sizeof(MYSQL_FIELD) * stmt->mysql->field_count)))
+- {
+- /*todo: set error */
+- DBUG_RETURN(1);
+- }
+- stmt->field_count= stmt->mysql->field_count;
+-
+- for (i=0; i < stmt->field_count; i++)
+- {
+- stmt->fields[i].db= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].db);
+- stmt->fields[i].table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].table);
+- stmt->fields[i].org_table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_table);
+- stmt->fields[i].name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].name);
+- stmt->fields[i].org_name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_name);
+- stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(&stmt->mem_root, stmt->mysql->fields[i].def) : NULL;
+- }
+- }
+-
+- if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS)
+- {
+- stmt->cursor_exists = TRUE;
+- stmt->mysql->status = MYSQL_STATUS_READY;
+-
+- /* Only cursor read */
+- stmt->default_rset_handler = _mysql_stmt_use_result;
+-
+- } else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
+- {
+- /*
+- We have asked for CURSOR but got no cursor, because the condition
+- above is not fulfilled. Then...
+- This is a single-row result set, a result set with no rows, EXPLAIN,
+- SHOW VARIABLES, or some other command which either a) bypasses the
+- cursors framework in the server and writes rows directly to the
+- network or b) is more efficient if all (few) result set rows are
+- precached on client and server's resources are freed.
+- */
+-
+- /* preferred is buffered read */
+- mysql_stmt_store_result(stmt);
+- } else
+- {
+- /* preferred is unbuffered read */
+- stmt->default_rset_handler = _mysql_stmt_use_result;
+- }
+- stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE;
+- /* in certain cases parameter types can change: For example see bug
+- 4026 (SELECT ?), so we need to update field information */
+- if (stmt->mysql->field_count == stmt->field_count)
+- {
+- uint i;
+- for (i=0; i < stmt->field_count; i++)
+- {
+- stmt->fields[i].type= stmt->mysql->fields[i].type;
+- stmt->fields[i].length= stmt->mysql->fields[i].length;
+- stmt->fields[i].flags= stmt->mysql->fields[i].flags;
+- stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
+- stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
+- }
+- } else
+- {
+- /* table was altered, see test_wl4166_2 */
+- SET_CLIENT_STMT_ERROR(stmt, CR_NEW_STMT_METADATA, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+- }
+- DBUG_RETURN(0);
+-}
+-
+-my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
+-{
+- unsigned char cmd_buf[STMT_ID_LENGTH];
+- my_bool ret= 1;
+-
+- DBUG_ENTER("mysql_stmt_reset");
+-
+- if (!stmt->mysql)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+-
+-
+- if (stmt->stmt_id)
+- {
+- if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
+- {
+- stmt->default_rset_handler(stmt);
+- stmt->state = MYSQL_STMT_USER_FETCHING;
+- }
+-
+- if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count)
+- {
+- stmt_flush_unbuffered(stmt);
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- }
+-
+- /* reset statement on server side */
+- if (stmt->mysql->status == MYSQL_STATUS_READY)
+- {
+- int4store(cmd_buf, stmt->stmt_id);
+- if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0)))
+- SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
+- stmt->mysql->net.last_error);
+-
+- }
+- if (stmt->params) {
+- ulonglong i;
+- for (i=0; i < stmt->param_count; i++)
+- if (stmt->params[i].long_data_used)
+- stmt->params[i].long_data_used= 0;
+- }
+- stmt->state= MYSQL_STMT_PREPARED;
+- stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
+- stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
+- stmt->upsert_status.server_status= stmt->mysql->server_status;
+- stmt->upsert_status.warning_count= stmt->mysql->warning_count;
+- stmt->mysql->status= MYSQL_STATUS_READY;
+- }
+-
+- DBUG_RETURN(ret);
+-}
+-
+-MYSQL_RES * STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt)
+-{
+- MYSQL_RES *res;
+-
+- DBUG_ENTER("mysql_stmt_result_metadata");
+-
+- if (!stmt->field_count)
+- DBUG_RETURN(NULL);
+-
+- /* aloocate result set structutr and copy stmt information */
+- if (!(res= (MYSQL_RES *)my_malloc(sizeof(MYSQL_RES), MYF(MY_WME | MY_ZEROFILL))))
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(NULL);
+- }
+-
+- res->eof= 1;
+- res->fields= stmt->fields;
+- res->field_count= stmt->field_count;
+- DBUG_RETURN(res);}
+-
+-const char * STDCALL mysql_stmt_sqlstate(MYSQL_STMT *stmt)
+-{
+- return stmt->sqlstate;
+-}
+-
+-MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt)
+-{
+- DBUG_ENTER("mysql_stmt_row_tell");
+- DBUG_RETURN(stmt->result_cursor);
+-}
+-
+-unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT *stmt)
+-{
+- return stmt->param_count;
+-}
+-
+-MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET new_row)
+-{
+- MYSQL_ROW_OFFSET old_row; /* for returning old position */
+- DBUG_ENTER("mysql_stmt_row_seek");
+-
+- old_row= stmt->result_cursor;
+- stmt->result_cursor= new_row;
+-
+- DBUG_RETURN(old_row);
+-}
+-
+-my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
+- const char *data, ulong length)
+-{
+- DBUG_ENTER("mysql_stmt_send_long_data");
+-
+- CLEAR_CLIENT_ERROR(stmt->mysql);
+- CLEAR_CLIENT_STMT_ERROR(stmt);
+-
+- if (stmt->state < MYSQL_STMT_PREPARED || !stmt->params)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, mysql_stmt_not_prepared);
+- DBUG_RETURN(1);
+- }
+-
+- if (param_number >= stmt->param_count)
+- {
+- SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
+- DBUG_RETURN(1);
+- }
+-
+- if (stmt->mysql->status== MYSQL_STATUS_READY && (length || !stmt->params[param_number].long_data_used))
+- {
+- int ret;
+- size_t packet_len;
+- uchar *cmd_buff= (uchar *)my_malloc(packet_len= STMT_ID_LENGTH + 2 + length, MYF(MY_WME | MY_ZEROFILL));
+- int4store(cmd_buff, stmt->stmt_id);
+- int2store(cmd_buff + STMT_ID_LENGTH, param_number);
+- memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
+- stmt->params[param_number].long_data_used= 1;
+- ret= simple_command(stmt->mysql,MYSQL_COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1);
+- my_free((gptr)cmd_buff, MYF(MY_WME));
+- DBUG_RETURN(ret);
+- }
+- DBUG_RETURN(1);
+-}
+-
+-my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
+-{
+- return stmt->upsert_status.last_insert_id;
+-}
+-
+-my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
+-{
+- return stmt->result.rows;
+-}
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_stmt_codec.c mariadb-native-client.trunk/libmysql/my_stmt_codec.c
+--- mariadb/libmysql/my_stmt_codec.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_stmt_codec.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,936 +0,0 @@
+-/****************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-*****************************************************************************/
+-
+-/* The implementation for prepared statements was ported from PHP's mysqlnd
+- extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
+-
+- Original file header:
+- +----------------------------------------------------------------------+
+- | PHP Version 5 |
+- +----------------------------------------------------------------------+
+- | Copyright (c) 2006-2011 The PHP Group |
+- +----------------------------------------------------------------------+
+- | This source file is subject to version 3.01 of the PHP license, |
+- | that is bundled with this package in the file LICENSE, and is |
+- | available through the world-wide-web at the following url: |
+- | http://www.php.net/license/3_01.txt |
+- | If you did not receive a copy of the PHP license and are unable to |
+- | obtain it through the world-wide-web, please send a note to |
+- | license@php.net so we can mail you a copy immediately. |
+- +----------------------------------------------------------------------+
+- | Authors: Georg Richter <georg@mysql.com> |
+- | Andrey Hristov <andrey@mysql.com> |
+- | Ulf Wendel <uwendel@mysql.com> |
+- +----------------------------------------------------------------------+
+-*/
+-
+-#include "my_global.h"
+-#include <my_sys.h>
+-#include <mysys_err.h>
+-#include <m_string.h>
+-#include <m_ctype.h>
+-#include "mysql.h"
+-
+-#define MYSQL_SILENT
+-
+-/* ranges for C-binding */
+-#define UINT_MAX32 0xFFFFFFFFL
+-#define UINT_MAX24 0x00FFFFFF
+-#define UINT_MAX16 0xFFFF
+-#ifndef INT_MIN8
+-#define INT_MIN8 (~0x7F)
+-#define INT_MAX8 0x7F
+-#endif
+-#define UINT_MAX8 0xFF
+-
+-#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN)
+-#define LONGLONG_MIN ((long long) 0x8000000000000000LL)
+-#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
+-#endif
+-
+-#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)
+-/* First check for ANSI C99 definition: */
+-#ifdef ULLONG_MAX
+-#define ULONGLONG_MAX ULLONG_MAX
+-#else
+-#define ULONGLONG_MAX ((unsigned long long)(~0ULL))
+-#endif
+-#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/
+-
+-#define YY_PART_YEAR 70
+-
+-struct st_mysql_perm_bind mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
+-my_bool mysql_ps_subsystem_initialized= 0;
+-
+-
+-#define NUMERIC_TRUNCATION(val,min_range, max_range)\
+- ((((val) > (max_range)) || ((val) < (min_range)) ? 1 : 0))
+-
+-
+-/* {{{ ps_fetch_from_1_to_8_bytes */
+-void ps_fetch_from_1_to_8_bytes(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
+- unsigned char **row, unsigned int byte_count)
+-{
+- my_bool is_unsigned= test(field->flags & UNSIGNED_FLAG);
+- r_param->buffer_length= byte_count;
+- switch (byte_count) {
+- case 1:
+- *(uchar *)r_param->buffer= **row;
+- *r_param->error= is_unsigned != r_param->is_unsigned && *(uchar *)r_param->buffer > INT_MAX8;
+- break;
+- case 2:
+- shortstore(r_param->buffer, ((ushort) sint2korr(*row)));
+- *r_param->error= is_unsigned != r_param->is_unsigned && *(ushort *)r_param->buffer > INT_MAX16;
+- break;
+- case 4:
+- {
+- longstore(r_param->buffer, ((uint32)sint4korr(*row)));
+- *r_param->error= is_unsigned != r_param->is_unsigned && *(uint32 *)r_param->buffer > INT_MAX32;
+- }
+- break;
+- case 8:
+- {
+- ulonglong val= (ulonglong)sint8korr(*row);
+- longlongstore(r_param->buffer, val);
+- *r_param->error= is_unsigned != r_param->is_unsigned && val > LONGLONG_MAX ;
+- }
+- break;
+- default:
+- r_param->buffer_length= 0;
+- break;
+- }
+- (*row)+= byte_count;
+-}
+-/* }}} */
+-
+-static longlong my_atoll(const char *number, const char *end, int *error)
+-{
+- char buffer[255];
+- longlong llval= 0;
+- size_t i;
+- /* set error at the following conditions:
+- - string contains invalid character(s)
+- - length > 254
+- - strtoll returns invalid range
+- */
+-
+- memcpy(buffer, number, MIN((uint)(end - number), 254));
+- buffer[(uint)(end - number)]= 0;
+-
+- llval= strtoll(buffer, NULL, 10);
+-
+- /* check size */
+- if ((uint)(end - number) > 254)
+- {
+- *error= 1;
+- return llval;
+- }
+-
+- /* check characters */
+- for (i=0; i < strlen(buffer); i++)
+- {
+- if (buffer[i] < '0' || buffer[i] > '9')
+- {
+- *error= 1;
+- return llval;
+- }
+- }
+-
+- /* check strtoll result */
+- if (errno == ERANGE)
+- *error= errno;
+- return llval;
+-}
+-
+-double my_atod(const char *number, const char *end, int *error)
+-{
+- double val= 0.0;
+- char buffer[255];
+- int len= (int)(end - number);
+-
+- if (len > 254)
+- *error= 1;
+-
+- len= MIN(len, 254);
+- memcpy(&buffer, number, len);
+- buffer[len]= '\0';
+-
+- val= strtod(buffer, NULL);
+-/* if (!*error)
+- *error= errno; */
+- return val;
+-}
+-
+-my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
+-{
+- my_bool is_time=0, is_date=0, has_time_frac=0;
+- char *p= (char *)str;
+-
+- if ((p= strchr(str, '-')) && p <= str + length)
+- is_date= 1;
+- if ((p= strchr(str, ':')) && p <= str + length)
+- is_time= 1;
+- if ((p= strchr(str, '.')) && p <= str + length)
+- has_time_frac= 1;
+-
+- p= (char *)str;
+-
+- memset(tm, 0, sizeof(MYSQL_TIME));
+-
+- if (is_date)
+- {
+- sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day);
+- p= strchr(str, ' ');
+- if (!p)
+- {
+- tm->time_type= MYSQL_TIMESTAMP_DATE;
+- return 0;
+- }
+- }
+- if (has_time_frac)
+- {
+- sscanf(p, "%d:%d:%d.%ld", &tm->hour, &tm->minute, &tm->second, &tm->second_part);
+- tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
+- return 0;
+- }
+- if (is_time)
+- {
+- sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second);
+- tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
+- return 0;
+- }
+- return 1;
+-}
+-
+-
+-static void convert_from_string(MYSQL_BIND *r_param, char *buffer, size_t len)
+-{
+- int error= 0;
+- switch (r_param->buffer_type)
+- {
+- case MYSQL_TYPE_TINY:
+- {
+- longlong val= my_atoll(buffer, buffer + len, &error);
+- *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0;
+- int1store(r_param->buffer, (uchar) val);
+- r_param->buffer_length= sizeof(uchar);
+- }
+- break;
+- case MYSQL_TYPE_YEAR:
+- case MYSQL_TYPE_SHORT:
+- {
+- longlong val= my_atoll(buffer, buffer + len, &error);
+- *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0;
+- shortstore(r_param->buffer, (short)val);
+- r_param->buffer_length= sizeof(short);
+- }
+- break;
+- case MYSQL_TYPE_LONG:
+- {
+- longlong val= my_atoll(buffer, buffer + len, &error);
+- *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0;
+- longstore(r_param->buffer, (int32)val);
+- r_param->buffer_length= sizeof(uint32);
+- }
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- {
+- longlong val= my_atoll(buffer, buffer + len, &error);
+- *r_param->error= error > 0; /* no need to check for truncation */
+- longlongstore(r_param->buffer, val);
+- r_param->buffer_length= sizeof(longlong);
+- }
+- break;
+- case MYSQL_TYPE_DOUBLE:
+- {
+- double val= my_atod(buffer, buffer + len, &error);
+- *r_param->error= error > 0; /* no need to check for truncation */
+- float8store(r_param->buffer, val);
+- r_param->buffer_length= sizeof(double);
+- }
+- break;
+- case MYSQL_TYPE_FLOAT:
+- {
+- float val= (float)my_atod(buffer, buffer + len, &error);
+- *r_param->error= error > 0; /* no need to check for truncation */
+- float4store(r_param->buffer, val);
+- r_param->buffer_length= sizeof(float);
+- }
+- break;
+- case MYSQL_TYPE_TIME:
+- case MYSQL_TYPE_DATE:
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- {
+- MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer;
+- str_to_TIME(buffer, len, tm);
+- break;
+- }
+- break;
+- case MYSQL_TYPE_TINY_BLOB:
+- case MYSQL_TYPE_MEDIUM_BLOB:
+- case MYSQL_TYPE_LONG_BLOB:
+- case MYSQL_TYPE_BLOB:
+- case MYSQL_TYPE_DECIMAL:
+- case MYSQL_TYPE_NEWDECIMAL:
+- default:
+- {
+- char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */
+- char *end= buffer + len;
+- size_t copylen= 0;
+-
+- if (start < end)
+- {
+- copylen= end - start;
+- if (r_param->buffer_length)
+- memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length));
+- }
+- if (copylen < r_param->buffer_length)
+- ((char *)r_param->buffer)[copylen]= '\0';
+- *r_param->error= (copylen > r_param->buffer_length);
+-
+- *r_param->length= (ulong)len;
+- }
+- break;
+- }
+-}
+-
+-static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, longlong val, my_bool is_unsigned)
+-{
+- switch (r_param->buffer_type) {
+- case MYSQL_TYPE_TINY:
+- *(uchar *)r_param->buffer= (uchar)val;
+- *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8);
+- r_param->buffer_length= 1;
+- break;
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_YEAR:
+- shortstore(r_param->buffer, (short)val);
+- *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16);
+- r_param->buffer_length= 2;
+- break;
+- case MYSQL_TYPE_LONG:
+- longstore(r_param->buffer, (int32)val);
+- *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32);
+- r_param->buffer_length= 4;
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- *r_param->error= (val < 0 && r_param->is_unsigned != is_unsigned);
+- longlongstore(r_param->buffer, val);
+- r_param->buffer_length= 8;
+- break;
+- case MYSQL_TYPE_DOUBLE:
+- {
+- volatile double dbl;
+-
+- dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val;
+- doublestore(r_param->buffer, dbl);
+- *r_param->error= is_unsigned ? (ulonglong )dbl != (ulonglong)val : (longlong)dbl != (longlong)val;
+- r_param->buffer_length= 8;
+- break;
+- }
+- case MYSQL_TYPE_FLOAT:
+- {
+- float fval;
+- fval= is_unsigned ? (float)(ulonglong)(val) : (float)val;
+- float4store(r_param->buffer, fval);
+- *r_param->error= is_unsigned ? (ulonglong)fval != (ulonglong)val : (longlong)fval != val;
+- r_param->buffer_length= 4;
+- }
+- break;
+- default:
+- {
+- char buffer[22];
+- char *endptr;
+- uint len;
+-
+- endptr= longlong10_to_str(val, buffer, is_unsigned ? 10 : -10);
+- len= (uint)(endptr - buffer);
+-
+- /* check if field flag is zerofill */
+-
+- convert_from_string(r_param, buffer, len);
+- }
+- break;
+- }
+-}
+-
+-
+-/* {{{ ps_fetch_null */
+-static
+-void ps_fetch_null(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row)
+-{
+- /* do nothing */
+-}
+-/* }}} */
+-
+-#define GET_LVALUE_FROM_ROW(is_unsigned, data, ucast, scast)\
+- (is_unsigned) ? (longlong)(ucast) *(longlong *)(data) : (longlong)(scast) *(longlong *)(data)
+-/* {{{ ps_fetch_int8 */
+-static
+-void ps_fetch_int8(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
+- unsigned char **row)
+-{
+- switch(r_param->buffer_type) {
+- case MYSQL_TYPE_TINY:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
+- break;
+- default:
+- {
+- uchar val= **row;
+- longlong lval= field->flags & UNSIGNED_FLAG ? (longlong) val : (longlong)(signed char)val;
+- convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
+- (*row) += 1;
+- }
+- break;
+- }
+-}
+-/* }}} */
+-
+-
+-/* {{{ ps_fetch_int16 */
+-static
+-void ps_fetch_int16(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
+- unsigned char **row)
+-{
+- switch (r_param->buffer_type) {
+- case MYSQL_TYPE_YEAR:
+- case MYSQL_TYPE_SHORT:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
+- break;
+- default:
+- {
+- short sval= sint2korr(*row);
+- longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ushort) sval : (longlong)sval;
+- convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
+- (*row) += 2;
+- }
+- break;
+- }
+-}
+-/* }}} */
+-
+-
+-/* {{{ ps_fetch_int32 */
+-static
+-void ps_fetch_int32(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
+- unsigned char **row)
+-{
+- switch (r_param->buffer_type) {
+-/* case MYSQL_TYPE_TINY:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
+- break;
+- case MYSQL_TYPE_YEAR:
+- case MYSQL_TYPE_SHORT:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
+- break; */
+- case MYSQL_TYPE_INT24:
+- case MYSQL_TYPE_LONG:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
+- break;
+- default:
+- {
+- int32 sval= sint4korr(*row);
+- longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(uint32) sval : (longlong)sval;
+- convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
+- (*row) += 4;
+- }
+- break;
+- }
+-}
+-/* }}} */
+-
+-
+-/* {{{ ps_fetch_int64 */
+-static
+-void ps_fetch_int64(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
+- unsigned char **row)
+-{
+- switch(r_param->buffer_type)
+- {
+-/* case MYSQL_TYPE_TINY:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
+- break;
+- case MYSQL_TYPE_YEAR:
+- case MYSQL_TYPE_SHORT:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
+- break;
+- case MYSQL_TYPE_INT24:
+- case MYSQL_TYPE_LONG:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
+- break; */
+- case MYSQL_TYPE_LONGLONG:
+- ps_fetch_from_1_to_8_bytes(r_param, field, row, 8);
+- break;
+- default:
+- {
+- longlong sval= (longlong)sint8korr(*row);
+- longlong lval= field->flags & UNSIGNED_FLAG ? (ulonglong) sval : (longlong)sval;
+- convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
+- (*row) += 8;
+- }
+- break;
+- }
+-}
+-/* }}} */
+-
+-static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size)
+-{
+- double check_trunc_val= (val > 0) ? floor(val) : -floor(-val);
+- char *buf= (char *)r_param->buffer;
+- switch (r_param->buffer_type)
+- {
+- case MYSQL_TYPE_TINY:
+- *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val;
+- *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) :
+- (double)((int8)*buf));
+- r_param->buffer_length= 1;
+- break;
+- case MYSQL_TYPE_SHORT:
+- case MYSQL_TYPE_YEAR:
+- {
+- if (r_param->is_unsigned)
+- {
+- ushort sval= (ushort)val;
+- shortstore(buf, sval);
+- *r_param->error= check_trunc_val != (double)sval;
+- } else {
+- short sval= (short)val;
+- shortstore(buf, sval);
+- *r_param->error= check_trunc_val != (double)sval;
+- }
+- r_param->buffer_length= 2;
+- }
+- break;
+- case MYSQL_TYPE_LONG:
+- {
+- if (r_param->is_unsigned)
+- {
+- uint32 lval= (uint32)val;
+- longstore(buf, lval);
+- *r_param->error= (check_trunc_val != (double)lval);
+- } else {
+- int32 lval= (int32)val;
+- longstore(buf, lval);
+- *r_param->error= (check_trunc_val != (double)lval);
+- }
+- r_param->buffer_length= 4;
+- }
+- break;
+- case MYSQL_TYPE_LONGLONG:
+- {
+- if (r_param->is_unsigned)
+- {
+- ulonglong llval= (ulonglong)val;
+- longlongstore(buf, llval);
+- *r_param->error= (check_trunc_val != (double)llval);
+- } else {
+- longlong llval= (longlong)val;
+- longlongstore(buf, llval);
+- *r_param->error= (check_trunc_val != (double)llval);
+- }
+- r_param->buffer_length= 8;
+- }
+- break;
+- case MYSQL_TYPE_FLOAT:
+- {
+- float fval= (float)val;
+- memcpy(buf, &fval, sizeof(float));
+- *r_param->error= (*(float*)buf != fval);
+- r_param->buffer_length= 4;
+- }
+- break;
+- case MYSQL_TYPE_DOUBLE:
+- {
+- memcpy(buf, &val, sizeof(double));
+- r_param->buffer_length= 8;
+- }
+- break;
+- default:
+- {
+- #define MAX_DOUBLE_STRING_REP_LENGTH 300
+- char buff[MAX_DOUBLE_STRING_REP_LENGTH];
+- char *end;
+- size_t length;
+-
+- length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length);
+-
+- /* TODO: move this to a header shared between client and server. */
+- if (field->decimals >= NOT_FIXED_DEC)
+- {
+- sprintf(buff, "%-*.*g", (int) length-1, DBL_DIG, val);
+- length= strlen(buff);
+- }
+- else
+- {
+- sprintf(buff, "%.*f", field->decimals, val);
+- length= strlen(buff);
+- }
+-
+- /* remove possible trailing blanks */
+- if ((end= strcend(buff, ' ')))
+- *end= 0;
+-
+- /* check if ZEROFILL flag is active */
+- if (field->flags & ZEROFILL_FLAG)
+- {
+- /* enough space available ? */
+- if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1)
+- break;
+- bmove_upp(buff + field->length, buff + length, length);
+- bfill((char*) buff, field->length - length, '0');
+- }
+- convert_from_string(r_param, buff, strlen(buff));
+- }
+- break;
+- }
+-}
+-
+-
+-/* {{{ ps_fetch_float */
+-static
+-void ps_fetch_float(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row)
+-{
+- switch(r_param->buffer_type)
+- {
+- case MYSQL_TYPE_FLOAT:
+- {
+- float *value= (float *)r_param->buffer;
+- float4get(*value, *row);
+- r_param->buffer_length= 4;
+- *r_param->error= 0;
+- }
+- break;
+- default:
+- {
+- float value;
+- memcpy(&value, *row, sizeof(float));
+- float4get(value, (char *)*row);
+- convert_from_float(r_param, field, value, sizeof(float));
+- }
+- break;
+- }
+- (*row)+= 4;
+-}
+-/* }}} */
+-
+-
+-/* {{{ ps_fetch_double */
+-static
+-void ps_fetch_double(MYSQL_BIND *r_param, const MYSQL_FIELD * field , unsigned char **row)
+-{
+- switch (r_param->buffer_type)
+- {
+- case MYSQL_TYPE_DOUBLE:
+- {
+- double *value= (double *)r_param->buffer;
+- float8get(*value, *row);
+- r_param->buffer_length= 8;
+- }
+- break;
+- default:
+- {
+- double value;
+- float8get(value, *row);
+- convert_from_float(r_param, field, value, sizeof(double));
+- }
+- break;
+- }
+- (*row)+= 8;
+-}
+-/* }}} */
+-
+-
+-static void convert_to_datetime(MYSQL_TIME *t, unsigned char **row, uint len, enum enum_field_types type)
+-{
+- memset(t, 0, sizeof(MYSQL_TIME));
+-
+- /* binary protocol for datetime:
+- 4-bytes: DATE
+- 7-bytes: DATE + TIME
+- >7 bytes: DATE + TIME with second_part
+- */
+-
+- if (len)
+- {
+- unsigned char *to= *row;
+- int has_date= 0, has_time= 0;
+- uint offset= 7;
+-
+- if (type == MYSQL_TYPE_TIME)
+- {
+- t->neg= to[0];
+- t->day= (ulong) sint4korr(to + 1);
+- t->time_type= MYSQL_TIMESTAMP_TIME;
+- offset= 8;
+- to++;
+- } else
+- {
+- t->year= (uint) sint2korr(to);
+- t->month= (uint) to[2];
+- t->day= (uint) to[3];
+- t->time_type= MYSQL_TIMESTAMP_DATE;
+- if (type == MYSQL_TYPE_DATE)
+- return;
+- has_date= 1;
+- }
+-
+- if (len > 4)
+- {
+- has_time= 1;
+- t->hour= (uint) to[4];
+- t->minute= (uint) to[5];
+- t->second= (uint) to[6];
+- if (has_date)
+- t->time_type= MYSQL_TIMESTAMP_DATETIME;
+- }
+- if (len > offset)
+- {
+- t->second_part= (ulong)sint4korr(to+7);
+- }
+- }
+-}
+-
+-
+-/* {{{ ps_fetch_datetime */
+-static
+-void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field,
+- unsigned char **row)
+-{
+- MYSQL_TIME *t= (MYSQL_TIME *)r_param->buffer;
+- unsigned int len= net_field_length(row);
+-
+- switch (r_param->buffer_type) {
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- convert_to_datetime(t, row, len, field->type);
+- break;
+- case MYSQL_TYPE_DATE:
+- convert_to_datetime(t, row, len, field->type);
+- break;
+- case MYSQL_TYPE_TIME:
+- convert_to_datetime(t, row, len, field->type);
+- if (t->day)
+- {
+- t->hour+= t->day * 24;
+- t->day= 0;
+- }
+- t->year= t->day= t->month= 0;
+- break;
+- case MYSQL_TYPE_YEAR:
+- {
+- MYSQL_TIME tm;
+- convert_to_datetime(&tm, row, len, field->type);
+- shortstore(r_param->buffer, tm.year);
+- break;
+- }
+- default:
+- {
+- char dtbuffer[60];
+- MYSQL_TIME tm;
+- unsigned int length;
+- convert_to_datetime(&tm, row, len, field->type);
+-
+- if (tm.time_type== MYSQL_TIMESTAMP_TIME && tm.day)
+- {
+- tm.hour+= tm.day * 24;
+- tm.day=0;
+- }
+- switch(field->type) {
+- case MYSQL_TYPE_DATE:
+- length= sprintf(dtbuffer, "%04u-%02u-%02u", tm.year, tm.month, tm.day);
+- break;
+- case MYSQL_TYPE_TIME:
+- length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second);
+- break;
+- case MYSQL_TYPE_DATETIME:
+- case MYSQL_TYPE_TIMESTAMP:
+- length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
+- break;
+- default:
+- dtbuffer[0]= 0;
+- length= 0;
+- break;
+- }
+- convert_from_string(r_param, dtbuffer, length);
+- break;
+- }
+- }
+- (*row) += len;
+-}
+-/* }}} */
+-
+-/* {{{ ps_fetch_string */
+-static
+-void ps_fetch_string(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
+- unsigned char **row)
+-{
+- /* C-API differs from PHP. While PHP just converts string to string,
+- C-API needs to convert the string to the defined type with in
+- the result bind buffer.
+- */
+- ulong field_length= net_field_length(row);
+-
+- convert_from_string(r_param, (char *)*row, field_length);
+- (*row) += field_length;
+-}
+-/* }}} */
+-
+-/* {{{ ps_fetch_bin */
+-static
+-void ps_fetch_bin(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
+- unsigned char **row)
+-{
+- ulong field_length= net_field_length(row);
+- size_t copylen;
+-
+- copylen= MIN(field_length, r_param->buffer_length);
+- memcpy(r_param->buffer, *row, copylen);
+- *r_param->error= copylen < field_length;
+- *r_param->length= field_length;
+-
+- (*row) += field_length;
+-}
+-/* }}} */
+-
+-/* {{{ _mysqlnd_init_ps_subsystem */
+-void mysql_init_ps_subsystem(void)
+-{
+- memset(mysql_ps_fetch_functions, 0, sizeof(mysql_ps_fetch_functions));
+- mysql_ps_fetch_functions[MYSQL_TYPE_NULL].func= ps_fetch_null;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NULL].max_len = 0;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY].max_len = 4;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
+- mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
+- mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].max_len = 6;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
+- mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
+- mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].max_len = 6;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
+- mysql_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
+- mysql_ps_fetch_functions[MYSQL_TYPE_INT24].max_len = 9;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG].max_len = 11;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].max_len = 21;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
+- mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
+- mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
+- mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = 13;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 15;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = 5;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= 12;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= 12;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_bin;
+- mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_bin;
+- mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_bin;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bin;
+- mysql_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
+- mysql_ps_fetch_functions[MYSQL_TYPE_BIT].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_STRING].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_SET].max_len = -1;
+-
+- mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
+- mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQL_PS_SKIP_RESULT_STR;
+- mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].max_len = -1;
+-
+- mysql_ps_subsystem_initialized= 1;
+-}
+-/* }}} */
+-
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * End:
+- * vim600: noet sw=4 ts=4 fdm=marker
+- * vim<600: noet sw=4 ts=4
+- */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_symlink.c mariadb-native-client.trunk/libmysql/my_symlink.c
+--- mariadb/libmysql/my_symlink.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_symlink.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,138 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <m_string.h>
+-#include <errno.h>
+-#ifdef HAVE_REALPATH
+-#include <sys/param.h>
+-#include <sys/stat.h>
+-#endif
+-
+-/*
+- Reads the content of a symbolic link
+- If the file is not a symbolic link, return the original file name in to.
+- Returns: 0 if table was a symlink,
+- 1 if table was a normal file
+- -1 on error.
+-*/
+-
+-int my_readlink(char *to, const char *filename, myf MyFlags)
+-{
+-#ifndef HAVE_READLINK
+- strmov(to,filename);
+- return 1;
+-#else
+- int result=0;
+- int length;
+- DBUG_ENTER("my_readlink");
+-
+- if ((length=readlink(filename, to, FN_REFLEN-1)) < 0)
+- {
+- /* Don't give an error if this wasn't a symlink */
+- if ((my_errno=errno) == EINVAL)
+- {
+- result= 1;
+- strmov(to,filename);
+- }
+- else
+- {
+- if (MyFlags & MY_WME)
+- my_error(EE_CANT_READLINK, MYF(0), filename, errno);
+- result= -1;
+- }
+- }
+- else
+- to[length]=0;
+- DBUG_RETURN(result);
+-#endif /* HAVE_READLINK */
+-}
+-
+-
+-/* Create a symbolic link */
+-
+-int my_symlink(const char *content, const char *linkname, myf MyFlags)
+-{
+-#ifndef HAVE_READLINK
+- return 0;
+-#else
+- int result;
+- DBUG_ENTER("my_symlink");
+-
+- result= 0;
+- if (symlink(content, linkname))
+- {
+- result= -1;
+- my_errno=errno;
+- if (MyFlags & MY_WME)
+- my_error(EE_CANT_SYMLINK, MYF(0), linkname, content, errno);
+- }
+- DBUG_RETURN(result);
+-#endif /* HAVE_READLINK */
+-}
+-
+-/*
+- Resolve all symbolic links in path
+- 'to' may be equal to 'filename'
+-
+- Because purify gives a lot of UMR errors when using realpath(),
+- this code is disabled when using purify.
+-
+- If MY_RESOLVE_LINK is given, only do realpath if the file is a link.
+-*/
+-
+-#if defined(SCO)
+-#define BUFF_LEN 4097
+-#elif defined(MAXPATHLEN)
+-#define BUFF_LEN MAXPATHLEN
+-#else
+-#define BUFF_LEN FN_LEN
+-#endif
+-
+-int my_realpath(char *to, const char *filename, myf MyFlags)
+-{
+-#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
+- int result=0;
+- char buff[BUFF_LEN];
+- struct stat stat_buff;
+- DBUG_ENTER("my_realpath");
+-
+- if (!(MyFlags & MY_RESOLVE_LINK) ||
+- (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+- {
+- char *ptr;
+- if ((ptr=realpath(filename,buff)))
+- strmake(to,ptr,FN_REFLEN-1);
+- else
+- {
+- /* Realpath didn't work; Use original name */
+- my_errno=errno;
+- if (MyFlags & MY_WME)
+- my_error(EE_REALPATH, MYF(0), filename, my_errno);
+- if (to != filename)
+- strmov(to,filename);
+- result= -1;
+- }
+- }
+- DBUG_RETURN(result);
+-#else
+- if (to != filename)
+- strmov(to,filename);
+- return 0;
+-#endif
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/mysys_priv.h mariadb-native-client.trunk/libmysql/mysys_priv.h
+--- mariadb/libmysql/mysys_priv.h 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/mysys_priv.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,32 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include <my_global.h>
+-#include <my_sys.h>
+-
+-#ifdef USE_SYSTEM_WRAPPERS
+-#include "system_wrappers.h"
+-#endif
+-
+-#ifdef THREAD
+-#include <my_pthread.h>
+-extern pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+- THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_net,THR_LOCK_charset;
+-extern pthread_mutex_t LOCK_bitmap;
+-#else
+-#include <my_no_pthread.h>
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_thr_init.c mariadb-native-client.trunk/libmysql/my_thr_init.c
+--- mariadb/libmysql/my_thr_init.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_thr_init.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,243 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+-** Functions to handle initializating and allocationg of all mysys & debug
+-** thread variables.
+-*/
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+-#ifdef THREAD
+-#ifdef USE_TLS
+-pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
+-#else
+-pthread_key(struct st_my_thread_var, THR_KEY_mysys);
+-#endif /* USE_TLS */
+-pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+- THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
+- THR_LOCK_net, THR_LOCK_charset;
+-#ifdef HAVE_OPENSSL
+-pthread_mutex_t LOCK_ssl_config;
+-#endif
+-#ifndef HAVE_LOCALTIME_R
+-pthread_mutex_t LOCK_localtime_r;
+-#endif
+-#ifndef HAVE_GETHOSTBYNAME_R
+-pthread_mutex_t LOCK_gethostbyname_r;
+-#endif
+-#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+-pthread_mutexattr_t my_fast_mutexattr;
+-#endif
+-#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+-pthread_mutexattr_t my_errchk_mutexattr;
+-#endif
+-
+-/* FIXME Note. TlsAlloc does not set an auto destructor, so
+- the function my_thread_global_free must be called from
+- somewhere before final exit of the library */
+-
+-my_bool my_thread_global_init(void)
+-{
+- if (pthread_key_create(&THR_KEY_mysys,free))
+- {
+- fprintf(stderr,"Can't initialize threads: error %d\n",errno);
+- exit(1);
+- }
+-#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+- pthread_mutexattr_init(&my_fast_mutexattr);
+- pthread_mutexattr_setkind_np(&my_fast_mutexattr,PTHREAD_MUTEX_ADAPTIVE_NP);
+-#endif
+-#ifdef PPTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+- pthread_mutexattr_init(&my_errchk_mutexattr);
+- pthread_mutexattr_setkind_np(&my_errchk_mutexattr,
+- PTHREAD_MUTEX_ERRORCHECK_NP);
+-#endif
+-#ifdef HAVE_OPENSSL
+- pthread_mutex_init(&LOCK_ssl_config,MY_MUTEX_INIT_FAST);
+-#endif
+- pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_keycache,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
+- pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
+- pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
+- pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
+-#ifdef _WIN32
+- /* win_pthread_init(); */
+-#endif
+-#ifndef HAVE_LOCALTIME_R
+- pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
+-#endif
+-#ifndef HAVE_GETHOSTBYNAME_R
+- pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
+-#endif
+- return my_thread_init();
+-}
+-
+-void my_thread_global_end(void)
+-{
+-#if defined(USE_TLS)
+- (void) TlsFree(THR_KEY_mysys);
+-#endif
+-#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+- pthread_mutexattr_destroy(&my_fast_mutexattr);
+-#endif
+-#ifdef PPTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+- pthread_mutexattr_destroy(&my_errchk_mutexattr);
+-#endif
+-#ifdef HAVE_OPENSSL
+- pthread_mutex_destroy(&LOCK_ssl_config);
+-#endif
+-#ifndef HAVE_GETHOSTBYNAME_R
+- pthread_mutex_destroy(&LOCK_gethostbyname_r);
+-#endif
+-}
+-
+-static long thread_id=0;
+-
+-/*
+- We can't use mutex_locks here if we are using windows as
+- we may have compiled the program with SAFE_MUTEX, in which
+- case the checking of mutex_locks will not work until
+- the pthread_self thread specific variable is initialized.
+-*/
+-
+-my_bool my_thread_init(void)
+-{
+- struct st_my_thread_var *tmp;
+-#if !defined(_WIN32) || defined(USE_TLS) || ! defined(SAFE_MUTEX)
+- pthread_mutex_lock(&THR_LOCK_lock);
+-#endif
+-#if !defined(_WIN32) || defined(USE_TLS)
+- if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
+- {
+- pthread_mutex_unlock(&THR_LOCK_lock);
+- return 0; /* Safequard */
+- }
+- /* We must have many calloc() here because these are freed on
+- pthread_exit */
+- if (!(tmp=(struct st_my_thread_var *)
+- calloc(1,sizeof(struct st_my_thread_var))))
+- {
+- pthread_mutex_unlock(&THR_LOCK_lock);
+- return 1;
+- }
+- pthread_setspecific(THR_KEY_mysys,tmp);
+-
+-#else
+- if (THR_KEY_mysys.id) /* Already initialized */
+- {
+-#if !defined(_WIN32) || defined(USE_TLS) || ! defined(SAFE_MUTEX)
+- pthread_mutex_unlock(&THR_LOCK_lock);
+-#endif
+- return 0;
+- }
+- tmp= &THR_KEY_mysys;
+-#endif
+- tmp->id= ++thread_id;
+- pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
+- pthread_cond_init(&tmp->suspend, NULL);
+-#if !defined(_WIN32) || defined(USE_TLS) || ! defined(SAFE_MUTEX)
+- pthread_mutex_unlock(&THR_LOCK_lock);
+-#endif
+- return 0;
+-}
+-
+-void my_thread_end(void)
+-{
+- struct st_my_thread_var *tmp=my_thread_var;
+- if (tmp)
+- {
+-#if !defined(DBUG_OFF)
+- if (tmp->dbug)
+- {
+- free(tmp->dbug);
+- tmp->dbug=0;
+- }
+-#endif
+-#if !defined(__bsdi__) || defined(HAVE_mit_thread) /* bsdi dumps core here */
+- pthread_cond_destroy(&tmp->suspend);
+-#endif
+- pthread_mutex_destroy(&tmp->mutex);
+-#if (!defined(_WIN32) && !defined(OS2)) || defined(USE_TLS)
+- free(tmp);
+-#endif
+- }
+-#if (!defined(_WIN32) && !defined(OS2)) || defined(USE_TLS)
+- pthread_setspecific(THR_KEY_mysys,0);
+-#endif
+-}
+-
+-struct st_my_thread_var *_my_thread_var(void)
+-{
+- struct st_my_thread_var *tmp=
+- my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+-#if defined(USE_TLS)
+- /* This can only happen in a .DLL */
+- if (!tmp)
+- {
+- my_thread_init();
+- tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+- }
+-#endif
+- return tmp;
+-}
+-
+-/****************************************************************************
+-** Get name of current thread.
+-****************************************************************************/
+-
+-#define UNKNOWN_THREAD -1
+-
+-long my_thread_id()
+-{
+-#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
+- return pthread_getsequence_np(pthread_self());
+-#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) && !defined(HAVE_mit_thread)
+- return pthread_self();
+-#else
+- return my_thread_var->id;
+-#endif
+-}
+-
+-#ifdef DBUG_OFF
+-const char *my_thread_name(void)
+-{
+- return "no_name";
+-}
+-
+-#else
+-
+-const char *my_thread_name(void)
+-{
+- char name_buff[100];
+- struct st_my_thread_var *tmp=my_thread_var;
+- if (!tmp->name[0])
+- {
+- long id=my_thread_id();
+- sprintf(name_buff,"T@%ld", id);
+- strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
+- }
+- return tmp->name;
+-}
+-#endif /* DBUG_OFF */
+-
+-#endif /* THREAD */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_vsnprintf.c mariadb-native-client.trunk/libmysql/my_vsnprintf.c
+--- mariadb/libmysql/my_vsnprintf.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/my_vsnprintf.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,119 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <m_string.h>
+-#include <stdarg.h>
+-#include <m_ctype.h>
+-
+-
+-int my_snprintf(char* to, size_t n, const char* fmt, ...)
+-{
+- int result;
+- va_list args;
+- va_start(args,fmt);
+- result= my_vsnprintf(to, n, fmt, args);
+- va_end(args);
+- return result;
+-}
+-
+-
+-int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
+-{
+- char *start=to, *end=to+n-1;
+- for (; *fmt ; fmt++)
+- {
+- if (fmt[0] != '%')
+- {
+- if (to == end) /* End of buffer */
+- break;
+- *to++= *fmt; /* Copy ordinary char */
+- continue;
+- }
+- /* Skipp if max size is used (to be compatible with printf) */
+- fmt++;
+- while (isdigit(*fmt) || *fmt == '.' || *fmt == '-')
+- fmt++;
+- if (*fmt == 'l')
+- fmt++;
+- if (*fmt == 's') /* String parameter */
+- {
+- reg2 char *par = va_arg(ap, char *);
+- uint plen;
+- if (!par) par = (char*)"(null)";
+- plen = (uint) strlen(par);
+- if ((uint) (end-to) > plen) /* Replace if possible */
+- {
+- to=strmov(to,par);
+- continue;
+- }
+- }
+- else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
+- {
+- register int iarg;
+- if ((uint) (end-to) < 16)
+- break;
+- iarg = va_arg(ap, int);
+- if (*fmt == 'd')
+- to=int10_to_str((long) iarg,to, -10);
+- else
+- to=int10_to_str((long) (uint) iarg,to,10);
+- continue;
+- }
+- /* We come here on '%%', unknown code or too long parameter */
+- if (to == end)
+- break;
+- *to++='%'; /* % used as % or unknown code */
+- }
+- *to='\0'; /* End of errmessage */
+- return (uint) (to - start);
+-}
+-
+-
+-#ifdef MAIN
+-static void my_printf(const char * fmt, ...)
+-{
+- char buf[32];
+- int n;
+- va_list ar;
+- va_start(ar, fmt);
+- n = my_vsnprintf(buf, sizeof(buf),fmt, ar);
+- printf(buf);
+- printf("n=%d, strlen=%d\n", n, strlen(buf));
+- va_end(ar);
+-}
+-
+-
+-int main()
+-{
+-
+- my_printf("Hello\n");
+- my_printf("Hello int, %d\n", 1);
+- my_printf("Hello string '%s'\n", "I am a string");
+- my_printf("Hello hack hack hack hack hack hack hack %d\n", 1);
+- my_printf("Hello %d hack %d\n", 1, 4);
+- my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4);
+- my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
+- my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
+- my_printf("Hello %u\n", 1);
+- my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\
+- `%-.64s' (%-.64s)", 1, 0,0,0,0);
+- return 0;
+-}
+-#endif
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/my_write.c mariadb-native-client.trunk/libmysql/my_write.c
+--- mariadb/libmysql/my_write.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/my_write.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,90 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-#include "mysys_priv.h"
+-#include "mysys_err.h"
+-#include <errno.h>
+-
+-
+- /* Write a chunk of bytes to a file */
+-
+-uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
+-{
+- uint writenbytes,errors;
+- ulong written;
+- DBUG_ENTER("my_write");
+- DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %d MyFlags: %d",
+- Filedes, Buffer, Count, MyFlags));
+- errors=0; written=0L;
+-
+- for (;;)
+- {
+- if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+- break;
+- if ((int) writenbytes != -1)
+- { /* Safeguard */
+- written+=writenbytes;
+- Buffer+=writenbytes;
+- Count-=writenbytes;
+- }
+- my_errno=errno;
+- DBUG_PRINT("error",("Write only %d bytes, error: %d",
+- writenbytes,my_errno));
+-#ifndef NO_BACKGROUND
+-#ifdef THREAD
+- if (my_thread_var->abort)
+- MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+-#endif
+- if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL) &&
+- (uint) writenbytes != (uint) -1)
+- {
+- if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+- my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
+- my_filename(Filedes));
+- VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
+- continue;
+- }
+- if (!writenbytes)
+- {
+- /* We may come here on an interrupt or if the file quote is exeeded */
+- if (my_errno == EINTR)
+- continue;
+- if (!errors++) /* Retry once */
+- {
+- errno=EFBIG; /* Assume this is the error */
+- continue;
+- }
+- }
+- else if ((uint) writenbytes != (uint) -1)
+- continue; /* Retry */
+-#endif
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- {
+- if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+- {
+- my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+- my_filename(Filedes),my_errno);
+- }
+- DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
+- }
+- else
+- break; /* Return bytes written */
+- }
+- if (MyFlags & (MY_NABP | MY_FNABP))
+- DBUG_RETURN(0); /* Want only errors */
+- DBUG_RETURN(writenbytes+written);
+-} /* my_write */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/net.c mariadb-native-client.trunk/libmysql/net.c
+--- mariadb/libmysql/net.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/net.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,732 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Write and read of logical packets to/from socket
+-** Writes are cached into net_buffer_length big packets.
+-** Read packets are reallocated dynamicly when reading big packets.
+-** Each logical packet has the following pre-info:
+-** 3 byte length & 1 byte package-number.
+-*/
+-
+-#include <my_global.h>
+-#include <violite.h>
+-#include <my_sys.h>
+-#include <m_string.h>
+-#include "mysql.h"
+-#include "mysqld_error.h"
+-#include <signal.h>
+-#include <errno.h>
+-#include <sys/types.h>
+-#ifdef MYSQL_SERVER
+-#include <violite.h>
+-#endif
+-
+-#define MAX_PACKET_LENGTH (256L*256L*256L-1)
+-
+-ulong max_allowed_packet=1024L * 1024L * 1024L;
+-ulong net_read_timeout= NET_READ_TIMEOUT;
+-ulong net_write_timeout= NET_WRITE_TIMEOUT;
+-ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+-
+-#if !defined(_WIN32) && !defined(MSDOS)
+-#include <sys/socket.h>
+-#else
+-#undef MYSQL_SERVER /* Win32 can't handle interrupts */
+-#endif
+-#if !defined(MSDOS) && !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
+-#include <netinet/in_systm.h>
+-#include <netinet/in.h>
+-#include <netinet/ip.h>
+-#if !defined(alpha_linux_port)
+-#include <netinet/tcp.h>
+-#endif
+-#endif
+-#include "mysqld_error.h"
+-#ifdef MYSQL_SERVER
+-#include "my_pthread.h"
+-#include "thr_alarm.h"
+-void sql_print_error(const char *format,...);
+-#define RETRY_COUNT mysqld_net_retry_count
+-extern ulong mysqld_net_retry_count;
+-#else
+-
+-#ifdef OS2 /* avoid name conflict */
+-#define thr_alarm_t thr_alarm_t_net
+-#define ALARM ALARM_net
+-#endif
+-
+-typedef my_bool thr_alarm_t;
+-typedef my_bool ALARM;
+-#define thr_alarm_init(A) (*(A))=0
+-#define thr_alarm_in_use(A) (*(A))
+-#define thr_end_alarm(A)
+-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
+-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
+-{
+- *A=1;
+- return 0;
+-}
+-#define thr_got_alarm(A) 0
+-#define RETRY_COUNT 1
+-#endif
+-
+-#ifdef MYSQL_SERVER
+-extern ulong bytes_sent, bytes_received;
+-extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+-#else
+-#undef statistic_add
+-#define statistic_add(A,B,C)
+-#endif
+-
+-/*
+-** Give error if a too big packet is found
+-** The server can change this with the -O switch, but because the client
+-** can't normally do this the client should have a bigger max-buffer.
+-*/
+-
+-#define TEST_BLOCKING 8
+-static int net_write_buff(NET *net,const char *packet, size_t len);
+-
+-
+- /* Init with packet info */
+-
+-int my_net_init(NET *net, Vio* vio)
+-{
+- if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+- return 1;
+- if (net_buffer_length > max_allowed_packet)
+- max_allowed_packet=net_buffer_length;
+- net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+- net->vio = vio;
+- net->error=0; net->return_status=0;
+- net->read_timeout=(uint) net_read_timeout; /* Timeout for read */
+- net->pkt_nr=0;
+- net->write_pos=net->read_pos = net->buff;
+- net->last_error[0]= net->sqlstate[0] =0;
+-
+- net->compress=0; net->reading_or_writing=0;
+- net->where_b = net->remain_in_buf=0;
+- net->last_errno=0;
+-
+- if (vio != 0) /* If real connection */
+- {
+- net->fd = vio_fd(vio); /* For perl DBI/DBD */
+-#if defined(MYSQL_SERVER) && !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
+- if (!(test_flags & TEST_BLOCKING))
+- vio_blocking(vio, FALSE);
+-#endif
+- vio_fastsend(vio);
+- }
+- return 0;
+-}
+-
+-void net_end(NET *net)
+-{
+- my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+- net->buff=0;
+-}
+-
+-/* Realloc the packet buffer */
+-
+-static my_bool net_realloc(NET *net, size_t length)
+-{
+- uchar *buff;
+- ulong pkt_length;
+-
+- DBUG_ENTER("net_realloc");
+- DBUG_PRINT("info", ("length: %lu max_allowed_packet: %lu",
+- (ulong)length, max_allowed_packet));
+-
+- if (length >= max_allowed_packet)
+- {
+- DBUG_PRINT("error",("Packet too large (%lu)", length));
+- net->error=1;
+- net->last_errno=ER_NET_PACKET_TOO_LARGE;
+- DBUG_RETURN(1);
+- }
+- pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+- {
+- DBUG_PRINT("info", ("Out of memory"));
+- net->error=1;
+-#ifdef MYSQL_SERVER
+- net->last_errno=ER_OUT_OF_RESOURCES;
+-#endif
+- DBUG_RETURN(1);
+- }
+- net->buff=net->write_pos=buff;
+- net->buff_end=buff+(net->max_packet=pkt_length);
+- DBUG_RETURN(0);
+-}
+-
+- /* Remove unwanted characters from connection */
+-
+-void net_clear(NET *net)
+-{
+-#ifndef EXTRA_DEBUG
+- int count; /* One may get 'unused' warning */
+- bool is_blocking=vio_is_blocking(net->vio);
+- if (is_blocking)
+- vio_blocking(net->vio, FALSE);
+- if (!vio_is_blocking(net->vio)) /* Safety if SSL */
+- {
+- while ( (count = vio_read(net->vio, (char*) (net->buff),
+- net->max_packet)) > 0)
+- DBUG_PRINT("info",("skipped %d bytes from file: %s",
+- count,vio_description(net->vio)));
+- if (is_blocking)
+- vio_blocking(net->vio, TRUE);
+- }
+-#endif /* EXTRA_DEBUG */
+- net->pkt_nr=0; /* Ready for new command */
+- net->write_pos=net->buff;
+-}
+-
+- /* Flush write_buffer if not empty. */
+-
+-int net_flush(NET *net)
+-{
+- int error=0;
+- DBUG_ENTER("net_flush");
+- if (net->buff != net->write_pos)
+- {
+- error=net_real_write(net,(char*) net->buff,
+- (uint) (net->write_pos - net->buff));
+- net->write_pos=net->buff;
+- }
+- DBUG_RETURN(error);
+-}
+-
+-
+-/*****************************************************************************
+-** Write something to server/client buffer
+-*****************************************************************************/
+-
+-
+-/*
+-** Write a logical packet with packet header
+-** Format: Packet length (3 bytes), packet number(1 byte)
+-** When compression is used a 3 byte compression length is added
+-** NOTE: If compression is used the original package is destroyed!
+-*/
+-
+-int
+-my_net_write(NET *net, const char *packet, size_t len)
+-{
+- uchar buff[NET_HEADER_SIZE];
+- if (len >= MAX_PACKET_LENGTH)
+- {
+- net->error=1;
+- net->last_errno=ER_NET_PACKET_TOO_LARGE;
+- return 1;
+- }
+- int3store(buff,len);
+- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+- if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+- return 1;
+- return net_write_buff(net,packet,len);
+-}
+-
+-int
+-net_write_command(NET *net, uchar command,
+- const char *packet, size_t len)
+-{
+- uchar buff[NET_HEADER_SIZE+1];
+- size_t buff_size= NET_HEADER_SIZE + 1;
+- size_t length= 1 + len; /* 1 extra byte for command */
+- int rc;
+-
+- buff[4]=command;
+-
+- if (length >= MAX_PACKET_LENGTH)
+- {
+- len= MAX_PACKET_LENGTH - 1;
+- do
+- {
+- int3store(buff, MAX_PACKET_LENGTH);
+- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+-
+- if (net_write_buff(net, (char *)buff, buff_size) ||
+- net_write_buff(net, packet, len))
+- return(1);
+- packet+= len;
+- length-= MAX_PACKET_LENGTH;
+- len= MAX_PACKET_LENGTH;
+- buff_size= NET_HEADER_SIZE; /* don't send command for further packets */
+- } while (length >= MAX_PACKET_LENGTH);
+- len= length;
+- }
+- int3store(buff,length);
+- buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+- rc= test (net_write_buff(net,(char *)buff, buff_size) ||
+- net_write_buff(net,packet,len) ||
+- net_flush(net));
+- return rc;
+-}
+-
+-
+-static int
+-net_write_buff(NET *net,const char *packet, size_t len)
+-{
+- size_t left_length=(size_t) (net->buff_end - net->write_pos);
+-
+- if (len > left_length)
+- {
+- if (net->write_pos != net->buff)
+- {
+- memcpy((char*) net->write_pos,packet,left_length);
+- if (net_real_write(net,(char*) net->buff,
+- (size_t)(net->write_pos - net->buff) + left_length))
+- return 1;
+- packet+=left_length;
+- len-=left_length;
+- net->write_pos= net->buff;
+- }
+- if (len > net->max_packet)
+- return(test(net_real_write(net, packet, len)));
+- }
+- memcpy((char*) net->write_pos,packet,len);
+- net->write_pos+=len;
+- return 0;
+-}
+-
+-/* Read and write using timeouts */
+-
+-int
+-net_real_write(NET *net,const char *packet,ulong len)
+-{
+- int length;
+- char *pos,*end;
+- thr_alarm_t alarmed;
+-#if !defined(_WIN32) && !defined(__EMX__) && !defined(OS2)
+- ALARM alarm_buff;
+-#endif
+- uint retry_count=0;
+- my_bool net_blocking = vio_is_blocking(net->vio);
+- DBUG_ENTER("net_real_write");
+-
+- if (net->error == 2)
+- DBUG_RETURN(-1); /* socket can't be used */
+-
+- net->reading_or_writing=2;
+-#ifdef HAVE_COMPRESS
+- if (net->compress)
+- {
+- ulong complen;
+- uchar *b;
+- uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
+- if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
+- MYF(MY_WME))))
+- {
+-#ifdef MYSQL_SERVER
+- net->last_errno=ER_OUT_OF_RESOURCES;
+- net->error=2;
+-#endif
+- net->reading_or_writing=0;
+- DBUG_RETURN(1);
+- }
+- memcpy(b+header_length,packet,len);
+-
+- if (my_compress((byte*) b+header_length,&len,&complen))
+- {
+- DBUG_PRINT("warning",
+- ("Compression error; Continuing without compression"));
+- complen=0;
+- }
+- int3store(&b[NET_HEADER_SIZE],complen);
+- int3store(b,len);
+- b[3]=(uchar) (net->pkt_nr++);
+- len+= header_length;
+- packet= (char*) b;
+- }
+-#endif /* HAVE_COMPRESS */
+-
+- /* DBUG_DUMP("net",packet,len); */
+-#ifdef MYSQL_SERVER
+- thr_alarm_init(&alarmed);
+- if (net_blocking)
+- thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff);
+-#else
+- alarmed=0;
+-#endif /* MYSQL_SERVER */
+-
+- pos=(char*) packet; end=pos+len;
+- while (pos != end)
+- {
+- if ((int) (length=vio_write(net->vio,pos,(int) (end-pos))) <= 0)
+- {
+- my_bool interrupted = vio_should_retry(net->vio);
+-#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2))
+- if ((interrupted || length==0) && !thr_alarm_in_use(&alarmed))
+- {
+- if (!thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff))
+- { /* Always true for client */
+- if (!vio_is_blocking(net->vio))
+- {
+- while (vio_blocking(net->vio, TRUE) < 0)
+- {
+- if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+- continue;
+-#ifdef EXTRA_DEBUG
+- fprintf(stderr,
+- "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+- my_progname,vio_errno(net->vio));
+-#endif /* EXTRA_DEBUG */
+- net->error=2; /* Close socket */
+- goto end;
+- }
+- }
+- retry_count=0;
+- continue;
+- }
+- }
+- else
+-#endif /* (!defined(_WIN32) && !defined(__EMX__)) */
+- if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
+- interrupted)
+- {
+- if (retry_count++ < RETRY_COUNT)
+- continue;
+-#ifdef EXTRA_DEBUG
+- fprintf(stderr, "%s: write looped, aborting thread\n",
+- my_progname);
+-#endif /* EXTRA_DEBUG */
+- }
+-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+- if (vio_errno(net->vio) == SOCKET_EINTR)
+- {
+- DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+- continue;
+- }
+-#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+- net->error=2; /* Close socket */
+-#ifdef MYSQL_SERVER
+- net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+- ER_NET_ERROR_ON_WRITE);
+-#endif /* MYSQL_SERVER */
+- break;
+- }
+- pos+=length;
+- statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+- }
+-#ifndef _WIN32
+- end:
+-#endif
+-#ifdef HAVE_COMPRESS
+- if (net->compress)
+- my_free((char*) packet,MYF(0));
+-#endif
+- if (thr_alarm_in_use(&alarmed))
+- {
+- thr_end_alarm(&alarmed);
+- vio_blocking(net->vio, net_blocking);
+- }
+- net->reading_or_writing=0;
+- DBUG_RETURN(((int) (pos != end)));
+-}
+-
+-
+-/*****************************************************************************
+-** Read something from server/clinet
+-*****************************************************************************/
+-
+-#ifdef MYSQL_SERVER
+-
+-/*
+- Help function to clear the commuication buffer when we get a too
+- big packet
+-*/
+-
+-static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed,
+- ALARM *alarm_buff)
+-{
+- uint retry_count=0;
+- if (!thr_alarm_in_use(alarmed))
+- {
+- if (thr_alarm(alarmed,net->timeout,alarm_buff) ||
+- (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
+- return; /* Can't setup, abort */
+- }
+- while (remain > 0)
+- {
+- ulong length;
+- if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
+- {
+- my_bool interrupted = vio_should_retry(net->vio);
+- if (!thr_got_alarm(alarmed) && interrupted)
+- { /* Probably in MIT threads */
+- if (retry_count++ < RETRY_COUNT)
+- continue;
+- }
+- return;
+- }
+- remain -=(ulong) length;
+- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+- }
+-}
+-#endif /* MYSQL_SERVER */
+-
+-
+-static ulong
+-my_real_read(NET *net, size_t *complen)
+-{
+- uchar *pos;
+- size_t length;
+- uint i,retry_count=0;
+- ulong len=packet_error;
+- thr_alarm_t alarmed;
+-#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
+- ALARM alarm_buff;
+-#endif
+- my_bool net_blocking=vio_is_blocking(net->vio);
+- size_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+- NET_HEADER_SIZE);
+- *complen = 0;
+-
+- net->reading_or_writing=1;
+- thr_alarm_init(&alarmed);
+-#ifdef MYSQL_SERVER
+- if (net_blocking)
+- thr_alarm(&alarmed,net->timeout,&alarm_buff);
+-#endif /* MYSQL_SERVER */
+-
+- pos = net->buff + net->where_b; /* net->packet -4 */
+- for (i=0 ; i < 2 ; i++)
+- {
+- while (remain > 0)
+- {
+- /* First read is done with non blocking mode */
+- if ((long) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+- {
+- my_bool interrupted = vio_should_retry(net->vio);
+-
+- DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+- length, vio_errno(net->vio)));
+-#if (!defined(_WIN32) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
+- /*
+- We got an error that there was no data on the socket. We now set up
+- an alarm to not 'read forever', change the socket to non blocking
+- mode and try again
+- */
+- if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
+- {
+- if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
+- {
+- if (!vio_is_blocking(net->vio))
+- {
+- while (vio_blocking(net->vio,TRUE) < 0)
+- {
+- if (vio_should_retry(net->vio) &&
+- retry_count++ < RETRY_COUNT)
+- continue;
+- DBUG_PRINT("error",
+- ("fcntl returned error %d, aborting thread",
+- vio_errno(net->vio)));
+-#ifdef EXTRA_DEBUG
+- fprintf(stderr,
+- "%s: read: fcntl returned error %d, aborting thread\n",
+- my_progname,vio_errno(net->vio));
+-#endif /* EXTRA_DEBUG */
+- len= packet_error;
+- net->error=2; /* Close socket */
+-#ifdef MYSQL_SERVER
+- net->last_errno=ER_NET_FCNTL_ERROR;
+-#endif
+- goto end;
+- }
+- }
+- retry_count=0;
+- continue;
+- }
+- }
+-#endif /* (!defined(_WIN32) && !defined(__EMX__)) || defined(MYSQL_SERVER) */
+- if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
+- interrupted)
+- { /* Probably in MIT threads */
+- if (retry_count++ < RETRY_COUNT)
+- continue;
+-#ifdef EXTRA_DEBUG
+- fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+- my_progname,vio_errno(net->vio));
+-#endif /* EXTRA_DEBUG */
+- }
+-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+- if (vio_should_retry(net->vio))
+- {
+- DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+- continue;
+- }
+-#endif
+- DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+- len= packet_error;
+- net->error=2; /* Close socket */
+- goto end;
+- }
+- remain -= (ulong) length;
+- pos+= (ulong) length;
+- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+- }
+- if (i == 0)
+- { /* First parts is packet length */
+- ulong helping;
+- if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+- {
+- if (net->buff[net->where_b] != (uchar) 255)
+- {
+- DBUG_PRINT("error",
+- ("Packets out of order (Found: %d, expected %d)",
+- (int) net->buff[net->where_b + 3],
+- (uint) (uchar) net->pkt_nr));
+-#ifdef EXTRA_DEBUG
+- fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+- (int) net->buff[net->where_b + 3],
+- (uint) (uchar) net->pkt_nr);
+-#endif
+- }
+- len= packet_error;
+-#ifdef MYSQL_SERVER
+- net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+-#endif
+- goto end;
+- }
+- net->pkt_nr++;
+-#ifdef HAVE_COMPRESS
+- if (net->compress)
+- {
+- /* complen is > 0 if package is really compressed */
+- *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+- }
+-#endif
+-
+- len=uint3korr(net->buff+net->where_b);
+- if (!len)
+- goto end;
+- helping = max(len,*complen) + net->where_b;
+- /* The necessary size of net->buff */
+- if (helping >= net->max_packet)
+- {
+- /* We must allocate one extra byte for the end null */
+- if (net_realloc(net,helping))
+- {
+-#ifdef MYSQL_SERVER
+- if (i == 1)
+- my_net_skip_rest(net, len, &alarmed, &alarm_buff);
+-#endif
+- len= packet_error; /* Return error */
+- goto end;
+- }
+- }
+- pos=net->buff + net->where_b;
+- remain = len;
+- }
+- }
+-
+-end:
+- if (thr_alarm_in_use(&alarmed))
+- {
+- thr_end_alarm(&alarmed);
+- vio_blocking(net->vio, net_blocking);
+- }
+- net->reading_or_writing=0;
+- return(len);
+-}
+-
+-ulong my_net_read(NET *net)
+-{
+- ulong len,complen;
+-
+-#ifdef HAVE_COMPRESS
+- if (!net->compress)
+- {
+-#endif
+- len = my_real_read (net,(size_t *)&complen);
+- if (len == MAX_PACKET_LENGTH)
+- {
+- /* multi packet read */
+- size_t length= 0;
+- ulong last_pos= net->where_b;
+-
+- do
+- {
+- length+= len;
+- net->where_b+= len;
+- } while (len == MAX_PACKET_LENGTH);
+- net->where_b= last_pos;
+- if (len != packet_error)
+- len+= length;
+- }
+- net->read_pos = net->buff + net->where_b;
+- if (len != packet_error)
+- net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+- return len;
+-#ifdef HAVE_COMPRESS
+- }
+- if (net->remain_in_buf)
+- net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
+- for (;;)
+- {
+- if (net->remain_in_buf)
+- {
+- uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+- if (net->remain_in_buf >= 4)
+- {
+- net->length = uint3korr(pos);
+- if (net->length <= net->remain_in_buf - 4)
+- {
+- /* We have a full packet */
+- len=net->length;
+- net->remain_in_buf -= net->length + 4;
+- net->read_pos=pos + 4;
+- break; /* We have a full packet */
+- }
+- }
+- /* Move data down to read next data packet after current one */
+- if (net->buf_length != net->remain_in_buf)
+- {
+- memmove(net->buff,pos,net->remain_in_buf);
+- net->buf_length=net->remain_in_buf;
+- }
+- net->where_b=net->buf_length;
+- }
+- else
+- {
+- net->where_b=0;
+- net->buf_length=0;
+- }
+-
+- if ((len = my_real_read(net,(size_t *)&complen)) == packet_error)
+- break;
+- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
+- {
+- len= packet_error;
+- net->error=2; /* caller will close socket */
+-#ifdef MYSQL_SERVER
+- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+-#endif
+- break;
+- }
+- net->buf_length+=len;
+- net->remain_in_buf+=len;
+- }
+- if (len != packet_error)
+- {
+- net->save_char= net->read_pos[len]; /* Must be saved */
+- net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+- }
+- return len;
+-#endif
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/password.c mariadb-native-client.trunk/libmysql/password.c
+--- mariadb/libmysql/password.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/password.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,235 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* password checking routines */
+-/*****************************************************************************
+- The main idea is that no password are sent between client & server on
+- connection and that no password are saved in mysql in a decodable form.
+-
+- On connection a random string is generated and sent to the client.
+- The client generates a new string with a random generator inited with
+- the hash values from the password and the sent string.
+- This 'check' string is sent to the server where it is compared with
+- a string generated from the stored hash_value of the password and the
+- random string.
+-
+- The password is saved (in user.password) by using the PASSWORD() function in
+- mysql.
+-
+- Example:
+- update user set password=PASSWORD("hello") where user="test"
+- This saves a hashed number as a string in the password field.
+-*****************************************************************************/
+-
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <m_string.h>
+-#include <sha1.h>
+-#include "mysql.h"
+-
+-
+-void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+-{ /* For mysql 3.21.# */
+-#ifdef HAVE_purify
+- bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+-#endif
+- rand_st->max_value= 0x3FFFFFFFL;
+- rand_st->max_value_dbl=(double) rand_st->max_value;
+- rand_st->seed1=seed1%rand_st->max_value ;
+- rand_st->seed2=seed2%rand_st->max_value;
+-}
+-
+-static void old_randominit(struct rand_struct *rand_st,ulong seed1)
+-{ /* For mysql 3.20.# */
+- rand_st->max_value= 0x01FFFFFFL;
+- rand_st->max_value_dbl=(double) rand_st->max_value;
+- seed1%=rand_st->max_value;
+- rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
+-}
+-
+-double rnd(struct rand_struct *rand_st)
+-{
+- rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+- rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+- return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+-}
+-
+-void hash_password(ulong *result, const char *password, size_t len)
+-{
+- register ulong nr=1345345333L, add=7, nr2=0x12345671L;
+- ulong tmp;
+- const char *password_end= password + len;
+- for (; password < password_end; password++)
+- {
+- if (*password == ' ' || *password == '\t')
+- continue; /* skipp space in password */
+- tmp= (ulong) (uchar) *password;
+- nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+- nr2+=(nr2 << 8) ^ nr;
+- add+=tmp;
+- }
+- result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+- result[1]=nr2 & (((ulong) 1L << 31) -1L);
+- return;
+-}
+-
+-static inline unsigned int char_val(char X)
+-{
+- return (uint) (X >= '0' && X <= '9' ? X-'0' :
+- X >= 'A' && X <= 'Z' ? X-'A'+10 :
+- X-'a'+10);
+-}
+-
+-/*
+- * Genererate a new message based on message and password
+- * The same thing is done in client and server and the results are checked.
+- */
+-
+-/* scramble for 4.1 servers
+- * Code based on php_nysqlnd_scramble function from PHP's mysqlnd extension,
+- * written by Andrey Hristov (andrey@php.net)
+- * License: PHP License 3.0
+- */
+-void my_crypt(unsigned char *buffer, const unsigned char *s1, const unsigned char *s2, size_t len)
+-{
+- const unsigned char *s1_end= s1 + len;
+- while (s1 < s1_end) {
+- *buffer++= *s1++ ^ *s2++;
+- }
+-}
+-
+-void my_scramble_41(const unsigned char *buffer, const char *scramble, const char *password)
+-{
+- MYSQL_SHA1_CTX context;
+- unsigned char sha1[SHA1_MAX_LENGTH];
+- unsigned char sha2[SHA1_MAX_LENGTH];
+-
+-
+- /* Phase 1: hash password */
+- MYSQL_SHA1Init(&context);
+- MYSQL_SHA1Update(&context, (unsigned char *)password, strlen((char *)password));
+- MYSQL_SHA1Final(sha1, &context);
+-
+- /* Phase 2: hash sha1 */
+- MYSQL_SHA1Init(&context);
+- MYSQL_SHA1Update(&context, (unsigned char*)sha1, SHA1_MAX_LENGTH);
+- MYSQL_SHA1Final(sha2, &context);
+-
+- /* Phase 3: hash scramble + sha2 */
+- MYSQL_SHA1Init(&context);
+- MYSQL_SHA1Update(&context, (unsigned char *)scramble, SCRAMBLE_LENGTH);
+- MYSQL_SHA1Update(&context, (unsigned char*)sha2, SHA1_MAX_LENGTH);
+- MYSQL_SHA1Final((unsigned char *)buffer, &context);
+-
+- /* let's crypt buffer now */
+- my_crypt((uchar *)buffer, (const unsigned char *)buffer, (const unsigned char *)sha1, SHA1_MAX_LENGTH);
+-}
+-/* }}} */
+-
+-void make_scrambled_password(char *to,const char *password)
+-{
+- ulong hash_res[2];
+- hash_password(hash_res,password, strlen(password));
+- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+-}
+-
+-/*
+-** This code assumes that len(password) is divideable with 8 and that
+-** res is big enough (2 in mysql)
+-*/
+-
+-void get_salt_from_password(ulong *res,const char *password)
+-{
+- res[0]=res[1]=0;
+- if (password)
+- {
+- while (*password)
+- {
+- ulong val=0;
+- uint i;
+- for (i=0 ; i < 8 ; i++)
+- val=(val << 4)+char_val(*password++);
+- *res++=val;
+- }
+- }
+- return;
+-}
+-
+-void make_password_from_salt(char *to, ulong *hash_res)
+-{
+- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+-}
+-
+-
+-/*
+- * Genererate a new message based on message and password
+- * The same thing is done in client and server and the results are checked.
+- */
+-
+-char *scramble_323(char *to,const char *message,const char *password)
+-{
+- struct rand_struct rand_st;
+- ulong hash_pass[2],hash_message[2];
+- if (password && password[0])
+- {
+- char *to_start=to;
+- hash_password(hash_pass, password, strlen(password));
+- hash_password(hash_message, message, strlen(message));
+- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+- hash_pass[1] ^ hash_message[1]);
+- while (*message++)
+- *to++= (char) (floor(rnd(&rand_st)*31)+64);
+- { /* Make it harder to break */
+- char extra=(char) (floor(rnd(&rand_st)*31));
+- while (to_start != to)
+- *(to_start++)^=extra;
+- }
+- }
+- *to=0;
+- return to;
+-}
+-
+-
+-my_bool check_scramble(const char *scrambled, const char *message,
+- ulong *hash_pass, my_bool old_ver)
+-{
+- struct rand_struct rand_st;
+- ulong hash_message[2];
+- char buff[16],*to,extra; /* Big enough for check */
+- const char *pos;
+-
+- hash_password(hash_message,message, strlen(message));
+- if (old_ver)
+- old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+- else
+- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+- hash_pass[1] ^ hash_message[1]);
+- to=buff;
+- for (pos=scrambled ; *pos ; pos++)
+- *to++=(char) (floor(rnd(&rand_st)*31)+64);
+- if (old_ver)
+- extra=0;
+- else
+- extra=(char) (floor(rnd(&rand_st)*31));
+- to=buff;
+- while (*scrambled)
+- {
+- if (*scrambled++ != (char) (*to++ ^ extra))
+- return 1; /* Wrong password */
+- }
+- return 0;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/safemalloc.c mariadb-native-client.trunk/libmysql/safemalloc.c
+--- mariadb/libmysql/safemalloc.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/safemalloc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,523 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- * [This posting refers to an article entitled "oops, corrupted memory
+- * again!" in net.lang.c. I am posting it here because it is source.]
+- *
+- * My tool for approaching this problem is to build another level of data
+- * abstraction on top of malloc() and free() that implements some checking.
+- * This does a number of things for you:
+- * - Checks for overruns and underruns on allocated data
+- * - Keeps track of where in the program the memory was malloc'ed
+- * - Reports on pieces of memory that were not free'ed
+- * - Records some statistics such as maximum memory used
+- * - Marks newly malloc'ed and newly free'ed memory with special values
+- * You can use this scheme to:
+- * - Find bugs such as overrun, underrun, etc because you know where
+- * a piece of data was malloc'ed and where it was free'ed
+- * - Find bugs where memory was not free'ed
+- * - Find bugs where newly malloc'ed memory is used without initializing
+- * - Find bugs where newly free'ed memory is still used
+- * - Determine how much memory your program really uses
+- * - and other things
+- */
+-
+-/*
+- * To implement my scheme you must have a C compiler that has __LINE__ and
+- * __FILE__ macros. If your compiler doesn't have these then (a) buy another:
+- * compilers that do are available on UNIX 4.2bsd based systems and the PC,
+- * and probably on other machines; or (b) change my scheme somehow. I have
+- * recomendations on both these points if you would like them (e-mail please).
+- *
+- * There are 4 functions in my package:
+- * char *NEW( uSize ) Allocate memory of uSize bytes
+- * (equivalent to malloc())
+- * char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
+- * free pPtr.
+- * (equivalent to realloc())
+- * FREE( pPtr ) Free memory allocated by NEW
+- * (equivalent to free())
+- * TERMINATE(file) End system, report errors and stats on file
+- * I personally use two more functions, but have not included them here:
+- * char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory
+- * char *RENEW( pPtr, uSize )
+- * (equivalent to realloc())
+- */
+-
+-/*
+- * Memory sub-system, written by Bjorn Benson
+- Fixed to use my_sys scheme by Michael Widenius
+- */
+-
+-#ifndef SAFEMALLOC
+-#define SAFEMALLOC /* Get protos from my_sys */
+-#endif
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#include "my_static.h"
+-#include "mysys_err.h"
+-
+-ulonglong safemalloc_mem_limit = ~(ulonglong)0;
+-
+-#define pNext tInt._pNext
+-#define pPrev tInt._pPrev
+-#define sFileName tInt._sFileName
+-#define uLineNum tInt._uLineNum
+-#define uDataSize tInt._uDataSize
+-#define lSpecialValue tInt._lSpecialValue
+-
+- /* Static functions prototypes */
+-
+-static int check_ptr(const char *where, byte *ptr, const char *sFile,
+- uint uLine);
+-static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
+-
+-/*
+- * Note: both these refer to the NEW'ed
+- * data only. They do not include
+- * malloc() roundoff or the extra
+- * space required by the remember
+- * structures.
+- */
+-
+-#define ALLOC_VAL (uchar) 0xA5 /* NEW'ed memory is filled with this */
+- /* value so that references to it will */
+- /* end up being very strange. */
+-#define FREE_VAL (uchar) 0x8F /* FREE'ed memory is filled with this */
+- /* value so that references to it will */
+- /* also end up being strange. */
+-
+-#define MAGICKEY 0x14235296 /* A magic value for underrun key */
+-#define MAGICEND0 0x68 /* Magic values for overrun keys */
+-#define MAGICEND1 0x34 /* " */
+-#define MAGICEND2 0x7A /* " */
+-#define MAGICEND3 0x15 /* " */
+-
+- /* Warning: do not change the MAGICEND? values to */
+- /* something with the high bit set. Various C */
+- /* compilers (like the 4.2bsd one) do not do the */
+- /* sign extension right later on in this code and */
+- /* you will get erroneous errors. */
+-
+-
+-/*
+- * gptr _mymalloc( uint uSize, my_string sFile, uint uLine, MyFlags )
+- * Allocate some memory.
+- */
+-
+-gptr _mymalloc (size_t uSize, const char *sFile, uint uLine, myf MyFlags)
+-{
+- struct remember *pTmp;
+- DBUG_ENTER("_mymalloc");
+- DBUG_PRINT("enter",("Size: %u",uSize));
+-
+-
+- if (!sf_malloc_quick)
+- (void) _sanity (sFile, uLine);
+-
+- if(uSize + lCurMemory > safemalloc_mem_limit)
+- pTmp = 0;
+- else
+- /* Allocate the physical memory */
+- pTmp = (struct remember *) malloc (
+- sizeof (struct irem) /* remember data */
+- + sf_malloc_prehunc
+- + uSize /* size requested */
+- + 4 /* overrun mark */
+- + sf_malloc_endhunc
+- );
+-
+- /* Check if there isn't anymore memory avaiable */
+- if (pTmp == NULL)
+- {
+- if (MyFlags & MY_FAE)
+- error_handler_hook=fatal_error_handler_hook;
+- if (MyFlags & (MY_FAE+MY_WME))
+- {
+- char buff[SC_MAXWIDTH];
+- my_errno=errno;
+- sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile);
+- my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+- sprintf(buff,"needed %ld byte (%ldk), memory in use: %lu bytes (%ldk)",
+- (long) uSize, (long) ((uSize + 1023L) / 1024L),
+- (long) lMaxMemory, (long) (lMaxMemory + 1023L) / 1024L);
+- my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+- }
+- DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
+- lMaxMemory,uLine, sFile));
+- if (MyFlags & MY_FAE)
+- exit(1);
+- DBUG_RETURN ((gptr) NULL);
+- }
+-
+- /* Fill up the structure */
+- *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY;
+- pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0;
+- pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1;
+- pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2;
+- pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3;
+- pTmp -> sFileName = (my_string) sFile;
+- pTmp -> uLineNum = uLine;
+- pTmp -> uDataSize = uSize;
+- pTmp -> pPrev = NULL;
+-
+- /* Add this remember structure to the linked list */
+- pthread_mutex_lock(&THR_LOCK_malloc);
+- if ((pTmp->pNext=pRememberRoot))
+- {
+- pRememberRoot -> pPrev = pTmp;
+- }
+- pRememberRoot = pTmp;
+-
+- /* Keep the statistics */
+- lCurMemory += uSize;
+- if (lCurMemory > lMaxMemory) {
+- lMaxMemory = lCurMemory;
+- }
+- cNewCount++;
+- pthread_mutex_unlock(&THR_LOCK_malloc);
+-
+- /* Set the memory to the aribtrary wierd value */
+- if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick)
+- bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
+- (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
+- /* Return a pointer to the real data */
+- DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
+- if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
+- sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+- if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
+- sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+- DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
+-}
+-
+-/*
+- * Allocate some new memory and move old memoryblock there.
+- * Free then old memoryblock
+- */
+-
+-gptr _myrealloc (register gptr pPtr, register size_t uSize,
+- const char *sFile, uint uLine, myf MyFlags)
+-{
+- struct remember *pRec;
+- gptr ptr;
+- DBUG_ENTER("_myrealloc");
+-
+- if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR))
+- DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags));
+-
+- if (!sf_malloc_quick)
+- (void) _sanity (sFile, uLine);
+-
+- if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
+- DBUG_RETURN((gptr) NULL);
+-
+- pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)-
+- sf_malloc_prehunc);
+- if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+- != MAGICKEY)
+- {
+- fprintf (stderr, "Reallocating unallocated data at line %d, '%s'\n",
+- uLine, sFile);
+- DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
+- uLine, sFile));
+- (void) fflush(stderr);
+- DBUG_RETURN((gptr) NULL);
+- }
+-
+- if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
+- {
+- uSize=min(uSize,pRec->uDataSize); /* Move as much as possibly */
+- memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */
+- _myfree(pPtr,sFile,uLine,0); /* Free not needed area */
+- }
+- else
+- {
+- if (MyFlags & MY_HOLD_ON_ERROR)
+- DBUG_RETURN(pPtr);
+- if (MyFlags & MY_FREE_ON_ERROR)
+- _myfree(pPtr,sFile,uLine,0);
+- }
+- DBUG_RETURN(ptr);
+-} /* _myrealloc */
+-
+-
+-/*
+- * void _myfree( my_string pPtr, my_string sFile, uint uLine, myf myflags)
+- * Deallocate some memory.
+- */
+-
+-void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
+-{
+- struct remember *pRec;
+- DBUG_ENTER("_myfree");
+- DBUG_PRINT("enter",("ptr: %lx",pPtr));
+-
+- if (!sf_malloc_quick)
+- (void) _sanity (sFile, uLine);
+-
+- if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
+- check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
+- DBUG_VOID_RETURN;
+-
+- /* Calculate the address of the remember structure */
+- pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
+- sf_malloc_prehunc);
+-
+- /* Check to make sure that we have a real remember structure */
+- /* Note: this test could fail for four reasons: */
+- /* (1) The memory was already free'ed */
+- /* (2) The memory was never new'ed */
+- /* (3) There was an underrun */
+- /* (4) A stray pointer hit this location */
+-
+- if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+- != MAGICKEY)
+- {
+- fprintf (stderr, "Freeing unallocated data at line %d, '%s'\n",
+- uLine, sFile);
+- DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
+- (void) fflush(stderr);
+- DBUG_VOID_RETURN;
+- }
+-
+- /* Remove this structure from the linked list */
+- pthread_mutex_lock(&THR_LOCK_malloc);
+- if (pRec -> pPrev) {
+- pRec -> pPrev -> pNext = pRec -> pNext;
+- } else {
+- pRememberRoot = pRec -> pNext;
+- }
+- if (pRec -> pNext) {
+- pRec -> pNext -> pPrev = pRec -> pPrev;
+- }
+- /* Handle the statistics */
+- lCurMemory -= pRec -> uDataSize;
+- cNewCount--;
+- pthread_mutex_unlock(&THR_LOCK_malloc);
+-
+-#ifndef HAVE_purify
+- /* Mark this data as free'ed */
+- if (!sf_malloc_quick)
+- bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
+-#endif
+- *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;
+-
+- /* Actually free the memory */
+- free ((my_string ) pRec);
+- DBUG_VOID_RETURN;
+-}
+-
+- /* Check if we have a wrong pointer */
+-
+-static int check_ptr(const char *where, byte *ptr, const char *sFile,
+- uint uLine)
+-{
+- if (!ptr)
+- {
+- fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
+- where,uLine, sFile);
+- DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
+- (void) fflush(stderr);
+- return 1;
+- }
+-#ifndef _MSC_VER
+- if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
+- {
+- fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
+- where,uLine, sFile);
+- DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
+- uLine,sFile));
+- (void) fflush(stderr);
+- return 1;
+- }
+-#endif
+- if (ptr < sf_min_adress || ptr > sf_max_adress)
+- {
+- fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
+- where,uLine, sFile);
+- DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
+- uLine,sFile));
+- (void) fflush(stderr);
+- return 1;
+- }
+- return 0;
+-}
+-
+-
+-/*
+- * TERMINATE(FILE *file)
+- * Report on all the memory pieces that have not been
+- * free'ed as well as the statistics.
+- */
+-
+-void TERMINATE (FILE *file)
+-{
+- struct remember *pPtr;
+- DBUG_ENTER("TERMINATE");
+- pthread_mutex_lock(&THR_LOCK_malloc);
+-
+- /* Report the difference between number of calls to */
+- /* NEW and the number of calls to FREE. >0 means more */
+- /* NEWs than FREEs. <0, etc. */
+-
+- if (cNewCount)
+- {
+- if (file)
+- {
+- fprintf (file, "cNewCount: %d\n", cNewCount);
+- (void) fflush(file);
+- }
+- DBUG_PRINT("safe",("cNewCount: %d",cNewCount));
+- }
+-
+- /* Report on all the memory that was allocated with NEW */
+- /* but not free'ed with FREE. */
+-
+- if ((pPtr=pRememberRoot))
+- {
+- if (file)
+- {
+- fprintf(file, "Memory that was not free'ed (%zu bytes):\n",lCurMemory);
+- (void) fflush(file);
+- }
+- DBUG_PRINT("safe",("Memory that was not free'ed (%zu bytes):",lCurMemory));
+- while (pPtr)
+- {
+- if (file)
+- {
+- fprintf (file,
+- "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n",
+- pPtr -> uDataSize,
+- (ulong) &(pPtr -> aData[sf_malloc_prehunc]),
+- pPtr -> uLineNum, pPtr -> sFileName);
+- (void) fflush(file);
+- }
+- DBUG_PRINT("safe",
+- ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
+- pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
+- pPtr -> uLineNum, pPtr -> sFileName));
+- pPtr = pPtr -> pNext;
+- }
+- }
+- /* Report the memory usage statistics */
+- if (file)
+- {
+- fprintf (file, "Maximum memory usage: %zu bytes (%ldk)\n",
+- lMaxMemory, (lMaxMemory + 1023L) / 1024L);
+- (void) fflush(file);
+- }
+- DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)",
+- lMaxMemory, (lMaxMemory + 1023L) / 1024L));
+- pthread_mutex_unlock(&THR_LOCK_malloc);
+- DBUG_VOID_RETURN;
+-}
+-
+-
+- /* Returns 0 if chunk is ok */
+-
+-static int _checkchunk (register struct remember *pRec, const char *sFile,
+- uint uLine)
+-{
+- reg1 size_t uSize;
+- reg2 my_string magicp;
+- reg3 int flag=0;
+-
+- /* Check for a possible underrun */
+- if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+- != MAGICKEY)
+- {
+- fprintf (stderr, "Memory allocated at %s:%d was underrun,",
+- pRec -> sFileName, pRec -> uLineNum);
+- fprintf (stderr, " discovered at %s:%d\n", sFile, uLine);
+- (void) fflush(stderr);
+- DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
+- &(pRec -> aData[sf_malloc_prehunc]),
+- pRec -> sFileName,
+- pRec -> uLineNum));
+- flag=1;
+- }
+-
+- /* Check for a possible overrun */
+- uSize = pRec->uDataSize;
+- magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
+- if (*magicp++ != MAGICEND0 ||
+- *magicp++ != MAGICEND1 ||
+- *magicp++ != MAGICEND2 ||
+- *magicp++ != MAGICEND3)
+- {
+- fprintf (stderr, "Memory allocated at %s:%d was overrun,",
+- pRec -> sFileName, pRec -> uLineNum);
+- fprintf (stderr, " discovered at '%s:%d'\n", sFile, uLine);
+- (void) fflush(stderr);
+- DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
+- &(pRec -> aData[sf_malloc_prehunc]),
+- pRec -> sFileName,
+- pRec -> uLineNum));
+- flag=1;
+- }
+- return(flag);
+-}
+-
+-
+- /* Returns how many wrong chunks */
+-
+-int _sanity (const char *sFile, uint uLine)
+-{
+- reg1 struct remember *pTmp;
+- reg2 int flag=0;
+- uint count=0;
+-
+- pthread_mutex_lock(&THR_LOCK_malloc);
+- count=cNewCount;
+- for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext)
+- flag+=_checkchunk (pTmp, sFile, uLine);
+- pthread_mutex_unlock(&THR_LOCK_malloc);
+- if (count || pTmp)
+- {
+- const char *format="Safemalloc link list destroyed, discovered at '%s:%d'";
+- fprintf (stderr, format, sFile, uLine); fputc('\n',stderr);
+- (void) fflush(stderr);
+- DBUG_PRINT("safe",(format, sFile, uLine));
+- flag=1;
+- }
+- return flag;
+-} /* _sanity */
+-
+-
+- /* malloc and copy */
+-
+-gptr _my_memdup(const byte *from, size_t length, const char *sFile, uint uLine,
+- myf MyFlags)
+-{
+- gptr ptr;
+- if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+- memcpy((byte*) ptr, (byte*) from, length);
+- return(ptr);
+-} /*_my_memdup */
+-
+-
+-my_string _my_strdup(const char *from, const char *sFile, uint uLine,
+- myf MyFlags)
+-{
+- gptr ptr;
+- size_t length= strlen(from)+1;
+- if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+- return((my_string) ptr);
+-} /* _my_strdup */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/sha1.c mariadb-native-client.trunk/libmysql/sha1.c
+--- mariadb/libmysql/sha1.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/sha1.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,325 +0,0 @@
+-/****************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+-*****************************************************************************/
+-
+-/* This code came from the PHP project, initially written by
+- Stefan Esser */
+-
+-
+-#include "my_global.h"
+-#include "string.h"
+-
+-/* This code is heavily based on the PHP md5 implementation */
+-
+-#include "sha1.h"
+-
+-
+-static void SHA1Transform(uint32[5], const unsigned char[64]);
+-static void SHA1Encode(unsigned char *, uint32 *, unsigned int);
+-static void SHA1Decode(uint32 *, const unsigned char *, unsigned int);
+-
+-static unsigned char PADDING[64] =
+-{
+- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+-};
+-
+-/* F, G, H and I are basic SHA1 functions.
+- */
+-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+-#define G(x, y, z) ((x) ^ (y) ^ (z))
+-#define H(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
+-#define I(x, y, z) ((x) ^ (y) ^ (z))
+-
+-/* ROTATE_LEFT rotates x left n bits.
+- */
+-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+-
+-/* W[i]
+- */
+-#define W(i) ( tmp=x[(i-3)&15]^x[(i-8)&15]^x[(i-14)&15]^x[i&15], \
+- (x[i&15]=ROTATE_LEFT(tmp, 1)) )
+-
+-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+- */
+-#define FF(a, b, c, d, e, w) { \
+- (e) += F ((b), (c), (d)) + (w) + (uint32)(0x5A827999); \
+- (e) += ROTATE_LEFT ((a), 5); \
+- (b) = ROTATE_LEFT((b), 30); \
+- }
+-#define GG(a, b, c, d, e, w) { \
+- (e) += G ((b), (c), (d)) + (w) + (uint32)(0x6ED9EBA1); \
+- (e) += ROTATE_LEFT ((a), 5); \
+- (b) = ROTATE_LEFT((b), 30); \
+- }
+-#define HH(a, b, c, d, e, w) { \
+- (e) += H ((b), (c), (d)) + (w) + (uint32)(0x8F1BBCDC); \
+- (e) += ROTATE_LEFT ((a), 5); \
+- (b) = ROTATE_LEFT((b), 30); \
+- }
+-#define II(a, b, c, d, e, w) { \
+- (e) += I ((b), (c), (d)) + (w) + (uint32)(0xCA62C1D6); \
+- (e) += ROTATE_LEFT ((a), 5); \
+- (b) = ROTATE_LEFT((b), 30); \
+- }
+-
+-
+-/* {{{ MYSQL_SHA1Init
+- * SHA1 initialization. Begins an SHA1 operation, writing a new context.
+- */
+-void MYSQL_SHA1Init(MYSQL_SHA1_CTX * context)
+-{
+- context->count[0] = context->count[1] = 0;
+- /* Load magic initialization constants.
+- */
+- context->state[0] = 0x67452301;
+- context->state[1] = 0xefcdab89;
+- context->state[2] = 0x98badcfe;
+- context->state[3] = 0x10325476;
+- context->state[4] = 0xc3d2e1f0;
+-}
+-/* }}} */
+-
+-/* {{{ MYSQL_SHA1Update
+- SHA1 block update operation. Continues an SHA1 message-digest
+- operation, processing another message block, and updating the
+- context.
+- */
+-void MYSQL_SHA1Update(MYSQL_SHA1_CTX * context, const unsigned char *input,
+- size_t inputLen)
+-{
+- unsigned int i, index, partLen;
+-
+- /* Compute number of bytes mod 64 */
+- index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
+-
+- /* Update number of bits */
+- if ((context->count[0] += ((uint32) inputLen << 3))
+- < ((uint32) inputLen << 3))
+- context->count[1]++;
+- context->count[1] += ((uint32) inputLen >> 29);
+-
+- partLen = 64 - index;
+-
+- /* Transform as many times as possible.
+- */
+- if (inputLen >= partLen) {
+- memcpy
+- ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
+- SHA1Transform(context->state, context->buffer);
+-
+- for (i = partLen; i + 63 < inputLen; i += 64)
+- SHA1Transform(context->state, &input[i]);
+-
+- index = 0;
+- } else
+- i = 0;
+-
+- /* Buffer remaining input */
+- memcpy
+- ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i],
+- inputLen - i);
+-}
+-/* }}} */
+-
+-/* {{{ MYSQL_SHA1Final
+- SHA1 finalization. Ends an SHA1 message-digest operation, writing the
+- the message digest and zeroizing the context.
+- */
+-void MYSQL_SHA1Final(unsigned char digest[20], MYSQL_SHA1_CTX * context)
+-{
+- unsigned char bits[8];
+- unsigned int index, padLen;
+-
+- /* Save number of bits */
+- bits[7] = context->count[0] & 0xFF;
+- bits[6] = (context->count[0] >> 8) & 0xFF;
+- bits[5] = (context->count[0] >> 16) & 0xFF;
+- bits[4] = (context->count[0] >> 24) & 0xFF;
+- bits[3] = context->count[1] & 0xFF;
+- bits[2] = (context->count[1] >> 8) & 0xFF;
+- bits[1] = (context->count[1] >> 16) & 0xFF;
+- bits[0] = (context->count[1] >> 24) & 0xFF;
+-
+- /* Pad out to 56 mod 64.
+- */
+- index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
+- padLen = (index < 56) ? (56 - index) : (120 - index);
+- MYSQL_SHA1Update(context, PADDING, padLen);
+-
+- /* Append length (before padding) */
+- MYSQL_SHA1Update(context, bits, 8);
+-
+- /* Store state in digest */
+- SHA1Encode(digest, context->state, 20);
+-
+- /* Zeroize sensitive information.
+- */
+- memset((unsigned char*) context, 0, sizeof(*context));
+-}
+-/* }}} */
+-
+-/* {{{ SHA1Transform
+- * SHA1 basic transformation. Transforms state based on block.
+- */
+-static void SHA1Transform(uint32 state[5], const unsigned char block[64])
+-{
+- uint32 a = state[0], b = state[1], c = state[2];
+- uint32 d = state[3], e = state[4], x[16], tmp;
+-
+- SHA1Decode(x, block, 64);
+-
+- /* Round 1 */
+- FF(a, b, c, d, e, x[0]); /* 1 */
+- FF(e, a, b, c, d, x[1]); /* 2 */
+- FF(d, e, a, b, c, x[2]); /* 3 */
+- FF(c, d, e, a, b, x[3]); /* 4 */
+- FF(b, c, d, e, a, x[4]); /* 5 */
+- FF(a, b, c, d, e, x[5]); /* 6 */
+- FF(e, a, b, c, d, x[6]); /* 7 */
+- FF(d, e, a, b, c, x[7]); /* 8 */
+- FF(c, d, e, a, b, x[8]); /* 9 */
+- FF(b, c, d, e, a, x[9]); /* 10 */
+- FF(a, b, c, d, e, x[10]); /* 11 */
+- FF(e, a, b, c, d, x[11]); /* 12 */
+- FF(d, e, a, b, c, x[12]); /* 13 */
+- FF(c, d, e, a, b, x[13]); /* 14 */
+- FF(b, c, d, e, a, x[14]); /* 15 */
+- FF(a, b, c, d, e, x[15]); /* 16 */
+- FF(e, a, b, c, d, W(16)); /* 17 */
+- FF(d, e, a, b, c, W(17)); /* 18 */
+- FF(c, d, e, a, b, W(18)); /* 19 */
+- FF(b, c, d, e, a, W(19)); /* 20 */
+-
+- /* Round 2 */
+- GG(a, b, c, d, e, W(20)); /* 21 */
+- GG(e, a, b, c, d, W(21)); /* 22 */
+- GG(d, e, a, b, c, W(22)); /* 23 */
+- GG(c, d, e, a, b, W(23)); /* 24 */
+- GG(b, c, d, e, a, W(24)); /* 25 */
+- GG(a, b, c, d, e, W(25)); /* 26 */
+- GG(e, a, b, c, d, W(26)); /* 27 */
+- GG(d, e, a, b, c, W(27)); /* 28 */
+- GG(c, d, e, a, b, W(28)); /* 29 */
+- GG(b, c, d, e, a, W(29)); /* 30 */
+- GG(a, b, c, d, e, W(30)); /* 31 */
+- GG(e, a, b, c, d, W(31)); /* 32 */
+- GG(d, e, a, b, c, W(32)); /* 33 */
+- GG(c, d, e, a, b, W(33)); /* 34 */
+- GG(b, c, d, e, a, W(34)); /* 35 */
+- GG(a, b, c, d, e, W(35)); /* 36 */
+- GG(e, a, b, c, d, W(36)); /* 37 */
+- GG(d, e, a, b, c, W(37)); /* 38 */
+- GG(c, d, e, a, b, W(38)); /* 39 */
+- GG(b, c, d, e, a, W(39)); /* 40 */
+-
+- /* Round 3 */
+- HH(a, b, c, d, e, W(40)); /* 41 */
+- HH(e, a, b, c, d, W(41)); /* 42 */
+- HH(d, e, a, b, c, W(42)); /* 43 */
+- HH(c, d, e, a, b, W(43)); /* 44 */
+- HH(b, c, d, e, a, W(44)); /* 45 */
+- HH(a, b, c, d, e, W(45)); /* 46 */
+- HH(e, a, b, c, d, W(46)); /* 47 */
+- HH(d, e, a, b, c, W(47)); /* 48 */
+- HH(c, d, e, a, b, W(48)); /* 49 */
+- HH(b, c, d, e, a, W(49)); /* 50 */
+- HH(a, b, c, d, e, W(50)); /* 51 */
+- HH(e, a, b, c, d, W(51)); /* 52 */
+- HH(d, e, a, b, c, W(52)); /* 53 */
+- HH(c, d, e, a, b, W(53)); /* 54 */
+- HH(b, c, d, e, a, W(54)); /* 55 */
+- HH(a, b, c, d, e, W(55)); /* 56 */
+- HH(e, a, b, c, d, W(56)); /* 57 */
+- HH(d, e, a, b, c, W(57)); /* 58 */
+- HH(c, d, e, a, b, W(58)); /* 59 */
+- HH(b, c, d, e, a, W(59)); /* 60 */
+-
+- /* Round 4 */
+- II(a, b, c, d, e, W(60)); /* 61 */
+- II(e, a, b, c, d, W(61)); /* 62 */
+- II(d, e, a, b, c, W(62)); /* 63 */
+- II(c, d, e, a, b, W(63)); /* 64 */
+- II(b, c, d, e, a, W(64)); /* 65 */
+- II(a, b, c, d, e, W(65)); /* 66 */
+- II(e, a, b, c, d, W(66)); /* 67 */
+- II(d, e, a, b, c, W(67)); /* 68 */
+- II(c, d, e, a, b, W(68)); /* 69 */
+- II(b, c, d, e, a, W(69)); /* 70 */
+- II(a, b, c, d, e, W(70)); /* 71 */
+- II(e, a, b, c, d, W(71)); /* 72 */
+- II(d, e, a, b, c, W(72)); /* 73 */
+- II(c, d, e, a, b, W(73)); /* 74 */
+- II(b, c, d, e, a, W(74)); /* 75 */
+- II(a, b, c, d, e, W(75)); /* 76 */
+- II(e, a, b, c, d, W(76)); /* 77 */
+- II(d, e, a, b, c, W(77)); /* 78 */
+- II(c, d, e, a, b, W(78)); /* 79 */
+- II(b, c, d, e, a, W(79)); /* 80 */
+-
+- state[0] += a;
+- state[1] += b;
+- state[2] += c;
+- state[3] += d;
+- state[4] += e;
+-
+- /* Zeroize sensitive information. */
+- memset((unsigned char*) x, 0, sizeof(x));
+-}
+-/* }}} */
+-
+-/* {{{ SHA1Encode
+- Encodes input (uint32) into output (unsigned char). Assumes len is
+- a multiple of 4.
+- */
+-static void SHA1Encode(unsigned char *output, uint32 *input, unsigned int len)
+-{
+- unsigned int i, j;
+-
+- for (i = 0, j = 0; j < len; i++, j += 4) {
+- output[j] = (unsigned char) ((input[i] >> 24) & 0xff);
+- output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff);
+- output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff);
+- output[j + 3] = (unsigned char) (input[i] & 0xff);
+- }
+-}
+-/* }}} */
+-
+-/* {{{ SHA1Decode
+- Decodes input (unsigned char) into output (uint32). Assumes len is
+- a multiple of 4.
+- */
+-static void SHA1Decode(uint32 *output, const unsigned char * input, unsigned int len)
+-{
+- unsigned int i, j;
+-
+- for (i = 0, j = 0; j < len; i++, j += 4)
+- output[i] = ((uint32) input[j + 3]) | (((uint32) input[j + 2]) << 8) |
+- (((uint32) input[j + 1]) << 16) | (((uint32) input[j]) << 24);
+-}
+-/* }}} */
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * End:
+- * vim600: sw=4 ts=4 fdm=marker
+- * vim<600: sw=4 ts=4
+- */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/str2int.c mariadb-native-client.trunk/libmysql/str2int.c
+--- mariadb/libmysql/str2int.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/str2int.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,202 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- str2int(src, radix, lower, upper, &val)
+- converts the string pointed to by src to an integer and stores it in
+- val. It skips leading spaces and tabs (but not newlines, formfeeds,
+- backspaces), then it accepts an optional sign and a sequence of digits
+- in the specified radix. The result should satisfy lower <= *val <= upper.
+- The result is a pointer to the first character after the number;
+- trailing spaces will NOT be skipped.
+-
+- If an error is detected, the result will be NullS, the value put
+- in val will be 0, and errno will be set to
+- EDOM if there are no digits
+- ERANGE if the result would overflow or otherwise fail to lie
+- within the specified bounds.
+- Check that the bounds are right for your machine.
+- This looks amazingly complicated for what you probably thought was an
+- easy task. Coping with integer overflow and the asymmetric range of
+- twos complement machines is anything but easy.
+-
+- So that users of atoi and atol can check whether an error occured,
+- I have taken a wholly unprecedented step: errno is CLEARED if this
+- call has no problems.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-#include "m_ctype.h"
+-#include "my_sys.h" /* defines errno */
+-#include <errno.h>
+-
+-#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
+- X >= 'A' && X <= 'Z' ? X-'A'+10 :\
+- X >= 'a' && X <= 'z' ? X-'a'+10 :\
+- '\177')
+-
+-char *str2int(register const char *src, register int radix, long int lower, long int upper, long int *val)
+-{
+- int sign; /* is number negative (+1) or positive (-1) */
+- int n; /* number of digits yet to be converted */
+- long limit; /* "largest" possible valid input */
+- long scale; /* the amount to multiply next digit by */
+- long sofar; /* the running value */
+- register int d; /* (negative of) next digit */
+- char *start;
+- int digits[32]; /* Room for numbers */
+-
+- /* Make sure *val is sensible in case of error */
+-
+- *val = 0;
+-
+- /* Check that the radix is in the range 2..36 */
+-
+-#ifndef DBUG_OFF
+- if (radix < 2 || radix > 36) {
+- errno=EDOM;
+- return NullS;
+- }
+-#endif
+-
+- /* The basic problem is: how do we handle the conversion of
+- a number without resorting to machine-specific code to
+- check for overflow? Obviously, we have to ensure that
+- no calculation can overflow. We are guaranteed that the
+- "lower" and "upper" arguments are valid machine integers.
+- On sign-and-magnitude, twos-complement, and ones-complement
+- machines all, if +|n| is representable, so is -|n|, but on
+- twos complement machines the converse is not true. So the
+- "maximum" representable number has a negative representative.
+- Limit is set to min(-|lower|,-|upper|); this is the "largest"
+- number we are concerned with. */
+-
+- /* Calculate Limit using Scale as a scratch variable */
+-
+- if ((limit = lower) > 0) limit = -limit;
+- if ((scale = upper) > 0) scale = -scale;
+- if (scale < limit) limit = scale;
+-
+- /* Skip leading spaces and check for a sign.
+- Note: because on a 2s complement machine MinLong is a valid
+- integer but |MinLong| is not, we have to keep the current
+- converted value (and the scale!) as *negative* numbers,
+- so the sign is the opposite of what you might expect.
+- */
+- while (isspace(*src)) src++;
+- sign = -1;
+- if (*src == '+') src++; else
+- if (*src == '-') src++, sign = 1;
+-
+- /* Skip leading zeros so that we never compute a power of radix
+- in scale that we won't have a need for. Otherwise sticking
+- enough 0s in front of a number could cause the multiplication
+- to overflow when it neededn't.
+- */
+- start=(char*) src;
+- while (*src == '0') src++;
+-
+- /* Move over the remaining digits. We have to convert from left
+- to left in order to avoid overflow. Answer is after last digit.
+- */
+-
+- for (n = 0; (digits[n]=char_val(*src)) < radix && n < 20; n++,src++) ;
+-
+- /* Check that there is at least one digit */
+-
+- if (start == src) {
+- errno=EDOM;
+- return NullS;
+- }
+-
+- /* The invariant we want to maintain is that src is just
+- to the right of n digits, we've converted k digits to
+- sofar, scale = -radix**k, and scale < sofar < 0. Now
+- if the final number is to be within the original
+- Limit, we must have (to the left)*scale+sofar >= Limit,
+- or (to the left)*scale >= Limit-sofar, i.e. the digits
+- to the left of src must form an integer <= (Limit-sofar)/(scale).
+- In particular, this is true of the next digit. In our
+- incremental calculation of Limit,
+-
+- IT IS VITAL that (-|N|)/(-|D|) = |N|/|D|
+- */
+-
+- for (sofar = 0, scale = -1; --n >= 1;)
+- {
+- if ((long) -(d=digits[n]) < limit) {
+- errno=ERANGE;
+- return NullS;
+- }
+- limit = (limit+d)/radix, sofar += d*scale; scale *= radix;
+- }
+- if (n == 0)
+- {
+- if ((long) -(d=digits[n]) < limit) /* get last digit */
+- {
+- errno=ERANGE;
+- return NullS;
+- }
+- sofar+=d*scale;
+- }
+-
+- /* Now it might still happen that sofar = -32768 or its equivalent,
+- so we can't just multiply by the sign and check that the result
+- is in the range lower..upper. All of this caution is a right
+- pain in the neck. If only there were a standard routine which
+- says generate thus and such a signal on integer overflow...
+- But not enough machines can do it *SIGH*.
+- */
+- if (sign < 0)
+- {
+- if (sofar < -LONG_MAX || (sofar= -sofar) > upper)
+- {
+- errno=ERANGE;
+- return NullS;
+- }
+- }
+- else if (sofar < lower)
+- {
+- errno=ERANGE;
+- return NullS;
+- }
+- *val = sofar;
+- errno=0; /* indicate that all went well */
+- return (char*) src;
+-}
+-
+- /* Theese are so slow compared with ordinary, optimized atoi */
+-
+-#ifdef WANT_OUR_ATOI
+-
+-int atoi(const char *src)
+-{
+- long val;
+- str2int(src, 10, (long) INT_MIN, (long) INT_MAX, &val);
+- return (int) val;
+-}
+-
+-
+-long atol(const char *src)
+-{
+- long val;
+- str2int(src, 10, LONG_MIN, LONG_MAX, &val);
+- return val;
+-}
+-
+-#endif /* WANT_OUR_ATOI */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strcend.c mariadb-native-client.trunk/libmysql/strcend.c
+--- mariadb/libmysql/strcend.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strcend.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,48 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strcend.c
+- Author : Michael Widenius: ifdef MC68000
+- Updated: 20 April 1984
+- Defines: strcend()
+-
+- strcend(s, c) returns a pointer to the first place in s where c
+- occurs, or a pointer to the end-null of s if c does not occur in s.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-/**
+- \fn char *strcend
+- \brief returns a pointer to the first occurence of specified stopchar
+- \param str char *
+- \param stopchar char
+-
+- returns a poimter to the first occurence of stopchar or to null char,
+- if stopchar wasn't found.
+-*/
+-char *strcend(register const char *str, register char stopchar)
+-{
+- for (;;)
+- {
+- if (*str == stopchar)
+- return (char*) str;
+- if (!*str++)
+- return (char*) str-1;
+- }
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strcont.c mariadb-native-client.trunk/libmysql/strcont.c
+--- mariadb/libmysql/strcont.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strcont.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,46 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strcont.c
+- Author : Monty
+- Updated: 1988.07.27
+- Defines: strcont()
+-
+- strcont(str, set) if str contanies any character in the string set.
+- The result is the position of the first found character in str, or NullS
+- if there isn't anything found.
+-
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-my_string strcont(reg1 const char *str,reg2 const char *set)
+-{
+- reg3 my_string start = (my_string) set;
+-
+- while (*str)
+- {
+- while (*set)
+- {
+- if (*set++ == *str)
+- return ((char*) str);
+- }
+- set=start; str++;
+- }
+- return (NullS);
+-} /* strcont */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strend.c mariadb-native-client.trunk/libmysql/strend.c
+--- mariadb/libmysql/strend.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strend.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,50 +0,0 @@
+-/* Copyright (C) 2002 MySQL AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strend.c
+- Author : Richard A. O'Keefe.
+- Updated: 23 April 1984
+- Defines: strend()
+-
+- strend(s) returns a character pointer to the NUL which ends s. That
+- is, strend(s)-s == strlen(s). This is useful for adding things at
+- the end of strings. It is redundant, because strchr(s,'\0') could
+- be used instead, but this is clearer and faster.
+- Beware: the asm version works only if strlen(s) < 65535.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#if VaxAsm
+-
+-char *strend(s)
+-const char *s;
+-{
+- asm("locc $0,$65535,*4(ap)");
+- asm("movl r1,r0");
+-}
+-
+-#else /* ~VaxAsm */
+-
+-char *strend(register const char *s)
+-{
+- while (*s++);
+- return (char*) (s-1);
+-}
+-
+-#endif /* VaxAsm */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strfill.c mariadb-native-client.trunk/libmysql/strfill.c
+--- mariadb/libmysql/strfill.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strfill.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strfill.c
+- Author : Monty
+- Updated: 1987.04.16
+- Defines: strfill()
+-
+- strfill(dest, len, fill) makes a string of fill-characters. The result
+- string is of length == len. The des+len character is allways set to NULL.
+- strfill() returns pointer to dest+len;
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-my_string strfill(my_string s, size_t len, pchar fill)
+-{
+- while (len--) *s++ = fill;
+- *(s) = '\0';
+- return(s);
+-} /* strfill */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/string.c mariadb-native-client.trunk/libmysql/string.c
+--- mariadb/libmysql/string.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/string.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,127 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Code for handling strings with can grow dynamicly.
+- Copyright Monty Program KB.
+- By monty.
+-*/
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-
+-my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
+- size_t init_alloc, size_t alloc_increment)
+-{
+- uint length;
+- DBUG_ENTER("init_dynamic_string");
+-
+- if (!alloc_increment)
+- alloc_increment=128;
+- length=1;
+- if (init_str && (length= (uint) strlen(init_str)+1) < init_alloc)
+- init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
+- if (!init_alloc)
+- init_alloc=alloc_increment;
+-
+- if (!(str->str=(char*) my_malloc(init_alloc,MYF(MY_WME))))
+- DBUG_RETURN(TRUE);
+- str->length=length-1;
+- if (init_str)
+- memcpy(str->str,init_str,length);
+- str->max_length=init_alloc;
+- str->alloc_increment=alloc_increment;
+- DBUG_RETURN(FALSE);
+-}
+-
+-
+-my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
+-{
+- uint length;
+- DBUG_ENTER("dynstr_set");
+-
+- if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length)
+- {
+- str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)*
+- str->alloc_increment;
+- if (!str->max_length)
+- str->max_length=str->alloc_increment;
+- if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+- DBUG_RETURN(TRUE);
+- }
+- if (init_str)
+- {
+- str->length=length-1;
+- memcpy(str->str,init_str,length);
+- }
+- else
+- str->length=0;
+- DBUG_RETURN(FALSE);
+-}
+-
+-
+-my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size)
+-{
+- DBUG_ENTER("dynstr_realloc");
+-
+- if (!additional_size) DBUG_RETURN(FALSE);
+- if (str->length + additional_size > str->max_length)
+- {
+- str->max_length=((str->length + additional_size+str->alloc_increment-1)/
+- str->alloc_increment)*str->alloc_increment;
+- if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+- DBUG_RETURN(TRUE);
+- }
+- DBUG_RETURN(FALSE);
+-}
+-
+-
+-my_bool dynstr_append(DYNAMIC_STRING *str, const char *append)
+-{
+- return dynstr_append_mem(str,append,strlen(append));
+-}
+-
+-
+-my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
+- size_t length)
+-{
+- char *new_ptr;
+- if (str->length+length >= str->max_length)
+- {
+- size_t new_length=(str->length+length+str->alloc_increment)/
+- str->alloc_increment;
+- new_length*=str->alloc_increment;
+- if (!(new_ptr=(char*) my_realloc(str->str,new_length,MYF(MY_WME))))
+- return TRUE;
+- str->str=new_ptr;
+- str->max_length=new_length;
+- }
+- memcpy(str->str + str->length,append,length);
+- str->length+=length;
+- str->str[str->length]=0; /* Safety for C programs */
+- return FALSE;
+-}
+-
+-
+-void dynstr_free(DYNAMIC_STRING *str)
+-{
+- if (str->str)
+- {
+- my_free(str->str,MYF(MY_WME));
+- str->str=0;
+- }
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strinstr.c mariadb-native-client.trunk/libmysql/strinstr.c
+--- mariadb/libmysql/strinstr.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strinstr.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,50 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strinstr.c
+- Author : Monty & David
+- Updated: 1986.12.08
+- Defines: strinstr()
+-
+- strinstr(src, pat) looks for an instance of pat in src. pat is not a
+- regex(3) pattern, it is a literal string which must be matched exactly.
+- The result 0 if the pattern was not found else it is the start char of
+- the pattern counted from the beginning of the string, where the first
+- char is 1.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-uint strinstr(reg1 const char *str,reg4 const char *search)
+-{
+- reg2 my_string i,j;
+- my_string start = (my_string) str;
+-
+- skipp:
+- while (*str != '\0')
+- {
+- if (*str++ == *search)
+- {
+- i=(my_string) str; j= (my_string) search+1;
+- while (*j)
+- if (*i++ != *j++) goto skipp;
+- return ((uint) (str - start));
+- }
+- }
+- return (0);
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strmake.c mariadb-native-client.trunk/libmysql/strmake.c
+--- mariadb/libmysql/strmake.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strmake.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,54 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strmake.c
+- Author : Michael Widenius
+- Updated: 20 Jul 1984
+- Defines: strmake()
+-
+- strmake(dst,src,length) moves length characters, or until end, of src to
+- dst and appends a closing NUL to dst.
+- Note that is strlen(src) >= length then dst[length] will be set to \0
+- strmake() returns pointer to closing null
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#ifdef BAD_STRING_COMPILER
+-
+-char *strmake(char *dst,const char *src, size_t length)
+-{
+- reg1 char *res;
+-
+- if ((res=memccpy(dst,src,0,length)))
+- return res-1;
+- dst[length]=0;
+- return dst+length;
+-}
+-
+-#define strmake strmake_overlapp /* Use orginal for overlapping str */
+-#endif
+-
+-char *strmake(register char *dst, register const char *src, size_t length)
+-{
+- while (length--)
+- if (! (*dst++ = *src++))
+- return dst-1;
+- *dst=0;
+- return dst;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strmov.c mariadb-native-client.trunk/libmysql/strmov.c
+--- mariadb/libmysql/strmov.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strmov.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,59 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- strmov(dst, src) moves all the characters of src (including the
+- closing NUL) to dst, and returns a pointer to the new closing NUL in
+- dst. The similar UNIX routine strcpy returns the old value of dst,
+- which I have never found useful. strmov(strmov(dst,a),b) moves a//b
+- into dst, which seems useful.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#ifdef BAD_STRING_COMPILER
+-#undef strmov
+-#define strmov strmov_overlapp
+-#endif
+-
+-#ifndef strmov
+-
+-#if !defined(MC68000) && !defined(DS90)
+-
+-char *strmov(register char *dst, register const char *src)
+-{
+- while ((*dst++ = *src++)) ;
+- return dst-1;
+-}
+-
+-#else
+-
+-char *strmov(dst, src)
+- char *dst, *src;
+-{
+- asm(" movl 4(a7),a1 ");
+- asm(" movl 8(a7),a0 ");
+- asm(".L4: movb (a0)+,(a1)+ ");
+- asm(" jne .L4 ");
+- asm(" movl a1,d0 ");
+- asm(" subql #1,d0 ");
+-}
+-
+-#endif
+-
+-#endif /* strmov */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strnlen.c mariadb-native-client.trunk/libmysql/strnlen.c
+--- mariadb/libmysql/strnlen.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strnlen.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strnlen.c
+- Author : Michael Widenius
+- Updated: 20 April 1984
+- Defines: strnlen.
+- strnlen(s, len) returns the length of s or len if s is longer than len.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-#ifndef HAVE_STRNLEN
+-
+-uint strnlen(register const char *s, register uint maxlen)
+-{
+- const char *end= (const char *)memchr(s, '\0', maxlen);
+- return end ? (uint) (end - s) : maxlen;
+-}
+-
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strnmov.c mariadb-native-client.trunk/libmysql/strnmov.c
+--- mariadb/libmysql/strnmov.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strnmov.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- strnmov(dst,src,length) moves length characters, or until end, of src to
+- dst and appends a closing NUL to dst if src is shorter than length.
+- The result is a pointer to the first NUL in dst, or is dst+n if dst was
+- truncated.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-
+-char *strnmov(register char *dst, register const char *src, uint n)
+-{
+- while (n-- != 0) {
+- if (!(*dst++ = *src++)) {
+- return (char*) dst-1;
+- }
+- }
+- return dst;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strto.c mariadb-native-client.trunk/libmysql/strto.c
+--- mariadb/libmysql/strto.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strto.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,210 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- strtol,strtoul,strtoll,strtoull
+- convert string to long, unsigned long, long long or unsigned long long.
+- strtoxx(char *src,char **ptr,int base)
+- converts the string pointed to by src to an long of appropriate long and
+- returnes it. It skips leading spaces and tabs (but not newlines, formfeeds,
+- backspaces), then it accepts an optional sign and a sequence of digits
+- in the specified radix.
+- If the value of ptr is not (char **)NULL, a pointer to the character
+- terminating the scan is returned in the location pointed to by ptr.
+- Trailing spaces will NOT be skipped.
+-
+- If an error is detected, the result will be LONG_MIN, 0 or LONG_MAX,
+- (or LONGLONG..) and errno will be set to
+- EDOM if there are no digits
+- ERANGE if the result would overflow.
+- the ptr will be set to src.
+- This file is based on the strtol from the the GNU C Library.
+- it can be compiled with the UNSIGNED and/or LONGLONG flag set
+-*/
+-
+-#define strtoll glob_strtoll /* Fix for True64 */
+-
+-#include <global.h>
+-#include "m_string.h"
+-#include "m_ctype.h"
+-#include "my_sys.h" /* defines errno */
+-#include <errno.h>
+-
+-#undef strtoull
+-#undef strtoll
+-#undef strtoul
+-#undef strtol
+-#ifdef USE_LONGLONG
+-#define UTYPE_MAX (~(ulonglong) 0)
+-#define TYPE_MIN LONGLONG_MIN
+-#define TYPE_MAX LONGLONG_MAX
+-#define longtype longlong
+-#define ulongtype ulonglong
+-#ifdef USE_UNSIGNED
+-#define function ulongtype strtoull
+-#else
+-#define function longtype strtoll
+-#endif
+-#else
+-#define UTYPE_MAX (ulong) ~0L
+-#define TYPE_MIN LONG_MIN
+-#define TYPE_MAX LONG_MAX
+-#define longtype long
+-#define ulongtype unsigned long
+-#ifdef USE_UNSIGNED
+-#define function ulongtype strtoul
+-#else
+-#define function longtype strtol
+-#endif
+-#endif
+-
+-
+-/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+- If BASE is 0 the base is determined by the presence of a leading
+- zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+- If BASE is < 2 or > 36, it is reset to 10.
+- If ENDPTR is not NULL, a pointer to the character after the last
+- one converted is stored in *ENDPTR. */
+-
+-
+-function (const char *nptr,char **endptr,int base)
+-{
+- int negative;
+- register ulongtype cutoff;
+- register unsigned int cutlim;
+- register ulongtype i;
+- register const char *s;
+- register unsigned char c;
+- const char *save;
+- int overflow;
+-
+- if (base < 0 || base == 1 || base > 36)
+- base = 10;
+-
+- s = nptr;
+-
+- /* Skip white space. */
+- while (isspace (*s))
+- ++s;
+- if (*s == '\0')
+- {
+- goto noconv;
+- }
+-
+- /* Check for a sign. */
+- if (*s == '-')
+- {
+- negative = 1;
+- ++s;
+- }
+- else if (*s == '+')
+- {
+- negative = 0;
+- ++s;
+- }
+- else
+- negative = 0;
+-
+- if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
+- s += 2;
+-
+- /* If BASE is zero, figure it out ourselves. */
+- if (base == 0)
+- {
+- if (*s == '0')
+- {
+- if (toupper (s[1]) == 'X')
+- {
+- s += 2;
+- base = 16;
+- }
+- else
+- base = 8;
+- }
+- else
+- base = 10;
+- }
+-
+- /* Save the pointer so we can check later if anything happened. */
+- save = s;
+-
+- cutoff = UTYPE_MAX / (unsigned long int) base;
+- cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
+-
+- overflow = 0;
+- i = 0;
+- for (c = *s; c != '\0'; c = *++s)
+- {
+- if (isdigit (c))
+- c -= '0';
+- else if (isalpha (c))
+- c = toupper (c) - 'A' + 10;
+- else
+- break;
+- if (c >= base)
+- break;
+- /* Check for overflow. */
+- if (i > cutoff || (i == cutoff && c > cutlim))
+- overflow = 1;
+- else
+- {
+- i *= (ulongtype) base;
+- i += c;
+- }
+- }
+-
+- /* Check if anything actually happened. */
+- if (s == save)
+- goto noconv;
+-
+- /* Store in ENDPTR the address of one character
+- past the last character we converted. */
+- if (endptr != NULL)
+- *endptr = (char *) s;
+-
+-#ifndef USE_UNSIGNED
+- /* Check for a value that is within the range of
+- `unsigned long int', but outside the range of `long int'. */
+- if (negative)
+- {
+- if (i > (ulongtype) TYPE_MIN)
+- overflow = 1;
+- }
+- else if (i > (ulongtype) TYPE_MAX)
+- overflow = 1;
+-#endif
+-
+- if (overflow)
+- {
+- my_errno=ERANGE;
+-#ifdef USE_UNSIGNED
+- return UTYPE_MAX;
+-#else
+- return negative ? TYPE_MIN : TYPE_MAX;
+-#endif
+- }
+-
+- /* Return the result of the appropriate sign. */
+- return (negative ? -((longtype) i) : (longtype) i);
+-
+-noconv:
+- /* There was no number to convert. */
+- my_errno=EDOM;
+- if (endptr != NULL)
+- *endptr = (char *) nptr;
+- return 0L;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strtoll.c mariadb-native-client.trunk/libmysql/strtoll.c
+--- mariadb/libmysql/strtoll.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strtoll.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,199 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* This is defines strtoll() if neaded */
+-
+-#include <my_global.h>
+-#include <m_string.h>
+-#if !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
+-#define USE_LONGLONG
+-
+-#define strtoll glob_strtoll /* Fix for True64 */
+-
+-#include <global.h>
+-#include "m_string.h"
+-#include "m_ctype.h"
+-#include "my_sys.h" /* defines errno */
+-#include <errno.h>
+-
+-#undef strtoull
+-#undef strtoll
+-#undef strtoul
+-#undef strtol
+-#ifdef USE_LONGLONG
+-#define UTYPE_MAX (~(ulonglong) 0)
+-#define TYPE_MIN LONGLONG_MIN
+-#define TYPE_MAX LONGLONG_MAX
+-#define longtype longlong
+-#define ulongtype ulonglong
+-#ifdef USE_UNSIGNED
+-#define function ulongtype strtoull
+-#else
+-#define function longtype strtoll
+-#endif
+-#else
+-#define UTYPE_MAX (ulong) ~0L
+-#define TYPE_MIN LONG_MIN
+-#define TYPE_MAX LONG_MAX
+-#define longtype long
+-#define ulongtype unsigned long
+-#ifdef USE_UNSIGNED
+-#define function ulongtype strtoul
+-#else
+-#define function longtype strtol
+-#endif
+-#endif
+-
+-
+-/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+- If BASE is 0 the base is determined by the presence of a leading
+- zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+- If BASE is < 2 or > 36, it is reset to 10.
+- If ENDPTR is not NULL, a pointer to the character after the last
+- one converted is stored in *ENDPTR. */
+-
+-
+-function (const char *nptr,char **endptr,int base)
+-{
+- int negative;
+- register ulongtype cutoff;
+- register unsigned int cutlim;
+- register ulongtype i;
+- register const char *s;
+- register unsigned char c;
+- const char *save;
+- int overflow;
+-
+- if (base < 0 || base == 1 || base > 36)
+- base = 10;
+-
+- s = nptr;
+-
+- /* Skip white space. */
+- while (isspace (*s))
+- ++s;
+- if (*s == '\0')
+- {
+- goto noconv;
+- }
+-
+- /* Check for a sign. */
+- if (*s == '-')
+- {
+- negative = 1;
+- ++s;
+- }
+- else if (*s == '+')
+- {
+- negative = 0;
+- ++s;
+- }
+- else
+- negative = 0;
+-
+- if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
+- s += 2;
+-
+- /* If BASE is zero, figure it out ourselves. */
+- if (base == 0)
+- {
+- if (*s == '0')
+- {
+- if (toupper (s[1]) == 'X')
+- {
+- s += 2;
+- base = 16;
+- }
+- else
+- base = 8;
+- }
+- else
+- base = 10;
+- }
+-
+- /* Save the pointer so we can check later if anything happened. */
+- save = s;
+-
+- cutoff = UTYPE_MAX / (unsigned long int) base;
+- cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
+-
+- overflow = 0;
+- i = 0;
+- for (c = *s; c != '\0'; c = *++s)
+- {
+- if (isdigit (c))
+- c -= '0';
+- else if (isalpha (c))
+- c = toupper (c) - 'A' + 10;
+- else
+- break;
+- if (c >= base)
+- break;
+- /* Check for overflow. */
+- if (i > cutoff || (i == cutoff && c > cutlim))
+- overflow = 1;
+- else
+- {
+- i *= (ulongtype) base;
+- i += c;
+- }
+- }
+-
+- /* Check if anything actually happened. */
+- if (s == save)
+- goto noconv;
+-
+- /* Store in ENDPTR the address of one character
+- past the last character we converted. */
+- if (endptr != NULL)
+- *endptr = (char *) s;
+-
+-#ifndef USE_UNSIGNED
+- /* Check for a value that is within the range of
+- `unsigned long int', but outside the range of `long int'. */
+- if (negative)
+- {
+- if (i > (ulongtype) TYPE_MIN)
+- overflow = 1;
+- }
+- else if (i > (ulongtype) TYPE_MAX)
+- overflow = 1;
+-#endif
+-
+- if (overflow)
+- {
+- my_errno=ERANGE;
+-#ifdef USE_UNSIGNED
+- return UTYPE_MAX;
+-#else
+- return negative ? TYPE_MIN : TYPE_MAX;
+-#endif
+- }
+-
+- /* Return the result of the appropriate sign. */
+- return (negative ? -((longtype) i) : (longtype) i);
+-
+-noconv:
+- /* There was no number to convert. */
+- my_errno=EDOM;
+- if (endptr != NULL)
+- *endptr = (char *) nptr;
+- return 0L;
+-}
+-
+-
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strtoull.c mariadb-native-client.trunk/libmysql/strtoull.c
+--- mariadb/libmysql/strtoull.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strtoull.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,26 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* This is defines strtoull() */
+-
+-#include <my_global.h>
+-#include <m_string.h>
+-#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
+-#define USE_UNSIGNED
+-#define USE_LONGLONG
+-#include "strto.c"
+-#endif
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strxmov.c mariadb-native-client.trunk/libmysql/strxmov.c
+--- mariadb/libmysql/strxmov.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strxmov.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,50 +0,0 @@
+-/* Copyright (C) 2002 MySQL AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* File : strxmov.c
+- Author : Richard A. O'Keefe.
+- Updated: 25 may 1984
+- Defines: strxmov()
+-
+- strxmov(dst, src1, ..., srcn, NullS)
+- moves the concatenation of src1,...,srcn to dst, terminates it
+- with a NUL character, and returns a pointer to the terminating NUL.
+- It is just like strmov except that it concatenates multiple sources.
+- Beware: the last argument should be the null character pointer.
+- Take VERY great care not to omit it! Also be careful to use NullS
+- and NOT to use 0, as on some machines 0 is not the same size as a
+- character pointer, or not the same bit pattern as NullS.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-#include <stdarg.h>
+-
+-char *strxmov(char *dst,const char *src, ...)
+-{
+- va_list pvar;
+-
+- va_start(pvar,src);
+- while (src != NullS) {
+- while ((*dst++ = *src++)) ;
+- dst--;
+- src = va_arg(pvar, char *);
+- }
+- va_end(pvar);
+- *dst = 0; /* there might have been no sources! */
+- return dst;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/strxnmov.c mariadb-native-client.trunk/libmysql/strxnmov.c
+--- mariadb/libmysql/strxnmov.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/strxnmov.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,48 +0,0 @@
+-/* File : strxnmov.c
+- Author : Richard A. O'Keefe.
+- Updated: 2 June 1984
+- Defines: strxnmov()
+-
+- strxnmov(dst, len, src1, ..., srcn, NullS)
+- moves the first len characters of the concatenation of src1,...,srcn
+- to dst. If there aren't that many characters, a NUL character will
+- be added to the end of dst to terminate it properly. This gives the
+- same effect as calling strxcpy(buff, src1, ..., srcn, NullS) with a
+- large enough buffer, and then calling strnmov(dst, buff, len).
+- It is just like strnmov except that it concatenates multiple sources.
+- Beware: the last argument should be the null character pointer.
+- Take VERY great care not to omit it! Also be careful to use NullS
+- and NOT to use 0, as on some machines 0 is not the same size as a
+- character pointer, or not the same bit pattern as NullS.
+-
+- Note: strxnmov is like strnmov in that it moves up to len
+- characters; dst will be padded on the right with one NUL characters if
+- needed.
+-*/
+-
+-#include <my_global.h>
+-#include "m_string.h"
+-#include <stdarg.h>
+-
+-char *strxnmov(char *dst, size_t len, const char *src, ...)
+-{
+- va_list pvar;
+- char *end_of_dst=dst+len;
+-
+- va_start(pvar,src);
+- while (src != NullS)
+- {
+- do
+- {
+- if (dst == end_of_dst)
+- goto end;
+- }
+- while ((*dst++ = *src++));
+- dst--;
+- src = va_arg(pvar, char *);
+- }
+- *dst=0;
+-end:
+- va_end(pvar);
+- return dst;
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/thr_mutex.c mariadb-native-client.trunk/libmysql/thr_mutex.c
+--- mariadb/libmysql/thr_mutex.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/thr_mutex.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,231 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* This makes a wrapper for mutex handling to make it easier to debug mutex */
+-
+-#include <my_global.h>
+-#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98)
+-#define __USE_UNIX98 /* To get rw locks under Linux */
+-#endif
+-#include <m_string.h>
+-#if defined(THREAD) && defined(SAFE_MUTEX)
+-#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
+-#include <my_pthread.h>
+-
+-#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
+-/* Remove wrappers */
+-#undef pthread_mutex_init
+-#undef pthread_mutex_lock
+-#undef pthread_mutex_unlock
+-#undef pthread_mutex_destroy
+-#undef pthread_cond_wait
+-#undef pthread_cond_timedwait
+-#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
+-#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
+-#endif
+-#endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */
+-
+-int safe_mutex_init(safe_mutex_t *mp,
+- const pthread_mutexattr_t *attr __attribute__((unused)))
+-{
+- bzero((char*) mp,sizeof(*mp));
+- pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
+- pthread_mutex_init(&mp->mutex,attr);
+- return 0;
+-}
+-
+-int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
+-{
+- int error;
+- pthread_mutex_lock(&mp->global);
+- if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
+- {
+- fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d\n",
+- file,line,mp->file,mp->line);
+- fflush(stderr);
+- abort();
+- }
+- pthread_mutex_unlock(&mp->global);
+- error=pthread_mutex_lock(&mp->mutex);
+- if (error || (error=pthread_mutex_lock(&mp->global)))
+- {
+- fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
+- error, file, line);
+- fflush(stderr);
+- abort();
+- }
+- if (mp->count++)
+- {
+- fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, line %d more than 1 time\n", file,line);
+- fflush(stderr);
+- abort();
+- }
+- mp->thread=pthread_self();
+- mp->file= (char*) file;
+- mp->line=line;
+- pthread_mutex_unlock(&mp->global);
+- return error;
+-}
+-
+-
+-int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
+-{
+- int error;
+- pthread_mutex_lock(&mp->global);
+- if (mp->count == 0)
+- {
+- fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n Last used at %s, line: %d\n",
+- file,line,mp->file ? mp->file : "",mp->line);
+- fflush(stderr);
+- abort();
+- }
+- if (!pthread_equal(pthread_self(),mp->thread))
+- {
+- fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+- file,line,mp->file,mp->line);
+- fflush(stderr);
+- abort();
+- }
+- mp->count--;
+-#ifdef _WIN32
+- pthread_mutex_unlock(&mp->mutex);
+- error=0;
+-#else
+- error=pthread_mutex_unlock(&mp->mutex);
+- if (error)
+- {
+- fprintf(stderr,"safe_mutex: Got error: %d when trying to unlock mutex at %s, line %d\n", error, file, line);
+- fflush(stderr);
+- abort();
+- }
+-#endif /* _WIN32 */
+- pthread_mutex_unlock(&mp->global);
+- return error;
+-}
+-
+-
+-int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
+- uint line)
+-{
+- int error;
+- pthread_mutex_lock(&mp->global);
+- if (mp->count == 0)
+- {
+- fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
+- fflush(stderr);
+- abort();
+- }
+- if (!pthread_equal(pthread_self(),mp->thread))
+- {
+- fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+- file,line,mp->file,mp->line);
+- fflush(stderr);
+- abort();
+- }
+-
+- if (mp->count-- != 1)
+- {
+- fprintf(stderr,"safe_mutex: Count was %d on locked mutex at %s, line %d\n",
+- mp->count+1, file, line);
+- fflush(stderr);
+- abort();
+- }
+- pthread_mutex_unlock(&mp->global);
+- error=pthread_cond_wait(cond,&mp->mutex);
+- pthread_mutex_lock(&mp->global);
+- if (error)
+- {
+- fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_wait at %s, line %d\n", error, file, line);
+- fflush(stderr);
+- abort();
+- }
+- if (mp->count++)
+- {
+- fprintf(stderr,
+- "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d\n",
+- mp->count-1, my_thread_id(), file, line);
+- fflush(stderr);
+- abort();
+- }
+- mp->thread=pthread_self();
+- mp->file= (char*) file;
+- mp->line=line;
+- pthread_mutex_unlock(&mp->global);
+- return error;
+-}
+-
+-
+-int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
+- struct timespec *abstime,
+- const char *file, uint line)
+-{
+- int error;
+- pthread_mutex_lock(&mp->global);
+- if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
+- {
+- fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
+- fflush(stderr);
+- abort();
+- }
+- mp->count--; /* Mutex will be released */
+- pthread_mutex_unlock(&mp->global);
+- error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
+-#ifdef EXTRA_DEBUG
+- if (error && (error != EINTR && error != ETIMEDOUT))
+- {
+- fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_timedwait at %s, line %d\n", error, file, line);
+- }
+-#endif
+- pthread_mutex_lock(&mp->global);
+- if (mp->count++)
+- {
+- fprintf(stderr,
+- "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d (error: %d)\n",
+- mp->count-1, my_thread_id(), file, line, error);
+- fflush(stderr);
+- abort();
+- }
+- mp->thread=pthread_self();
+- mp->file= (char*) file;
+- mp->line=line;
+- pthread_mutex_unlock(&mp->global);
+- return error;
+-}
+-
+-int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
+-{
+- int error=0;
+- if (mp->count != 0)
+- {
+- fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
+- mp->file,mp->line, file, line);
+- fflush(stderr);
+- abort();
+- }
+-#ifdef _WIN32
+- pthread_mutex_destroy(&mp->global);
+- pthread_mutex_destroy(&mp->mutex);
+-#else
+- if (pthread_mutex_destroy(&mp->global))
+- error=1;
+- if (pthread_mutex_destroy(&mp->mutex))
+- error=1;
+-#endif
+- return error;
+-}
+-
+-#endif /* THREAD && SAFE_MUTEX */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/typelib.c mariadb-native-client.trunk/libmysql/typelib.c
+--- mariadb/libmysql/typelib.c 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/libmysql/typelib.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,106 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/* Functions to handle typelib */
+-
+-#include "mysys_priv.h"
+-#include <m_string.h>
+-#include <m_ctype.h>
+-
+-/***************************************************************************
+-** Search after a fieldtype. Endspace in x is not compared.
+-** If part, uniq field is found and full_name == 0 then x is expanded
+-** to full field.
+-** full_name has the following bit values:
+-** If & 1 accept only whole names
+-** If & 2 don't expand if half field
+-** If & 4 allow #number# as type
+-****************************************************************************/
+-
+-int find_type(my_string x, TYPELIB *typelib, uint full_name)
+-{
+- int find,pos,findpos= 0;
+- reg1 my_string i;
+- reg2 const char *j;
+- DBUG_ENTER("find_type");
+- DBUG_PRINT("enter",("x: '%s' lib: %lx",x,typelib));
+-
+- if (!typelib->count)
+- {
+- DBUG_PRINT("exit",("no count"));
+- DBUG_RETURN(0);
+- }
+- LINT_INIT(findpos);
+- find=0;
+- for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
+- {
+- for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
+- if (! *j)
+- {
+- while (*i == ' ')
+- i++; /* skipp_end_space */
+- if (! *i)
+- DBUG_RETURN(pos+1);
+- }
+- if (! *i && (!*j || !(full_name & 1)))
+- {
+- find++;
+- findpos=pos;
+- }
+- }
+- if (find == 0 && (full_name & 4) && x[0] == '#' && strend(x)[-1] == '#' &&
+- (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
+- find=1;
+- else if (find == 0 || ! x[0])
+- {
+- DBUG_PRINT("exit",("Couldn't find type"));
+- DBUG_RETURN(0);
+- }
+- else if (find != 1 || (full_name & 1))
+- {
+- DBUG_PRINT("exit",("Too many possybilities"));
+- DBUG_RETURN(-1);
+- }
+- if (!(full_name & 2))
+- (void) strmov(x,typelib->type_names[findpos]);
+- DBUG_RETURN(findpos+1);
+-} /* find_type */
+-
+-
+- /* Get name of type nr 'nr' */
+- /* Warning first type is 1, 0 = empty field */
+-
+-void make_type(register my_string to, register uint nr, register TYPELIB *typelib)
+-{
+- DBUG_ENTER("make_type");
+- if (!nr)
+- to[0]=0;
+- else
+- (void) strmov(to,get_type(typelib,nr-1));
+- DBUG_VOID_RETURN;
+-} /* make_type */
+-
+-
+- /* Get type */
+- /* Warning first type is 0 */
+-
+-const char *get_type(TYPELIB *typelib, uint nr)
+-{
+- if (nr < (uint) typelib->count && typelib->type_names)
+- return(typelib->type_names[nr]);
+- return "?";
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/version_script.txt mariadb-native-client.trunk/libmysql/version_script.txt
+--- mariadb/libmysql/version_script.txt 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/version_script.txt 1970-01-01 01:00:00.000000000 +0100
+@@ -1,108 +0,0 @@
+-{
+-global:
+- get_tty_password;
+- load_defaults;
+- mysql_thread_end;
+- mysql_thread_init;
+- myodbc_remove_escape;
+- mysql_affected_rows;
+- mysql_autocommit;
+- mysql_stmt_bind_param;
+- mysql_stmt_bind_result;
+- mysql_change_user;
+- mysql_character_set_name;
+- mysql_close;
+- mysql_commit;
+- mysql_data_seek;
+- mysql_debug;
+- mysql_dump_debug_info;
+- mysql_eof;
+- mysql_errno;
+- mysql_error;
+- mysql_escape_string;
+- mysql_hex_string;
+- mysql_stmt_execute;
+- mysql_stmt_fetch;
+- mysql_stmt_fetch_column;
+- mysql_fetch_field;
+- mysql_fetch_field_direct;
+- mysql_fetch_fields;
+- mysql_fetch_lengths;
+- mysql_fetch_row;
+- mysql_field_count;
+- mysql_field_seek;
+- mysql_field_tell;
+- mysql_free_result;
+- mysql_get_client_info;
+- mysql_get_host_info;
+- mysql_get_proto_info;
+- mysql_get_server_info;
+- mysql_get_client_version;
+- mysql_get_ssl_cipher;
+- mysql_info;
+- mysql_init;
+- mysql_insert_id;
+- mysql_kill;
+- mysql_set_server_option;
+- mysql_list_dbs;
+- mysql_list_fields;
+- mysql_list_processes;
+- mysql_list_tables;
+- mysql_more_results;
+- mysql_next_result;
+- mysql_num_fields;
+- mysql_num_rows;
+- mysql_options;
+- mysql_stmt_param_count;
+- mysql_ping;
+- mysql_stmt_result_metadata;
+- mysql_query;
+- mysql_read_query_result;
+- mysql_real_connect;
+- mysql_real_escape_string;
+- mysql_real_query;
+- mysql_refresh;
+- mysql_rollback;
+- mysql_row_seek;
+- mysql_row_tell;
+- mysql_select_db;
+- mysql_stmt_send_long_data;
+- mysql_send_query;
+- mysql_shutdown;
+- mysql_ssl_set;
+- mysql_stat;
+- mysql_stmt_affected_rows;
+- mysql_stmt_close;
+- mysql_stmt_reset;
+- mysql_stmt_data_seek;
+- mysql_stmt_errno;
+- mysql_stmt_error;
+- mysql_stmt_free_result;
+- mysql_stmt_num_rows;
+- mysql_stmt_row_seek;
+- mysql_stmt_row_tell;
+- mysql_stmt_store_result;
+- mysql_store_result;
+- mysql_thread_id;
+- mysql_thread_safe;
+- mysql_use_result;
+- mysql_warning_count;
+- mysql_stmt_sqlstate;
+- mysql_sqlstate;
+- mysql_get_server_version;
+- mysql_stmt_prepare;
+- mysql_stmt_init;
+- mysql_stmt_insert_id;
+- mysql_stmt_attr_get;
+- mysql_stmt_attr_set;
+- mysql_stmt_field_count;
+- mysql_set_local_infile_default;
+- mysql_set_local_infile_handler;
+- mysql_server_init;
+- mysql_server_end;
+- mysql_set_character_set;
+- mysql_get_character_set_info;
+-local:
+- *;
+-};
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/libmysql/violite.c mariadb-native-client.trunk/libmysql/violite.c
+--- mariadb/libmysql/violite.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/libmysql/violite.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,486 +0,0 @@
+-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+- MA 02111-1307, USA */
+-
+-/*
+- Note that we can't have assertion on file descriptors; The reason for
+- this is that during mysql shutdown, another thread can close a file
+- we are working on. In this case we should just return read errors from
+- the file descriptior.
+-*/
+-
+-#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
+-
+-#include <my_global.h>
+-#include <errno.h>
+-#include <assert.h>
+-#include <violite.h>
+-#include <my_sys.h>
+-#include <my_net.h>
+-#include <m_string.h>
+-#ifdef HAVE_POLL
+-#include <sys/poll.h>
+-#endif
+-#ifdef HAVE_SYS_IOCTL_H
+-#include <sys/ioctl.h>
+-#endif
+-#ifdef HAVE_FCNTL_H
+-#include <fcntl.h>
+-#endif
+-
+-#ifdef HAVE_OPENSSL
+-#include <my_secure.h>
+-#endif
+-
+-#ifdef _WIN32
+-#define socklen_t int
+-#pragma comment (lib, "ws2_32")
+-#endif
+-
+-#if !defined(MSDOS) && !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__FreeBSD__)
+-#include <netinet/in_systm.h>
+-#include <netinet/ip.h>
+-#if !defined(alpha_linux_port)
+-#include <netinet/tcp.h>
+-#endif
+-#endif
+-
+-#if defined(__EMX__) || defined(OS2)
+-#define ioctlsocket ioctl
+-#endif /* defined(__EMX__) */
+-
+-#if defined(MSDOS) || defined(_WIN32)
+-#define O_NONBLOCK 1 /* For emulation of fcntl() */
+-#endif
+-#ifndef EWOULDBLOCK
+-#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN
+-#endif
+-
+-
+-typedef void *vio_ptr;
+-typedef char *vio_cstring;
+-
+-/*
+- * 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)
+-{
+- bzero((char*) vio, sizeof(*vio));
+- vio->type= type;
+- vio->sd= sd;
+- vio->hPipe= hPipe;
+- vio->localhost= localhost;
+-}
+-
+-void vio_timeout(Vio *vio, int type, uint seconds)
+-{
+-#ifdef _WIN32
+- uint timeout= seconds * 1000; /* milli secs */
+-#else
+- struct timeval timeout;
+- timeout.tv_sec= seconds;
+- timeout.tv_usec= 0;
+-#endif
+-
+- if (setsockopt(vio->sd, SOL_SOCKET, type,
+-#ifdef _WIN32
+- (const char *)&timeout,
+-#else
+- (const void *)&timeout,
+-#endif
+- sizeof(timeout)))
+- {
+- DBUG_PRINT("error", ("setsockopt failed. Errno: %d", errno));
+- }
+-}
+-
+-void vio_read_timeout(Vio *vio, uint seconds)
+-{
+- vio_timeout(vio, SO_RCVTIMEO, seconds);
+-}
+-
+-void vio_write_timeout(Vio *vio, uint seconds)
+-{
+- vio_timeout(vio, SO_SNDTIMEO, seconds);
+-}
+-
+-/* 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;
+- 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);
+- sprintf(vio->desc,
+- (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
+- vio->sd);
+-#if !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
+-#if !defined(NO_FCNTL_NONBLOCK)
+- vio->fcntl_mode = fcntl(sd, F_GETFL);
+-#elif defined(HAVE_SYS_IOCTL_H) /* hpux */
+- /* Non blocking sockets doesn't work good on HPUX 11.0 */
+- (void) ioctl(sd,FIOSNBIO,0);
+-#endif
+-#else /* !defined(_WIN32) && !defined(__EMX__) */
+- {
+- /* set to blocking mode by default */
+- ulong arg=0, r;
+- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
+- }
+-#endif
+- }
+- DBUG_RETURN(vio);
+-}
+-
+-
+-#ifdef _WIN32
+-
+-Vio *vio_new_win32pipe(HANDLE hPipe)
+-{
+- Vio *vio;
+- DBUG_ENTER("vio_new_handle");
+- if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
+- {
+- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
+- strmov(vio->desc, "named pipe");
+- }
+- DBUG_RETURN(vio);
+-}
+-
+-#endif
+-
+-void vio_delete(Vio * vio)
+-{
+- /* It must be safe to delete null pointers. */
+- /* This matches the semantics of C++'s delete operator. */
+- if (vio)
+- {
+- if (vio->type != VIO_CLOSED)
+- vio_close(vio);
+- my_free((gptr) vio,MYF(0));
+- }
+-}
+-
+-int vio_errno(Vio *vio __attribute__((unused)))
+-{
+- return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
+-}
+-
+-
+-int vio_read(Vio * vio, gptr buf, int size)
+-{
+- int r;
+- DBUG_ENTER("vio_read");
+- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
+-
+-#ifdef HAVE_OPENSSL
+- if (vio->type == VIO_TYPE_SSL)
+- {
+- r= my_ssl_read(vio, (uchar *)buf, size);
+- DBUG_RETURN(r);
+- }
+-#endif
+-
+-#if defined( _WIN32) || defined(OS2)
+- if (vio->type == VIO_TYPE_NAMEDPIPE)
+- {
+- DWORD length;
+-#ifdef OS2
+- if (!DosRead((HFILE)vio->hPipe, buf, size, &length))
+- DBUG_RETURN(-1);
+-#else
+- if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
+- DBUG_RETURN(-1);
+-#endif
+- DBUG_RETURN(length);
+- }
+- r = recv(vio->sd, buf, size,0);
+-#else
+- errno=0; /* For linux */
+- r = read(vio->sd, buf, size);
+-#endif /* _WIN32 */
+-#ifndef DBUG_OFF
+- if (r < 0)
+- {
+- DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno));
+- }
+-#endif /* DBUG_OFF */
+- DBUG_PRINT("exit", ("%d", r));
+- DBUG_RETURN(r);
+-}
+-
+-
+-int vio_write(Vio * vio, const gptr buf, int size)
+-{
+- int r;
+- DBUG_ENTER("vio_write");
+- DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size));
+-#ifdef HAVE_OPENSSL
+- if (vio->type == VIO_TYPE_SSL)
+- {
+- r= my_ssl_write(vio, (uchar *)buf, size);
+- DBUG_RETURN(r);
+- }
+-#endif
+-#if defined( _WIN32) || defined(OS2)
+- if ( vio->type == VIO_TYPE_NAMEDPIPE)
+- {
+- DWORD length;
+-#ifdef OS2
+- if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length))
+- DBUG_RETURN(-1);
+-#else
+- if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
+- DBUG_RETURN(-1);
+-#endif
+- DBUG_RETURN(length);
+- }
+- r = send(vio->sd, buf, size,0);
+-#else
+- r = write(vio->sd, buf, size);
+-#endif /* _WIN32 */
+-#ifndef DBUG_OFF
+- if (r < 0)
+- {
+- DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno));
+- }
+-#endif /* DBUG_OFF */
+- DBUG_PRINT("exit", ("%d", r));
+- DBUG_RETURN(r);
+-}
+-
+-
+-int vio_blocking(Vio * vio, my_bool set_blocking_mode)
+-{
+- int r=0;
+- DBUG_ENTER("vio_blocking");
+- DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
+-
+-#if !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
+-#if !defined(NO_FCNTL_NONBLOCK)
+-
+- if (vio->sd >= 0)
+- {
+- int old_fcntl=vio->fcntl_mode;
+- if (set_blocking_mode)
+- vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
+- else
+- vio->fcntl_mode |= O_NONBLOCK; /* set bit */
+- if (old_fcntl != vio->fcntl_mode)
+- r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
+- }
+-#endif /* !defined(NO_FCNTL_NONBLOCK) */
+-#else /* !defined(_WIN32) && !defined(__EMX__) */
+-#ifndef __EMX__
+- if (vio->type != VIO_TYPE_NAMEDPIPE)
+-#endif
+- {
+- ulong arg;
+- int old_fcntl=vio->fcntl_mode;
+- if (set_blocking_mode)
+- {
+- arg = 0;
+- vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
+- }
+- else
+- {
+- arg = 1;
+- vio->fcntl_mode |= O_NONBLOCK; /* set bit */
+- }
+- if (old_fcntl != vio->fcntl_mode)
+- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
+- }
+-#endif /* !defined(_WIN32) && !defined(__EMX__) */
+- DBUG_RETURN(r);
+-}
+-
+-my_bool
+-vio_is_blocking(Vio * vio)
+-{
+- my_bool r;
+- DBUG_ENTER("vio_is_blocking");
+- r = !(vio->fcntl_mode & O_NONBLOCK);
+- DBUG_PRINT("exit", ("%d", (int) r));
+- DBUG_RETURN(r);
+-}
+-
+-
+-int vio_fastsend(Vio * vio __attribute__((unused)))
+-{
+- int r=0;
+- DBUG_ENTER("vio_fastsend");
+-
+-#ifdef IPTOS_THROUGHPUT
+- {
+-#ifndef __EMX__
+- int tos = IPTOS_THROUGHPUT;
+- if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos)))
+-#endif /* !__EMX__ */
+- {
+- int nodelay = 1;
+- if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
+- sizeof(nodelay))) {
+- DBUG_PRINT("warning",
+- ("Couldn't set socket option for fast send"));
+- r= -1;
+- }
+- }
+- }
+-#endif /* IPTOS_THROUGHPUT */
+- DBUG_PRINT("exit", ("%d", r));
+- DBUG_RETURN(r);
+-}
+-
+-int vio_keepalive(Vio* vio, my_bool set_keep_alive)
+-{
+- int r=0;
+- uint opt = 0;
+- DBUG_ENTER("vio_keepalive");
+- DBUG_PRINT("enter", ("sd=%d set_keep_alive=%d", vio->sd, (int)
+- set_keep_alive));
+- if (vio->type != VIO_TYPE_NAMEDPIPE)
+- {
+- if (set_keep_alive)
+- opt = 1;
+- r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
+- sizeof(opt));
+- }
+- DBUG_RETURN(r);
+-}
+-
+-
+-my_bool
+-vio_should_retry(Vio * vio __attribute__((unused)))
+-{
+- int en = socket_errno;
+- return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK;
+-}
+-
+-
+-int vio_close(Vio * vio)
+-{
+- int r;
+- DBUG_ENTER("vio_close");
+-#ifdef HAVE_OPENSSL
+- if (vio->type == VIO_TYPE_SSL)
+- {
+- r = my_ssl_close(vio);
+- }
+-#endif
+-#ifdef _WIN32
+- if (vio->type == VIO_TYPE_NAMEDPIPE)
+- {
+- r=CloseHandle(vio->hPipe);
+- }
+- else if (vio->type != VIO_CLOSED)
+-#endif /* _WIN32 */
+- {
+- r=0;
+- if (shutdown(vio->sd,2))
+- r= -1;
+- if (closesocket(vio->sd))
+- r= -1;
+- }
+- if (r)
+- {
+- DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno));
+- /* FIXME: error handling (not critical for MySQL) */
+- }
+- vio->type= VIO_CLOSED;
+- vio->sd= -1;
+- DBUG_RETURN(r);
+-}
+-
+-
+-const char *vio_description(Vio * vio)
+-{
+- return vio->desc;
+-}
+-
+-enum enum_vio_type vio_type(Vio* vio)
+-{
+- return vio->type;
+-}
+-
+-my_socket vio_fd(Vio* vio)
+-{
+- return vio->sd;
+-}
+-
+-
+-my_bool vio_peer_addr(Vio * vio, char *buf)
+-{
+- DBUG_ENTER("vio_peer_addr");
+- DBUG_PRINT("enter", ("sd=%d", vio->sd));
+- if (vio->localhost)
+- {
+- strmov(buf,"127.0.0.1");
+- }
+- else
+- {
+- socklen_t addrLen = sizeof(struct sockaddr);
+- if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)),
+- &addrLen) != 0)
+- {
+- DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno));
+- DBUG_RETURN(1);
+- }
+- my_inet_ntoa(vio->remote.sin_addr,buf);
+- }
+- DBUG_PRINT("exit", ("addr=%s", buf));
+- DBUG_RETURN(0);
+-}
+-
+-
+-void vio_in_addr(Vio *vio, struct in_addr *in)
+-{
+- DBUG_ENTER("vio_in_addr");
+- if (vio->localhost)
+- bzero((char*) in, sizeof(*in)); /* This should never be executed */
+- else
+- *in=vio->remote.sin_addr;
+- DBUG_VOID_RETURN;
+-}
+-
+-
+-/* Return 0 if there is data to be read */
+-
+-my_bool vio_poll_read(Vio *vio,uint timeout)
+-{
+-#ifndef HAVE_POLL
+- return 0;
+-#else
+- struct pollfd fds;
+- int res;
+- DBUG_ENTER("vio_poll");
+- fds.fd=vio->sd;
+- fds.events=POLLIN;
+- fds.revents=0;
+- if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
+- {
+- DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */
+- }
+- DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
+-#endif
+-}
+-
+-#endif /* HAVE_VIO */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/LibmysqlFunctions.cmake mariadb-native-client.trunk/LibmysqlFunctions.cmake
+--- mariadb/LibmysqlFunctions.cmake 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/LibmysqlFunctions.cmake 1970-01-01 01:00:00.000000000 +0100
+@@ -1,108 +0,0 @@
+-# This file is included by CMakeLists.txt and
+-# checks for various functions.
+-# include/my_config.h.in
+-# You will find the appropiate defines in
+-
+-INCLUDE(CheckFunctionExists)
+-
+-CHECK_FUNCTION_EXISTS (access HAVE_ACCESS)
+-CHECK_FUNCTION_EXISTS (aiowait HAVE_AIOWAIT)
+-CHECK_FUNCTION_EXISTS (alarm HAVE_ALARM)
+-CHECK_FUNCTION_EXISTS (alloca HAVE_ALLOCA)
+-CHECK_FUNCTION_EXISTS (bcmp HAVE_BCMP)
+-CHECK_FUNCTION_EXISTS (bfill HAVE_BFILL)
+-CHECK_FUNCTION_EXISTS (bmove HAVE_BMOVE)
+-CHECK_FUNCTION_EXISTS (bzero HAVE_BZERO)
+-CHECK_FUNCTION_EXISTS (clock_gettime HAVE_CLOCK_GETTIME)
+-CHECK_FUNCTION_EXISTS (compress HAVE_COMPRESS)
+-CHECK_FUNCTION_EXISTS (crypt HAVE_CRYPT)
+-CHECK_FUNCTION_EXISTS (dlerror HAVE_DLERROR)
+-CHECK_FUNCTION_EXISTS (dlopen HAVE_DLOPEN)
+-CHECK_FUNCTION_EXISTS (fchmod HAVE_FCHMOD)
+-CHECK_FUNCTION_EXISTS (fcntl HAVE_FCNTL)
+-CHECK_FUNCTION_EXISTS (fconvert HAVE_FCONVERT)
+-CHECK_FUNCTION_EXISTS (fdatasync HAVE_FDATASYNC)
+-CHECK_FUNCTION_EXISTS (fesetround HAVE_FESETROUND)
+-CHECK_FUNCTION_EXISTS (finite HAVE_FINITE)
+-CHECK_FUNCTION_EXISTS (fseeko HAVE_FSEEKO)
+-CHECK_FUNCTION_EXISTS (fsync HAVE_FSYNC)
+-CHECK_FUNCTION_EXISTS (getaddrinfo HAVE_GETADDRINFO)
+-CHECK_FUNCTION_EXISTS (getcwd HAVE_GETCWD)
+-CHECK_FUNCTION_EXISTS (gethostbyaddr_r HAVE_GETHOSTBYADDR_R)
+-CHECK_FUNCTION_EXISTS (gethostbyname_r HAVE_GETHOSTBYNAME_R)
+-CHECK_FUNCTION_EXISTS (gethrtime HAVE_GETHRTIME)
+-CHECK_FUNCTION_EXISTS (getnameinfo HAVE_GETNAMEINFO)
+-CHECK_FUNCTION_EXISTS (getpagesize HAVE_GETPAGESIZE)
+-CHECK_FUNCTION_EXISTS (getpass HAVE_GETPASS)
+-CHECK_FUNCTION_EXISTS (getpassphrase HAVE_GETPASSPHRASE)
+-CHECK_FUNCTION_EXISTS (getpwnam HAVE_GETPWNAM)
+-CHECK_FUNCTION_EXISTS (getpwuid HAVE_GETPWUID)
+-CHECK_FUNCTION_EXISTS (getrlimit HAVE_GETRLIMIT)
+-CHECK_FUNCTION_EXISTS (getrusage HAVE_GETRUSAGE)
+-CHECK_FUNCTION_EXISTS (getwd HAVE_GETWD)
+-CHECK_FUNCTION_EXISTS (gmtime_r HAVE_GMTIME_R)
+-CHECK_FUNCTION_EXISTS (initgroups HAVE_INITGROUPS)
+-CHECK_FUNCTION_EXISTS (ldiv HAVE_LDIV)
+-CHECK_FUNCTION_EXISTS (localtime_r HAVE_LOCALTIME_R)
+-CHECK_FUNCTION_EXISTS (log2 HAVE_LOG2)
+-CHECK_FUNCTION_EXISTS (longjmp HAVE_LONGJMP)
+-CHECK_FUNCTION_EXISTS (lstat HAVE_LSTAT)
+-CHECK_FUNCTION_EXISTS (madvise HAVE_MADVISE)
+-CHECK_FUNCTION_EXISTS (mallinfo HAVE_MALLINFO)
+-CHECK_FUNCTION_EXISTS (memalign HAVE_MEMALIGN)
+-CHECK_FUNCTION_EXISTS (memcpy HAVE_MEMCPY)
+-CHECK_FUNCTION_EXISTS (memmove HAVE_MEMMOVE)
+-CHECK_FUNCTION_EXISTS (mkstemp HAVE_MKSTEMP)
+-CHECK_FUNCTION_EXISTS (mlock HAVE_MLOCK)
+-CHECK_FUNCTION_EXISTS (mlockall HAVE_MLOCKALL)
+-CHECK_FUNCTION_EXISTS (mmap HAVE_MMAP)
+-CHECK_FUNCTION_EXISTS (mmap64 HAVE_MMAP64)
+-CHECK_FUNCTION_EXISTS (perror HAVE_PERROR)
+-CHECK_FUNCTION_EXISTS (poll HAVE_POLL)
+-CHECK_FUNCTION_EXISTS (pread HAVE_PREAD)
+-CHECK_FUNCTION_EXISTS (pthread_attr_create HAVE_PTHREAD_ATTR_CREATE)
+-CHECK_FUNCTION_EXISTS (pthread_attr_getstacksize HAVE_PTHREAD_ATTR_GETSTACKSIZE)
+-CHECK_FUNCTION_EXISTS (pthread_attr_setprio HAVE_PTHREAD_ATTR_SETPRIO)
+-CHECK_FUNCTION_EXISTS (pthread_attr_setschedparam HAVE_PTHREAD_ATTR_SETSCHEDPARAM)
+-CHECK_FUNCTION_EXISTS (pthread_attr_setscope HAVE_PTHREAD_ATTR_SETSCOPE)
+-CHECK_FUNCTION_EXISTS (pthread_attr_setstacksize HAVE_PTHREAD_ATTR_SETSTACKSIZE)
+-CHECK_FUNCTION_EXISTS (pthread_condattr_create HAVE_PTHREAD_CONDATTR_CREATE)
+-CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT)
+-CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE)
+-CHECK_FUNCTION_EXISTS (pthread_kill HAVE_PTHREAD_KILL)
+-CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK)
+-CHECK_FUNCTION_EXISTS (pthread_setprio_np HAVE_PTHREAD_SETPRIO_NP)
+-CHECK_FUNCTION_EXISTS (pthread_setschedparam HAVE_PTHREAD_SETSCHEDPARAM)
+-CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK)
+-CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK)
+-CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP)
+-CHECK_FUNCTION_EXISTS (readdir_r HAVE_READDIR_R)
+-CHECK_FUNCTION_EXISTS (readlink HAVE_READLINK)
+-CHECK_FUNCTION_EXISTS (realpath HAVE_REALPATH)
+-CHECK_FUNCTION_EXISTS (rename HAVE_RENAME)
+-CHECK_FUNCTION_EXISTS (sched_yield HAVE_SCHED_YIELD)
+-CHECK_FUNCTION_EXISTS (select HAVE_SELECT)
+-CHECK_FUNCTION_EXISTS (setfd HAVE_SETFD)
+-CHECK_FUNCTION_EXISTS (setfilepointer HAVE_SETFILEPOINTER)
+-CHECK_FUNCTION_EXISTS (sigaction HAVE_SIGACTION)
+-CHECK_FUNCTION_EXISTS (sigthreadmask HAVE_SIGTHREADMASK)
+-CHECK_FUNCTION_EXISTS (sigwait HAVE_SIGWAIT)
+-CHECK_FUNCTION_EXISTS (sleep HAVE_SLEEP)
+-CHECK_FUNCTION_EXISTS (snprintf HAVE_SNPRINTF)
+-CHECK_FUNCTION_EXISTS (stpcpy HAVE_STPCPY)
+-CHECK_FUNCTION_EXISTS (strerror HAVE_STRERROR)
+-CHECK_FUNCTION_EXISTS (strlcpy HAVE_STRLCPY)
+-CHECK_FUNCTION_EXISTS (strnlen HAVE_STRNLEN)
+-CHECK_FUNCTION_EXISTS (strpbrk HAVE_STRPBRK)
+-CHECK_FUNCTION_EXISTS (strsep HAVE_STRSEP)
+-CHECK_FUNCTION_EXISTS (strstr HAVE_STRSTR)
+-CHECK_FUNCTION_EXISTS (strtok_r HAVE_STRTOK_R)
+-CHECK_FUNCTION_EXISTS (strtol HAVE_STRTOL)
+-CHECK_FUNCTION_EXISTS (strtoll HAVE_STRTOLL)
+-CHECK_FUNCTION_EXISTS (strtoul HAVE_STRTOUL)
+-CHECK_FUNCTION_EXISTS (strtoull HAVE_STRTOULL)
+-CHECK_FUNCTION_EXISTS (tell HAVE_TELL)
+-CHECK_FUNCTION_EXISTS (thr_setconcurrency HAVE_THR_SETCONCURRENCY)
+-CHECK_FUNCTION_EXISTS (thr_yield HAVE_THR_YIELD)
+-CHECK_FUNCTION_EXISTS (vasprintf HAVE_VASPRINTF)
+-CHECK_FUNCTION_EXISTS (vsnprintf HAVE_VSNPRINTF)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/LibmysqlIncludeFiles.cmake mariadb-native-client.trunk/LibmysqlIncludeFiles.cmake
+--- mariadb/LibmysqlIncludeFiles.cmake 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/LibmysqlIncludeFiles.cmake 1970-01-01 01:00:00.000000000 +0100
+@@ -1,68 +0,0 @@
+-# This file is included by CMakeLists.txt and
+-# checks for various header files.
+-# You will find the appropiate defines in
+-# include/my_config.h.in
+-
+-INCLUDE(CheckIncludeFiles)
+-
+-CHECK_INCLUDE_FILES (alloca.h HAVE_ALLOCA_H)
+-CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H)
+-CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H)
+-CHECK_INCLUDE_FILES (dirent.h HAVE_DIRENT_H)
+-CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H)
+-CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H)
+-CHECK_INCLUDE_FILES (fcntl.h HAVE_FCNTL_H)
+-CHECK_INCLUDE_FILES (fenv.h HAVE_FENV_H)
+-CHECK_INCLUDE_FILES (float.h HAVE_FLOAT_H)
+-CHECK_INCLUDE_FILES (fpu/control.h HAVE_FPU_CONTROL_H)
+-CHECK_INCLUDE_FILES (grp.h HAVE_GRP_H)
+-CHECK_INCLUDE_FILES (ieeefp.h HAVE_IEEEFP_H)
+-CHECK_INCLUDE_FILES (limits.h HAVE_LIMITS_H)
+-CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
+-CHECK_INCLUDE_FILES (memory.h HAVE_MEMORY_H)
+-CHECK_INCLUDE_FILES (netinet/in.h HAVE_NETINET_IN_H)
+-CHECK_INCLUDE_FILES (paths.h HAVE_PATHS_H)
+-CHECK_INCLUDE_FILES (pwd.h HAVE_PWD_H)
+-CHECK_INCLUDE_FILES (sched.h HAVE_SCHED_H)
+-CHECK_INCLUDE_FILES (select.h HAVE_SELECT_H)
+-
+-CHECK_INCLUDE_FILES (signal.h INCLUDE_SIGNAL)
+-IF(INCLUDE_SIGNAL)
+- SET(HAVE_SIGNAL 1)
+- SET(CMAKE_EXTRA_INCLUDE_FILES signal.h)
+-ENDIF(INCLUDE_SIGNAL)
+-
+-CHECK_INCLUDE_FILES (stddef.h HAVE_STDDEF_H)
+-
+-CHECK_INCLUDE_FILES (stdint.h HAVE_STDINT_H)
+-IF(HAVE_STDINT_H)
+- SET(CMAKE_EXTRA_INCLUDE_FILES stdint.h)
+-ENDIF(HAVE_STDINT_H)
+-
+-CHECK_INCLUDE_FILES (stdlib.h HAVE_STDLIB_H)
+-CHECK_INCLUDE_FILES (string.h HAVE_STRING_H)
+-CHECK_INCLUDE_FILES (strings.h HAVE_STRINGS_H)
+-CHECK_INCLUDE_FILES (synch.h HAVE_SYNCH_H)
+-CHECK_INCLUDE_FILES (sys/fpu.h HAVE_SYS_FPU_H)
+-CHECK_INCLUDE_FILES (sys/ioctl.h HAVE_SYS_IOCTL_H)
+-CHECK_INCLUDE_FILES (sys/ipc.h HAVE_SYS_IPC_H)
+-CHECK_INCLUDE_FILES (sys/mman.h HAVE_SYS_MMAN_H)
+-CHECK_INCLUDE_FILES (sys/prctl.h HAVE_SYS_PRCTL_H)
+-CHECK_INCLUDE_FILES (sys/select.h HAVE_SYS_SELECT_H)
+-CHECK_INCLUDE_FILES (sys/shm.h HAVE_SYS_SHM_H)
+-
+-CHECK_INCLUDE_FILES (sys/socket.h HAVE_SYS_SOCKET_H)
+-IF(HAVE_SYS_SOCKET_H)
+- SET(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+-ENDIF(HAVE_SYS_SOCKET_H)
+-
+-CHECK_INCLUDE_FILES (sys/stat.h HAVE_SYS_STAT_H)
+-CHECK_INCLUDE_FILES (sys/stream.h HAVE_SYS_STREAM_H)
+-CHECK_INCLUDE_FILES (sys/timeb.h HAVE_SYS_TIMEB_H)
+-CHECK_INCLUDE_FILES (sys/types.h HAVE_SYS_TYPES_H)
+-CHECK_INCLUDE_FILES (sys/un.h HAVE_SYS_UN_H)
+-CHECK_INCLUDE_FILES (sysent.h HAVE_SYSENT_H)
+-CHECK_INCLUDE_FILES (termio.h HAVE_TERMIO_H)
+-CHECK_INCLUDE_FILES (termios.h HAVE_TERMIOS_H)
+-CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H)
+-CHECK_INCLUDE_FILES (utime.h HAVE_UTIME_H)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/LibmysqlTypes.cmake mariadb-native-client.trunk/LibmysqlTypes.cmake
+--- mariadb/LibmysqlTypes.cmake 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/LibmysqlTypes.cmake 1970-01-01 01:00:00.000000000 +0100
+@@ -1,106 +0,0 @@
+-# This file is included by CMakeLists.txt and
+-# checks for type sizes.
+-# You will find the appropiate defines in
+-# include/my_config.h.in
+-INCLUDE (CheckTypeSize)
+-
+-SET(CMAKE_EXTRA_INCLUDE_FILES signal.h)
+-CHECK_TYPE_SIZE(sigset_t SIZEOF_SIGSET_T)
+-CHECK_TYPE_SIZE(char SIZEOF_CHAR)
+-CHECK_TYPE_SIZE("char *" SIZEOF_CHARP)
+-CHECK_TYPE_SIZE(short SIZEOF_SHORT)
+-CHECK_TYPE_SIZE(int SIZEOF_INT)
+-CHECK_TYPE_SIZE(long SIZEOF_LONG)
+-CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
+-SET(CMAKE_EXTRA_INCLUDE_FILES stdio.h)
+-CHECK_TYPE_SIZE(size_t SIZEOF_SIZE_T)
+-SET(CMAKE_EXTRA_INCLUDE_FILES sys/types.h)
+-CHECK_TYPE_SIZE(off_t SIZEOF_OFF_T)
+-CHECK_TYPE_SIZE(uchar SIZEOF_UCHAR)
+-CHECK_TYPE_SIZE(uint SIZEOF_UINT)
+-CHECK_TYPE_SIZE(ulong SIZEOF_ULONG)
+-CHECK_TYPE_SIZE(int8 SIZEOF_INT8)
+-CHECK_TYPE_SIZE(uint8 SIZEOF_UINT8)
+-CHECK_TYPE_SIZE(int16 SIZEOF_INT16)
+-CHECK_TYPE_SIZE(uint16 SIZEOF_UINT16)
+-CHECK_TYPE_SIZE(int32 SIZEOF_INT32)
+-CHECK_TYPE_SIZE(uint32 SIZEOF_UINT32)
+-CHECK_TYPE_SIZE(u_int32_t SIZEOF_UINT_32_T)
+-CHECK_TYPE_SIZE(int64 SIZEOF_INT64)
+-CHECK_TYPE_SIZE(uint64 SIZEOF_UINT64)
+-CHECK_TYPE_SIZE(socklen_t SIZEOF_SOCKLEN_T)
+-
+-#
+-# Compile testing
+-#
+-INCLUDE (CheckCSourceCompiles)
+-
+-#
+-# signal handler
+-#
+-CHECK_C_SOURCE_COMPILES("
+- #include <signal.h>
+-
+- #ifdef signal
+- #undef signal
+- #endif
+-
+- #ifdef __cplusplus
+- extern \"C\" void (*signal (int, void (*)(int)))(int);
+- #else
+- void (*signal ()) ();
+- #endif
+-
+- int main(int ac, char **av)
+- {
+- }"
+- IS_VOID_SIGNAL)
+-
+-IF(IS_VOID_SIGNAL)
+- SET(RETSIGTYPE "void")
+-ELSE(IS_VOID_SIGNAL)
+- SET(RETSIGTYPE "int")
+-ENDIF(IS_VOID_SIGNAL)
+-
+-#
+-# quick sort
+-#
+-CHECK_C_SOURCE_COMPILES("
+- #include <stdlib.h>
+- #ifdef __cplusplus
+- extern \"C\" void qsort(void *base, size_t nel, size_t width, int (*compar) (const void *, const void *));
+- #else
+- void qsort(void *base, size_t nel, size_t width, int (*compar) (const void *, const void *));
+- #endif
+- int main(int ac, char **av)
+- {
+- }"
+- IS_VOID_QSORT)
+-IF(IS_VOID_QSORT)
+- SET(RETQSORTTYPE "void")
+-ELSE(IS_VOID_QSORT)
+- SET(RETQSORTTYPE "int")
+-ENDIF(IS_VOID_QSORT)
+-
+-#
+-# SOCKET_SIZE
+-#
+-IF(WIN32)
+- SET(SOCKET_SIZE_TYPE int)
+-ELSE(WIN32)
+- FOREACH(CHECK_TYPE "socklen_t" "size_t" "int")
+- IF (NOT SOCKET_SIZE_TYPE)
+- CHECK_C_SOURCE_COMPILES("
+- #include <sys/socket.h>
+- int main()
+- {
+- getsockname(0, 0, (${CHECK_TYPE} *)0);
+- return 0;
+- }"
+- SOCKET_SIZE_FOUND_${CHECK_TYPE})
+- IF(SOCKET_SIZE_FOUND_${CHECK_TYPE})
+- SET(SOCKET_SIZE_TYPE ${CHECK_TYPE})
+- ENDIF(SOCKET_SIZE_FOUND_${CHECK_TYPE})
+- ENDIF (NOT SOCKET_SIZE_TYPE)
+- ENDFOREACH()
+-ENDIF(WIN32)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/mariadb_config/CMakeLists.txt mariadb-native-client.trunk/mariadb_config/CMakeLists.txt
+--- mariadb/mariadb_config/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/mariadb_config/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,38 @@
++INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
++
++# Figure out additional libraries for use with
++
+FOREACH (dep ${libmariadb_LIB_DEPENDS})
+ STRING(REGEX MATCH "^-l.*$" out "${dep}")
- IF(out)
- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${dep}")
- ENDIF(out)
-@@ -19,12 +19,15 @@
- IF(MATH_LIBRARY)
- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lm")
- ENDIF(MATH_LIBRARY)
++ IF(out)
++ SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${dep}")
++ ENDIF(out)
++ENDFOREACH(dep)
++
++IF(UNIX)
++ IF(OPENSSL_LIBRARIES)
++ SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lssl")
++ ENDIF()
++ SEARCH_LIBRARY(LIBNSL getaddrinfo "nsl_r;nsl")
++ SEARCH_LIBRARY(LIBBIND bind "bind;socket")
++ SEARCH_LIBRARY(LIBSOCKET setsockopt "socket")
++ SEARCH_LIBRARY(LIBDL dlopen "dl")
++ SEARCH_LIBRARY(LIBM floor m)
++ FOREACH(lib ${EXTRA_LIBS})
++ SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -l${lib}")
++ ENDFOREACH()
+ IF(WITH_SQLITE)
+ SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lsqlite")
+ ENDIF()
- ENDIF(UNIX)
-
--CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.c.in
-- ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.c @ONLY)
++ENDIF(UNIX)
++
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mariadb_config.c.in
+ ${CMAKE_CURRENT_BINARY_DIR}/mariadb_config.c @ONLY)
-
--ADD_EXECUTABLE(mariadb_config ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.c)
++
+ADD_EXECUTABLE(mariadb_config ${CMAKE_CURRENT_BINARY_DIR}/mariadb_config.c)
- TARGET_LINK_LIBRARIES(mariadb_config mariadbclient)
-
- # Installation
-
-=== renamed file 'mysql_config/mysql_config.c.in' => 'mariadb_config/mariadb_config.c.in'
---- mariadb/mysql_config/mysql_config.c.in 2012-11-28 22:13:00 +0000
-+++ mariadb/mariadb_config/mariadb_config.c.in 2013-03-14 21:01:43 +0000
-@@ -3,8 +3,8 @@
- #include <getopt.h>
- #include <stdio.h>
-
--#define INCLUDE "-I@CMAKE_INSTALL_PREFIX@/mariadbclient/include"
--#define LIBS "-L@CMAKE_INSTALL_PREFIX@/lib -lmariadb" \
++TARGET_LINK_LIBRARIES(mariadb_config mariadbclient)
++
++# Installation
++#
++INSTALL(TARGETS mariadb_config
++ DESTINATION "bin")
+diff -x .bzr -u --recursive -N mariadb-native-client.release/mariadb_config/mariadb_config.c.in mariadb-native-client.trunk/mariadb_config/mariadb_config.c.in
+--- mariadb/mariadb_config/mariadb_config.c.in 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/mariadb_config/mariadb_config.c.in 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,100 @@
++#include <my_global.h>
++#include <my_sys.h>
++#include <getopt.h>
++#include <stdio.h>
++
+#define INCLUDE "-I@CMAKE_INSTALL_PREFIX@/include/mariadb"
+#define LIBS "-L@CMAKE_INSTALL_PREFIX@/lib/mariadb -lmariadb" \
- "@extra_dynamic_LDFLAGS@"
- #define CFLAGS INCLUDE "@CMAKE_C_FLAGS@"
- #define VERSION "@MYSQL_CLIENT_VERSION@"
-@@ -53,7 +53,6 @@
-
- int main(int argc, char **argv)
- {
++ "@extra_dynamic_LDFLAGS@"
++#define CFLAGS INCLUDE "@CMAKE_C_FLAGS@"
++#define VERSION "@MYSQL_CLIENT_VERSION@"
++#define SOCKET "@MYSQL_UNIX_ADDR@"
++#define PORT "@MYSQL_PORT@"
++
++static struct option long_options[]=
++{
++ {"cflags", no_argument, 0, 'a'},
++ {"help", no_argument, 0, 'b'},
++ {"include", no_argument, 0, 'c'},
++ {"libs", no_argument, 0, 'd'},
++ {"libs_r", no_argument, 0, 'e'},
++ {"version", no_argument, 0, 'f'},
++ {"socket", no_argument, 0, 'g'},
++ {"port", no_argument, 0, 'h'},
++ {NULL, 0, 0, 0}
++};
++
++static char *values[]=
++{
++ CFLAGS,
++ NULL,
++ INCLUDE,
++ LIBS,
++ LIBS,
++ VERSION,
++ SOCKET,
++ PORT
++};
++
++void usage(void)
++{
++ int i=0;
++ puts("Copyright 2011 Monty Program AB");
++ puts("Get compiler flags for using the MariaDB client library.");
++ printf("Usage: %s [OPTIONS]\n", my_progname);
++ while (long_options[i].name)
++ {
++ if (values[i])
++ printf(" --%-12s [%s]\n", long_options[i].name, values[i]);
++ i++;
++ }
++}
++
++
++int main(int argc, char **argv)
++{
++ int c;
++ my_progname= argv[0];
++
++ if (argc <= 1)
++ {
++ usage();
++ exit(1);
++ }
++
++ while(1)
++ {
++ int option_index= 0;
++ c= getopt_long(argc, argv, "abcdef", long_options, &option_index);
++
++ switch(c) {
++ case 'a':
++ puts(CFLAGS);
++ break;
++ case 'b':
++ usage();
++ break;
++ case 'c':
++ puts(INCLUDE);
++ break;
++ case 'd':
++ case 'e':
++ puts(LIBS);
++ break;
++ case 'f':
++ puts(VERSION);
++ break;
++ case 'g':
++ puts(SOCKET);
++ break;
++ case 'h':
++ puts(PORT);
++ break;
++ default:
++ exit(0);
++ }
++ }
++
++ exit(0);
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/mysql_config/CMakeLists.txt mariadb-native-client.trunk/mysql_config/CMakeLists.txt
+--- mariadb/mysql_config/CMakeLists.txt 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/mysql_config/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+@@ -1,33 +0,0 @@
+-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+-
+-# Figure out additional libraries for use with
+-
+-FOREACH (dep ${libmysql_LIB_DEPENDS})
+- STRING(REGEX MATCH "^-.*$" out "${dep}")
+- IF(out)
+- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${dep}")
+- ENDIF(out)
+-ENDFOREACH(dep)
+-
+-IF(UNIX)
+- IF(OPENSSL_LIBRARIES)
+- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lssl")
+- ENDIF(OPENSSL_LIBRARIES)
+- IF(DL_LIBRARY)
+- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -ldl")
+- ENDIF(DL_LIBRARY)
+- IF(MATH_LIBRARY)
+- SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lm")
+- ENDIF(MATH_LIBRARY)
+-ENDIF(UNIX)
+-
+-CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mysql_config.c.in
+- ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.c @ONLY)
+-
+-ADD_EXECUTABLE(mariadb_config ${CMAKE_CURRENT_BINARY_DIR}/mysql_config.c)
+-TARGET_LINK_LIBRARIES(mariadb_config mariadbclient)
+-
+-# Installation
+-#
+-INSTALL(TARGETS mariadb_config
+- DESTINATION "bin")
+diff -x .bzr -u --recursive -N mariadb-native-client.release/mysql_config/mysql_config.c.in mariadb-native-client.trunk/mysql_config/mysql_config.c.in
+--- mariadb/mysql_config/mysql_config.c.in 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/mysql_config/mysql_config.c.in 1970-01-01 01:00:00.000000000 +0100
+@@ -1,101 +0,0 @@
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <getopt.h>
+-#include <stdio.h>
+-
+-#define INCLUDE "-I@CMAKE_INSTALL_PREFIX@/mariadbclient/include"
+-#define LIBS "-L@CMAKE_INSTALL_PREFIX@/lib -lmariadb" \
+- "@extra_dynamic_LDFLAGS@"
+-#define CFLAGS INCLUDE "@CMAKE_C_FLAGS@"
+-#define VERSION "@MYSQL_CLIENT_VERSION@"
+-#define SOCKET "@MYSQL_UNIX_ADDR@"
+-#define PORT "@MYSQL_PORT@"
+-
+-static struct option long_options[]=
+-{
+- {"cflags", no_argument, 0, 'a'},
+- {"help", no_argument, 0, 'b'},
+- {"include", no_argument, 0, 'c'},
+- {"libs", no_argument, 0, 'd'},
+- {"libs_r", no_argument, 0, 'e'},
+- {"version", no_argument, 0, 'f'},
+- {"socket", no_argument, 0, 'g'},
+- {"port", no_argument, 0, 'h'},
+- {NULL, 0, 0, 0}
+-};
+-
+-static char *values[]=
+-{
+- CFLAGS,
+- NULL,
+- INCLUDE,
+- LIBS,
+- LIBS,
+- VERSION,
+- SOCKET,
+- PORT
+-};
+-
+-void usage(void)
+-{
+- int i=0;
+- puts("Copyright 2011 Monty Program AB");
+- puts("Get compiler flags for using the MariaDB client library.");
+- printf("Usage: %s [OPTIONS]\n", my_progname);
+- while (long_options[i].name)
+- {
+- if (values[i])
+- printf(" --%-12s [%s]\n", long_options[i].name, values[i]);
+- i++;
+- }
+-}
+-
+-
+-int main(int argc, char **argv)
+-{
- int error;
- int c;
- my_progname= argv[0];
-
-
-=== added directory 'plugins'
-=== added file 'plugins/CMakeLists.txt'
---- mariadb/plugins/CMakeLists.txt 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/CMakeLists.txt 2013-03-14 21:01:43 +0000
+- int c;
+- my_progname= argv[0];
+-
+- if (argc <= 1)
+- {
+- usage();
+- exit(1);
+- }
+-
+- while(1)
+- {
+- int option_index= 0;
+- c= getopt_long(argc, argv, "abcdef", long_options, &option_index);
+-
+- switch(c) {
+- case 'a':
+- puts(CFLAGS);
+- break;
+- case 'b':
+- usage();
+- break;
+- case 'c':
+- puts(INCLUDE);
+- break;
+- case 'd':
+- case 'e':
+- puts(LIBS);
+- break;
+- case 'f':
+- puts(VERSION);
+- break;
+- case 'g':
+- puts(SOCKET);
+- break;
+- case 'h':
+- puts(PORT);
+- break;
+- default:
+- exit(0);
+- }
+- }
+-
+- exit(0);
+-}
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/CMakeLists.txt mariadb-native-client.trunk/plugins/CMakeLists.txt
+--- mariadb/plugins/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,6 @@
+FILE(GLOB plugin_dirs ${CMAKE_SOURCE_DIR}/plugins/*)
+FOREACH(dir ${plugin_dirs})
@@ -5217,11 +57660,9 @@
+ ADD_SUBDIRECTORY(${dir})
+ ENDIF()
+ENDFOREACH()
-
-=== added directory 'plugins/sqlite'
-=== added file 'plugins/sqlite/CMakeLists.txt'
---- mariadb/plugins/sqlite/CMakeLists.txt 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/sqlite/CMakeLists.txt 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/sqlite/CMakeLists.txt mariadb-native-client.trunk/plugins/sqlite/CMakeLists.txt
+--- mariadb/plugins/sqlite/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/sqlite/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,22 @@
+# If option WITH_SQLITE was specified, we build this plugin
+# as an internal plugin.
@@ -5245,10 +57686,9 @@
+ # LIBRARY DESTINATION "plugins"
+ # ARCHIVE DESTINATION "plugins")
+ENDIF()
-
-=== added file 'plugins/sqlite/sqlite3.c'
---- mariadb/plugins/sqlite/sqlite3.c 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/sqlite/sqlite3.c 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/sqlite/sqlite3.c mariadb-native-client.trunk/plugins/sqlite/sqlite3.c
+--- mariadb/plugins/sqlite/sqlite3.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/sqlite/sqlite3.c 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,137413 @@
+/******************************************************************************
+** This file is an amalgamation of many separate C source files from SQLite
@@ -41460,7 +93900,7 @@
+ int sz; /* Bytes of memory required to allocate the new cache */
+
+ /*
-+ ** The separateCache variable is true if each PCache has its own private
++ ** The seperateCache variable is true if each PCache has its own private
+ ** PGroup. In other words, separateCache is true for mode (1) where no
+ ** mutexing is required.
+ **
@@ -47573,7 +100013,7 @@
+** page is initialized to all zeros.
+**
+** If noContent is true, it means that we do not care about the contents
-+** of the page. This occurs in two separate scenarios:
++** of the page. This occurs in two seperate scenarios:
+**
+** a) When reading a free-list leaf page from the database, and
+**
@@ -66368,7 +118808,7 @@
+** the blob of data that it corresponds to. In a table record, all serial
+** types are stored at the start of the record, and the blobs of data at
+** the end. Hence these functions allow the caller to handle the
-+** serial-type and data blob separately.
++** serial-type and data blob seperately.
+**
+** The following table describes the various storage classes for data:
+**
@@ -88072,7 +140512,7 @@
+ /* Drop all SQLITE_MASTER table and index entries that refer to the
+ ** table. The program name loops through the master table and deletes
+ ** every row that refers to a table of the same name as the one being
-+ ** dropped. Triggers are handled separately because a trigger can be
++ ** dropped. Triggers are handled seperately because a trigger can be
+ ** created in the temp database that refers to a table in another
+ ** database.
+ */
@@ -142663,10 +195103,460 @@
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
+
+/************** End of fts3_icu.c ********************************************/
-
-=== added file 'plugins/sqlite/sqlite3.h'
---- mariadb/plugins/sqlite/sqlite3.h 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/sqlite/sqlite3.h 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/sqlite/sqlite3ext.h mariadb-native-client.trunk/plugins/sqlite/sqlite3ext.h
+--- mariadb/plugins/sqlite/sqlite3ext.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/sqlite/sqlite3ext.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,447 @@
++/*
++** 2006 June 7
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This header file defines the SQLite interface for use by
++** shared libraries that want to be imported as extensions into
++** an SQLite instance. Shared libraries that intend to be loaded
++** as extensions by SQLite should #include this file instead of
++** sqlite3.h.
++*/
++#ifndef _SQLITE3EXT_H_
++#define _SQLITE3EXT_H_
++#include "sqlite3.h"
++
++typedef struct sqlite3_api_routines sqlite3_api_routines;
++
++/*
++** The following structure holds pointers to all of the SQLite API
++** routines.
++**
++** WARNING: In order to maintain backwards compatibility, add new
++** interfaces to the end of this structure only. If you insert new
++** interfaces in the middle of this structure, then older different
++** versions of SQLite will not be able to load each others' shared
++** libraries!
++*/
++struct sqlite3_api_routines {
++ void * (*aggregate_context)(sqlite3_context*,int nBytes);
++ int (*aggregate_count)(sqlite3_context*);
++ int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
++ int (*bind_double)(sqlite3_stmt*,int,double);
++ int (*bind_int)(sqlite3_stmt*,int,int);
++ int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
++ int (*bind_null)(sqlite3_stmt*,int);
++ int (*bind_parameter_count)(sqlite3_stmt*);
++ int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
++ const char * (*bind_parameter_name)(sqlite3_stmt*,int);
++ int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
++ int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
++ int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
++ int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
++ int (*busy_timeout)(sqlite3*,int ms);
++ int (*changes)(sqlite3*);
++ int (*close)(sqlite3*);
++ int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
++ int eTextRep,const char*));
++ int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
++ int eTextRep,const void*));
++ const void * (*column_blob)(sqlite3_stmt*,int iCol);
++ int (*column_bytes)(sqlite3_stmt*,int iCol);
++ int (*column_bytes16)(sqlite3_stmt*,int iCol);
++ int (*column_count)(sqlite3_stmt*pStmt);
++ const char * (*column_database_name)(sqlite3_stmt*,int);
++ const void * (*column_database_name16)(sqlite3_stmt*,int);
++ const char * (*column_decltype)(sqlite3_stmt*,int i);
++ const void * (*column_decltype16)(sqlite3_stmt*,int);
++ double (*column_double)(sqlite3_stmt*,int iCol);
++ int (*column_int)(sqlite3_stmt*,int iCol);
++ sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
++ const char * (*column_name)(sqlite3_stmt*,int);
++ const void * (*column_name16)(sqlite3_stmt*,int);
++ const char * (*column_origin_name)(sqlite3_stmt*,int);
++ const void * (*column_origin_name16)(sqlite3_stmt*,int);
++ const char * (*column_table_name)(sqlite3_stmt*,int);
++ const void * (*column_table_name16)(sqlite3_stmt*,int);
++ const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
++ const void * (*column_text16)(sqlite3_stmt*,int iCol);
++ int (*column_type)(sqlite3_stmt*,int iCol);
++ sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
++ void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
++ int (*complete)(const char*sql);
++ int (*complete16)(const void*sql);
++ int (*create_collation)(sqlite3*,const char*,int,void*,
++ int(*)(void*,int,const void*,int,const void*));
++ int (*create_collation16)(sqlite3*,const void*,int,void*,
++ int(*)(void*,int,const void*,int,const void*));
++ int (*create_function)(sqlite3*,const char*,int,int,void*,
++ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
++ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
++ void (*xFinal)(sqlite3_context*));
++ int (*create_function16)(sqlite3*,const void*,int,int,void*,
++ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
++ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
++ void (*xFinal)(sqlite3_context*));
++ int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
++ int (*data_count)(sqlite3_stmt*pStmt);
++ sqlite3 * (*db_handle)(sqlite3_stmt*);
++ int (*declare_vtab)(sqlite3*,const char*);
++ int (*enable_shared_cache)(int);
++ int (*errcode)(sqlite3*db);
++ const char * (*errmsg)(sqlite3*);
++ const void * (*errmsg16)(sqlite3*);
++ int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
++ int (*expired)(sqlite3_stmt*);
++ int (*finalize)(sqlite3_stmt*pStmt);
++ void (*free)(void*);
++ void (*free_table)(char**result);
++ int (*get_autocommit)(sqlite3*);
++ void * (*get_auxdata)(sqlite3_context*,int);
++ int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
++ int (*global_recover)(void);
++ void (*interruptx)(sqlite3*);
++ sqlite_int64 (*last_insert_rowid)(sqlite3*);
++ const char * (*libversion)(void);
++ int (*libversion_number)(void);
++ void *(*malloc)(int);
++ char * (*mprintf)(const char*,...);
++ int (*open)(const char*,sqlite3**);
++ int (*open16)(const void*,sqlite3**);
++ int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
++ int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
++ void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
++ void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
++ void *(*realloc)(void*,int);
++ int (*reset)(sqlite3_stmt*pStmt);
++ void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
++ void (*result_double)(sqlite3_context*,double);
++ void (*result_error)(sqlite3_context*,const char*,int);
++ void (*result_error16)(sqlite3_context*,const void*,int);
++ void (*result_int)(sqlite3_context*,int);
++ void (*result_int64)(sqlite3_context*,sqlite_int64);
++ void (*result_null)(sqlite3_context*);
++ void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
++ void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
++ void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
++ void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
++ void (*result_value)(sqlite3_context*,sqlite3_value*);
++ void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
++ int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
++ const char*,const char*),void*);
++ void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
++ char * (*snprintf)(int,char*,const char*,...);
++ int (*step)(sqlite3_stmt*);
++ int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
++ char const**,char const**,int*,int*,int*);
++ void (*thread_cleanup)(void);
++ int (*total_changes)(sqlite3*);
++ void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
++ int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
++ void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
++ sqlite_int64),void*);
++ void * (*user_data)(sqlite3_context*);
++ const void * (*value_blob)(sqlite3_value*);
++ int (*value_bytes)(sqlite3_value*);
++ int (*value_bytes16)(sqlite3_value*);
++ double (*value_double)(sqlite3_value*);
++ int (*value_int)(sqlite3_value*);
++ sqlite_int64 (*value_int64)(sqlite3_value*);
++ int (*value_numeric_type)(sqlite3_value*);
++ const unsigned char * (*value_text)(sqlite3_value*);
++ const void * (*value_text16)(sqlite3_value*);
++ const void * (*value_text16be)(sqlite3_value*);
++ const void * (*value_text16le)(sqlite3_value*);
++ int (*value_type)(sqlite3_value*);
++ char *(*vmprintf)(const char*,va_list);
++ /* Added ??? */
++ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
++ /* Added by 3.3.13 */
++ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
++ int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
++ int (*clear_bindings)(sqlite3_stmt*);
++ /* Added by 3.4.1 */
++ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
++ void (*xDestroy)(void *));
++ /* Added by 3.5.0 */
++ int (*bind_zeroblob)(sqlite3_stmt*,int,int);
++ int (*blob_bytes)(sqlite3_blob*);
++ int (*blob_close)(sqlite3_blob*);
++ int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
++ int,sqlite3_blob**);
++ int (*blob_read)(sqlite3_blob*,void*,int,int);
++ int (*blob_write)(sqlite3_blob*,const void*,int,int);
++ int (*create_collation_v2)(sqlite3*,const char*,int,void*,
++ int(*)(void*,int,const void*,int,const void*),
++ void(*)(void*));
++ int (*file_control)(sqlite3*,const char*,int,void*);
++ sqlite3_int64 (*memory_highwater)(int);
++ sqlite3_int64 (*memory_used)(void);
++ sqlite3_mutex *(*mutex_alloc)(int);
++ void (*mutex_enter)(sqlite3_mutex*);
++ void (*mutex_free)(sqlite3_mutex*);
++ void (*mutex_leave)(sqlite3_mutex*);
++ int (*mutex_try)(sqlite3_mutex*);
++ int (*open_v2)(const char*,sqlite3**,int,const char*);
++ int (*release_memory)(int);
++ void (*result_error_nomem)(sqlite3_context*);
++ void (*result_error_toobig)(sqlite3_context*);
++ int (*sleep)(int);
++ void (*soft_heap_limit)(int);
++ sqlite3_vfs *(*vfs_find)(const char*);
++ int (*vfs_register)(sqlite3_vfs*,int);
++ int (*vfs_unregister)(sqlite3_vfs*);
++ int (*xthreadsafe)(void);
++ void (*result_zeroblob)(sqlite3_context*,int);
++ void (*result_error_code)(sqlite3_context*,int);
++ int (*test_control)(int, ...);
++ void (*randomness)(int,void*);
++ sqlite3 *(*context_db_handle)(sqlite3_context*);
++ int (*extended_result_codes)(sqlite3*,int);
++ int (*limit)(sqlite3*,int,int);
++ sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
++ const char *(*sql)(sqlite3_stmt*);
++ int (*status)(int,int*,int*,int);
++ int (*backup_finish)(sqlite3_backup*);
++ sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
++ int (*backup_pagecount)(sqlite3_backup*);
++ int (*backup_remaining)(sqlite3_backup*);
++ int (*backup_step)(sqlite3_backup*,int);
++ const char *(*compileoption_get)(int);
++ int (*compileoption_used)(const char*);
++ int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
++ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
++ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
++ void (*xFinal)(sqlite3_context*),
++ void(*xDestroy)(void*));
++ int (*db_config)(sqlite3*,int,...);
++ sqlite3_mutex *(*db_mutex)(sqlite3*);
++ int (*db_status)(sqlite3*,int,int*,int*,int);
++ int (*extended_errcode)(sqlite3*);
++ void (*log)(int,const char*,...);
++ sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
++ const char *(*sourceid)(void);
++ int (*stmt_status)(sqlite3_stmt*,int,int);
++ int (*strnicmp)(const char*,const char*,int);
++ int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
++ int (*wal_autocheckpoint)(sqlite3*,int);
++ int (*wal_checkpoint)(sqlite3*,const char*);
++ void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
++ int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
++ int (*vtab_config)(sqlite3*,int op,...);
++ int (*vtab_on_conflict)(sqlite3*);
++};
++
++/*
++** The following macros redefine the API routines so that they are
++** redirected throught the global sqlite3_api structure.
++**
++** This header file is also used by the loadext.c source file
++** (part of the main SQLite library - not an extension) so that
++** it can get access to the sqlite3_api_routines structure
++** definition. But the main library does not want to redefine
++** the API. So the redefinition macros are only valid if the
++** SQLITE_CORE macros is undefined.
++*/
++#ifndef SQLITE_CORE
++#define sqlite3_aggregate_context sqlite3_api->aggregate_context
++#ifndef SQLITE_OMIT_DEPRECATED
++#define sqlite3_aggregate_count sqlite3_api->aggregate_count
++#endif
++#define sqlite3_bind_blob sqlite3_api->bind_blob
++#define sqlite3_bind_double sqlite3_api->bind_double
++#define sqlite3_bind_int sqlite3_api->bind_int
++#define sqlite3_bind_int64 sqlite3_api->bind_int64
++#define sqlite3_bind_null sqlite3_api->bind_null
++#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
++#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
++#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
++#define sqlite3_bind_text sqlite3_api->bind_text
++#define sqlite3_bind_text16 sqlite3_api->bind_text16
++#define sqlite3_bind_value sqlite3_api->bind_value
++#define sqlite3_busy_handler sqlite3_api->busy_handler
++#define sqlite3_busy_timeout sqlite3_api->busy_timeout
++#define sqlite3_changes sqlite3_api->changes
++#define sqlite3_close sqlite3_api->close
++#define sqlite3_collation_needed sqlite3_api->collation_needed
++#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
++#define sqlite3_column_blob sqlite3_api->column_blob
++#define sqlite3_column_bytes sqlite3_api->column_bytes
++#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
++#define sqlite3_column_count sqlite3_api->column_count
++#define sqlite3_column_database_name sqlite3_api->column_database_name
++#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
++#define sqlite3_column_decltype sqlite3_api->column_decltype
++#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
++#define sqlite3_column_double sqlite3_api->column_double
++#define sqlite3_column_int sqlite3_api->column_int
++#define sqlite3_column_int64 sqlite3_api->column_int64
++#define sqlite3_column_name sqlite3_api->column_name
++#define sqlite3_column_name16 sqlite3_api->column_name16
++#define sqlite3_column_origin_name sqlite3_api->column_origin_name
++#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
++#define sqlite3_column_table_name sqlite3_api->column_table_name
++#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
++#define sqlite3_column_text sqlite3_api->column_text
++#define sqlite3_column_text16 sqlite3_api->column_text16
++#define sqlite3_column_type sqlite3_api->column_type
++#define sqlite3_column_value sqlite3_api->column_value
++#define sqlite3_commit_hook sqlite3_api->commit_hook
++#define sqlite3_complete sqlite3_api->complete
++#define sqlite3_complete16 sqlite3_api->complete16
++#define sqlite3_create_collation sqlite3_api->create_collation
++#define sqlite3_create_collation16 sqlite3_api->create_collation16
++#define sqlite3_create_function sqlite3_api->create_function
++#define sqlite3_create_function16 sqlite3_api->create_function16
++#define sqlite3_create_module sqlite3_api->create_module
++#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
++#define sqlite3_data_count sqlite3_api->data_count
++#define sqlite3_db_handle sqlite3_api->db_handle
++#define sqlite3_declare_vtab sqlite3_api->declare_vtab
++#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
++#define sqlite3_errcode sqlite3_api->errcode
++#define sqlite3_errmsg sqlite3_api->errmsg
++#define sqlite3_errmsg16 sqlite3_api->errmsg16
++#define sqlite3_exec sqlite3_api->exec
++#ifndef SQLITE_OMIT_DEPRECATED
++#define sqlite3_expired sqlite3_api->expired
++#endif
++#define sqlite3_finalize sqlite3_api->finalize
++#define sqlite3_free sqlite3_api->free
++#define sqlite3_free_table sqlite3_api->free_table
++#define sqlite3_get_autocommit sqlite3_api->get_autocommit
++#define sqlite3_get_auxdata sqlite3_api->get_auxdata
++#define sqlite3_get_table sqlite3_api->get_table
++#ifndef SQLITE_OMIT_DEPRECATED
++#define sqlite3_global_recover sqlite3_api->global_recover
++#endif
++#define sqlite3_interrupt sqlite3_api->interruptx
++#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
++#define sqlite3_libversion sqlite3_api->libversion
++#define sqlite3_libversion_number sqlite3_api->libversion_number
++#define sqlite3_malloc sqlite3_api->malloc
++#define sqlite3_mprintf sqlite3_api->mprintf
++#define sqlite3_open sqlite3_api->open
++#define sqlite3_open16 sqlite3_api->open16
++#define sqlite3_prepare sqlite3_api->prepare
++#define sqlite3_prepare16 sqlite3_api->prepare16
++#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
++#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
++#define sqlite3_profile sqlite3_api->profile
++#define sqlite3_progress_handler sqlite3_api->progress_handler
++#define sqlite3_realloc sqlite3_api->realloc
++#define sqlite3_reset sqlite3_api->reset
++#define sqlite3_result_blob sqlite3_api->result_blob
++#define sqlite3_result_double sqlite3_api->result_double
++#define sqlite3_result_error sqlite3_api->result_error
++#define sqlite3_result_error16 sqlite3_api->result_error16
++#define sqlite3_result_int sqlite3_api->result_int
++#define sqlite3_result_int64 sqlite3_api->result_int64
++#define sqlite3_result_null sqlite3_api->result_null
++#define sqlite3_result_text sqlite3_api->result_text
++#define sqlite3_result_text16 sqlite3_api->result_text16
++#define sqlite3_result_text16be sqlite3_api->result_text16be
++#define sqlite3_result_text16le sqlite3_api->result_text16le
++#define sqlite3_result_value sqlite3_api->result_value
++#define sqlite3_rollback_hook sqlite3_api->rollback_hook
++#define sqlite3_set_authorizer sqlite3_api->set_authorizer
++#define sqlite3_set_auxdata sqlite3_api->set_auxdata
++#define sqlite3_snprintf sqlite3_api->snprintf
++#define sqlite3_step sqlite3_api->step
++#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
++#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
++#define sqlite3_total_changes sqlite3_api->total_changes
++#define sqlite3_trace sqlite3_api->trace
++#ifndef SQLITE_OMIT_DEPRECATED
++#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
++#endif
++#define sqlite3_update_hook sqlite3_api->update_hook
++#define sqlite3_user_data sqlite3_api->user_data
++#define sqlite3_value_blob sqlite3_api->value_blob
++#define sqlite3_value_bytes sqlite3_api->value_bytes
++#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
++#define sqlite3_value_double sqlite3_api->value_double
++#define sqlite3_value_int sqlite3_api->value_int
++#define sqlite3_value_int64 sqlite3_api->value_int64
++#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
++#define sqlite3_value_text sqlite3_api->value_text
++#define sqlite3_value_text16 sqlite3_api->value_text16
++#define sqlite3_value_text16be sqlite3_api->value_text16be
++#define sqlite3_value_text16le sqlite3_api->value_text16le
++#define sqlite3_value_type sqlite3_api->value_type
++#define sqlite3_vmprintf sqlite3_api->vmprintf
++#define sqlite3_overload_function sqlite3_api->overload_function
++#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
++#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
++#define sqlite3_clear_bindings sqlite3_api->clear_bindings
++#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
++#define sqlite3_blob_bytes sqlite3_api->blob_bytes
++#define sqlite3_blob_close sqlite3_api->blob_close
++#define sqlite3_blob_open sqlite3_api->blob_open
++#define sqlite3_blob_read sqlite3_api->blob_read
++#define sqlite3_blob_write sqlite3_api->blob_write
++#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
++#define sqlite3_file_control sqlite3_api->file_control
++#define sqlite3_memory_highwater sqlite3_api->memory_highwater
++#define sqlite3_memory_used sqlite3_api->memory_used
++#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
++#define sqlite3_mutex_enter sqlite3_api->mutex_enter
++#define sqlite3_mutex_free sqlite3_api->mutex_free
++#define sqlite3_mutex_leave sqlite3_api->mutex_leave
++#define sqlite3_mutex_try sqlite3_api->mutex_try
++#define sqlite3_open_v2 sqlite3_api->open_v2
++#define sqlite3_release_memory sqlite3_api->release_memory
++#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
++#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
++#define sqlite3_sleep sqlite3_api->sleep
++#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
++#define sqlite3_vfs_find sqlite3_api->vfs_find
++#define sqlite3_vfs_register sqlite3_api->vfs_register
++#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
++#define sqlite3_threadsafe sqlite3_api->xthreadsafe
++#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
++#define sqlite3_result_error_code sqlite3_api->result_error_code
++#define sqlite3_test_control sqlite3_api->test_control
++#define sqlite3_randomness sqlite3_api->randomness
++#define sqlite3_context_db_handle sqlite3_api->context_db_handle
++#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
++#define sqlite3_limit sqlite3_api->limit
++#define sqlite3_next_stmt sqlite3_api->next_stmt
++#define sqlite3_sql sqlite3_api->sql
++#define sqlite3_status sqlite3_api->status
++#define sqlite3_backup_finish sqlite3_api->backup_finish
++#define sqlite3_backup_init sqlite3_api->backup_init
++#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
++#define sqlite3_backup_remaining sqlite3_api->backup_remaining
++#define sqlite3_backup_step sqlite3_api->backup_step
++#define sqlite3_compileoption_get sqlite3_api->compileoption_get
++#define sqlite3_compileoption_used sqlite3_api->compileoption_used
++#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
++#define sqlite3_db_config sqlite3_api->db_config
++#define sqlite3_db_mutex sqlite3_api->db_mutex
++#define sqlite3_db_status sqlite3_api->db_status
++#define sqlite3_extended_errcode sqlite3_api->extended_errcode
++#define sqlite3_log sqlite3_api->log
++#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
++#define sqlite3_sourceid sqlite3_api->sourceid
++#define sqlite3_stmt_status sqlite3_api->stmt_status
++#define sqlite3_strnicmp sqlite3_api->strnicmp
++#define sqlite3_unlock_notify sqlite3_api->unlock_notify
++#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
++#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
++#define sqlite3_wal_hook sqlite3_api->wal_hook
++#define sqlite3_blob_reopen sqlite3_api->blob_reopen
++#define sqlite3_vtab_config sqlite3_api->vtab_config
++#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
++#endif /* SQLITE_CORE */
++
++#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
++#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
++
++#endif /* _SQLITE3EXT_H_ */
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/sqlite/sqlite3.h mariadb-native-client.trunk/plugins/sqlite/sqlite3.h
+--- mariadb/plugins/sqlite/sqlite3.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/sqlite/sqlite3.h 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,7160 @@
+/*
+** 2001 September 15
@@ -149828,462 +202718,9 @@
+
+#endif /* ifndef _SQLITE3RTREE_H_ */
+
-
-=== added file 'plugins/sqlite/sqlite3ext.h'
---- mariadb/plugins/sqlite/sqlite3ext.h 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/sqlite/sqlite3ext.h 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,447 @@
-+/*
-+** 2006 June 7
-+**
-+** The author disclaims copyright to this source code. In place of
-+** a legal notice, here is a blessing:
-+**
-+** May you do good and not evil.
-+** May you find forgiveness for yourself and forgive others.
-+** May you share freely, never taking more than you give.
-+**
-+*************************************************************************
-+** This header file defines the SQLite interface for use by
-+** shared libraries that want to be imported as extensions into
-+** an SQLite instance. Shared libraries that intend to be loaded
-+** as extensions by SQLite should #include this file instead of
-+** sqlite3.h.
-+*/
-+#ifndef _SQLITE3EXT_H_
-+#define _SQLITE3EXT_H_
-+#include "sqlite3.h"
-+
-+typedef struct sqlite3_api_routines sqlite3_api_routines;
-+
-+/*
-+** The following structure holds pointers to all of the SQLite API
-+** routines.
-+**
-+** WARNING: In order to maintain backwards compatibility, add new
-+** interfaces to the end of this structure only. If you insert new
-+** interfaces in the middle of this structure, then older different
-+** versions of SQLite will not be able to load each others' shared
-+** libraries!
-+*/
-+struct sqlite3_api_routines {
-+ void * (*aggregate_context)(sqlite3_context*,int nBytes);
-+ int (*aggregate_count)(sqlite3_context*);
-+ int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
-+ int (*bind_double)(sqlite3_stmt*,int,double);
-+ int (*bind_int)(sqlite3_stmt*,int,int);
-+ int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
-+ int (*bind_null)(sqlite3_stmt*,int);
-+ int (*bind_parameter_count)(sqlite3_stmt*);
-+ int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
-+ const char * (*bind_parameter_name)(sqlite3_stmt*,int);
-+ int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
-+ int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
-+ int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
-+ int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
-+ int (*busy_timeout)(sqlite3*,int ms);
-+ int (*changes)(sqlite3*);
-+ int (*close)(sqlite3*);
-+ int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
-+ int eTextRep,const char*));
-+ int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
-+ int eTextRep,const void*));
-+ const void * (*column_blob)(sqlite3_stmt*,int iCol);
-+ int (*column_bytes)(sqlite3_stmt*,int iCol);
-+ int (*column_bytes16)(sqlite3_stmt*,int iCol);
-+ int (*column_count)(sqlite3_stmt*pStmt);
-+ const char * (*column_database_name)(sqlite3_stmt*,int);
-+ const void * (*column_database_name16)(sqlite3_stmt*,int);
-+ const char * (*column_decltype)(sqlite3_stmt*,int i);
-+ const void * (*column_decltype16)(sqlite3_stmt*,int);
-+ double (*column_double)(sqlite3_stmt*,int iCol);
-+ int (*column_int)(sqlite3_stmt*,int iCol);
-+ sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
-+ const char * (*column_name)(sqlite3_stmt*,int);
-+ const void * (*column_name16)(sqlite3_stmt*,int);
-+ const char * (*column_origin_name)(sqlite3_stmt*,int);
-+ const void * (*column_origin_name16)(sqlite3_stmt*,int);
-+ const char * (*column_table_name)(sqlite3_stmt*,int);
-+ const void * (*column_table_name16)(sqlite3_stmt*,int);
-+ const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
-+ const void * (*column_text16)(sqlite3_stmt*,int iCol);
-+ int (*column_type)(sqlite3_stmt*,int iCol);
-+ sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
-+ void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
-+ int (*complete)(const char*sql);
-+ int (*complete16)(const void*sql);
-+ int (*create_collation)(sqlite3*,const char*,int,void*,
-+ int(*)(void*,int,const void*,int,const void*));
-+ int (*create_collation16)(sqlite3*,const void*,int,void*,
-+ int(*)(void*,int,const void*,int,const void*));
-+ int (*create_function)(sqlite3*,const char*,int,int,void*,
-+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xFinal)(sqlite3_context*));
-+ int (*create_function16)(sqlite3*,const void*,int,int,void*,
-+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xFinal)(sqlite3_context*));
-+ int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
-+ int (*data_count)(sqlite3_stmt*pStmt);
-+ sqlite3 * (*db_handle)(sqlite3_stmt*);
-+ int (*declare_vtab)(sqlite3*,const char*);
-+ int (*enable_shared_cache)(int);
-+ int (*errcode)(sqlite3*db);
-+ const char * (*errmsg)(sqlite3*);
-+ const void * (*errmsg16)(sqlite3*);
-+ int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
-+ int (*expired)(sqlite3_stmt*);
-+ int (*finalize)(sqlite3_stmt*pStmt);
-+ void (*free)(void*);
-+ void (*free_table)(char**result);
-+ int (*get_autocommit)(sqlite3*);
-+ void * (*get_auxdata)(sqlite3_context*,int);
-+ int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
-+ int (*global_recover)(void);
-+ void (*interruptx)(sqlite3*);
-+ sqlite_int64 (*last_insert_rowid)(sqlite3*);
-+ const char * (*libversion)(void);
-+ int (*libversion_number)(void);
-+ void *(*malloc)(int);
-+ char * (*mprintf)(const char*,...);
-+ int (*open)(const char*,sqlite3**);
-+ int (*open16)(const void*,sqlite3**);
-+ int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
-+ int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
-+ void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
-+ void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
-+ void *(*realloc)(void*,int);
-+ int (*reset)(sqlite3_stmt*pStmt);
-+ void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
-+ void (*result_double)(sqlite3_context*,double);
-+ void (*result_error)(sqlite3_context*,const char*,int);
-+ void (*result_error16)(sqlite3_context*,const void*,int);
-+ void (*result_int)(sqlite3_context*,int);
-+ void (*result_int64)(sqlite3_context*,sqlite_int64);
-+ void (*result_null)(sqlite3_context*);
-+ void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
-+ void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
-+ void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
-+ void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
-+ void (*result_value)(sqlite3_context*,sqlite3_value*);
-+ void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
-+ int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
-+ const char*,const char*),void*);
-+ void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
-+ char * (*snprintf)(int,char*,const char*,...);
-+ int (*step)(sqlite3_stmt*);
-+ int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
-+ char const**,char const**,int*,int*,int*);
-+ void (*thread_cleanup)(void);
-+ int (*total_changes)(sqlite3*);
-+ void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
-+ int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
-+ void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
-+ sqlite_int64),void*);
-+ void * (*user_data)(sqlite3_context*);
-+ const void * (*value_blob)(sqlite3_value*);
-+ int (*value_bytes)(sqlite3_value*);
-+ int (*value_bytes16)(sqlite3_value*);
-+ double (*value_double)(sqlite3_value*);
-+ int (*value_int)(sqlite3_value*);
-+ sqlite_int64 (*value_int64)(sqlite3_value*);
-+ int (*value_numeric_type)(sqlite3_value*);
-+ const unsigned char * (*value_text)(sqlite3_value*);
-+ const void * (*value_text16)(sqlite3_value*);
-+ const void * (*value_text16be)(sqlite3_value*);
-+ const void * (*value_text16le)(sqlite3_value*);
-+ int (*value_type)(sqlite3_value*);
-+ char *(*vmprintf)(const char*,va_list);
-+ /* Added ??? */
-+ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
-+ /* Added by 3.3.13 */
-+ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
-+ int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
-+ int (*clear_bindings)(sqlite3_stmt*);
-+ /* Added by 3.4.1 */
-+ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
-+ void (*xDestroy)(void *));
-+ /* Added by 3.5.0 */
-+ int (*bind_zeroblob)(sqlite3_stmt*,int,int);
-+ int (*blob_bytes)(sqlite3_blob*);
-+ int (*blob_close)(sqlite3_blob*);
-+ int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
-+ int,sqlite3_blob**);
-+ int (*blob_read)(sqlite3_blob*,void*,int,int);
-+ int (*blob_write)(sqlite3_blob*,const void*,int,int);
-+ int (*create_collation_v2)(sqlite3*,const char*,int,void*,
-+ int(*)(void*,int,const void*,int,const void*),
-+ void(*)(void*));
-+ int (*file_control)(sqlite3*,const char*,int,void*);
-+ sqlite3_int64 (*memory_highwater)(int);
-+ sqlite3_int64 (*memory_used)(void);
-+ sqlite3_mutex *(*mutex_alloc)(int);
-+ void (*mutex_enter)(sqlite3_mutex*);
-+ void (*mutex_free)(sqlite3_mutex*);
-+ void (*mutex_leave)(sqlite3_mutex*);
-+ int (*mutex_try)(sqlite3_mutex*);
-+ int (*open_v2)(const char*,sqlite3**,int,const char*);
-+ int (*release_memory)(int);
-+ void (*result_error_nomem)(sqlite3_context*);
-+ void (*result_error_toobig)(sqlite3_context*);
-+ int (*sleep)(int);
-+ void (*soft_heap_limit)(int);
-+ sqlite3_vfs *(*vfs_find)(const char*);
-+ int (*vfs_register)(sqlite3_vfs*,int);
-+ int (*vfs_unregister)(sqlite3_vfs*);
-+ int (*xthreadsafe)(void);
-+ void (*result_zeroblob)(sqlite3_context*,int);
-+ void (*result_error_code)(sqlite3_context*,int);
-+ int (*test_control)(int, ...);
-+ void (*randomness)(int,void*);
-+ sqlite3 *(*context_db_handle)(sqlite3_context*);
-+ int (*extended_result_codes)(sqlite3*,int);
-+ int (*limit)(sqlite3*,int,int);
-+ sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
-+ const char *(*sql)(sqlite3_stmt*);
-+ int (*status)(int,int*,int*,int);
-+ int (*backup_finish)(sqlite3_backup*);
-+ sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
-+ int (*backup_pagecount)(sqlite3_backup*);
-+ int (*backup_remaining)(sqlite3_backup*);
-+ int (*backup_step)(sqlite3_backup*,int);
-+ const char *(*compileoption_get)(int);
-+ int (*compileoption_used)(const char*);
-+ int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
-+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
-+ void (*xFinal)(sqlite3_context*),
-+ void(*xDestroy)(void*));
-+ int (*db_config)(sqlite3*,int,...);
-+ sqlite3_mutex *(*db_mutex)(sqlite3*);
-+ int (*db_status)(sqlite3*,int,int*,int*,int);
-+ int (*extended_errcode)(sqlite3*);
-+ void (*log)(int,const char*,...);
-+ sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
-+ const char *(*sourceid)(void);
-+ int (*stmt_status)(sqlite3_stmt*,int,int);
-+ int (*strnicmp)(const char*,const char*,int);
-+ int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
-+ int (*wal_autocheckpoint)(sqlite3*,int);
-+ int (*wal_checkpoint)(sqlite3*,const char*);
-+ void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
-+ int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
-+ int (*vtab_config)(sqlite3*,int op,...);
-+ int (*vtab_on_conflict)(sqlite3*);
-+};
-+
-+/*
-+** The following macros redefine the API routines so that they are
-+** redirected throught the global sqlite3_api structure.
-+**
-+** This header file is also used by the loadext.c source file
-+** (part of the main SQLite library - not an extension) so that
-+** it can get access to the sqlite3_api_routines structure
-+** definition. But the main library does not want to redefine
-+** the API. So the redefinition macros are only valid if the
-+** SQLITE_CORE macros is undefined.
-+*/
-+#ifndef SQLITE_CORE
-+#define sqlite3_aggregate_context sqlite3_api->aggregate_context
-+#ifndef SQLITE_OMIT_DEPRECATED
-+#define sqlite3_aggregate_count sqlite3_api->aggregate_count
-+#endif
-+#define sqlite3_bind_blob sqlite3_api->bind_blob
-+#define sqlite3_bind_double sqlite3_api->bind_double
-+#define sqlite3_bind_int sqlite3_api->bind_int
-+#define sqlite3_bind_int64 sqlite3_api->bind_int64
-+#define sqlite3_bind_null sqlite3_api->bind_null
-+#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
-+#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
-+#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
-+#define sqlite3_bind_text sqlite3_api->bind_text
-+#define sqlite3_bind_text16 sqlite3_api->bind_text16
-+#define sqlite3_bind_value sqlite3_api->bind_value
-+#define sqlite3_busy_handler sqlite3_api->busy_handler
-+#define sqlite3_busy_timeout sqlite3_api->busy_timeout
-+#define sqlite3_changes sqlite3_api->changes
-+#define sqlite3_close sqlite3_api->close
-+#define sqlite3_collation_needed sqlite3_api->collation_needed
-+#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
-+#define sqlite3_column_blob sqlite3_api->column_blob
-+#define sqlite3_column_bytes sqlite3_api->column_bytes
-+#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
-+#define sqlite3_column_count sqlite3_api->column_count
-+#define sqlite3_column_database_name sqlite3_api->column_database_name
-+#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
-+#define sqlite3_column_decltype sqlite3_api->column_decltype
-+#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
-+#define sqlite3_column_double sqlite3_api->column_double
-+#define sqlite3_column_int sqlite3_api->column_int
-+#define sqlite3_column_int64 sqlite3_api->column_int64
-+#define sqlite3_column_name sqlite3_api->column_name
-+#define sqlite3_column_name16 sqlite3_api->column_name16
-+#define sqlite3_column_origin_name sqlite3_api->column_origin_name
-+#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
-+#define sqlite3_column_table_name sqlite3_api->column_table_name
-+#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
-+#define sqlite3_column_text sqlite3_api->column_text
-+#define sqlite3_column_text16 sqlite3_api->column_text16
-+#define sqlite3_column_type sqlite3_api->column_type
-+#define sqlite3_column_value sqlite3_api->column_value
-+#define sqlite3_commit_hook sqlite3_api->commit_hook
-+#define sqlite3_complete sqlite3_api->complete
-+#define sqlite3_complete16 sqlite3_api->complete16
-+#define sqlite3_create_collation sqlite3_api->create_collation
-+#define sqlite3_create_collation16 sqlite3_api->create_collation16
-+#define sqlite3_create_function sqlite3_api->create_function
-+#define sqlite3_create_function16 sqlite3_api->create_function16
-+#define sqlite3_create_module sqlite3_api->create_module
-+#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
-+#define sqlite3_data_count sqlite3_api->data_count
-+#define sqlite3_db_handle sqlite3_api->db_handle
-+#define sqlite3_declare_vtab sqlite3_api->declare_vtab
-+#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
-+#define sqlite3_errcode sqlite3_api->errcode
-+#define sqlite3_errmsg sqlite3_api->errmsg
-+#define sqlite3_errmsg16 sqlite3_api->errmsg16
-+#define sqlite3_exec sqlite3_api->exec
-+#ifndef SQLITE_OMIT_DEPRECATED
-+#define sqlite3_expired sqlite3_api->expired
-+#endif
-+#define sqlite3_finalize sqlite3_api->finalize
-+#define sqlite3_free sqlite3_api->free
-+#define sqlite3_free_table sqlite3_api->free_table
-+#define sqlite3_get_autocommit sqlite3_api->get_autocommit
-+#define sqlite3_get_auxdata sqlite3_api->get_auxdata
-+#define sqlite3_get_table sqlite3_api->get_table
-+#ifndef SQLITE_OMIT_DEPRECATED
-+#define sqlite3_global_recover sqlite3_api->global_recover
-+#endif
-+#define sqlite3_interrupt sqlite3_api->interruptx
-+#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
-+#define sqlite3_libversion sqlite3_api->libversion
-+#define sqlite3_libversion_number sqlite3_api->libversion_number
-+#define sqlite3_malloc sqlite3_api->malloc
-+#define sqlite3_mprintf sqlite3_api->mprintf
-+#define sqlite3_open sqlite3_api->open
-+#define sqlite3_open16 sqlite3_api->open16
-+#define sqlite3_prepare sqlite3_api->prepare
-+#define sqlite3_prepare16 sqlite3_api->prepare16
-+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
-+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
-+#define sqlite3_profile sqlite3_api->profile
-+#define sqlite3_progress_handler sqlite3_api->progress_handler
-+#define sqlite3_realloc sqlite3_api->realloc
-+#define sqlite3_reset sqlite3_api->reset
-+#define sqlite3_result_blob sqlite3_api->result_blob
-+#define sqlite3_result_double sqlite3_api->result_double
-+#define sqlite3_result_error sqlite3_api->result_error
-+#define sqlite3_result_error16 sqlite3_api->result_error16
-+#define sqlite3_result_int sqlite3_api->result_int
-+#define sqlite3_result_int64 sqlite3_api->result_int64
-+#define sqlite3_result_null sqlite3_api->result_null
-+#define sqlite3_result_text sqlite3_api->result_text
-+#define sqlite3_result_text16 sqlite3_api->result_text16
-+#define sqlite3_result_text16be sqlite3_api->result_text16be
-+#define sqlite3_result_text16le sqlite3_api->result_text16le
-+#define sqlite3_result_value sqlite3_api->result_value
-+#define sqlite3_rollback_hook sqlite3_api->rollback_hook
-+#define sqlite3_set_authorizer sqlite3_api->set_authorizer
-+#define sqlite3_set_auxdata sqlite3_api->set_auxdata
-+#define sqlite3_snprintf sqlite3_api->snprintf
-+#define sqlite3_step sqlite3_api->step
-+#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
-+#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
-+#define sqlite3_total_changes sqlite3_api->total_changes
-+#define sqlite3_trace sqlite3_api->trace
-+#ifndef SQLITE_OMIT_DEPRECATED
-+#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
-+#endif
-+#define sqlite3_update_hook sqlite3_api->update_hook
-+#define sqlite3_user_data sqlite3_api->user_data
-+#define sqlite3_value_blob sqlite3_api->value_blob
-+#define sqlite3_value_bytes sqlite3_api->value_bytes
-+#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
-+#define sqlite3_value_double sqlite3_api->value_double
-+#define sqlite3_value_int sqlite3_api->value_int
-+#define sqlite3_value_int64 sqlite3_api->value_int64
-+#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
-+#define sqlite3_value_text sqlite3_api->value_text
-+#define sqlite3_value_text16 sqlite3_api->value_text16
-+#define sqlite3_value_text16be sqlite3_api->value_text16be
-+#define sqlite3_value_text16le sqlite3_api->value_text16le
-+#define sqlite3_value_type sqlite3_api->value_type
-+#define sqlite3_vmprintf sqlite3_api->vmprintf
-+#define sqlite3_overload_function sqlite3_api->overload_function
-+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
-+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
-+#define sqlite3_clear_bindings sqlite3_api->clear_bindings
-+#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
-+#define sqlite3_blob_bytes sqlite3_api->blob_bytes
-+#define sqlite3_blob_close sqlite3_api->blob_close
-+#define sqlite3_blob_open sqlite3_api->blob_open
-+#define sqlite3_blob_read sqlite3_api->blob_read
-+#define sqlite3_blob_write sqlite3_api->blob_write
-+#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
-+#define sqlite3_file_control sqlite3_api->file_control
-+#define sqlite3_memory_highwater sqlite3_api->memory_highwater
-+#define sqlite3_memory_used sqlite3_api->memory_used
-+#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
-+#define sqlite3_mutex_enter sqlite3_api->mutex_enter
-+#define sqlite3_mutex_free sqlite3_api->mutex_free
-+#define sqlite3_mutex_leave sqlite3_api->mutex_leave
-+#define sqlite3_mutex_try sqlite3_api->mutex_try
-+#define sqlite3_open_v2 sqlite3_api->open_v2
-+#define sqlite3_release_memory sqlite3_api->release_memory
-+#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
-+#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
-+#define sqlite3_sleep sqlite3_api->sleep
-+#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
-+#define sqlite3_vfs_find sqlite3_api->vfs_find
-+#define sqlite3_vfs_register sqlite3_api->vfs_register
-+#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
-+#define sqlite3_threadsafe sqlite3_api->xthreadsafe
-+#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
-+#define sqlite3_result_error_code sqlite3_api->result_error_code
-+#define sqlite3_test_control sqlite3_api->test_control
-+#define sqlite3_randomness sqlite3_api->randomness
-+#define sqlite3_context_db_handle sqlite3_api->context_db_handle
-+#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
-+#define sqlite3_limit sqlite3_api->limit
-+#define sqlite3_next_stmt sqlite3_api->next_stmt
-+#define sqlite3_sql sqlite3_api->sql
-+#define sqlite3_status sqlite3_api->status
-+#define sqlite3_backup_finish sqlite3_api->backup_finish
-+#define sqlite3_backup_init sqlite3_api->backup_init
-+#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
-+#define sqlite3_backup_remaining sqlite3_api->backup_remaining
-+#define sqlite3_backup_step sqlite3_api->backup_step
-+#define sqlite3_compileoption_get sqlite3_api->compileoption_get
-+#define sqlite3_compileoption_used sqlite3_api->compileoption_used
-+#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
-+#define sqlite3_db_config sqlite3_api->db_config
-+#define sqlite3_db_mutex sqlite3_api->db_mutex
-+#define sqlite3_db_status sqlite3_api->db_status
-+#define sqlite3_extended_errcode sqlite3_api->extended_errcode
-+#define sqlite3_log sqlite3_api->log
-+#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
-+#define sqlite3_sourceid sqlite3_api->sourceid
-+#define sqlite3_stmt_status sqlite3_api->stmt_status
-+#define sqlite3_strnicmp sqlite3_api->strnicmp
-+#define sqlite3_unlock_notify sqlite3_api->unlock_notify
-+#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
-+#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
-+#define sqlite3_wal_hook sqlite3_api->wal_hook
-+#define sqlite3_blob_reopen sqlite3_api->blob_reopen
-+#define sqlite3_vtab_config sqlite3_api->vtab_config
-+#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
-+#endif /* SQLITE_CORE */
-+
-+#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
-+#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
-+
-+#endif /* _SQLITE3EXT_H_ */
-
-=== added file 'plugins/sqlite/sqlite_client_plugin.c'
---- mariadb/plugins/sqlite/sqlite_client_plugin.c 1970-01-01 00:00:00 +0000
-+++ mariadb/plugins/sqlite/sqlite_client_plugin.c 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/plugins/sqlite/sqlite_client_plugin.c mariadb-native-client.trunk/plugins/sqlite/sqlite_client_plugin.c
+--- mariadb/plugins/sqlite/sqlite_client_plugin.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/plugins/sqlite/sqlite_client_plugin.c 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,870 @@
+/************************************************************************************
+ Copyright (C) 2012 Monty Program AB
@@ -151155,46 +203592,460 @@
+ NULL,
+ &s3_methods
+};
-
-=== renamed directory 'unittest/libmysql' => 'unittest/libmariadb'
-=== modified file 'unittest/libmariadb/CMakeLists.txt'
---- mariadb/unittest/libmysql/CMakeLists.txt 2012-11-28 22:13:00 +0000
-+++ mariadb/unittest/libmariadb/CMakeLists.txt 2013-03-14 21:01:43 +0000
-@@ -21,7 +21,7 @@
- ${CMAKE_SOURCE_DIR}/unittest/mytap)
-
- SET(API_TESTS "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
-- "sp" "result" "connection" "misc" "ssl")
-+ "sp" "result" "connection" "misc" "ssl" "ps_new" "sqlite3" "thread")
+diff -x .bzr -u --recursive -N mariadb-native-client.release/README mariadb-native-client.trunk/README
+--- mariadb/README 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/README 2013-10-19 07:29:16.000000000 +0200
+@@ -4,10 +4,15 @@
+ This code is based on the LGPL libmysql client library from MySQL 3.23
+ and PHP's mysqlnd extension.
- FOREACH(API_TEST ${API_TESTS})
- ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
-
-=== modified file 'unittest/libmariadb/basic-t.c'
---- mariadb/unittest/libmysql/basic-t.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/basic-t.c 2013-03-14 21:01:43 +0000
-@@ -33,6 +33,7 @@
- {
- MYSQL_ROW row;
- MYSQL_RES *res;
-+ MYSQL_FIELD *field;
- int rc;
++This product includes PHP software, freely available from
++<http://www.php.net/software/>
++
+ The following are the main known limitations:
- MYSQL *my= mysql_init(NULL);
-@@ -46,7 +47,8 @@
+- - float to string conversion for prepared statements
+- doesn't work correctly
++- double to string conversion for prepared statements
++ doesn't work correctly
++- support for dynamic columns is not integrated yet
++- Asynchronus interface is not integrated yet
- res= mysql_store_result(my);
- FAIL_IF(!res, mysql_error(my));
--
+ If you want to be part of this development effort, you can discuss this at
+ maria-developers@lists.launchpad.org.
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/basic-t.c mariadb-native-client.trunk/unittest/libmariadb/basic-t.c
+--- mariadb/unittest/libmariadb/basic-t.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/basic-t.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,585 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++
++
++/**
++ Some basic tests of the client API.
++*/
++
++#include "my_test.h"
++#include "ma_common.h"
++
++static int basic_connect(MYSQL *mysql)
++{
++ MYSQL_ROW row;
++ MYSQL_RES *res;
++ MYSQL_FIELD *field;
++ int rc;
++
++ MYSQL *my= mysql_init(NULL);
++ FAIL_IF(!my, "mysql_init() failed");
++
++ FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
++ port, socketname, 0), mysql_error(my));
++
++ rc= mysql_query(my, "SELECT @@version");
++ check_mysql_rc(rc, my);
++
++ res= mysql_store_result(my);
++ FAIL_IF(!res, mysql_error(my));
+ field= mysql_fetch_fields(res);
+ FAIL_IF(!field, "couldn't fetch field");
- while ((row= mysql_fetch_row(res)) != NULL)
- {
- FAIL_IF(mysql_num_fields(res) != 1, "Got the wrong number of fields");
-@@ -424,6 +426,56 @@
- return OK;
- }
-
++ while ((row= mysql_fetch_row(res)) != NULL)
++ {
++ FAIL_IF(mysql_num_fields(res) != 1, "Got the wrong number of fields");
++ }
++ FAIL_IF(mysql_errno(my), mysql_error(my));
++
++ mysql_free_result(res);
++ mysql_close(my);
++
++ return OK;
++}
++
++
++static int use_utf8(MYSQL *my)
++{
++ MYSQL_ROW row;
++ MYSQL_RES *res;
++ int rc;
++
++ /* Make sure that we actually ended up with utf8. */
++ rc= mysql_query(my, "SELECT @@character_set_connection");
++ check_mysql_rc(rc, my);
++
++ res= mysql_store_result(my);
++ FAIL_IF(!res, mysql_error(my));
++
++ while ((row= mysql_fetch_row(res)) != NULL)
++ {
++ FAIL_IF(strcmp(row[0], "utf8"), "wrong character set");
++ }
++ FAIL_IF(mysql_errno(my), mysql_error(my));
++ mysql_free_result(res);
++
++ return OK;
++}
++
++int client_query(MYSQL *mysql) {
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE t1("
++ "id int primary key auto_increment, "
++ "name varchar(20))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' "
++ "WHERE name= 'deleted'");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug12001(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ const char *query= "DROP TABLE IF EXISTS test_table;"
++ "CREATE TABLE test_table(id INT);"
++ "INSERT INTO test_table VALUES(10);"
++ "UPDATE test_table SET id=20 WHERE id=10;"
++ "SELECT * FROM test_table;"
++ "INSERT INTO non_existent_table VALUES(11);";
++ int rc, res;
++
++
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ do
++ {
++ if (mysql_field_count(mysql) &&
++ (result= mysql_use_result(mysql)))
++ {
++ mysql_free_result(result);
++ }
++ }
++ while (!(res= mysql_next_result(mysql)));
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_UNLESS(res==1, "res != 1");
++
++ return OK;
++}
++
++
++/* connection options */
++struct my_option_st opt_utf8[] = {
++ {MYSQL_SET_CHARSET_NAME, "utf8"},
++ {0, NULL}
++};
++
++static int test_bad_union(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *query= "SELECT 1, 2 union SELECT 1";
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_UNLESS(rc && mysql_errno(mysql) == 1222, "Error expected");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/*
++ Test that mysql_insert_id() behaves as documented in our manual
++*/
++static int test_mysql_insert_id(MYSQL *mysql)
++{
++ my_ulonglong res;
++ int rc;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "drop table if exists t2");
++ check_mysql_rc(rc, mysql);
++ /* table without auto_increment column */
++ rc= mysql_query(mysql, "create table t1 (f1 int, f2 varchar(255), key(f1))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1,'a')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "insert into t1 values (null,'b')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "insert into t1 select 5,'c'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++
++ /*
++ Test for bug #34889: mysql_client_test::test_mysql_insert_id test fails
++ sporadically
++ */
++ rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (null,'b')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 select 5,'c'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "drop table t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 select null,'d'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "insert into t1 values (null,last_insert_id(300))");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 300, "");
++ rc= mysql_query(mysql, "insert into t1 select null,last_insert_id(400)");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ /*
++ Behaviour change: old code used to return 0; but 400 is consistent
++ with INSERT VALUES, and the manual's section of mysql_insert_id() does not
++ say INSERT SELECT should be different.
++ */
++ FAIL_UNLESS(res == 400, "");
++
++ /* table with auto_increment column */
++ rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (1,'a')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 1, "");
++ /* this should not influence next INSERT if it doesn't have auto_inc */
++ rc= mysql_query(mysql, "insert into t1 values (10,'e')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++
++ rc= mysql_query(mysql, "insert into t2 values (null,'b')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 2, "");
++ rc= mysql_query(mysql, "insert into t2 select 5,'c'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ /*
++ Manual says that for multirow insert this should have been 5, but does not
++ say for INSERT SELECT. This is a behaviour change: old code used to return
++ 0. We try to be consistent with INSERT VALUES.
++ */
++ FAIL_UNLESS(res == 5, "");
++ rc= mysql_query(mysql, "insert into t2 select null,'d'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 6, "");
++ /* with more than one row */
++ rc= mysql_query(mysql, "insert into t2 values (10,'a'),(11,'b')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 11, "");
++ rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ /*
++ Manual says that for multirow insert this should have been 13, but does
++ not say for INSERT SELECT. This is a behaviour change: old code used to
++ return 0. We try to be consistent with INSERT VALUES.
++ */
++ FAIL_UNLESS(res == 13, "");
++ rc= mysql_query(mysql, "insert into t2 values (null,'a'),(null,'b')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 14, "");
++ rc= mysql_query(mysql, "insert into t2 select null,'a' union select null,'b'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 16, "");
++ rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_query(mysql, "insert ignore into t2 select 12,'a' union select 13,'b'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "insert into t2 values (12,'a'),(13,'b')");
++ FAIL_IF(!rc, "Error expected");
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "insert ignore into t2 values (12,'a'),(13,'b')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ /* mixing autogenerated and explicit values */
++ rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b')");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b'),(25,'g')");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_query(mysql, "insert into t2 values (null,last_insert_id(300))");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ /*
++ according to the manual, this might be 20 or 300, but it looks like
++ auto_increment column takes priority over last_insert_id().
++ */
++ FAIL_UNLESS(res == 20, "");
++ /* If first autogenerated number fails and 2nd works: */
++ rc= mysql_query(mysql, "drop table t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t2 (f1 int not null primary key "
++ "auto_increment, f2 varchar(255), unique (f2))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (null,'e')");
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 1, "");
++ rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(null,'a'),(null,'e')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 2, "");
++ /* If autogenerated fails and explicit works: */
++ rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(12,'c'),(null,'d')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ /*
++ Behaviour change: old code returned 3 (first autogenerated, even if it
++ fails); we now return first successful autogenerated.
++ */
++ FAIL_UNLESS(res == 13, "");
++ /* UPDATE may update mysql_insert_id() if it uses LAST_INSERT_ID(#) */
++ rc= mysql_query(mysql, "update t2 set f1=14 where f1=12");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "update t2 set f1=0 where f1=14");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ rc= mysql_query(mysql, "update t2 set f2=last_insert_id(372) where f1=0");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 372, "");
++ /* check that LAST_INSERT_ID() does not update mysql_insert_id(): */
++ rc= mysql_query(mysql, "insert into t2 values (null,'g')");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 15, "");
++ rc= mysql_query(mysql, "update t2 set f2=(@li:=last_insert_id()) where f1=15");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 0, "");
++ /*
++ Behaviour change: now if ON DUPLICATE KEY UPDATE updates a row,
++ mysql_insert_id() returns the id of the row, instead of not being
++ affected.
++ */
++ rc= mysql_query(mysql, "insert into t2 values (null,@li) on duplicate key "
++ "update f2=concat('we updated ',f2)");
++ check_mysql_rc(rc, mysql);
++ res= mysql_insert_id(mysql);
++ FAIL_UNLESS(res == 15, "");
++
++ rc= mysql_query(mysql, "drop table t1,t2");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test simple select to debug */
++
++static int test_select_direct(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(id int, id1 tinyint, "
++ " id2 float, "
++ " id3 double, "
++ " name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert a row and commit the transaction */
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 5, 2.3, 4.5, 'venu')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT * FROM test_select");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ mysql_free_result(result);
++ return OK;
++}
++
++/*
++ Ensure we execute the status code while testing
++*/
++
++static int test_status(MYSQL *mysql)
++{
++ mysql_stat(mysql);
++ check_mysql_rc(mysql_errno(mysql), mysql);
++ return OK;
++}
++
+static int bug_conc1(MYSQL *mysql)
+{
+ mysql_real_connect(mysql, hostname, username, password, schema,
@@ -151245,553 +204096,10649 @@
+ return OK;
+}
+
- struct my_tests_st my_tests[] = {
- {"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
- {"use_utf8", use_utf8, TEST_CONNECTION_NEW, 0, opt_utf8, NULL},
-@@ -433,16 +485,19 @@
- {"test_mysql_insert_id", test_mysql_insert_id, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
- {"test_bug12001", test_bug12001, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
- {"test_status", test_status, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
++static int test_reconnect_maxpackage(MYSQL *my)
++{
++ int rc;
++ ulong max_packet= 0;
++ MYSQL *mysql= mysql_init(NULL);
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ char *query;
++
++ FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname,
++ CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
++ mysql->reconnect= 1;
++
++ rc= mysql_query(mysql, "SELECT @@max_allowed_packet");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++ max_packet= atol(row[0]);
++ diag("max_allowed_packet=%lu", max_packet);
++ mysql_free_result(res);
++
++ query= (char *)malloc(max_packet + 30);
++ memset(query, 0, max_packet + 30);
++
++ strcpy(query, "SELECT '");
++ memset(query + 8, 'A', max_packet);
++ strcat(query, "' FROM DUAL");
++
++
++ rc= mysql_query(mysql, query);
++ free(query);
++ if (!rc)
++ {
++ diag("expected error");
++ mysql_close(mysql);
++ return FAIL;
++ }
++ else
++ diag("Error: %s", mysql_error(mysql));
++
++ rc= mysql_query(mysql, "SELECT @@max_allowed_packet");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++ max_packet= atol(row[0]);
++ diag("max_allowed_packet=%lu", max_packet);
++ mysql_free_result(res);
++
++
++ mysql_close(mysql);
++ return OK;
++}
++
++static int test_compressed(MYSQL *my)
++{
++ int rc;
++ MYSQL *mysql= mysql_init(NULL);
++ MYSQL_RES *res;
++
++ mysql_options(mysql, MYSQL_OPT_COMPRESS, (void *)1);
++ FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname,
++ CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
++ mysql->reconnect= 1;
++
++ rc= mysql_query(mysql, "SHOW VARIABLES");
++ check_mysql_rc(rc, mysql);
++
++ if ((res= mysql_store_result(mysql)))
++ mysql_free_result(res);
++
++ mysql_close(mysql);
++
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_compressed", test_compressed, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_reconnect_maxpackage", test_reconnect_maxpackage, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"use_utf8", use_utf8, TEST_CONNECTION_NEW, 0, opt_utf8, NULL},
++ {"client_query", client_query, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bad_union", test_bad_union, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_select_direct", test_select_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_mysql_insert_id", test_mysql_insert_id, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug12001", test_bug12001, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
++ {"test_status", test_status, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
+ {"bug_conc1", bug_conc1, TEST_CONNECTION_NEW, 0, NULL, NULL},
+ {"test_options_initcmd", test_options_initcmd, TEST_CONNECTION_NONE, 0, NULL, NULL},
+ {"test_extended_init_values", test_extended_init_values, TEST_CONNECTION_NONE, 0, NULL, NULL},
- {NULL, NULL, 0, 0, NULL, NULL}
- };
-
-
- int main(int argc, char **argv)
- {
--/*
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
+
- if (argc > 1)
-- get_options(&argc, &argv);
--*/
++
++int main(int argc, char **argv)
++{
++ if (argc > 1)
+ get_options(argc, argv);
+
- get_envvars();
-
- run_tests(my_tests);
-
-=== added directory 'unittest/libmariadb/certs'
-=== added file 'unittest/libmariadb/certs/ca-cert.pem'
---- mariadb/unittest/libmariadb/certs/ca-cert.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/ca-cert.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,21 @@
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/ca.pem mariadb-native-client.trunk/unittest/libmariadb/certs/ca.pem
+--- mariadb/unittest/libmariadb/certs/ca.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/ca.pem 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
-+MIIDXTCCAkWgAwIBAgIJAKJqUreNtr3EMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-+aWRnaXRzIFB0eSBMdGQwHhcNMTIxMjAxMTExMjA3WhcNMjIxMDEwMTExMjA3WjBF
-+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-+CgKCAQEAyMo3pYxaOc0dtWXBm3yzFdZ5E2YJBB0P/ZOoaDECZrVnHPL4jb3yqpNn
-+sZ576IDgw3+4bY/RFbUBLnx2oz0XMgwxwQ+rNxxi2jWnBuezd3CLS64vgmS4Ftdv
-++ikLsdw8hYTzNYwV3xK5iQnHj4WCeUw+ATucbCXlDeeCynfpMk/RWxE218R5UOjg
-+0JfqPtKfZMADzhoE3cEM5xWvPaQOSaBQXsVfziRCsj+2GdRjUZpChIlHLV99looT
-+T4oL1N8cfWG6I0ATje3a5y4yrxeDCoGEbvJcvD9xLciLmHJ9fTuzECw40+X8BUaL
-+2fEUymvtYjcvj0iRYGa4GkaETS7jDQIDAQABo1AwTjAdBgNVHQ4EFgQUUk+4Eg7w
-+xG/VQ7r2GdDVnKBMB28wHwYDVR0jBBgwFoAUUk+4Eg7wxG/VQ7r2GdDVnKBMB28w
-+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAvxPUK88FFPpjcnM6k9v/
-+XdEb4xgivcdTxQD5QH9A9lQZWnaMd+7dWGoeLgwP3/N/b7gV6BgAJt73aWa7AkMV
-+SKi10qk7IOs2DXlNuFzs1uy7ziBWrftUp5cTIDjZ8B5jZ23vUjkQfMivi9dnhVwp
-+UUjhh0gjoxYtvP8VJzz7FEMtHNEiwQsQ7G/at4T2xTWR4TlYXdvzE+5x1JdMYoed
-+vO4sihtZ2REZrXasvwpA2TofTTvOWGiU28SqV0AFh3Kz64WnRuJBkTR3zK5iTQvy
-+Zc7Loz5yZC+5ebn1hG2yjjpjJUfcEdv2i85hQQBjZarC6ibfptrgeO/bAQEU8ppV
-+kA==
++MIICTDCCAbWgAwIBAgIJAMc8o9u+bopUMA0GCSqGSIb3DQEBBQUAMD8xEzARBgoJ
++kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQ8wDQYDVQQD
++DAZzZXJ2ZXIwHhcNMTMwOTE4MTQ1MjE3WhcNMTMxMDE4MTQ1MjE3WjA/MRMwEQYK
++CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEPMA0GA1UE
++AwwGc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSnS+kxI2wBY1M
++eINRxfpyx5BQ8x4hX8o79PT+1PpEYEt/aNL1D2LronG4tbpB6pFTJ+mxnbPAOhns
++nGEpYYh5Tz1VOcB1+IMko/Eqa4jComxb1Yxv3c1xbtFNyGaylOCQ1KHs60UNDL8K
++eZs827ys293jPjR7Kz3fzTfPRCgc3wIDAQABo1AwTjAdBgNVHQ4EFgQUDYVv8BN8
++pzV3lwVpUzg1zSFLm9UwHwYDVR0jBBgwFoAUDYVv8BN8pzV3lwVpUzg1zSFLm9Uw
++DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBkU+Vx9Qkx/l/covoosxUl
++xigDiZf0WZhsBNudu3aB5OV08eXLdkPxnF/nmTotiK+FvmIAh1fM65mMLlxbfRpH
++3kAlI470shYEaysC1aIgcdha7EHJXcmKeMcGdaJR3UKrg7h/3XX4WdFV/27q9tjx
+++CIl79v79TqPaKLL08jWHg==
+-----END CERTIFICATE-----
-
-=== added file 'unittest/libmariadb/certs/ca-key.pem'
---- mariadb/unittest/libmariadb/certs/ca-key.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/ca-key.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,27 @@
-+-----BEGIN RSA PRIVATE KEY-----
-+MIIEogIBAAKCAQEAyMo3pYxaOc0dtWXBm3yzFdZ5E2YJBB0P/ZOoaDECZrVnHPL4
-+jb3yqpNnsZ576IDgw3+4bY/RFbUBLnx2oz0XMgwxwQ+rNxxi2jWnBuezd3CLS64v
-+gmS4Ftdv+ikLsdw8hYTzNYwV3xK5iQnHj4WCeUw+ATucbCXlDeeCynfpMk/RWxE2
-+18R5UOjg0JfqPtKfZMADzhoE3cEM5xWvPaQOSaBQXsVfziRCsj+2GdRjUZpChIlH
-+LV99looTT4oL1N8cfWG6I0ATje3a5y4yrxeDCoGEbvJcvD9xLciLmHJ9fTuzECw4
-+0+X8BUaL2fEUymvtYjcvj0iRYGa4GkaETS7jDQIDAQABAoIBACeVdhL08HSks06n
-+mNuGYefUOFpSq0RcVmKvUWv4/XgyGvniDI4k/EoUdUTW8aaMgcMI0tsGlzmoTWtU
-+ri7QRFphfQ2KgT6EIhjSqvL5iq/pSAzLciJKqOAX6MNwhBW0TVolM61CyK0Ji/ow
-+K19n+qjfFvo3Pkcz0UxEb8xqh1abfCgjaJnnjj0JlUO+xqNNRh3Gm6M2BrmrNhuR
-+l4fRr/moOrK+uMD1PCHJcx5zlWSX4FBjF52iD8divsD6vM10dBiyamNc3WrBHiWN
-+cp7ARtRcMS2k1XrUTAv69ltAll1BPzHQ7yC/HpJq4QBxoDRPPftsiRB9izC5MyDt
-+HdqArgECgYEA8ByToWHP+Ao+tw/xH26yRz1d/1pe7hq+qB13LEyvDZe4wd1smuv/
-+3VkNG/43yEYaLy3VxwKhxePrFL5WasLpB1dAmGIwio1hb2LldBlZp6HoW1u8MNYL
-+grC/3TLp1hQP2WT/yKuuqwKW+ebRpov2oTV7HmO7g+eKUDZOEjhPS90CgYEA1hOK
-+udBOEAGOYKa7086fSTFvJWMNy3lDEmJuvMVXcaYroaBjKWM2XZnCwKDymj+0mtzl
-+HY6SVgZEM+mfdm0U9kuRdQSaOCrmmLg0nBqta2fng939hSY1ED8TGMt6rDWA4lOD
-+SPiJwdeKkZEb7jSkLBojfNwpv/4+IfGZC18+2PECgYBIwjAOIAiX/erBKCiFwNJu
-++e6I2UaY2ivZ34vkNZx5/vaycDlfvJG87iYlzGP04SFAGKCF/Isu3wC2OXMQSN26
-+JrthMafJ5EuZKBulkaT0QgCZ5nNhTQsR4CNTkQEAqPWgh5Vmpnd4RIGhWks/L3xd
-+n0oejFQfBUOJSNthdAS7VQKBgHRl974Epw1I61NeFS6bYDx55ocbjrqd2nw6jR+S
-+5XLj+UFOZdxxF3RZUG1QldiM3vR9Ow6RILwpeBgJ5SyNLyKkABjyQbBckzlinyhp
-+0PVfb6BhqaEmHyAQS5/ls3PDO6rT4cRhbvW47p0rm1YvxTw9kiIny4ObB8mJBcAL
-+L67hAoGAIg00eMX2tqaY772vho2Q8ba2OT8ZvhGxRd2+eIB8LbK7Nh119+4O37zr
-+sHEq7QD15i34PM/dI9fbxFXi9cFFsxdwE5b4stTx/ZPdz5og05FCTyBX88L1FzLc
-+ZPEDbdYcajXSJSeGtbwilNKDtqLx62ANPRvrACZSKYWdfYRwBgw=
-+-----END RSA PRIVATE KEY-----
-
-=== renamed file 'unittest/libmysql/ca.pem' => 'unittest/libmariadb/certs/ca.pem'
-=== added file 'unittest/libmariadb/certs/client-cert.pem'
---- mariadb/unittest/libmariadb/certs/client-cert.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/client-cert.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
-+MIIDGTCCAgECAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
-+BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
-+ZDAeFw0xMjEyMDExMTE5NTBaFw0yMjExMjkxMTE5NTBaMGAxCzAJBgNVBAYTAkFV
-+MRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz
-+IFB0eSBMdGQxGTAXBgNVBAMMEGNsaWVudC5sb2NhbGhvc3QwggEiMA0GCSqGSIb3
-+DQEBAQUAA4IBDwAwggEKAoIBAQCfq0vKNGpEXPHiISQu0sLoIJ81eHzJyKUEHo+z
-+TKOqo+mHnH7Zvrx7ABr8cELdCKDJzhAn5hc1kEKnPNoaZK8gja5XoCx/cTIda7D6
-+/OKYUd+K39R+QV3HgBS4C/AG2djPcV1aoy7c7PQQrEtjovu/OEqJfgKyaN0N1AC0
-+mgP8hydX6P49WVs/TTguvqd7S19lhS1FzlKcfM5o7tnsSqLSYyZ+UebJN1O6WAQY
-+B5MPx3KLUu7Ze/auGwc4NvVTrRmN00Y2z98OynmlVzazUkt0L37Ya8ojxMkUMBon
-++gMKo6VaXGPlrteD+fs37O64Hhpb31zsoEtK3+0cgCChGl3FAgMBAAEwDQYJKoZI
-+hvcNAQEFBQADggEBAC3l+GCH29tKQlY+zyo8CdX0n0LKwKNJKFuxOBWEYG6WHcId
-+lE99faUlFF2XvN32MN+tFU9VXoxNm0BCOiMu3O9HcqWp3Bfzu36tNbQlBrpcVGYQ
-+Zq2zAEbWvNoQjVkDAHIRrbGJ9dv3a+ev7O0sjA1BxdfrWhhl4uyfWb3XCSG+0qeb
-+1S/PmYq+HzGNkmgMlRBZX0Bu+wwTBEreSCaieZrNqJUsLzIxjR+8m7YM6I7U0Ihi
-+PEGmzMFz70OBeMVc/4h7jzcMMvHRhHNSMnUVsXxhxHl6EW29Uha66nf9zd3A9b1g
-+/q8S27ufXMLGIPP+6PCRqiF792Kq9OTn67Iq7Tw=
++MIICTDCCAbWgAwIBAgIJAINPYND1suQ5MA0GCSqGSIb3DQEBBQUAMD8xEzARBgoJ
++kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQ8wDQYDVQQD
++DAZjbGllbnQwHhcNMTMwOTE4MTQ1MjE3WhcNMTMxMDE4MTQ1MjE3WjA/MRMwEQYK
++CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEPMA0GA1UE
++AwwGY2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH0i3GrrSfiYf8
++qk4eZfcPpgLW1X7lSOWxB9yvP7xE4rGNeKAIA6ZMCfvsuf4ABBH6ktPVqKEMnOPP
++ro40fyUz/Oa77M0j8hhRld7BGRcckcpkz/xfRBQ4bZuuBXlkFKDeGpyGGVdrUBFg
++pGx6tCxgLjcss+Mg31QQp2dgfHsuXwIDAQABo1AwTjAdBgNVHQ4EFgQUDrNUQrfC
++7FA4jhm5WBPqhpwIBc8wHwYDVR0jBBgwFoAUDrNUQrfC7FA4jhm5WBPqhpwIBc8w
++DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBD0fpXPv6Vv80uibJ1njm9
++znClMWKRMRu2jU1P3aSynzLHssqIA+hWCNZZHyXvHOvsizEhJU1aW/zTuUSeWg0Q
++Ay4o3Tycw0gh5NbNNMyyLi5ZivsPq6mYBlnYtCdXmDLj7gqrK4qu2xo19ifaIlUY
++sD9uawV17DPPers9aYOqVg==
+-----END CERTIFICATE-----
-
-=== added file 'unittest/libmariadb/certs/client-key.pem'
---- mariadb/unittest/libmariadb/certs/client-key.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/client-key.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,28 @@
-+-----BEGIN PRIVATE KEY-----
-+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCfq0vKNGpEXPHi
-+ISQu0sLoIJ81eHzJyKUEHo+zTKOqo+mHnH7Zvrx7ABr8cELdCKDJzhAn5hc1kEKn
-+PNoaZK8gja5XoCx/cTIda7D6/OKYUd+K39R+QV3HgBS4C/AG2djPcV1aoy7c7PQQ
-+rEtjovu/OEqJfgKyaN0N1AC0mgP8hydX6P49WVs/TTguvqd7S19lhS1FzlKcfM5o
-+7tnsSqLSYyZ+UebJN1O6WAQYB5MPx3KLUu7Ze/auGwc4NvVTrRmN00Y2z98Oynml
-+VzazUkt0L37Ya8ojxMkUMBon+gMKo6VaXGPlrteD+fs37O64Hhpb31zsoEtK3+0c
-+gCChGl3FAgMBAAECggEBAIGbfIQAlBo2ECpsmIBhmNDwWgv/Z9wrwLddT2xN07Ta
-+JOBtyhJaX4jAhydOwRfGvy3Q1RBuF3zlQxWZsbkm7XlRSKncXQJ+Eh4Lore5uv3F
-+x91k34o06Tjd4POczRPilbmd3heKyqmOtncqRG/2hr+ro+WDohDMSlPFOWVgd8ft
-+bP/CcNqQ4J/FqbItQPxXK6dJkFL8BR66SlslEX38bmUK+/9EGTiAttye4BXhZ6Pu
-+sr9g0A24fYOiHZ6CFawnFDzTZzMXyRpQnXZi0isakgvXq4i8FeSI+p5zQGle2LE1
-+f2u+QnMOiymAbrXLhLKWrJMS207IQmzFvc3YOumQhKkCgYEA1Jj0999ks42/NPk3
-+UWzUZRlOCpUbRb+Olo0DfWPR8KhjQYV8B3Sqc3Ao4NZzhGZecJDYWTlNMGiCIGIR
-+vrtFW8huL5fOE/XZqkrVShXvK/Zhs73EqWnYCRP2i4E3E6RvB5MniRHeRZ0l9FiH
-+qh+kp9z8OLZ6J7IrXQyWClSt1/sCgYEAwEQhCQwhUPb74zL0UUjk1LZPJAQJHvaD
-+3PWIYX6FKtjjUIOcCXGgQM6C9omXOdv+mMryKTkpCEt4TrDN1Q9vvMBYAjcHlhhi
-+QQ041+dFNGwsXa6e24Ei8v5qgzR5mzvAVL3381WfyF22Bsjw0dfVwlTZvI7oUMmu
-+5pthuYKt9T8CgYBVfz3lAV4KJ5MhxqfMgyvXjJmp/9T789FwEj25C4++bLmd/ASp
-+Ku3xhsWpxhSmxlRsiJO5LiYwtZa/VzEztzRpeO13DmG9/T0QExA7vx50W51nH4Yb
-+a4mJ/RFFgS2ZJKPSNAfOQ/VToaNF5OSKMjeRmnmEhT4TAMAXp5wfg3Z2SQKBgFna
-+fSXhSWCxTJ6tnYivbGIMoYfPawPRaWbGSOpnWozft7xVBYNUWvRujr3xJ3+e1KlL
-+j0i8sfRycNM1xbwg7rNjoL3IQf9ffeuw5jPgnXMWatWNWihzfYXaaKTQzVRC5Gu2
-+LD7IcVgOk5cwKXuoRvn+9ZMtply7JMYZL96mt+25AoGBAMnJmRAzIONjtsYAhjvu
-+SEur63oM2qXTsjMLbVK+jgGww8D7ESPZI2Hr3h9SoyQGebJZXmLbzk0qi3yVVamx
-+fHCyORgEh7qVSkUqnxVB0nTacbqdKpGUpNDEPyw4+Yad1wTUxMWcii0V3s5K84v/
-+zVLsxtDOT8M6Z57mZXUzKaTT
-+-----END PRIVATE KEY-----
-
-=== added file 'unittest/libmariadb/certs/client-req.pem'
---- mariadb/unittest/libmariadb/certs/client-req.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/client-req.pem 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/client-cert.pem mariadb-native-client.trunk/unittest/libmariadb/certs/client-cert.pem
+--- mariadb/unittest/libmariadb/certs/client-cert.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/client-cert.pem 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,15 @@
++-----BEGIN CERTIFICATE-----
++MIICTDCCAbWgAwIBAgIJAINPYND1suQ5MA0GCSqGSIb3DQEBBQUAMD8xEzARBgoJ
++kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQ8wDQYDVQQD
++DAZjbGllbnQwHhcNMTMwOTE4MTQ1MjE3WhcNMTMxMDE4MTQ1MjE3WjA/MRMwEQYK
++CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEPMA0GA1UE
++AwwGY2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH0i3GrrSfiYf8
++qk4eZfcPpgLW1X7lSOWxB9yvP7xE4rGNeKAIA6ZMCfvsuf4ABBH6ktPVqKEMnOPP
++ro40fyUz/Oa77M0j8hhRld7BGRcckcpkz/xfRBQ4bZuuBXlkFKDeGpyGGVdrUBFg
++pGx6tCxgLjcss+Mg31QQp2dgfHsuXwIDAQABo1AwTjAdBgNVHQ4EFgQUDrNUQrfC
++7FA4jhm5WBPqhpwIBc8wHwYDVR0jBBgwFoAUDrNUQrfC7FA4jhm5WBPqhpwIBc8w
++DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBD0fpXPv6Vv80uibJ1njm9
++znClMWKRMRu2jU1P3aSynzLHssqIA+hWCNZZHyXvHOvsizEhJU1aW/zTuUSeWg0Q
++Ay4o3Tycw0gh5NbNNMyyLi5ZivsPq6mYBlnYtCdXmDLj7gqrK4qu2xo19ifaIlUY
++sD9uawV17DPPers9aYOqVg==
++-----END CERTIFICATE-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/client-key-enc.pem mariadb-native-client.trunk/unittest/libmariadb/certs/client-key-enc.pem
+--- mariadb/unittest/libmariadb/certs/client-key-enc.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/client-key-enc.pem 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,17 @@
-+-----BEGIN CERTIFICATE REQUEST-----
-+MIICpTCCAY0CAQAwYDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
-+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEZMBcGA1UEAwwQY2xp
-+ZW50LmxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ+r
-+S8o0akRc8eIhJC7SwuggnzV4fMnIpQQej7NMo6qj6Yecftm+vHsAGvxwQt0IoMnO
-+ECfmFzWQQqc82hpkryCNrlegLH9xMh1rsPr84phR34rf1H5BXceAFLgL8AbZ2M9x
-+XVqjLtzs9BCsS2Oi+784Sol+ArJo3Q3UALSaA/yHJ1fo/j1ZWz9NOC6+p3tLX2WF
-+LUXOUpx8zmju2exKotJjJn5R5sk3U7pYBBgHkw/HcotS7tl79q4bBzg29VOtGY3T
-+RjbP3w7KeaVXNrNSS3QvfthryiPEyRQwGif6AwqjpVpcY+Wu14P5+zfs7rgeGlvf
-+XOygS0rf7RyAIKEaXcUCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQBOs8sFu+Lh
-+8wuC1QJ6Wqx4tSjVOsFlu6WQpaZ0fiYb9RpK1V//2sUGTX7SRiKOJE7/zh+Ehu5m
-+DsIEo5Ptu/JasYbBp3BeRSVVlyLGITvOGpUapUnOebvp+it/v9kjGW33vG2t3+j4
-+LihduPz6xz1GacCVNU3iQQGCE/I0tv3nSu/E0zTR4EvBneKFeV5ox63Cor9g7kQM
-+80Pv39YDv/Tc/JWmkZsILxWbzLyIuzyHiPTJMsz5P0GAIxPBl0PiTCaJuXkgIhIh
-+HIblZuW4I1gqGgAkZBS/iAxwV9VjZkldcc76qOkSfQIqQoTUn5UvDCvTmfAHHQuH
-+eu7XCpo8W7lx
-+-----END CERTIFICATE REQUEST-----
-
-=== added file 'unittest/libmariadb/certs/server-cert.pem'
---- mariadb/unittest/libmariadb/certs/server-cert.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/server-cert.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,19 @@
++-----BEGIN ENCRYPTED PRIVATE KEY-----
++MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQItEtCzxFB1MgCAggA
++MBQGCCqGSIb3DQMHBAhQRWSgaevikASCAoD0NCt6KOmLcMeg/gMjodCa66nYftCQ
++oQ7j62krniWZq2b5CjvSFuh71cq2M5qOEpgs9a6kOTdQ8aZNxaB4mNDgLqoxY9yV
++MACfIRoBqHc7TbWwKCPbE+5PzCjCuG+1Hqr3HQYPpOYTZqXHuHNhBWzeUEr+eITf
++fnxdoiVnKbwT5E3fVaHGJI7h5JrUkz3So6ynUbE3blmCroHAqsp9N5YAW+Kabq8p
++sCVoDz/xat3cyhHWaj3LZsRzr1WmPgqXQtRde6UU8hECZ6JhkqzvMnYCnOmxtXWu
++KcRAGg3SQOqYZi7uc8p3beNvfIHffywhGxzMDDGIDhRbw+eDBQmVAZIdHJpZ70Nf
++c8Zgdqx7Q8KT8mpu3JlmQ1dl+7Wh8HNejMIHCS18lV1BU3K2gdYmfpzeiFdzFEvq
++2evXcU3zP1OKmrcMTaL8oHtbTKk/ArWb3j19/5KxR5BZoiZuZ9+x1GuZx5oF+T+5
++/ExWFtO92EIZvTdhMgLJBnXE0ULUB0vYWN75tVvSc8nKeC+AbZWTYZdB5wtd8YLv
++0rz26/kxW/icC5bfNPf8gFojs7bMDDIeqgPLlwLCWkUu6FBTfvlYQYSbHubqAqaH
++p76pY2SzMr9ZH0o/mtdjCBxl+Jy6mel7hEa5ADueBoiskUOCWUyy8NndfADX3zaM
++uqm45AVI3mu/wEfSpu9DUklhkm9AtXKBi9Ash+Bj8XGWOZixe/xwAU8gABS2VBmB
++qXtPPiUqEi2t7wFDEOuqfymnV7khg26Xz45/8LZnHkXJXXZp7aJI4piX/gooLZaT
++L5Hso5vidt9tcr3AuNv84ZLXIptZZzun9SIB3klm/tssYFgqxxo/hLaN
++-----END ENCRYPTED PRIVATE KEY-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/client-key.pem mariadb-native-client.trunk/unittest/libmariadb/certs/client-key.pem
+--- mariadb/unittest/libmariadb/certs/client-key.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/client-key.pem 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,15 @@
++-----BEGIN RSA PRIVATE KEY-----
++MIICXgIBAAKBgQDH0i3GrrSfiYf8qk4eZfcPpgLW1X7lSOWxB9yvP7xE4rGNeKAI
++A6ZMCfvsuf4ABBH6ktPVqKEMnOPPro40fyUz/Oa77M0j8hhRld7BGRcckcpkz/xf
++RBQ4bZuuBXlkFKDeGpyGGVdrUBFgpGx6tCxgLjcss+Mg31QQp2dgfHsuXwIDAQAB
++AoGBALnq696NlM9PlnBXQOH1uz8bFk8vS6coAVaK2yFPqutpBQx9LGDojGT5cSXc
++E+GN5/B9ho2oHVhv7WLBpdxgZIpox1C8JUSaCohjFaY3F9m7SzjpasvZ4g9+5Dap
++eWmsWs6DlyV4QZy0+7B/nDmtaOzwJ+IgwbkSfB/mJ8nIItBBAkEA+IlW4h4n1Abv
++X7TnYpwCEXS0YACVc+Ms6LNu9+u5Yy7p1MMH5brrbHXZlFHqK6eUqKp83K5fCQsO
++n2BBO8h54QJBAM3SVQThp70XOMAv0KIJ/2vwhqhNAwVL2pEwP8SZYSGlobUToX68
++RcHCVsGGd9tv2SQAsXeHAK9Oq3paaIarMD8CQQCdN7u3RB4ruMtZvoUUUt3YDvw/
++Mn9YFKAG/+K1f+8A999BELKBN1HPhWlCsuKwBM08OMTNkJxbixwP44LAf5vhAkEA
++vhgCIAUOOE2nQ5Gl3tLfDmFS7URbgtvBHZFzg++pTzs79BMSeAwJXWBRYmIAdzKB
++WYguYFfW4RMGu3WezqpzXwJAf4VPFKjd4om9+44dX8egxFO9vqX2/OV2CdxyGZnB
++5VZB3sL3ip2XdKCLnPN4qdDNlulq9TBuMu0SK5dZcwBiCA==
++-----END RSA PRIVATE KEY-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/create_certs.sh mariadb-native-client.trunk/unittest/libmariadb/certs/create_certs.sh
+--- mariadb/unittest/libmariadb/certs/create_certs.sh 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/create_certs.sh 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,15 @@
++openssl req -x509 -newkey rsa:1024 \
++-keyout server-key-enc.pem -out server-cert.pem \
++-subj '/DC=com/DC=example/CN=server' -passout pass:qwerty
++
++openssl rsa -in server-key-enc.pem -out server-key.pem \
++-passin pass:qwerty -passout pass:
++
++openssl req -x509 -newkey rsa:1024 \
++-keyout client-key-enc.pem -out client-cert.pem \
++-subj '/DC=com/DC=example/CN=client' -passout pass:qwerty
++
++openssl rsa -in client-key-enc.pem -out client-key.pem \
++-passin pass:qwerty -passout pass:
++
++cat server-cert.pem client-cert.pem > ca.pem
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/server-cert.pem mariadb-native-client.trunk/unittest/libmariadb/certs/server-cert.pem
+--- mariadb/unittest/libmariadb/certs/server-cert.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/server-cert.pem 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
-+MIIDGTCCAgECAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
-+BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
-+ZDAeFw0xMjEyMDExMTE0NDBaFw0yMjExMjkxMTE0NDBaMGAxCzAJBgNVBAYTAkFV
-+MRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz
-+IFB0eSBMdGQxGTAXBgNVBAMMEHNlcnZlci5sb2NhbGhvc3QwggEiMA0GCSqGSIb3
-+DQEBAQUAA4IBDwAwggEKAoIBAQDJF13NPPgprDQC4BSo+f4cSzS4j46n+TEAaCu0
-+m+Bw0HSGr6MAXIn7EUr3VYx8zKI74/HG1HYBS8dPT0p3Hc8qcvsMtcujKyGIsOYc
-+bUtpCkZMYhChIMMA/AAO+wlyonaSUYYUmTlDCsbcolq9cjQnQtlXGSPkDzVJCJng
-+h4jeKZZ9LiVvWEblEu4YrAEnquErdalPmNeJ2LgqMG4pewJuXqtu98ue1Je28MnV
-+S/NrRPPtemsZcFcJlQLoGw/gtZRWQ0gM+hHaqc6xVrHmKJSyGURUwORSlKvX/lIn
-+58ZtDyS7bI1W1DtMZ2/UFxNTdmCoC6SF/fj/DGuzbiKErGa5AgMBAAEwDQYJKoZI
-+hvcNAQEFBQADggEBAFCKctZQ2cmR+AmESpzJl6EZspCKtd2gUsla531OrKnUWfYU
-+FcuZ+DEffnp4jQXtnVqO4mkBjVW5Etr5XF8r3Lm2cVTHkt/IfVjT5LcEdUdFzm4Q
-+UQHkAikc6pkz60guVXyi4SDkhjKyO/2K0HgwG1ndj+uAuatskAdybmS/OqvelRSL
-+lw72tND+Fy3RNwdf/cmmbDMGxfZO2LB/LRL1Yknn6CtHuCAWWwdUx7VkpRcjIpsI
-+X/CcvRgab8rCv/EZtBuhI2bunQ7MkAv4B93Y0o9t7H0mFTywrqj33e6iG/fS+dkK
-+2l0qvPpJ1YPqjuw0IGVujykdsGBXvXqbtxnGWMY=
++MIICTDCCAbWgAwIBAgIJAMc8o9u+bopUMA0GCSqGSIb3DQEBBQUAMD8xEzARBgoJ
++kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQ8wDQYDVQQD
++DAZzZXJ2ZXIwHhcNMTMwOTE4MTQ1MjE3WhcNMTMxMDE4MTQ1MjE3WjA/MRMwEQYK
++CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEPMA0GA1UE
++AwwGc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSnS+kxI2wBY1M
++eINRxfpyx5BQ8x4hX8o79PT+1PpEYEt/aNL1D2LronG4tbpB6pFTJ+mxnbPAOhns
++nGEpYYh5Tz1VOcB1+IMko/Eqa4jComxb1Yxv3c1xbtFNyGaylOCQ1KHs60UNDL8K
++eZs827ys293jPjR7Kz3fzTfPRCgc3wIDAQABo1AwTjAdBgNVHQ4EFgQUDYVv8BN8
++pzV3lwVpUzg1zSFLm9UwHwYDVR0jBBgwFoAUDYVv8BN8pzV3lwVpUzg1zSFLm9Uw
++DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBkU+Vx9Qkx/l/covoosxUl
++xigDiZf0WZhsBNudu3aB5OV08eXLdkPxnF/nmTotiK+FvmIAh1fM65mMLlxbfRpH
++3kAlI470shYEaysC1aIgcdha7EHJXcmKeMcGdaJR3UKrg7h/3XX4WdFV/27q9tjx
+++CIl79v79TqPaKLL08jWHg==
+-----END CERTIFICATE-----
-
-=== added file 'unittest/libmariadb/certs/server-key.pem'
---- mariadb/unittest/libmariadb/certs/server-key.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/server-key.pem 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,28 @@
-+-----BEGIN PRIVATE KEY-----
-+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDJF13NPPgprDQC
-+4BSo+f4cSzS4j46n+TEAaCu0m+Bw0HSGr6MAXIn7EUr3VYx8zKI74/HG1HYBS8dP
-+T0p3Hc8qcvsMtcujKyGIsOYcbUtpCkZMYhChIMMA/AAO+wlyonaSUYYUmTlDCsbc
-+olq9cjQnQtlXGSPkDzVJCJngh4jeKZZ9LiVvWEblEu4YrAEnquErdalPmNeJ2Lgq
-+MG4pewJuXqtu98ue1Je28MnVS/NrRPPtemsZcFcJlQLoGw/gtZRWQ0gM+hHaqc6x
-+VrHmKJSyGURUwORSlKvX/lIn58ZtDyS7bI1W1DtMZ2/UFxNTdmCoC6SF/fj/DGuz
-+biKErGa5AgMBAAECggEBAIHC1ELGHxU1C/L3Ch3oA7PaS9D0wgdeY+JxVhKbq37g
-+5PCskbCABoG+rPNhfuBhZCbldnTpUKSRc7GX5uNqlu47eAjBnwBRqrf7/uFFHa5Q
-+dQCBH136OBuAgcEo+PXCJGVSugS8wxih8aUaFxe8hC75kioEDQbzUV0pcbJTg1xn
-+sLIEfIeNwHMemLtpN4n+GpJ8j19GLqaUDcjPM5ZRUs4yDvv1FZeGXjHijyZLP11h
-+rJLVrvmhqUoEG/ZdkqYKPrOG5qpOnkn/i9WPoUrahtWb6kKsZUjPoBCKqCqq/0kT
-+0WRI7Qgz13wPpbsVL8gQU9PgUM9MyNKH7yqGZnTmHiECgYEA61CvZD26tciutQfq
-+s0N8k20vQpX0uelDxsYBI9Acxt7LNWEIeiZLhrGKMSWsg0v541RKjiewzDcVOfQb
-+qA7wPC/IWfc1F/1gK3yg025IRgXhcuoWVd9jm7ob/czzxQIA8ew2fsDgqlYwkqPb
-+661TdEnctjYt29nqAQkayDdW8DUCgYEA2sSJzhAsscIE94TMw4O0C4PaOiYMfVb0
-+oi7S4E7OLZ3bXm8OSlYRPxL66VxyNW+2g4BwXqMrsxd5x7QHGXEaqDPP8YEEOxrK
-+pkMiCfDvGpN0dlIobpPNVVGTfDcY/go3y30ZsdcX4G6S9lqsGEDo/hdVPrpeOULp
-+rG1Yimgu9PUCgYEAwUXwCOE6rXw7Iq1x8/MGKwCOxJ3t95TD+ks/PG7+c8kiFqGw
-+GMPDXMoNuvg6jUyl3jWpVsD60YCcipEY9hvu7UBBysLkdOPDTXR7k60M55aE6aGi
-+3r0wTwO5YegogDN5GzrsN4er/7vzAT5cr2IZHXZdNbuiRuTg8iDMQo5RddECgYEA
-+n+hJUnZANS68srA/fCoo0MHwIdDuEDAfYO0Y9xyjWHSqhLxola2TracSAMGyOZ0O
-+q9CWUpayupXOTkspZU9nTMuSk9TaYtmShzVLDDkwjRx7ZIFpTGp9DIA0bfdYLVkK
-+r5Mh1PyEV2h7w9dDM/c+V3x2swNHHFPsujyzG3hL2oECgYBgi1w63a/cfkQACVRt
-+tjy1ZtP50sRaSlXXC5Txh9u6AoO0k13V1+POo3LikYHfZRRrLTtMUrPVPAdD5H3v
-+rQ11p7gVgzw7ikMEi4hNw2ueX6UXzVSxAyeLGdG71QToqXPwK1tH/AOnD5g6hYAS
-+kXsNUaCkLeNkkbcWxXPY2HE6MA==
-+-----END PRIVATE KEY-----
-
-=== added file 'unittest/libmariadb/certs/server-req.pem'
---- mariadb/unittest/libmariadb/certs/server-req.pem 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/certs/server-req.pem 2013-03-14 21:01:43 +0000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/server-key-enc.pem mariadb-native-client.trunk/unittest/libmariadb/certs/server-key-enc.pem
+--- mariadb/unittest/libmariadb/certs/server-key-enc.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/server-key-enc.pem 2013-10-19 07:29:16.000000000 +0200
@@ -0,0 +1,17 @@
-+-----BEGIN CERTIFICATE REQUEST-----
-+MIICpTCCAY0CAQAwYDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
-+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEZMBcGA1UEAwwQc2Vy
-+dmVyLmxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMkX
-+Xc08+CmsNALgFKj5/hxLNLiPjqf5MQBoK7Sb4HDQdIavowBcifsRSvdVjHzMojvj
-+8cbUdgFLx09PSncdzypy+wy1y6MrIYiw5hxtS2kKRkxiEKEgwwD8AA77CXKidpJR
-+hhSZOUMKxtyiWr1yNCdC2VcZI+QPNUkImeCHiN4pln0uJW9YRuUS7hisASeq4St1
-+qU+Y14nYuCowbil7Am5eq273y57Ul7bwydVL82tE8+16axlwVwmVAugbD+C1lFZD
-+SAz6EdqpzrFWseYolLIZRFTA5FKUq9f+Uifnxm0PJLtsjVbUO0xnb9QXE1N2YKgL
-+pIX9+P8Ma7NuIoSsZrkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQB+Ctji5m7b
-+v/IYBSvvMIhWRDcQIQ/+3pzwtPRH8wb2iB6kYLFirC8vPYn320Dvva4MRp1DPzvP
-+egQduKFO0ic36DvDvKooSKVvCSoS/LGhH/jFFTbFmp7aJF0raqBU8HIg38eJ0KPv
-+smVND9uQ+Cibdzn6f3EX/a0c3FRtEtu5cYkJ1B7dksKr1guaobUOxQ4ti4mm4vkG
-+ll6VHdSMlHTsFLE3cqL7C+0g8f1cJYKyyXtx/43mzdYyOzHptndjmXfitATxw9Zy
-+hCXJtvgwbQdGA8ZiCeB6BxNfbD4Bhm2G0k59Vv942IunQUShWwDXTlSXz7DFRs/h
-+lDL64qSmNvdm
-+-----END CERTIFICATE REQUEST-----
-
-=== modified file 'unittest/libmariadb/charset.c'
---- mariadb/unittest/libmysql/charset.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/charset.c 2013-03-14 21:01:43 +0000
-@@ -672,8 +672,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
-- // get_options(&argc, &argv);
++-----BEGIN ENCRYPTED PRIVATE KEY-----
++MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQILNmuYbHy6EsCAggA
++MBQGCCqGSIb3DQMHBAh39D+PX3mtuASCAoBCFRKn73NQZlDOzIhe0oNZcB5NCAaw
++bIySG3lwlFU5YUcttZ6aLnaHOPBDjCSf3TFSXmxBDKYDgWz8A54MOa3lHVcjVgAn
++U1jpNRRfW82t4b7zyf0EdHi2IsOjjW4VUJLZjsyYqFBhTaT7Wz4nL6iHRnE2lndM
++25LGpNkwlrkRyB5tvIQTeEThCWscJj4/DCNtCvTfDtgyCGjAL+Hl1Ggfx6tJRoLO
++A8XxdrfP4SGxOBLe9tI65XSviujr+pXt4Gw7SwjnyuqCqZ7zdpmI/A9SmPwLScRk
++HSO0h4aXXZOOHvVjR3UtHPltOaHvlotnWuxC2c7OlAK2swa/InHPpXpYdObqRg92
++uV6Kn26XpT7+IlY0PrO6TmvbjF5FgKh9R+yBY4S7Faa0Tte32V2nomi0Z6FITrA1
++cC5b32ligf/cHn/0i9E/spgW7yyhbAeNdBmq/3Eer8fc6EjKfd7DTF+ieNgC+OxW
++hR6OnJcmmTqtw/GYOLpWrguQ5O/BkzIpZXhmpsluAq31XSQRrvWDHKJizj/PoVBg
++SYjGPX7C/LGYcAwytRUDZSURZX03vE987KfdzrvqMfwoxmkdhDvWQ2/Nr6lWb488
++hpUwcSnGmrKM2bMCuOD5CTz4u77wHXVt6ychdqyrLI1wBQKX7yysutU0jqOwsSxQ
++OWzEurh1WGEyDKzTrFSNElTwCA6pF7nvF9aOd2D2U/tMw15Gx5hknu28KeMuQI6+
++ueyG3mbE3gKSbKlFlCYhpJv0s0++Dbrp9rh5oPZG1yj+9+D8M8yB4rDFYNiKJ3Ot
++X/RoN8PXz9ToD6Z715llXl5t1gYmayzlNjcI/kvAXT68IZr0CzHNJxMM
++-----END ENCRYPTED PRIVATE KEY-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/certs/server-key.pem mariadb-native-client.trunk/unittest/libmariadb/certs/server-key.pem
+--- mariadb/unittest/libmariadb/certs/server-key.pem 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/certs/server-key.pem 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,15 @@
++-----BEGIN RSA PRIVATE KEY-----
++MIICXAIBAAKBgQDSnS+kxI2wBY1MeINRxfpyx5BQ8x4hX8o79PT+1PpEYEt/aNL1
++D2LronG4tbpB6pFTJ+mxnbPAOhnsnGEpYYh5Tz1VOcB1+IMko/Eqa4jComxb1Yxv
++3c1xbtFNyGaylOCQ1KHs60UNDL8KeZs827ys293jPjR7Kz3fzTfPRCgc3wIDAQAB
++AoGBAIODSYvOfFcMsHWuzvlR8ZiYisIxfYADi4my5QT3QqtNofcWIpyJlhBjaDWZ
++rIuaiFJvmtqhCewfm66G25j2YTuT0N4rZkcEzPm9y6NGgEgBWgMM01Jm2scg7WEN
++IS/KYWptqGxeMLSPWAaVUT6LU4wfbueXBBfV9Mp0jBXW/vKhAkEA+9GhXU65/eQO
++HnZRfPspuWeHAFRYGmPWnClDdOjFlmL0PpC5f6kENtX41PZEDUj1damJIJ/A/zRB
++heKn9UV6kQJBANYcaYxuhCpjvlSm8wRc80AY8Ncn8hDQBCHhjHWSOdDyv/rvKeht
++lOSeu8UJieJJwccJGa002Ql/ByvZIgJUeG8CQDqBF5ZQBhIge89D+eapi6YRkWHY
++Nqfa7i9VvuBYfB9WWhx3D0HDiMEcsTT5ChJ0EuMFQmCb/QDNqTNr1026mKECQBRP
++o6+fuEfxKFgNclZCnwzAkPBIKM1xfkLci5+HnJZ2wMGEOJyE8K/zYuqhKgRebNR9
++x4LH1aLx+vMs6O4Bp18CQGUQe24ONr9t+hSJ9FNdNfww/lIzJWvCt7xpqdccbd9O
++3mrka7/Kfl8LFEpkk7XuAXuNB0wgd0aowD7NnZgaJcs=
++-----END RSA PRIVATE KEY-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/charset.c mariadb-native-client.trunk/unittest/libmariadb/charset.c
+--- mariadb/unittest/libmariadb/charset.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/charset.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,686 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++
++#include "my_test.h"
++
++/*
++ test gbk charset escaping
++
++ The important part is that 0x27 (') is the second-byte in a invalid
++ two-byte GBK character here. But 0xbf5c is a valid GBK character, so
++ it needs to be escaped as 0x5cbf27
++
++*/
++#define TEST_BUG8378_IN "\xef\xbb\xbf\x27\xbf\x10"
++#define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10"
++
++/* set connection options */
++struct my_option_st opt_bug8378[] = {
++ {MYSQL_SET_CHARSET_NAME, "gbk"},
++ {0, NULL}
++};
++
++int bug_8378(MYSQL *mysql) {
++ int rc, len;
++ char out[9], buf[256];
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++
++ len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
++ FAIL_IF(memcmp(out, TEST_BUG8378_OUT, len), "wrong result");
++
++ sprintf(buf, "SELECT '%s' FROM DUAL", TEST_BUG8378_OUT);
++
++ rc= mysql_query(mysql, buf);
++ check_mysql_rc(rc, mysql);
++
++ if ((res= mysql_store_result(mysql))) {
++ row= mysql_fetch_row(res);
++ if (memcmp(row[0], TEST_BUG8378_IN, 4)) {
++ mysql_free_result(res);
++ return FAIL;
++ }
++ mysql_free_result(res);
++ } else
++ return FAIL;
++
++ return OK;
++}
++
++int test_client_character_set(MYSQL *mysql)
++{
++ MY_CHARSET_INFO cs;
++ char *csname= (char*) "utf8";
++ char *csdefault= (char*)mysql_character_set_name(mysql);
++
++ FAIL_IF(mysql_set_character_set(mysql, csname), mysql_error(mysql));
++
++ mysql_get_character_set_info(mysql, &cs);
++
++ FAIL_IF(strcmp(cs.csname, "utf8") || strcmp(cs.name, "utf8_general_ci"), "Character set != UTF8");
++ FAIL_IF(mysql_set_character_set(mysql, csdefault), mysql_error(mysql));
++
++ return OK;
++}
++
++/*
++ * Regression test for bug #10214
++ *
++ * Test escaping with NO_BACKSLASH_ESCAPES
++ *
++ */
++int bug_10214(MYSQL *mysql)
++{
++ int len, rc;
++ char out[8];
++
++ /* reset sql_mode */
++ rc= mysql_query(mysql, "SET sql_mode=''");
++ check_mysql_rc(rc, mysql);
++
++ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
++ FAIL_IF(memcmp(out, "a\\'b\\\\c", len), NULL);
++
++ rc= mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
++ check_mysql_rc(rc, mysql);
++ FAIL_IF(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES),
++ "wrong server status: NO_BACKSLASH_ESCAPES not set");
++
++ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
++ FAIL_IF(memcmp(out, "a''b\\c", len), "wrong result");
++
++ return OK;
++}
++
++/*
++ * simple escaping of special chars
++ */
++int test_escaping(MYSQL *mysql)
++{
++ int i= 0, rc, len;
++ char out[20];
++ char *escape_chars[] = {"'", "\x0", "\n", "\r", "\\", "\0", NULL};
++
++ /* reset sql_mode, mysql_change_user call doesn't reset it */
++ rc= mysql_query(mysql, "SET sql_mode=''");
++ check_mysql_rc(rc, mysql);
++
++ while (escape_chars[i]) {
++ len= mysql_real_escape_string(mysql, out, escape_chars[i], 1);
++ FAIL_IF(len < 2, "Len < 2");
++ i++;
++ }
++
++ return OK;
++}
++
++/*
++ * server doesn't reset sql_mode after COM_CHANGE_USER
++ */
++int bug_41785(MYSQL *mysql)
++{
++ char out[10];
++ int rc, len;
++
++ len= mysql_real_escape_string(mysql, out, "\\", 1);
++ FAIL_IF(len != 2, "len != 2");
++
++ rc= mysql_query(mysql, "SET SQL_MODE=NO_BACKSLASH_ESCAPES");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "SET sql_mode=''");
++ check_mysql_rc(rc, mysql);
++
++ mysql_change_user(mysql, "root", "", "test");
++
++ len= mysql_real_escape_string(mysql, out, "\\", 1);
++ FAIL_IF(len != 2, "len != 2");
++
++ return OK;
++}
++
++static int test_conversion(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ int rc;
++ MYSQL_BIND my_bind[1];
++ uchar buff[4];
++ ulong length;
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, "
++ " character_set_results=latin1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ stmt_text= "INSERT INTO t1 (a) VALUES (?)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer= (char*) buff;
++ my_bind[0].length= &length;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++
++ mysql_stmt_bind_param(stmt, my_bind);
++
++ buff[0]= (uchar) 0xC3;
++ buff[1]= (uchar) 0xA0;
++ length= 2;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ stmt_text= "SELECT a FROM t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ my_bind[0].buffer_length= sizeof(buff);
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(length == 1, "length != 1");
++ FAIL_UNLESS(buff[0] == 0xE0, "buff[0] != 0xE0");
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ stmt_text= "DROP TABLE t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "SET NAMES DEFAULT";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug27876(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++ uchar utf8_func[] =
++ {
++ 0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba,
++ 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba,
++ 0xd0, 0xb0,
++ 0x00
++ };
++
++ uchar utf8_param[] =
++ {
++ 0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0,
++ 0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a,
++ 0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1,
++ 0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f,
++ 0x00
++ };
++
++ char query[500];
++
++ DBUG_ENTER("test_bug27876");
++
++ rc= mysql_query(mysql, "set names utf8");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "select version()");
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++ mysql_free_result(result);
++
++ sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ sprintf(query,
++ "CREATE FUNCTION %s( %s VARCHAR(25))"
++ " RETURNS VARCHAR(25) DETERMINISTIC RETURN %s",
++ (char*) utf8_func, (char*) utf8_param, (char*) utf8_param);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++ sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++ mysql_free_result(result);
++
++ sprintf(query, "DROP FUNCTION %s", (char*) utf8_func);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "set names default");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_ps_i18n(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *stmt_text;
++ MYSQL_BIND bind_array[2];
++
++ /* Represented as numbers to keep UTF8 tools from clobbering them. */
++ const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
++ const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
++ char buf1[16], buf2[16];
++ ulong buf1_len, buf2_len;
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ /*
++ Create table with binary columns, set session character set to cp1251,
++ client character set to koi8, and make sure that there is conversion
++ on insert and no conversion on select
++ */
++
++ stmt_text= "CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, "
++ "CHARACTER_SET_CONNECTION=cp1251, "
++ "CHARACTER_SET_RESULTS=koi8r";
++
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ memset(bind_array, '\0', sizeof(bind_array));
++ bind_array[0].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[0].buffer= (void *) koi8;
++ bind_array[0].buffer_length= strlen(koi8);
++
++ bind_array[1].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[1].buffer= (void *) koi8;
++ bind_array[1].buffer_length= strlen(koi8);
++
++ stmt= mysql_stmt_init(mysql);
++ check_stmt_rc(rc, stmt);
++
++ stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_bind_param(stmt, bind_array);
++ check_stmt_rc(rc, stmt);
++
++// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "SELECT c1, c2 FROM t1";
++
++ /* c1 and c2 are binary so no conversion will be done on select */
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ bind_array[0].buffer= buf1;
++ bind_array[0].buffer_length= sizeof(buf1);
++ bind_array[0].length= &buf1_len;
++
++ bind_array[1].buffer= buf2;
++ bind_array[1].buffer_length= sizeof(buf2);
++ bind_array[1].length= &buf2_len;
++
++ mysql_stmt_bind_result(stmt, bind_array);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(buf1_len == strlen(cp1251), "buf1_len != strlen(cp1251)");
++ FAIL_UNLESS(buf2_len == strlen(cp1251), "buf2_len != strlen(cp1251)");
++ FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "buf1 != cp1251");
++ FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "buf2 != cp1251");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ /*
++ Now create table with two cp1251 columns, set client character
++ set to koi8 and supply columns of one row as string and another as
++ binary data. Binary data must not be converted on insert, and both
++ columns must be converted to client character set on select.
++ */
++
++ stmt_text= "CREATE TABLE t1 (c1 VARCHAR(255) CHARACTER SET cp1251, "
++ "c2 VARCHAR(255) CHARACTER SET cp1251)";
++
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ /* this data must be converted */
++ bind_array[0].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[0].buffer= (void *) koi8;
++ bind_array[0].buffer_length= strlen(koi8);
++
++ bind_array[1].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[1].buffer= (void *) koi8;
++ bind_array[1].buffer_length= strlen(koi8);
++
++ mysql_stmt_bind_param(stmt, bind_array);
++
++// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* this data must not be converted */
++ bind_array[0].buffer_type= MYSQL_TYPE_BLOB;
++ bind_array[0].buffer= (void *) cp1251;
++ bind_array[0].buffer_length= strlen(cp1251);
++
++ bind_array[1].buffer_type= MYSQL_TYPE_BLOB;
++ bind_array[1].buffer= (void *) cp1251;
++ bind_array[1].buffer_length= strlen(cp1251);
++
++ mysql_stmt_bind_param(stmt, bind_array);
++
++// mysql_stmt_send_long_data(stmt, 0, cp1251, strlen(cp1251));
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* Fetch data and verify that rows are in koi8 */
++
++ stmt_text= "SELECT c1, c2 FROM t1";
++
++ /* c1 and c2 are binary so no conversion will be done on select */
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ bind_array[0].buffer= buf1;
++ bind_array[0].buffer_length= sizeof(buf1);
++ bind_array[0].length= &buf1_len;
++
++ bind_array[1].buffer= buf2;
++ bind_array[1].buffer_length= sizeof(buf2);
++ bind_array[1].length= &buf2_len;
++
++ mysql_stmt_bind_result(stmt, bind_array);
++
++ while ((rc= mysql_stmt_fetch(stmt)) == 0)
++ {
++ FAIL_UNLESS(buf1_len == strlen(koi8), "buf1_len != strlen(koi8)");
++ FAIL_UNLESS(buf2_len == strlen(koi8), "buf2_len != strlen(koi8)");
++ FAIL_UNLESS(!memcmp(buf1, koi8, buf1_len), "buf1 != koi8");
++ FAIL_UNLESS(!memcmp(buf2, koi8, buf1_len), "buf2 != koi8");
++ }
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ mysql_stmt_close(stmt);
++
++ stmt_text= "DROP TABLE t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "SET NAMES DEFAULT";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/*
++ Bug#30472: libmysql doesn't reset charset, insert_id after succ.
++ mysql_change_user() call row insertions.
++*/
++
++static int bug30472_retrieve_charset_info(MYSQL *con,
++ char *character_set_name,
++ char *character_set_client,
++ char *character_set_results,
++ char *collation_connection)
++{
++ MYSQL_RES *rs;
++ MYSQL_ROW row;
++ int rc;
++
++ /* Get the cached client character set name. */
++
++ strcpy(character_set_name, mysql_character_set_name(con));
++
++ /* Retrieve server character set information. */
++
++ rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'");
++ check_mysql_rc(rc, con);
++
++ rs= mysql_store_result(con);
++ FAIL_IF(!rs, "Invalid result set");
++ row= mysql_fetch_row(rs);
++ FAIL_IF(!row, "Couldn't fetch row");
++ strcpy(character_set_client, row[1]);
++ mysql_free_result(rs);
++
++ rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");
++ check_mysql_rc(rc, con);
++ rs= mysql_store_result(con);
++ FAIL_IF(!rs, "Invalid result set");
++ row= mysql_fetch_row(rs);
++ FAIL_IF(!row, "Couldn't fetch row");
++ strcpy(character_set_results, row[1]);
++ mysql_free_result(rs);
++
++ rc= mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'");
++ check_mysql_rc(rc, con);
++ rs= mysql_store_result(con);
++ FAIL_IF(!rs, "Invalid result set");
++ row= mysql_fetch_row(rs);
++ FAIL_IF(!row, "Couldn't fetch row");
++ strcpy(collation_connection, row[1]);
++ mysql_free_result(rs);
++ return OK;
++}
++
++#define MY_CS_NAME_SIZE 32
++
++static int test_bug30472(MYSQL *mysql)
++{
++ int rc;
++
++ char character_set_name_1[MY_CS_NAME_SIZE];
++ char character_set_client_1[MY_CS_NAME_SIZE];
++ char character_set_results_1[MY_CS_NAME_SIZE];
++ char collation_connnection_1[MY_CS_NAME_SIZE];
++
++ char character_set_name_2[MY_CS_NAME_SIZE];
++ char character_set_client_2[MY_CS_NAME_SIZE];
++ char character_set_results_2[MY_CS_NAME_SIZE];
++ char collation_connnection_2[MY_CS_NAME_SIZE];
++
++ char character_set_name_3[MY_CS_NAME_SIZE];
++ char character_set_client_3[MY_CS_NAME_SIZE];
++ char character_set_results_3[MY_CS_NAME_SIZE];
++ char collation_connnection_3[MY_CS_NAME_SIZE];
++
++ char character_set_name_4[MY_CS_NAME_SIZE];
++ char character_set_client_4[MY_CS_NAME_SIZE];
++ char character_set_results_4[MY_CS_NAME_SIZE];
++ char collation_connnection_4[MY_CS_NAME_SIZE];
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++ /* Retrieve character set information. */
++
++ mysql_set_character_set(mysql, "latin1");
++ bug30472_retrieve_charset_info(mysql,
++ character_set_name_1,
++ character_set_client_1,
++ character_set_results_1,
++ collation_connnection_1);
++
++ /* Switch client character set. */
++
++ FAIL_IF(mysql_set_character_set(mysql, "utf8"), "Setting cs to utf8 failed");
++
++ /* Retrieve character set information. */
++
++ bug30472_retrieve_charset_info(mysql,
++ character_set_name_2,
++ character_set_client_2,
++ character_set_results_2,
++ collation_connnection_2);
++
++ /*
++ Check that
++ 1) character set has been switched and
++ 2) new character set is different from the original one.
++ */
++
++ FAIL_UNLESS(strcmp(character_set_name_2, "utf8") == 0, "cs_name != utf8");
++ FAIL_UNLESS(strcmp(character_set_client_2, "utf8") == 0, "cs_client != utf8");
++ FAIL_UNLESS(strcmp(character_set_results_2, "utf8") == 0, "cs_result != ut8");
++ FAIL_UNLESS(strcmp(collation_connnection_2, "utf8_general_ci") == 0, "collation != utf8_general_ci");
++
++ diag("%s %s", character_set_name_1, character_set_name_2);
++ FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0, "cs_name1 = cs_name2");
++ FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0, "cs_client1 = cs_client2");
++ FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0, "cs_result1 = cs_result2");
++ FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0, "collation1 = collation2");
++
++ /* Call mysql_change_user() with the same username, password, database. */
++
++ rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
++ mysql_set_character_set(mysql, "latin1");
++ check_mysql_rc(rc, mysql);
++
++ /* Retrieve character set information. */
++
++ bug30472_retrieve_charset_info(mysql,
++ character_set_name_3,
++ character_set_client_3,
++ character_set_results_3,
++ collation_connnection_3);
++
++ /* Check that character set information has been reset. */
++
++ FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0, "cs_name1 != cs_name3");
++ FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0, "cs_client1 != cs_client3");
++ FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0, "cs_result1 != cs_result3");
++ FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0, "collation1 != collation3");
++
++ /* Change connection-default character set in the client. */
++
++ mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
++
++ /*
++ Call mysql_change_user() in order to check that new connection will
++ have UTF8 character set on the client and on the server.
++ */
++
++ rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
++ check_mysql_rc(rc, mysql);
++
++ /* Retrieve character set information. */
++
++ bug30472_retrieve_charset_info(mysql,
++ character_set_name_4,
++ character_set_client_4,
++ character_set_results_4,
++ collation_connnection_4);
++
++ /* Check that we have UTF8 on the server and on the client. */
++
++ FAIL_UNLESS(strcmp(character_set_name_4, "utf8") == 0, "cs_name != utf8");
++ FAIL_UNLESS(strcmp(character_set_client_4, "utf8") == 0, "cs_client != utf8");
++ FAIL_UNLESS(strcmp(character_set_results_4, "utf8") == 0, "cs_result != utf8");
++ FAIL_UNLESS(strcmp(collation_connnection_4, "utf8_general_ci") == 0, "collation_connection != utf8_general_ci");
++
++ /* That's it. Cleanup. */
++
++ return OK;
++}
++
++static int test_bug_54100(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ MYSQL_ROW row;
++ int rc;
++
++ rc= mysql_query(mysql, "SHOW CHARACTER SET");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++
++ while ((row= mysql_fetch_row(result)))
++ {
++ /* ignore ucs2 */
++ if (strcmp(row[0], "ucs2") && strcmp(row[0], "utf16le") && strcmp(row[0], "utf8mb4") &&
++ strcmp(row[0], "utf16") && strcmp(row[0], "utf32")) {
++ rc= mysql_set_character_set(mysql, row[0]);
++ check_mysql_rc(rc, mysql);
++ }
++ }
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++struct my_tests_st my_tests[] = {
++ {"bug_8378: mysql_real_escape with gbk", bug_8378, TEST_CONNECTION_NEW, 0, opt_bug8378, NULL},
++ {"test_client_character_set", test_client_character_set, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"bug_10214: mysql_real_escape with NO_BACKSLASH_ESCAPES", bug_10214, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_escaping", test_escaping, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_conversion", test_conversion, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"bug_41785", bug_41785, TEST_CONNECTION_DEFAULT, 0, NULL, "not fixed yet"},
++ {"test_bug27876", test_bug27876, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug30472", test_bug30472, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_ps_i18n", test_ps_i18n, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug_54100", test_bug_54100, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, 0}
++};
++
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/connection.c'
---- mariadb/unittest/libmysql/connection.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/connection.c 2013-03-14 21:01:43 +0000
-@@ -167,7 +167,8 @@
- const char *db= "mysqltest_user_test_database";
- int rc;
-
-- DBUG_ENTER("test_change_user");
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/CMakeLists.txt mariadb-native-client.trunk/unittest/libmariadb/CMakeLists.txt
+--- mariadb/unittest/libmariadb/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,32 @@
++# Copyright (C) 2008 Sun Microsystems, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++
++ENABLE_TESTING()
++
++
++INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
++ ${CMAKE_BINARY_DIR}/include
++ ${CMAKE_SOURCE_DIR}/unittest/mytap)
++ADD_DEFINITIONS(-DLIBMARIADB)
++
++SET(API_TESTS "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
++ "sp" "result" "connection" "misc" "ssl" "ps_new" "sqlite3" "thread" "cs_conv" "dyncol")
++
++FOREACH(API_TEST ${API_TESTS})
++ ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
++ TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient ${EXTRA_LIBS})
++ ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST})
++ SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120)
++ENDFOREACH(API_TEST)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/connection.c mariadb-native-client.trunk/unittest/libmariadb/connection.c
+--- mariadb/unittest/libmariadb/connection.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/connection.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,631 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++/**
++ Some basic tests of the client API.
++*/
++
++#include "my_test.h"
++
++static int test_bug20023(MYSQL *mysql)
++{
++ int sql_big_selects_orig;
++ int max_join_size_orig;
++
++ int sql_big_selects_2;
++ int sql_big_selects_3;
++ int sql_big_selects_4;
++ int sql_big_selects_5;
++ int rc;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ /***********************************************************************
++ Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values.
++ ***********************************************************************/
++
++ query_int_variable(mysql,
++ "@@session.sql_big_selects",
++ &sql_big_selects_orig);
++
++ query_int_variable(mysql,
++ "@@global.max_join_size",
++ &max_join_size_orig);
++
++ /***********************************************************************
++ Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value.
++ ***********************************************************************/
++
++ /* Issue COM_CHANGE_USER. */
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ /* Query SQL_BIG_SELECTS. */
++
++ query_int_variable(mysql,
++ "@@session.sql_big_selects",
++ &sql_big_selects_2);
++
++ /* Check that SQL_BIG_SELECTS is reset properly. */
++
++ FAIL_UNLESS(sql_big_selects_orig == sql_big_selects_2, "Different value for sql_big_select");
++
++ /***********************************************************************
++ Test that if MAX_JOIN_SIZE set to non-default value,
++ SQL_BIG_SELECTS will be 0.
++ ***********************************************************************/
++
++ /* Set MAX_JOIN_SIZE to some non-default value. */
++
++ rc= mysql_query(mysql, "SET @@global.max_join_size = 10000");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "SET @@session.max_join_size = default");
++ check_mysql_rc(rc, mysql);
++
++ /* Issue COM_CHANGE_USER. */
++
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ /* Query SQL_BIG_SELECTS. */
++
++ query_int_variable(mysql,
++ "@@session.sql_big_selects",
++ &sql_big_selects_3);
++
++ /* Check that SQL_BIG_SELECTS is 0. */
++
++ FAIL_UNLESS(sql_big_selects_3 == 0, "big_selects != 0");
++
++ /***********************************************************************
++ Test that if MAX_JOIN_SIZE set to default value,
++ SQL_BIG_SELECTS will be 1.
++ ***********************************************************************/
++
++ /* Set MAX_JOIN_SIZE to the default value (-1). */
++
++ rc= mysql_query(mysql, "SET @@global.max_join_size = cast(-1 as unsigned int)");
++ rc= mysql_query(mysql, "SET @@session.max_join_size = default");
++
++ /* Issue COM_CHANGE_USER. */
++
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ /* Query SQL_BIG_SELECTS. */
++
++ query_int_variable(mysql,
++ "@@session.sql_big_selects",
++ &sql_big_selects_4);
++
++ /* Check that SQL_BIG_SELECTS is 1. */
++
++ FAIL_UNLESS(sql_big_selects_4 == 1, "sql_big_select != 1");
++
++ /***********************************************************************
++ Restore MAX_JOIN_SIZE.
++ Check that SQL_BIG_SELECTS will be the original one.
++ ***********************************************************************/
++
++ rc= mysql_query(mysql, "SET @@global.max_join_size = cast(-1 as unsigned int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SET @@session.max_join_size = default");
++ check_mysql_rc(rc, mysql);
++
++ /* Issue COM_CHANGE_USER. */
++
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ /* Query SQL_BIG_SELECTS. */
++
++ query_int_variable(mysql,
++ "@@session.sql_big_selects",
++ &sql_big_selects_5);
++
++ /* Check that SQL_BIG_SELECTS is 1. */
++
++ FAIL_UNLESS(sql_big_selects_5 == sql_big_selects_orig, "big_select != 1");
++
++ /***********************************************************************
++ That's it. Cleanup.
++ ***********************************************************************/
++
++ return OK;
++}
++
++static int test_change_user(MYSQL *mysql)
++{
++ char buff[256];
++ const char *user_pw= "mysqltest_pw";
++ const char *user_no_pw= "mysqltest_no_pw";
++ const char *pw= "password";
++ const char *db= "mysqltest_user_test_database";
++ int rc;
++
+ diag("Due to mysql_change_user security fix this test will not work anymore.");
+ return(SKIP);
-
- /* Prepare environment */
- sprintf(buff, "drop database if exists %s", db);
-@@ -321,6 +322,9 @@
- static char db[NAME_CHAR_LEN+1];
- static char query[LARGE_BUFFER_SIZE*2];
-
++
++ /* Prepare environment */
++ sprintf(buff, "drop database if exists %s", db);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ sprintf(buff, "create database %s", db);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ sprintf(buff,
++ "grant select on %s.* to %s@'%%' identified by '%s'",
++ db,
++ user_pw,
++ pw);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ sprintf(buff,
++ "grant select on %s.* to %s@'%%'",
++ db,
++ user_no_pw);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++
++ /* Try some combinations */
++ rc= mysql_change_user(mysql, NULL, NULL, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++
++ rc= mysql_change_user(mysql, "", NULL, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", "", NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", "", "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, NULL, "", "");
++ FAIL_UNLESS(rc, "Error expected");
++
++
++ rc= mysql_change_user(mysql, NULL, NULL, "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", NULL, "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, NULL, "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, "", "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, "", NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, NULL, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, "", db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, NULL, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_pw, pw, db);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_pw, pw, NULL);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_pw, pw, "");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_no_pw, pw, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_no_pw, pw, "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_no_pw, pw, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user_no_pw, "", NULL);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_no_pw, "", "");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_no_pw, "", db);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, user_no_pw, NULL, db);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_change_user(mysql, "", pw, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", pw, "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", pw, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, NULL, pw, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, NULL, NULL, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, NULL, "", db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", "", db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ /* Cleanup the environment */
++
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ sprintf(buff, "drop database %s", db);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ sprintf(buff, "drop user %s@'%%'", user_pw);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ sprintf(buff, "drop user %s@'%%'", user_no_pw);
++ rc= mysql_query(mysql, buff);
++ check_mysql_rc(rc, mysql)
++
++ return OK;
++}
++
++/**
++ Bug#31669 Buffer overflow in mysql_change_user()
++*/
++
++#define LARGE_BUFFER_SIZE 2048
++
++static int test_bug31669(MYSQL *mysql)
++{
++ int rc;
++ static char buff[LARGE_BUFFER_SIZE+1];
++ static char user[USERNAME_CHAR_LENGTH+1];
++ static char db[NAME_CHAR_LEN+1];
++ static char query[LARGE_BUFFER_SIZE*2];
++
+ diag("Due to mysql_change_user security fix this test will not work anymore.");
+ return(SKIP);
+
- rc= mysql_change_user(mysql, NULL, NULL, NULL);
- FAIL_UNLESS(rc, "Error expected");
-
-@@ -501,8 +505,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++ rc= mysql_change_user(mysql, NULL, NULL, NULL);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc= mysql_change_user(mysql, "", "", "");
++ FAIL_UNLESS(rc, "Error expected");
++
++ memset(buff, 'a', sizeof(buff));
++
++ rc= mysql_change_user(mysql, buff, buff, buff);
++ FAIL_UNLESS(rc, "Error epected");
++
++ rc = mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ memset(db, 'a', sizeof(db));
++ db[NAME_CHAR_LEN]= 0;
++ sprintf(query, "CREATE DATABASE IF NOT EXISTS %s", db);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ memset(user, 'b', sizeof(user));
++ user[USERNAME_CHAR_LENGTH]= 0;
++ memset(buff, 'c', sizeof(buff));
++ buff[LARGE_BUFFER_SIZE]= 0;
++ sprintf(query, "GRANT ALL PRIVILEGES ON *.* TO '%s'@'%%' IDENTIFIED BY '%s' WITH GRANT OPTION", user, buff);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "FLUSH PRIVILEGES");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_change_user(mysql, user, buff, db);
++ check_mysql_rc(rc, mysql);
++
++ user[USERNAME_CHAR_LENGTH-1]= 'a';
++ rc= mysql_change_user(mysql, user, buff, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ user[USERNAME_CHAR_LENGTH-1]= 'b';
++ buff[LARGE_BUFFER_SIZE-1]= 'd';
++ rc= mysql_change_user(mysql, user, buff, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ buff[LARGE_BUFFER_SIZE-1]= 'c';
++ db[NAME_CHAR_LEN-1]= 'e';
++ rc= mysql_change_user(mysql, user, buff, db);
++ FAIL_UNLESS(rc, "Error expected");
++
++ db[NAME_CHAR_LEN-1]= 'a';
++ rc= mysql_change_user(mysql, user, buff, db);
++ FAIL_UNLESS(!rc, "Error expected");
++
++ rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1);
++ FAIL_UNLESS(rc, "Error expected");
++
++ rc = mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ sprintf(query, "DROP DATABASE %s", db);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ sprintf(query, "DELETE FROM mysql.user WHERE User='%s'", user);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++ FAIL_UNLESS(mysql_affected_rows(mysql) == 1, "");
++
++ return OK;
++}
++
++/**
++ Bug# 33831 mysql_real_connect() should fail if
++ given an already connected MYSQL handle.
++*/
++
++static int test_bug33831(MYSQL *mysql)
++{
++ FAIL_IF(mysql_real_connect(mysql, hostname, username,
++ password, schema, port, socketname, 0),
++ "Error expected");
++
++ return OK;
++}
++
++/* Test MYSQL_OPT_RECONNECT, Bug#15719 */
++
++static int test_opt_reconnect(MYSQL *mysql)
++{
++ my_bool my_true= TRUE;
++ int rc;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "not enough memory");
++
++ FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
++
++ rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, &my_true);
++ check_mysql_rc(rc, mysql);
++
++ FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1");
++
++ if (!(mysql_real_connect(mysql, hostname, username,
++ password, schema, port,
++ socketname, 0)))
++ {
++ diag("connection failed");
++ mysql_close(mysql);
++ return FAIL;
++ }
++
++ FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1");
++
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "not enough memory");
++
++ FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
++
++ if (!(mysql_real_connect(mysql, hostname, username,
++ password, schema, port,
++ socketname, 0)))
++ {
++ diag("connection failed");
++ mysql_close(mysql);
++ return FAIL;
++ }
++
++ FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
++
++ mysql_close(mysql);
++ return OK;
++}
++
++
++static int test_compress(MYSQL *mysql)
++{
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ int rc;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "not enough memory");
++
++ /* use compressed protocol */
++ rc= mysql_options(mysql, MYSQL_OPT_COMPRESS, NULL);
++
++
++
++ if (!(mysql_real_connect(mysql, hostname, username,
++ password, schema, port,
++ socketname, 0)))
++ {
++ diag("connection failed");
++ return FAIL;
++ }
++
++ rc= mysql_query(mysql, "SHOW STATUS LIKE 'compression'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++ FAIL_UNLESS(strcmp(row[1], "ON") == 0, "Compression off");
++ mysql_free_result(res);
++
++ mysql_close(mysql);
++ return OK;
++}
++
++static int test_reconnect(MYSQL *mysql)
++{
++ my_bool my_true= TRUE;
++ MYSQL *mysql1;
++ int rc;
++
++ mysql1= mysql_init(NULL);
++ FAIL_IF(!mysql1, "not enough memory");
++
++ FAIL_UNLESS(mysql1->reconnect == 0, "reconnect != 0");
++
++ rc= mysql_options(mysql1, MYSQL_OPT_RECONNECT, &my_true);
++ check_mysql_rc(rc, mysql1);
++
++ FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1");
++
++ if (!(mysql_real_connect(mysql1, hostname, username,
++ password, schema, port,
++ socketname, 0)))
++ {
++ diag("connection failed");
++ mysql_close(mysql);
++ return FAIL;
++ }
++
++ FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1");
++
++ diag("Thread_id before kill: %lu", mysql_thread_id(mysql1));
++ mysql_kill(mysql, mysql_thread_id(mysql1));
++ sleep(2);
++
++ rc= mysql_query(mysql1, "SELECT 1 FROM DUAL LIMIT 0");
++ FAIL_IF(rc == 0, "error expected");
++ rc= mysql_query(mysql1, "SELECT 1 FROM DUAL LIMIT 0");
++ check_mysql_rc(rc, mysql1);
++ diag("Thread_id after kill: %lu", mysql_thread_id(mysql1));
++
++ FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1");
++ mysql_close(mysql1);
++ return OK;
++}
++
++int test_conc21(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *res= NULL;
++ MYSQL_ROW row;
++ char tmp[256];
++ int check_server_version= 0;
++ int major=0, minor= 0, patch=0;
++
++ rc= mysql_query(mysql, "SELECT @@version");
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_store_result(mysql);
++ FAIL_IF(res == NULL, "invalid result set");
++
++ row= mysql_fetch_row(res);
++ strcpy(tmp, row[0]);
++ mysql_free_result(res);
++
++ sscanf(tmp, "%d.%d.%d", &major, &minor, &patch);
++
++ check_server_version= major * 10000 + minor * 100 + patch;
++
++ FAIL_IF(mysql_get_server_version(mysql) != check_server_version, "Numeric server version mismatch");
++ FAIL_IF(strcmp(mysql_get_server_info(mysql), tmp) != 0, "String server version mismatch");
++ return OK;
++}
++
++int test_conc26(MYSQL *my)
++{
++ MYSQL *mysql= mysql_init(NULL);
++ mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
++
++ FAIL_IF(mysql_real_connect(mysql, hostname, "notexistinguser", "password", schema, port, NULL, CLIENT_REMEMBER_OPTIONS),
++ "Error expected");
++
++ FAIL_IF(!mysql->options.charset_name || strcmp(mysql->options.charset_name, "utf8") != 0,
++ "expected charsetname=utf8");
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(mysql_real_connect(mysql, hostname, "notexistinguser", "password", schema, port, NULL, 0),
++ "Error expected");
++ FAIL_IF(mysql->options.charset_name, "Error: options not freed");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++int test_connection_timeout(MYSQL *my)
++{
++ unsigned int timeout= 5;
++ time_t start, elapsed;
++ MYSQL *mysql= mysql_init(NULL);
++ mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout);
++ start= time(NULL);
++ if (mysql_real_connect(mysql, "192.168.1.101", "notexistinguser", "password", schema, port, NULL, CLIENT_REMEMBER_OPTIONS))
++ {
++ diag("Error expected - maybe you have to change hostname");
++ return FAIL;
++ }
++ elapsed= time(NULL) - start;
++ diag("elapsed: %u", elapsed);
++ mysql_close(mysql);
++ FAIL_IF(elapsed > timeout + 1, "timeout ignored")
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_bug20023", test_bug20023, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_bug31669", test_bug31669, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_bug33831", test_bug33831, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_change_user", test_change_user, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_opt_reconnect", test_opt_reconnect, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_compress", test_compress, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_reconnect", test_reconnect, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_conc21", test_conc21, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_conc26", test_conc26, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_connection_timeout", test_connection_timeout, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/cursor.c'
---- mariadb/unittest/libmysql/cursor.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/cursor.c 2013-03-14 21:01:43 +0000
-@@ -46,6 +46,10 @@
-
- MYSQL_STMT *stmt= mysql_stmt_init(mysql);
- rc= mysql_stmt_prepare(stmt, query, strlen(query));
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/cs_conv.c mariadb-native-client.trunk/unittest/libmariadb/cs_conv.c
+--- mariadb/unittest/libmariadb/cs_conv.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/cs_conv.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,129 @@
++/*
++Copyright (c) 2013 Monty Program AB. All rights reserved.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++
++#include "my_test.h"
++#include <locale.h>
++
++
++typedef struct {
++ char *cs_from;
++ char *cs_to;
++ char *hex_source;
++ char *source;
++ size_t len;
++} CS_CONV;
++
++
++
++static int test_cs_conversion(MYSQL *mysql)
++{
++ CS_CONV cs_conv[]= { {"latin1", "utf8", NULL, "Günter André",0},
++ {"koi8r", "utf8", NULL, "×ÁÓÑ", 0},
++ {"koi8r", "utf8", NULL, "÷áóñ", 0},
++ {"koi8r", "utf8", NULL, "É", 0},
++ {"koi8r", "utf8", NULL, "Ê", 0},
++ {"ucs2", "utf8", "0x0041040B", "\x00\x41\x04\x0B", 4},
++ {"ucs2", "utf8", "0x039C03C903B4", "\x03\x9C\x03\xC9\x03\xB4",6},
++ {"ucs2", "utf8", "0x039C03C903B403B11F770308", "\x03\x9C\x03\xC9\x03\xB4\x03\xB1\x1F\x77\x03\x08", 0},
++ {"ucs2", "utf8", "0x0030", "\x00\x30", 2},
++ {"ucs2", "utf8", NULL, "£Ã£±", 0},
++ {"ucs2", "utf8", NULL, "£Ã£±", 0},
++ {"ucs2", "utf8", NULL, "£Ã£±", 0},
++ {"ucs2", "sjis", NULL, "£Ã£±", 0},
++ {"ucs2", "ujis", NULL, "£Ã£±", 0},
++ {"eucjpms", "ujis", NULL, "C1", 0},
++ {"latin1", "sjis", NULL, "C1", 0},
++ {"utf8", "latin1", NULL, "C1", 0},
++ /* C8 pane not supported
++ {"big5", "utf8", "0xC84041", "\xC8\x40\x41", 0}, */
++ {"latin1", "utf8", "0xFF8F", "\xFF\x8F", 0},
++ {NULL, NULL, NULL}
++ };
++ int i= 0, rc;
++
++ setlocale(LC_ALL, "en_GB");
++
++ while (cs_conv[i].cs_from)
++ {
++ int error_code;
++ char query[1024];
++ size_t from_len, to_len= 1024;
++ CHARSET_INFO *cs_from, *cs_to;
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ char str_converted[1024];
++ char str_expected[1024];
++ memset(str_converted, 0, 1024);
++ memset(str_expected, 0, 1024);
++
++ FAIL_IF(!(cs_from= mysql_get_charset_by_name(cs_conv[i].cs_from)), "invalid character set");
++ FAIL_IF(!(cs_to= mysql_get_charset_by_name(cs_conv[i].cs_to)), "invalid character set");
++
++
++ snprintf(query, 1024, "SET NAMES %s", cs_conv[i].cs_to);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ snprintf(query, 1024, "SELECT CONVERT(_%s %s%s%s using %s)",
++ cs_conv[i].cs_from,
++ cs_conv[i].hex_source ? "" : "\"",
++ cs_conv[i].hex_source ? cs_conv[i].hex_source : cs_conv[i].source,
++ cs_conv[i].hex_source ? "" : "\"",
++ cs_conv[i].cs_to);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_store_result(mysql);
++ FAIL_IF(!res, "expected result set");
++
++ FAIL_IF(!(row= mysql_fetch_row(res)), "fetching row failed");
++ strcpy(str_converted, row[0]);
++ mysql_free_result(res);
++
++ from_len= cs_conv[i].len ? cs_conv[i].len : strlen(cs_conv[i].source);
++ FAIL_IF(mariadb_convert_string(cs_conv[i].source, &from_len, cs_from,
++ str_expected, &to_len, cs_to, &error_code) < 1, "conversion error occured");
++
++ if (strcmp(str_converted, str_expected))
++ {
++ diag("Error converting from %s to %s\ndb:'%s' library: '%s'",
++ cs_from->csname, cs_to->csname, str_converted, str_expected);
++ return FAIL;
++ }
++ i++;
++ }
++
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_cs_conversion", test_cs_conversion, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, 0}
++};
++
++
++int main(int argc, char **argv)
++{
++ if (argc > 1)
++ get_options(argc, argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/cursor.c mariadb-native-client.trunk/unittest/libmariadb/cursor.c
+--- mariadb/unittest/libmariadb/cursor.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/cursor.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,1850 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++/* helper functions */
++enum { MAX_COLUMN_LENGTH= 255 };
++
++typedef struct st_stmt_fetch
++{
++ const char *query;
++ unsigned stmt_no;
++ MYSQL_STMT *handle;
++ my_bool is_open;
++ MYSQL_BIND *bind_array;
++ char **out_data;
++ unsigned long *out_data_length;
++ unsigned column_count;
++ unsigned row_count;
++} Stmt_fetch;
++
++MYSQL_STMT *open_cursor(MYSQL *mysql, const char *query)
++{
++ int rc;
++ const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
++
++ MYSQL_STMT *stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ if (rc) {
+ diag("Error: %s", mysql_stmt_error(stmt));
+ return NULL;
+ }
- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
- return stmt;
- }
-@@ -1645,7 +1649,11 @@
- rc= mysql_stmt_reset(stmt);
- check_stmt_rc(rc, stmt);
- rc= mysql_stmt_fetch(stmt);
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ return stmt;
++}
++
++/*
++ Create statement handle, prepare it with statement, execute and allocate
++ fetch buffers.
++*/
++
++int stmt_fetch_init(MYSQL *mysql, Stmt_fetch *fetch, unsigned stmt_no_arg,
++ const char *query_arg)
++{
++ unsigned long type= CURSOR_TYPE_READ_ONLY;
++ int rc;
++ unsigned i;
++ MYSQL_RES *metadata;
++ DBUG_ENTER("stmt_fetch_init");
++
++ /* Save query and statement number for error messages */
++ fetch->stmt_no= stmt_no_arg;
++ fetch->query= query_arg;
++
++ fetch->handle= mysql_stmt_init(mysql);
++
++ rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
++ FAIL_IF(rc, mysql_stmt_error(fetch->handle));
++
++ /*
++ The attribute is sent to server on execute and asks to open read-only
++ for result set
++ */
++ mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
++ (const void*) &type);
++
++ rc= mysql_stmt_execute(fetch->handle);
++ FAIL_IF(rc, mysql_stmt_error(fetch->handle));
++
++ /* Find out total number of columns in result set */
++ metadata= mysql_stmt_result_metadata(fetch->handle);
++ fetch->column_count= mysql_num_fields(metadata);
++ mysql_free_result(metadata);
++
++ /*
++ Now allocate bind handles and buffers for output data:
++ calloc memory to reduce number of MYSQL_BIND members we need to
++ set up.
++ */
++
++ fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
++ fetch->column_count);
++ fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
++ fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
++ fetch->column_count);
++ for (i= 0; i < fetch->column_count; ++i)
++ {
++ fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
++ fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
++ fetch->bind_array[i].buffer= fetch->out_data[i];
++ fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
++ fetch->bind_array[i].length= fetch->out_data_length + i;
++ }
++
++ mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
++
++ fetch->row_count= 0;
++ fetch->is_open= TRUE;
++
++ /* Ready for reading rows */
++ return OK;
++}
++
++
++int fill_tables(MYSQL *mysql, const char **query_list, unsigned query_count)
++{
++ int rc;
++ const char **query;
++ DBUG_ENTER("fill_tables");
++ for (query= query_list; query < query_list + query_count;
++ ++query)
++ {
++ rc= mysql_query(mysql, *query);
++ check_mysql_rc(rc, mysql);
++ }
++ return OK;
++}
++
++int stmt_fetch_fetch_row(Stmt_fetch *fetch)
++{
++ int rc;
++ unsigned i;
++
++ if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
++ {
++ ++fetch->row_count;
++ for (i= 0; i < fetch->column_count; ++i)
++ {
++ fetch->out_data[i][fetch->out_data_length[i]]= '\0';
++ }
++ }
++ else
++ fetch->is_open= FALSE;
++
++ return rc;
++}
++
++void stmt_fetch_close(Stmt_fetch *fetch)
++{
++ unsigned i;
++
++ for (i= 0; i < fetch->column_count; ++i)
++ free(fetch->out_data[i]);
++ free(fetch->out_data);
++ free(fetch->out_data_length);
++ free(fetch->bind_array);
++ mysql_stmt_close(fetch->handle);
++}
++
++
++
++enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
++
++int fetch_n(MYSQL *mysql, const char **query_list, unsigned query_count,
++ enum fetch_type fetch_type)
++{
++ unsigned open_statements= query_count;
++ int rc, error_count= 0;
++ Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
++ query_count);
++ Stmt_fetch *fetch;
++ DBUG_ENTER("fetch_n");
++
++ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
++ {
++ if (stmt_fetch_init(mysql, fetch, fetch - fetch_array,
++ query_list[fetch - fetch_array]))
++ return FAIL;
++ }
++
++ if (fetch_type == USE_STORE_RESULT)
++ {
++ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
++ {
++ rc= mysql_stmt_store_result(fetch->handle);
++ FAIL_IF(rc, mysql_stmt_error(fetch->handle));
++ }
++ }
++
++ while (open_statements)
++ {
++ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
++ {
++ if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
++ {
++ open_statements--;
++ /*
++ We try to fetch from the rest of the statements in case of
++ error
++ */
++ if (rc != MYSQL_NO_DATA)
++ error_count++;
++ }
++ }
++ }
++ if (!error_count)
++ {
++ unsigned total_row_count= 0;
++ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
++ total_row_count+= fetch->row_count;
++ }
++ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
++ stmt_fetch_close(fetch);
++ free(fetch_array);
++
++ return (error_count) ? FAIL:OK;
++}
++
++static int test_basic_cursors(MYSQL *mysql)
++{
++ const char *basic_tables[]=
++ {
++ "DROP TABLE IF EXISTS t1, t2",
++
++ "CREATE TABLE t1 "
++ "(id INTEGER NOT NULL PRIMARY KEY, "
++ " name VARCHAR(20) NOT NULL)",
++
++ "INSERT INTO t1 (id, name) VALUES "
++ " (2, 'Ja'), (3, 'Ede'), "
++ " (4, 'Haag'), (5, 'Kabul'), "
++ " (6, 'Almere'), (7, 'Utrecht'), "
++ " (8, 'Qandahar'), (9, 'Amsterdam'), "
++ " (10, 'Amersfoort'), (11, 'Constantine')",
++
++ "CREATE TABLE t2 "
++ "(id INTEGER NOT NULL PRIMARY KEY, "
++ " name VARCHAR(20) NOT NULL)",
++
++ "INSERT INTO t2 (id, name) VALUES "
++ " (4, 'Guam'), (5, 'Aruba'), "
++ " (6, 'Angola'), (7, 'Albania'), "
++ " (8, 'Anguilla'), (9, 'Argentina'), "
++ " (10, 'Azerbaijan'), (11, 'Afghanistan'), "
++ " (12, 'Burkina Faso'), (13, 'Faroe Islands')"
++ };
++
++ const char *queries[]=
++ {
++ "SELECT * FROM t1",
++ "SELECT * FROM t2"
++ };
++
++
++ FAIL_IF(fill_tables(mysql, basic_tables, sizeof(basic_tables)/sizeof(*basic_tables)), "fill_tables failed");
++
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
++ return OK;
++}
++
++
++static int test_cursors_with_union(MYSQL *mysql)
++{
++ const char *queries[]=
++ {
++ "SELECT t1.name FROM t1 UNION SELECT t2.name FROM t2",
++ "SELECT t1.id FROM t1 WHERE t1.id < 5"
++ };
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
++
++ return OK;
++}
++
++
++static int test_cursors_with_procedure(MYSQL *mysql)
++{
++ const char *queries[]=
++ {
++ "SELECT * FROM t1 procedure analyse()"
++ };
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
++ FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
++
++ return OK;
++}
++
++/*
++ Bug#21206: memory corruption when too many cursors are opened at once
++
++ Memory corruption happens when more than 1024 cursors are open
++ simultaneously.
++*/
++static int test_bug21206(MYSQL *mysql)
++{
++ int retcode= OK;
++
++ const size_t cursor_count= 1025;
++
++ const char *create_table[]=
++ {
++ "DROP TABLE IF EXISTS t1",
++ "CREATE TABLE t1 (i INT)",
++ "INSERT INTO t1 VALUES (1), (2), (3)"
++ };
++ const char *query= "SELECT * FROM t1";
++
++ Stmt_fetch *fetch_array=
++ (Stmt_fetch*) calloc(cursor_count, sizeof(Stmt_fetch));
++
++ Stmt_fetch *fetch;
++
++ FAIL_IF(fill_tables(mysql, create_table, sizeof(create_table) / sizeof(*create_table)), "fill_tables failed");
++
++ for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch)
++ {
++ if ((retcode= stmt_fetch_init(mysql, fetch, fetch - fetch_array, query)))
++ break;
++ }
++
++ for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch)
++ stmt_fetch_close(fetch);
++
++ free(fetch_array);
++
++ return retcode;
++}
++
++static int test_bug10729(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char a[21];
++ int rc;
++ const char *stmt_text;
++ int i= 0;
++ const char *name_array[3]= { "aaa", "bbb", "ccc" };
++ ulong type;
++
++ mysql_query(mysql, "drop table if exists t1");
++ mysql_query(mysql, "create table t1 (id integer not null primary key,"
++ "name VARCHAR(20) NOT NULL)");
++ rc= mysql_query(mysql, "insert into t1 (id, name) values "
++ "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "select name from t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void*) a;
++ my_bind[0].buffer_length= sizeof(a);
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ for (i= 0; i < 3; i++)
++ {
++ int row_no= 0;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while ((rc= mysql_stmt_fetch(stmt)) == 0)
++ {
++ FAIL_UNLESS(strcmp(a, name_array[row_no]) == 0, "a != name_array[row_no]");
++ ++row_no;
++ }
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ }
++ rc= mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#10736: cursors and subqueries, memroot management */
++
++static int test_bug10736(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char a[21];
++ int rc;
++ const char *stmt_text;
++ int i= 0;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
++ "name VARCHAR(20) NOT NULL)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 (id, name) values "
++ "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "select name from t1 where name=(select name from t1 where id=2)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void*) a;
++ my_bind[0].buffer_length= sizeof(a);
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ for (i= 0; i < 3; i++)
++ {
++ int row_no= 0;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while ((rc= mysql_stmt_fetch(stmt)) == 0)
++ ++row_no;
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ }
++ rc= mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#10794: cursors, packets out of order */
++
++static int test_bug10794(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt, *stmt1;
++ MYSQL_BIND my_bind[2];
++ char a[21];
++ int id_val;
++ ulong a_len;
++ int rc;
++ const char *stmt_text;
++ int i= 0;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
++ "name varchar(20) not null)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "insert into t1 (id, name) values (?, ?)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void*) &id_val;
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void*) a;
++ my_bind[1].length= &a_len;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ for (i= 0; i < 42; i++)
++ {
++ id_val= (i+1)*10;
++ sprintf(a, "a%d", i);
++ a_len= strlen(a); /* safety against broken sprintf */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++ stmt_text= "select name from t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ stmt1= mysql_stmt_init(mysql);
++ mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void*) a;
++ my_bind[0].buffer_length= sizeof(a);
++ my_bind[0].length= &a_len;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ /* Don't optimize: an attribute of the original test case */
++ mysql_stmt_free_result(stmt);
++ mysql_stmt_reset(stmt);
++ stmt_text= "select name from t1 where id=10";
++ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_stmt_bind_result(stmt1, my_bind);
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++ while (1)
++ {
++ rc= mysql_stmt_fetch(stmt1);
++ if (rc == MYSQL_NO_DATA)
++ {
++ break;
++ }
++ check_stmt_rc(rc, stmt1);
++ }
++ mysql_stmt_close(stmt);
++ mysql_stmt_close(stmt1);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#10760: cursors, crash in a fetch after rollback. */
++
++static int test_bug10760(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ int rc;
++ const char *stmt_text;
++ char id_buf[20];
++ ulong id_len;
++ int i= 0;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ /* create tables */
++ rc= mysql_query(mysql, "create table t1 (id integer not null primary key)"
++ " engine=MyISAM");
++ check_mysql_rc(rc, mysql);;
++ for (; i < 42; ++i)
++ {
++ char buf[100];
++ sprintf(buf, "insert into t1 (id) values (%d)", i+1);
++ rc= mysql_query(mysql, buf);
++ check_mysql_rc(rc, mysql);;
++ }
++ mysql_autocommit(mysql, FALSE);
++ /* create statement */
++ stmt= mysql_stmt_init(mysql);
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++
++ /*
++ 1: check that a deadlock within the same connection
++ is resolved and an error is returned. The deadlock is modelled
++ as follows:
++ con1: open cursor for select * from t1;
++ con1: insert into t1 (id) values (1)
++ */
++ stmt_text= "select id from t1 order by 1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);;
++ rc= mysql_query(mysql, "update t1 set id=id+100");
++ /*
++ If cursors are not materialized, the update will return an error;
++ we mainly test that it won't deadlock.
++ */
++ /* FAIL_IF(!rc, "Error expected"); */
++ /*
++ 2: check that MyISAM tables used in cursors survive
++ COMMIT/ROLLBACK.
++ */
++ rc= mysql_rollback(mysql); /* should not close the cursor */
++ check_mysql_rc(rc, mysql);;
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);;
++
++ /*
++ 3: check that cursors to InnoDB tables are closed (for now) by
++ COMMIT/ROLLBACK.
++ */
++ if (check_variable(mysql, "@@have_innodb", "YES"))
++ {
++ stmt_text= "select id from t1 order by 1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);;
++
++ rc= mysql_query(mysql, "alter table t1 engine=InnoDB");
++ check_mysql_rc(rc, mysql);;
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void*) id_buf;
++ my_bind[0].buffer_length= sizeof(id_buf);
++ my_bind[0].length= &id_len;
++ check_stmt_rc(rc, stmt);;
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_execute(stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ rc= mysql_rollback(mysql); /* should close the cursor */
++ }
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_autocommit(mysql, TRUE); /* restore default */
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#11172: cursors, crash on a fetch from a datetime column */
++
++static int test_bug11172(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND bind_in[1], bind_out[2];
++ MYSQL_TIME hired;
++ int rc;
++ const char *stmt_text;
++ int i= 0, id;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
++ "hired date not null)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "insert into t1 (id, hired) values (1, '1933-08-24'), "
++ "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), "
++ "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')");
++ check_mysql_rc(rc, mysql);
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ stmt_text= "SELECT id, hired FROM t1 WHERE hired=?";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++
++ memset(bind_in, '\0', sizeof(bind_in));
++ memset(bind_out, '\0', sizeof(bind_out));
++ memset(&hired, '\0', sizeof(hired));
++ hired.year= 1965;
++ hired.month= 1;
++ hired.day= 1;
++ bind_in[0].buffer_type= MYSQL_TYPE_DATE;
++ bind_in[0].buffer= (void*) &hired;
++ bind_in[0].buffer_length= sizeof(hired);
++ bind_out[0].buffer_type= MYSQL_TYPE_LONG;
++ bind_out[0].buffer= (void*) &id;
++ bind_out[1]= bind_in[0];
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_bind_param(stmt, bind_in);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_result(stmt, bind_out);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while ((rc= mysql_stmt_fetch(stmt)) == 0);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ if (!mysql_stmt_free_result(stmt))
++ mysql_stmt_reset(stmt);
++ }
++ mysql_stmt_close(stmt);
++ mysql_rollback(mysql);
++ mysql_rollback(mysql);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#11656: cursors, crash on a fetch from a query with distinct. */
++
++static int test_bug11656(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ int rc;
++ const char *stmt_text;
++ char buf[2][20];
++ int i= 0;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 ("
++ "server varchar(40) not null, "
++ "test_kind varchar(1) not null, "
++ "test_id varchar(30) not null , "
++ "primary key (server,test_kind,test_id))");
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "select distinct test_kind, test_id from t1 "
++ "where server in (?, ?)";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ strcpy(buf[0], "pcint502_MY2");
++ strcpy(buf[1], "*");
++ for (i=0; i < 2; i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[i].buffer= (uchar* *)&buf[i];
++ my_bind[i].buffer_length= strlen(buf[i]);
++ }
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Cursors: opening a cursor to a compilicated query with ORDER BY */
++
++static int test_bug11901(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ int rc;
++ char workdept[20];
++ ulong workdept_len;
++ uint32 empno;
++ const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
++ const char *stmt_text;
++
++
++ stmt_text= "drop table if exists t1, t2";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "create table t1 ("
++ " empno int(11) not null, firstname varchar(20) not null,"
++ " midinit varchar(20) not null, lastname varchar(20) not null,"
++ " workdept varchar(6) not null, salary double not null,"
++ " bonus float not null, primary key (empno), "
++ " unique key (workdept, empno) "
++ ") default charset=latin1 collate=latin1_bin";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "insert into t1 values "
++ "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000),"
++ "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), "
++ "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), "
++ "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
++ "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), "
++ "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), "
++ "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), "
++ "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), "
++ "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), "
++ "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), "
++ "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), "
++ "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), "
++ "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), "
++ "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), "
++ "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), "
++ "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), "
++ "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), "
++ "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), "
++ "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), "
++ "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), "
++ "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), "
++ "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), "
++ "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), "
++ "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), "
++ "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), "
++ "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), "
++ "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), "
++ "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), "
++ "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), "
++ "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), "
++ "(330, 'WING', '', 'LEE', 'E21', 25370, 500), "
++ "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)";
++
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "create table t2 ("
++ " deptno varchar(6) not null, deptname varchar(20) not null,"
++ " mgrno int(11) not null, location varchar(20) not null,"
++ " admrdept varchar(6) not null, refcntd int(11) not null,"
++ " refcntu int(11) not null, primary key (deptno)"
++ ") default charset=latin1 collate=latin1_bin";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "insert into t2 values "
++ "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), "
++ "('B01', 'PLANNING', 20, '', 'A00', 0, 0), "
++ "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), "
++ "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0),"
++ "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), "
++ "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), "
++ "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), "
++ "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), "
++ "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "select t1.empno, t1.workdept "
++ "from (t1 left join t2 on t2.deptno = t1.workdept) "
++ "where t2.deptno in "
++ " (select t2.deptno "
++ " from (t1 left join t2 on t2.deptno = t1.workdept) "
++ " where t1.empno = ?) "
++ "order by 1";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ check_stmt_rc(rc, stmt);
++
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= &empno;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[1].buffer= (void*) workdept;
++ my_bind[1].buffer_length= sizeof(workdept);
++ my_bind[1].length= &workdept_len;
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ empno= 10;
++
++ /* ERROR: next statement causes a server crash */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#11904: mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY grouping wrong result */
++
++static int test_bug11904(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt1;
++ int rc;
++ const char *stmt_text;
++ const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
++ MYSQL_BIND my_bind[2];
++ int country_id=0;
++ char row_data[11]= {0};
++
++ /* create tables */
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug11904b");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE bug11904b (id int, name char(10), primary key(id, name))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO bug11904b VALUES (1, 'sofia'), (1,'plovdiv'),"
++ " (1,'varna'), (2,'LA'), (2,'new york'), (3,'heidelberg'),"
++ " (3,'berlin'), (3, 'frankfurt')");
++
++ check_mysql_rc(rc, mysql);
++ mysql_commit(mysql);
++ /* create statement */
++ stmt1= mysql_stmt_init(mysql);
++ mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++
++ stmt_text= "SELECT id, MIN(name) FROM bug11904b GROUP BY id ORDER BY id";
++
++ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt1);
++
++ memset(my_bind, 0, sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer=& country_id;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].length= 0;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer=& row_data;
++ my_bind[1].buffer_length= sizeof(row_data) - 1;
++ my_bind[1].length= 0;
++
++ rc= mysql_stmt_bind_result(stmt1, my_bind);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++ FAIL_UNLESS(country_id == 1, "country_id != 1");
++ FAIL_UNLESS(memcmp(row_data, "plovdiv", 7) == 0, "row_data != 'plovdiv'");
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++ FAIL_UNLESS(country_id == 2, "country_id != 2");
++ FAIL_UNLESS(memcmp(row_data, "LA", 2) == 0, "row_data != 'LA'");
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++ FAIL_UNLESS(country_id == 3, "country_id != 3");
++ FAIL_UNLESS(memcmp(row_data, "berlin", 6) == 0, "row_data != 'Berlin'");
++
++ rc= mysql_stmt_close(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_query(mysql, "drop table bug11904b");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++/* Bug#12243: multiple cursors, crash in a fetch after commit. */
++
++static int test_bug12243(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt1, *stmt2;
++ int rc;
++ const char *stmt_text;
++ ulong type;
++
++ if (!check_variable(mysql, "@@have_innodb", "YES"))
++ {
++ diag("Skip -> Test required InnoDB");
++ return SKIP;
++ }
++
++ /* create tables */
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (a int) engine=InnoDB");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)");
++ check_mysql_rc(rc, mysql);
++ mysql_autocommit(mysql, FALSE);
++ /* create statement */
++ stmt1= mysql_stmt_init(mysql);
++ stmt2= mysql_stmt_init(mysql);
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ check_stmt_rc(rc, stmt1);
++
++ stmt_text= "select a from t1";
++
++ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt2);
++ rc= mysql_stmt_execute(stmt2);
++ check_stmt_rc(rc, stmt2);
++ rc= mysql_stmt_fetch(stmt2);
++ check_stmt_rc(rc, stmt2);
++
++ rc= mysql_stmt_close(stmt1);
++ check_stmt_rc(rc, stmt1);
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++ rc= mysql_stmt_fetch(stmt2);
++ check_stmt_rc(rc, stmt2);
++
++ mysql_stmt_close(stmt2);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ mysql_autocommit(mysql, TRUE); /* restore default */
++
++ return OK;
++}
++
++/* Bug#11909: wrong metadata if fetching from two cursors */
++
++static int test_bug11909(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt1, *stmt2;
++ MYSQL_BIND my_bind[7];
++ int rc;
++ char firstname[20], midinit[20], lastname[20], workdept[20];
++ ulong firstname_len, midinit_len, lastname_len, workdept_len;
++ uint32 empno;
++ double salary;
++ float bonus;
++ const char *stmt_text;
++ const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
++
++
++ stmt_text= "drop table if exists t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "create table t1 ("
++ " empno int(11) not null, firstname varchar(20) not null,"
++ " midinit varchar(20) not null, lastname varchar(20) not null,"
++ " workdept varchar(6) not null, salary double not null,"
++ " bonus float not null, primary key (empno)"
++ ") default charset=latin1 collate=latin1_bin";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "insert into t1 values "
++ "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), "
++ "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800),"
++ "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800),"
++ "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
++ "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ /* ****** Begin of trace ****** */
++
++ stmt_text= "SELECT empno, firstname, midinit, lastname,"
++ "workdept, salary, bonus FROM t1 ORDER BY empno";
++ stmt1= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt1, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt1);
++ mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE,
++ (const void*) &type);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void*) &empno;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[1].buffer= (void*) firstname;
++ my_bind[1].buffer_length= sizeof(firstname);
++ my_bind[1].length= &firstname_len;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[2].buffer= (void*) midinit;
++ my_bind[2].buffer_length= sizeof(midinit);
++ my_bind[2].length= &midinit_len;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[3].buffer= (void*) lastname;
++ my_bind[3].buffer_length= sizeof(lastname);
++ my_bind[3].length= &lastname_len;
++
++ my_bind[4].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[4].buffer= (void*) workdept;
++ my_bind[4].buffer_length= sizeof(workdept);
++ my_bind[4].length= &workdept_len;
++
++ my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[5].buffer= (void*) &salary;
++
++ my_bind[6].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[6].buffer= (void*) &bonus;
++ rc= mysql_stmt_bind_result(stmt1, my_bind);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ FAIL_UNLESS(empno == 10, "empno != 10");
++ FAIL_UNLESS(strcmp(firstname, "CHRISTINE""") == 0, "firstname != 'Christine'");
++ FAIL_UNLESS(strcmp(midinit, "I""") == 0, "");
++ FAIL_UNLESS(strcmp(lastname, "HAAS""") == 0, "lastname != 'HAAS'");
++ FAIL_UNLESS(strcmp(workdept, "A00""") == 0, "workdept != 'A00'");
++ FAIL_UNLESS(salary == (double) 52750.0, "salary != 52750");
++ FAIL_UNLESS(bonus == (float) 1000.0, "bonus =! 1000");
++
++ stmt_text = "SELECT empno, firstname FROM t1";
++ stmt2= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt2, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt2);
++ mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE,
++ (const void*) &type);
++ rc= mysql_stmt_bind_result(stmt2, my_bind);
++ check_stmt_rc(rc, stmt2);
++
++ rc= mysql_stmt_execute(stmt2);
++ check_stmt_rc(rc, stmt2);
++
++ rc= mysql_stmt_fetch(stmt2);
++ FAIL_UNLESS(rc == 0, "rc != 0")
++
++ FAIL_UNLESS(empno == 10, "empno != 10");
++ FAIL_UNLESS(strcmp(firstname, "CHRISTINE""") == 0, "firstname != 'Christine'");
++
++ rc= mysql_stmt_reset(stmt2);
++ check_stmt_rc(rc, stmt2);
++
++ /* ERROR: next statement should return 0 */
++
++ rc= mysql_stmt_fetch(stmt1);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++
++ mysql_stmt_close(stmt1);
++ mysql_stmt_close(stmt2);
++ rc= mysql_rollback(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#13488: wrong column metadata when fetching from cursor */
++
++static int test_bug13488(MYSQL *mysql)
++{
++ MYSQL_BIND my_bind[3];
++ MYSQL_STMT *stmt1;
++ int rc, f1, f2, f3, i;
++ const ulong type= CURSOR_TYPE_READ_ONLY;
++ const char *query= "select f1, f2, f3 from t1 left join t2 on f1=f2 where f1=1";
++
++
++ rc= mysql_query(mysql, "drop table if exists t1, t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (f1 int not null primary key)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t2 (f2 int not null primary key, "
++ "f3 int not null)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1), (2)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (1,2), (2,4)");
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, 0, sizeof(my_bind));
++ for (i= 0; i < 3; i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[i].buffer_length= 4;
++ my_bind[i].length= 0;
++ }
++ my_bind[0].buffer=&f1;
++ my_bind[1].buffer=&f2;
++ my_bind[2].buffer=&f3;
++
++ stmt1= mysql_stmt_init(mysql);
++ rc= mysql_stmt_attr_set(stmt1,STMT_ATTR_CURSOR_TYPE, (const void *)&type);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_prepare(stmt1, query, strlen(query));
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_bind_result(stmt1, my_bind);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_free_result(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_reset(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_close(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_UNLESS(f1 == 1, "f1 != 1");
++ FAIL_UNLESS(f2 == 1, "f2 != 1");
++ FAIL_UNLESS(f3 == 2, "f3 != 2");
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug#13524: warnings of a previous command are not reset when fetching
++ from a cursor.
++*/
++
++static int test_bug13524(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ unsigned int warning_count;
++ const ulong type= CURSOR_TYPE_READ_ONLY;
++ const char *query= "select * from t1";
++
++
++ rc= mysql_query(mysql, "drop table if exists t1, t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (a int not null primary key)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ warning_count= mysql_warning_count(mysql);
++ FAIL_UNLESS(warning_count == 0, "warning_count != 0");
++
++ /* Check that DROP TABLE produced a warning (no such table) */
++ rc= mysql_query(mysql, "drop table if exists t2");
++ check_mysql_rc(rc, mysql);
++ warning_count= mysql_warning_count(mysql);
++ FAIL_UNLESS(warning_count == 1, "warning_count != 1");
++
++ /*
++ Check that fetch from a cursor cleared the warning from the previous
++ command.
++ */
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ warning_count= mysql_warning_count(mysql);
++ FAIL_UNLESS(warning_count == 0, "warning_count != 0");
++
++ /* Cleanup */
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0"
++*/
++
++static int test_bug14845(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const ulong type= CURSOR_TYPE_READ_ONLY;
++ const char *query= "select count(*) from t1 where 1 = 0";
++
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (id int(11) default null, "
++ "name varchar(20) default null)"
++ "engine=MyISAM DEFAULT CHARSET=utf8");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1,'abc'),(2,'def')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
++
++ /* Cleanup */
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/*
++ Bug#14210 "Simple query with > operator on large table gives server
++ crash"
++*/
++
++static int test_bug14210(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *stmt_text;
++ ulong type;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ /*
++ To trigger the problem the table must be InnoDB, although the problem
++ itself is not InnoDB related. In case the table is MyISAM this test
++ is harmless.
++ */
++ rc= mysql_query(mysql, "create table t1 (a varchar(255)) engine=InnoDB");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 (a) values (repeat('a', 256))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "set @@session.max_heap_table_size=16384");
++
++ /* Create a big enough table (more than max_heap_table_size) */
++ for (i= 0; i < 8; i++)
++ {
++ rc= mysql_query(mysql, "insert into t1 (a) select a from t1");
++ check_mysql_rc(rc, mysql);
++ }
++ /* create statement */
++ stmt= mysql_stmt_init(mysql);
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
++
++ stmt_text= "select a from t1";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ while ((rc= mysql_stmt_fetch(stmt)) == 0);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "set @@session.max_heap_table_size=default");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug#24179 "select b into $var" fails with --cursor_protocol"
++ The failure is correct, check that the returned message is meaningful.
++*/
++
++static int test_bug24179(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++
++ stmt= open_cursor(mysql, "select 1 into @a");
++ rc= mysql_stmt_execute(stmt);
++ FAIL_UNLESS(rc, "Error expected");
++ FAIL_UNLESS(mysql_stmt_errno(stmt) == 1323, "stmt_errno != 1323");
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/**
++ Bug#32265 Server returns different metadata if prepared statement is used
++*/
++
++static int test_bug32265(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ MYSQL_FIELD *field;
++ MYSQL_RES *metadata;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1");
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1");
++ check_mysql_rc(rc, mysql);
++
++ stmt= open_cursor(mysql, "SELECT * FROM t1");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_field(metadata);
++ FAIL_UNLESS(field, "couldn't fetch field");
++ FAIL_UNLESS(strcmp(field->table, "t1") == 0, "table != t1");
++ FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
++ FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
++ mysql_free_result(metadata);
++ mysql_stmt_close(stmt);
++
++ stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_field(metadata);
++ FAIL_UNLESS(strcmp(field->table, "") == 0, "field != ''");
++ FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
++ FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
++ mysql_free_result(metadata);
++ mysql_stmt_close(stmt);
++
++ stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_field(metadata);
++ FAIL_UNLESS(strcmp(field->table, "") == 0, "table != ''");
++ FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
++ FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
++ mysql_free_result(metadata);
++ mysql_stmt_close(stmt);
++
++ stmt= open_cursor(mysql, "SELECT * FROM v1");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_field(metadata);
++ FAIL_UNLESS(strcmp(field->table, "v1") == 0, "table != v1");
++ FAIL_UNLESS(strcmp(field->org_table, "v1") == 0, "org_table != v1");
++ FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
++ mysql_free_result(metadata);
++ mysql_stmt_close(stmt);
++
++ stmt= open_cursor(mysql, "SELECT * FROM v1 /* SIC */ GROUP BY 1");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_field(metadata);
++ FAIL_UNLESS(strcmp(field->table, "v1") == 0, "table != v1");
++ FAIL_UNLESS(strcmp(field->org_table, "v1") == 0, "org_table != v1");
++ FAIL_UNLESS(strcmp(field->db, schema) == 0, "schema != db");
++ mysql_free_result(metadata);
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/**
++ Bug#38486 Crash when using cursor protocol
++*/
++
++static int test_bug38486(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ int rc;
++ unsigned long type= CURSOR_TYPE_READ_ONLY;
++
++ DBUG_ENTER("test_bug38486");
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "CREATE TABLE t1 (a INT)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "INSERT INTO t1 VALUES (1)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug8880(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt_list[2], **stmt;
++ MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2;
++ int rc;
++
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1,1)");
++ check_mysql_rc(rc, mysql);
++ /*
++ when inserting 2 rows everything works well
++ mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)");
++ */
++ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
++ *stmt= open_cursor(mysql, "select a from t1");
++ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
++ {
++ rc= mysql_stmt_execute(*stmt);
++ check_stmt_rc(rc, *stmt);
++ }
++ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
++ mysql_stmt_close(*stmt);
++ return OK;
++}
++
++static int test_bug9159(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *stmt_text= "select a, b from t1";
++ const unsigned long type= CURSOR_TYPE_READ_ONLY;
++
++
++ mysql_query(mysql, "drop table if exists t1");
++ mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
++ rc= mysql_query(mysql, "insert into t1 values (1,1)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type);
++
++ mysql_stmt_execute(stmt);
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/*
++ We can't have more than one cursor open for a prepared statement.
++ Test re-executions of a PS with cursor; mysql_stmt_reset must close
++ the cursor attached to the statement, if there is one.
++*/
++
++static int test_bug9478(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char a[6];
++ ulong a_len;
++ int rc, i;
++ DBUG_ENTER("test_bug9478");
++
++ mysql_query(mysql, "drop table if exists t1");
++ mysql_query(mysql, "create table t1 (id integer not null primary key, "
++ " name varchar(20) not null)");
++ rc= mysql_query(mysql, "insert into t1 (id, name) values "
++ " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= open_cursor(mysql, "select name from t1 where id=2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (char*) a;
++ my_bind[0].buffer_length= sizeof(a);
++ my_bind[0].length= &a_len;
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ for (i= 0; i < 5; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /*
++ The query above is a one-row result set. Therefore, there is no
++ cursor associated with it, as the server won't bother with opening
++ a cursor for a one-row result set. The first row was read from the
++ server in the fetch above. But there is eof packet pending in the
++ network. mysql_stmt_execute will flush the packet and successfully
++ execute the statement.
++ */
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ {
++ char buff[8];
++ /* Fill in the fetch packet */
++ int4store(buff, stmt->stmt_id);
++ buff[4]= 1; /* prefetch rows */
++/* rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
++ (uchar*) buff,
++ sizeof(buff), 0,0,1,NULL) ||
++ (*mysql->methods->read_query_result)(mysql)); */
++ FAIL_UNLESS(rc, "error expected");
++ }
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
+
+ /* mariadb client supports GEOMETRY, so no error will
+ be returned
- FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
+ */
- }
- rc= mysql_stmt_close(stmt);
- check_stmt_rc(rc, stmt);
-@@ -1831,8 +1839,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++ }
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* Test the case with a server side cursor */
++ stmt= open_cursor(mysql, "select name from t1");
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ for (i= 0; i < 5; i++)
++ {
++ DBUG_PRINT("loop",("i: %d", i));
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ while (! (rc= mysql_stmt_fetch(stmt)));
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
++ }
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Crash when opening a cursor to a query with DISTICNT and no key */
++
++static int test_bug9520(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char a[6];
++ ulong a_len;
++ int rc, row_count= 0;
++
++
++ mysql_query(mysql, "drop table if exists t1");
++ mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5),"
++ " primary key (a, b, c))");
++ rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), "
++ " ('a', 'b', 'c'), ('k', 'l', 'm')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= open_cursor(mysql, "select distinct b from t1");
++
++ /*
++ Not crashes with:
++ stmt= open_cursor(mysql, "select distinct a from t1");
++ */
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (char*) a;
++ my_bind[0].buffer_length= sizeof(a);
++ my_bind[0].length= &a_len;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ while (!(rc= mysql_stmt_fetch(stmt)))
++ row_count++;
++
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ FAIL_UNLESS(row_count == 3, "row_count != 3");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/*
++ Error message is returned for unsupported features.
++ Test also cursors with non-default PREFETCH_ROWS
++*/
++
++static int test_bug9643(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ int32 a;
++ int rc;
++ const char *stmt_text;
++ int num_rows= 0;
++ ulong type;
++ ulong prefetch_rows= 5;
++
++
++ mysql_query(mysql, "drop table if exists t1");
++ mysql_query(mysql, "create table t1 (id integer not null primary key)");
++ rc= mysql_query(mysql, "insert into t1 (id) values "
++ " (1), (2), (3), (4), (5), (6), (7), (8), (9)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ /* Not implemented in 5.0 */
++ type= (ulong) CURSOR_TYPE_SCROLLABLE;
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ FAIL_UNLESS(rc, "Error expected");
++
++ type= (ulong) CURSOR_TYPE_READ_ONLY;
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS,
++ (void*) &prefetch_rows);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "select * from t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void*) &a;
++ my_bind[0].buffer_length= sizeof(a);
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ while ((rc= mysql_stmt_fetch(stmt)) == 0)
++ ++num_rows;
++ FAIL_UNLESS(num_rows == 9, "num_rows != 9");
++
++ rc= mysql_stmt_close(stmt);
++ FAIL_UNLESS(rc == 0, "");
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++
++struct my_tests_st my_tests[] = {
++ {"test_basic_cursors", test_basic_cursors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_cursors_with_union", test_cursors_with_union, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_cursors_with_procedure", test_cursors_with_procedure, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug21206", test_bug21206, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug10729", test_bug10729, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug10736", test_bug10736, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug10794", test_bug10794, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug10760", test_bug10760, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11172", test_bug11172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11656", test_bug11656, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11901", test_bug11901, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11904", test_bug11904, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug12243", test_bug12243, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11909", test_bug11909, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug13488", test_bug13488, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug13524", test_bug13524, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug14845", test_bug14845, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug14210", test_bug14210, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug24179", test_bug24179, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug32265", test_bug32265, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug38486", test_bug38486, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug8880", test_bug8880, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug9159", test_bug9159, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug9478", test_bug9478, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug9520", test_bug9520, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug9643", test_bug9643, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/errors.c'
---- mariadb/unittest/libmysql/errors.c 2012-11-26 10:23:56 +0000
-+++ mariadb/unittest/libmariadb/errors.c 2013-03-14 21:01:43 +0000
-@@ -271,8 +271,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/data.csv mariadb-native-client.trunk/unittest/libmariadb/data.csv
+--- mariadb/unittest/libmariadb/data.csv 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/data.csv 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,100 @@
++00000100,1,60000.000000
++00000101,2,60000.000000
++00000102,3,60000.000000
++00000103,1,60000.000000
++00000104,2,60000.000000
++00000105,3,60000.000000
++00000106,1,60000.000000
++00000107,2,60000.000000
++00000108,3,60000.000000
++00000109,1,60000.000000
++00000110,2,60000.000000
++00000111,3,60000.000000
++00000112,1,60000.000000
++00000113,2,60000.000000
++00000114,3,60000.000000
++00000115,1,60000.000000
++00000116,2,60000.000000
++00000117,3,60000.000000
++00000118,1,60000.000000
++00000119,2,60000.000000
++00000120,3,60000.000000
++00000121,1,60000.000000
++00000122,2,60000.000000
++00000123,3,60000.000000
++00000124,1,60000.000000
++00000125,2,60000.000000
++00000126,3,60000.000000
++00000127,1,60000.000000
++00000128,2,60000.000000
++00000129,3,60000.000000
++00000130,1,60000.000000
++00000131,2,60000.000000
++00000132,3,60000.000000
++00000133,1,60000.000000
++00000134,2,60000.000000
++00000135,3,60000.000000
++00000136,1,60000.000000
++00000137,2,60000.000000
++00000138,3,60000.000000
++00000139,1,60000.000000
++00000140,2,60000.000000
++00000141,3,60000.000000
++00000142,1,60000.000000
++00000143,2,60000.000000
++00000144,3,60000.000000
++00000145,1,60000.000000
++00000146,2,60000.000000
++00000147,3,60000.000000
++00000148,1,60000.000000
++00000149,2,60000.000000
++00000150,3,60000.000000
++00000151,1,60000.000000
++00000152,2,60000.000000
++00000153,3,60000.000000
++00000154,1,60000.000000
++00000155,2,60000.000000
++00000156,3,60000.000000
++00000157,1,60000.000000
++00000158,2,60000.000000
++00000159,3,60000.000000
++00000160,1,60000.000000
++00000161,2,60000.000000
++00000162,3,60000.000000
++00000163,1,60000.000000
++00000164,2,60000.000000
++00000165,3,60000.000000
++00000166,1,60000.000000
++00000167,2,60000.000000
++00000168,3,60000.000000
++00000169,1,60000.000000
++00000170,2,60000.000000
++00000171,3,60000.000000
++00000172,1,60000.000000
++00000173,2,60000.000000
++00000174,3,60000.000000
++00000175,1,60000.000000
++00000176,2,60000.000000
++00000177,3,60000.000000
++00000178,1,60000.000000
++00000179,2,60000.000000
++00000180,3,60000.000000
++00000181,1,60000.000000
++00000182,2,60000.000000
++00000183,3,60000.000000
++00000184,1,60000.000000
++00000185,2,60000.000000
++00000186,3,60000.000000
++00000187,1,60000.000000
++00000188,2,60000.000000
++00000189,3,60000.000000
++00000190,1,60000.000000
++00000191,2,60000.000000
++00000192,3,60000.000000
++00000193,1,60000.000000
++00000194,2,60000.000000
++00000195,3,60000.000000
++00000196,1,60000.000000
++00000197,2,60000.000000
++00000198,3,60000.000000
++00000199,1,60000.000000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/dyncol.c mariadb-native-client.trunk/unittest/libmariadb/dyncol.c
+--- mariadb/unittest/libmariadb/dyncol.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/dyncol.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,271 @@
++/*
++Copyright (c) 2013 Monty Program AB. All rights reserved.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++
++#include "my_test.h"
++#include "ma_dyncol.h"
++
++static int create_dyncol_named(MYSQL *mysql)
++{
++ DYNAMIC_COLUMN dyncol;
++ DYNAMIC_COLUMN_VALUE *vals;
++ uint i, column_count= 6;
++ int rc;
++ char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5", "Val6"};
++ MYSQL_LEX_STRING keys1[]= {{"key1", 4}, {"key2", 4}, {"key3", 4}, {"key4", 4}, {"key5", 4}, {"key6", 4}},
++ keys2[]= {{"key1", 4}, {"key1", 4}, {"key3", 4}, {"key4", 4}, {"key5", 4}, {"key6", 4}},
++ keys3[]= {{"\x70\x61\x72\x61\x00\x30", 6}, {"\x70\x61\x72\x61\x00\x31", 6}, {"\x70\x61\x72\x61\x00\x32", 6},
++ {"\x70\x61\x72\x61\x00\x33", 6}, {"\x70\x61\x72\x61\x00\x34", 6}, {"\x70\x61\x72\x61\x00\x35", 6}};
++ MYSQL_LEX_STRING *my_keys;
++ uint my_count;
++
++ vals= (DYNAMIC_COLUMN_VALUE *)malloc(column_count * sizeof(DYNAMIC_COLUMN_VALUE));
++
++ for (i=0; i < column_count; i++)
++ {
++ vals[i].type= DYN_COL_STRING;
++ vals[i].x.string.value.str= strval[i];
++ vals[i].x.string.value.length= strlen(strval[i]);
++ vals[i].x.string.charset= (CHARSET_INFO *)mysql->charset;
++ diag("%s", keys3[i].str);
++ }
++
++ mariadb_dyncol_init(&dyncol);
++ rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys1, vals, 0);
++ FAIL_IF(mariadb_dyncol_create_many_named(&dyncol, column_count, keys1, vals, 1) < 0, "Error");
++ column_count= 0;
++ FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
++
++ FAIL_IF(column_count != 6, "6 columns expected");
++ mariadb_dyncol_free(&dyncol);
++
++ rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys3, vals, 1);
++ if (rc < 0) {
++ diag("Error!!: %d", rc);
++ return FAIL;
++ }
++ column_count= 0;
++ FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
++
++ FAIL_IF(column_count != 6, "6 columns expected");
++
++ mariadb_dyncol_free(&dyncol);
++
++ /* Now try to add a duplicate key */
++
++ FAIL_IF(mariadb_dyncol_create_many_named(&dyncol, column_count, keys2, vals, 1) >=0, "Error expected");
++ mariadb_dyncol_free(&dyncol);
++
++ /* binary keys */
++ rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys3, vals, 1);
++ FAIL_IF(rc < 0, "binary keys failed");
++
++ /* get keys*/
++ rc= mariadb_dyncol_list_named(&dyncol, &my_count, &my_keys);
++ FAIL_IF(rc < 0, "list named failed");
++
++ for (i=0; i < my_count; i++)
++ {
++ if (memcmp(my_keys[i].str, keys3[i].str, keys3[i].length) != 0)
++ diag("error key %d", i);
++ vals[i].type=DYN_COL_NULL;
++ }
++ rc= mariadb_dyncol_update_many_named(&dyncol, column_count, keys3, vals);
++ FAIL_IF(rc < 0, "update failed");
++ mariadb_dyncol_free(&dyncol);
++
++ keys3[0].str= "test";
++ for (i=0; i < column_count; i++)
++ diag("%s", my_keys[i].str);
++
++ free(vals);
++ free(my_keys);
++ return OK;
++}
++
++static int mdev_4994(MYSQL *mysql)
++{
++ DYNAMIC_COLUMN dyncol;
++ uint key= 1;
++ DYNAMIC_COLUMN_VALUE val;
++ int rc;
++
++
++ val.type= DYN_COL_NULL;
++
++ mariadb_dyncol_init(&dyncol);
++ rc= mariadb_dyncol_create_many_num(&dyncol, 1, &key, &val, 0);
++ FAIL_IF(rc < 0, "Unexpected error");
++ return OK;
++}
++
++static int create_dyncol_num(MYSQL *mysql)
++{
++ DYNAMIC_COLUMN dyncol;
++ DYNAMIC_COLUMN_VALUE vals[5];
++ uint i, column_count= 5;
++ uint my_count;
++ MYSQL_LEX_STRING *my_keys;
++ DYNAMIC_COLUMN_VALUE *my_vals;
++ int rc;
++ char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5"};
++
++ uint keys1[5]= {1,2,3,4,5},
++ keys2[5]= {1,2,2,4,5};
++ MYSQL_LEX_STRING key1= {"1",1};
++
++ for (i=0; i < column_count; i++)
++ {
++ vals[i].type= DYN_COL_STRING;
++ vals[i].x.string.value.str= strval[i];
++ vals[i].x.string.value.length= strlen(strval[i]);
++ vals[i].x.string.charset= (CHARSET_INFO *)mysql->charset;
++ }
++ FAIL_IF(mariadb_dyncol_create_many_num(&dyncol, column_count, keys1, vals, 1) <0, "Error (keys1)");
++
++ vals[0].x.string.value.str= strval[1];
++ rc= mariadb_dyncol_update_many_named(&dyncol,1, &key1, vals);
++ diag("update: %d", rc);
++
++ rc= mariadb_dyncol_unpack(&dyncol, &my_count, &my_keys, &my_vals);
++ diag("unpack: %d %d", rc, my_count);
++
++ diag("---------------__");
++ for(i=0; i < 5; i++)
++ {
++ diag("%s %d", my_keys[i].str, my_keys[i].length);
++ }
++ free(my_keys);
++ free(my_vals);
++
++ FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
++ FAIL_IF(column_count != 5, "5 columns expected");
++ mariadb_dyncol_free(&dyncol);
++ FAIL_IF(mariadb_dyncol_create_many_num(&dyncol, column_count, keys2, vals, 1) >=0, "Error expected (keys2)");
++ mariadb_dyncol_free(&dyncol);
++ return OK;
++}
++
++static int mdev_x1(MYSQL *mysql)
++{
++ int rc;
++ uint i;
++ uint num_keys[5]= {1,2,3,4,5};
++ char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5"};
++ DYNAMIC_COLUMN_VALUE vals[5];
++ DYNAMIC_COLUMN dynstr;
++ MYSQL_LEX_STRING my_key= {"1", 2};
++ uint unpack_columns;
++ MYSQL_LEX_STRING *unpack_keys;
++ DYNAMIC_COLUMN_VALUE *unpack_vals;
++
++ for (i=0; i < 5; i++)
++ {
++ vals[i].type= DYN_COL_STRING;
++ vals[i].x.string.value.str= strval[i];
++ vals[i].x.string.value.length= strlen(strval[i]);
++ vals[i].x.string.charset= (CHARSET_INFO *)mysql->charset;
++ }
++
++ mariadb_dyncol_init(&dynstr);
++
++ /* create numeric */
++ rc= mariadb_dyncol_create_many_num(&dynstr, 5, num_keys, vals, 1);
++ if (rc < 0)
++ {
++ diag("Error: %d", rc);
++ return FAIL;
++ }
++
++ /* unpack and print values */
++ rc= mariadb_dyncol_unpack(&dynstr, &unpack_columns, &unpack_keys, &unpack_vals);
++ if (rc < 0)
++ {
++ diag("Error: %d", rc);
++ return FAIL;
++ }
++
++ for (i=0; i < unpack_columns; i++)
++ if (memcmp(unpack_vals[i].x.string.value.str, vals[i].x.string.value.str, vals[i].x.string.value.length))
++ printf("Error1: key: %1s val: %s %s\n", unpack_keys[i].str, unpack_vals[i].x.string.value.str, vals[i].x.string.value.str);
++
++ free(unpack_keys);
++ free(unpack_vals);
++
++ /* change one value and update with named key */
++/* vals[0].x.string.value.str= strval[1]; */
++ rc= mariadb_dyncol_update_many_named(&dynstr, 1, &my_key, vals);
++ if (rc < 0)
++ {
++ diag("Error: %d", rc);
++ return FAIL;
++ }
++
++ /* unpack and print values */
++ rc= mariadb_dyncol_unpack(&dynstr, &unpack_columns, &unpack_keys, &unpack_vals);
++ if (rc < 0)
++ {
++ diag("Error: %d", rc);
++ return FAIL;
++ }
++ diag("Columns: %d", unpack_columns);
++
++ for (i=0; i < unpack_columns; i++)
++ diag("Key: %s Len: %d", unpack_keys[i].str, unpack_keys[i].length);
++
++
++ free(unpack_keys);
++ free(unpack_vals);
++
++ mariadb_dyncol_free(&dynstr);
++ return OK;
++}
++
++static int dyncol_column_count(MYSQL *mysql)
++{
++ DYNAMIC_COLUMN dyncol;
++ uint column_count= 5;
++ int rc;
++
++ mariadb_dyncol_init(&dyncol); /* memset(&dyncol, 0, sizeof(DYNAMIC_COLUMN)) */
++ rc= mariadb_dyncol_column_count(&dyncol, &column_count);
++ diag("rc=%d", rc);
++ FAIL_IF(rc < 0, "unexpected error");
++ FAIL_IF(column_count > 0, "Expected column_count=0");
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"mdev_x1", mdev_x1, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"mdev_4994", mdev_4994, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"create_dyncol_named", create_dyncol_named, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"create_dyncol_num", create_dyncol_num, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"dyncol_column_count", dyncol_column_count, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, 0}
++};
++
++
++int main(int argc, char **argv)
++{
++ if (argc > 1)
++ get_options(argc, argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/errors.c mariadb-native-client.trunk/unittest/libmariadb/errors.c
+--- mariadb/unittest/libmariadb/errors.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/errors.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,282 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++/* Test warnings */
++
++static int test_client_warnings(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
++
++ return OK;
++}
++
++
++static int test_ps_client_warnings(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ char *query= "DROP TABLE IF EXISTS test_non_exists";
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(rc, mysql_stmt_error(stmt));
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(rc, mysql_stmt_error(stmt));
++
++ FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_server_warnings(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SHOW WARNINGS");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, mysql_error(mysql));
++ FAIL_IF(!mysql_num_rows(result), "Empty resultset");
++
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++/* Test errors */
++
++static int test_client_errors(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE test_non_exists");
++ FAIL_IF(!rc, "Error expected");
++
++ FAIL_IF(!mysql_errno(mysql), "Error expected");
++ FAIL_IF(!strlen(mysql_error(mysql)), "Empty errormsg");
++ FAIL_IF(strcmp(mysql_sqlstate(mysql), "00000") == 0, "Invalid SQLstate");
++
++ return OK;
++}
++
++static int test_ps_client_errors(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ char *query= "DROP TABLE test_non_exists";
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(rc, mysql_stmt_error(stmt));
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, mysql_stmt_error(stmt));
++
++ FAIL_IF(!mysql_stmt_errno(stmt), "Error expected");
++ FAIL_IF(!strlen(mysql_stmt_error(stmt)), "Empty errormsg");
++ FAIL_IF(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Invalid SQLstate");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_server_errors(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++ rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE test_non_exists");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SHOW ERRORS");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, mysql_error(mysql));
++ FAIL_IF(!mysql_num_rows(result), "Empty resultset");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++/* Bug #16143: mysql_stmt_sqlstate returns an empty string instead of '00000' */
++
++static int test_bug16143(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ /* Check mysql_stmt_sqlstate return "no error" */
++ FAIL_UNLESS(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Expected SQLstate 000000");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/* Test warnings for cuted rows */
++
++static int test_cuted_rows(MYSQL *mysql)
++{
++ int rc, count;
++ MYSQL_RES *result;
++
++
++ mysql_query(mysql, "DROP TABLE if exists t1");
++ mysql_query(mysql, "DROP TABLE if exists t2");
++
++ rc= mysql_query(mysql, "CREATE TABLE t1(c1 tinyint)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t2(c1 int not null)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 values(10), (NULL), (NULL)");
++ check_mysql_rc(rc, mysql);
++
++ count= mysql_warning_count(mysql);
++ FAIL_UNLESS(count == 0, "warnings != 0");
++
++ rc= mysql_query(mysql, "INSERT INTO t2 SELECT * FROM t1");
++ check_mysql_rc(rc, mysql);
++
++ count= mysql_warning_count(mysql);
++ FAIL_UNLESS(count == 2, "warnings != 2");
++
++ rc= mysql_query(mysql, "SHOW WARNINGS");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 2, "rowcount != 2");
++ mysql_free_result(result);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES('junk'), (876789)");
++ check_mysql_rc(rc, mysql);
++
++ count= mysql_warning_count(mysql);
++ FAIL_UNLESS(count == 2, "warnings != 2");
++
++ rc= mysql_query(mysql, "SHOW WARNINGS");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 2, "rowcount != 2");
++ mysql_free_result(result);
++ return OK;
++}
++
++static int test_parse_error_and_bad_length(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++
++ /* check that we get 4 syntax errors over the 4 calls */
++
++ rc= mysql_query(mysql, "SHOW DATABAAAA");
++ FAIL_UNLESS(rc, "Error expected");
++ rc= mysql_real_query(mysql, "SHOW DATABASES", 100);
++ FAIL_UNLESS(rc, "Error expected");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SHOW DATABAAAA", strlen("SHOW DATABAAAA"));
++ FAIL_IF(!rc, "Error expected");
++ mysql_stmt_close(stmt);
++ stmt= mysql_stmt_init(mysql);
++ FAIL_UNLESS(stmt, "");
++ rc= mysql_stmt_prepare(stmt, "SHOW DATABASES", 100);
++ FAIL_IF(!rc, "Error expected");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++struct my_tests_st my_tests[] = {
++ {"test_client_warnings", test_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ps_client_warnings", test_ps_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_server_warnings", test_server_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_client_errors", test_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ps_client_errors", test_ps_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_server_errors", test_server_errors, TEST_CONNECTION_DEFAULT, 0, NULL , "Open bug: #42364"},
++ {"test_bug16143", test_bug16143, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_cuted_rows", test_cuted_rows, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_parse_error_and_bad_length", test_parse_error_and_bad_length, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/fetch.c'
---- mariadb/unittest/libmysql/fetch.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/fetch.c 2013-03-14 21:01:43 +0000
-@@ -893,8 +893,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/fetch.c mariadb-native-client.trunk/unittest/libmariadb/fetch.c
+--- mariadb/unittest/libmariadb/fetch.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/fetch.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,901 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++/* Generalized fetch conversion routine for all basic types */
++
++static int bind_fetch(MYSQL *mysql, int row_count)
++{
++ MYSQL_STMT *stmt;
++ int rc, i, count= row_count;
++ int32 data[10];
++ int8 i8_data;
++ int16 i16_data;
++ long i32_data;
++ longlong i64_data;
++ float f_data;
++ double d_data;
++ char s_data[10];
++ ulong length[10];
++ MYSQL_BIND my_bind[7];
++ my_bool is_null[7];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ strcpy(query, "INSERT INTO test_bind_fetch VALUES (?, ?, ?, ?, ?, ?, ?)");
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc,stmt);
++
++ FAIL_UNLESS(mysql_stmt_param_count(stmt) == 7, "ParamCount != 7");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[i].buffer= (void *) &data[i];
++ }
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc,stmt);
++
++ while (count--)
++ {
++ rc= 10+count;
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ data[i]= rc+i;
++ rc+= 12;
++ }
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++ }
++
++ rc= mysql_commit(mysql);
++ check_stmt_rc(rc,stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= my_stmt_result(mysql, "SELECT * FROM test_bind_fetch");
++ FAIL_UNLESS(row_count == rc, "Wrong number of rows");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ strcpy(query, "SELECT * FROM test_bind_fetch");
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc,stmt);
++
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].buffer= (void *) &data[i];
++ my_bind[i].length= &length[i];
++ my_bind[i].is_null= &is_null[i];
++ }
++
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&i8_data;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[1].buffer= (void *)&i16_data;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[2].buffer= (void *)&i32_data;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[3].buffer= (void *)&i64_data;
++
++ my_bind[4].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[4].buffer= (void *)&f_data;
++
++ my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[5].buffer= (void *)&d_data;
++
++ my_bind[6].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[6].buffer= (void *)&s_data;
++ my_bind[6].buffer_length= sizeof(s_data);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc,stmt);
++
++ while (row_count--)
++ {
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= 10+row_count;
++
++ /* TINY */
++ FAIL_UNLESS((int) i8_data == rc, "Invalid value for i8_data");
++ FAIL_UNLESS(length[0] == 1, "Invalid length");
++ rc+= 13;
++
++ /* SHORT */
++ FAIL_UNLESS((int) i16_data == rc, "Invalid value for i16_data");
++ FAIL_UNLESS(length[1] == 2, "Invalid length");
++ rc+= 13;
++
++ /* LONG */
++ FAIL_UNLESS((int) i32_data == rc, "Invalid value for i32_data");
++ FAIL_UNLESS(length[2] == 4, "Invalid length");
++ rc+= 13;
++
++ /* LONGLONG */
++ FAIL_UNLESS((int) i64_data == rc, "Invalid value for i64_data");
++ FAIL_UNLESS(length[3] == 8, "Invalid length");
++ rc+= 13;
++
++ /* FLOAT */
++ FAIL_UNLESS((int)f_data == rc, "Invalid value for f_data");
++ FAIL_UNLESS(length[4] == 4, "Invalid length");
++ rc+= 13;
++
++ /* DOUBLE */
++ FAIL_UNLESS((int)d_data == rc, "Invalid value for d_data");
++ FAIL_UNLESS(length[5] == 8, "Invalid length");
++ rc+= 13;
++
++ /* CHAR */
++ {
++ char buff[20];
++ long len= sprintf(buff, "%d", rc);
++ FAIL_UNLESS(strcmp(s_data, buff) == 0, "Invalid value for s_data");
++ FAIL_UNLESS(length[6] == (ulong) len, "Invalid length");
++ }
++ }
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++static int test_fetch_seek(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[3];
++ MYSQL_ROW_OFFSET row;
++ int rc;
++ int32 c1;
++ char c2[11], c3[20];
++ char *query = "SELECT * FROM t1";
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10), c3 timestamp)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql'), ('open'), ('source')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc,stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&c1;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)c2;
++ my_bind[1].buffer_length= sizeof(c2);
++
++ my_bind[2]= my_bind[1];
++ my_bind[2].buffer= (void *)c3;
++ my_bind[2].buffer_length= sizeof(c3);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc,stmt);
++
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ row= mysql_stmt_row_tell(stmt);
++
++ row= mysql_stmt_row_seek(stmt, row);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ row= mysql_stmt_row_seek(stmt, row);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ mysql_stmt_data_seek(stmt, 0);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Test mysql_stmt_fetch_column() with offset */
++
++static int test_fetch_offset(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char data[11];
++ ulong length;
++ int rc;
++ my_bool is_null;
++ char *query = "SELECT * FROM t1";
++
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1(a char(10))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values('abcdefghij'), (null)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, query, (unsigned long)strlen(query));
++ check_stmt_rc(rc,stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)data;
++ my_bind[0].buffer_length= 11;
++ my_bind[0].is_null= &is_null;
++ my_bind[0].length= &length;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ data[0]= '\0';
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc,stmt);
++
++
++ FAIL_IF(!(strncmp(data, "abcd", 4) == 0 && length == 10), "Wrong value");
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 5);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strncmp(data, "fg", 2) == 0 && length == 10), "Wrong value");
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 9);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strncmp(data, "j", 1) == 0 && length == 10), "Wrong value");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ is_null= 0;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc,stmt);
++
++ FAIL_IF(is_null != 1, "Null flag not set");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Test mysql_stmt_fetch_column() */
++
++static int test_fetch_column(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ char c2[20], bc2[20];
++ ulong l1, l2, bl1, bl2;
++ int rc, c1, bc1;
++ char *query= "SELECT * FROM t1 ORDER BY c2 DESC";
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc,stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&bc1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &bl1;
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)bc2;
++ my_bind[1].buffer_length= 7;
++ my_bind[1].is_null= 0;
++ my_bind[1].length= &bl2;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc,stmt);
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); /* No-op at this point */
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ c2[0]= '\0'; l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)c2;
++ my_bind[0].buffer_length= 7;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strncmp(c2, "venu", 4) == 0 && l2 == 4), "Expected c2='venu'");
++
++ c2[0]= '\0'; l2= 0;
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strcmp(c2, "venu") == 0 && l2 == 4), "Expected c2='venu'");
++
++ c1= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&c1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l1;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(c1 == 1 && l1 == 4), "Expected c1=1");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++
++ c2[0]= '\0'; l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)c2;
++ my_bind[0].buffer_length= 7;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strncmp(c2, "mysq", 4) == 0 && l2 == 5), "Expected c2='mysql'");
++
++ c2[0]= '\0'; l2= 0;
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(strcmp(c2, "mysql") == 0 && l2 == 5), "Expected c2='mysql'");
++
++ c1= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&c1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l1;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc,stmt);
++ FAIL_IF(!(c1 == 2 && l1 == 4), "Expected c2=2");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(rc!=MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Test fetch without prior bound buffers */
++
++static int test_fetch_nobuffs(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[4];
++ char str[4][50];
++ int rc;
++ char *query = "SELECT DATABASE(), CURRENT_USER(), \
++ CURRENT_DATE(), CURRENT_TIME()";
++
++ stmt = mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++
++ FAIL_IF(rc != 1, "Expected 1 row");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)str[0];
++ my_bind[0].buffer_length= sizeof(str[0]);
++ my_bind[1]= my_bind[2]= my_bind[3]= my_bind[0];
++ my_bind[1].buffer= (void *)str[1];
++ my_bind[2].buffer= (void *)str[2];
++ my_bind[3].buffer= (void *)str[3];
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ {
++ rc++;
++ }
++ FAIL_IF(rc != 1, "Expected 1 row");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/* Test fetch null */
++
++static int test_fetch_null(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ int i;
++ long nData= 0;
++ MYSQL_BIND my_bind[11];
++ ulong length[11];
++ my_bool is_null[11];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_fetch_null");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_fetch_null("
++ " col1 tinyint, col2 smallint, "
++ " col3 int, col4 bigint, "
++ " col5 float, col6 double, "
++ " col7 date, col8 time, "
++ " col9 varbinary(10), "
++ " col10 varchar(50), "
++ " col11 char(20))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_fetch_null (col11) "
++ "VALUES (1000), (88), (389789)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ FAIL_IF(rc, mysql_error(mysql));
++
++ /* fetch */
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[i].is_null= &is_null[i];
++ my_bind[i].length= &length[i];
++ }
++ my_bind[i-1].buffer= (void *)&nData; /* Last column is not null */
++
++ strcpy((char *)query , "SELECT * FROM test_fetch_null");
++
++ rc= my_stmt_result(mysql, query);
++ FAIL_UNLESS(rc == 3, "Exoected 3 rows");
++
++ stmt = mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ {
++ rc++;
++ for (i= 0; i < 10; i++)
++ {
++ FAIL_IF(!is_null[i], "Expected is_null");
++ }
++ FAIL_UNLESS(nData == 1000 || nData == 88 || nData == 389789, "Wrong value for nData");
++ FAIL_UNLESS(is_null[i] == 0, "Exoected !is_null");
++ FAIL_UNLESS(length[i] == 4, "Expected length=4");
++ }
++ FAIL_UNLESS(rc == 3, "Expected 3 rows");
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/* Test fetching of date, time and ts */
++
++static int test_fetch_date(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ uint i;
++ int rc;
++ long year;
++ char date[25], my_time[25], ts[25], ts_4[25], ts_6[20], dt[20];
++ ulong d_length, t_length, ts_length, ts4_length, ts6_length,
++ dt_length, y_length;
++ MYSQL_BIND my_bind[8];
++ my_bool is_null[8];
++ ulong length[8];
++ char *query= "SELECT * FROM test_bind_result";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 date, c2 time, \
++ c3 timestamp, \
++ c4 year, \
++ c5 datetime, \
++ c6 timestamp, \
++ c7 timestamp)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SET SQL_MODE=''");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES('2002-01-02', \
++ '12:49:00', \
++ '2002-01-02 17:46:59', \
++ 2010, \
++ '2010-07-10', \
++ '2020', '1999-12-29')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ FAIL_IF(rc, mysql_error(mysql));
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < array_elements(my_bind); i++)
++ {
++ my_bind[i].is_null= &is_null[i];
++ my_bind[i].length= &length[i];
++ }
++
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1]= my_bind[2]= my_bind[0];
++
++ my_bind[0].buffer= (void *)&date;
++ my_bind[0].buffer_length= sizeof(date);
++ my_bind[0].length= &d_length;
++
++ my_bind[1].buffer= (void *)&my_time;
++ my_bind[1].buffer_length= sizeof(my_time);
++ my_bind[1].length= &t_length;
++
++ my_bind[2].buffer= (void *)&ts;
++ my_bind[2].buffer_length= sizeof(ts);
++ my_bind[2].length= &ts_length;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[3].buffer= (void *)&year;
++ my_bind[3].length= &y_length;
++
++ my_bind[4].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[4].buffer= (void *)&dt;
++ my_bind[4].buffer_length= sizeof(dt);
++ my_bind[4].length= &dt_length;
++
++ my_bind[5].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[5].buffer= (void *)&ts_4;
++ my_bind[5].buffer_length= sizeof(ts_4);
++ my_bind[5].length= &ts4_length;
++
++ my_bind[6].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[6].buffer= (void *)&ts_6;
++ my_bind[6].buffer_length= sizeof(ts_6);
++ my_bind[6].length= &ts6_length;
++
++ rc= my_stmt_result(mysql, "SELECT * FROM test_bind_result");
++ FAIL_UNLESS(rc == 1, "Expected 1 row");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ ts_4[0]= '\0';
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(date, "2002-01-02") == 0, "date != '2002-01-02'");
++ FAIL_UNLESS(d_length == 10, "d_length != 10");
++
++ FAIL_UNLESS(strcmp(my_time, "12:49:00") == 0, "mytime != '12:49:00'");
++ FAIL_UNLESS(t_length == 8, "t_length != 8");
++
++ FAIL_UNLESS(strcmp(ts, "2002-01-02 17:46:59") == 0, "ts != '2002-01-02 17:46:59'");
++ FAIL_UNLESS(ts_length == 19, "ts_length != 19");
++
++ FAIL_UNLESS(strcmp(dt, "2010-07-10 00:00:00") == 0, "dt != 2010-07-10 00:00:00");
++ FAIL_UNLESS(dt_length == 19, "dt_length != 19");
++
++ FAIL_UNLESS(strcmp(ts_4, "0000-00-00 00:00:00") == 0, "ts4 != '0000-00-00 00:00:00'");
++ FAIL_UNLESS(ts4_length == strlen("0000-00-00 00:00:00"), "ts4_length != 19");
++
++ FAIL_UNLESS(strcmp(ts_6, "1999-12-29 00:00:00") == 0, "ts_6 != '1999-12-29 00:00:00'");
++ FAIL_UNLESS(ts6_length == 19, "ts6_length != 19");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/* Test fetching of str to all types */
++
++static int test_fetch_str(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 char(10), \
++ c2 char(10), \
++ c3 char(20), \
++ c4 char(20), \
++ c5 char(30), \
++ c6 char(40), \
++ c7 char(20))");
++ check_mysql_rc(rc, mysql);
++
++ return bind_fetch(mysql, 3);
++}
++
++/* Test fetching of long to all types */
++
++static int test_fetch_long(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 int unsigned, \
++ c2 int unsigned, \
++ c3 int, \
++ c4 int, \
++ c5 int, \
++ c6 int unsigned, \
++ c7 int)");
++ check_mysql_rc(rc, mysql);
++ return bind_fetch(mysql, 4);
++}
++
++
++/* Test fetching of short to all types */
++
++static int test_fetch_short(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 smallint unsigned, \
++ c2 smallint, \
++ c3 smallint unsigned, \
++ c4 smallint, \
++ c5 smallint, \
++ c6 smallint, \
++ c7 smallint unsigned)");
++ check_mysql_rc(rc, mysql);
++ return bind_fetch(mysql, 5);
++}
++
++
++/* Test fetching of tiny to all types */
++
++static int test_fetch_tiny(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 tinyint unsigned, \
++ c2 tinyint, \
++ c3 tinyint unsigned, \
++ c4 tinyint, \
++ c5 tinyint, \
++ c6 tinyint, \
++ c7 tinyint unsigned)");
++ check_mysql_rc(rc, mysql);
++ return bind_fetch(mysql, 3);
++}
++
++
++/* Test fetching of longlong to all types */
++
++static int test_fetch_bigint(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 bigint, \
++ c2 bigint, \
++ c3 bigint unsigned, \
++ c4 bigint unsigned, \
++ c5 bigint unsigned, \
++ c6 bigint unsigned, \
++ c7 bigint unsigned)");
++ check_mysql_rc(rc, mysql);
++ return bind_fetch(mysql, 2);
++}
++
++
++/* Test fetching of float to all types */
++
++static int test_fetch_float(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 float(3), \
++ c2 float, \
++ c3 float unsigned, \
++ c4 float, \
++ c5 float, \
++ c6 float, \
++ c7 float(10) unsigned)");
++ check_mysql_rc(rc, mysql);
++
++ return bind_fetch(mysql, 2);
++}
++
++
++/* Test fetching of double to all types */
++
++static int test_fetch_double(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 double(5, 2), "
++ "c2 double unsigned, c3 double unsigned, "
++ "c4 double unsigned, c5 double unsigned, "
++ "c6 double unsigned, c7 double unsigned)");
++ check_mysql_rc(rc, mysql);
++ return bind_fetch(mysql, 3);
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_fetch_seek", test_fetch_seek, 1, 0, NULL , NULL},
++ {"test_fetch_offset", test_fetch_offset, 1, 0, NULL , NULL},
++ {"test_fetch_column", test_fetch_column, 1, 0, NULL , NULL},
++ {"test_fetch_nobuffs", test_fetch_nobuffs, 1, 0, NULL , NULL},
++ {"test_fetch_null", test_fetch_null, 1, 0, NULL , NULL},
++ {"test_fetch_date", test_fetch_date, 1, 0, NULL , NULL},
++ {"test_fetch_str", test_fetch_str, 1, 0, NULL , NULL},
++ {"test_fetch_long", test_fetch_long, 1, 0, NULL , NULL},
++ {"test_fetch_short", test_fetch_short, 1, 0, NULL , NULL},
++ {"test_fetch_tiny", test_fetch_tiny, 1, 0, NULL , NULL},
++ {"test_fetch_bigint", test_fetch_bigint, 1, 0, NULL , NULL},
++ {"test_fetch_float", test_fetch_float, 1, 0, NULL , NULL},
++ {"test_fetch_double", test_fetch_double, 1, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/logs.c'
---- mariadb/unittest/libmysql/logs.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/logs.c 2013-03-14 21:01:43 +0000
-@@ -23,6 +23,7 @@
- */
- #include "my_test.h"
-
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/logs.c mariadb-native-client.trunk/unittest/libmariadb/logs.c
+--- mariadb/unittest/libmariadb/logs.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/logs.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,214 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
+#ifdef ENABLE_IF_IN_USE
- static int enable_general_log(MYSQL *mysql, int truncate)
- {
- int rc;
-@@ -51,7 +52,7 @@
-
- return OK;
- }
--
++static int enable_general_log(MYSQL *mysql, int truncate)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "set @save_global_general_log=@@global.general_log");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "set @@global.general_log=on");
++ check_mysql_rc(rc, mysql);
++
++ if (truncate)
++ {
++ rc= mysql_query(mysql, "truncate mysql.general_log");
++ check_mysql_rc(rc, mysql);
++ }
++
++ return OK;
++}
++
++
++static int restore_general_log(MYSQL *mysql)
++{
++ int rc;
++ rc= mysql_query(mysql, "set @@global.general_log=@save_global_general_log");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
+#endif
-
- /* Test update/binary logs */
-
-@@ -202,8 +203,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++
++/* Test update/binary logs */
++
++static int test_logs(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ char data[255];
++ ulong length;
++ int rc;
++ short id;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_logs");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_logs(id smallint, name varchar(20))");
++ check_mysql_rc(rc, mysql);
++
++ strcpy((char *)data, "INSERT INTO test_logs VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[0].buffer= (void *)&id;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)&data;
++ my_bind[1].buffer_length= 255;
++ my_bind[1].length= &length;
++
++ id= 9876;
++ strcpy((char *)data, "MySQL - Open Source Database");
++ length= strlen(data);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ strcpy((char *)data, "'");
++ length= 1;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ strcpy((char *)data, "\"");
++ length= 1;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ strcpy((char *)data, "my\'sql\'");
++ length= strlen(data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ strcpy((char *)data, "my\"sql\"");
++ length= strlen(data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ strcpy((char *)data, "INSERT INTO test_logs VALUES(20, 'mysql')");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ strcpy((char *)data, "SELECT * FROM test_logs WHERE id=?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ my_bind[1].buffer_length= 255;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(id == 9876, "id != 9876");
++ FAIL_UNLESS(length == 19 || length == 20, "Invalid Length"); /* Due to VARCHAR(20) */
++ FAIL_UNLESS(strncmp(data, "MySQL - Open Source", 19) == 0, "data != 'MySQL - Open Source'");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(length == 1, "length != 1");
++ FAIL_UNLESS(strcmp(data, "'") == 0, "data != '''");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(length == 1, "length != 1");
++ FAIL_UNLESS(strcmp(data, "\"") == 0, "data != '\"'");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(length == 7, "length != 7");
++ FAIL_UNLESS(strcmp(data, "my\'sql\'") == 0, "data != my'sql'");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(length == 7, "length != 7");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE test_logs");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++struct my_tests_st my_tests[] = {
++ {"test_logs", test_logs, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/misc.c'
---- mariadb/unittest/libmysql/misc.c 2012-11-26 10:23:56 +0000
-+++ mariadb/unittest/libmariadb/misc.c 2013-03-14 21:01:43 +0000
-@@ -51,12 +51,17 @@
- int rc;
-
- rc= mysql_query(mysql, "drop table if exists t1");
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/misc.c mariadb-native-client.trunk/unittest/libmariadb/misc.c
+--- mariadb/unittest/libmariadb/misc.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/misc.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,984 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++#include "ma_common.h"
++
++/*
++ Bug#28075 "COM_DEBUG crashes mysqld"
++*/
++
++static int test_bug28075(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_dump_debug_info(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_ping(mysql);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug#28505: mysql_affected_rows() returns wrong value if CLIENT_FOUND_ROWS
++ flag is set.
++*/
++
++static int test_bug28505(MYSQL *mysql)
++{
++ my_ulonglong res;
++ int rc;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
+ check_mysql_rc(rc, mysql);
- rc= mysql_query(mysql, "create table t1(f1 int primary key)");
++ rc= mysql_query(mysql, "create table t1(f1 int primary key)");
+ check_mysql_rc(rc, mysql);
- rc= mysql_query(mysql, "insert into t1 values(1)");
++ rc= mysql_query(mysql, "insert into t1 values(1)");
+ check_mysql_rc(rc, mysql);
- rc= mysql_query(mysql, "insert into t1 values(1) on duplicate key update f1=1");
++ rc= mysql_query(mysql, "insert into t1 values(1) on duplicate key update f1=1");
+ check_mysql_rc(rc, mysql);
- res= mysql_affected_rows(mysql);
- FAIL_UNLESS(!res, "res != 0");
- rc= mysql_query(mysql, "drop table t1");
++ res= mysql_affected_rows(mysql);
++ FAIL_UNLESS(!res, "res != 0");
++ rc= mysql_query(mysql, "drop table t1");
+ check_mysql_rc(rc, mysql);
- return OK;
- }
-
-@@ -251,7 +256,7 @@
- char test_frm[FN_REFLEN];
- int rc;
-
--
++ return OK;
++}
++
++/*
++ Bug #29692 Single row inserts can incorrectly report a huge number of
++ row insertions
++*/
++
++static int test_bug29692(MYSQL *mysql)
++{
++ int rc;
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1(f1 int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values(1)");
++ check_mysql_rc(rc, mysql);
++ FAIL_UNLESS(1 == mysql_affected_rows(mysql), "affected_rows != 1");
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int bug31418_impl()
++{
++ my_bool is_null;
++ MYSQL *mysql;
++ int rc;
++
++ /* Create a new connection. */
++
++ mysql= test_connect(NULL);
++ if (!mysql)
++ return FAIL;
++
++ /***********************************************************************
++ Check that lock is free:
++ - IS_FREE_LOCK() should return 1;
++ - IS_USED_LOCK() should return NULL;
++ ***********************************************************************/
++
++ is_null= query_int_variable(mysql,
++ "IS_FREE_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(!is_null && rc, "rc = 0");
++
++ is_null= query_int_variable(mysql,
++ "IS_USED_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(is_null, "rc = 0");
++
++ /***********************************************************************
++ Acquire lock and check the lock status (the lock must be in use):
++ - IS_FREE_LOCK() should return 0;
++ - IS_USED_LOCK() should return non-zero thread id;
++ ***********************************************************************/
++
++ query_int_variable(mysql, "GET_LOCK('bug31418', 1)", &rc);
++ FAIL_UNLESS(rc, "rc = 0");
++
++ is_null= query_int_variable(mysql,
++ "IS_FREE_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(!is_null && !rc, "rc = 0");
++
++ is_null= query_int_variable(mysql,
++ "IS_USED_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(!is_null && rc, "rc = 0");
++
++ /***********************************************************************
++ Issue COM_CHANGE_USER command and check the lock status
++ (the lock must be free):
++ - IS_FREE_LOCK() should return 1;
++ - IS_USED_LOCK() should return NULL;
++ **********************************************************************/
++
++ rc= mysql_change_user(mysql, username, password, schema ? schema : "test");
++ check_mysql_rc(rc, mysql);
++
++ is_null= query_int_variable(mysql,
++ "IS_FREE_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(!is_null && rc, "rc = 0");
++
++ is_null= query_int_variable(mysql,
++ "IS_USED_LOCK('bug31418')",
++ &rc);
++ FAIL_UNLESS(is_null, "rc = 0");
++
++ /***********************************************************************
++ That's it. Cleanup.
++ ***********************************************************************/
++
++ mysql_close(mysql);
++ return OK;
++}
++
++static int test_bug31418(MYSQL *mysql)
++{
++ int i;
++ /* Run test case for BUG#31418 for three different connections. */
++
++ for (i=0; i < 3; i++)
++ if (bug31418_impl())
++ return FAIL;
++
++ return OK;
++}
++
++/*
++ Altough mysql_create_db(), mysql_rm_db() are deprecated since 4.0 they
++ should not crash server and should not hang in case of errors.
++
++ Since those functions can't be seen in modern API (unless client library
++ was compiled with USE_OLD_FUNCTIONS define) we use simple_command() macro.
++*/
++static int test_bug6081(MYSQL *mysql)
++{
++ int rc;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= simple_command(mysql, MYSQL_COM_DROP_DB, (char*) schema,
++ (ulong)strlen(schema), 0U, NULL);
++ FAIL_IF(!rc, "Error expected");
++
++ rc= simple_command(mysql, MYSQL_COM_CREATE_DB, (char*) schema,
++ (ulong)strlen(schema), 0U, NULL);
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_select_db(mysql, schema);
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Query processing */
++
++static int test_debug_example(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_debug_example");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_debug_example("
++ "id INT PRIMARY KEY AUTO_INCREMENT, "
++ "name VARCHAR(20), xxx INT)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_debug_example (name) "
++ "VALUES ('mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "UPDATE test_debug_example SET name='updated' "
++ "WHERE name='deleted'");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT * FROM test_debug_example where name='mysql'");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result));
++ mysql_free_result(result);
++
++ rc= mysql_query(mysql, "DROP TABLE test_debug_example");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/*
++ Test a crash when invalid/corrupted .frm is used in the
++ SHOW TABLE STATUS
++ bug #93 (reported by serg@mysql.com).
++*/
++
++static int test_frm_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ MYSQL_RES *result;
++ MYSQL_ROW row;
++ FILE *test_file;
++ char data_dir[FN_REFLEN];
++ char test_frm[FN_REFLEN];
++ int rc;
++
+ return SKIP;
- mysql_autocommit(mysql, TRUE);
-
- rc= mysql_query(mysql, "drop table if exists test_frm_bug");
-@@ -828,8 +833,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "drop table if exists test_frm_bug");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "flush tables");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "show variables like 'datadir'", strlen("show variables like 'datadir'"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= data_dir;
++ my_bind[0].buffer_length= FN_REFLEN;
++ my_bind[1]= my_bind[0];
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ sprintf(test_frm, "%s/%s/test_frm_bug.frm", data_dir, schema);
++
++
++ if (!(test_file= my_fopen(test_frm, (int) (O_RDWR | O_CREAT), MYF(MY_WME))))
++ {
++ mysql_stmt_close(stmt);
++ diag("Can't write to file %s -> SKIP", test_frm);
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "SHOW TABLE STATUS like 'test_frm_bug'");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");/* It can't be NULL */
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 0");
++
++ mysql_data_seek(result, 0);
++
++ row= mysql_fetch_row(result);
++ FAIL_IF(!row, "couldn't fetch row");
++
++ FAIL_UNLESS(row[17] != 0, "row[17] != 0");
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ my_fclose(test_file, MYF(0));
++ mysql_query(mysql, "drop table if exists test_frm_bug");
++ return OK;
++}
++
++static int test_wl4166_1(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int int_data;
++ char str_data[50];
++ char tiny_data;
++ short small_data;
++ longlong big_data;
++ float real_data;
++ double double_data;
++ ulong length[7];
++ my_bool is_null[7];
++ MYSQL_BIND my_bind[7];
++ static char *query;
++ int rc;
++ int i;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS table_4166");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE table_4166(col1 tinyint NOT NULL, "
++ "col2 varchar(15), col3 int, "
++ "col4 smallint, col5 bigint, "
++ "col6 float, col7 double, "
++ "colX varchar(10) default NULL)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ query= "INSERT INTO table_4166(col1, col2, col3, col4, col5, col6, col7) "
++ "VALUES(?, ?, ?, ?, ?, ?, ?)";
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 7, "param_count != 7");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ /* tinyint */
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&tiny_data;
++ /* string */
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)str_data;
++ my_bind[1].buffer_length= 1000; /* Max string length */
++ /* integer */
++ my_bind[2].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[2].buffer= (void *)&int_data;
++ /* short */
++ my_bind[3].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[3].buffer= (void *)&small_data;
++ /* bigint */
++ my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[4].buffer= (void *)&big_data;
++ /* float */
++ my_bind[5].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[5].buffer= (void *)&real_data;
++ /* double */
++ my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[6].buffer= (void *)&double_data;
++
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].length= &length[i];
++ my_bind[i].is_null= &is_null[i];
++ is_null[i]= 0;
++ }
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ int_data= 320;
++ small_data= 1867;
++ big_data= 1000;
++ real_data= 2;
++ double_data= 6578.001;
++
++ /* now, execute the prepared statement to insert 10 records.. */
++ for (tiny_data= 0; tiny_data < 10; tiny_data++)
++ {
++ length[1]= sprintf(str_data, "MySQL%d", int_data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ int_data += 25;
++ small_data += 10;
++ big_data += 100;
++ real_data += 1;
++ double_data += 10.09;
++ }
++
++ /* force a re-prepare with some DDL */
++
++ rc= mysql_query(mysql,
++ "ALTER TABLE table_4166 change colX colX varchar(20) default NULL");
++ check_mysql_rc(rc, mysql);
++
++ /*
++ execute the prepared statement again,
++ without changing the types of parameters already bound.
++ */
++
++ for (tiny_data= 50; tiny_data < 60; tiny_data++)
++ {
++ length[1]= sprintf(str_data, "MySQL%d", int_data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ int_data += 25;
++ small_data += 10;
++ big_data += 100;
++ real_data += 1;
++ double_data += 10.09;
++ }
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE table_4166");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++
++static int test_wl4166_2(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int c_int;
++ MYSQL_TIME d_date;
++ MYSQL_BIND bind_out[2];
++ int rc;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (c_int int, d_date date)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "insert into t1 (c_int, d_date) values (42, '1948-05-15')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select * from t1", strlen("select * from t1"));
++ check_stmt_rc(rc, stmt);
++
++ memset(bind_out, '\0', sizeof(bind_out));
++ bind_out[0].buffer_type= MYSQL_TYPE_LONG;
++ bind_out[0].buffer= (void*) &c_int;
++
++ bind_out[1].buffer_type= MYSQL_TYPE_DATE;
++ bind_out[1].buffer= (void*) &d_date;
++
++ rc= mysql_stmt_bind_result(stmt, bind_out);
++ check_stmt_rc(rc, stmt);
++
++ /* int -> varchar transition */
++
++ rc= mysql_query(mysql,
++ "alter table t1 change column c_int c_int varchar(11)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(c_int == 42, "c_int != 42");
++ FAIL_UNLESS(d_date.year == 1948, "y!=1948");
++ FAIL_UNLESS(d_date.month == 5, "m != 5");
++ FAIL_UNLESS(d_date.day == 15, "d != 15");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* varchar to int retrieval with truncation */
++
++ rc= mysql_query(mysql, "update t1 set c_int='abcde'");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ FAIL_UNLESS(c_int == 0, "c != 0");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* alter table and increase the number of columns */
++ rc= mysql_query(mysql, "alter table t1 add column d_int int");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* decrease the number of columns */
++ rc= mysql_query(mysql, "alter table t1 drop d_date, drop d_int");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_stmt_execute(stmt);
++ diag("rc=%d error: %d\n", rc, mysql_stmt_errno(stmt));
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++/**
++ Test how warnings generated during assignment of parameters
++ are (currently not) preserve in case of reprepare.
++*/
++
++static int test_wl4166_3(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ MYSQL_TIME tm[1];
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (year datetime)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "insert into t1 (year) values (?)", strlen("insert into t1 (year) values (?)"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_DATETIME;
++ my_bind[0].buffer= &tm[0];
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ tm[0].year= 2014;
++ tm[0].month= 1; tm[0].day= 1;
++ tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1;
++ tm[0].second_part= 0; tm[0].neg= 0;
++
++ /* Cause a statement reprepare */
++ rc= mysql_query(mysql, "alter table t1 add column c int");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ diag("rc=%d %s", rc, mysql_stmt_error(stmt));
++ check_stmt_rc(rc, stmt);
++
++ if (verify_col_data(mysql, "t1", "year", "2014-01-01 01:01:01")) {
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ return FAIL;
++ }
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++
++/**
++ Test that long data parameters, as well as parameters
++ that were originally in a different character set, are
++ preserved in case of reprepare.
++*/
++
++static int test_wl4166_4(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *stmt_text;
++ MYSQL_BIND bind_array[2];
++
++ /* Represented as numbers to keep UTF8 tools from clobbering them. */
++ const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
++ const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
++ char buf1[16], buf2[16];
++ ulong buf1_len, buf2_len;
++
++ if (mysql_get_server_version(mysql) < 50100) {
++ diag("Test requires MySQL Server version 5.1 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ /*
++ Create table with binary columns, set session character set to cp1251,
++ client character set to koi8, and make sure that there is conversion
++ on insert and no conversion on select
++ */
++ rc= mysql_query(mysql,
++ "create table t1 (c1 varbinary(255), c2 varbinary(255))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "set character_set_client=koi8r, "
++ "character_set_connection=cp1251, "
++ "character_set_results=koi8r");
++ check_mysql_rc(rc, mysql);
++
++ memset(bind_array, '\0', sizeof(bind_array));
++
++ bind_array[0].buffer_type= MYSQL_TYPE_STRING;
++
++ bind_array[1].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[1].buffer= (void *) koi8;
++ bind_array[1].buffer_length= strlen(koi8);
++
++ stmt= mysql_stmt_init(mysql);
++ check_stmt_rc(rc, stmt);
++
++ stmt_text= "insert into t1 (c1, c2) values (?, ?)";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_bind_param(stmt, bind_array);
++
++ mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
++
++ /* Cause a reprepare at statement execute */
++ rc= mysql_query(mysql, "alter table t1 add column d int");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ stmt_text= "select c1, c2 from t1";
++
++ /* c1 and c2 are binary so no conversion will be done on select */
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ bind_array[0].buffer= buf1;
++ bind_array[0].buffer_length= sizeof(buf1);
++ bind_array[0].length= &buf1_len;
++
++ bind_array[1].buffer= buf2;
++ bind_array[1].buffer_length= sizeof(buf2);
++ bind_array[1].length= &buf2_len;
++
++ mysql_stmt_bind_result(stmt, bind_array);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(buf1_len == strlen(cp1251), "");
++ FAIL_UNLESS(buf2_len == strlen(cp1251), "");
++ FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "");
++ FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "set names default");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/**
++ Test that COM_REFRESH issues a implicit commit.
++*/
++
++static int test_wl4284_1(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_ROW row;
++ MYSQL_RES *result;
++
++ if (mysql_get_server_version(mysql) < 60000) {
++ diag("Test requires MySQL Server version 6.0 or above");
++ return SKIP;
++ }
++
++ /* set AUTOCOMMIT to OFF */
++ rc= mysql_autocommit(mysql, FALSE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS trans");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE trans (a INT) ENGINE= InnoDB");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO trans VALUES(1)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_refresh(mysql, REFRESH_GRANT | REFRESH_TABLES);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_rollback(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT * FROM trans");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ row= mysql_fetch_row(result);
++ FAIL_IF(!row, "Can't fetch row");
++
++ mysql_free_result(result);
++
++ /* set AUTOCOMMIT to OFF */
++ rc= mysql_autocommit(mysql, FALSE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE trans");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug49694(MYSQL *mysql)
++{
++ int rc;
++ int i;
++ FILE *fp;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS enclist");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE `enclist` ("
++ " `pat_id` int(11) NOT NULL,"
++ " `episode_id` int(11) NOT NULL,"
++ " `enc_id` double NOT NULL,"
++ " PRIMARY KEY (`pat_id`,`episode_id`,`enc_id`)"
++ ") ENGINE=MyISAM DEFAULT CHARSET=latin1");
++ check_mysql_rc(rc, mysql);
++
++ fp= fopen("data.csv", "w");
++ FAIL_IF(!fp, "Can't open data.csv");
++
++ for (i=0; i < 100; i++)
++ fprintf (fp, "%.08d,%d,%f\r\n", 100 + i, i % 3 + 1, 60000.0 + i/100);
++ fclose(fp);
++
++ rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE enclist "
++ "FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DELETE FROM enclist");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_IF(mysql_affected_rows(mysql) != 100, "Import failure. Expected 2 imported rows");
++
++ rc= mysql_query(mysql, "DROP TABLE enclist");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_conc49(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *res;
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS conc49");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE conc49 (a int, b int, c int) Engine=InnoDB DEFAULT CHARSET=latin1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE './sample.csv' INTO TABLE conc49 FIELDS ESCAPED BY ' ' TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\r\n'");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT a FROM conc49");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ rc= mysql_num_rows(res);
++ mysql_free_result(res);
++ FAIL_IF(rc != 3, "3 rows expected");
++ return OK;
++}
++
++static int test_ldi_path(MYSQL *mysql)
++{
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++#ifdef _WIN32
++ rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE 'X:/non_existing_path/data.csv' INTO TABLE t1 "
++ "FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'");
++#else
++ rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE '/non_existing_path/data.csv' INTO TABLE t1 "
++ "FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'");
++#endif
++ FAIL_IF(rc== 0, "Error expected");
++ FAIL_IF(mysql_errno(mysql) != 2, "Error code 2 expected");
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++#if _WIN32
++static int test_conc44(MYSQL *mysql)
++{
++ char query[1024];
++ char *a_filename= "æøå.csv";
++ int rc;
++ int i;
++ FILE *fp;
++
++ rc= mysql_set_character_set(mysql, "latin1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS enclist");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE `enclist` ("
++ " `pat_id` int(11) NOT NULL,"
++ " `episode_id` int(11) NOT NULL,"
++ " `enc_id` double NOT NULL,"
++ " PRIMARY KEY (`pat_id`,`episode_id`,`enc_id`)"
++ ") ENGINE=MyISAM DEFAULT CHARSET=latin1");
++ check_mysql_rc(rc, mysql);
++
++ fp= fopen(a_filename, "w");
++ FAIL_IF(!fp, "Can't open file");
++
++ for (i=0; i < 100; i++)
++ fprintf (fp, "%.08d,%d,%f\r\n", 100 + i, i % 3 + 1, 60000.0 + i/100);
++ fclose(fp);
++
++ sprintf(query, "LOAD DATA LOCAL INFILE '%s' INTO TABLE enclist "
++ "FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'", a_filename);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DELETE FROM enclist");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_IF(mysql_affected_rows(mysql) != 100, "Import failure. Expected 2 imported rows");
++
++ rc= mysql_query(mysql, "DROP TABLE enclist");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++#endif
++
++static int test_connect_attrs(MYSQL *my)
++{
++ MYSQL *mysql;
++ MYSQL_RES *result;
++ int rc, len;
++
++ mysql= mysql_init(NULL);
++
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo0", "bar0");
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo1", "bar1");
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo2", "bar2");
++
++ FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0), mysql_error(my));
++
++ if (!(mysql->server_capabilities & CLIENT_CONNECT_ATTRS))
++ {
++ mysql_close(mysql);
++ diag("Server doesn't support connection attributes");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "SELECT * FROM performance_schema.session_connect_attrs where attr_name like 'foo%'");
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql);
++ rc= mysql_num_rows(result);
++ mysql_free_result(result);
++
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, NULL);
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo0", "bar0");
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo1", "bar1");
++ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo2", "bar2");
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo0");
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo1");
++ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo2");
++
++ len= mysql->options.extension->connect_attrs_len;
++
++
++ mysql_close(mysql);
++
++ FAIL_IF(rc < 3, "Expected 3 or more rows");
++ FAIL_IF(len != 0, "Expected connection_attr_len=0");
++
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_connect_attrs", test_connect_attrs, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_conc49", test_conc49, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug28075", test_bug28075, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug28505", test_bug28505, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_debug_example", test_debug_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug29692", test_bug29692, TEST_CONNECTION_NEW, CLIENT_FOUND_ROWS, NULL, NULL},
++ {"test_bug31418", test_bug31418, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug6081", test_bug6081, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_frm_bug", test_frm_bug, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_wl4166_1", test_wl4166_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_wl4166_2", test_wl4166_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_wl4166_3", test_wl4166_3, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_wl4166_4", test_wl4166_4, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_wl4284_1", test_wl4284_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_bug49694", test_bug49694, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_ldi_path", test_ldi_path, TEST_CONNECTION_NEW, 0, NULL, NULL},
++#ifdef _WIN32
++ {"test_conc44", test_conc44, TEST_CONNECTION_NEW, 0, NULL, NULL},
++#endif
++ {NULL, NULL, 0, 0, NULL, 0}
++};
++
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/my_test.h'
---- mariadb/unittest/libmysql/my_test.h 2012-11-26 10:23:56 +0000
-+++ mariadb/unittest/libmariadb/my_test.h 2013-03-14 21:01:43 +0000
-@@ -365,13 +365,14 @@
- MYSQL *test_connect(struct my_tests_st *test) {
- MYSQL *mysql;
- char query[255];
--
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/my_test.h mariadb-native-client.trunk/unittest/libmariadb/my_test.h
+--- mariadb/unittest/libmariadb/my_test.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/my_test.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,520 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include <my_global.h>
++#include <my_sys.h>
++#include <mysql.h>
++#include <tap.h>
++#include <getopt.h>
++#include <memory.h>
++#include <errmsg.h>
++
++#ifndef OK
++# define OK 0
++#endif
++#ifndef FAIL
++# define FAIL 1
++#endif
++#ifndef SKIP
++# define SKIP -1
++#endif
++#ifndef FALSE
++# define FALSE 0
++#endif
++#ifndef TRUE
++# define TRUE 1
++#endif
++
++#define MAX_KEY MAX_INDEXES
++#define MAX_KEY_LENGTH_DECIMAL_WIDTH 4 /* strlen("4096") */
++
++#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
++
++#define check_mysql_rc(rc, mysql) \
++if (rc)\
++{\
++ diag("Error (%d): %s (%d) in %s line %d", rc, mysql_error(mysql), \
++ mysql_errno(mysql), __FILE__, __LINE__);\
++ return(FAIL);\
++}
++
++#define check_stmt_rc(rc, stmt) \
++if (rc)\
++{\
++ diag("Error: %s (%s: %d)", mysql_stmt_error(stmt), __FILE__, __LINE__);\
++ return(FAIL);\
++}
++
++#define FAIL_IF(expr, reason)\
++if (expr)\
++{\
++ diag("Error: %s (%s: %d)", (reason) ? reason : "", __FILE__, __LINE__);\
++ return FAIL;\
++}
++
++#define FAIL_UNLESS(expr, reason)\
++if (!(expr))\
++{\
++ diag("Error: %s (%s: %d)", reason, __FILE__, __LINE__);\
++ return FAIL;\
++}
++
++/* connection options */
++#define TEST_CONNECTION_DEFAULT 1 /* default connection */
++#define TEST_CONNECTION_NONE 2 /* tests creates own connection */
++#define TEST_CONNECTION_NEW 4 /* create a separate connection */
++#define TEST_CONNECTION_DONT_CLOSE 8 /* don't close connection */
++
++struct my_option_st
++{
++ enum mysql_option option;
++ char *value;
++};
++
++struct my_tests_st
++{
++ const char *name;
++ int (*function)(MYSQL *);
++ int connection;
++ ulong connect_flags;
++ struct my_option_st *options;
++ char *skipmsg;
++};
++
++static char *schema = "test";
++static char *hostname = 0;
++static char *password = 0;
++static unsigned int port = 0;
++static char *socketname = 0;
++static char *username = 0;
++/*
++static struct my_option test_options[] =
++{
++ {"schema", 'd', "database to use", (uchar **) &schema, (uchar **) &schema,
++ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
++ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
++ 0, 0, 0, 0, 0},
++ {"host", 'h', "Connect to host", (uchar **) &hostname, (uchar **) &hostname,
++ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
++ {"password", 'p',
++ "Password to use when connecting to server.", (uchar **) &password, (uchar **) &password,
++ 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
++ {"port", 'P', "Port number to use for connection or 0 for default to, in "
++ "order of preference, my.cnf, $MYSQL_TCP_PORT, "
++#if MYSQL_PORT_DEFAULT == 0
++ "/etc/services, "
++#endif
++ "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
++ (uchar **) &port,
++ (uchar **) &port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
++ {"socket", 'S', "Socket file to use for connection",
++ (uchar **) &socketname, (uchar **) &socketname, 0, GET_STR,
++ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
++ {"user", 'u', "User for login if not current user", (uchar **) &username,
++ (uchar **) &username, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
++ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
++};
++*/
++#define verify_prepare_field(result,no,name,org_name,type,table,\
++ org_table,db,length,def) \
++ do_verify_prepare_field((result),(no),(name),(org_name),(type), \
++ (table),(org_table),(db),(length),(def), \
++ __FILE__, __LINE__)
++
++int do_verify_prepare_field(MYSQL_RES *result,
++ unsigned int no, const char *name,
++ const char *org_name,
++ enum enum_field_types type,
++ const char *table,
++ const char *org_table, const char *db,
++ unsigned long length, const char *def,
++ const char *file, int line)
++{
++ MYSQL_FIELD *field;
++/* CHARSET_INFO *cs; */
++
++ FAIL_IF(!(field= mysql_fetch_field_direct(result, no)), "FAILED to get result");
++/* cs= mysql_find_charset_nr(field->charsetnr);
++ FAIL_UNLESS(cs, "Couldn't get character set"); */
++ FAIL_UNLESS(strcmp(field->name, name) == 0, "field->name differs");
++ FAIL_UNLESS(strcmp(field->org_name, org_name) == 0, "field->org_name differs");
++/*
++ if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32)
++ expected_field_length= UINT_MAX32;
++*/
++ /*
++ XXX: silent column specification change works based on number of
++ bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even
++ for CHAR(2) column if its character set is multibyte.
++ VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would
++ expect.
++ */
++// if (cs->char_maxlen == 1)
++// FAIL_UNLESS(field->type == type, "field->type differs");
++ if (table)
++ FAIL_UNLESS(strcmp(field->table, table) == 0, "field->table differs");
++ if (org_table)
++ FAIL_UNLESS(strcmp(field->org_table, org_table) == 0, "field->org_table differs");
++ FAIL_UNLESS(strcmp(field->db, db) == 0, "field->db differs");
++ /*
++ Character set should be taken into account for multibyte encodings, such
++ as utf8. Field length is calculated as number of characters * maximum
++ number of bytes a character can occupy.
++ */
++
++ return OK;
++}
++
++/* Prepare statement, execute, and process result set for given query */
++
++int my_stmt_result(MYSQL *mysql, const char *buff)
++{
++ MYSQL_STMT *stmt;
++ int row_count= 0;
++ int rc;
++
++ stmt= mysql_stmt_init(mysql);
++
++ rc= mysql_stmt_prepare(stmt, buff, strlen(buff));
++ FAIL_IF(rc, mysql_stmt_error(stmt));
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(rc, mysql_stmt_error(stmt));
++
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ row_count++;
++
++ mysql_stmt_close(stmt);
++
++ return row_count;
++}
++/*
++static my_bool
++get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
++ char *argument)
++{
++ switch (optid) {
++ case '?':
++ case 'I':
++ my_print_help(test_options);
++ exit(0);
++ break;
++ }
++ return 0;
++}
++*/
++/* Utility function to verify a particular column data */
++
++int verify_col_data(MYSQL *mysql, const char *table, const char *col,
++ const char *exp_data)
++{
++ static char query[MAX_TEST_QUERY_LENGTH];
++ MYSQL_RES *result;
++ MYSQL_ROW row;
++ int rc;
++
++ if (table && col)
++ {
++ sprintf(query, "SELECT %s FROM %s LIMIT 1", col, table);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++ }
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ if (!(row= mysql_fetch_row(result)) || !row[0]) {
++ diag("Failed to get the result");
++ goto error;
++ }
++ if(strcmp(row[0], exp_data)) {
++ diag("Expected %s, got %s", exp_data, row[0]);
++ goto error;
++ }
++ mysql_free_result(result);
++
++ return OK;
++
++error:
++ mysql_free_result(result);
++ return FAIL;
++}
++
++my_bool query_int_variable(MYSQL *con, const char *var_name, int *var_value)
++{
++ MYSQL_RES *rs;
++ MYSQL_ROW row;
++
++ char query_buffer[MAX_TEST_QUERY_LENGTH];
++
++ my_bool is_null;
++
++ sprintf(query_buffer,
++ "SELECT %s",
++ (const char *) var_name);
++
++ FAIL_IF(mysql_query(con, query_buffer), "Query failed");
++ FAIL_UNLESS(rs= mysql_store_result(con), "Invaliid result set");
++ FAIL_UNLESS(row= mysql_fetch_row(rs), "Nothing to fetch");
++
++ is_null= row[0] == NULL;
++
++ if (!is_null)
++ *var_value= atoi(row[0]);
++
++ mysql_free_result(rs);
++
++ return is_null;
++}
++
++static void usage()
++{
++ printf("Execute test with the following options:\n");
++ printf("-h hostname\n");
++ printf("-u username\n");
++ printf("-p password\n");
++ printf("-d database\n");
++ printf("-S socketname\n");
++ printf("-P port number\n");
++ printf("? displays this help and exits\n");
++}
++
++void get_options(int argc, char **argv)
++{
++ int c= 0;
++
++ while ((c=getopt(argc,argv, "h:u:p:d:P:S:?")) >= 0)
++ {
++ switch(c) {
++ case 'h':
++ hostname= optarg;
++ break;
++ case 'u':
++ username= optarg;
++ break;
++ case 'p':
++ password= optarg;
++ break;
++ case 'd':
++ schema= optarg;
++ break;
++ case 'P':
++ port= atoi(optarg);
++ break;
++ case 'S':
++ socketname= optarg;
++ break;
++ case '?':
++ usage();
++ exit(0);
++ break;
++ default:
++ printf("Unknown option %c\n", c);
++ usage();
++ exit(0);
++ }
++ }
++}
++
++
++int check_variable(MYSQL *mysql, char *variable, char *value)
++{
++ char query[MAX_TEST_QUERY_LENGTH];
++ MYSQL_RES *result;
++ MYSQL_ROW row;
++
++ sprintf(query, "SELECT %s", variable);
++ result= mysql_store_result(mysql);
++ if (!result)
++ return FAIL;
++
++ if ((row = mysql_fetch_row(result)))
++ if (strcmp(row[0], value) == 0) {
++ mysql_free_result(result);
++ return OK;
++ }
++ mysql_free_result(result);
++ return FAIL;
++}
++
++/*
++ * function *test_connect
++ *
++ * returns a new connection. This function will be called, if the test doesn't
++ * use default_connection.
++ */
++MYSQL *test_connect(struct my_tests_st *test) {
++ MYSQL *mysql;
++ char query[255];
+ int i= 1;
- if (!(mysql = mysql_init(NULL))) {
- diag("%s", "mysql_init failed - exiting");
- return(NULL);
- }
-
- mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, "1");
++ if (!(mysql = mysql_init(NULL))) {
++ diag("%s", "mysql_init failed - exiting");
++ return(NULL);
++ }
++
++ mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, "1");
+ mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i);
-
- /* option handling */
- if (test && test->options) {
-@@ -388,9 +389,8 @@
- i++;
- }
- }
--
- if (!(mysql_real_connect(mysql, hostname, username, password,
-- NULL, port, socketname, (test) ? test->connect_flags:0)))
++
++ /* option handling */
++ if (test && test->options) {
++ int i=0;
++
++ while (test->options[i].option)
++ {
++ if (mysql_options(mysql, test->options[i].option, test->options[i].value)) {
++ diag("Couldn't set option %d. Error (%d) %s", test->options[i].option,
++ mysql_errno(mysql), mysql_error(mysql));
++ mysql_close(mysql);
++ return(NULL);
++ }
++ i++;
++ }
++ }
++ if (!(mysql_real_connect(mysql, hostname, username, password,
+ schema, port, socketname, (test) ? test->connect_flags:0)))
- {
- diag("Couldn't establish connection to server %s. Error (%d): %s",
- hostname, mysql_errno(mysql), mysql_error(mysql));
-@@ -465,7 +465,10 @@
- plan(total);
-
- if ((mysql_default= test_connect(NULL)))
+ {
- diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default));
++ diag("Couldn't establish connection to server %s. Error (%d): %s",
++ hostname, mysql_errno(mysql), mysql_error(mysql));
++ mysql_close(mysql);
++ return(NULL);
++ }
++
++ /* change database or create if it doesn't exist */
++ if (mysql_select_db(mysql, schema)) {
++ if(mysql_errno(mysql) == 1049) {
++ sprintf(query, "CREATE DATABASE %s", schema);
++ if (mysql_query(mysql, query)) {
++ diag("Can't create database %s", schema);
++ mysql_close(mysql);
++ return NULL;
++ }
++ } else {
++ diag("Error (%d): %s", mysql_errno(mysql), mysql_error(mysql));
++ mysql_close(mysql);
++ return NULL;
++ }
++ }
++
++ return(mysql);
++}
++
++static int reset_connection(MYSQL *mysql) {
++ int rc;
++
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++ if (mysql_get_server_version(mysql) < 50400)
++ rc= mysql_query(mysql, "SET table_type='MyISAM'");
++ else
++ rc= mysql_query(mysql, "SET storage_engine='MyISAM'");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "SET sql_mode=''");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ * function get_envvars((
++ *
++ * checks for connection related environment variables
++ */
++void get_envvars() {
++ char *envvar;
++
++ if (!hostname && (envvar= getenv("MYSQL_TEST_HOST")))
++ hostname= envvar;
++ if (!username && (envvar= getenv("MYSQL_TEST_USER")))
++ username= envvar;
++ if (!password && (envvar= getenv("MYSQL_TEST_PASSWD")))
++ password= envvar;
++ if (!schema && (envvar= getenv("MYSQL_TEST_DB")))
++ schema= envvar;
++ if (!port && (envvar= getenv("MYSQL_TEST_PORT")))
++ port= atoi(envvar);
++ if (!socketname && (envvar= getenv("MYSQL_TEST_SOCKET")))
++ socketname= envvar;
++}
++
++void run_tests(struct my_tests_st *test) {
++ int i, rc, total=0;
++ MYSQL *mysql, *mysql_default= NULL; /* default connection */
++
++
++ while (test[total].function)
++ total++;
++ plan(total);
++
++ if ((mysql_default= test_connect(NULL)))
++ {
++ diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default));
+ diag("Host %s", mysql_get_host_info(mysql_default));
+ }
- else
- {
- diag("Can't connect to a server. Aborting....");
-
-=== modified file 'unittest/libmariadb/ps.c'
---- mariadb/unittest/libmysql/ps.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/ps.c 2013-03-14 21:01:43 +0000
-@@ -2463,14 +2463,17 @@
- check_stmt_rc(rc, stmt);
- my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
- rc= mysql_stmt_bind_result(stmt, my_bind);
++ else
++ {
++ diag("Can't connect to a server. Aborting....");
++ exit(0);
++ }
+
-+ /* Since libmariadb supports geometry types in prepared statements
-+ we have to skip the following check
- FAIL_IF(!rc, "Error expected");
--
- rc= mysql_stmt_store_result(stmt);
- FAIL_UNLESS(rc, "");
-
- rc= mysql_stmt_store_result(stmt);
-- FAIL_UNLESS(rc, ""); /* Old error must be reset first */
-+ FAIL_UNLESS(rc, "");
-
++ for (i=0; i < total; i++) {
++ if (!mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT))
++ {
++ diag("MySQL server not running");
++ skip(1, "%s", test[i].name);
++ } else if (!test[i].skipmsg) {
++ mysql= mysql_default;
++ if (test[i].connection & TEST_CONNECTION_NEW)
++ mysql= test_connect(&test[i]);
++ if (test[i].connection & TEST_CONNECTION_NONE)
++ mysql= NULL;
++
++ /* run test */
++ rc= test[i].function(mysql);
++
++ if (rc == SKIP)
++ skip(1, "%s", test[i].name);
++ else
++ ok(rc == OK, "%s", test[i].name);
++
++ /* if test failed, close and reopen default connection to prevent
++ errors for further tests */
++ if ((rc == FAIL || mysql_errno(mysql_default)) && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
++ mysql_close(mysql_default);
++ mysql_default= test_connect(&test[i]);
++ }
++ /* clear connection: reset default connection or close extra connection */
++ else if (mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
++ if (reset_connection(mysql))
++ return; /* default doesn't work anymore */
++ }
++ else if (mysql && !(test[i].connection & TEST_CONNECTION_DONT_CLOSE))
++ mysql_close(mysql);
++ } else {
++ skip(1, "%s", test[i].skipmsg);
++ }
++ }
++ if (mysql_default) {
++ mysql_close(mysql_default);
++ }
++ mysql_server_end();
++}
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/ps_bugs.c mariadb-native-client.trunk/unittest/libmariadb/ps_bugs.c
+--- mariadb/unittest/libmariadb/ps_bugs.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/ps_bugs.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,3871 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++#define MY_INT64_NUM_DECIMAL_DIGITS 21
++#define MAX_INDEXES 64
++
++/* A workaround for Sun Forte 5.6 on Solaris x86 */
++
++static int cmp_double(double *a, double *b)
++{
++ return *a == *b;
++ return OK;
++}
++
++/* Test BUG#1115 (incorrect string parameter value allocation) */
++
++static int test_bug1115(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, rowcount;
++ MYSQL_BIND my_bind[1];
++ ulong length[1];
++ char szData[11];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(\
++session_id char(9) NOT NULL, \
++ a int(8) unsigned NOT NULL, \
++ b int(5) NOT NULL, \
++ c int(5) NOT NULL, \
++ d datetime NOT NULL)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
++ "(\"abc\", 1, 2, 3, 2003-08-30), "
++ "(\"abd\", 1, 2, 3, 2003-08-30), "
++ "(\"abf\", 1, 2, 3, 2003-08-30), "
++ "(\"abg\", 1, 2, 3, 2003-08-30), "
++ "(\"abh\", 1, 2, 3, 2003-08-30), "
++ "(\"abj\", 1, 2, 3, 2003-08-30), "
++ "(\"abk\", 1, 2, 3, 2003-08-30), "
++ "(\"abl\", 1, 2, 3, 2003-08-30), "
++ "(\"abq\", 1, 2, 3, 2003-08-30) ");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
++ "(\"abw\", 1, 2, 3, 2003-08-30), "
++ "(\"abe\", 1, 2, 3, 2003-08-30), "
++ "(\"abr\", 1, 2, 3, 2003-08-30), "
++ "(\"abt\", 1, 2, 3, 2003-08-30), "
++ "(\"aby\", 1, 2, 3, 2003-08-30), "
++ "(\"abu\", 1, 2, 3, 2003-08-30), "
++ "(\"abi\", 1, 2, 3, 2003-08-30), "
++ "(\"abo\", 1, 2, 3, 2003-08-30), "
++ "(\"abp\", 1, 2, 3, 2003-08-30), "
++ "(\"abz\", 1, 2, 3, 2003-08-30), "
++ "(\"abx\", 1, 2, 3, 2003-08-30)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT * FROM test_select WHERE "
++ "CONVERT(session_id USING utf8)= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
++
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++
++ strcpy(szData, (char *)"abc");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 3;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount=%d != 1");
++
++ strcpy(szData, (char *)"venu");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 4;
++ my_bind[0].is_null= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 0, "rowcount != 0");
++
++ strcpy(szData, (char *)"abc");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 3;
++ my_bind[0].is_null= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++/* Test BUG#1180 (optimized away part of WHERE clause) */
++
++static int test_bug1180(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, rowcount;
++ MYSQL_BIND my_bind[1];
++ ulong length[1];
++ char szData[11];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(session_id char(9) NOT NULL)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES (\"abc\")");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT * FROM test_select WHERE ?= \"1111\" and "
++ "session_id= \"abc\"");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
++
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++
++ strcpy(szData, (char *)"abc");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 3;
++ my_bind[0].is_null= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 0, "rowcount != 0");
++
++ strcpy(szData, (char *)"1111");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 4;
++ my_bind[0].is_null= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++
++ strcpy(szData, (char *)"abc");
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)szData;
++ my_bind[0].buffer_length= 10;
++ my_bind[0].length= &length[0];
++ length[0]= 3;
++ my_bind[0].is_null= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 0, "rowcount != 0");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++
++/*
++ Test BUG#1644 (Insertion of more than 3 NULL columns with parameter
++ binding fails)
++*/
++
++static int test_bug1644(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ MYSQL_ROW row;
++ MYSQL_BIND my_bind[4];
++ int num;
++ my_bool isnull;
++ int rc, i;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS foo_dfr");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "CREATE TABLE foo_dfr(col1 int, col2 int, col3 int, col4 int);");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO foo_dfr VALUES (?, ?, ?, ? )");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 4, "Paramcount != 4");
++
++ memset(my_bind, '\0', sizeof(MYSQL_BIND) * 4);
++
++ num= 22;
++ isnull= 0;
++ for (i= 0 ; i < 4 ; i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[i].buffer= (void *)&num;
++ my_bind[i].is_null= &isnull;
++ }
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ isnull= 1;
++ for (i= 0 ; i < 4 ; i++)
++ my_bind[i].is_null= &isnull;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ isnull= 0;
++ num= 88;
++ for (i= 0 ; i < 4 ; i++)
++ my_bind[i].is_null= &isnull;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "SELECT * FROM foo_dfr");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid resultset");
++
++ FAIL_IF(mysql_num_rows(result) != 3, "rowcount != 3");
++
++ mysql_data_seek(result, 0);
++
++ row= mysql_fetch_row(result);
++ FAIL_IF(!row, "row = NULL");
++ for (i= 0 ; i < 4 ; i++)
++ {
++ FAIL_UNLESS(strcmp(row[i], "22") == 0, "Wrong value");
++ }
++ row= mysql_fetch_row(result);
++ FAIL_IF(!row, "Invalid row");
++ for (i= 0 ; i < 4 ; i++)
++ {
++ FAIL_UNLESS(row[i] == 0, "row[i] != 0");
++ }
++ row= mysql_fetch_row(result);
++ FAIL_IF(!row, "Invalid row");
++ for (i= 0 ; i < 4 ; i++)
++ {
++ FAIL_UNLESS(strcmp(row[i], "88") == 0, "row[i] != 88");
++ }
++ row= mysql_fetch_row(result);
++ FAIL_IF(row, "row != NULL");
++
++ mysql_free_result(result);
++
++ return OK;
++}
++
++static int test_bug11037(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *stmt_text;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (id int not null)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (1)");
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "select id FROM t1";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ /* expected error */
++ rc = mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc==1, "Error expedted");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */
++
++static int test_bug11183(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ char bug_statement[]= "insert into t1 values (1)";
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, bug_statement, strlen(bug_statement));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ /* Trying to execute statement that should fail on execute stage */
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_reset(stmt);
++ FAIL_IF(!mysql_stmt_errno(stmt) == 0, "stmt->error != 0");
++
++ rc= mysql_query(mysql, "create table t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ /* Trying to execute statement that should pass ok */
++ if (mysql_stmt_execute(stmt))
++ {
++ mysql_stmt_reset(stmt);
++ FAIL_IF(mysql_stmt_errno(stmt) == 0, "stmt->error != 0");
++ }
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug12744(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt = NULL;
++ int rc;
++
++ stmt = mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SET @a:=1", 9);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* set reconnect, kill and ping to reconnect */
++ rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_kill(mysql, mysql_thread_id(mysql));
++ //check_mysql_rc(rc, mysql);
++
++ sleep(2);
++ rc= mysql_ping(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_close(stmt);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug1500(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[3];
++ int rc;
++ int32 int_data[3]= {2, 3, 4};
++ const char *data;
++ const char *query;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (i INT)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bg1500 VALUES (1), (2)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ query= "SELECT i FROM test_bg1500 WHERE i IN (?, ?, ?)";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "paramcount != 3");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)int_data;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[2]= my_bind[1]= my_bind[0];
++ my_bind[1].buffer= (void *)(int_data + 1);
++ my_bind[2].buffer= (void *)(int_data + 2);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE test_bg1500");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (s VARCHAR(25), FULLTEXT(s)) engine=MyISAM");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "INSERT INTO test_bg1500 VALUES ('Gravedigger'), ('Greed'), ('Hollow Dogs')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (?)";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");
++
++ data= "Dogs";
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *) data;
++ my_bind[0].buffer_length= strlen(data);
++ my_bind[0].is_null= 0;
++ my_bind[0].length= 0;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ /* This should work too */
++ query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (CONCAT(?, 'digger'))";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");
++
++ data= "Grave";
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *) data;
++ my_bind[0].buffer_length= strlen(data);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug15510(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *query= "select 1 from dual where 1/0";
++
++
++ rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(mysql_warning_count(mysql), "Warning expected");
++
++ /* Cleanup */
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "set @@sql_mode=''");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug #15518 - Reusing a stmt that has failed during prepare
++ does not clear error
++*/
++
++static int test_bug15518(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++
++ stmt= mysql_stmt_init(mysql);
++
++ /*
++ The prepare of foo should fail with errno 1064 since
++ it's not a valid query
+ */
- mysql_stmt_close(stmt);
-
- mysql_query(mysql, "DROP TABLE test_pure");
-@@ -3042,7 +3045,7 @@
- rc= mysql_stmt_execute(stmt);
- check_stmt_rc(rc, stmt);
-
-- FAIL_IF(mysql_warning_count(mysql) != 12, "warning count != 12");
-+ FAIL_IF(mysql_warning_count(mysql) != 6, "warning count != 6");
-
- if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
- goto error;
-@@ -3080,7 +3083,7 @@
-
- rc= mysql_stmt_execute(stmt);
- check_stmt_rc(rc, stmt);
-- FAIL_IF(mysql_warning_count(mysql) != 6, "warning count != 6");
-+ FAIL_IF(mysql_warning_count(mysql) != 3, "warning count != 3");
-
- if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
- goto error;
-@@ -4608,8 +4611,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
-+ if (argc > 1)
-+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/ps_bugs.c'
---- mariadb/unittest/libmysql/ps_bugs.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/ps_bugs.c 2013-03-14 21:01:43 +0000
-@@ -2885,6 +2885,7 @@
- check_mysql_rc(rc, mysql);
- query_result= mysql_store_result(mysql);
- query_field_list= mysql_fetch_fields(query_result);
++ rc= mysql_stmt_prepare(stmt, "foo", 3);
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
++
++ /*
++ Use the same stmt and reprepare with another query that
++ suceeds
++ */
++ rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
++ FAIL_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql), "Error expected");
++
++ rc= mysql_stmt_close(stmt);
++ check_mysql_rc(rc, mysql);
++ /*
++ part2, when connection to server has been closed
++ after first prepare
++ */
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, "foo", 3);
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
++
++ /* Close connection to server */
++ mysql_close(mysql);
++
++ /*
++ Use the same stmt and reprepare with another query that
++ suceeds. The prepare should fail with error 2013 since
++ connection to server has been closed.
++ */
++ rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/*
++ Bug #15613: "libmysqlclient API function mysql_stmt_prepare returns wrong
++ field length"
++*/
++
++static int test_bug15613(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ MYSQL_RES *metadata;
++ MYSQL_FIELD *field;
++ int rc;
++
++ /* I. Prepare the table */
++ rc= mysql_query(mysql, "set names latin1");
++ check_mysql_rc(rc, mysql);
++ mysql_query(mysql, "drop table if exists t1");
++ rc= mysql_query(mysql,
++ "create table t1 (t text character set utf8, "
++ "tt tinytext character set utf8, "
++ "mt mediumtext character set utf8, "
++ "lt longtext character set utf8, "
++ "vl varchar(255) character set latin1,"
++ "vb varchar(255) character set binary,"
++ "vu varchar(255) character set utf8)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++
++ /* II. Check SELECT metadata */
++ stmt_text= ("select t, tt, mt, lt, vl, vb, vu from t1");
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ metadata= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_fields(metadata);
++ FAIL_UNLESS(field[0].length == 65535, "length != 65535");
++ FAIL_UNLESS(field[1].length == 255, "length != 244");
++ FAIL_UNLESS(field[2].length == 16777215, "length != 166777215");
++ FAIL_UNLESS(field[3].length == 4294967295UL, "length != 4294967295UL");
++ FAIL_UNLESS(field[4].length == 255, "length != 255");
++ FAIL_UNLESS(field[5].length == 255, "length != 255");
++ FAIL_UNLESS(field[6].length == 255, "length != 255");
++ mysql_free_result(metadata);
++ mysql_stmt_free_result(stmt);
++
++ /* III. Cleanup */
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "set names default");
++ check_mysql_rc(rc, mysql);
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug16144(MYSQL *mysql)
++{
++ const my_bool flag_orig= (my_bool) 0xde;
++ my_bool flag= flag_orig;
++ MYSQL_STMT *stmt;
++
++ /* Check that attr_get returns correct data on little and big endian CPUs */
++ stmt= mysql_stmt_init(mysql);
++ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void*) &flag);
++ mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &flag);
++ FAIL_UNLESS(flag == flag_orig, "flag != flag_orig");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/*
++ This tests for various mysql_stmt_send_long_data bugs described in #1664
++*/
++
++static int test_bug1664(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, int_data;
++ const char *data;
++ const char *str_data= "Simple string";
++ MYSQL_BIND my_bind[2];
++ const char *query= "INSERT INTO test_long_data(col2, col1) VALUES(?, ?)";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, col2 long varchar)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Param count != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)str_data;
++ my_bind[0].buffer_length= strlen(str_data);
++
++ my_bind[1].buffer= (void *)&int_data;
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ int_data= 1;
++
++ /*
++ Let us supply empty long_data. This should work and should
++ not break following execution.
++ */
++ data= "";
++ rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ if (verify_col_data(mysql, "test_long_data", "col1", "1"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", ""))
++ goto error;
++ rc= mysql_query(mysql, "DELETE FROM test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ /* This should pass OK */
++ data= (char *)"Data";
++ rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ if (verify_col_data(mysql, "test_long_data", "col1", "1"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", "Data"))
++ goto error;
++
++ /* clean up */
++ rc= mysql_query(mysql, "DELETE FROM test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ /*
++ Now we are changing int parameter and don't do anything
++ with first parameter. Second mysql_stmt_execute() should run
++ OK treating this first parameter as string parameter.
++ */
++
++ int_data= 2;
++ /* execute */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ if (verify_col_data(mysql, "test_long_data", "col1", "2"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", str_data))
++ goto error;
++
++ /* clean up */
++ rc= mysql_query(mysql, "DELETE FROM test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ /*
++ Now we are sending other long data. It should not be
++ concatened to previous.
++ */
++
++ data= (char *)"SomeOtherData";
++ rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ if (verify_col_data(mysql, "test_long_data", "col1", "2"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", "SomeOtherData"))
++ goto error;
++
++ mysql_stmt_close(stmt);
++
++ /* clean up */
++ rc= mysql_query(mysql, "DELETE FROM test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ /* Now let us test how mysql_stmt_reset works. */
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ data= (char *)"SomeData";
++ rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ if (verify_col_data(mysql, "test_long_data", "col1", "2"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", str_data))
++ goto error;
++
++ mysql_stmt_close(stmt);
++
++ /* Final clean up */
++ rc= mysql_query(mysql, "DROP TABLE test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++
++error:
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "DROP TABLE test_long_data");
++ return FAIL;
++}
++/* Test a misc bug */
++
++static int test_ushort_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[4];
++ ushort short_value;
++ uint32 long_value;
++ ulong s_length, l_length, ll_length, t_length;
++ ulonglong longlong_value;
++ int rc;
++ uchar tiny_value;
++ const char *query= "SELECT * FROM test_ushort";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_ushort(a smallint unsigned, \
++ b smallint unsigned, \
++ c smallint unsigned, \
++ d smallint unsigned)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[0].buffer= (void *)&short_value;
++ my_bind[0].is_unsigned= TRUE;
++ my_bind[0].length= &s_length;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[1].buffer= (void *)&long_value;
++ my_bind[1].length= &l_length;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[2].buffer= (void *)&longlong_value;
++ my_bind[2].length= &ll_length;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[3].buffer= (void *)&tiny_value;
++ my_bind[3].is_unsigned= TRUE;
++ my_bind[3].length= &t_length;
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(short_value == 35999, "short_value != 35999");
++ FAIL_UNLESS(s_length == 2, "length != 2");
++
++ FAIL_UNLESS(long_value == 35999, "long_value != 35999");
++ FAIL_UNLESS(l_length == 4, "length != 4");
++
++ FAIL_UNLESS(longlong_value == 35999, "longlong_value != 35999");
++ FAIL_UNLESS(ll_length == 8, "length != 8");
++
++ FAIL_UNLESS(tiny_value == 200, "tiny_value != 200");
++ FAIL_UNLESS(t_length == 1, "length != 1");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug1946(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *query= "INSERT INTO prepare_command VALUES (?)";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS prepare_command");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, "CREATE TABLE prepare_command(ID INT)");
++ check_mysql_rc(rc, mysql)
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_real_query(mysql, query, strlen(query));
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "DROP TABLE prepare_command");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug20152(MYSQL *mysql)
++{
++ MYSQL_BIND my_bind[1];
++ MYSQL_STMT *stmt;
++ MYSQL_TIME tm;
++ int rc;
++ const char *query= "INSERT INTO t1 (f1) VALUES (?)";
++
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_DATE;
++ my_bind[0].buffer= (void*)&tm;
++
++ tm.year = 2006;
++ tm.month = 6;
++ tm.day = 18;
++ tm.hour = 14;
++ tm.minute = 9;
++ tm.second = 42;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql)
++ rc= mysql_query(mysql, "CREATE TABLE t1 (f1 DATE)");
++ check_mysql_rc(rc, mysql)
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql)
++ FAIL_UNLESS(tm.hour == 14 && tm.minute == 9 && tm.second == 42, "time != 14:09:42");
++ return OK;
++}
++
++static int test_bug2247(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *res;
++ int rc;
++ int i;
++ const char *create= "CREATE TABLE bug2247(id INT UNIQUE AUTO_INCREMENT)";
++ const char *insert= "INSERT INTO bug2247 VALUES (NULL)";
++ const char *SELECT= "SELECT id FROM bug2247";
++ const char *update= "UPDATE bug2247 SET id=id+10";
++ const char *drop= "DROP TABLE IF EXISTS bug2247";
++ ulonglong exp_count;
++ enum { NUM_ROWS= 5 };
++
++
++ /* create table and insert few rows */
++ rc= mysql_query(mysql, drop);
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, create);
++ check_mysql_rc(rc, mysql)
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, insert, strlen(insert));
++ check_stmt_rc(rc, stmt);
++ for (i= 0; i < NUM_ROWS; ++i)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++ exp_count= mysql_stmt_affected_rows(stmt);
++ FAIL_UNLESS(exp_count == 1, "exp_count != 1");
++
++ rc= mysql_query(mysql, SELECT);
++ check_mysql_rc(rc, mysql)
++ /*
++ mysql_store_result overwrites mysql->affected_rows. Check that
++ mysql_stmt_affected_rows() returns the same value, whereas
++ mysql_affected_rows() value is correct.
++ */
++ res= mysql_store_result(mysql);
++ FAIL_IF(!res, "Invalid result set");
++
++ FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
++ FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
++
++ rc= mysql_query(mysql, update);
++ check_mysql_rc(rc, mysql)
++ FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
++ FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
++
++ mysql_free_result(res);
++ mysql_stmt_close(stmt);
++
++ /* check that mysql_stmt_store_result modifies mysql_stmt_affected_rows */
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, SELECT, strlen(SELECT));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt); rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt); exp_count= mysql_stmt_affected_rows(stmt);
++ FAIL_UNLESS(exp_count == NUM_ROWS, "exp_count != NUM_ROWS");
++
++ rc= mysql_query(mysql, insert);
++ check_mysql_rc(rc, mysql)
++ FAIL_UNLESS(mysql_affected_rows(mysql) == 1, "affected_rows != 1");
++ FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/*
++ Test for bug#2248 "mysql_fetch without prior mysql_stmt_execute hangs"
++*/
++
++static int test_bug2248(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *query1= "SELECT DATABASE()";
++ const char *query2= "INSERT INTO test_bug2248 VALUES (10)";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bug2248");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bug2248 (id int)");
++ check_mysql_rc(rc, mysql)
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query1, strlen(query1));
++ check_stmt_rc(rc, stmt);
++
++ /* This should not hang */
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ /* And this too */
++ rc= mysql_stmt_store_result(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query2, strlen(query2));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* This too should not hang but should return proper error */
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 1, "rc != 1");
++
++ /* This too should not hang but should not bark */
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++ /* This should return proper error */
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 1, "rc != 1");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE test_bug2248");
++ check_mysql_rc(rc, mysql)
++ return OK;
++}
++
++/*
++ BUG#23383: mysql_affected_rows() returns different values than
++ mysql_stmt_affected_rows()
++
++ Test that both mysql_affected_rows() and mysql_stmt_affected_rows()
++ return -1 on error, 0 when no rows were affected, and (positive) row
++ count when some rows were affected.
++*/
++static int test_bug23383(MYSQL *mysql)
++{
++ const char *insert_query= "INSERT INTO t1 VALUES (1), (2)";
++ const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3";
++ MYSQL_STMT *stmt;
++ my_ulonglong row_count;
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, insert_query);
++ check_mysql_rc(rc, mysql);
++ row_count= mysql_affected_rows(mysql);
++ FAIL_UNLESS(row_count == 2, "row_count != 2");
++
++ rc= mysql_query(mysql, insert_query);
++ FAIL_IF(!rc, "Error expected");
++ row_count= mysql_affected_rows(mysql);
++ FAIL_UNLESS(row_count == (my_ulonglong)-1, "rowcount != -1");
++
++ rc= mysql_query(mysql, update_query);
++ check_mysql_rc(rc, mysql);
++ row_count= mysql_affected_rows(mysql);
++ FAIL_UNLESS(row_count == 0, "");
++
++ rc= mysql_query(mysql, "DELETE FROM t1");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++
++ rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ row_count= mysql_stmt_affected_rows(stmt);
++ FAIL_UNLESS(row_count == 2, "row_count != 2");
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_UNLESS(rc != 0, "");
++ row_count= mysql_stmt_affected_rows(stmt);
++ FAIL_UNLESS(row_count == (my_ulonglong)-1, "rowcount != -1");
++
++ rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ row_count= mysql_stmt_affected_rows(stmt);
++ FAIL_UNLESS(row_count == 0, "rowcount != 0");
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Bug#27592 (stack overrun when storing datetime value using prepared statements)
++*/
++
++static int test_bug27592(MYSQL *mysql)
++{
++ const int NUM_ITERATIONS= 40;
++ int i;
++ int rc;
++ MYSQL_STMT *stmt= NULL;
++ MYSQL_BIND bind[1];
++ MYSQL_TIME time_val;
++
++ mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ mysql_query(mysql, "CREATE TABLE t1(c2 DATETIME)");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "INSERT INTO t1 VALUES (?)", strlen("INSERT INTO t1 VALUES (?)"));
++ check_stmt_rc(rc, stmt);
++
++ memset(bind, '\0', sizeof(bind));
++
++ bind[0].buffer_type= MYSQL_TYPE_DATETIME;
++ bind[0].buffer= (char *) &time_val;
++ bind[0].length= NULL;
++
++ for (i= 0; i < NUM_ITERATIONS; i++)
++ {
++ time_val.year= 2007;
++ time_val.month= 6;
++ time_val.day= 7;
++ time_val.hour= 18;
++ time_val.minute= 41;
++ time_val.second= 3;
++
++ time_val.second_part=0;
++ time_val.neg=0;
++
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/*
++ Bug#28934: server crash when receiving malformed com_execute packets
++*/
++
++static int test_bug28934(MYSQL *mysql)
++{
++ my_bool error= 0;
++ MYSQL_BIND bind[5];
++ MYSQL_STMT *stmt;
++ int rc, cnt;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1(id int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values(1),(2),(3),(4),(5)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select * from t1 where id in(?,?,?,?,?)", strlen("select * from t1 where id in(?,?,?,?,?)"));
++ check_stmt_rc(rc, stmt);
++
++ memset (&bind, '\0', sizeof (bind));
++ for (cnt= 0; cnt < 5; cnt++)
++ {
++ bind[cnt].buffer_type= MYSQL_TYPE_LONG;
++ bind[cnt].buffer= (char*)&cnt;
++ bind[cnt].buffer_length= 0;
++ }
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ stmt->param_count=2;
++ error= mysql_stmt_execute(stmt);
++ FAIL_UNLESS(error != 0, "Error expected");
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug3035(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ MYSQL_BIND bind_array[12], *my_bind= bind_array, *bind_end= my_bind + 12;
++ int8 int8_val;
++ uint8 uint8_val;
++ int16 int16_val;
++ uint16 uint16_val;
++ int32 int32_val;
++ uint32 uint32_val;
++ longlong int64_val;
++ ulonglong uint64_val;
++ double double_val, udouble_val, double_tmp;
++ char longlong_as_string[22], ulonglong_as_string[22];
++
++ /* mins and maxes */
++ const int8 int8_min= -128;
++ const int8 int8_max= 127;
++ const uint8 uint8_min= 0;
++ const uint8 uint8_max= 255;
++
++ const int16 int16_min= -32768;
++ const int16 int16_max= 32767;
++ const uint16 uint16_min= 0;
++ const uint16 uint16_max= 65535;
++
++ const int32 int32_max= 2147483647L;
++ const int32 int32_min= -int32_max - 1;
++ const uint32 uint32_min= 0;
++ const uint32 uint32_max= 4294967295U;
++
++ /* it might not work okay everyplace */
++ const longlong int64_max= 9223372036854775807LL;
++ const longlong int64_min= -int64_max - 1;
++
++ const ulonglong uint64_min= 0U;
++ const ulonglong uint64_max= 18446744073709551615ULL;
++
++ const char *stmt_text;
++
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "CREATE TABLE t1 (i8 TINYINT, ui8 TINYINT UNSIGNED, "
++ "i16 SMALLINT, ui16 SMALLINT UNSIGNED, "
++ "i32 INT, ui32 INT UNSIGNED, "
++ "i64 BIGINT, ui64 BIGINT UNSIGNED, "
++ "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ memset(bind_array, '\0', sizeof(bind_array));
++ for (my_bind= bind_array; my_bind < bind_end; my_bind++)
++ my_bind->error= &my_bind->error_value;
++
++ bind_array[0].buffer_type= MYSQL_TYPE_TINY;
++ bind_array[0].buffer= (void *) &int8_val;
++
++ bind_array[1].buffer_type= MYSQL_TYPE_TINY;
++ bind_array[1].buffer= (void *) &uint8_val;
++ bind_array[1].is_unsigned= 1;
++
++ bind_array[2].buffer_type= MYSQL_TYPE_SHORT;
++ bind_array[2].buffer= (void *) &int16_val;
++
++ bind_array[3].buffer_type= MYSQL_TYPE_SHORT;
++ bind_array[3].buffer= (void *) &uint16_val;
++ bind_array[3].is_unsigned= 1;
++
++ bind_array[4].buffer_type= MYSQL_TYPE_LONG;
++ bind_array[4].buffer= (void *) &int32_val;
++
++ bind_array[5].buffer_type= MYSQL_TYPE_LONG;
++ bind_array[5].buffer= (void *) &uint32_val;
++ bind_array[5].is_unsigned= 1;
++
++ bind_array[6].buffer_type= MYSQL_TYPE_LONGLONG;
++ bind_array[6].buffer= (void *) &int64_val;
++
++ bind_array[7].buffer_type= MYSQL_TYPE_LONGLONG;
++ bind_array[7].buffer= (void *) &uint64_val;
++ bind_array[7].is_unsigned= 1;
++
++ stmt= mysql_stmt_init(mysql);
++ check_stmt_rc(rc, stmt);
++
++ stmt_text= "INSERT INTO t1 (i8, ui8, i16, ui16, i32, ui32, i64, ui64) "
++ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_bind_param(stmt, bind_array);
++
++ int8_val= int8_min;
++ uint8_val= uint8_min;
++ int16_val= int16_min;
++ uint16_val= uint16_min;
++ int32_val= int32_min;
++ uint32_val= uint32_min;
++ int64_val= int64_min;
++ uint64_val= uint64_min;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ int8_val= int8_max;
++ uint8_val= uint8_max;
++ int16_val= int16_max;
++ uint16_val= uint16_max;
++ int32_val= int32_max;
++ uint32_val= uint32_max;
++ int64_val= int64_max;
++ uint64_val= uint64_max;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ stmt_text= "SELECT i8, ui8, i16, ui16, i32, ui32, i64, ui64, ui64, "
++ "cast(ui64 as signed), ui64, cast(ui64 as signed)"
++ "FROM t1 ORDER BY id ASC";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ bind_array[8].buffer_type= MYSQL_TYPE_DOUBLE;
++ bind_array[8].buffer= (void *) &udouble_val;
++
++ bind_array[9].buffer_type= MYSQL_TYPE_DOUBLE;
++ bind_array[9].buffer= (void *) &double_val;
++
++ bind_array[10].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[10].buffer= (void *) &ulonglong_as_string;
++ bind_array[10].buffer_length= sizeof(ulonglong_as_string);
++
++ bind_array[11].buffer_type= MYSQL_TYPE_STRING;
++ bind_array[11].buffer= (void *) &longlong_as_string;
++ bind_array[11].buffer_length= sizeof(longlong_as_string);
++
++ mysql_stmt_bind_result(stmt, bind_array);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(int8_val == int8_min, "int8_val != int8_min");
++ FAIL_UNLESS(uint8_val == uint8_min, "uint8_val != uint8_min");
++ FAIL_UNLESS(int16_val == int16_min, "int16_val != int16_min");
++ FAIL_UNLESS(uint16_val == uint16_min, "uint16_val != uint16_min");
++ FAIL_UNLESS(int32_val == int32_min, "int32_val != int32_min");
++ FAIL_UNLESS(uint32_val == uint32_min, "uint32_val != uint32_min");
++ FAIL_UNLESS(int64_val == int64_min, "int64_val != int64_min");
++ FAIL_UNLESS(uint64_val == uint64_min, "uint64_val != uint64_min");
++ FAIL_UNLESS(double_val == (longlong) uint64_min, "double_val != uint64_min");
++ double_tmp= ulonglong2double(uint64_val);
++ FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
++ FAIL_UNLESS(!strcmp(longlong_as_string, "0"), "longlong_as_string != '0'");
++ FAIL_UNLESS(!strcmp(ulonglong_as_string, "0"), "ulonglong_as_string != '0'");
++
++ rc= mysql_stmt_fetch(stmt);
++
++ FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED || rc == 0, "rc != 0,MYSQL_DATA_TRUNCATED");
++
++ FAIL_UNLESS(int8_val == int8_max, "int8_val != int8_max");
++ FAIL_UNLESS(uint8_val == uint8_max, "uint8_val != uint8_max");
++ FAIL_UNLESS(int16_val == int16_max, "int16_val != int16_max");
++ FAIL_UNLESS(uint16_val == uint16_max, "uint16_val != uint16_max");
++ FAIL_UNLESS(int32_val == int32_max, "int32_val != int32_max");
++ FAIL_UNLESS(uint32_val == uint32_max, "uint32_val != uint32_max");
++ FAIL_UNLESS(int64_val == int64_max, "int64_val != int64_max");
++ FAIL_UNLESS(uint64_val == uint64_max, "uint64_val != uint64_max");
++ FAIL_UNLESS(double_val == (longlong) uint64_val, "double_val != uint64_val");
++ double_tmp= ulonglong2double(uint64_val);
++ FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
++ FAIL_UNLESS(!strcmp(longlong_as_string, "-1"), "longlong_as_string != '-1'");
++ FAIL_UNLESS(!strcmp(ulonglong_as_string, "18446744073709551615"), "ulonglong_as_string != '18446744073709551615'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
++
++ mysql_stmt_close(stmt);
++
++ stmt_text= "DROP TABLE t1";
++ mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ return OK;
++}
++
++/*
++ Test for BUG#3420 ("select id1, value1 from t where id= ? or value= ?"
++ returns all rows in the table)
++*/
++
++static int test_ps_conj_select(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ MYSQL_BIND my_bind[2];
++ int32 int_data;
++ char str_data[32];
++ unsigned long str_length;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
++ "value2 varchar(100), value1 varchar(100))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
++ "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "select id1, value1 from t1 where id1= ? or "
++ "CONVERT(value1 USING utf8)= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
++
++ /* Always bzero all members of bind parameter */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&int_data;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[1].buffer= (void *)str_data;
++ my_bind[1].buffer_length= array_elements(str_data);
++ my_bind[1].length= &str_length;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ int_data= 1;
++ strcpy(str_data, "hh");
++ str_length= strlen(str_data);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc=0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 3, "rc != 3");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test for NULL as PS parameter (BUG#3367, BUG#3371) */
++
++static int test_ps_null_param(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++
++ MYSQL_BIND in_bind;
++ my_bool in_is_null;
++ long int in_long;
++
++ MYSQL_BIND out_bind;
++ ulong out_length;
++ my_bool out_is_null;
++ char out_str_data[20];
++
++ const char *queries[]= {"select ?", "select ?+1",
++ "select col1 from test_ps_nulls where col1 <=> ?",
++ NULL
++ };
++ const char **cur_query= queries;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ps_nulls");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_ps_nulls(col1 int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_ps_nulls values (1), (null)");
++ check_mysql_rc(rc, mysql);
++
++ /* Always bzero all members of bind parameter */
++ memset(&in_bind, '\0', sizeof(in_bind));
++ memset(&out_bind, '\0', sizeof(out_bind));
++ in_bind.buffer_type= MYSQL_TYPE_LONG;
++ in_bind.is_null= &in_is_null;
++ in_bind.length= 0;
++ in_bind.buffer= (void *)&in_long;
++ in_is_null= 1;
++ in_long= 1;
++
++ out_bind.buffer_type= MYSQL_TYPE_STRING;
++ out_bind.is_null= &out_is_null;
++ out_bind.length= &out_length;
++ out_bind.buffer= out_str_data;
++ out_bind.buffer_length= array_elements(out_str_data);
++
++ /* Execute several queries, all returning NULL in result. */
++ for(cur_query= queries; *cur_query; cur_query++)
++ {
++ char query[MAX_TEST_QUERY_LENGTH];
++ strcpy(query, *cur_query);
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
++
++ rc= mysql_stmt_bind_param(stmt, &in_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_result(stmt, &out_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc != MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ FAIL_UNLESS(out_is_null, "!out_is_null");
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ mysql_stmt_close(stmt);
++ }
++ return OK;
++}
++
++/*
++ utility for the next test; expects 3 rows in the result from a SELECT,
++ compares each row/field with an expected value.
++ */
++#define test_ps_query_cache_result(i1,s1,l1,i2,s2,l2,i3,s3,l3) \
++ r_metadata= mysql_stmt_result_metadata(stmt); \
++ FAIL_UNLESS(r_metadata != NULL, ""); \
++ rc= mysql_stmt_fetch(stmt); \
++ check_stmt_rc(rc,stmt); \
++ FAIL_UNLESS((r_int_data == i1) && (r_str_length == l1) && \
++ (strcmp(r_str_data, s1) == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt); \
++ check_stmt_rc(rc,stmt); \
++ FAIL_UNLESS((r_int_data == i2) && (r_str_length == l2) && \
++ (strcmp(r_str_data, s2) == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt); \
++ check_stmt_rc(rc,stmt); \
++ FAIL_UNLESS((r_int_data == i3) && (r_str_length == l3) && \
++ (strcmp(r_str_data, s3) == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt); \
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA"); \
++ mysql_free_result(r_metadata);
++
++/* reads Qcache_hits from server and returns its value */
++static int query_cache_hits(MYSQL *mysql)
++{
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ int rc;
++ uint result;
++
++ rc= mysql_query(mysql, "show status like 'qcache_hits'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_use_result(mysql);
++
++ row= mysql_fetch_row(res);
++
++ result= atoi(row[1]);
++ mysql_free_result(res);
++ return result;
++}
++
++
++/*
++ Test that prepared statements make use of the query cache just as normal
++ statements (BUG#735).
++*/
++static int test_ps_query_cache(MYSQL *mysql)
++{
++ MYSQL *lmysql= mysql;
++ MYSQL_STMT *stmt;
++ int rc;
++ MYSQL_BIND p_bind[2],r_bind[2]; /* p: param bind; r: result bind */
++ int32 p_int_data, r_int_data;
++ char p_str_data[32], r_str_data[32];
++ unsigned long p_str_length, r_str_length;
++ MYSQL_RES *r_metadata;
++ char query[MAX_TEST_QUERY_LENGTH];
++ uint hits1, hits2;
++ enum enum_test_ps_query_cache
++ {
++ /*
++ We iterate the same prepare/executes block, but have iterations where
++ we vary the query cache conditions.
++ */
++ /* the query cache is enabled for the duration of prep&execs: */
++ TEST_QCACHE_ON= 0,
++ /*
++ same but using a new connection (to see if qcache serves results from
++ the previous connection as it should):
++ */
++ TEST_QCACHE_ON_WITH_OTHER_CONN,
++ /*
++ First border case: disables the query cache before prepare and
++ re-enables it before execution (to test if we have no bug then):
++ */
++ TEST_QCACHE_OFF_ON,
++ /*
++ Second border case: enables the query cache before prepare and
++ disables it before execution:
++ */
++ TEST_QCACHE_ON_OFF
++ };
++ enum enum_test_ps_query_cache iteration;
++
++
++ /* prepare the table */
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
++ "value2 varchar(100), value1 varchar(100))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
++ "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
++ check_mysql_rc(rc, mysql);
++
++ for (iteration= TEST_QCACHE_ON; iteration <= TEST_QCACHE_ON_OFF; iteration++)
++ {
++ switch (iteration) {
++ case TEST_QCACHE_ON:
++ case TEST_QCACHE_ON_OFF:
++ rc= mysql_query(lmysql, "set global query_cache_size=1000000");
++ check_mysql_rc(rc, mysql);
++ break;
++ case TEST_QCACHE_OFF_ON:
++ rc= mysql_query(lmysql, "set global query_cache_size=0");
++ check_mysql_rc(rc, mysql);
++ break;
++ case TEST_QCACHE_ON_WITH_OTHER_CONN:
++ lmysql= test_connect(NULL);
++ FAIL_IF(!lmysql, "Opening new connection failed");
++ break;
++ }
++
++ strcpy(query, "select id1, value1 from t1 where id1= ? or "
++ "CONVERT(value1 USING utf8)= ?");
++ stmt= mysql_stmt_init(lmysql);
++ FAIL_IF(!stmt, mysql_error(lmysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
++
++ switch (iteration) {
++ case TEST_QCACHE_OFF_ON:
++ rc= mysql_query(lmysql, "set global query_cache_size=1000000");
++ check_mysql_rc(rc, mysql);
++ break;
++ case TEST_QCACHE_ON_OFF:
++ rc= mysql_query(lmysql, "set global query_cache_size=0");
++ check_mysql_rc(rc, mysql);
++ default:
++ break;
++ }
++
++ memset(p_bind, '\0', sizeof(p_bind));
++ p_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ p_bind[0].buffer= (void *)&p_int_data;
++ p_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ p_bind[1].buffer= (void *)p_str_data;
++ p_bind[1].buffer_length= array_elements(p_str_data);
++ p_bind[1].length= &p_str_length;
++
++ rc= mysql_stmt_bind_param(stmt, p_bind);
++ check_stmt_rc(rc, stmt);
++ p_int_data= 1;
++ strcpy(p_str_data, "hh");
++ p_str_length= strlen(p_str_data);
++
++ memset(r_bind, '\0', sizeof(r_bind));
++ r_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ r_bind[0].buffer= (void *)&r_int_data;
++ r_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ r_bind[1].buffer= (void *)r_str_data;
++ r_bind[1].buffer_length= array_elements(r_str_data);
++ r_bind[1].length= &r_str_length;
++
++ rc= mysql_stmt_bind_result(stmt, r_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++// test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
++ r_metadata= mysql_stmt_result_metadata(stmt);
++ FAIL_UNLESS(r_metadata != NULL, "");
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++ FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
++ (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++ FAIL_UNLESS((r_int_data == 2) && (r_str_length == 2) &&
++ (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc,stmt);
++ FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
++ (strcmp(r_str_data, "ii") == 0), "test_ps_query_cache_result failure"); \
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ mysql_free_result(r_metadata);
++
++
++ /* now retry with the same parameter values and see qcache hits */
++ hits1= query_cache_hits(lmysql);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt); test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
++ hits2= query_cache_hits(lmysql);
++ switch(iteration) {
++ case TEST_QCACHE_ON_WITH_OTHER_CONN:
++ case TEST_QCACHE_ON: /* should have hit */
++ FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1 + 1");
++ break;
++ case TEST_QCACHE_OFF_ON:
++ case TEST_QCACHE_ON_OFF: /* should not have hit */
++ FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
++ break;
++ }
++
++ /* now modify parameter values and see qcache hits */
++ strcpy(p_str_data, "ii");
++ p_str_length= strlen(p_str_data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
++ hits1= query_cache_hits(lmysql);
++
++ switch(iteration) {
++ case TEST_QCACHE_ON:
++ case TEST_QCACHE_OFF_ON:
++ case TEST_QCACHE_ON_OFF: /* should not have hit */
++ FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
++ break;
++ case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
++ FAIL_UNLESS(hits1-hits2 == 1, "hits2 != hits1+1");
++ break;
++ }
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
++ hits2= query_cache_hits(lmysql);
++
++ mysql_stmt_close(stmt);
++
++ switch(iteration) {
++ case TEST_QCACHE_ON: /* should have hit */
++ FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
++ break;
++ case TEST_QCACHE_OFF_ON:
++ case TEST_QCACHE_ON_OFF: /* should not have hit */
++ FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
++ break;
++ case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
++ FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
++ break;
++ }
++
++ } /* for(iteration=...) */
++
++ if (lmysql != mysql)
++ mysql_close(lmysql);
++
++ rc= mysql_query(mysql, "set global query_cache_size=0");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug3117(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND buffer;
++ longlong lii;
++ ulong length;
++ my_bool is_null;
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (id int auto_increment primary key)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT LAST_INSERT_ID()", strlen("SELECT LAST_INSERT_ID()"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ memset(&buffer, '\0', sizeof(buffer));
++ buffer.buffer_type= MYSQL_TYPE_LONGLONG;
++ buffer.buffer_length= sizeof(lii);
++ buffer.buffer= (void *)&lii;
++ buffer.length= &length;
++ buffer.is_null= &is_null;
++
++ rc= mysql_stmt_bind_result(stmt, &buffer);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(is_null == 0 && lii == 1, "is_null != 0 || lii != 1");
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(is_null == 0 && lii == 2, "is_null != 0 || lii != 2");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/**
++ Bug#36004 mysql_stmt_prepare resets the list of warnings
++*/
++
++static int test_bug36004(MYSQL *mysql)
++{
++ int rc, warning_count= 0;
++ MYSQL_STMT *stmt;
++
++
++ if (mysql_get_server_version(mysql) < 60000) {
++ diag("Test requires MySQL Server version 6.0 or above");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "drop table if exists inexistant");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_UNLESS(mysql_warning_count(mysql) == 1, "");
++ query_int_variable(mysql, "@@warning_count", &warning_count);
++ FAIL_UNLESS(warning_count, "Warning expected");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select 1", strlen("select 1"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
++ query_int_variable(mysql, "@@warning_count", &warning_count);
++ FAIL_UNLESS(warning_count, "warning expected");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
++ mysql_stmt_close(stmt);
++
++ query_int_variable(mysql, "@@warning_count", &warning_count);
++ FAIL_UNLESS(warning_count, "Warning expected");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "drop table if exists inexistant", strlen("drop table if exists inexistant"));
++ check_stmt_rc(rc, stmt);
++
++ query_int_variable(mysql, "@@warning_count", &warning_count);
++ FAIL_UNLESS(warning_count == 0, "No warning expected");
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug3796(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ const char *concat_arg0= "concat_with_";
++ enum { OUT_BUFF_SIZE= 30 };
++ char out_buff[OUT_BUFF_SIZE];
++ char canonical_buff[OUT_BUFF_SIZE];
++ ulong out_length;
++ const char *stmt_text;
++ int rc;
++
++
++ /* Create and fill test table */
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "CREATE TABLE t1 (a INT, b VARCHAR(30))";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "INSERT INTO t1 VALUES(1, 'ONE'), (2, 'TWO')";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ /* Create statement handle and prepare it with select */
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT concat(?, b) FROM t1";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ /* Bind input buffers */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *) concat_arg0;
++ my_bind[0].buffer_length= strlen(concat_arg0);
++
++ mysql_stmt_bind_param(stmt, my_bind);
++
++ /* Execute the select statement */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ my_bind[0].buffer= (void *) out_buff;
++ my_bind[0].buffer_length= OUT_BUFF_SIZE;
++ my_bind[0].length= &out_length;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ strcpy(canonical_buff, concat_arg0);
++ strcat(canonical_buff, "ONE");
++ FAIL_UNLESS(strlen(canonical_buff) == out_length &&
++ strncmp(out_buff, canonical_buff, out_length) == 0, "");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ strcpy(canonical_buff + strlen(concat_arg0), "TWO");
++ FAIL_UNLESS(strlen(canonical_buff) == out_length &&
++ strncmp(out_buff, canonical_buff, out_length) == 0, "");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug4026(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ MYSQL_TIME time_in, time_out;
++ MYSQL_TIME datetime_in, datetime_out;
++ const char *stmt_text;
++ int rc;
++
++
++ /* Check that microseconds are inserted and selected successfully */
++
++ /* Create a statement handle and prepare it with select */
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT ?, ?";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ /* Bind input buffers */
++ memset(my_bind, '\0', sizeof(my_bind));
++ memset(&time_in, '\0', sizeof(time_in));
++ memset(&time_out, '\0', sizeof(time_out));
++ memset(&datetime_in, '\0', sizeof(datetime_in));
++ memset(&datetime_out, '\0', sizeof(datetime_out));
++ my_bind[0].buffer_type= MYSQL_TYPE_TIME;
++ my_bind[0].buffer= (void *) &time_in;
++ my_bind[1].buffer_type= MYSQL_TYPE_DATETIME;
++ my_bind[1].buffer= (void *) &datetime_in;
++
++ time_in.hour= 23;
++ time_in.minute= 59;
++ time_in.second= 59;
++ time_in.second_part= 123456;
++ /*
++ This is not necessary, just to make DIE_UNLESS below work: this field
++ is filled in when time is received from server
++ */
++ time_in.time_type= MYSQL_TIMESTAMP_TIME;
++
++ datetime_in= time_in;
++ datetime_in.year= 2003;
++ datetime_in.month= 12;
++ datetime_in.day= 31;
++ datetime_in.time_type= MYSQL_TIMESTAMP_DATETIME;
++
++ mysql_stmt_bind_param(stmt, my_bind);
++
++ /* Execute the select statement */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ my_bind[0].buffer= (void *) &time_out;
++ my_bind[1].buffer= (void *) &datetime_out;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ FAIL_UNLESS(memcmp(&time_in, &time_out, sizeof(time_in)) == 0, "time_in != time_out");
++ FAIL_UNLESS(memcmp(&datetime_in, &datetime_out, sizeof(datetime_in)) == 0, "datetime_in != datetime_out");
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug4030(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[3];
++ MYSQL_TIME time_canonical, time_out;
++ MYSQL_TIME date_canonical, date_out;
++ MYSQL_TIME datetime_canonical, datetime_out;
++ const char *stmt_text;
++ int rc;
++
++
++ /* Check that microseconds are inserted and selected successfully */
++
++ /* Execute a query with time values in prepared mode */
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT '23:59:59.123456', '2003-12-31', "
++ "'2003-12-31 23:59:59.123456'";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* Bind output buffers */
++ memset(my_bind, '\0', sizeof(my_bind));
++ memset(&time_canonical, '\0', sizeof(time_canonical));
++ memset(&time_out, '\0', sizeof(time_out));
++ memset(&date_canonical, '\0', sizeof(date_canonical));
++ memset(&date_out, '\0', sizeof(date_out));
++ memset(&datetime_canonical, '\0', sizeof(datetime_canonical));
++ memset(&datetime_out, '\0', sizeof(datetime_out));
++ my_bind[0].buffer_type= MYSQL_TYPE_TIME;
++ my_bind[0].buffer= (void *) &time_out;
++ my_bind[1].buffer_type= MYSQL_TYPE_DATE;
++ my_bind[1].buffer= (void *) &date_out;
++ my_bind[2].buffer_type= MYSQL_TYPE_DATETIME;
++ my_bind[2].buffer= (void *) &datetime_out;
++
++ time_canonical.hour= 23;
++ time_canonical.minute= 59;
++ time_canonical.second= 59;
++ time_canonical.second_part= 123456;
++ time_canonical.time_type= MYSQL_TIMESTAMP_TIME;
++
++ date_canonical.year= 2003;
++ date_canonical.month= 12;
++ date_canonical.day= 31;
++ date_canonical.time_type= MYSQL_TIMESTAMP_DATE;
++
++ datetime_canonical= time_canonical;
++ datetime_canonical.year= 2003;
++ datetime_canonical.month= 12;
++ datetime_canonical.day= 31;
++ datetime_canonical.time_type= MYSQL_TIMESTAMP_DATETIME;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ FAIL_UNLESS(memcmp(&time_canonical, &time_out, sizeof(time_out)) == 0, "time_canonical != time_out");
++ FAIL_UNLESS(memcmp(&date_canonical, &date_out, sizeof(date_out)) == 0, "date_canoncical != date_out");
++ FAIL_UNLESS(memcmp(&datetime_canonical, &datetime_out, sizeof(datetime_out)) == 0, "datetime_canonical != datetime_out");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug4079(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ const char *stmt_text;
++ uint32 res;
++ int rc;
++
++ /* Create and fill table */
++ mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ mysql_query(mysql, "CREATE TABLE t1 (a int)");
++ mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2)");
++
++ /* Prepare erroneous statement */
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT 1 < (SELECT a FROM t1)";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ /* Execute the select statement */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* Bind input buffers */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *) &res;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 1, "rc != 1");
++ /* buggy version of libmysql hanged up here */
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug4172(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[3];
++ const char *stmt_text;
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ int rc;
++ char f[100], d[100], e[100];
++ ulong f_len, d_len, e_len;
++
++ diag("numeric precision in ps not fixed now");
++ return SKIP;
++
++
++ mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ mysql_query(mysql, "CREATE TABLE t1 (f float, d double, e decimal(10,4))");
++ mysql_query(mysql, "INSERT INTO t1 VALUES (12345.1234, 123456.123456, "
++ "123456.1234)");
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT f, d, e FROM t1";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= f;
++ my_bind[0].buffer_length= sizeof(f);
++ my_bind[0].length= &f_len;
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= d;
++ my_bind[1].buffer_length= sizeof(d);
++ my_bind[1].length= &d_len;
++ my_bind[2].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[2].buffer= e;
++ my_bind[2].buffer_length= sizeof(e);
++ my_bind[2].length= &e_len;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ mysql_stmt_store_result(stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++
++ diag("expected %s %s %s", row[0], row[1], row[2]);
++ FAIL_UNLESS(!strcmp(f, row[0]) && !strcmp(d, row[1]) && !strcmp(e, row[2]), "");
++
++ mysql_free_result(res);
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug4231(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ MYSQL_TIME tm[2];
++ const char *stmt_text;
++ int rc;
++
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "CREATE TABLE t1 (a int)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "INSERT INTO t1 VALUES (1)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT a FROM t1 WHERE ? = ?";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ /* Bind input buffers */
++ memset(my_bind, '\0', sizeof(my_bind)); memset(tm, '\0', sizeof(tm));
++ my_bind[0].buffer_type= MYSQL_TYPE_DATE;
++ my_bind[0].buffer= &tm[0];
++ my_bind[1].buffer_type= MYSQL_TYPE_DATE;
++ my_bind[1].buffer= &tm[1];
++
++ mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ /*
++ First set server-side params to some non-zero non-equal values:
++ then we will check that they are not used when client sends
++ new (zero) times.
++ */
++ tm[0].time_type = MYSQL_TIMESTAMP_DATE;
++ tm[0].year = 2000;
++ tm[0].month = 1;
++ tm[0].day = 1;
++ tm[1]= tm[0];
++ --tm[1].year; /* tm[0] != tm[1] */
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++
++ /* binds are unequal, no rows should be returned */
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* Set one of the dates to zero */
++ tm[0].year= tm[0].month= tm[0].day= 0;
++ tm[1]= tm[0];
++ mysql_stmt_execute(stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++
++ mysql_stmt_close(stmt);
++ stmt_text= "DROP TABLE t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug4236(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt, *stmt1;
++ const char *stmt_text;
++ int rc;
++ MYSQL_STMT backup;
++ MYSQL *mysql1;
++
++
++ stmt= mysql_stmt_init(mysql);
++
++ /* mysql_stmt_execute() of statement with statement id= 0 crashed server */
++ stmt_text= "SELECT 1";
++ /* We need to prepare statement to pass by possible check in libmysql */
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt); /* Hack to check that server works OK if statement wasn't found */
++ backup.stmt_id= stmt->stmt_id;
++ stmt->stmt_id= 0;
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ /* lets try to hack with a new connection */
++ mysql1= test_connect(NULL);
++ stmt1= mysql_stmt_init(mysql1);
++ stmt_text= "SELECT 2";
++ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ stmt->stmt_id= stmt1->stmt_id;
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt1);
++ mysql_close(mysql1);
++
++ /* Restore original statement id to be able to reprepare it */
++ stmt->stmt_id= backup.stmt_id;
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug5126(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ int32 c1, c2;
++ const char *stmt_text;
++ int rc;
++
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "CREATE TABLE t1 (a mediumint, b int)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "INSERT INTO t1 VALUES (8386608, 1)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT a, b FROM t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ /* Bind output buffers */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= &c1;
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[1].buffer= &c2;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ FAIL_UNLESS(c1 == 8386608 && c2 == 1, "c1 != 8386608 || c2 != 1");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug5194(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND *my_bind;
++ char *query;
++ char *param_str;
++ int param_str_length;
++ const char *stmt_text;
++ int rc;
++ float float_array[250] =
++ {
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
++ 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25
++ };
++ float *fa_ptr= float_array;
++ /* Number of columns per row */
++ const int COLUMN_COUNT= sizeof(float_array)/sizeof(*float_array);
++ /* Number of rows per bulk insert to start with */
++ const int MIN_ROWS_PER_INSERT= 262;
++ /* Max number of rows per bulk insert to end with */
++ const int MAX_ROWS_PER_INSERT= 300;
++ const int MAX_PARAM_COUNT= COLUMN_COUNT*MAX_ROWS_PER_INSERT;
++ const char *query_template= "insert into t1 values %s";
++ const int CHARS_PER_PARAM= 5; /* space needed to place ", ?" in the query */
++ const int uint16_max= 65535;
++ int nrows, i;
++
++
++ stmt_text= "drop table if exists t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++
++ stmt_text= "create table if not exists t1"
++ "(c1 float, c2 float, c3 float, c4 float, c5 float, c6 float, "
++ "c7 float, c8 float, c9 float, c10 float, c11 float, c12 float, "
++ "c13 float, c14 float, c15 float, c16 float, c17 float, c18 float, "
++ "c19 float, c20 float, c21 float, c22 float, c23 float, c24 float, "
++ "c25 float, c26 float, c27 float, c28 float, c29 float, c30 float, "
++ "c31 float, c32 float, c33 float, c34 float, c35 float, c36 float, "
++ "c37 float, c38 float, c39 float, c40 float, c41 float, c42 float, "
++ "c43 float, c44 float, c45 float, c46 float, c47 float, c48 float, "
++ "c49 float, c50 float, c51 float, c52 float, c53 float, c54 float, "
++ "c55 float, c56 float, c57 float, c58 float, c59 float, c60 float, "
++ "c61 float, c62 float, c63 float, c64 float, c65 float, c66 float, "
++ "c67 float, c68 float, c69 float, c70 float, c71 float, c72 float, "
++ "c73 float, c74 float, c75 float, c76 float, c77 float, c78 float, "
++ "c79 float, c80 float, c81 float, c82 float, c83 float, c84 float, "
++ "c85 float, c86 float, c87 float, c88 float, c89 float, c90 float, "
++ "c91 float, c92 float, c93 float, c94 float, c95 float, c96 float, "
++ "c97 float, c98 float, c99 float, c100 float, c101 float, c102 float, "
++ "c103 float, c104 float, c105 float, c106 float, c107 float, c108 float, "
++ "c109 float, c110 float, c111 float, c112 float, c113 float, c114 float, "
++ "c115 float, c116 float, c117 float, c118 float, c119 float, c120 float, "
++ "c121 float, c122 float, c123 float, c124 float, c125 float, c126 float, "
++ "c127 float, c128 float, c129 float, c130 float, c131 float, c132 float, "
++ "c133 float, c134 float, c135 float, c136 float, c137 float, c138 float, "
++ "c139 float, c140 float, c141 float, c142 float, c143 float, c144 float, "
++ "c145 float, c146 float, c147 float, c148 float, c149 float, c150 float, "
++ "c151 float, c152 float, c153 float, c154 float, c155 float, c156 float, "
++ "c157 float, c158 float, c159 float, c160 float, c161 float, c162 float, "
++ "c163 float, c164 float, c165 float, c166 float, c167 float, c168 float, "
++ "c169 float, c170 float, c171 float, c172 float, c173 float, c174 float, "
++ "c175 float, c176 float, c177 float, c178 float, c179 float, c180 float, "
++ "c181 float, c182 float, c183 float, c184 float, c185 float, c186 float, "
++ "c187 float, c188 float, c189 float, c190 float, c191 float, c192 float, "
++ "c193 float, c194 float, c195 float, c196 float, c197 float, c198 float, "
++ "c199 float, c200 float, c201 float, c202 float, c203 float, c204 float, "
++ "c205 float, c206 float, c207 float, c208 float, c209 float, c210 float, "
++ "c211 float, c212 float, c213 float, c214 float, c215 float, c216 float, "
++ "c217 float, c218 float, c219 float, c220 float, c221 float, c222 float, "
++ "c223 float, c224 float, c225 float, c226 float, c227 float, c228 float, "
++ "c229 float, c230 float, c231 float, c232 float, c233 float, c234 float, "
++ "c235 float, c236 float, c237 float, c238 float, c239 float, c240 float, "
++ "c241 float, c242 float, c243 float, c244 float, c245 float, c246 float, "
++ "c247 float, c248 float, c249 float, c250 float)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ my_bind= (MYSQL_BIND*) malloc(MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
++ query= (char*) malloc(strlen(query_template) +
++ MAX_PARAM_COUNT * CHARS_PER_PARAM + 1);
++ param_str= (char*) malloc(COLUMN_COUNT * CHARS_PER_PARAM);
++
++ FAIL_IF(my_bind == 0 || query == 0 || param_str == 0, "Not enought memory")
++
++ stmt= mysql_stmt_init(mysql);
++
++ /* setup a template for one row of parameters */
++ sprintf(param_str, "(");
++ for (i= 1; i < COLUMN_COUNT; ++i)
++ strcat(param_str, "?, ");
++ strcat(param_str, "?)");
++ param_str_length= strlen(param_str);
++
++ /* setup bind array */
++ memset(my_bind, '\0', MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
++ for (i= 0; i < MAX_PARAM_COUNT; ++i)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[i].buffer= fa_ptr;
++ if (++fa_ptr == float_array + COLUMN_COUNT)
++ fa_ptr= float_array;
++ }
++
++ /*
++ Test each number of rows per bulk insert, so that we can see where
++ MySQL fails.
++ */
++ for (nrows= MIN_ROWS_PER_INSERT; nrows <= MAX_ROWS_PER_INSERT; ++nrows)
++ {
++ char *query_ptr;
++ /* Create statement text for current number of rows */
++ sprintf(query, query_template, param_str);
++ query_ptr= query + strlen(query);
++ for (i= 1; i < nrows; ++i)
++ {
++ memcpy(query_ptr, ", ", 2);
++ query_ptr+= 2;
++ memcpy(query_ptr, param_str, param_str_length);
++ query_ptr+= param_str_length;
++ }
++ *query_ptr= '\0';
++
++ rc= mysql_stmt_prepare(stmt, query, query_ptr - query);
++
++ if (rc && nrows * COLUMN_COUNT > uint16_max) /* expected error */
++ break;
++
++ check_stmt_rc(rc, stmt);
++
++ /* bind the parameter array and execute the query */
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_reset(stmt);
++ }
++
++ free(param_str);
++ free(query);
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++ free(my_bind);
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_bug5315(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ int rc;
++
++
++ stmt_text= "SELECT 1";
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_change_user(mysql, username, password, schema);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_UNLESS(rc != 0, "Error expected");
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug5399(MYSQL *mysql)
++{
++ /*
++ Ascii 97 is 'a', which gets mapped to Ascii 65 'A' unless internal
++ statement id hash in the server uses binary collation.
++ */
++#define NUM_OF_USED_STMT 97
++ MYSQL_STMT *stmt_list[NUM_OF_USED_STMT];
++ MYSQL_STMT **stmt;
++ MYSQL_BIND my_bind[1];
++ char buff[600];
++ int rc;
++ int32 no;
++
++
++ memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= &no;
++
++ for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
++ {
++ sprintf(buff, "select %d", (int) (stmt - stmt_list));
++ *stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(*stmt, buff, strlen(buff));
++ check_stmt_rc(rc, *stmt); mysql_stmt_bind_result(*stmt, my_bind);
++ }
++
++ for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
++ {
++ rc= mysql_stmt_execute(*stmt);
++ check_stmt_rc(rc, *stmt);
++ rc= mysql_stmt_store_result(*stmt);
++ check_stmt_rc(rc, *stmt);
++ rc= mysql_stmt_fetch(*stmt);
++ FAIL_UNLESS((int32) (stmt - stmt_list) == no, "");
++ }
++
++ for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
++ mysql_stmt_close(*stmt);
++#undef NUM_OF_USED_STMT
++ return OK;
++}
++
++static int test_bug6046(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ int rc;
++ short b= 1;
++ MYSQL_BIND my_bind[1];
++
++
++ stmt_text= "DROP TABLE IF EXISTS t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "CREATE TABLE t1 (a int, b int)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "INSERT INTO t1 VALUES (1,1),(2,2),(3,1),(4,2)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++
++ stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 "
++ "WHERE t1.b > ? ORDER BY t1.a";
++
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ b= 1;
++ memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer= &b;
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++
++ mysql_stmt_bind_param(stmt, my_bind);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_store_result(stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug6049(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ const char *stmt_text;
++ char buffer[30];
++ ulong length;
++ int rc;
++
++
++ stmt_text= "SELECT MAKETIME(-25, 12, 12)";
++
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type = MYSQL_TYPE_STRING;
++ my_bind[0].buffer = &buffer;
++ my_bind[0].buffer_length = sizeof(buffer);
++ my_bind[0].length = &length;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(row[0], (char*) buffer) == 0, "row[0] != buffer");
++
++ mysql_free_result(res);
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug6058(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ const char *stmt_text;
++ char buffer[30];
++ ulong length;
++ int rc;
++
++
++ stmt_text= "SELECT CAST('0000-00-00' AS DATE)";
++
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type = MYSQL_TYPE_STRING;
++ my_bind[0].buffer = &buffer;
++ my_bind[0].buffer_length = sizeof(buffer);
++ my_bind[0].length = &length;
++
++ mysql_stmt_bind_result(stmt, my_bind);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(row[0], buffer) == 0, "row[0] != buffer");
++
++ mysql_free_result(res);
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++static int test_bug6059(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *stmt_text;
++ int rc;
++
++ stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'";
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(mysql_stmt_field_count(stmt) == 0, "");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug6096(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *query_result, *stmt_metadata;
++ const char *stmt_text;
++ MYSQL_BIND my_bind[12];
++ MYSQL_FIELD *query_field_list, *stmt_field_list;
++ ulong query_field_count, stmt_field_count;
++ int rc;
++ my_bool update_max_length= TRUE;
++ uint i;
++
++
++ stmt_text= "drop table if exists t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ mysql_query(mysql, "set sql_mode=''");
++ stmt_text= "create table t1 (c_tinyint tinyint, c_smallint smallint, "
++ " c_mediumint mediumint, c_int int, "
++ " c_bigint bigint, c_float float, "
++ " c_double double, c_varchar varchar(20), "
++ " c_char char(20), c_time time, c_date date, "
++ " c_datetime datetime)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "insert into t1 values (-100, -20000, 30000000, 4, 8, 1.0, "
++ "2.0, 'abc', 'def', now(), now(), now())";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "select * from t1";
++
++ /* Run select in prepared and non-prepared mode and compare metadata */
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ query_result= mysql_store_result(mysql);
++ query_field_list= mysql_fetch_fields(query_result);
+ FAIL_IF(!query_field_list, "fetch_fields faild");
- query_field_count= mysql_num_fields(query_result);
-
- stmt= mysql_stmt_init(mysql);
-@@ -3709,8 +3710,96 @@
-
- return OK;
- }
++ query_field_count= mysql_num_fields(query_result);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt); mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
++ (void*) &update_max_length);
++ mysql_stmt_store_result(stmt);
++ stmt_metadata= mysql_stmt_result_metadata(stmt);
++ stmt_field_list= mysql_fetch_fields(stmt_metadata);
++ stmt_field_count= mysql_num_fields(stmt_metadata);
++ FAIL_UNLESS(stmt_field_count == query_field_count, "");
++
++
++ /* Bind and fetch the data */
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < stmt_field_count; ++i)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[i].buffer_length= stmt_field_list[i].max_length + 1;
++ my_bind[i].buffer= malloc(my_bind[i].buffer_length);
++ }
++ mysql_stmt_bind_result(stmt, my_bind);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* Clean up */
++
++ for (i= 0; i < stmt_field_count; ++i)
++ free(my_bind[i].buffer);
++ mysql_stmt_close(stmt);
++ mysql_free_result(query_result);
++ mysql_free_result(stmt_metadata);
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Bug#7990 - mysql_stmt_close doesn't reset mysql->net.last_error */
++
++static int test_bug7990(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, "foo", 3);
++ /*
++ XXX: the fact that we store errno both in STMT and in
++ MYSQL is not documented and is subject to change in 5.0
++ */
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
++ mysql_stmt_close(stmt);
++ FAIL_UNLESS(!mysql_errno(mysql), "errno != 0");
++ return OK;
++}
++
++/* Bug#8330 - mysql_stmt_execute crashes (libmysql) */
++
++static int test_bug8330(MYSQL *mysql)
++{
++ const char *stmt_text;
++ MYSQL_STMT *stmt[2];
++ int i, rc;
++ const char *query= "select a,b from t1 where a=?";
++ MYSQL_BIND my_bind[2];
++ long lval[2];
++
++ stmt_text= "drop table if exists t1";
++ /* in case some previos test failed */
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "create table t1 (a int, b int)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i=0; i < 2; i++)
++ {
++ stmt[i]= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt[i], query, strlen(query));
++ check_stmt_rc(rc, stmt[i]);
++ my_bind[i].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[i].buffer= (void*) &lval[i];
++ my_bind[i].is_null= 0;
++ mysql_stmt_bind_param(stmt[i], &my_bind[i]);
++ }
++
++ rc= mysql_stmt_execute(stmt[0]);
++ check_stmt_rc(rc, stmt[0]);
++ rc= mysql_stmt_execute(stmt[1]);
++ FAIL_UNLESS(rc && mysql_stmt_errno(stmt[1]) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
++ rc= mysql_stmt_execute(stmt[0]);
++ check_stmt_rc(rc, stmt[0]);
++ mysql_stmt_close(stmt[0]);
++ mysql_stmt_close(stmt[1]);
++
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test misc field information, bug: #74 */
++
++static int test_field_misc(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ int rc;
++
++
++ rc= mysql_query(mysql, "SELECT @@autocommit");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ verify_prepare_field(result, 0,
++ "@@autocommit", "", /* field and its org name */
++ MYSQL_TYPE_LONGLONG, /* field type */
++ "", "", /* table and its org name */
++ "", 1, 0); /* db name, length(its bool flag)*/
++
++ mysql_free_result(result);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT @@autocommit", strlen("SELECT @@autocommit"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ verify_prepare_field(result, 0,
++ "@@autocommit", "", /* field and its org name */
++ MYSQL_TYPE_LONGLONG, /* field type */
++ "", "", /* table and its org name */
++ "", 1, 0); /* db name, length(its bool flag)*/
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT @@max_error_count", strlen("SELECT @@max_error_count"));
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ if (verify_prepare_field(result, 0,
++ "@@max_error_count", "", /* field and its org name */
++ MYSQL_TYPE_LONGLONG, /* field type */
++ "", "", /* table and its org name */
++ /* db name, length */
++ "", MY_INT64_NUM_DECIMAL_DIGITS , 0))
++ goto error;
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT @@max_allowed_packet", strlen("SELECT @@max_allowed_packet"));
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ if (verify_prepare_field(result, 0,
++ "@@max_allowed_packet", "", /* field and its org name */
++ MYSQL_TYPE_LONGLONG, /* field type */
++ "", "", /* table and its org name */
++ /* db name, length */
++ "", MY_INT64_NUM_DECIMAL_DIGITS, 0))
++ goto error;
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT @@sql_warnings", strlen("SELECT @@sql_warnings"));
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ if (verify_prepare_field(result, 0,
++ "@@sql_warnings", "", /* field and its org name */
++ MYSQL_TYPE_LONGLONG, /* field type */
++ "", "", /* table and its org name */
++ "", 1, 0)) /* db name, length */
++ goto error;
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++ return OK;
++
++error:
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++ return FAIL;
++}
++
++/* Test a memory ovverun bug */
++
++static int test_mem_overun(MYSQL *mysql)
++{
++ char buffer[10000], field[12];
++ MYSQL_STMT *stmt;
++ MYSQL_RES *field_res, *res;
++ int rc, i, length;
++
++ /*
++ Test a memory ovverun bug when a table had 1000 fields with
++ a row of data
++ */
++ rc= mysql_query(mysql, "drop table if exists t_mem_overun");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(buffer, "create table t_mem_overun(");
++ for (i= 0; i < 1000; i++)
++ {
++ sprintf(field, "c%d int, ", i);
++ strcat(buffer, field);
++ }
++ length= strlen(buffer);
++ buffer[length-2]= ')';
++ buffer[--length]= '\0';
++
++ rc= mysql_real_query(mysql, buffer, length);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(buffer, "insert into t_mem_overun values(");
++ for (i= 0; i < 1000; i++)
++ {
++ strcat(buffer, "1, ");
++ }
++ length= strlen(buffer);
++ buffer[length-2]= ')';
++ buffer[--length]= '\0';
++
++ rc= mysql_real_query(mysql, buffer, length);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "select * from t_mem_overun");
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_store_result(mysql);
++ rc= 0;
++ while (mysql_fetch_row(res))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ mysql_free_result(res);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select * from t_mem_overun", strlen("select * from t_mem_overun"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ field_res= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!field_res, "Invalid result set");
++
++ FAIL_UNLESS( 1000 == mysql_num_fields(field_res), "fields != 1000");
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
++
++ mysql_free_result(field_res);
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug8722(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *stmt_text;
++
++ /* Prepare test data */
++ stmt_text= "drop table if exists t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "drop view if exists v1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "CREATE TABLE t1 (c1 varchar(10), c2 varchar(10), c3 varchar(10),"
++ " c4 varchar(10), c5 varchar(10), c6 varchar(10),"
++ " c7 varchar(10), c8 varchar(10), c9 varchar(10),"
++ "c10 varchar(10))";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "CREATE VIEW v1 AS SELECT * FROM t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "select * from v1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++ stmt_text= "drop table if exists t1, v1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test DECIMAL conversion */
++
++static int test_decimal_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char data[30];
++ int rc;
++ my_bool is_null;
++
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "drop table if exists test_decimal_bug");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table test_decimal_bug(c1 decimal(10, 2))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into test_decimal_bug value(8), (10.22), (5.61)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select c1 from test_decimal_bug where c1=?",
++ strlen("select c1 from test_decimal_bug where c1=?"));
++ check_stmt_rc(rc, stmt);
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL;
++ my_bind[0].buffer= (void *)data;
++ my_bind[0].buffer_length= 25;
++ my_bind[0].is_null= &is_null;
++
++ is_null= 0;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ strcpy(data, "8.0");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ data[0]= 0;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(data, "8.00") == 0, "data != '8.00'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ strcpy(data, "5.61");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ data[0]= 0;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(data, "5.61") == 0, "data != '5.61'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ is_null= 1;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ strcpy(data, "10.22"); is_null= 0;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ data[0]= 0;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(data, "10.22") == 0, "data != '10.22'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test EXPLAIN bug (#115, reported by mark@mysql.com & georg@php.net). */
++
++static int test_explain_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ int rc;
++
++
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_explain");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_explain(id int, name char(2))");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "explain test_explain", strlen("explain test_explain"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 2, "rowcount != 2");
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ FAIL_UNLESS(6 == mysql_num_fields(result), "fields != 6");
++
++ if (verify_prepare_field(result, 0, "Field", "COLUMN_NAME",
++ mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 64, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 0, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 2, "Null", "IS_NULLABLE",
++ mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 3, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 3, "Key", "COLUMN_KEY",
++ mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 3, 0))
++ goto error;
++
++ if ( mysql_get_server_version(mysql) >= 50027 )
++ {
++ /* The patch for bug#23037 changes column type of DEAULT to blob */
++ if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
++ MYSQL_TYPE_BLOB, 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 0, 0))
++ goto error;
++ }
++ else
++ {
++ if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
++ mysql_get_server_version(mysql) >= 50027 ?
++ MYSQL_TYPE_BLOB :
++ mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ mysql_get_server_version(mysql) >= 50027 ? 0 :64, 0))
++ goto error;
++ }
++
++ if (verify_prepare_field(result, 5, "Extra", "EXTRA",
++ mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
++ 0, 0,
++ mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
++ 27, 0))
++ goto error;
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "explain select id, name FROM test_explain", strlen("explain select id, name FROM test_explain"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid result set");
++
++ FAIL_UNLESS(10 == mysql_num_fields(result), "fields != 10");
++
++ if (verify_prepare_field(result, 0, "id", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 1, "select_type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 19, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 2, "table", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 10, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
++ goto error;
++
++ if ( verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
++ goto error;
++
++ if (mysql_get_server_version(mysql) <= 50000)
++ {
++ if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
++ goto error;
++ }
++ else if (mysql_get_server_version(mysql) <= 60000)
++ {
++ if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
++ goto error;
++ }
++ else
++ {
++ if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", (MAX_KEY_LENGTH_DECIMAL_WIDTH + 1) * MAX_KEY, 0))
++ goto error;
++ }
++
++ if (verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "",
++ NAME_CHAR_LEN*16, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, "", "", "", 10, 0))
++ goto error;
++
++ if (verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, "", "", "", 255, 0))
++ goto error;
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++ return OK;
++error:
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++ return FAIL;
++}
++
++static int test_sshort_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[4];
++ short short_value;
++ int32 long_value;
++ ulong s_length, l_length, ll_length, t_length;
++ ulonglong longlong_value;
++ int rc;
++ uchar tiny_value;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sshort");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_sshort(a smallint signed, \
++ b smallint signed, \
++ c smallint unsigned, \
++ d smallint unsigned)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_sshort VALUES(-5999, -5999, 35999, 200)");
++ check_mysql_rc(rc, mysql);
++
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_sshort", strlen("SELECT * FROM test_sshort"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[0].buffer= (void *)&short_value;
++ my_bind[0].length= &s_length;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[1].buffer= (void *)&long_value;
++ my_bind[1].length= &l_length;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[2].buffer= (void *)&longlong_value;
++ my_bind[2].length= &ll_length;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[3].buffer= (void *)&tiny_value;
++ my_bind[3].is_unsigned= TRUE;
++ my_bind[3].length= &t_length;
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(short_value == -5999, "sv != -5999");
++ FAIL_UNLESS(s_length == 2, "s_length != 2");
++
++ FAIL_UNLESS(long_value == -5999, "l_v != -5999");
++ FAIL_UNLESS(l_length == 4, "l_length != 4");
++
++ FAIL_UNLESS(longlong_value == 35999, "llv != 35999");
++ FAIL_UNLESS(ll_length == 8, "ll_length != 8");
++
++ FAIL_UNLESS(tiny_value == 200, "t_v != 200");
++ FAIL_UNLESS(t_length == 1, "t_length != 1");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++/* Test a misc tinyint-signed conversion bug */
++
++static int test_stiny_bug(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[4];
++ short short_value;
++ int32 long_value;
++ ulong s_length, l_length, ll_length, t_length;
++ ulonglong longlong_value;
++ int rc;
++ uchar tiny_value;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stiny");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_stiny(a tinyint signed, \
++ b tinyint signed, \
++ c tinyint unsigned, \
++ d tinyint unsigned)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_stiny VALUES(-128, -127, 255, 0)");
++ check_mysql_rc(rc, mysql);
++
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_stiny", strlen("SELECT * FROM test_stiny"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[0].buffer= (void *)&short_value;
++ my_bind[0].length= &s_length;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[1].buffer= (void *)&long_value;
++ my_bind[1].length= &l_length;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[2].buffer= (void *)&longlong_value;
++ my_bind[2].length= &ll_length;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[3].buffer= (void *)&tiny_value;
++ my_bind[3].length= &t_length;
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(short_value == -128, "s_v != -128");
++ FAIL_UNLESS(s_length == 2, "s_length != 2");
++
++ FAIL_UNLESS(long_value == -127, "l_v != -127");
++ FAIL_UNLESS(l_length == 4, "l_length != 4");
++
++ FAIL_UNLESS(longlong_value == 255, "llv != 255");
++ FAIL_UNLESS(ll_length == 8, "ll_length != 8");
++
++ FAIL_UNLESS(tiny_value == 0, "t_v != 0");
++ FAIL_UNLESS(t_length == 1, "t_length != 1");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bug53311(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ int i;
++ char *query= "INSERT INTO bug53311 VALUES (1)";
++
++ rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug53311");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE bug53311 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i=0; i < 2; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ /* kill connection */
++ rc= mysql_kill(mysql, mysql_thread_id(mysql));
++ sleep(1);
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(rc == 0, "Error expected");
++ FAIL_IF(mysql_stmt_errno(stmt) == 0, "Errno != 0 expected");
++ rc= mysql_stmt_close(stmt);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
+#define PREPARE_SQL "EXPLAIN SELECT t1.*, t2.* FROM test AS t1, test AS t2"
+
+#ifdef NOT_IN_USE
@@ -151878,29 +214825,4938 @@
+
+ mysql_free_result(res);
+ mysql_stmt_close(stmt);
++ return OK;
+}
-
- struct my_tests_st my_tests[] = {
++
++struct my_tests_st my_tests[] = {
+ {"test_conc_5", test_conc_5, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
- {"test_bug1115", test_bug1115, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
- {"test_bug1180", test_bug1180, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
- {"test_bug1644", test_bug1644, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
-@@ -3768,8 +3857,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++ {"test_bug1115", test_bug1115, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug1180", test_bug1180, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug1644", test_bug1644, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11037", test_bug11037, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11183", test_bug11183, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug12744", test_bug12744, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug1500", test_bug1500, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug15510", test_bug15510, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug15518", test_bug15518, TEST_CONNECTION_NEW | TEST_CONNECTION_DONT_CLOSE, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_bug15613", test_bug15613, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug16144", test_bug16144, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug1664", test_bug1664, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug1946", test_bug1946, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug2247", test_bug2247, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug2248", test_bug2248, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug20152", test_bug20152, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug23383", test_bug23383, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug27592", test_bug27592, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug28934", test_bug28934, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug36004", test_bug36004, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug3035", test_bug3035, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug3117", test_bug3117, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug3796", test_bug3796, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4026", test_bug4026, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4030", test_bug4030, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4079", test_bug4079, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4172", test_bug4172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4231", test_bug4231, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug4236", test_bug4236, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug5126", test_bug5126, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug5194", test_bug5194, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug5315", test_bug5315, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug5399", test_bug5399, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug6046", test_bug6046, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug6049", test_bug6049, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug6058", test_bug6058, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug6059", test_bug6059, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug6096", test_bug6096, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug7990", test_bug7990, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug8330", test_bug8330, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug8722", test_bug8722, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ps_conj_select", test_ps_conj_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ps_null_param", test_ps_null_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ps_query_cache", test_ps_query_cache, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_ushort_bug", test_ushort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_field_misc", test_field_misc, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_mem_overun", test_mem_overun, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_decimal_bug", test_decimal_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_explain_bug", test_explain_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_sshort_bug", test_sshort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_stiny_bug", test_stiny_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug53311", test_bug53311, TEST_CONNECTION_NEW, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== added file 'unittest/libmariadb/ps_new.c'
---- mariadb/unittest/libmariadb/ps_new.c 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/ps_new.c 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,147 @@
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/ps.c mariadb-native-client.trunk/unittest/libmariadb/ps.c
+--- mariadb/unittest/libmariadb/ps.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/ps.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,4853 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++/* Utility function to verify the field members */
++
++
++static int test_prepare_insert_update(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ int i;
++ const char *testcase[]= {
++ "CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B))",
++ "INSERT t1 VALUES (1,2,10), (3,4,20)",
++ "INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100",
++ "SELECT * FROM t1",
++ "INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0",
++ "SELECT * FROM t1",
++ "INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a)",
++ NULL};
++ const char **cur_query;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ for (cur_query= testcase; *cur_query; cur_query++)
++ {
++ char query[MAX_TEST_QUERY_LENGTH];
++ strcpy(query, *cur_query);
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount is not 0");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* try the last query several times */
++ if (!cur_query[1])
++ {
++ for (i=0; i < 3;i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++ }
++ mysql_stmt_close(stmt);
++ }
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/*
++ Generalized conversion routine to handle DATE, TIME and DATETIME
++ conversion using MYSQL_TIME structure
++*/
++
++static int test_bind_date_conv(MYSQL *mysql, uint row_count)
++{
++ MYSQL_STMT *stmt= 0;
++ uint rc, i, count= row_count;
++ ulong length[4];
++ MYSQL_BIND my_bind[4];
++ my_bool is_null[4]= {0};
++ MYSQL_TIME tm[4];
++ ulong second_part;
++ uint year, month, day, hour, minute, sec;
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "INSERT INTO test_date VALUES(?, ?, ?, ?)", strlen("INSERT INTO test_date VALUES(?, ?, ?, ?)"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 4, "param_count != 4");
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP;
++ my_bind[1].buffer_type= MYSQL_TYPE_TIME;
++ my_bind[2].buffer_type= MYSQL_TYPE_DATETIME;
++ my_bind[3].buffer_type= MYSQL_TYPE_DATETIME;
++
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].buffer= (void *) &tm[i];
++ my_bind[i].is_null= &is_null[i];
++ my_bind[i].length= &length[i];
++ my_bind[i].buffer_length= 30;
++ length[i]= 20;
++ }
++
++ second_part= 0;
++
++ year= 2000;
++ month= 01;
++ day= 10;
++
++ hour= 11;
++ minute= 16;
++ sec= 20;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (count= 0; count < row_count; count++)
++ {
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ tm[i].neg= 0;
++ tm[i].second_part= second_part+count;
++ if (my_bind[i].buffer_type != MYSQL_TYPE_TIME)
++ {
++ tm[i].year= year+count;
++ tm[i].month= month+count;
++ tm[i].day= day+count;
++ }
++ else
++ tm[i].year= tm[i].month= tm[i].day= 0;
++ if (my_bind[i].buffer_type != MYSQL_TYPE_DATE)
++ {
++ tm[i].hour= hour+count;
++ tm[i].minute= minute+count;
++ tm[i].second= sec+count;
++ }
++ else
++ tm[i].hour= tm[i].minute= tm[i].second= 0;
++ }
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ mysql_stmt_close(stmt);
++
++ rc= my_stmt_result(mysql, "SELECT * FROM test_date");
++ FAIL_UNLESS(row_count == rc, "rowcount != rc");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_date", strlen("SELECT * FROM test_date"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ for (count= 0; count < row_count; count++)
++ {
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == 0 || rc == MYSQL_DATA_TRUNCATED, "rc != 0 | rc != MYSQL_DATA_TRUNCATED");
++
++ for (i= 0; i < array_elements(my_bind); i++)
++ {
++ FAIL_UNLESS(tm[i].year == 0 || tm[i].year == year+count, "wrong value for year");
++ FAIL_UNLESS(tm[i].month == 0 || tm[i].month == month+count, "wrong value for month");
++ FAIL_UNLESS(tm[i].day == 0 || tm[i].day == day+count, "wrong value for day");
++ FAIL_UNLESS(tm[i].hour == 0 || tm[i].hour == hour+count, "wrong value for hour");
++ FAIL_UNLESS(tm[i].minute == 0 || tm[i].minute == minute+count, "wrong value for minute");
++ FAIL_UNLESS(tm[i].second == 0 || tm[i].second == sec+count, "wrong value for second");
++ FAIL_UNLESS(tm[i].second_part == 0 ||
++ tm[i].second_part == second_part+count, "wrong value for second_part");
++ }
++ }
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++/* Test simple prepares of all DML statements */
++
++static int test_prepare_simple(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_simple");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prepare_simple("
++ "id int, name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert */
++ strcpy(query, "INSERT INTO test_prepare_simple VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount is not 2");
++ mysql_stmt_close(stmt);
++
++ /* update */
++ strcpy(query, "UPDATE test_prepare_simple SET id=? "
++ "WHERE id=? AND CONVERT(name USING utf8)= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "Paramcount is not 3");
++ mysql_stmt_close(stmt);
++
++ /* delete */
++ strcpy(query, "DELETE FROM test_prepare_simple WHERE id=10");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount is not 0");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ /* delete */
++ strcpy(query, "DELETE FROM test_prepare_simple WHERE id=?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ /* select */
++ strcpy(query, "SELECT * FROM test_prepare_simple WHERE id=? "
++ "AND CONVERT(name USING utf8)= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_prepare_field_result(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_field_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prepare_field_result(int_c int, "
++ "var_c varchar(50), ts_c timestamp, "
++ "char_c char(4), date_c date, extra tinyint)");
++ check_mysql_rc(rc, mysql);
++
++ /* insert */
++ strcpy(query, "SELECT int_c, var_c, date_c as date, ts_c, char_c FROM "
++ " test_prepare_field_result as t1 WHERE int_c=?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, mysql_stmt_error(stmt));
++
++ if (verify_prepare_field(result, 0, "int_c", "int_c", MYSQL_TYPE_LONG,
++ "t1", "test_prepare_field_result", schema, 11, 0))
++ goto error;
++ if (verify_prepare_field(result, 1, "var_c", "var_c", MYSQL_TYPE_VAR_STRING,
++ "t1", "test_prepare_field_result", schema, 50, 0))
++ goto error;
++ if (verify_prepare_field(result, 2, "date", "date_c", MYSQL_TYPE_DATE,
++ "t1", "test_prepare_field_result", schema, 10, 0))
++ goto error;
++ if (verify_prepare_field(result, 3, "ts_c", "ts_c", MYSQL_TYPE_TIMESTAMP,
++ "t1", "test_prepare_field_result", schema, 19, 0))
++ goto error;
++ if (verify_prepare_field(result, 4, "char_c", "char_c",
++ (mysql_get_server_version(mysql) <= 50000 ?
++ MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING),
++ "t1", "test_prepare_field_result", schema, 4, 0))
++ goto error;
++
++ FAIL_IF(mysql_num_fields(result) != 5, "Paramcount != 5");
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ return OK;
++
++error:
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++ return FAIL;
++}
++
++
++/* Test simple prepare field results */
++
++static int test_prepare_syntax(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_syntax");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prepare_syntax("
++ "id int, name varchar(50), extra int)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_prepare_syntax VALUES(?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "error expected");
++
++ strcpy(query, "SELECT id, name FROM test_prepare_syntax WHERE id=? AND WHERE");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "error expected");
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_prepare(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ int int_data, o_int_data;
++ char str_data[50], data[50];
++ char tiny_data, o_tiny_data;
++ short small_data, o_small_data;
++ longlong big_data, o_big_data;
++ float real_data, o_real_data;
++ double double_data, o_double_data;
++ ulong length[7], len;
++ my_bool is_null[7];
++ MYSQL_BIND my_bind[7];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 tinyint, "
++ "col2 varchar(15), col3 int, "
++ "col4 smallint, col5 bigint, "
++ "col6 float, col7 double )");
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare */
++ strcpy(query, "INSERT INTO my_prepare VALUES(?, ?, ?, ?, ?, ?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 7, "Paramcount != 7");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* tinyint */
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&tiny_data;
++ /* string */
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)str_data;
++ my_bind[1].buffer_length= 1000; /* Max string length */
++ /* integer */
++ my_bind[2].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[2].buffer= (void *)&int_data;
++ /* short */
++ my_bind[3].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[3].buffer= (void *)&small_data;
++ /* bigint */
++ my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[4].buffer= (void *)&big_data;
++ /* float */
++ my_bind[5].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[5].buffer= (void *)&real_data;
++ /* double */
++ my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[6].buffer= (void *)&double_data;
++
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].length= &length[i];
++ my_bind[i].is_null= &is_null[i];
++ is_null[i]= 0;
++ }
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ int_data= 320;
++ small_data= 1867;
++ big_data= 1000;
++ real_data= 2;
++ double_data= 6578.001;
++
++ /* now, execute the prepared statement to insert 10 records.. */
++ for (tiny_data= 0; tiny_data < 100; tiny_data++)
++ {
++ length[1]= sprintf(str_data, "MySQL%d", int_data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ int_data += 25;
++ small_data += 10;
++ big_data += 100;
++ real_data += 1;
++ double_data += 10.09;
++ }
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= my_stmt_result(mysql, "SELECT * FROM my_prepare");
++ FAIL_UNLESS(rc != 1, "rowcount != 1");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM my_prepare", 25);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /* get the result */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ o_int_data= 320;
++ o_small_data= 1867;
++ o_big_data= 1000;
++ o_real_data= 2;
++ o_double_data= 6578.001;
++
++ /* now, execute the prepared statement to insert 10 records.. */
++ for (o_tiny_data= 0; o_tiny_data < 100; o_tiny_data++)
++ {
++ len= sprintf(data, "MySQL%d", o_int_data);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(tiny_data == o_tiny_data, "Wrong value for tiny_data");
++ FAIL_UNLESS(is_null[0] == 0, "Wrong value for is_null");
++ FAIL_UNLESS(length[0] == 1, "length != 0");
++
++ FAIL_UNLESS(int_data == o_int_data, "Wrong value for int_data");
++ FAIL_UNLESS(length[2] == 4, "length != 4");
++
++ FAIL_UNLESS(small_data == o_small_data, "Wrong value for small_data");
++ FAIL_UNLESS(length[3] == 2, "length != 2");
++
++ FAIL_UNLESS(big_data == o_big_data, "Wrong value for big_data");
++ FAIL_UNLESS(length[4] == 8, "length != 8");
++
++ FAIL_UNLESS(real_data == o_real_data, "Wrong value for real_data");
++ FAIL_UNLESS(length[5] == 4, "length != 4");
++
++ FAIL_UNLESS(double_data == o_double_data, "Wrong value for double_data");
++ FAIL_UNLESS(length[6] == 8, "length != 8");
++
++ FAIL_UNLESS(strcmp(data, str_data) == 0, "Wrong value for data");
++ FAIL_UNLESS(length[1] == len, "length != len");
++
++ o_int_data += 25;
++ o_small_data += 10;
++ o_big_data += 100;
++ o_real_data += 1;
++ o_double_data += 10.09;
++ }
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_prepare_multi_statements(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ char query[MAX_TEST_QUERY_LENGTH];
++ int rc;
++
++ strcpy(query, "select 1; select 'another value'");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "Error expected");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_prepare_ext(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char *sql;
++ int nData= 1;
++ char tData= 1;
++ short sData= 10;
++ longlong bData= 20;
++ int rowcount= 0;
++ MYSQL_BIND my_bind[6];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_ext");
++ check_mysql_rc(rc, mysql)
++
++ sql= (char *)"CREATE TABLE test_prepare_ext"
++ "("
++ " c1 tinyint,"
++ " c2 smallint,"
++ " c3 mediumint,"
++ " c4 int,"
++ " c5 integer,"
++ " c6 bigint,"
++ " c7 float,"
++ " c8 double,"
++ " c9 double precision,"
++ " c10 real,"
++ " c11 decimal(7, 4),"
++ " c12 numeric(8, 4),"
++ " c13 date,"
++ " c14 datetime,"
++ " c15 timestamp,"
++ " c16 time,"
++ " c17 year,"
++ " c18 bit,"
++ " c19 bool,"
++ " c20 char,"
++ " c21 char(10),"
++ " c22 varchar(30),"
++ " c23 tinyblob,"
++ " c24 tinytext,"
++ " c25 blob,"
++ " c26 text,"
++ " c27 mediumblob,"
++ " c28 mediumtext,"
++ " c29 longblob,"
++ " c30 longtext,"
++ " c31 enum('one', 'two', 'three'),"
++ " c32 set('monday', 'tuesday', 'wednesday'))";
++
++ rc= mysql_query(mysql, sql);
++ check_mysql_rc(rc, mysql)
++
++ /* insert by prepare - all integers */
++ strcpy(query, "INSERT INTO test_prepare_ext(c1, c2, c3, c4, c5, c6) VALUES(?, ?, ?, ?, ?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 6, "Paramcount != 6");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /*tinyint*/
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&tData;
++
++ /*smallint*/
++ my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[1].buffer= (void *)&sData;
++
++ /*mediumint*/
++ my_bind[2].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[2].buffer= (void *)&nData;
++
++ /*int*/
++ my_bind[3].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[3].buffer= (void *)&nData;
++
++ /*integer*/
++ my_bind[4].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[4].buffer= (void *)&nData;
++
++ /*bigint*/
++ my_bind[5].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[5].buffer= (void *)&bData;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /*
++ * integer to integer
++ */
++ for (nData= 0; nData<10; nData++, tData++, sData++, bData++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++
++ strcpy(query, "SELECT c1, c2, c3, c4, c5, c6 FROM test_prepare_ext");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ /* get the result */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++
++ FAIL_UNLESS(nData == rowcount, "Invalid rowcount");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_prepare_alter(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL *mysql_new;
++ int rc, id;
++ MYSQL_BIND my_bind[1];
++ my_bool is_null;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_alter");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prep_alter(id int, name char(20))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_prep_alter values(10, 'venu'), (20, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_prep_alter VALUES(?, 'monty')");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ is_null= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[0].buffer= (void *)&id;
++ my_bind[0].is_null= &is_null;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ id= 30;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++
++ mysql_new= mysql_init(NULL);
++ FAIL_IF(!mysql_new, "mysql_init failed");
++ FAIL_IF(!(mysql_real_connect(mysql_new, hostname, username, password,
++ schema, port, socketname, 0)), "mysql_real_connect failed");
++ rc= mysql_query(mysql_new, "ALTER TABLE test_prep_alter change id id_new varchar(20)");
++ check_mysql_rc(rc, mysql_new);
++ mysql_close(mysql_new);
++
++ is_null= 1;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= my_stmt_result(mysql, "SELECT * FROM test_prep_alter");
++ FAIL_UNLESS(rc == 4, "rowcount != 4");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_prepare_resultset(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ MYSQL_RES *result;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_resultset");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prepare_resultset(id int, \
++ name varchar(50), extra double)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ strcpy(query, "SELECT * FROM test_prepare_resultset");
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt), "Paramcount != 0");
++
++ result= mysql_stmt_result_metadata(stmt);
++ FAIL_IF(!result, "Invalid resultset");
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++/* Test the direct query execution in the middle of open stmts */
++
++static int test_open_direct(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_open_direct");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_open_direct(id int, name char(6))");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_open_direct values(10, 'mysql')");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "invalid resultset");
++
++ FAIL_IF(mysql_num_rows(result), "rowcount != 0");
++ mysql_free_result(result);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "affected rows != 1");
++
++ rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "invalid resultset");
++
++ FAIL_IF(mysql_num_rows(result) != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "affected rows != 1");
++
++ rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid resultset");
++ FAIL_IF(mysql_num_rows(result) != 2, "rowcount != 2");
++
++ mysql_free_result(result);
++
++ mysql_stmt_close(stmt);
++
++ /* run a direct query in the middle of a fetch */
++
++ strcpy(query, "SELECT * FROM test_open_direct");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)");
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)");
++ check_mysql_rc(rc, mysql);
++
++ /* run a direct query with store result */
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "drop table test_open_direct");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ return OK;
++}
++
++static int test_select_show(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++ int rowcount;
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_show");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_show(id int(4) NOT NULL primary "
++ " key, name char(2))");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "show columns from test_show");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 2, "rowcount != 2");
++
++ mysql_stmt_close(stmt);
++
++ strcpy(query, "show tables from mysql like ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "Error expected");
++
++ strcpy(query, "show tables like \'test_show\'");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_stmt_close(stmt);
++
++ strcpy(query, "describe test_show");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 2, "rowcount != 2");
++ mysql_stmt_close(stmt);
++
++ strcpy(query, "show keys from test_show");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rowcount= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_simple_update(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char szData[25];
++ int nData= 1;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ ulong length[2];
++ int rowcount= 0;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_update(col1 int, "
++ " col2 varchar(50), col3 int )");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_update VALUES(1, 'MySQL', 100)");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_IF(mysql_affected_rows(mysql) != 1, "Affected rows != 1");
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare */
++ strcpy(query, "UPDATE test_update SET col2= ? WHERE col1= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ nData= 1;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= szData; /* string data */
++ my_bind[0].buffer_length= sizeof(szData);
++ my_bind[0].length= &length[0];
++ length[0]= sprintf(szData, "updated-data");
++
++ my_bind[1].buffer= (void *) &nData;
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected_rows != 1");
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM test_update");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid resultset");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++/* Test simple long data handling */
++
++static int test_long_data(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, int_data;
++ char *data= NullS;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[3];
++ int rowcount;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, "
++ " col2 long varchar, col3 long varbinary)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_long_data(col1, col2) VALUES(?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ strcpy(query, "INSERT INTO test_long_data(col1, col2, col3) VALUES(?, ?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "Paramcount != 3");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)&int_data;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++
++ my_bind[2]= my_bind[1];
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ int_data= 999;
++ data= (char *)"Michael";
++
++ /* supply data in pieces */
++ rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++ data= (char *)" 'Monty' Widenius";
++ rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_send_long_data(stmt, 2, "Venu (venu@mysql.com)", 4);
++ check_stmt_rc(rc, stmt);
++
++ /* execute */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* now fetch the results ..*/
++ rc= mysql_query(mysql, "SELECT * FROM test_long_data");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rowcount= 0;
++ while (mysql_fetch_row(result))
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ if (verify_col_data(mysql, "test_long_data", "col1", "999"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col2", "Michael 'Monty' Widenius"))
++ goto error;
++ if (verify_col_data(mysql, "test_long_data", "col3", "Venu"))
++ goto error;
++
++ mysql_stmt_close(stmt);
++ return OK;
++
++error:
++ mysql_stmt_close(stmt);
++ return FAIL;
++}
++
++
++/* Test long data (string) handling */
++
++static int test_long_data_str(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i, rowcount= 0;
++ char data[255];
++ long length;
++ ulong length1;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ my_bool is_null[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(id int, longstr long varchar)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_long_data_str VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)&length;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].is_null= &is_null[0];
++ is_null[0]= 0;
++ length= 0;
++
++ my_bind[1].buffer= data; /* string data */
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].length= &length1;
++ my_bind[1].is_null= &is_null[1];
++ is_null[1]= 0;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ length= 40;
++ strcpy(data, "MySQL AB");
++
++ /* supply data in pieces */
++ for(i= 0; i < 4; i++)
++ {
++ rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 5);
++ check_stmt_rc(rc, stmt);
++ }
++ /* execute */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* now fetch the results ..*/
++ rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr FROM test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++
++ mysql_free_result(result);
++
++ sprintf(data, "%d", i*5);
++ if (verify_col_data(mysql, "test_long_data_str", "LENGTH(longstr)", data))
++ goto error;
++ strcpy(data, "MySQLMySQLMySQLMySQL");
++ if (verify_col_data(mysql, "test_long_data_str", "longstr", data))
++ goto error;
++
++ rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++
++error:
++ rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
++ check_mysql_rc(rc, mysql);
++ return FAIL;
++}
++
++
++/* Test long data (string) handling */
++
++static int test_long_data_str1(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i, rowcount= 0;
++ char data[255];
++ long length;
++ ulong max_blob_length, blob_length, length1;
++ my_bool true_value;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ MYSQL_FIELD *field;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(longstr long varchar, blb long varbinary)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_long_data_str VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= data; /* string data */
++ my_bind[0].buffer_length= sizeof(data);
++ my_bind[0].length= &length1;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ length1= 0;
++
++ my_bind[1]= my_bind[0];
++ my_bind[1].buffer_type= MYSQL_TYPE_BLOB;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ length= sprintf(data, "MySQL AB");
++
++ /* supply data in pieces */
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_send_long_data(stmt, 0, data, length);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_send_long_data(stmt, 1, data, 2);
++ check_stmt_rc(rc, stmt);
++ }
++
++ /* execute */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* now fetch the results ..*/
++ rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr, LENGTH(blb), blb FROM test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++
++ mysql_field_seek(result, 1);
++ field= mysql_fetch_field(result);
++ max_blob_length= field->max_length;
++
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ sprintf(data, "%ld", (long)i*length);
++ if (verify_col_data(mysql, "test_long_data_str", "length(longstr)", data))
++ return FAIL;
++
++ sprintf(data, "%d", i*2);
++ if (verify_col_data(mysql, "test_long_data_str", "length(blb)", data))
++ return FAIL;
++
++ /* Test length of field->max_length */
++ strcpy(query, "SELECT * from test_long_data_str");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_fields(result);
++
++ /* First test what happens if STMT_ATTR_UPDATE_MAX_LENGTH is not used */
++ FAIL_IF(field->max_length != 0, "field->max_length != 0");
++ mysql_free_result(result);
++
++ /* Enable updating of field->max_length */
++ true_value= 1;
++ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &true_value);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ result= mysql_stmt_result_metadata(stmt);
++ field= mysql_fetch_fields(result);
++
++ FAIL_UNLESS(field->max_length == max_blob_length, "field->max_length != max_blob_length");
++
++ /* Fetch results into a data buffer that is smaller than data */
++ memset(my_bind, '\0', sizeof(*my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_BLOB;
++ my_bind[0].buffer= (void *) &data; /* this buffer won't be altered */
++ my_bind[0].buffer_length= 16;
++ my_bind[0].length= &blob_length;
++ my_bind[0].error= &my_bind[0].error_value;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ data[16]= 0;
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "truncation expected");
++ FAIL_UNLESS(my_bind[0].error_value, "No error value");
++ FAIL_UNLESS(strlen(data) == 16, "Invalid string length");
++ FAIL_UNLESS(blob_length == max_blob_length, "blob_length != max_blob_length");
++
++ /* Fetch all data */
++ memset((my_bind+1), '\0', sizeof(*my_bind));
++ my_bind[1].buffer_type= MYSQL_TYPE_BLOB;
++ my_bind[1].buffer= (void *) &data; /* this buffer won't be altered */
++ my_bind[1].buffer_length= sizeof(data);
++ my_bind[1].length= &blob_length;
++ memset(data, '\0', sizeof(data));
++ mysql_stmt_fetch_column(stmt, my_bind+1, 0, 0);
++ FAIL_UNLESS(strlen(data) == max_blob_length, "strlen(data) != max_blob_length");
++
++ mysql_free_result(result);
++ mysql_stmt_close(stmt);
++
++ /* Drop created table */
++ rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++/* Test long data (binary) handling */
++
++static int test_long_data_bin(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, rowcount= 0;
++ char data[255];
++ long length;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_bin");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_long_data_bin(id int, longbin long varbinary)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_long_data_bin VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)&length;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ length= 0;
++
++ my_bind[1].buffer= data; /* string data */
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG_BLOB;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ length= 10;
++ strcpy(data, "MySQL AB");
++
++ /* supply data in pieces */
++ {
++ int i;
++ for (i= 0; i < 100; i++)
++ {
++ rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 4);
++ check_stmt_rc(rc, stmt);
++ }
++ }
++ /* execute */
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* now fetch the results ..*/
++ rc= mysql_query(mysql, "SELECT LENGTH(longbin), longbin FROM test_long_data_bin");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++/* Test simple delete */
++
++static int test_simple_delete(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, rowcount= 0;
++ char szData[30]= {0};
++ int nData= 1;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ ulong length[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_simple_delete");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_simple_delete(col1 int, \
++ col2 varchar(50), col3 int )");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_simple_delete VALUES(1, 'MySQL', 100)");
++ check_mysql_rc(rc, mysql);
++
++ FAIL_IF(mysql_affected_rows(mysql) != 1, "Affected rows != 1");
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare */
++ strcpy(query, "DELETE FROM test_simple_delete WHERE col1= ? AND "
++ "CONVERT(col2 USING utf8)= ? AND col3= 100");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt)
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ nData= 1;
++ strcpy(szData, "MySQL");
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= szData; /* string data */
++ my_bind[1].buffer_length= sizeof(szData);
++ my_bind[1].length= &length[1];
++ length[1]= 5;
++
++ my_bind[0].buffer= (void *)&nData;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM test_simple_delete");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount, "rowcount > 0");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++static int test_update(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char szData[25];
++ int nData= 1, rowcount= 0;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ ulong length[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_update("
++ "col1 int primary key auto_increment, "
++ "col2 varchar(50), col3 int )");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_update(col2, col3) VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* string data */
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= szData;
++ my_bind[0].buffer_length= sizeof(szData);
++ my_bind[0].length= &length[0];
++ length[0]= sprintf(szData, "inserted-data");
++
++ my_bind[1].buffer= (void *)&nData;
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ nData= 100;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
++ mysql_stmt_close(stmt);
++
++ strcpy(query, "UPDATE test_update SET col2= ? WHERE col3= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
++ nData= 100;
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= szData;
++ my_bind[0].buffer_length= sizeof(szData);
++ my_bind[0].length= &length[0];
++ length[0]= sprintf(szData, "updated-data");
++
++ my_bind[1].buffer= (void *)&nData;
++ my_bind[1].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
++
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM test_update");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++/* Test prepare without parameters */
++
++static int test_prepare_noparam(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, rowcount= 0;
++ MYSQL_RES *result;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare");
++ check_mysql_rc(rc, mysql);
++
++
++ rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 int, col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare */
++ strcpy(query, "INSERT INTO my_prepare VALUES(10, 'venu')");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM my_prepare");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 1, "rowcount != 1");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++
++/* Test simple bind result */
++
++static int test_bind_result(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ int nData;
++ ulong length1;
++ char szData[100];
++ MYSQL_BIND my_bind[2];
++ my_bool is_null[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_result(col1 int , col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(10, 'venu')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(20, 'MySQL')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result(col2) VALUES('monty')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* fetch */
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *) &nData; /* integer data */
++ my_bind[0].is_null= &is_null[0];
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= szData; /* string data */
++ my_bind[1].buffer_length= sizeof(szData);
++ my_bind[1].length= &length1;
++ my_bind[1].is_null= &is_null[1];
++
++ strcpy(query, "SELECT * FROM test_bind_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 10, "nData != 10");
++ FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
++ FAIL_UNLESS(length1 == 4, "length1 != 4");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 20, "nData != 20");
++ FAIL_UNLESS(strcmp(szData, "MySQL") == 0, "szData != 'MySQL'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(is_null[0], "null flag not set");
++ FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'Monty'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bind_result_ext(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ uchar t_data;
++ short s_data;
++ int i_data;
++ longlong b_data;
++ float f_data;
++ double d_data;
++ char szData[20], bData[20];
++ ulong szLength, bLength;
++ MYSQL_BIND my_bind[8];
++ ulong length[8];
++ my_bool is_null[8];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, "
++ " c2 smallint, "
++ " c3 int, c4 bigint, "
++ " c5 float, c6 double, "
++ " c7 varbinary(10), "
++ " c8 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result "
++ "VALUES (19, 2999, 3999, 4999999, "
++ " 2345.6, 5678.89563, 'venu', 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < (int) array_elements(my_bind); i++)
++ {
++ my_bind[i].length= &length[i];
++ my_bind[i].is_null= &is_null[i];
++ }
++
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&t_data;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[2].buffer_type= MYSQL_TYPE_LONG;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG;
++ my_bind[1].buffer= (void *)&s_data;
++
++ my_bind[2].buffer= (void *)&i_data;
++ my_bind[3].buffer= (void *)&b_data;
++
++ my_bind[4].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[4].buffer= (void *)&f_data;
++
++ my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[5].buffer= (void *)&d_data;
++
++ my_bind[6].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[6].buffer= (void *)szData;
++ my_bind[6].buffer_length= sizeof(szData);
++ my_bind[6].length= &szLength;
++
++ my_bind[7].buffer_type= MYSQL_TYPE_TINY_BLOB;
++ my_bind[7].buffer= (void *)&bData;
++ my_bind[7].length= &bLength;
++ my_bind[7].buffer_length= sizeof(bData);
++
++ strcpy(query, "select * from test_bind_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(t_data == 19, "tdata != 19");
++ FAIL_UNLESS(s_data == 2999, "s_data != 2999");
++ FAIL_UNLESS(i_data == 3999, "i_data != 3999");
++ FAIL_UNLESS(b_data == 4999999, "b_data != 4999999");
++ FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
++ FAIL_UNLESS(strncmp(bData, "mysql", 5) == 0, "nData != 'mysql'");
++ FAIL_UNLESS(szLength == 4, "szLength != 4");
++ FAIL_UNLESS(bLength == 5, "bLength != 5");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++
++/* Test ext bind result */
++
++static int test_bind_result_ext1(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ uint i;
++ int rc;
++ char t_data[20];
++ float s_data;
++ short i_data;
++ uchar b_data;
++ int f_data;
++ long bData;
++ char d_data[20];
++ double szData;
++ MYSQL_BIND my_bind[8];
++ ulong length[8];
++ my_bool is_null[8];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, c2 smallint, \
++ c3 int, c4 bigint, \
++ c5 float, c6 double, \
++ c7 varbinary(10), \
++ c8 varchar(10))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(120, 2999, 3999, 54, \
++ 2.6, 58.89, \
++ '206', '6.7')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *) t_data;
++ my_bind[0].buffer_length= sizeof(t_data);
++ my_bind[0].error= &my_bind[0].error_value;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_FLOAT;
++ my_bind[1].buffer= (void *)&s_data;
++ my_bind[1].buffer_length= 0;
++ my_bind[1].error= &my_bind[1].error_value;
++
++ my_bind[2].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[2].buffer= (void *)&i_data;
++ my_bind[2].buffer_length= 0;
++ my_bind[2].error= &my_bind[2].error_value;
++
++ my_bind[3].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[3].buffer= (void *)&b_data;
++ my_bind[3].buffer_length= 0;
++ my_bind[3].error= &my_bind[3].error_value;
++
++ my_bind[4].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[4].buffer= (void *)&f_data;
++ my_bind[4].buffer_length= 0;
++ my_bind[4].error= &my_bind[4].error_value;
++
++ my_bind[5].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[5].buffer= (void *)d_data;
++ my_bind[5].buffer_length= sizeof(d_data);
++ my_bind[5].error= &my_bind[5].error_value;
++
++ my_bind[6].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[6].buffer= (void *)&bData;
++ my_bind[6].buffer_length= 0;
++ my_bind[6].error= &my_bind[6].error_value;
++
++ my_bind[7].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[7].buffer= (void *)&szData;
++ my_bind[7].buffer_length= 0;
++ my_bind[7].error= &my_bind[7].error_value;
++
++ for (i= 0; i < array_elements(my_bind); i++)
++ {
++ my_bind[i].is_null= &is_null[i];
++ my_bind[i].length= &length[i];
++ }
++
++ strcpy(query, "select * from test_bind_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(strcmp(t_data, "120") == 0, "t_data != 120");
++ FAIL_UNLESS(i_data == 3999, "i_data != 3999");
++ FAIL_UNLESS(f_data == 2, "f_data != 2");
++ FAIL_UNLESS(strcmp(d_data, "58.89") == 0, "d_data != 58.89");
++ FAIL_UNLESS(b_data == 54, "b_data != 54");
++
++ FAIL_UNLESS(length[0] == 3, "Wrong length");
++ FAIL_UNLESS(length[1] == 4, "Wrong length");
++ FAIL_UNLESS(length[2] == 2, "Wrong length");
++ FAIL_UNLESS(length[3] == 1, "Wrong length");
++ FAIL_UNLESS(length[4] == 4, "Wrong length");
++ FAIL_UNLESS(length[5] == 5, "Wrong length");
++ FAIL_UNLESS(length[6] == 4, "Wrong length");
++ FAIL_UNLESS(length[7] == 8, "Wrong length");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_bind_negative(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ char *query;
++ int rc;
++ MYSQL_BIND my_bind[1];
++ int32 my_val= 0;
++ ulong my_length= 0L;
++ my_bool my_null= FALSE;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create temporary table t1 (c1 int unsigned)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (-1)");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"INSERT INTO t1 VALUES (?)";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ /* bind parameters */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&my_val;
++ my_bind[0].length= &my_length;
++ my_bind[0].is_null= (char*)&my_null;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ my_val= -1;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_buffers(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ int rc;
++ ulong length;
++ my_bool is_null;
++ char buffer[20];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_buffer");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_buffer(str varchar(20))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into test_buffer values('MySQL')\
++ , ('Database'), ('Open-Source'), ('Popular')");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "select str from test_buffer");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(buffer, '\0', sizeof(buffer)); /* Avoid overruns in printf() */
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].length= &length;
++ my_bind[0].is_null= &is_null;
++ my_bind[0].buffer_length= 1;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)buffer;
++ my_bind[0].error= &my_bind[0].error_value;
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ buffer[1]= 'X';
++ rc= mysql_stmt_fetch(stmt);
++
++ FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "rc != MYSQL_DATA_TRUNCATED");
++ FAIL_UNLESS(my_bind[0].error_value, "Errorflag not set");
++ FAIL_UNLESS(buffer[0] == 'M', "buffer[0] != M");
++ FAIL_UNLESS(buffer[1] == 'X', "buffer[1] != X");
++ FAIL_UNLESS(length == 5, "length != 5");
++
++ my_bind[0].buffer_length= 8;
++ rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(strncmp(buffer, "Database", 8) == 0, "buffer != 'Database'");
++ FAIL_UNLESS(length == 8, "length != 8");
++
++ my_bind[0].buffer_length= 12;
++ rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(strcmp(buffer, "Open-Source") == 0, "buffer != 'Open-Source'");
++ FAIL_UNLESS(length == 11, "Length != 11");
++
++ my_bind[0].buffer_length= 6;
++ rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "rc != MYSQL_DATA_TRUNCATED");
++ FAIL_UNLESS(my_bind[0].error_value, "Errorflag not set");
++ FAIL_UNLESS(strncmp(buffer, "Popula", 6) == 0, "buffer != 'Popula'");
++ FAIL_UNLESS(length == 7, "length != 7");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_xjoin(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query=
++ "select t.id, p1.value, n1.value, p2.value, n2.value from t3 t LEFT JOIN t1 p1 ON (p1.id=t.param1_id) LEFT JOIN t2 p2 ON (p2.id=t.param2_id) LEFT JOIN t4 n1 ON (n1.id=p1.name_id) LEFT JOIN t4 n2 ON (n2.id=p2.name_id) where t.id=1";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t3 (id int(8), param1_id int(8), param2_id int(8)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 ( id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t2 (id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t4(id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t3 values (1, 1, 1), (2, 2, null)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (1, 1, 'aaa'), (2, null, 'bbb')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t2 values (1, 2, 'ccc')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t4 values (1, 'Name1'), (2, null)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1, t2, t3, t4");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_union_param(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ char *query;
++ int rc, i;
++ MYSQL_BIND my_bind[2];
++ char my_val[4];
++ ulong my_length= 3L;
++ my_bool my_null= FALSE;
++
++ strcpy(my_val, "abc");
++
++ query= (char*)"select ? as my_col union distinct select ?";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* bind parameters */
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (char*) &my_val;
++ my_bind[0].buffer_length= 4;
++ my_bind[0].length= &my_length;
++ my_bind[0].is_null= (char*)&my_null;
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (char*) &my_val;
++ my_bind[1].buffer_length= 4;
++ my_bind[1].length= &my_length;
++ my_bind[1].is_null= (char*)&my_null;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ }
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_union(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ const char *query= "SELECT t1.name FROM t1 UNION "
++ "SELECT t2.name FROM t2";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "CREATE TABLE t1 "
++ "(id INTEGER NOT NULL PRIMARY KEY, "
++ " name VARCHAR(20) NOT NULL)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "INSERT INTO t1 (id, name) VALUES "
++ "(2, 'Ja'), (3, 'Ede'), "
++ "(4, 'Haag'), (5, 'Kabul'), "
++ "(6, 'Almere'), (7, 'Utrecht'), "
++ "(8, 'Qandahar'), (9, 'Amsterdam'), "
++ "(10, 'Amersfoort'), (11, 'Constantine')");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE TABLE t2 "
++ "(id INTEGER NOT NULL PRIMARY KEY, "
++ " name VARCHAR(20) NOT NULL)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "INSERT INTO t2 (id, name) VALUES "
++ "(4, 'Guam'), (5, 'Aruba'), "
++ "(6, 'Angola'), (7, 'Albania'), "
++ "(8, 'Anguilla'), (9, 'Argentina'), "
++ "(10, 'Azerbaijan'), (11, 'Afghanistan'), "
++ "(12, 'Burkina Faso'), (13, 'Faroe Islands')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 20, "rc != 20");
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_union2(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query= "select col1 FROM t1 where col1=1 union distinct "
++ "select col1 FROM t1 where col1=2";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1(col1 INT, \
++ col2 VARCHAR(40), \
++ col3 SMALLINT, \
++ col4 TIMESTAMP)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 0, "rowcount != 0");
++ }
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Misc tests to keep pure coverage happy */
++
++static int test_pure_coverage(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ int rc;
++ ulong length;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_pure");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_pure(c1 int, c2 varchar(20))");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "insert into test_pure(c67788) values(10)", strlen("insert into test_pure(c67788) values(10)"));
++ FAIL_IF(!rc, "Error expected");
++ mysql_stmt_close(stmt);
++
++ /* Query without params and result should allow to bind 0 arrays */
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "insert into test_pure(c2) values(10)", strlen("insert into test_pure(c2) values(10)"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, (MYSQL_BIND*)0);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_result(stmt, (MYSQL_BIND*)0);
++ FAIL_UNLESS(rc == 1, "");
++
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "insert into test_pure(c2) values(?)", strlen("insert into test_pure(c2) values(?)"));
++ check_stmt_rc(rc, stmt);
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].length= &length;
++ my_bind[0].is_null= 0;
++ my_bind[0].buffer_length= 0;
++
++ my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ FAIL_IF(!rc, "Error expected");
++
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "select * from test_pure", strlen("select * from test_pure"));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++
++ /* Since libmariadb supports geometry types in prepared statements
++ we have to skip the following check
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_stmt_store_result(stmt);
++ FAIL_UNLESS(rc, "");
++
++ rc= mysql_stmt_store_result(stmt);
++ FAIL_UNLESS(rc, "");
++
++ */
++ mysql_stmt_close(stmt);
++
++ mysql_query(mysql, "DROP TABLE test_pure");
++ return OK;
++}
++
++static int test_insert_select(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt_insert, *stmt_select;
++ char *query;
++ int rc;
++ uint i;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t2 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t2 values (1)");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"insert into t1 select a from t2";
++ stmt_insert= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_insert, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_insert, query, strlen(query));
++ check_stmt_rc(rc, stmt_insert);
++
++ query= (char*)"select * from t1";
++ stmt_select= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_select, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_select, query, strlen(query));
++ check_stmt_rc(rc, stmt_select);
++
++ for(i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt_insert);
++ check_stmt_rc(rc, stmt_insert);
++
++ rc= mysql_stmt_execute(stmt_select);
++ check_stmt_rc(rc, stmt_select);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == (int)(i+1), "rc != i+1");
++ }
++
++ mysql_stmt_close(stmt_insert);
++ mysql_stmt_close(stmt_select);
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test simple prepare-insert */
++
++static int test_insert(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char str_data[50];
++ char tiny_data;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[2];
++ ulong length;
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_insert");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_prep_insert(col1 tinyint, \
++ col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare */
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "INSERT INTO test_prep_insert VALUES(?, ?)",
++ strlen("INSERT INTO test_prep_insert VALUES(?, ?)"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Param_count != 2");
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* tinyint */
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&tiny_data;
++
++ /* string */
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= str_data;
++ my_bind[1].buffer_length= sizeof(str_data);;
++ my_bind[1].length= &length;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /* now, execute the prepared statement to insert 10 records.. */
++ for (tiny_data= 0; tiny_data < 3; tiny_data++)
++ {
++ length= sprintf(str_data, "MySQL%d", tiny_data);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM test_prep_insert");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS((int) tiny_data == rc, "rowcount != tinydata");
++ mysql_free_result(result);
++
++ return OK;
++}
++
++static int test_join(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i, j;
++ const char *query[]= {"SELECT * FROM t2 join t1 on (t1.a=t2.a)",
++ "SELECT * FROM t2 natural join t1",
++ "SELECT * FROM t2 join t1 using(a)",
++ "SELECT * FROM t2 left join t1 on(t1.a=t2.a)",
++ "SELECT * FROM t2 natural left join t1",
++ "SELECT * FROM t2 left join t1 using(a)",
++ "SELECT * FROM t2 right join t1 on(t1.a=t2.a)",
++ "SELECT * FROM t2 natural right join t1",
++ "SELECT * FROM t2 right join t1 using(a)"};
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t2 (a int , c int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "insert into t2 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);");
++ check_mysql_rc(rc, mysql);
++
++ for (j= 0; j < 9; j++)
++ {
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query[j], strlen(query[j]));
++ check_stmt_rc(rc, stmt);
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 5, "rowcount != 5");
++ }
++ mysql_stmt_close(stmt);
++ }
++
++ rc= mysql_query(mysql, "DROP TABLE t1, t2");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_left_join_view(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query=
++ "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
++
++
++ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
++ check_mysql_rc(rc, mysql);
++
++ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
++ check_mysql_rc(rc, mysql);
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 3, "rowcount != 3");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test simple sample - manual */
++
++static int test_manual_sample(MYSQL *mysql)
++{
++ unsigned int param_count;
++ MYSQL_STMT *stmt;
++ short small_data;
++ int int_data;
++ int rc;
++ char str_data[50];
++ ulonglong affected_rows;
++ MYSQL_BIND my_bind[3];
++ my_bool is_null;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ /*
++ Sample which is incorporated directly in the manual under Prepared
++ statements section (Example from mysql_stmt_execute()
++ */
++
++ memset(str_data, 0, sizeof(str_data));
++ mysql_autocommit(mysql, 1);
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE test_table(col1 int, col2 varchar(50), \
++ col3 smallint, \
++ col4 timestamp)");
++ check_mysql_rc(rc, mysql);
++
++ /* Prepare a insert query with 3 parameters */
++ strcpy(query, "INSERT INTO test_table(col1, col2, col3) values(?, ?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ /* Get the parameter count from the statement */
++ param_count= mysql_stmt_param_count(stmt);
++ FAIL_IF(param_count != 3, "param_count != 3");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* INTEGER PART */
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&int_data;
++
++ /* STRING PART */
++ my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
++ my_bind[1].buffer= (void *)str_data;
++ my_bind[1].buffer_length= sizeof(str_data);
++
++ /* SMALLINT PART */
++ my_bind[2].buffer_type= MYSQL_TYPE_SHORT;
++ my_bind[2].buffer= (void *)&small_data;
++ my_bind[2].is_null= &is_null;
++ is_null= 0;
++
++ /* Bind the buffers */
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /* Specify the data */
++ int_data= 10; /* integer */
++ strcpy(str_data, "MySQL"); /* string */
++
++ /* INSERT SMALLINT data as NULL */
++ is_null= 1;
++
++ /* Execute the insert statement - 1*/
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* Get the total rows affected */
++ affected_rows= mysql_stmt_affected_rows(stmt);
++ FAIL_IF(affected_rows != 1, "affected-rows != 1");
++
++ /* Re-execute the insert, by changing the values */
++ int_data= 1000;
++ strcpy(str_data, "The most popular open source database");
++ small_data= 1000; /* smallint */
++ is_null= 0; /* reset */
++
++ /* Execute the insert statement - 2*/
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* Get the total rows affected */
++ affected_rows= mysql_stmt_affected_rows(stmt);
++
++ FAIL_IF(affected_rows != 1, "affected_rows != 1");
++
++ /* Close the statement */
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* DROP THE TABLE */
++ rc= mysql_query(mysql, "DROP TABLE test_table");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_create_drop(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select;
++ char *query;
++ int rc, i;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t2 (a int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (a int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t2 values (3), (2), (1);");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"create table t1 (a int)";
++ stmt_create= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_create, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_create, query, strlen(query));
++ check_stmt_rc(rc, stmt_create);
++
++ query= (char*)"drop table t1";
++ stmt_drop= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_drop, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_drop, query, strlen(query));
++ check_stmt_rc(rc, stmt_drop);
++
++ query= (char*)"select a in (select a from t2) from t1";
++ stmt_select= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_select, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_select, query, strlen(query));
++ check_stmt_rc(rc, stmt_select);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"create table t1 select a from t2";
++ stmt_create_select= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_create_select, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_create_select, query, strlen(query));
++ check_stmt_rc(rc, stmt_create_select);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt_create);
++ check_stmt_rc(rc, stmt_create);
++
++ rc= mysql_stmt_execute(stmt_select);
++ check_stmt_rc(rc, stmt_select);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 0, "rowcount != 0");
++
++ rc= mysql_stmt_execute(stmt_drop);
++ check_stmt_rc(rc, stmt_drop);
++
++ rc= mysql_stmt_execute(stmt_create_select);
++ check_stmt_rc(rc, stmt_create);
++
++ rc= mysql_stmt_execute(stmt_select);
++ check_stmt_rc(rc, stmt_select);
++ rc= 0;
++ while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 3, "rowcount != 3");
++
++ rc= mysql_stmt_execute(stmt_drop);
++ check_stmt_rc(rc, stmt_drop);
++ }
++
++ mysql_stmt_close(stmt_create);
++ mysql_stmt_close(stmt_drop);
++ mysql_stmt_close(stmt_select);
++ mysql_stmt_close(stmt_create_select);
++
++ rc= mysql_query(mysql, "DROP TABLE t2");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test DATE, TIME, DATETIME and TS with MYSQL_TIME conversion */
++
++static int test_date(MYSQL *mysql)
++{
++ int rc;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \
++ c2 TIME, \
++ c3 DATETIME, \
++ c4 DATE)");
++
++ check_mysql_rc(rc, mysql);
++
++ return test_bind_date_conv(mysql, 5);
++}
++
++
++/* Test all time types to DATE and DATE to all types */
++
++static int test_date_date(MYSQL *mysql)
++{
++ int rc;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_date(c1 DATE, \
++ c2 DATE, \
++ c3 DATE, \
++ c4 DATE)");
++
++ check_mysql_rc(rc, mysql);
++
++ return test_bind_date_conv(mysql, 3);
++}
++
++/* Test all time types to TIMESTAMP and TIMESTAMP to all types */
++
++static int test_date_ts(MYSQL *mysql)
++{
++ int rc;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \
++ c2 TIMESTAMP, \
++ c3 TIMESTAMP, \
++ c4 TIMESTAMP)");
++
++ check_mysql_rc(rc, mysql);
++
++ return test_bind_date_conv(mysql, 2);
++}
++
++
++/* Test all time types to DATETIME and DATETIME to all types */
++
++static int test_date_dt(MYSQL *mysql)
++{
++ int rc;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_date(c1 datetime, "
++ " c2 datetime, c3 datetime, c4 date)");
++ check_mysql_rc(rc, mysql);
++
++ return test_bind_date_conv(mysql, 2);
++}
++
++/* Test all time types to TIME and TIME to all types */
++
++static int test_date_time(MYSQL *mysql)
++{
++ int rc;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIME, \
++ c2 TIME, \
++ c3 TIME, \
++ c4 TIME)");
++
++ check_mysql_rc(rc, mysql);
++
++ return test_bind_date_conv(mysql, 3);
++}
++
++/*
++ Test of basic checks that are performed in server for components
++ of MYSQL_TIME parameters.
++*/
++
++static int test_datetime_ranges(MYSQL *mysql)
++{
++ const char *stmt_text;
++ int rc, i;
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[6];
++ MYSQL_TIME tm[6];
++
++
++ stmt_text= "drop table if exists t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "create table t1 (year datetime, month datetime, day datetime, "
++ "hour datetime, min datetime, sec datetime)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ stmt_text= "INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_stmt_param_count(stmt) != 6, "param_count != 6");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < 6; i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_DATETIME;
++ my_bind[i].buffer= &tm[i];
++ }
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10;
++ tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
++ tm[0].second_part= 0; tm[0].neg= 0;
++
++ tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
++ tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32;
++ tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_warning_count(mysql) != 6, "warning count != 6");
++
++ if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "month", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "day", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "hour", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "min", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "sec", "0000-00-00 00:00:00"))
++ goto error;
++
++ mysql_stmt_close(stmt);
++
++ stmt_text= "delete from t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "INSERT INTO t1 (year, month, day) VALUES (?, ?, ?)";
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ /*
++ We reuse contents of bind and tm arrays left from previous part of test.
++ */
++ for (i= 0; i < 3; i++)
++ my_bind[i].buffer_type= MYSQL_TYPE_DATE;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_warning_count(mysql) != 3, "warning count != 3");
++
++ if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "month", "0000-00-00 00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "day", "0000-00-00 00:00:00"))
++ goto error;
++
++ mysql_stmt_close(stmt);
++
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ stmt_text= "INSERT INTO t1 VALUES (?,?,?,?,?)";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_stmt_param_count(stmt) != 5, "param_count != 5");
++
++ /*
++ Again we reuse what we can from previous part of test.
++ */
++ for (i= 0; i < 5; i++)
++ my_bind[i].buffer_type= MYSQL_TYPE_TIME;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ tm[0].year= 0; tm[0].month= 0; tm[0].day= 10;
++ tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
++ tm[0].second_part= 0; tm[0].neg= 0;
++
++ tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
++ tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(mysql_warning_count(mysql) != 2, "warning_count != 2");
++
++ if (verify_col_data(mysql, "t1", "day_ovfl", "838:59:59"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "day", "828:30:30"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "hour", "270:30:30"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "min", "00:00:00"))
++ goto error;
++ if (verify_col_data(mysql, "t1", "sec", "00:00:00"))
++ goto error;
++
++ mysql_stmt_close(stmt);
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++error:
++ mysql_stmt_close(stmt);
++ stmt_text= "drop table t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_derived(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ MYSQL_BIND my_bind[1];
++ int32 my_val= 0;
++ ulong my_length= 0L;
++ my_bool my_null= FALSE;
++ const char *query=
++ "select count(1) from (select f.id from t1 f where f.id=?) as x";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (id int(8), primary key (id)) \
++ENGINE=InnoDB DEFAULT CHARSET=utf8");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (1)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&my_val;
++ my_bind[0].length= &my_length;
++ my_bind[0].is_null= (char*)&my_null;
++ my_val= 1;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_distinct(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query=
++ "SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), \
++(1, 10), (2, 20), (3, 30), (4, 40), (5, 50);");
++ check_mysql_rc(rc, mysql);
++
++ for (i= 0; i < 3; i++)
++ {
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 5, "rowcount != 5");
++ mysql_stmt_close(stmt);
++ }
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_do_set(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt_do, *stmt_set;
++ char *query;
++ int rc, i;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"do @var:=(1 in (select * from t1))";
++ stmt_do= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_do, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_do, query, strlen(query));
++ check_stmt_rc(rc, stmt_do);
++
++ query= (char*)"set @var=(1 in (select * from t1))";
++ stmt_set= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_set, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_set, query, strlen(query));
++ check_stmt_rc(rc, stmt_set);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt_do);
++ check_stmt_rc(rc, stmt_do);
++ rc= mysql_stmt_execute(stmt_set);
++ check_stmt_rc(rc, stmt_set);
++ }
++
++ mysql_stmt_close(stmt_do);
++ mysql_stmt_close(stmt_set);
++ return OK;
++}
++
++static int test_double_compare(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char real_data[10], tiny_data;
++ double double_data;
++ MYSQL_RES *result;
++ MYSQL_BIND my_bind[3];
++ ulong length[3];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_double_compare");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_double_compare(col1 tinyint, "
++ " col2 float, col3 double )");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_double_compare "
++ "VALUES (1, 10.2, 34.5)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "UPDATE test_double_compare SET col1=100 "
++ "WHERE col1 = ? AND col2 = ? AND COL3 = ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "param_count != 3");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* tinyint */
++ my_bind[0].buffer_type= MYSQL_TYPE_TINY;
++ my_bind[0].buffer= (void *)&tiny_data;
++
++ /* string->float */
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)&real_data;
++ my_bind[1].buffer_length= sizeof(real_data);
++ my_bind[1].length= &length[1];
++ length[1]= 10;
++
++ /* double */
++ my_bind[2].buffer_type= MYSQL_TYPE_DOUBLE;
++ my_bind[2].buffer= (void *)&double_data;
++
++ tiny_data= 1;
++ strcpy(real_data, "10.2");
++ double_data= 34.5;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt), "affected_rows != 0");
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* test the results now, only one row should exist */
++ rc= mysql_query(mysql, "SELECT * FROM test_double_compare");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS((int)tiny_data == rc, "rowcount != tinydata");
++ mysql_free_result(result);
++ return OK;
++}
++
++static int test_multi(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt_delete, *stmt_update, *stmt_select1, *stmt_select2;
++ char *query;
++ MYSQL_BIND my_bind[1];
++ int rc, i;
++ int32 param= 1;
++ ulong length= 1;
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&param;
++ my_bind[0].length= &length;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1 (a int, b int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t2 (a int, b int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t1 values (3, 3), (2, 2), (1, 1)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into t2 values (3, 3), (2, 2), (1, 1)");
++ check_mysql_rc(rc, mysql);
++
++ query= (char*)"delete t1, t2 from t1, t2 where t1.a=t2.a and t1.b=10";
++ stmt_delete= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_delete, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_delete, query, strlen(query));
++ check_stmt_rc(rc, stmt_delete);
++
++ query= (char*)"update t1, t2 set t1.b=10, t2.b=10 where t1.a=t2.a and t1.b=?";
++ stmt_update= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_update, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_update, query, strlen(query));
++ check_stmt_rc(rc, stmt_update);
++
++ query= (char*)"select * from t1";
++ stmt_select1= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_select1, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_select1, query, strlen(query));
++ check_stmt_rc(rc, stmt_select1);
++
++ query= (char*)"select * from t2";
++ stmt_select2= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_select2, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_select2, query, strlen(query));
++ check_stmt_rc(rc, stmt_select2);
++
++ for(i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_bind_param(stmt_update, my_bind);
++ check_stmt_rc(rc, stmt_update);
++
++ rc= mysql_stmt_execute(stmt_update);
++ check_stmt_rc(rc, stmt_update);
++
++ rc= mysql_stmt_execute(stmt_delete);
++ check_stmt_rc(rc, stmt_delete);
++
++ rc= mysql_stmt_execute(stmt_select1);
++ check_stmt_rc(rc, stmt_select1);
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt_select1))
++ rc++;
++ FAIL_UNLESS(rc == 3-param, "rc != 3 - param");
++
++ rc= mysql_stmt_execute(stmt_select2);
++ check_stmt_rc(rc, stmt_select2);
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt_select2))
++ rc++;
++ FAIL_UNLESS(rc == 3-param, "rc != 3 - param");
++
++ param++;
++ }
++
++ mysql_stmt_close(stmt_delete);
++ mysql_stmt_close(stmt_update);
++ mysql_stmt_close(stmt_select1);
++ mysql_stmt_close(stmt_select2);
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/* Multiple stmts .. */
++
++static int test_multi_stmt(MYSQL *mysql)
++{
++
++ MYSQL_STMT *stmt, *stmt1, *stmt2;
++ int rc;
++ uint32 id;
++ char name[50];
++ MYSQL_BIND my_bind[2];
++ ulong length[2];
++ my_bool is_null[2];
++ static char *query;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_multi_table");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_multi_table(id int, name char(20))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_multi_table values(10, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ query= "SELECT * FROM test_multi_table WHERE id=?";
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ stmt2= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt2, mysql_error(mysql));
++ query= "UPDATE test_multi_table SET name='updated' WHERE id=10";
++ rc= mysql_stmt_prepare(stmt2, query, strlen(query));
++ check_stmt_rc(rc, stmt2);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&id;
++ my_bind[0].is_null= &is_null[0];
++ my_bind[0].length= &length[0];
++ is_null[0]= 0;
++ length[0]= 0;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)name;
++ my_bind[1].buffer_length= sizeof(name);
++ my_bind[1].length= &length[1];
++ my_bind[1].is_null= &is_null[1];
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ id= 10;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ id= 999;
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(id == 10, "id != 10");
++ FAIL_UNLESS(strcmp(name, "mysql") == 0, "name != 'mysql'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
++
++ /* alter the table schema now */
++ stmt1= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt1, mysql_error(mysql));
++ query= "DELETE FROM test_multi_table WHERE id=? AND CONVERT(name USING utf8)=?";
++ rc= mysql_stmt_prepare(stmt1, query, strlen(query));
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_IF(mysql_stmt_param_count(stmt1) != 2, "param_count != 2");
++
++ rc= mysql_stmt_bind_param(stmt1, my_bind);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_execute(stmt2);
++ check_stmt_rc(rc, stmt2);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt2) != 1, "affected_rows != 1");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(id == 10, "id != 10");
++ FAIL_UNLESS(strcmp(name, "updated") == 0, "name != 'updated'");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt1) != 1, "affected_rows != 1");
++
++ mysql_stmt_close(stmt1);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= my_stmt_result(mysql, "SELECT * FROM test_multi_table");
++ FAIL_UNLESS(rc == 0, "rc != 0");
++
++ mysql_stmt_close(stmt);
++ mysql_stmt_close(stmt2);
++
++ return OK;
++}
++
++/* Test 'n' statements create and close */
++
++static int test_nstmts(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ char query[255];
++ int rc;
++ static uint i, total_stmts= 2000;
++ MYSQL_BIND my_bind[1];
++
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_nstmts");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_nstmts(id int)");
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)&i;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++
++ for (i= 0; i < total_stmts; i++)
++ {
++ strcpy(query, "insert into test_nstmts values(?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++ }
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, " select count(*) from test_nstmts", strlen(" select count(*) from test_nstmts"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ i= 0;
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS( i == total_stmts, "total_stmts != i");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE test_nstmts");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test simple null */
++
++static int test_null(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ uint nData;
++ MYSQL_BIND my_bind[2];
++ my_bool is_null[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_null");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_null(col1 int, col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert by prepare, wrong column name */
++ strcpy(query, "INSERT INTO test_null(col3, col2) VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ FAIL_IF(!rc, "Error expected");
++ mysql_stmt_close(stmt);
++
++ strcpy(query, "INSERT INTO test_null(col1, col2) VALUES(?, ?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].is_null= &is_null[0];
++ is_null[0]= 1;
++ my_bind[1]= my_bind[0];
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /* now, execute the prepared statement to insert 10 records.. */
++ for (nData= 0; nData<10; nData++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ /* Re-bind with MYSQL_TYPE_NULL */
++ my_bind[0].buffer_type= MYSQL_TYPE_NULL;
++ is_null[0]= 0; /* reset */
++ my_bind[1]= my_bind[0];
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (nData= 0; nData<10; nData++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ mysql_stmt_close(stmt);
++
++ /* now fetch the results ..*/
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ nData*= 2;
++ rc= my_stmt_result(mysql, "SELECT * FROM test_null");;
++ FAIL_UNLESS((int) nData == rc, "rc != ndata");
++
++ /* Fetch results */
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&nData; /* this buffer won't be altered */
++ my_bind[0].length= 0;
++ my_bind[1]= my_bind[0];
++ my_bind[0].is_null= &is_null[0];
++ my_bind[1].is_null= &is_null[1];
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_null", strlen("SELECT * FROM test_null"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ is_null[0]= is_null[1]= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ {
++ FAIL_UNLESS(is_null[0], "!is_null");
++ FAIL_UNLESS(is_null[1], "!is_null");
++ rc++;
++ is_null[0]= is_null[1]= 0;
++ }
++ FAIL_UNLESS(rc == (int) nData, "rc != nData");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_order_param(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ static char *query;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1(a INT, b char(10))");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ query= "select sum(a) + 200, 1 from t1 "
++ " union distinct "
++ "select sum(a) + 200, 1 from t1 group by b ";
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ query= "select sum(a) + 200, ? from t1 group by b "
++ " union distinct "
++ "select sum(a) + 200, 1 from t1 group by b ";
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ query= "select sum(a) + 200, ? from t1 "
++ " union distinct "
++ "select sum(a) + 200, 1 from t1 group by b ";
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_rename(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ const char *query= "rename table t1 to t2, t3 to t4";
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "create table t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Errr expected");
++
++ rc= mysql_query(mysql, "create table t3 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ FAIL_IF(!rc, "Errr expected");
++
++ rc= mysql_query(mysql, "rename table t2 to t1, t4 to t3");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t2, t4");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_rewind(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind;
++ int rc = 0;
++ const char *stmt_text;
++ long unsigned int length=4, Data=0;
++ my_bool isnull=0;
++
++
++ stmt_text= "CREATE TABLE t1 (a int)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ stmt_text= "INSERT INTO t1 VALUES(2),(3),(4)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ stmt_text= "SELECT * FROM t1";
++ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
++ check_stmt_rc(rc, stmt);
++
++ memset(&my_bind, '\0', sizeof(MYSQL_BIND));
++ my_bind.buffer_type= MYSQL_TYPE_LONG;
++ my_bind.buffer= (void *)&Data; /* this buffer won't be altered */
++ my_bind.length= &length;
++ my_bind.is_null= &isnull;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, &my_bind);
++ check_stmt_rc(rc, stmt);
++
++ /* retreive all result sets till we are at the end */
++ while(!(rc=mysql_stmt_fetch(stmt)));
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* seek to the first row */
++ mysql_stmt_data_seek(stmt, 0);
++
++ /* now we should be able to fetch the results again */
++ /* but mysql_stmt_fetch returns MYSQL_NO_DATA */
++ while(!(rc= mysql_stmt_fetch(stmt)));
++
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ stmt_text= "DROP TABLE t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ rc= mysql_stmt_free_result(stmt);
++ rc= mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test simple select */
++
++static int test_select(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char szData[25];
++ int nData= 1;
++ MYSQL_BIND my_bind[2];
++ ulong length[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert a row and commit the transaction */
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')");
++ check_mysql_rc(rc, mysql);
++
++ /* now insert the second row, and roll back the transaction */
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES(20, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT * FROM test_select WHERE id= ? "
++ "AND CONVERT(name USING utf8) =?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ /* string data */
++ nData= 10;
++ strcpy(szData, (char *)"venu");
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)szData;
++ my_bind[1].buffer_length= 4;
++ my_bind[1].length= &length[1];
++ length[1]= 4;
++
++ my_bind[0].buffer= (void *)&nData;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rc != 1");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test simple select with prepare */
++
++static int test_select_prepare(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert a row and commit the transaction */
++ rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_select", strlen("SELECT * FROM test_select"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE test_select");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_select(id tinyint, id1 int, "
++ " id2 float, id3 float, "
++ " name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* insert a row and commit the transaction */
++ rc= mysql_query(mysql, "INSERT INTO test_select(id, id1, id2, name) VALUES(10, 5, 2.3, 'venu')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_select", strlen("SELECT * FROM test_select"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rowcount != 1");
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test simple show */
++
++static int test_select_show_table(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SHOW TABLES FROM mysql", strlen("SHOW TABLES FROM mysql"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt), "param_count != 0");
++
++ for (i= 1; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++
++ while (!mysql_stmt_fetch(stmt));
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test simple select */
++
++static int test_select_version(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT @@version", strlen("SELECT @@version"));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt), "param_count != 0");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ while (!mysql_stmt_fetch(stmt));
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_selecttmp(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query= "select a, (select count(distinct t1.b) as sum from t1, t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3";
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t2 (a int, b int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t3 (a int, b int);");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,
++ "insert into t1 values (0, 100), (1, 2), (1, 3), (2, 2), (2, 7), \
++(2, -1), (3, 10);");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "insert into t2 values (0, 0), (1, 1), (2, 1), (3, 1), (4, 1);");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "insert into t3 values (3, 3), (2, 2), (1, 1);");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 3, "rowcount != 3");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1, t2, t3");
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++static int test_set_option(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_RES *result;
++ int rc;
++
++
++ mysql_autocommit(mysql, TRUE);
++
++ /* LIMIT the rows count to 2 */
++ rc= mysql_query(mysql, "SET SQL_SELECT_LIMIT= 2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_limit");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_limit(a tinyint)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_limit VALUES(10), (20), (30), (40)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT * FROM test_limit");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 2, "rowcunt != 2");
++ mysql_free_result(result);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_limit", strlen("SELECT * FROM test_limit"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 2, "");
++
++ mysql_stmt_close(stmt);
++
++ /* RESET the LIMIT the rows count to 0 */
++ rc= mysql_query(mysql, "SET SQL_SELECT_LIMIT=DEFAULT");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_limit", strlen("SELECT * FROM test_limit"));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (!mysql_stmt_fetch(stmt))
++ rc++;
++ FAIL_UNLESS(rc == 4, "rowcount != 4");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test simple set-variable prepare */
++
++static int test_set_variable(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt, *stmt1;
++ int rc;
++ int set_count, def_count, get_count;
++ ulong length;
++ char var[NAME_LEN+1];
++ MYSQL_BIND set_bind[1], get_bind[2];
++
++
++ mysql_autocommit(mysql, TRUE);
++
++ stmt1= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt1, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt1, "show variables like 'max_error_count'", strlen("show variables like 'max_error_count'"));
++ check_stmt_rc(rc, stmt1);
++
++ memset(get_bind, '\0', sizeof(get_bind));
++
++ get_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ get_bind[0].buffer= (void *)var;
++ get_bind[0].length= &length;
++ get_bind[0].buffer_length= (int)NAME_LEN;
++ length= NAME_LEN;
++
++ get_bind[1].buffer_type= MYSQL_TYPE_LONG;
++ get_bind[1].buffer= (void *)&get_count;
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_bind_result(stmt1, get_bind);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ def_count= get_count;
++
++ FAIL_UNLESS(strcmp(var, "max_error_count") == 0, "var != max_error_count");
++ rc= mysql_stmt_fetch(stmt1);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, "set max_error_count=?", strlen("set max_error_count=?"));
++ check_stmt_rc(rc, stmt);
++
++ memset(set_bind, '\0', sizeof(set_bind));
++
++ set_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ set_bind[0].buffer= (void *)&set_count;
++
++ rc= mysql_stmt_bind_param(stmt, set_bind);
++ check_stmt_rc(rc, stmt);
++
++ set_count= 31;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_commit(mysql);
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_UNLESS(get_count == set_count, "get_count != set_count");
++
++ rc= mysql_stmt_fetch(stmt1);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ /* restore back to default */
++ set_count= def_count;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ rc= mysql_stmt_fetch(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_UNLESS(get_count == set_count, "get_count != set_count");
++
++ rc= mysql_stmt_fetch(stmt1);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ mysql_stmt_close(stmt1);
++ return OK;
++}
++
++/* Test SQLmode */
++
++static int test_sqlmode(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ char c1[5], c2[5];
++ int rc;
++ int ignore_space= 0;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_piping");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_piping(name varchar(10))");
++ check_mysql_rc(rc, mysql);
++
++ /* PIPES_AS_CONCAT */
++ strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\"");
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)c1;
++ my_bind[0].buffer_length= 2;
++
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= (void *)c2;
++ my_bind[1].buffer_length= 3;
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ strcpy(c1, "My"); strcpy(c2, "SQL");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ if (verify_col_data(mysql, "test_piping", "name", "MySQL"))
++ return FAIL;
++
++ rc= mysql_query(mysql, "DELETE FROM test_piping");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT connection_id ()");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ /* ANSI */
++ strcpy(query, "SET SQL_MODE= \"ANSI\"");
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ strcpy(c1, "My"); strcpy(c2, "SQL");
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++ if (verify_col_data(mysql, "test_piping", "name", "MySQL"))
++ return FAIL;
++
++ /* ANSI mode spaces ...
++ skip, if ignore_space was set
++ */
++ query_int_variable(mysql, "@@sql_mode LIKE '%IGNORE_SPACE%'", &ignore_space);
++
++ if (!ignore_space)
++ {
++ strcpy(query, "SELECT connection_id ()");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ }
++ /* IGNORE SPACE MODE */
++ strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\"");
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT connection_id ()");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++/* Test mysql_stmt_close for open stmts */
++
++static int test_stmt_close(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt1, *stmt2, *stmt3, *stmt_x;
++ MYSQL_BIND my_bind[1];
++ MYSQL_RES *result;
++ unsigned int count;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++
++ mysql->reconnect= 1;
++
++ /* set AUTOCOMMIT to ON*/
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stmt_close");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_stmt_close(id int)");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "DO \"nothing\"");
++ stmt1= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt1, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt1, query, strlen(query));
++ check_stmt_rc(rc, stmt1);
++
++ FAIL_IF(mysql_stmt_param_count(stmt1), "param_count != 0");
++
++ strcpy(query, "INSERT INTO test_stmt_close(id) VALUES(?)");
++ stmt_x= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt_x, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt_x, query, strlen(query));
++ check_stmt_rc(rc, stmt_x);
++
++ FAIL_IF(mysql_stmt_param_count(stmt_x) != 1, "param_count != 1");
++
++ strcpy(query, "UPDATE test_stmt_close SET id= ? WHERE id= ?");
++ stmt3= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt3, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt3, query, strlen(query));
++ check_stmt_rc(rc, stmt3);
++
++ FAIL_IF(mysql_stmt_param_count(stmt3) != 2, "param_count != 2");
++
++ strcpy(query, "SELECT * FROM test_stmt_close WHERE id= ?");
++ stmt2= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt2, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt2, query, strlen(query));
++ check_stmt_rc(rc, stmt2);
++
++ FAIL_IF(mysql_stmt_param_count(stmt2) != 1, "param_count != 1");
++
++ rc= mysql_stmt_close(stmt1);
++ check_stmt_rc(rc, stmt1);
++
++ /*
++ Originally we were going to close all statements automatically in
++ mysql_close(). This proved to not work well - users weren't able to
++ close statements by hand once mysql_close() had been called.
++ Now mysql_close() doesn't free any statements, so this test doesn't
++ serve its original designation any more.
++ Here we free stmt2 and stmt3 by hand to avoid memory leaks.
++ */
++ mysql_stmt_close(stmt2);
++ mysql_stmt_close(stmt3);
++
++ /*
++ We need to bzero bind structure because mysql_stmt_bind_param checks all
++ its members.
++ */
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer= (void *)&count;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ count= 100;
++
++ rc= mysql_stmt_bind_param(stmt_x, my_bind);
++ check_stmt_rc(rc, stmt_x);
++
++ rc= mysql_stmt_execute(stmt_x);
++ check_stmt_rc(rc, stmt_x);
++
++ FAIL_IF(mysql_stmt_affected_rows(stmt_x) != 1, "affected_rows != 1");
++
++ rc= mysql_stmt_close(stmt_x);
++ check_stmt_rc(rc, stmt_x);
++
++ rc= mysql_query(mysql, "SELECT id FROM test_stmt_close");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 1, "rwcount != 1");
++ mysql_free_result(result);
++ return OK;
++}
++
++static int test_new_date(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND bind[1];
++ int rc;
++ char buffer[50];
++
++
++ mysql->reconnect= 1;
++
++ /* set AUTOCOMMIT to ON*/
++ mysql_autocommit(mysql, TRUE);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a date, b date)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (now(), now() + INTERVAL 1 day)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, "SELECT if(1, a, b) FROM t1", 26);
++ check_stmt_rc(rc, stmt);
++
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer_length= 50;
++ bind[0].buffer= (void *)buffer;
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_IF(rc != MYSQL_NO_DATA, "NO DATA expected");
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++static int test_long_data1(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ MYSQL_BIND bind[1];
++ char query[MAX_TEST_QUERY_LENGTH];
++ char *data= "12345";
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS tld");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE tld (col1 int, "
++ "col2 long varbinary)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO tld VALUES (1,'test')");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "UPDATE tld SET col2=? WHERE col1=1");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_send_long_data(stmt, 0, data, 6);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++ return OK;
++}
++
++int test_blob_9000(MYSQL *mysql)
++{
++ MYSQL_BIND bind[1];
++ MYSQL_STMT *stmt;
++ int rc;
++ char buffer[9200];
++ char *query= "INSERT INTO tb9000 VALUES (?)";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS tb9000");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE tb9000 (a blob)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ memset(buffer, 'C', 9200);
++ bind[0].buffer= buffer;
++ bind[0].buffer_length= 9200;
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++int test_fracseconds(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char *str= "SELECT NOW(6)";
++ char buffer[60], buffer1[60];
++ MYSQL_BIND bind[2];
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, str, strlen(str));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(&bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer= buffer;
++ bind[0].buffer_length=60;
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(strlen(buffer) != 26, "Expected timestamp with length of 26");
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a timestamp(6), b time(6))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO t1 VALUES ('2012-04-25 10:20:49.0194','10:20:49.0194' )");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, "SELECT a,b FROM t1", 18);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(bind, 0, 2 * sizeof(MYSQL_BIND));
++ bind[0].buffer= buffer;
++ bind[1].buffer= buffer1;
++ bind[0].buffer_length= bind[1].buffer_length= 60;
++ bind[0].buffer_type= bind[1].buffer_type= MYSQL_TYPE_STRING;
++
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(strcmp(buffer, "2012-04-25 10:20:49.019400") != 0, "Wrong result");
++ FAIL_IF(strcmp(buffer1, "10:20:49.019400") != 0, "Wrong result");
++
++ rc= mysql_stmt_close(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++
++ return OK;
++}
++
++int test_notrunc(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ my_bool trunc= 1;
++ MYSQL_BIND bind[1];
++ char buffer[5];
++ int rc;
++ my_bool error= 0;
++ unsigned long len= 1;
++
++ char *query= "SELECT '1234567890' FROM DUAL";
++
++ mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &trunc);
++
++ stmt= mysql_stmt_init(mysql);
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer_type= MYSQL_TYPE_LONG;
++ bind[0].buffer= buffer;
++ bind[0].buffer_length= 3;
++ bind[0].length= &len;
++ bind[0].error= &error;
++
++// rc= mysql_stmt_bind_result(stmt, bind);
++// check_stmt_rc(rc, stmt);
++ mysql_stmt_store_result(stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ diag("rc= %d len=%lu", rc, len);
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_notrunc", test_notrunc, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_fracseconds", test_fracseconds, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_blob_9000", test_blob_9000, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_long_data1", test_long_data1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_insert_update", test_prepare_insert_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_simple", test_prepare_simple, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_syntax", test_prepare_syntax, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_field_result", test_prepare_field_result, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare", test_prepare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_ext", test_prepare_ext, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_multi_statements", test_prepare_multi_statements, TEST_CONNECTION_NEW, 0, NULL , NULL},
++ {"test_prepare_alter", test_prepare_alter, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_resultset", test_prepare_resultset, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_open_direct", test_open_direct, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_select_show", test_select_show, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_select", test_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_long_data", test_long_data, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_long_data_str", test_long_data_str, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_long_data_str1", test_long_data_str1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_long_data_bin", test_long_data_bin, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_simple_update", test_simple_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_simple_delete", test_simple_delete, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_update", test_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_prepare_noparam", test_prepare_noparam, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bind_result", test_bind_result, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bind_result_ext", test_bind_result_ext, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bind_result_ext1", test_bind_result_ext1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bind_negative", test_bind_negative, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_buffers", test_buffers, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_xjoin", test_xjoin, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_union", test_union, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_union2", test_union2, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_union_param", test_union_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_pure_coverage", test_pure_coverage, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_insert_select", test_insert_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_insert", test_insert, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_join", test_join, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_left_join_view", test_left_join_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_manual_sample", test_manual_sample, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_create_drop", test_create_drop, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_date", test_date, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_date_ts", test_date_ts, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_date_dt", test_date_dt, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_date_date", test_date_date, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_date_time", test_date_time, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_datetime_ranges", test_datetime_ranges, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_derived", test_derived, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_distinct", test_distinct, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_do_set", test_do_set, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_double_compare", test_double_compare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_multi", test_multi, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_multi_stmt", test_multi_stmt, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_nstmts", test_nstmts, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_null", test_null, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_order_param", test_order_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_rename", test_rename, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_rewind", test_rewind, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_select_prepare", test_select_prepare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_select_show_table", test_select_show_table, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_select_version", test_select_version, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_selecttmp", test_selecttmp, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_set_option", test_set_option, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_set_variable", test_set_variable, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_sqlmode", test_sqlmode, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_stmt_close", test_stmt_close, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_new_date", test_new_date, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
++ if (argc > 1)
++ get_options(argc, argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/ps_new.c mariadb-native-client.trunk/unittest/libmariadb/ps_new.c
+--- mariadb/unittest/libmariadb/ps_new.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/ps_new.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,505 @@
+/************************************************************************************
+ Copyright (C) 2012 Monty Program AB
+
@@ -151954,7 +219810,7 @@
+ stmt = mysql_stmt_init(mysql);
+ if (!stmt)
+ {
-+ printf("Could not initialize statement\n");
++ diag("Could not initialize statement");
+ exit(1);
+ }
+ rc = mysql_stmt_prepare(stmt, "CALL p1(?, ?, ?)", 16);
@@ -152008,8 +219864,8 @@
+
+ FAIL_IF(int_data[0] != 10 || int_data[1] != 20 || int_data[2] != 30,
+ "expected 10 20 30");
-+
-+ FAIL_IF(mysql_stmt_next_result(stmt) != 0, "expected more results");
++ rc= mysql_stmt_next_result(stmt);
++ check_stmt_rc(rc, stmt);
+ rc= mysql_stmt_bind_result(stmt, rs_bind);
+
+ rc= mysql_stmt_fetch(stmt);
@@ -152029,11 +219885,369 @@
+ FAIL_IF(mysql_stmt_field_count(stmt) != 0, "expected 0 fields");
+
+ rc= mysql_stmt_close(stmt);
++ return OK;
++}
++
++int test_sp_params(MYSQL *mysql)
++{
++ int i, rc;
++ MYSQL_STMT *stmt;
++ int a[] = {10,20,30};
++ MYSQL_BIND bind[3];
++ char *stmtstr= "CALL P1(?,?,?)";
++ char res[3][20];
++
++ rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)"
++ "BEGIN "
++ " SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; "
++ " SELECT p_inout, p_in, substring(p_out, 9);"
++ "END");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "expected param_count=3");
++
++ memset(bind, 0, sizeof(MYSQL_BIND) * 3);
++ for (i=0; i < 3; i++)
++ {
++ bind[i].buffer= &a[i];
++ bind[i].buffer_type= MYSQL_TYPE_LONG;
++ }
++ bind[0].buffer_type= MYSQL_TYPE_NULL;
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
++
++ memset(res, 0, 60);
++
++ memset(bind, 0, sizeof(MYSQL_BIND) * 3);
++ for (i=0; i < 3; i++)
++ {
++ bind[i].buffer_type= MYSQL_TYPE_STRING;
++ bind[i].buffer_length= 20;
++ bind[i].buffer= res[i];
++ }
++
++ do {
++ if (mysql->server_status & SERVER_PS_OUT_PARAMS)
++ {
++ diag("out param result set");
++ FAIL_IF(mysql_stmt_field_count(stmt) != 2, "expected 2 columns");
++ FAIL_IF(strcmp(stmt->fields[0].org_name, "p_out") != 0, "wrong field name");
++ FAIL_IF(strcmp(stmt->fields[1].org_name, "p_inout") != 0, "wrong field name");
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(strcmp(res[0],"This is OUT param") != 0, "comparison failed");
++ FAIL_IF(strcmp(res[1],"200") != 0, "comparison failed");
++ }
++ else
++ if (mysql_stmt_field_count(stmt))
++ {
++ diag("sp result set");
++ FAIL_IF(mysql_stmt_field_count(stmt) != 3, "expected 3 columns");
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_IF(strcmp(res[0],"200") != 0, "comparison failed");
++ FAIL_IF(strcmp(res[1],"300") != 0, "comparison failed");
++ FAIL_IF(strcmp(res[2],"OUT param") != 0, "comparison failed");
++
++ }
++ } while (mysql_stmt_next_result(stmt) == 0);
++
++ rc= mysql_stmt_close(stmt);
++ return OK;
++}
++
++int test_sp_reset(MYSQL *mysql)
++{
++ int i, rc;
++ MYSQL_STMT *stmt;
++ int a[] = {10,20,30};
++ MYSQL_BIND bind[3];
++ char *stmtstr= "CALL P1(?,?,?)";
++
++ rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)"
++ "BEGIN "
++ " SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; "
++ " SELECT p_inout, p_in, substring(p_out, 9);"
++ "END");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
++ check_stmt_rc(rc, stmt);
++
++ FAIL_IF(mysql_stmt_param_count(stmt) != 3, "expected param_count=3");
++
++ memset(bind, 0, sizeof(MYSQL_BIND) * 3);
++ for (i=0; i < 3; i++)
++ {
++ bind[i].buffer= &a[i];
++ bind[i].buffer_type= MYSQL_TYPE_LONG;
++ }
++ bind[0].buffer_type= MYSQL_TYPE_NULL;
++ rc= mysql_stmt_bind_param(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /*connection shouldn't be blocked now */
++
++ rc= mysql_query(mysql, "DROP PROCEDURE p1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_close(stmt);
++ return OK;
+}
+
++int test_sp_reset1(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_STMT *stmt;
++ MYSQL_BIND bind[1];
++
++ char tmp[20];
++ char *stmtstr= "CALL P1(?)";
++
++ rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19))"
++ "BEGIN "
++ " SET p_out = 'foo';"
++ " SELECT 'foo' FROM DUAL;"
++ " SELECT 'bar' FROM DUAL;"
++ "END");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
++ check_stmt_rc(rc, stmt);
++
++ memset(tmp, 0, sizeof(tmp));
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer= tmp;
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++ bind[0].buffer_length= 4;
++
++ mysql_stmt_bind_param(stmt, bind);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_next_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* mysql_stmt_reset should set statement in prepared state.
++ * this means: all subsequent result sets should be flushed.
++ * Let's try!
++ */
++ rc= mysql_stmt_reset(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "DROP PROCEDURE p1");
++ check_mysql_rc(rc, mysql);
++
++ mysql_stmt_close(stmt);
++ return OK;
++}
++
++int test_sp_reset2(MYSQL *mysql)
++{
++ int rc, i;
++ MYSQL_STMT *stmt;
++ MYSQL_BIND bind[4];
++ long l[4];
++ char *stmtstr= "CALL P1()";
++
++ memset(l, 0, sizeof(l));
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE PROCEDURE p1()"
++ "BEGIN "
++ " SET @a:=1;"
++ " INSERT INTO t1 VALUES(1);"
++ " SELECT 1 FROM DUAL;"
++ " SELECT 2,3 FROM DUAL;"
++ " INSERT INTO t1 VALUES(2);"
++ " SELECT 3,4,5 FROM DUAL;"
++ " SELECT 4,5,6,7 FROM DUAL;"
++ "END");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(bind, 0, sizeof(MYSQL_BIND) * 4);
++ for (i=0; i < 4; i++)
++ {
++ bind[i].buffer_type= MYSQL_TYPE_LONG;
++ bind[i].buffer= &l[i];
++ }
++
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ while (rc != MYSQL_NO_DATA)
++ {
++ rc= mysql_stmt_fetch(stmt);
++ diag("l=%ld", l[0]);
++ }
++
++ rc= mysql_stmt_next_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* now rebind since we expect 2 columns */
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ while (rc != MYSQL_NO_DATA)
++ {
++ rc= mysql_stmt_fetch(stmt);
++ diag("l=%ld l=%ld", l[0], l[1]);
++ }
++
++
++ rc= mysql_stmt_next_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ /* now rebind since we expect 2 columns */
++ rc= mysql_stmt_bind_result(stmt, bind);
++ check_stmt_rc(rc, stmt);
++
++ while (rc != MYSQL_NO_DATA)
++ {
++ rc= mysql_stmt_fetch(stmt);
++ diag("l=%ld l=%ld l=%ld", l[0], l[1], l[2]);
++ }
++
++ rc= mysql_stmt_close(stmt);
++
++
++ rc= mysql_query(mysql, "DROP PROCEDURE p1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++int test_query(MYSQL *mysql)
++{
++ int rc;
++ int i;
++ MYSQL_STMT *stmt;
++ MYSQL_BIND bind[1];
++
++ char tmp[20];
++ char *stmtstr= "CALL P1(?)";
++
++ rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19))"
++ "BEGIN "
++ " SET p_out = 'foo';"
++ " SELECT 1 FROM DUAL;"
++ "END");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
++ check_stmt_rc(rc, stmt);
++
++ for (i=0; i < 1000; i++)
++ {
++ int status;
++ memset(tmp, 0, sizeof(tmp));
++ memset(bind, 0, sizeof(MYSQL_BIND));
++ bind[0].buffer= tmp;
++ bind[0].buffer_type= MYSQL_TYPE_STRING;
++ bind[0].buffer_length= 4;
++
++ mysql_stmt_bind_param(stmt, bind);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ do {
++ if (stmt->field_count)
++ {
++ mysql_stmt_bind_result(stmt, bind);
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++ while(mysql_stmt_fetch(stmt) == 0);
++
++ rc= mysql_stmt_free_result(stmt);
++ check_stmt_rc(rc, stmt);
++ }
++ status= mysql_stmt_next_result(stmt);
++ if (status == 1)
++ check_stmt_rc(status, stmt);
++ } while (status == 0);
++
++ rc= mysql_stmt_reset(stmt);
++ if (rc)
++ diag("reset failed after %d iterations", i);
++ check_stmt_rc(rc, stmt);
++ }
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++
+struct my_tests_st my_tests[] = {
-+ {"test_multi_result", test_multi_result, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_query", test_query, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_RESULTS , NULL , NULL},
++ {"test_sp_params", test_sp_params, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_sp_reset", test_sp_reset, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_sp_reset1", test_sp_reset1, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_sp_reset2", test_sp_reset2, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
++ {"test_multi_result", test_multi_result, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
+ {NULL, NULL, 0, 0, NULL, NULL}
+};
+
@@ -152048,47 +220262,1187 @@
+
+ return(exit_status());
+}
-
-=== modified file 'unittest/libmariadb/result.c'
---- mariadb/unittest/libmysql/result.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/result.c 2013-03-14 21:01:43 +0000
-@@ -1053,8 +1053,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/result.c mariadb-native-client.trunk/unittest/libmariadb/result.c
+--- mariadb/unittest/libmariadb/result.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/result.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,1064 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++/**
++ Some basic tests of the client API.
++*/
++
++#include "my_test.h"
++
++static int client_store_result(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ int rc, rowcount= 0;
++
++ rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL UNION SELECT 'bar' FROM DUAL");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ /* since we use store result, we should be able execute other api calls */
++ rc= mysql_ping(mysql);
++ FAIL_IF(rc, "mysql_ping failed");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 2, "rowcount != 2");
++
++ mysql_free_result(result);
++
++ return OK;
++}
++
++static int client_use_result(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ int rc, rowcount= 0;
++
++ rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL UNION SELECT 'bar' FROM DUAL");
++ check_mysql_rc(rc, mysql);
++
++ /* get the result */
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ /* since we use use result, we shouldn't be able execute other api calls */
++ rc= mysql_ping(mysql);
++ FAIL_IF(!rc, "Error expected");
++
++ while (mysql_fetch_row(result))
++ rowcount++;
++
++ FAIL_IF(rowcount != 2, "rowcount != 2");
++
++ mysql_free_result(result);
++
++ return OK;
++}
++
++static int test_free_result(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char c2[5];
++ ulong bl1, l2;
++ int rc, c1, bc1;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "drop table if exists test_free_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table test_free_result("
++ "c1 int primary key auto_increment)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into test_free_result values(), (), ()");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "select * from test_free_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&bc1;
++ my_bind[0].length= &bl1;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ c2[0]= '\0'; l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)c2;
++ my_bind[0].buffer_length= 7;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(strncmp(c2, "1", 1) == 0, "c2 != '1'");
++ FAIL_UNLESS(l2 == 1, "l2 != 1");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ c1= 0, l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&c1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(c1 == 2, "c1 != 2");
++ FAIL_UNLESS(l2 == 4, "l2 != 4");
++
++ rc= mysql_query(mysql, "drop table test_free_result");
++ FAIL_IF(!rc, "Error commands out of sync expected");
++
++ rc= mysql_stmt_free_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "drop table test_free_result");
++ check_mysql_rc(rc, mysql); /* should be successful */
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++
++/* Test mysql_stmt_store_result() */
++
++static int test_free_store_result(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[1];
++ char c2[5];
++ ulong bl1, l2;
++ int rc, c1, bc1;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "drop table if exists test_free_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table test_free_result(c1 int primary key auto_increment)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "insert into test_free_result values(), (), ()");
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "select * from test_free_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&bc1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &bl1;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ c2[0]= '\0'; l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (void *)c2;
++ my_bind[0].buffer_length= 7;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(strncmp(c2, "1", 1) == 0, "c2 != '1'");
++ FAIL_UNLESS(l2 == 1, "l2 != 1");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ c1= 0, l2= 0;
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *)&c1;
++ my_bind[0].buffer_length= 0;
++ my_bind[0].is_null= 0;
++ my_bind[0].length= &l2;
++
++ rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(c1 == 2, "c1 != 2");
++ FAIL_UNLESS(l2 == 4, "l2 != 4");
++
++ rc= mysql_stmt_free_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_query(mysql, "drop table test_free_result");
++ check_mysql_rc(rc, mysql);
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_store_result(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ int32 nData;
++ char szData[100];
++ MYSQL_BIND my_bind[2];
++ ulong length, length1;
++ my_bool is_null[2];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ /* fetch */
++ memset(my_bind, '\0', sizeof(my_bind));
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *) &nData; /* integer data */
++ my_bind[0].length= &length;
++ my_bind[0].is_null= &is_null[0];
++
++ length= 0;
++ my_bind[1].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[1].buffer= szData; /* string data */
++ my_bind[1].buffer_length= sizeof(szData);
++ my_bind[1].length= &length1;
++ my_bind[1].is_null= &is_null[1];
++ length1= 0;
++
++ strcpy(query, "SELECT * FROM test_store_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 10, "nData != 10");
++ FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
++ FAIL_UNLESS(length1 == 4, "length1 != 4");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 20, "nData != 20");
++ FAIL_UNLESS(strcmp(szData, "mysql") == 0, "szDaza != 'mysql'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ length= 99;
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(is_null[0], "isnull set");
++ FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'monty'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 10, "nData != 10");
++ FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
++ FAIL_UNLESS(length1 == 4, "length1 != 4");
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 20, "nData != 20");
++ FAIL_UNLESS(strcmp(szData, "mysql") == 0, "szDaza != 'mysql'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ length= 99;
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(is_null[0], "isnull set");
++ FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'monty'");
++ FAIL_UNLESS(length1 == 5, "length1 != 5");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++
++/* Test simple bind store result */
++
++static int test_store_result1(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ strcpy(query, "SELECT * FROM test_store_result");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 3, "rowcount != 3");
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= 0;
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rc++;
++ FAIL_UNLESS(rc == 3, "rowcount != 3");
++
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++
++/* Another test for bind and store result */
++
++static int test_store_result2(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc;
++ int nData;
++ ulong length;
++ MYSQL_BIND my_bind[1];
++ char query[MAX_TEST_QUERY_LENGTH];
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_commit(mysql);
++ check_mysql_rc(rc, mysql);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++
++ my_bind[0].buffer_type= MYSQL_TYPE_LONG;
++ my_bind[0].buffer= (void *) &nData; /* integer data */
++ my_bind[0].length= &length;
++ my_bind[0].is_null= 0;
++
++ strcpy((char *)query , "SELECT col1 FROM test_store_result where col1= ?");
++ stmt= mysql_stmt_init(mysql);
++ FAIL_IF(!stmt, mysql_error(mysql));
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ nData= 10; length= 0;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ nData= 0;
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 10, "nData != 10");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++
++ nData= 20;
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ nData= 0;
++ rc= mysql_stmt_store_result(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++
++ FAIL_UNLESS(nData == 20, "nData != 20");
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
++ mysql_stmt_close(stmt);
++
++ return OK;
++}
++
++static int test_bug11718(MYSQL *mysql)
++{
++ MYSQL_RES *res;
++ int rc;
++ const char *query= "select str_to_date(concat(f3),'%Y%m%d') from t1,t2 "
++ "where f1=f2 order by f1";
++
++ rc= mysql_query(mysql, "drop table if exists t1, t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (f1 int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t2 (f2 int, f3 numeric(8))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1), (2)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (1,20050101), (2,20050202)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, query);
++ check_mysql_rc(rc, mysql);
++ res = mysql_store_result(mysql);
++
++ FAIL_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE, "type != MYSQL_TYPE_DATE");
++ mysql_free_result(res);
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug19671(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ int rc;
++
++ mysql_query(mysql, "set sql_mode=''");
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, "drop view if exists v1");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, "create table t1(f1 int)");
++ check_mysql_rc(rc, mysql)
++
++ rc= mysql_query(mysql, "create view v1 as select va.* from t1 va");
++ check_mysql_rc(rc, mysql)
++
++ result= mysql_list_fields(mysql, "v1", NULL);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 0, "");
++
++ if (verify_prepare_field(result, 0, "f1", "f1", MYSQL_TYPE_LONG,
++ "v1", "v1", schema, 11, "0")) {
++ mysql_free_result(result);
++ diag("verify_prepare_field failed");
++ return FAIL;
++ }
++
++ mysql_free_result(result);
++ check_mysql_rc(mysql_query(mysql, "drop view v1"), mysql)
++ check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql)
++ return OK;
++}
++
++/*
++ Bug#21726: Incorrect result with multiple invocations of
++ LAST_INSERT_ID
++
++ Test that client gets updated value of insert_id on UPDATE that uses
++ LAST_INSERT_ID(expr).
++ select_query added to test for bug
++ #26921 Problem in mysql_insert_id() Embedded C API function
++*/
++static int test_bug21726(MYSQL *mysql)
++{
++ const char *create_table[]=
++ {
++ "DROP TABLE IF EXISTS t1",
++ "CREATE TABLE t1 (i INT)",
++ "INSERT INTO t1 VALUES (1)",
++ };
++ const char *update_query= "UPDATE t1 SET i= LAST_INSERT_ID(i + 1)";
++ int rc;
++ my_ulonglong insert_id;
++ const char *select_query= "SELECT * FROM t1";
++ MYSQL_RES *result;
++
++ rc= mysql_query(mysql, create_table[0]);
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, create_table[1]);
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, create_table[2]);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, update_query);
++ check_mysql_rc(rc, mysql)
++ insert_id= mysql_insert_id(mysql);
++ FAIL_UNLESS(insert_id == 2, "insert_id != 2");
++
++ rc= mysql_query(mysql, update_query);
++ check_mysql_rc(rc, mysql)
++ insert_id= mysql_insert_id(mysql);
++ FAIL_UNLESS(insert_id == 3, "insert_id != 3");
++
++ rc= mysql_query(mysql, select_query);
++ check_mysql_rc(rc, mysql)
++ insert_id= mysql_insert_id(mysql);
++ FAIL_UNLESS(insert_id == 3, "insert_id != 3");
++ result= mysql_store_result(mysql);
++ mysql_free_result(result);
++
++ return OK;
++}
++
++/* Bug#6761 - mysql_list_fields doesn't work */
++
++static int test_bug6761(MYSQL *mysql)
++{
++ const char *stmt_text;
++ MYSQL_RES *res;
++ int rc;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
++ check_mysql_rc(rc, mysql);
++
++ stmt_text= "CREATE TABLE t1 (a int, b char(255), c decimal)";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_list_fields(mysql, "t1", "%");
++ FAIL_UNLESS(res && mysql_num_fields(res) == 3, "num_fields != 3");
++ mysql_free_result(res);
++
++ stmt_text= "DROP TABLE t1";
++ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
++ check_mysql_rc(rc, mysql);
++ return OK;
++}
++
++/* Test field flags (verify .NET provider) */
++
++static int test_field_flags(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++ MYSQL_FIELD *field;
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_flags");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_field_flags(id int NOT NULL AUTO_INCREMENT PRIMARY KEY, \
++ id1 int NOT NULL, \
++ id2 int UNIQUE, \
++ id3 int, \
++ id4 int NOT NULL, \
++ id5 int, \
++ KEY(id3, id4))");
++ check_mysql_rc(rc, mysql);
++
++ /* with table name included with TRUE column name */
++ rc= mysql_query(mysql, "SELECT * FROM test_field_flags");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ mysql_field_seek(result, 0);
++
++ field= mysql_fetch_field(result);
++ FAIL_UNLESS(field->flags & NOT_NULL_FLAG &&
++ field->flags & PRI_KEY_FLAG &&
++ field->flags & AUTO_INCREMENT_FLAG, "Wrong flags for field 0");
++
++ field= mysql_fetch_field(result);
++ FAIL_UNLESS(field->flags & NOT_NULL_FLAG, "Wrong flags for field 1");
++
++ field= mysql_fetch_field(result);
++ FAIL_UNLESS(field->flags & UNIQUE_KEY_FLAG, "Wrong flags for field 2");
++
++ field= mysql_fetch_field(result);
++ FAIL_UNLESS(field->flags & MULTIPLE_KEY_FLAG, "Wrong flags for field 3");
++
++ field= mysql_fetch_field(result);
++ FAIL_UNLESS(field->flags & NOT_NULL_FLAG, "Wrong flags for field 4");
++
++ mysql_free_result(result);
++ return OK;
++}
++
++/* Test real and alias names */
++
++static int test_field_names(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names2");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_field_names1(id int, name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_field_names2(id int, name varchar(50))");
++ check_mysql_rc(rc, mysql);
++
++ /* with table name included with TRUE column name */
++ rc= mysql_query(mysql, "SELECT id as 'id-alias' FROM test_field_names1");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 0, "rowcount != 0");
++ mysql_free_result(result);
++
++ /* with table name included with TRUE column name */
++ rc= mysql_query(mysql, "SELECT t1.id as 'id-alias', test_field_names2.name FROM test_field_names1 t1, test_field_names2");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_use_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 0, "rowcount != 0");
++ mysql_free_result(result);
++ return OK;
++}
++
++/* Test FUNCTION field info / DATE_FORMAT() table_name . */
++
++static int test_func_fields(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *result;
++ MYSQL_FIELD *field;
++
++
++ rc= mysql_autocommit(mysql, TRUE);
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_dateformat");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE test_dateformat(id int, \
++ ts timestamp)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO test_dateformat(id) values(10)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT ts FROM test_dateformat");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(!field, "Invalid field");
++ FAIL_UNLESS(strcmp(field->table, "test_dateformat") == 0, "field->table != 'test_dateformat'");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(field, "no more fields expected");
++
++ mysql_free_result(result);
++
++ /* DATE_FORMAT */
++ rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'venu' FROM test_dateformat");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(!field, "Invalid field");
++ FAIL_UNLESS(field->table[0] == '\0', "field->table != ''");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(field, "no more fields expected");
++
++ mysql_free_result(result);
++
++ /* FIELD ALIAS TEST */
++ rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'YEAR' FROM test_dateformat");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(!field, "Invalid field");
++ FAIL_UNLESS(strcmp(field->name, "YEAR") == 0, "name != 'YEAR'");
++ FAIL_UNLESS(field->org_name[0] == '\0', "org_name != ''");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(field, "no more fields expected");
++
++ mysql_free_result(result);
++ return OK;
++}
++
++/* Test mysql_list_fields() */
++
++static int test_list_fields(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ int rc;
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10) default 'mysql')");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_list_fields(mysql, "t1", NULL);
++ FAIL_IF(!result, "Invalid result set");
++
++ rc= 0;
++ while (mysql_fetch_row(result))
++ rc++;
++ FAIL_UNLESS(rc == 0, "rowcount != 0");
++
++ if (verify_prepare_field(result, 0, "c1", "c1", MYSQL_TYPE_LONG,
++ "t1", "t1",
++ schema, 11, "0"))
++ goto error;
++
++ if (verify_prepare_field(result, 1, "c2", "c2", MYSQL_TYPE_STRING,
++ "t1", "t1",
++ schema, 10, "mysql"))
++ goto error;
++
++ mysql_free_result(result);
++ check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql);
++ return OK;
++
++error:
++ mysql_free_result(result);
++ check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql);
++ return FAIL;
++}
++
++/* Test correct max length for MEDIUMTEXT and LONGTEXT columns */
++
++static int test_bug9735(MYSQL *mysql)
++{
++ MYSQL_RES *res;
++ int rc;
++
++
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (a mediumtext, b longtext) "
++ "character set latin1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "select * from t1");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ if (verify_prepare_field(res, 0, "a", "a", MYSQL_TYPE_BLOB,
++ "t1", "t1", schema, (1U << 24)-1, 0))
++ goto error;
++ if (verify_prepare_field(res, 1, "b", "b", MYSQL_TYPE_BLOB,
++ "t1", "t1", schema, ~0U, 0))
++ goto error;
++ mysql_free_result(res);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++ return OK;
++error:
++ mysql_free_result(res);
++ rc= mysql_query(mysql, "drop table t1");
++ return FAIL;
++}
++
++/*
++ Check that mysql_next_result works properly in case when one of
++ the statements used in a multi-statement query is erroneous
++*/
++
++static int test_bug9992(MYSQL *mysql)
++{
++ MYSQL_RES* res ;
++ int rc;
++
++ /* Sic: SHOW DATABASE is incorrect syntax. */
++ rc= mysql_query(mysql, "SHOW TABLES; SHOW DATABASE; SELECT 1;");
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_store_result(mysql);
++ FAIL_UNLESS(res, "Invalid resultset");
++ mysql_free_result(res);
++ rc= mysql_next_result(mysql);
++ FAIL_UNLESS(rc == 1, "Error expected"); /* Got errors, as expected */
++
++ return OK;
++}
++
++/* Test the support of multi-statement executions */
++
++static int test_multi_statements(MYSQL *mysql)
++{
++ MYSQL *mysql_local;
++ MYSQL_RES *result;
++ int rc;
++
++ const char *query= "\
++DROP TABLE IF EXISTS test_multi_tab;\
++CREATE TABLE test_multi_tab(id int, name char(20));\
++INSERT INTO test_multi_tab(id) VALUES(10), (20);\
++INSERT INTO test_multi_tab VALUES(20, 'insert;comma');\
++SELECT * FROM test_multi_tab;\
++UPDATE test_multi_tab SET name='new;name' WHERE id=20;\
++DELETE FROM test_multi_tab WHERE name='new;name';\
++SELECT * FROM test_multi_tab;\
++DELETE FROM test_multi_tab WHERE id=10;\
++SELECT * FROM test_multi_tab;\
++DROP TABLE test_multi_tab;\
++select 1;\
++DROP TABLE IF EXISTS test_multi_tab";
++ uint count, exp_value;
++ uint rows[]= {0, 0, 2, 1, 3, 2, 2, 1, 1, 0, 0, 1, 0};
++
++ /*
++ First test that we get an error for multi statements
++ (Because default connection is not opened with CLIENT_MULTI_STATEMENTS)
++ */
++ mysql_local= mysql;
++ mysql = test_connect(NULL);
++ rc= mysql_query(mysql, query); /* syntax error */
++ FAIL_IF(!rc, "Error expected");
++
++ rc= mysql_next_result(mysql);
++ FAIL_UNLESS(rc == -1, "rc != -1");
++ rc= mysql_more_results(mysql);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++
++ mysql_close(mysql);
++ mysql= mysql_local;
++
++ mysql_local->reconnect= 1;
++
++ rc= mysql_query(mysql_local, query);
++ check_mysql_rc(rc, mysql);
++
++ for (count= 0 ; count < array_elements(rows) ; count++)
++ {
++ if ((result= mysql_store_result(mysql_local)))
++ {
++ mysql_free_result(result);
++ }
++
++ exp_value= (uint) mysql_affected_rows(mysql_local);
++ FAIL_IF(rows[count] != exp_value, "row[count] != exp_value");
++ if (count != array_elements(rows) -1)
++ {
++ rc= mysql_more_results(mysql_local);
++ FAIL_IF(!rc, "More results expected");
++ rc= mysql_next_result(mysql_local);
++ check_mysql_rc(rc, mysql_local);
++ }
++ else
++ {
++ rc= mysql_more_results(mysql_local);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ rc= mysql_next_result(mysql_local);
++ FAIL_UNLESS(rc == -1, "rc != -1");
++ }
++ }
++
++ /* check that errors abort multi statements */
++
++ rc= mysql_query(mysql_local, "select 1+1+a;select 1+1");
++ FAIL_IF(!rc, "Error expected");
++ rc= mysql_more_results(mysql_local);
++ FAIL_UNLESS(rc == 0, "rc != 0");
++ rc= mysql_next_result(mysql_local);
++ FAIL_UNLESS(rc == -1, "rc != -1");
++
++ rc= mysql_query(mysql_local, "select 1+1;select 1+1+a;select 1");
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql_local);
++ FAIL_IF(!result, "Invalid result set");
++ mysql_free_result(result);
++ rc= mysql_more_results(mysql_local);
++ FAIL_UNLESS(rc == 1, "rc != 1");
++ rc= mysql_next_result(mysql_local);
++ FAIL_UNLESS(rc > 0, "rc <= 0");
++
++ /*
++ Ensure that we can now do a simple query (this checks that the server is
++ not trying to send us the results for the last 'select 1'
++ */
++ rc= mysql_query(mysql_local, "select 1+1+1");
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql_local);
++ FAIL_IF(!result, "Invalid result set");
++ mysql_free_result(result);
++
++ /*
++ Check if errors in one of the queries handled properly.
++ */
++ rc= mysql_query(mysql_local, "select 1; select * from not_existing_table");
++ check_mysql_rc(rc, mysql);
++ result= mysql_store_result(mysql_local);
++ mysql_free_result(result);
++
++ rc= mysql_next_result(mysql_local);
++ FAIL_UNLESS(rc > 0, "rc <= 0");
++
++ rc= mysql_next_result(mysql_local);
++ FAIL_UNLESS(rc < 0, "rc >= 0");
++
++ return OK;
++}
++
++
++
++struct my_tests_st my_tests[] = {
++ {"client_store_result", client_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"client_use_result", client_use_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_free_result", test_free_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_free_store_result", test_free_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_store_result", test_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_store_result1", test_store_result1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_store_result2", test_store_result2, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug11718", test_bug11718, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug19671", test_bug19671, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug21726", test_bug21726, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug6761", test_bug6761, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_field_flags", test_field_flags, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_field_names", test_field_names, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_func_fields", test_func_fields, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_list_fields", test_list_fields, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug9735", test_bug9735, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
++ {"test_bug9992", test_bug9992, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
++ {"test_multi_statements", test_multi_statements, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== modified file 'unittest/libmariadb/sp.c'
---- mariadb/unittest/libmysql/sp.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/sp.c 2013-03-14 21:01:43 +0000
-@@ -80,8 +80,8 @@
-
- int main(int argc, char **argv)
- {
--// if (argc > 1)
--// get_options(&argc, &argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/sample.csv mariadb-native-client.trunk/unittest/libmariadb/sample.csv
+--- mariadb/unittest/libmariadb/sample.csv 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/sample.csv 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,3 @@
++"1","1","1"
++"2","2","2"
++"3","3","3"
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/sp.c mariadb-native-client.trunk/unittest/libmariadb/sp.c
+--- mariadb/unittest/libmariadb/sp.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/sp.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,91 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++/* Bug#15752 "Lost connection to MySQL server when calling a SP from C API" */
++
++static int test_bug15752(MYSQL *mysql)
++{
++ int rc, i;
++ const int ITERATION_COUNT= 100;
++ const char *query= "CALL p1()";
++
++
++ rc= mysql_query(mysql, "drop procedure if exists p1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create procedure p1() select 1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_real_query(mysql, query, strlen(query));
++ check_mysql_rc(rc, mysql);
++ mysql_free_result(mysql_store_result(mysql));
++
++ rc= mysql_real_query(mysql, query, strlen(query));
++ FAIL_UNLESS(rc && mysql_errno(mysql) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
++
++ rc= mysql_next_result(mysql);
++ check_mysql_rc(rc, mysql);
++
++ mysql_free_result(mysql_store_result(mysql));
++
++ rc= mysql_next_result(mysql);
++ FAIL_IF(rc != -1, "rc != -1");
++
++ for (i = 0; i < ITERATION_COUNT; i++)
++ {
++ rc= mysql_real_query(mysql, query, strlen(query));
++ check_mysql_rc(rc, mysql);
++ mysql_free_result(mysql_store_result(mysql));
++ rc= mysql_next_result(mysql);
++ check_mysql_rc(rc, mysql);
++ mysql_free_result(mysql_store_result(mysql));
++ rc= mysql_next_result(mysql);
++ FAIL_IF(rc != -1, "rc != -1");
++
++ }
++ rc= mysql_query(mysql, "drop procedure p1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++
++
++struct my_tests_st my_tests[] = {
++ {"test_bug15752", test_bug15752, TEST_CONNECTION_NEW, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
+ if (argc > 1)
+ get_options(argc, argv);
-
- get_envvars();
-
-
-=== added file 'unittest/libmariadb/sqlite3.c'
---- mariadb/unittest/libmariadb/sqlite3.c 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/sqlite3.c 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,191 @@
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/sqlite3.c mariadb-native-client.trunk/unittest/libmariadb/sqlite3.c
+--- mariadb/unittest/libmariadb/sqlite3.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/sqlite3.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,195 @@
+/**
+ Some basic tests for sqlite
+*/
+
+#include "my_test.h"
+
++#ifdef HAVE_SQLITE
+static int test1(MYSQL *mysql)
+{
+ MYSQL_ROW row;
@@ -152105,7 +221459,7 @@
+
+ diag("Server name: %s", mysql_get_server_name(my));
+
-+ diag("Connected to: %s (%d)", mysql_get_server_info(my), mysql_get_server_version(my));
++ diag("Connected to: %s (%lu)", mysql_get_server_info(my), mysql_get_server_version(my));
+
+ rc= mysql_query(my, "CREATE TABLE t1 (a int, b varchar(255))");
+ rc= mysql_query(my, "DELETE FROM t1");
@@ -152253,11 +221607,14 @@
+
+ return OK;
+}
++#endif
+
+
+struct my_tests_st my_tests[] = {
++#ifdef HAVE_SQLITE
+ {"test-sqlite", test1, TEST_CONNECTION_NONE, 0, NULL, NULL},
+ {"test_simple_prepare", test_simple_prepare, TEST_CONNECTION_NONE, 0, NULL, NULL},
++#endif
+ {NULL, NULL, 0, 0, NULL, NULL}
+};
+
@@ -152274,41 +221631,226 @@
+
+ return(exit_status());
+}
-
-=== modified file 'unittest/libmariadb/ssl.c'
---- mariadb/unittest/libmysql/ssl.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/ssl.c 2013-03-14 21:01:43 +0000
-@@ -74,7 +74,7 @@
- my= mysql_init(NULL);
- FAIL_IF(!my, "mysql_init() failed");
-
-- mysql_ssl_set(my,0, 0, "./ca.pem", 0);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/ssl.c mariadb-native-client.trunk/unittest/libmariadb/ssl.c
+--- mariadb/unittest/libmariadb/ssl.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/ssl.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,469 @@
++/************************************************************************************
++ Copyright (C) 2012 Monty Program AB
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public
++ License as published by the Free Software Foundation; either
++ version 2 of the License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; if not see <http://www.gnu.org/licenses>
++ or write to the Free Software Foundation, Inc.,
++ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
++ *************************************************************************************/
++
++#include "my_test.h"
++#include <my_pthread.h>
++
++static int skip_ssl= 1;
++
++#ifndef WIN32
++pthread_mutex_t LOCK_test;
++#endif
++
++int check_skip_ssl()
++{
++#ifndef HAVE_OPENSSL
++ diag("client library built without OpenSSL support -> skip");
++ return 1;
++#endif
++ if (skip_ssl)
++ {
++ diag("server doesn't support SSL -> skip");
++ return 1;
++ }
++ return 0;
++}
++
++static int test_ssl(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++
++ rc= mysql_query(mysql, "SELECT @@have_ssl");
++ check_mysql_rc(rc, mysql);
++
++ res= mysql_store_result(mysql);
++ FAIL_IF(!res, mysql_error(mysql));
++
++ if ((row= mysql_fetch_row(res)))
++ {
++ if (!strcmp(row[0], "YES"))
++ skip_ssl= 0;
++ diag("SSL: %s", row[0]);
++ }
++ mysql_free_result(res);
++
++ return OK;
++}
++
++static int test_ssl_cipher(MYSQL *unused)
++{
++ MYSQL *my;
++ char *cipher;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ my= mysql_init(NULL);
++ FAIL_IF(!my, "mysql_init() failed");
++
+ mysql_ssl_set(my,0, 0, "./certs/ca.pem", 0, 0);
-
- FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
- port, socketname, 0), mysql_error(my));
-@@ -115,7 +115,7 @@
- mysql[i]= mysql_init(NULL);
- FAIL_IF(!mysql[i],"mysql_init() failed");
-
-- mysql_ssl_set(mysql[i], 0, 0, "./ca.pem", 0);
++
++ FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
++ port, socketname, 0), mysql_error(my));
++
++ cipher= (char *)mysql_get_ssl_cipher(my);
++ FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
++ mysql_close(my);
++ return OK;
++}
++
++static int test_multi_ssl_connections(MYSQL *unused)
++{
++ MYSQL *mysql[50], *my;
++ char *cipher;
++ int i, rc;
++ int old_connections= 0, new_connections= 0;
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ my= mysql_init(NULL);
++ FAIL_IF(!my,"mysql_init() failed");
++ FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
++ port, socketname, 0), mysql_error(my));
++
++ rc= mysql_query(my, "SHOW STATUS LIKE 'Ssl_accepts'");
++ check_mysql_rc(rc, my);
++
++ res= mysql_store_result(my);
++ if ((row= mysql_fetch_row(res)))
++ old_connections= atoi(row[1]);
++ mysql_free_result(res);
++
++ for (i=0; i < 50; i++)
++ {
++ mysql[i]= mysql_init(NULL);
++ FAIL_IF(!mysql[i],"mysql_init() failed");
++
+ mysql_ssl_set(mysql[i], 0, 0, "./certs/ca.pem", 0, 0);
-
- FAIL_IF(!mysql_real_connect(mysql[i], hostname, username, password, schema,
- port, socketname, 0), mysql_error(mysql[i]));
-@@ -154,7 +154,7 @@
- mysql_thread_end();
- pthread_exit(-1);
- }
-- mysql_ssl_set(mysql, 0, 0, "./ca.pem", 0);
++
++ mysql_real_connect(mysql[i], hostname, username, password, schema,
++ port, socketname, 0);
++ if (mysql_errno(mysql[i]))
++ {
++ diag("loop: %d error: %d %s", i, mysql_errno(mysql[i]), mysql_error(mysql[i]));
++ return FAIL;
++ }
++
++ cipher= (char *)mysql_get_ssl_cipher(mysql[i]);
++ FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
++ }
++ for (i=0; i < 50; i++)
++ mysql_close(mysql[i]);
++
++ rc= mysql_query(my, "SHOW STATUS LIKE 'Ssl_accepts'");
++ check_mysql_rc(rc, my);
++
++ res= mysql_store_result(my);
++ if ((row= mysql_fetch_row(res)))
++ new_connections= atoi(row[1]);
++ mysql_free_result(res);
++
++ mysql_close(my);
++
++ diag("%d SSL connections processed", new_connections - old_connections);
++ FAIL_IF(new_connections - old_connections < 50, "new_connections should be at least old_connections + 50");
++ return OK;
++}
++
++#ifndef WIN32
++static void ssl_thread(void)
++{
++ MYSQL *mysql;
++
++ mysql_thread_init();
++
++ if (!(mysql= mysql_init(NULL)))
++ {
++ mysql_thread_end();
++ pthread_exit(NULL);
++ }
+ mysql_ssl_set(mysql, 0, 0, "./certs/ca.pem", 0, 0);
-
- if(!mysql_real_connect(mysql, hostname, username, password, schema,
- port, socketname, 0))
-@@ -213,8 +213,30 @@
- }
- #endif
-
++
++ if(!mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0))
++ {
++ diag(">Error: %s", mysql_error(mysql));
++ mysql_close(mysql);
++ mysql_thread_end();
++ pthread_exit(NULL);
++ }
++
++ pthread_mutex_lock(&LOCK_test);
++ mysql_query(mysql, "UPDATE ssltest SET a=a+1");
++ pthread_mutex_unlock(&LOCK_test);
++ mysql_close(mysql);
++ mysql_thread_end();
++ pthread_exit(0);
++}
++
++static int test_ssl_threads(MYSQL *mysql)
++{
++ int i, rc;
++ pthread_t thread[50];
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ rc= mysql_query(mysql, "DROP TABLE IF exists ssltest");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE ssltest (a int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT into ssltest VALUES (0)");
++ check_mysql_rc(rc, mysql);
++
++ pthread_mutex_init(&LOCK_test, NULL);
++
++ for (i=0; i < 50; i++)
++ pthread_create(&thread[i], NULL, (void *)&ssl_thread, NULL);
++ for (i=0; i < 50; i++)
++ pthread_join(thread[i], NULL);
++
++ pthread_mutex_destroy(&LOCK_test);
++
++ rc= mysql_query(mysql, "SELECT a FROM ssltest");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ row= mysql_fetch_row(res);
++ diag("Found: %s", row[0]);
++ FAIL_IF(strcmp(row[0], "50") != 0, "Expected 50");
++ mysql_free_result(res);
++ return OK;
++}
++#endif
++
+static int test_phpbug51647(MYSQL *my)
+{
+ MYSQL* mysql;
@@ -152319,7 +221861,7 @@
+ mysql= mysql_init(NULL);
+ FAIL_IF(!mysql, "Can't allocate memory");
+
-+ mysql_ssl_set(mysql, "certs/client-key.pem", "certs/client-cert.pem", "certs/ca-cert.pem", 0, 0);
++ mysql_ssl_set(mysql, "./certs/client-key.pem", "./certs/client-cert.pem", "./certs/ca.pem", 0, 0);
+
+ FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
+ port, socketname, 0), mysql_error(mysql));
@@ -152329,18 +221871,243 @@
+ return OK;
+}
+
++static int test_conc50(MYSQL *my)
++{
++ MYSQL *mysql;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, "certs/my_cert.pem", NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ diag("Error: %d %s", mysql_errno(mysql), mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int test_conc50_1(MYSQL *my)
++{
++ MYSQL *mysql;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, "./certs/ca.pem", NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ if (mysql_errno(mysql))
++ diag("Error: %d %s", mysql_errno(mysql), mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql), "No error expected");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int test_conc50_2(MYSQL *my)
++{
++ MYSQL *mysql;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, "./certs/dummy.pem", NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int test_conc50_3(MYSQL *my)
++{
++ MYSQL *mysql;
++ int rc;
++ char query[256];
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql_query(my, "DROP USER 'ssltest'@'localhost'");
++
++ sprintf(query, "GRANT ALL ON %s.* TO 'ssltest'@'localhost' REQUIRE SSL", schema ? schema : "*");
++ rc= mysql_query(my, query);
++ check_mysql_rc(rc, my);
++ rc= mysql_query(my, "FLUSH PRIVILEGES");
++ check_mysql_rc(rc, my);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, (const char *)"ssltest", NULL, schema,
++ port, socketname, 0);
++ FAIL_IF(!mysql_errno(mysql), "Error expected, SSL connection required!");
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, "./certs/ca.pem", NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, "ssltest", NULL, schema,
++ port, socketname, 0);
++ FAIL_IF(mysql_errno(mysql), "No error expected");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int test_conc50_4(MYSQL *my)
++{
++ MYSQL *mysql;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, "./certs/ca.pem", NULL, NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ diag("Error: %s", mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int verify_ssl_server_cert(MYSQL *my)
++{
++ MYSQL *mysql;
++ uint verify= 1;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, NULL, NULL, "./certs/ca.pem", NULL, NULL);
++ mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++static int test_bug62743(MYSQL *my)
++{
++ MYSQL *mysql;
++
++ if (check_skip_ssl())
++ return SKIP;
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, "dummykey", NULL, NULL, NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ diag("Error: %s", mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, "./certs/client-key.pem", NULL, NULL, NULL, NULL);
+
- struct my_tests_st my_tests[] = {
- {"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ diag("Error with key: %s", mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql) != 2026, "Expected errno 2026");
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, "./certs/client-key.pem", "./certs/client-cert.pem", NULL, NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ FAIL_IF(mysql_errno(mysql) != 0, "Expected no error");
++ mysql_close(mysql);
++
++ mysql= mysql_init(NULL);
++ FAIL_IF(!mysql, "Can't allocate memory");
++
++ mysql_ssl_set(mysql, "./certs/client-key.pem", "blablubb", NULL, NULL, NULL);
++
++ mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0);
++ diag("Error with cert: %s", mysql_error(mysql));
++ FAIL_IF(mysql_errno(mysql) == 0, "Expected error");
++ mysql_close(mysql);
++
++ return OK;
++}
++
++struct my_tests_st my_tests[] = {
++ {"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_conc50", test_conc50, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_conc50_1", test_conc50_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_conc50_2", test_conc50_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_conc50_3", test_conc50_3, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_conc50_4", test_conc50_4, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"verify_ssl_server_cert", verify_ssl_server_cert, TEST_CONNECTION_NEW, 0, NULL, NULL},
++ {"test_bug62743", test_bug62743, TEST_CONNECTION_NEW, 0, NULL, NULL},
+ {"test_phpbug51647", test_phpbug51647, TEST_CONNECTION_NONE, 0, NULL, NULL},
- {"test_ssl_cipher", test_ssl_cipher, TEST_CONNECTION_NONE, 0, NULL, NULL},
- {"test_multi_ssl_connections", test_multi_ssl_connections, TEST_CONNECTION_NONE, 0, NULL, NULL},
- #ifndef WIN32
-
-=== added file 'unittest/libmariadb/thread.c'
---- mariadb/unittest/libmariadb/thread.c 1970-01-01 00:00:00 +0000
-+++ mariadb/unittest/libmariadb/thread.c 2013-03-14 21:01:43 +0000
-@@ -0,0 +1,61 @@
++ {"test_ssl_cipher", test_ssl_cipher, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_multi_ssl_connections", test_multi_ssl_connections, TEST_CONNECTION_NONE, 0, NULL, NULL},
++#ifndef WIN32
++ {"test_ssl_threads", test_ssl_threads, TEST_CONNECTION_NEW, 0, NULL, NULL},
++#endif
++
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++
++int main(int argc, char **argv)
++{
++ get_envvars();
++
++ if (argc > 1)
++ get_options(argc, argv);
++
++
++ run_tests(my_tests);
++
++ mysql_server_end();
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/thread.c mariadb-native-client.trunk/unittest/libmariadb/thread.c
+--- mariadb/unittest/libmariadb/thread.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/thread.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,167 @@
+/*
+*/
+
@@ -152376,11 +222143,119 @@
+ mysql_free_result(res);
+ mysql_close(my);
+
++
+ return OK;
+}
+
++pthread_mutex_t LOCK_test;
++
++#ifndef _WIN32
++int thread_conc27(void);
++#else
++DWORD WINAPI thread_conc27(void);
++#endif
++
++#define THREAD_NUM 100
++
++/* run this test as root and increase the number of handles (ulimit -n) */
++static int test_conc_27(MYSQL *mysql)
++{
++
++ int rc;
++ int i;
++ MYSQL_ROW row;
++ MYSQL_RES *res;
++#ifndef _WIN32
++ pthread_t threads[THREAD_NUM];
++#else
++ HANDLE hthreads[THREAD_NUM];
++ DWORD threads[THREAD_NUM];
++#endif
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t_conc27");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "CREATE TABLE t_conc27(a int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "INSERT INTO t_conc27 VALUES(0)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SET GLOBAL max_connections=100000");
++ check_mysql_rc(rc, mysql);
++
++ pthread_mutex_init(&LOCK_test, NULL);
++ for (i=0; i < THREAD_NUM; i++)
++ {
++#ifndef _WIN32
++ pthread_create(&threads[i], NULL, (void *)thread_conc27, NULL);
++#else
++ hthreads[i]= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_conc27, NULL, 0, &threads[i]);
++ if (hthreads[i]==NULL)
++ diag("error while starting thread");
++#endif
++ }
++ for (i=0; i < THREAD_NUM; i++)
++ {
++#ifndef _WIN32
++ pthread_join(threads[i], NULL);
++#else
++ WaitForSingleObject(hthreads[i], INFINITE);
++#endif
++ }
++ pthread_mutex_destroy(&LOCK_test);
++
++ rc= mysql_query(mysql, "SELECT a FROM t_conc27");
++ check_mysql_rc(rc,mysql);
++
++ res= mysql_store_result(mysql);
++ FAIL_IF(!res, "invalid result");
++
++ row= mysql_fetch_row(res);
++ FAIL_IF(!row, "can't fetch row");
++
++ diag("row=%s", row[0]);
++ FAIL_IF(atoi(row[0]) != THREAD_NUM, "expected value THREAD_NUM");
++ mysql_free_result(res);
++
++ return OK;
++}
++
++#ifndef _WIN32
++int thread_conc27(void)
++#else
++DWORD WINAPI thread_conc27(void)
++#endif
++{
++ MYSQL *mysql;
++ int rc;
++ MYSQL_RES *res;
++ mysql_thread_init();
++ mysql= mysql_init(NULL);
++ if(!mysql_real_connect(mysql, hostname, username, password, schema,
++ port, socketname, 0))
++ {
++ diag(">Error: %s", mysql_error(mysql));
++ mysql_close(mysql);
++ mysql_thread_end();
++ goto end;
++ }
++ pthread_mutex_lock(&LOCK_test);
++ rc= mysql_query(mysql, "UPDATE t_conc27 SET a=a+1");
++ check_mysql_rc(rc, mysql);
++ pthread_mutex_unlock(&LOCK_test);
++ check_mysql_rc(rc, mysql);
++ if (res= mysql_store_result(mysql))
++ mysql_free_result(res);
++ mysql_close(mysql);
++end:
++ mysql_thread_end();
++ return 0;
++}
++
+struct my_tests_st my_tests[] = {
+ {"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
++ {"test_conc_27", test_conc_27, TEST_CONNECTION_NEW, 0, NULL, NULL},
+ {NULL, NULL, 0, 0, NULL, NULL}
+};
+
@@ -152389,9 +222264,6 @@
+{
+
+ mysql_library_init(0,0,NULL);
-+ mysql_thread_init();
-+ mysql_thread_end();
-+ mysql_library_end();
+
+ if (argc > 1)
+ get_options(argc, argv);
@@ -152400,19 +222272,20526 @@
+
+ run_tests(my_tests);
+
++ mysql_server_end();
+ return(exit_status());
+}
-
-=== modified file 'unittest/libmariadb/view.c'
---- mariadb/unittest/libmysql/view.c 2012-11-26 07:32:41 +0000
-+++ mariadb/unittest/libmariadb/view.c 2013-03-14 21:01:43 +0000
-@@ -569,7 +569,7 @@
- rc= mysql_query(mysql, "drop table t1");
- check_mysql_rc(rc, mysql);
-
-- return OK;
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmariadb/view.c mariadb-native-client.trunk/unittest/libmariadb/view.c
+--- mariadb/unittest/libmariadb/view.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/unittest/libmariadb/view.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,700 @@
++/*
++Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
++
++The MySQL Connector/C is licensed under the terms of the GPLv2
++<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
++MySQL Connectors. There are special exceptions to the terms and
++conditions of the GPLv2 as it is applied to this software, see the
++FLOSS License Exception
++<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published
++by the Free Software Foundation; version 2 of the License.
++
++This program is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License along
++with this program; if not, write to the Free Software Foundation, Inc.,
++51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++#include "my_test.h"
++
++static int test_view(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ MYSQL_BIND my_bind[1];
++ char str_data[50];
++ ulong length = 0L;
++ long is_null = 0L;
++ const char *query=
++ "SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?";
++
++ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3,v1");
++ check_mysql_rc(rc, mysql);
++
++ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1,t2,t3");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE TABLE t1 ("
++ " SERVERGRP varchar(20) NOT NULL default '', "
++ " DBINSTANCE varchar(20) NOT NULL default '', "
++ " PRIMARY KEY (SERVERGRP)) "
++ " CHARSET=latin1 collate=latin1_bin");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE TABLE t2 ("
++ " SERVERNAME varchar(20) NOT NULL, "
++ " SERVERGRP varchar(20) NOT NULL, "
++ " PRIMARY KEY (SERVERNAME)) "
++ " CHARSET=latin1 COLLATE latin1_bin");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE TABLE t3 ("
++ " SERVERGRP varchar(20) BINARY NOT NULL, "
++ " TABNAME varchar(30) NOT NULL, MAPSTATE char(1) NOT NULL, "
++ " ACTSTATE char(1) NOT NULL , "
++ " LOCAL_NAME varchar(30) NOT NULL, "
++ " CHG_DATE varchar(8) NOT NULL default '00000000', "
++ " CHG_TIME varchar(6) NOT NULL default '000000', "
++ " MXUSER varchar(12) NOT NULL default '', "
++ " PRIMARY KEY (SERVERGRP, TABNAME, MAPSTATE, ACTSTATE, "
++ " LOCAL_NAME)) CHARSET=latin1 COLLATE latin1_bin");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE VIEW v1 AS select sql_no_cache"
++ " T0001.SERVERNAME AS SERVERNAME, T0003.TABNAME AS"
++ " TABNAME,T0003.LOCAL_NAME AS LOCAL_NAME,T0002.DBINSTANCE AS"
++ " DBINSTANCE from t2 T0001 join t1 T0002 join t3 T0003 where"
++ " ((T0002.SERVERGRP = T0001.SERVERGRP) and"
++ " (T0002.SERVERGRP = T0003.SERVERGRP)"
++ " and (T0003.MAPSTATE = _latin1'A') and"
++ " (T0003.ACTSTATE = _latin1' '))");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ strcpy(str_data, "TEST");
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[0].buffer= (char *)&str_data;
++ my_bind[0].buffer_length= 50;
++ my_bind[0].length= &length;
++ length= 4;
++ my_bind[0].is_null= (char*)&is_null;
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ int rowcount= 0;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_IF(rowcount != 1, "Expected 1 row");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1,t2,t3");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_view_where(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query=
++ "select v1.c,v2.c from v1, v2";
++
++ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1,v2");
++ check_mysql_rc(rc, mysql);
++
++ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,v2,t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE TABLE t1 (a int, b int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"create view v1 (c) as select b from t1 where a<3");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"create view v2 (c) as select b from t1 where a>=3");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ int rowcount= 0;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_UNLESS(4 == rowcount, "Expected 4 rows");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW v1, v2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_view_2where(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ MYSQL_BIND my_bind[8];
++ char parms[8][100];
++ ulong length[8];
++ const char *query=
++ "select relid, report, handle, log_group, username, variant, type, "
++ "version, erfdat, erftime, erfname, aedat, aetime, aename, dependvars, "
++ "inactive from V_LTDX where mandt = ? and relid = ? and report = ? and "
++ "handle = ? and log_group = ? and username in ( ? , ? ) and type = ?";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS LTDX");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS V_LTDX");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE TABLE LTDX (MANDT char(3) NOT NULL default '000', "
++ " RELID char(2) NOT NULL, REPORT varchar(40) NOT NULL,"
++ " HANDLE varchar(4) NOT NULL, LOG_GROUP varchar(4) NOT NULL,"
++ " USERNAME varchar(12) NOT NULL,"
++ " VARIANT varchar(12) NOT NULL,"
++ " TYPE char(1) NOT NULL, SRTF2 int(11) NOT NULL,"
++ " VERSION varchar(6) NOT NULL default '000000',"
++ " ERFDAT varchar(8) NOT NULL default '00000000',"
++ " ERFTIME varchar(6) NOT NULL default '000000',"
++ " ERFNAME varchar(12) NOT NULL,"
++ " AEDAT varchar(8) NOT NULL default '00000000',"
++ " AETIME varchar(6) NOT NULL default '000000',"
++ " AENAME varchar(12) NOT NULL,"
++ " DEPENDVARS varchar(10) NOT NULL,"
++ " INACTIVE char(1) NOT NULL, CLUSTR smallint(6) NOT NULL,"
++ " CLUSTD blob,"
++ " PRIMARY KEY (MANDT, RELID, REPORT, HANDLE, LOG_GROUP, "
++ "USERNAME, VARIANT, TYPE, SRTF2))"
++ " CHARSET=latin1 COLLATE latin1_bin");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE VIEW V_LTDX AS select T0001.MANDT AS "
++ " MANDT,T0001.RELID AS RELID,T0001.REPORT AS "
++ " REPORT,T0001.HANDLE AS HANDLE,T0001.LOG_GROUP AS "
++ " LOG_GROUP,T0001.USERNAME AS USERNAME,T0001.VARIANT AS "
++ " VARIANT,T0001.TYPE AS TYPE,T0001.VERSION AS "
++ " VERSION,T0001.ERFDAT AS ERFDAT,T0001.ERFTIME AS "
++ " ERFTIME,T0001.ERFNAME AS ERFNAME,T0001.AEDAT AS "
++ " AEDAT,T0001.AETIME AS AETIME,T0001.AENAME AS "
++ " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS "
++ " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)");
++ check_mysql_rc(rc, mysql);
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++ for (i=0; i < 8; i++) {
++ strcpy(parms[i], "1");
++ my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
++ my_bind[i].buffer = (char *)&parms[i];
++ my_bind[i].buffer_length = 100;
++ my_bind[i].is_null = 0;
++ my_bind[i].length = &length[i];
++ length[i] = 1;
++ }
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP VIEW V_LTDX");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE LTDX");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_view_star(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ MYSQL_BIND my_bind[8];
++ char parms[8][100];
++ ulong length[8];
++ const char *query= "SELECT * FROM vt1 WHERE a IN (?,?)";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, vt1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, vt1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
++ check_mysql_rc(rc, mysql);
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++ for (i= 0; i < 2; i++) {
++ sprintf((char *)&parms[i], "%d", i);
++ my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
++ my_bind[i].buffer = (char *)&parms[i];
++ my_bind[i].buffer_length = 100;
++ my_bind[i].is_null = 0;
++ my_bind[i].length = &length[i];
++ length[i] = 1;
++ }
++
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_fetch(stmt);
++ FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
++ }
++
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW vt1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_view_insert(MYSQL *mysql)
++{
++ MYSQL_STMT *insert_stmt, *select_stmt;
++ int rc, i;
++ MYSQL_BIND my_bind[1];
++ int my_val = 0;
++ ulong my_length = 0L;
++ long my_null = 0L;
++ const char *query=
++ "insert into v1 values (?)";
++
++ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
++ check_mysql_rc(rc, mysql);
++ rc = mysql_query(mysql, "DROP VIEW IF EXISTS t1,v1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql,"create table t1 (a int, primary key (a))");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create view v1 as select a from t1 where a>=1");
++ check_mysql_rc(rc, mysql);
++
++ insert_stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(insert_stmt, query, strlen(query));
++ check_stmt_rc(rc, insert_stmt);
++ query= "select * from t1";
++ select_stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(select_stmt, query, strlen(query));
++ check_stmt_rc(rc, select_stmt);
++
++ memset(my_bind, '\0', sizeof(MYSQL_BIND));
++ my_bind[0].buffer_type = MYSQL_TYPE_LONG;
++ my_bind[0].buffer = (char *)&my_val;
++ my_bind[0].length = &my_length;
++ my_bind[0].is_null = (char*)&my_null;
++ rc= mysql_stmt_bind_param(insert_stmt, my_bind);
++ check_stmt_rc(rc, select_stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ int rowcount= 0;
++ my_val= i;
++
++ rc= mysql_stmt_execute(insert_stmt);
++ check_stmt_rc(rc, insert_stmt);;
++
++ rc= mysql_stmt_execute(select_stmt);
++ check_stmt_rc(rc, select_stmt);;
++ while (mysql_stmt_fetch(select_stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_UNLESS((i+1) == rowcount, "rowcount != i+1");
++ }
++ mysql_stmt_close(insert_stmt);
++ mysql_stmt_close(select_stmt);
++
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_left_join_view(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ int rc, i;
++ const char *query=
++ "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
++
++ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
++ check_mysql_rc(rc, mysql);
++
++ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
++ check_mysql_rc(rc, mysql);
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++
++ for (i= 0; i < 3; i++)
++ {
++ int rowcount= 0;
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_UNLESS(3 == rowcount, "Expected 3 rows");
++ }
++ mysql_stmt_close(stmt);
++
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++static int test_view_insert_fields(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ char parm[11][1000];
++ ulong l[11];
++ int rc, i;
++ int rowcount= 0;
++ MYSQL_BIND my_bind[11];
++ const char *query= "INSERT INTO `v1` ( `K1C4` ,`K2C4` ,`K3C4` ,`K4N4` ,`F1C4` ,`F2I4` ,`F3N5` ,`F7F8` ,`F6N4` ,`F5C8` ,`F9D8` ) VALUES( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )";
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE TABLE t1 (K1C4 varchar(4) NOT NULL,"
++ "K2C4 varchar(4) NOT NULL, K3C4 varchar(4) NOT NULL,"
++ "K4N4 varchar(4) NOT NULL default '0000',"
++ "F1C4 varchar(4) NOT NULL, F2I4 int(11) NOT NULL,"
++ "F3N5 varchar(5) NOT NULL default '00000',"
++ "F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) NOT NULL,"
++ "F6N4 varchar(4) NOT NULL default '0000',"
++ "F7F8 double NOT NULL default '0',"
++ "F8F8 double NOT NULL default '0',"
++ "F9D8 decimal(8,2) NOT NULL default '0.00',"
++ "PRIMARY KEY (K1C4,K2C4,K3C4,K4N4)) "
++ "CHARSET=latin1 COLLATE latin1_bin");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql,
++ "CREATE VIEW v1 AS select sql_no_cache "
++ " K1C4 AS K1C4, K2C4 AS K2C4, K3C4 AS K3C4, K4N4 AS K4N4, "
++ " F1C4 AS F1C4, F2I4 AS F2I4, F3N5 AS F3N5,"
++ " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8"
++ " from t1 T0001");
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i= 0; i < 11; i++)
++ {
++ l[i]= 20;
++ my_bind[i].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[i].is_null= 0;
++ my_bind[i].buffer= (char *)&parm[i];
++
++ strcpy(parm[i], "1");
++ my_bind[i].buffer_length= 2;
++ my_bind[i].length= &l[i];
++ }
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_bind_param(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ mysql_stmt_close(stmt);
++
++ query= "select * from t1";
++ stmt= mysql_stmt_init(mysql);
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
++ rowcount++;
++ FAIL_UNLESS(1 == rowcount, "Expected 1 row");
++
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_view_sp_list_fields(MYSQL *mysql)
++{
++ int rc;
++ MYSQL_RES *res;
++ MYSQL_ROW row;
++ int skip;
++
++ /* skip this test if bin_log is on */
++ rc= mysql_query(mysql, "SHOW VARIABLES LIKE 'log_bin'");
++ check_mysql_rc(rc, mysql);
++ res= mysql_store_result(mysql);
++ FAIL_IF(!res, "empty/invalid resultset");
++ row = mysql_fetch_row(res);
++ skip= (strcmp((char *)row[1], "ON") == 0);
++ mysql_free_result(res);
++
++ if (skip) {
++ diag("bin_log is ON -> skip");
++ return SKIP;
++ }
++
++ rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create function f1 () returns int return 5");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t2 (s1 int);");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \
++count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \
++from t2);");
++ check_mysql_rc(rc, mysql);
++ res= mysql_list_fields(mysql, "v1", NullS);
++ FAIL_UNLESS(res != 0 && mysql_num_fields(res) != 0, "0 Fields");
++ rc= mysql_query(mysql, "DROP FUNCTION f1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP TABLE t1, t2");
++ mysql_free_result(res);
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++static int test_bug19671(MYSQL *mysql)
++{
++ MYSQL_RES *result;
++ MYSQL_FIELD *field;
++ int rc, retcode= OK;
++
++
++ rc= mysql_query(mysql, "set sql_mode=''");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "drop table if exists t1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "drop view if exists v1");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create table t1(f1 int)");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "create view v1 as select va.* from t1 va");
++ check_mysql_rc(rc, mysql);
++
++ rc= mysql_query(mysql, "SELECT * FROM v1");
++ check_mysql_rc(rc, mysql);
++
++ result= mysql_store_result(mysql);
++ FAIL_IF(!result, "Invalid result set");
++
++ field= mysql_fetch_field(result);
++ FAIL_IF(!field, "Can't fetch field");
++
++ if (strcmp(field->table, "v1") != 0) {
++ diag("Wrong value '%s' for field_table. Expected 'v1'. (%s: %d)", field->table, __FILE__, __LINE__);
++ retcode= FAIL;
++ }
++
++ mysql_free_result(result);
++
++ rc= mysql_query(mysql, "drop view v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "drop table t1");
++ check_mysql_rc(rc, mysql);
++
+ return retcode;
- }
-
- /*
-
++}
++
++/*
++ Bug#11111: fetch from view returns wrong data
++*/
++
++static int test_bug11111(MYSQL *mysql)
++{
++ MYSQL_STMT *stmt;
++ MYSQL_BIND my_bind[2];
++ char buf[2][20];
++ ulong len[2];
++ int i;
++ int rc;
++ const char *query= "SELECT DISTINCT f1,ff2 FROM v1";
++
++ rc= mysql_query(mysql, "drop table if exists t1, t2, v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "drop view if exists t1, t2, v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t1 (f1 int, f2 int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create table t2 (ff1 int, ff2 int)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "create view v1 as select * from t1, t2 where f1=ff1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t1 values (1,1), (2,2), (3,3)");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "insert into t2 values (1,1), (2,2), (3,3)");
++ check_mysql_rc(rc, mysql);
++
++ stmt= mysql_stmt_init(mysql);
++
++ rc= mysql_stmt_prepare(stmt, query, strlen(query));
++ check_stmt_rc(rc, stmt);
++ rc= mysql_stmt_execute(stmt);
++ check_stmt_rc(rc, stmt);
++
++ memset(my_bind, '\0', sizeof(my_bind));
++ for (i=0; i < 2; i++)
++ {
++ my_bind[i].buffer_type= MYSQL_TYPE_STRING;
++ my_bind[i].buffer= (uchar* *)&buf[i];
++ my_bind[i].buffer_length= 20;
++ my_bind[i].length= &len[i];
++ }
++
++ rc= mysql_stmt_bind_result(stmt, my_bind);
++ check_stmt_rc(rc, stmt);
++
++ rc= mysql_stmt_fetch(stmt);
++ check_stmt_rc(rc, stmt);
++ FAIL_UNLESS(!strcmp(buf[1],"1"), "buf[1] != '1'");
++ mysql_stmt_close(stmt);
++ rc= mysql_query(mysql, "drop view v1");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "drop table t1, t2");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++/**
++ Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW
++*/
++
++static int test_bug29306(MYSQL *mysql)
++{
++ MYSQL_FIELD *field;
++ int rc;
++ MYSQL_RES *res;
++
++ DBUG_ENTER("test_bug29306");
++
++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS tab17557");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW IF EXISTS view17557");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE TABLE tab17557 (dd decimal (3,1))");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "CREATE VIEW view17557 as SELECT dd FROM tab17557");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "INSERT INTO tab17557 VALUES (7.6)");
++ check_mysql_rc(rc, mysql);
++
++ /* Checking the view */
++ res= mysql_list_fields(mysql, "view17557", NULL);
++ while ((field= mysql_fetch_field(res)))
++ {
++ FAIL_UNLESS(field->decimals == 1, "field->decimals != 1");
++ }
++ mysql_free_result(res);
++
++ rc= mysql_query(mysql, "DROP TABLE tab17557");
++ check_mysql_rc(rc, mysql);
++ rc= mysql_query(mysql, "DROP VIEW view17557");
++ check_mysql_rc(rc, mysql);
++
++ return OK;
++}
++
++
++struct my_tests_st my_tests[] = {
++ {"test_view", test_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_where", test_view_where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_2where", test_view_2where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_star", test_view_star, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_insert", test_view_insert, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_left_join_view", test_left_join_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_insert_fields", test_view_insert_fields, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_view_sp_list_fields", test_view_sp_list_fields,TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug19671", test_bug19671, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug29306", test_bug29306, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {"test_bug11111", test_bug11111, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
++ {NULL, NULL, 0, 0, NULL, NULL}
++};
++
++int main(int argc, char **argv)
++{
++// if (argc > 1)
++// get_options(&argc, &argv);
++
++ get_envvars();
++
++ run_tests(my_tests);
++
++ return(exit_status());
++}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/basic-t.c mariadb-native-client.trunk/unittest/libmysql/basic-t.c
+--- mariadb/unittest/libmysql/basic-t.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/basic-t.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,451 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-
+-
+-/**
+- Some basic tests of the client API.
+-*/
+-
+-#include "my_test.h"
+-
+-static int basic_connect(MYSQL *mysql)
+-{
+- MYSQL_ROW row;
+- MYSQL_RES *res;
+- int rc;
+-
+- MYSQL *my= mysql_init(NULL);
+- FAIL_IF(!my, "mysql_init() failed");
+-
+- FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
+- port, socketname, 0), mysql_error(my));
+-
+- rc= mysql_query(my, "SELECT @@version");
+- check_mysql_rc(rc, my);
+-
+- res= mysql_store_result(my);
+- FAIL_IF(!res, mysql_error(my));
+-
+- while ((row= mysql_fetch_row(res)) != NULL)
+- {
+- FAIL_IF(mysql_num_fields(res) != 1, "Got the wrong number of fields");
+- }
+- FAIL_IF(mysql_errno(my), mysql_error(my));
+-
+- mysql_free_result(res);
+- mysql_close(my);
+-
+- return OK;
+-}
+-
+-
+-static int use_utf8(MYSQL *my)
+-{
+- MYSQL_ROW row;
+- MYSQL_RES *res;
+- int rc;
+-
+- /* Make sure that we actually ended up with utf8. */
+- rc= mysql_query(my, "SELECT @@character_set_connection");
+- check_mysql_rc(rc, my);
+-
+- res= mysql_store_result(my);
+- FAIL_IF(!res, mysql_error(my));
+-
+- while ((row= mysql_fetch_row(res)) != NULL)
+- {
+- FAIL_IF(strcmp(row[0], "utf8"), "wrong character set");
+- }
+- FAIL_IF(mysql_errno(my), mysql_error(my));
+-
+-
+- return OK;
+-}
+-
+-int client_query(MYSQL *mysql) {
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE t1("
+- "id int primary key auto_increment, "
+- "name varchar(20))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' "
+- "WHERE name= 'deleted'");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug12001(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- const char *query= "DROP TABLE IF EXISTS test_table;"
+- "CREATE TABLE test_table(id INT);"
+- "INSERT INTO test_table VALUES(10);"
+- "UPDATE test_table SET id=20 WHERE id=10;"
+- "SELECT * FROM test_table;"
+- "INSERT INTO non_existent_table VALUES(11);";
+- int rc, res;
+-
+-
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- do
+- {
+- if (mysql_field_count(mysql) &&
+- (result= mysql_use_result(mysql)))
+- {
+- mysql_free_result(result);
+- }
+- }
+- while (!(res= mysql_next_result(mysql)));
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_UNLESS(res==1, "res != 1");
+-
+- return OK;
+-}
+-
+-
+-/* connection options */
+-struct my_option_st opt_utf8[] = {
+- {MYSQL_SET_CHARSET_NAME, "utf8"},
+- {0, NULL}
+-};
+-
+-static int test_bad_union(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *query= "SELECT 1, 2 union SELECT 1";
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_UNLESS(rc && mysql_errno(mysql) == 1222, "Error expected");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/*
+- Test that mysql_insert_id() behaves as documented in our manual
+-*/
+-static int test_mysql_insert_id(MYSQL *mysql)
+-{
+- my_ulonglong res;
+- int rc;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "drop table if exists t2");
+- check_mysql_rc(rc, mysql);
+- /* table without auto_increment column */
+- rc= mysql_query(mysql, "create table t1 (f1 int, f2 varchar(255), key(f1))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1,'a')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "insert into t1 values (null,'b')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "insert into t1 select 5,'c'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+-
+- /*
+- Test for bug #34889: mysql_client_test::test_mysql_insert_id test fails
+- sporadically
+- */
+- rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (null,'b')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 select 5,'c'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "drop table t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 select null,'d'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "insert into t1 values (null,last_insert_id(300))");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 300, "");
+- rc= mysql_query(mysql, "insert into t1 select null,last_insert_id(400)");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- /*
+- Behaviour change: old code used to return 0; but 400 is consistent
+- with INSERT VALUES, and the manual's section of mysql_insert_id() does not
+- say INSERT SELECT should be different.
+- */
+- FAIL_UNLESS(res == 400, "");
+-
+- /* table with auto_increment column */
+- rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (1,'a')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 1, "");
+- /* this should not influence next INSERT if it doesn't have auto_inc */
+- rc= mysql_query(mysql, "insert into t1 values (10,'e')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+-
+- rc= mysql_query(mysql, "insert into t2 values (null,'b')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 2, "");
+- rc= mysql_query(mysql, "insert into t2 select 5,'c'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- /*
+- Manual says that for multirow insert this should have been 5, but does not
+- say for INSERT SELECT. This is a behaviour change: old code used to return
+- 0. We try to be consistent with INSERT VALUES.
+- */
+- FAIL_UNLESS(res == 5, "");
+- rc= mysql_query(mysql, "insert into t2 select null,'d'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 6, "");
+- /* with more than one row */
+- rc= mysql_query(mysql, "insert into t2 values (10,'a'),(11,'b')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 11, "");
+- rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- /*
+- Manual says that for multirow insert this should have been 13, but does
+- not say for INSERT SELECT. This is a behaviour change: old code used to
+- return 0. We try to be consistent with INSERT VALUES.
+- */
+- FAIL_UNLESS(res == 13, "");
+- rc= mysql_query(mysql, "insert into t2 values (null,'a'),(null,'b')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 14, "");
+- rc= mysql_query(mysql, "insert into t2 select null,'a' union select null,'b'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 16, "");
+- rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_query(mysql, "insert ignore into t2 select 12,'a' union select 13,'b'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "insert into t2 values (12,'a'),(13,'b')");
+- FAIL_IF(!rc, "Error expected");
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "insert ignore into t2 values (12,'a'),(13,'b')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- /* mixing autogenerated and explicit values */
+- rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b')");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b'),(25,'g')");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_query(mysql, "insert into t2 values (null,last_insert_id(300))");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- /*
+- according to the manual, this might be 20 or 300, but it looks like
+- auto_increment column takes priority over last_insert_id().
+- */
+- FAIL_UNLESS(res == 20, "");
+- /* If first autogenerated number fails and 2nd works: */
+- rc= mysql_query(mysql, "drop table t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t2 (f1 int not null primary key "
+- "auto_increment, f2 varchar(255), unique (f2))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (null,'e')");
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 1, "");
+- rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(null,'a'),(null,'e')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 2, "");
+- /* If autogenerated fails and explicit works: */
+- rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(12,'c'),(null,'d')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- /*
+- Behaviour change: old code returned 3 (first autogenerated, even if it
+- fails); we now return first successful autogenerated.
+- */
+- FAIL_UNLESS(res == 13, "");
+- /* UPDATE may update mysql_insert_id() if it uses LAST_INSERT_ID(#) */
+- rc= mysql_query(mysql, "update t2 set f1=14 where f1=12");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "update t2 set f1=0 where f1=14");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- rc= mysql_query(mysql, "update t2 set f2=last_insert_id(372) where f1=0");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 372, "");
+- /* check that LAST_INSERT_ID() does not update mysql_insert_id(): */
+- rc= mysql_query(mysql, "insert into t2 values (null,'g')");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 15, "");
+- rc= mysql_query(mysql, "update t2 set f2=(@li:=last_insert_id()) where f1=15");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 0, "");
+- /*
+- Behaviour change: now if ON DUPLICATE KEY UPDATE updates a row,
+- mysql_insert_id() returns the id of the row, instead of not being
+- affected.
+- */
+- rc= mysql_query(mysql, "insert into t2 values (null,@li) on duplicate key "
+- "update f2=concat('we updated ',f2)");
+- check_mysql_rc(rc, mysql);
+- res= mysql_insert_id(mysql);
+- FAIL_UNLESS(res == 15, "");
+-
+- rc= mysql_query(mysql, "drop table t1,t2");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test simple select to debug */
+-
+-static int test_select_direct(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(id int, id1 tinyint, "
+- " id2 float, "
+- " id3 double, "
+- " name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert a row and commit the transaction */
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 5, 2.3, 4.5, 'venu')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_select");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-/*
+- Ensure we execute the status code while testing
+-*/
+-
+-static int test_status(MYSQL *mysql)
+-{
+- mysql_stat(mysql);
+- check_mysql_rc(mysql_errno(mysql), mysql);
+- return OK;
+-}
+-
+-struct my_tests_st my_tests[] = {
+- {"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
+- {"use_utf8", use_utf8, TEST_CONNECTION_NEW, 0, opt_utf8, NULL},
+- {"client_query", client_query, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bad_union", test_bad_union, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_select_direct", test_select_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_mysql_insert_id", test_mysql_insert_id, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug12001", test_bug12001, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
+- {"test_status", test_status, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+-/*
+- if (argc > 1)
+- get_options(&argc, &argv);
+-*/
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/ca.pem mariadb-native-client.trunk/unittest/libmysql/ca.pem
+--- mariadb/unittest/libmysql/ca.pem 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/ca.pem 1970-01-01 01:00:00.000000000 +0100
+@@ -1,38 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIIDGDCCAgACAQEwDQYJKoZIhvcNAQEFBQAwUjELMAkGA1UEBhMCREUxCzAJBgNV
+-BAgMAkJXMRMwEQYDVQQHDApIZWlkZWxiZXJnMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+-aWRnaXRzIFB0eSBMdGQwHhcNMTIxMTIyMDcxMDM5WhcNMjIxMDAxMDcxMDM5WjBS
+-MQswCQYDVQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkhlaWRlbGJlcmcx
+-ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
+-AQEBBQADggEPADCCAQoCggEBAOKiAyhtJXHgjr0cLFx+gYqBZCzg+Bpevh3/+U0t
+-A5trng5kht8dbI6m0Qjz8Mi09sFxaHmmL6WA+wxL8LqwMjOXpn3aAjNW3+QFu5Ei
+-Iy+8KrwdJdZVzRHCCLt4HWpeMQBzn2y/MUgZzc8+RhcQSu2KVDBiKLVpa6Z9k3gl
+-wsezI8ClJ6vWsJGnJX699H9BhMyS85ipVmeL69h5tWsdHQtmbK+XdHPQldi9r/88
+-f2VfIOo7EFSm9ohJG70P8lhEIqByhQ8Hw0akGWLLsLg4cufPVrOdPZocJ/qJjQVG
+-OkfSPkIgwKnpzGbXjFG5IMh5rXJCIRbO3ofTxGpSTzNQ0hcCAwEAATANBgkqhkiG
+-9w0BAQUFAAOCAQEAb7bIszKyzpCvom4FjnNYT3buQCf0qnUGoPgVpXIpjc4Lsyr0
+-nmIfgGNo/+5B1cj3iAtIuSojXOK96r8a84TueCaeX9ZDdG+ZZm9ng6mIiyQraZyR
+-Gl+VsTH40O0QTjMcPB344Yz0ZSHU1E35LzarApHtqZi9TpCBFc0td1EhxX7rdEOD
+-WzBRTKcMzV+Y0Fslqjy73JVYnaxJ/ZShW7TOowrdjE9DZ8VZ7dVSJOtdTLB5WNQE
+-mxFInjbUig5vvHzmf4bEsBDz7RXy0W8fMQd2HEcgGBDwdQYq18kZl9H5plORDCgg
+-S93U+OoInjEU2KEWyDyiBI7OwAZYIQytrxDBOw==
+------END CERTIFICATE-----
+------BEGIN CERTIFICATE-----
+-MIIDGDCCAgACAQEwDQYJKoZIhvcNAQEFBQAwUjELMAkGA1UEBhMCREUxCzAJBgNV
+-BAgMAkJXMRMwEQYDVQQHDApIZWlkZWxiZXJnMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+-aWRnaXRzIFB0eSBMdGQwHhcNMTIxMTIyMDcxMTI0WhcNMjIxMDAxMDcxMTI0WjBS
+-MQswCQYDVQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkhlaWRlbGJlcmcx
+-ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
+-AQEBBQADggEPADCCAQoCggEBANofs7wzZpUourQz03gALCHcTYXbuTJ16w/rbvql
+-WUa1R/qUgaxN9k7SEj260Vr7PMEREAIdKIu54jCy/yCRzYb/03HorQjJgGXjYvtX
+-nmwwUgLZSz3aLIX2p7jcw3ESiqN1/oZ3fB8+i6HT8igFcmbAOkPEN8TBM9Qenqj7
+-NNx9iYAOp7r8xJXJXTEWBIy0kJ2eXZQacveLGPgFs6Qq0Hvn8FsXT9zQQH98BQhL
+-o35vjxas/A8ThZiKd8cCmUbTtGxIlncR7FmJuqKAJVTSg/ZePFoYqW0s9GAtPJfC
+-DVdaT94uGZIWtOCLPqQgiEyjdHWHdeF+WBdXex3xRI3Ii+UCAwEAATANBgkqhkiG
+-9w0BAQUFAAOCAQEAKSXEbcpfgqZiWIJBpQX86kNMWhjA4m8GKwXoxhgxTtEZPju/
+-VO/ehjsTo8AnRQdW4/sD+KgVqn6F4jw5WVwK6L0TTlat5umn+zKW9c72Cmsf7kiZ
+-pc6bluyKv1uhS5pK1HLjQaL8vY4WExHkh8nGEuS4IIhAtHzBblE3G4/Kdq7V7IO7
+-+YaSwO1nRiYaFbrZkF8u+GOIVJlcQ7C7m2332c0NFYBmYoeJ03rwb8kWe40UHaiP
+-R3Pl/bzrRbcHiSqLawFpfYOG1+Sq9GkBwysv6ADU4wKcu9dYNvjgbRHhHuSLB3am
+-Dnj09lCHMDxHUtk1PhLsxG65lMw4GaUEqjfUmg==
+------END CERTIFICATE-----
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/charset.c mariadb-native-client.trunk/unittest/libmysql/charset.c
+--- mariadb/unittest/libmysql/charset.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/charset.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,683 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-
+-#include "my_test.h"
+-
+-/*
+- test gbk charset escaping
+-
+- The important part is that 0x27 (') is the second-byte in a invalid
+- two-byte GBK character here. But 0xbf5c is a valid GBK character, so
+- it needs to be escaped as 0x5cbf27
+-
+-*/
+-#define TEST_BUG8378_IN "\xef\xbb\xbf\x27\xbf\x10"
+-#define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10"
+-
+-/* set connection options */
+-struct my_option_st opt_bug8378[] = {
+- {MYSQL_SET_CHARSET_NAME, "gbk"},
+- {0, NULL}
+-};
+-
+-int bug_8378(MYSQL *mysql) {
+- int rc, len;
+- char out[9], buf[256];
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+-
+- len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
+- FAIL_IF(memcmp(out, TEST_BUG8378_OUT, len), "wrong result");
+-
+- sprintf(buf, "SELECT '%s' FROM DUAL", TEST_BUG8378_OUT);
+-
+- rc= mysql_query(mysql, buf);
+- check_mysql_rc(rc, mysql);
+-
+- if ((res= mysql_store_result(mysql))) {
+- row= mysql_fetch_row(res);
+- if (memcmp(row[0], TEST_BUG8378_IN, 4)) {
+- mysql_free_result(res);
+- return FAIL;
+- }
+- mysql_free_result(res);
+- } else
+- return FAIL;
+-
+- return OK;
+-}
+-
+-int test_client_character_set(MYSQL *mysql)
+-{
+- MY_CHARSET_INFO cs;
+- char *csname= (char*) "utf8";
+- char *csdefault= (char*)mysql_character_set_name(mysql);
+-
+- FAIL_IF(mysql_set_character_set(mysql, csname), mysql_error(mysql));
+-
+- mysql_get_character_set_info(mysql, &cs);
+-
+- FAIL_IF(strcmp(cs.csname, "utf8") || strcmp(cs.name, "utf8_general_ci"), "Character set != UTF8");
+- FAIL_IF(mysql_set_character_set(mysql, csdefault), mysql_error(mysql));
+-
+- return OK;
+-}
+-
+-/*
+- * Regression test for bug #10214
+- *
+- * Test escaping with NO_BACKSLASH_ESCAPES
+- *
+- */
+-int bug_10214(MYSQL *mysql)
+-{
+- int len, rc;
+- char out[8];
+-
+- /* reset sql_mode */
+- rc= mysql_query(mysql, "SET sql_mode=''");
+- check_mysql_rc(rc, mysql);
+-
+- len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+- FAIL_IF(memcmp(out, "a\\'b\\\\c", len), NULL);
+-
+- rc= mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
+- check_mysql_rc(rc, mysql);
+- FAIL_IF(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES),
+- "wrong server status: NO_BACKSLASH_ESCAPES not set");
+-
+- len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+- FAIL_IF(memcmp(out, "a''b\\c", len), "wrong result");
+-
+- return OK;
+-}
+-
+-/*
+- * simple escaping of special chars
+- */
+-int test_escaping(MYSQL *mysql)
+-{
+- int i= 0, rc, len;
+- char out[20];
+- char *escape_chars[] = {"'", "\x0", "\n", "\r", "\\", "\0", NULL};
+-
+- /* reset sql_mode, mysql_change_user call doesn't reset it */
+- rc= mysql_query(mysql, "SET sql_mode=''");
+- check_mysql_rc(rc, mysql);
+-
+- while (escape_chars[i]) {
+- len= mysql_real_escape_string(mysql, out, escape_chars[i], 1);
+- FAIL_IF(len < 2, "Len < 2");
+- i++;
+- }
+-
+- return OK;
+-}
+-
+-/*
+- * server doesn't reset sql_mode after COM_CHANGE_USER
+- */
+-int bug_41785(MYSQL *mysql)
+-{
+- char out[10];
+- int rc, len;
+-
+- len= mysql_real_escape_string(mysql, out, "\\", 1);
+- FAIL_IF(len != 2, "len != 2");
+-
+- rc= mysql_query(mysql, "SET SQL_MODE=NO_BACKSLASH_ESCAPES");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "SET sql_mode=''");
+- check_mysql_rc(rc, mysql);
+-
+- mysql_change_user(mysql, "root", "", "test");
+-
+- len= mysql_real_escape_string(mysql, out, "\\", 1);
+- FAIL_IF(len != 2, "len != 2");
+-
+- return OK;
+-}
+-
+-static int test_conversion(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- int rc;
+- MYSQL_BIND my_bind[1];
+- uchar buff[4];
+- ulong length;
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, "
+- " character_set_results=latin1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- stmt_text= "INSERT INTO t1 (a) VALUES (?)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer= (char*) buff;
+- my_bind[0].length= &length;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+-
+- mysql_stmt_bind_param(stmt, my_bind);
+-
+- buff[0]= (uchar) 0xC3;
+- buff[1]= (uchar) 0xA0;
+- length= 2;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- stmt_text= "SELECT a FROM t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- my_bind[0].buffer_length= sizeof(buff);
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(length == 1, "length != 1");
+- FAIL_UNLESS(buff[0] == 0xE0, "buff[0] != 0xE0");
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- stmt_text= "DROP TABLE t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "SET NAMES DEFAULT";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug27876(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+- uchar utf8_func[] =
+- {
+- 0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba,
+- 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba,
+- 0xd0, 0xb0,
+- 0x00
+- };
+-
+- uchar utf8_param[] =
+- {
+- 0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0,
+- 0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a,
+- 0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1,
+- 0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f,
+- 0x00
+- };
+-
+- char query[500];
+-
+- DBUG_ENTER("test_bug27876");
+-
+- rc= mysql_query(mysql, "set names utf8");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "select version()");
+- check_mysql_rc(rc, mysql);
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+- mysql_free_result(result);
+-
+- sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- sprintf(query,
+- "CREATE FUNCTION %s( %s VARCHAR(25))"
+- " RETURNS VARCHAR(25) DETERMINISTIC RETURN %s",
+- (char*) utf8_func, (char*) utf8_param, (char*) utf8_param);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+- sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+- mysql_free_result(result);
+-
+- sprintf(query, "DROP FUNCTION %s", (char*) utf8_func);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "set names default");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_ps_i18n(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *stmt_text;
+- MYSQL_BIND bind_array[2];
+-
+- /* Represented as numbers to keep UTF8 tools from clobbering them. */
+- const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
+- const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
+- char buf1[16], buf2[16];
+- ulong buf1_len, buf2_len;
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- Create table with binary columns, set session character set to cp1251,
+- client character set to koi8, and make sure that there is conversion
+- on insert and no conversion on select
+- */
+-
+- stmt_text= "CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, "
+- "CHARACTER_SET_CONNECTION=cp1251, "
+- "CHARACTER_SET_RESULTS=koi8r";
+-
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- memset(bind_array, '\0', sizeof(bind_array));
+- bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[0].buffer= (void *) koi8;
+- bind_array[0].buffer_length= strlen(koi8);
+-
+- bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[1].buffer= (void *) koi8;
+- bind_array[1].buffer_length= strlen(koi8);
+-
+- stmt= mysql_stmt_init(mysql);
+- check_stmt_rc(rc, stmt);
+-
+- stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_bind_param(stmt, bind_array);
+- check_stmt_rc(rc, stmt);
+-
+-// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "SELECT c1, c2 FROM t1";
+-
+- /* c1 and c2 are binary so no conversion will be done on select */
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- bind_array[0].buffer= buf1;
+- bind_array[0].buffer_length= sizeof(buf1);
+- bind_array[0].length= &buf1_len;
+-
+- bind_array[1].buffer= buf2;
+- bind_array[1].buffer_length= sizeof(buf2);
+- bind_array[1].length= &buf2_len;
+-
+- mysql_stmt_bind_result(stmt, bind_array);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(buf1_len == strlen(cp1251), "buf1_len != strlen(cp1251)");
+- FAIL_UNLESS(buf2_len == strlen(cp1251), "buf2_len != strlen(cp1251)");
+- FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "buf1 != cp1251");
+- FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "buf2 != cp1251");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- Now create table with two cp1251 columns, set client character
+- set to koi8 and supply columns of one row as string and another as
+- binary data. Binary data must not be converted on insert, and both
+- columns must be converted to client character set on select.
+- */
+-
+- stmt_text= "CREATE TABLE t1 (c1 VARCHAR(255) CHARACTER SET cp1251, "
+- "c2 VARCHAR(255) CHARACTER SET cp1251)";
+-
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- /* this data must be converted */
+- bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[0].buffer= (void *) koi8;
+- bind_array[0].buffer_length= strlen(koi8);
+-
+- bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[1].buffer= (void *) koi8;
+- bind_array[1].buffer_length= strlen(koi8);
+-
+- mysql_stmt_bind_param(stmt, bind_array);
+-
+-// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* this data must not be converted */
+- bind_array[0].buffer_type= MYSQL_TYPE_BLOB;
+- bind_array[0].buffer= (void *) cp1251;
+- bind_array[0].buffer_length= strlen(cp1251);
+-
+- bind_array[1].buffer_type= MYSQL_TYPE_BLOB;
+- bind_array[1].buffer= (void *) cp1251;
+- bind_array[1].buffer_length= strlen(cp1251);
+-
+- mysql_stmt_bind_param(stmt, bind_array);
+-
+-// mysql_stmt_send_long_data(stmt, 0, cp1251, strlen(cp1251));
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* Fetch data and verify that rows are in koi8 */
+-
+- stmt_text= "SELECT c1, c2 FROM t1";
+-
+- /* c1 and c2 are binary so no conversion will be done on select */
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- bind_array[0].buffer= buf1;
+- bind_array[0].buffer_length= sizeof(buf1);
+- bind_array[0].length= &buf1_len;
+-
+- bind_array[1].buffer= buf2;
+- bind_array[1].buffer_length= sizeof(buf2);
+- bind_array[1].length= &buf2_len;
+-
+- mysql_stmt_bind_result(stmt, bind_array);
+-
+- while ((rc= mysql_stmt_fetch(stmt)) == 0)
+- {
+- FAIL_UNLESS(buf1_len == strlen(koi8), "buf1_len != strlen(koi8)");
+- FAIL_UNLESS(buf2_len == strlen(koi8), "buf2_len != strlen(koi8)");
+- FAIL_UNLESS(!memcmp(buf1, koi8, buf1_len), "buf1 != koi8");
+- FAIL_UNLESS(!memcmp(buf2, koi8, buf1_len), "buf2 != koi8");
+- }
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- mysql_stmt_close(stmt);
+-
+- stmt_text= "DROP TABLE t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "SET NAMES DEFAULT";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/*
+- Bug#30472: libmysql doesn't reset charset, insert_id after succ.
+- mysql_change_user() call row insertions.
+-*/
+-
+-static int bug30472_retrieve_charset_info(MYSQL *con,
+- char *character_set_name,
+- char *character_set_client,
+- char *character_set_results,
+- char *collation_connection)
+-{
+- MYSQL_RES *rs;
+- MYSQL_ROW row;
+- int rc;
+-
+- /* Get the cached client character set name. */
+-
+- strcpy(character_set_name, mysql_character_set_name(con));
+-
+- /* Retrieve server character set information. */
+-
+- rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'");
+- check_mysql_rc(rc, con);
+-
+- rs= mysql_store_result(con);
+- FAIL_IF(!rs, "Invalid result set");
+- row= mysql_fetch_row(rs);
+- FAIL_IF(!row, "Couldn't fetch row");
+- strcpy(character_set_client, row[1]);
+- mysql_free_result(rs);
+-
+- rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");
+- check_mysql_rc(rc, con);
+- rs= mysql_store_result(con);
+- FAIL_IF(!rs, "Invalid result set");
+- row= mysql_fetch_row(rs);
+- FAIL_IF(!row, "Couldn't fetch row");
+- strcpy(character_set_results, row[1]);
+- mysql_free_result(rs);
+-
+- rc= mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'");
+- check_mysql_rc(rc, con);
+- rs= mysql_store_result(con);
+- FAIL_IF(!rs, "Invalid result set");
+- row= mysql_fetch_row(rs);
+- FAIL_IF(!row, "Couldn't fetch row");
+- strcpy(collation_connection, row[1]);
+- mysql_free_result(rs);
+- return OK;
+-}
+-
+-#define MY_CS_NAME_SIZE 32
+-
+-static int test_bug30472(MYSQL *mysql)
+-{
+- int rc;
+-
+- char character_set_name_1[MY_CS_NAME_SIZE];
+- char character_set_client_1[MY_CS_NAME_SIZE];
+- char character_set_results_1[MY_CS_NAME_SIZE];
+- char collation_connnection_1[MY_CS_NAME_SIZE];
+-
+- char character_set_name_2[MY_CS_NAME_SIZE];
+- char character_set_client_2[MY_CS_NAME_SIZE];
+- char character_set_results_2[MY_CS_NAME_SIZE];
+- char collation_connnection_2[MY_CS_NAME_SIZE];
+-
+- char character_set_name_3[MY_CS_NAME_SIZE];
+- char character_set_client_3[MY_CS_NAME_SIZE];
+- char character_set_results_3[MY_CS_NAME_SIZE];
+- char collation_connnection_3[MY_CS_NAME_SIZE];
+-
+- char character_set_name_4[MY_CS_NAME_SIZE];
+- char character_set_client_4[MY_CS_NAME_SIZE];
+- char character_set_results_4[MY_CS_NAME_SIZE];
+- char collation_connnection_4[MY_CS_NAME_SIZE];
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+- /* Retrieve character set information. */
+-
+- bug30472_retrieve_charset_info(mysql,
+- character_set_name_1,
+- character_set_client_1,
+- character_set_results_1,
+- collation_connnection_1);
+-
+- /* Switch client character set. */
+-
+- FAIL_IF(mysql_set_character_set(mysql, "utf8"), "Setting cs to utf8 failed");
+-
+- /* Retrieve character set information. */
+-
+- bug30472_retrieve_charset_info(mysql,
+- character_set_name_2,
+- character_set_client_2,
+- character_set_results_2,
+- collation_connnection_2);
+-
+- /*
+- Check that
+- 1) character set has been switched and
+- 2) new character set is different from the original one.
+- */
+-
+- FAIL_UNLESS(strcmp(character_set_name_2, "utf8") == 0, "cs_name != utf8");
+- FAIL_UNLESS(strcmp(character_set_client_2, "utf8") == 0, "cs_client != utf8");
+- FAIL_UNLESS(strcmp(character_set_results_2, "utf8") == 0, "cs_result != ut8");
+- FAIL_UNLESS(strcmp(collation_connnection_2, "utf8_general_ci") == 0, "collation != utf8_general_ci");
+-
+- FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0, "cs_name1 = cs_name2");
+- FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0, "cs_client1 = cs_client2");
+- FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0, "cs_result1 = cs_result2");
+- FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0, "collation1 = collation2");
+-
+- /* Call mysql_change_user() with the same username, password, database. */
+-
+- rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
+- check_mysql_rc(rc, mysql);
+-
+- /* Retrieve character set information. */
+-
+- bug30472_retrieve_charset_info(mysql,
+- character_set_name_3,
+- character_set_client_3,
+- character_set_results_3,
+- collation_connnection_3);
+-
+- /* Check that character set information has been reset. */
+-
+- FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0, "cs_name1 != cs_name3");
+- FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0, "cs_client1 != cs_client3");
+- FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0, "cs_result1 != cs_result3");
+- FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0, "collation1 != collation3");
+-
+- /* Change connection-default character set in the client. */
+-
+- mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
+-
+- /*
+- Call mysql_change_user() in order to check that new connection will
+- have UTF8 character set on the client and on the server.
+- */
+-
+- rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
+- check_mysql_rc(rc, mysql);
+-
+- /* Retrieve character set information. */
+-
+- bug30472_retrieve_charset_info(mysql,
+- character_set_name_4,
+- character_set_client_4,
+- character_set_results_4,
+- collation_connnection_4);
+-
+- /* Check that we have UTF8 on the server and on the client. */
+-
+- FAIL_UNLESS(strcmp(character_set_name_4, "utf8") == 0, "cs_name != utf8");
+- FAIL_UNLESS(strcmp(character_set_client_4, "utf8") == 0, "cs_client != utf8");
+- FAIL_UNLESS(strcmp(character_set_results_4, "utf8") == 0, "cs_result != utf8");
+- FAIL_UNLESS(strcmp(collation_connnection_4, "utf8_general_ci") == 0, "collation_connection != utf8_general_ci");
+-
+- /* That's it. Cleanup. */
+-
+- return OK;
+-}
+-
+-static int test_bug_54100(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- MYSQL_ROW row;
+- int rc;
+-
+- rc= mysql_query(mysql, "SHOW CHARACTER SET");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+-
+- while ((row= mysql_fetch_row(result)))
+- {
+- /* ignore ucs2 */
+- if (strcmp(row[0], "ucs2") && strcmp(row[0], "utf16le") && strcmp(row[0], "utf8mb4") &&
+- strcmp(row[0], "utf16") && strcmp(row[0], "utf32")) {
+- rc= mysql_set_character_set(mysql, row[0]);
+- check_mysql_rc(rc, mysql);
+- }
+- }
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"bug_8378: mysql_real_escape with gbk", bug_8378, TEST_CONNECTION_NEW, 0, opt_bug8378, NULL},
+- {"test_client_character_set", test_client_character_set, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"bug_10214: mysql_real_escape with NO_BACKSLASH_ESCAPES", bug_10214, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_escaping", test_escaping, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_conversion", test_conversion, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"bug_41785", bug_41785, TEST_CONNECTION_DEFAULT, 0, NULL, "not fixed yet"},
+- {"test_bug27876", test_bug27876, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug30472", test_bug30472, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_ps_i18n", test_ps_i18n, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug_54100", test_bug_54100, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {NULL, NULL, 0, 0, NULL, 0}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+- // get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/CMakeLists.txt mariadb-native-client.trunk/unittest/libmysql/CMakeLists.txt
+--- mariadb/unittest/libmysql/CMakeLists.txt 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+@@ -1,31 +0,0 @@
+-# Copyright (C) 2008 Sun Microsystems, Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; version 2 of the License.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-
+-ENABLE_TESTING()
+-
+-
+-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+- ${CMAKE_BINARY_DIR}/include
+- ${CMAKE_SOURCE_DIR}/unittest/mytap)
+-
+-SET(API_TESTS "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
+- "sp" "result" "connection" "misc" "ssl")
+-
+-FOREACH(API_TEST ${API_TESTS})
+- ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
+- TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient)
+- ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST})
+- SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120)
+-ENDFOREACH(API_TEST)
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/connection.c mariadb-native-client.trunk/unittest/libmysql/connection.c
+--- mariadb/unittest/libmysql/connection.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/connection.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,512 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-/**
+- Some basic tests of the client API.
+-*/
+-
+-#include "my_test.h"
+-
+-static int test_bug20023(MYSQL *mysql)
+-{
+- int sql_big_selects_orig;
+- int max_join_size_orig;
+-
+- int sql_big_selects_2;
+- int sql_big_selects_3;
+- int sql_big_selects_4;
+- int sql_big_selects_5;
+- int rc;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- /***********************************************************************
+- Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values.
+- ***********************************************************************/
+-
+- query_int_variable(mysql,
+- "@@session.sql_big_selects",
+- &sql_big_selects_orig);
+-
+- query_int_variable(mysql,
+- "@@global.max_join_size",
+- &max_join_size_orig);
+-
+- /***********************************************************************
+- Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value.
+- ***********************************************************************/
+-
+- /* Issue COM_CHANGE_USER. */
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- /* Query SQL_BIG_SELECTS. */
+-
+- query_int_variable(mysql,
+- "@@session.sql_big_selects",
+- &sql_big_selects_2);
+-
+- /* Check that SQL_BIG_SELECTS is reset properly. */
+-
+- FAIL_UNLESS(sql_big_selects_orig == sql_big_selects_2, "Different value for sql_big_select");
+-
+- /***********************************************************************
+- Test that if MAX_JOIN_SIZE set to non-default value,
+- SQL_BIG_SELECTS will be 0.
+- ***********************************************************************/
+-
+- /* Set MAX_JOIN_SIZE to some non-default value. */
+-
+- rc= mysql_query(mysql, "SET @@global.max_join_size = 10000");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "SET @@session.max_join_size = default");
+- check_mysql_rc(rc, mysql);
+-
+- /* Issue COM_CHANGE_USER. */
+-
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- /* Query SQL_BIG_SELECTS. */
+-
+- query_int_variable(mysql,
+- "@@session.sql_big_selects",
+- &sql_big_selects_3);
+-
+- /* Check that SQL_BIG_SELECTS is 0. */
+-
+- FAIL_UNLESS(sql_big_selects_3 == 0, "big_selects != 0");
+-
+- /***********************************************************************
+- Test that if MAX_JOIN_SIZE set to default value,
+- SQL_BIG_SELECTS will be 1.
+- ***********************************************************************/
+-
+- /* Set MAX_JOIN_SIZE to the default value (-1). */
+-
+- rc= mysql_query(mysql, "SET @@global.max_join_size = cast(-1 as unsigned int)");
+- rc= mysql_query(mysql, "SET @@session.max_join_size = default");
+-
+- /* Issue COM_CHANGE_USER. */
+-
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- /* Query SQL_BIG_SELECTS. */
+-
+- query_int_variable(mysql,
+- "@@session.sql_big_selects",
+- &sql_big_selects_4);
+-
+- /* Check that SQL_BIG_SELECTS is 1. */
+-
+- FAIL_UNLESS(sql_big_selects_4 == 1, "sql_big_select != 1");
+-
+- /***********************************************************************
+- Restore MAX_JOIN_SIZE.
+- Check that SQL_BIG_SELECTS will be the original one.
+- ***********************************************************************/
+-
+- rc= mysql_query(mysql, "SET @@global.max_join_size = cast(-1 as unsigned int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SET @@session.max_join_size = default");
+- check_mysql_rc(rc, mysql);
+-
+- /* Issue COM_CHANGE_USER. */
+-
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- /* Query SQL_BIG_SELECTS. */
+-
+- query_int_variable(mysql,
+- "@@session.sql_big_selects",
+- &sql_big_selects_5);
+-
+- /* Check that SQL_BIG_SELECTS is 1. */
+-
+- FAIL_UNLESS(sql_big_selects_5 == sql_big_selects_orig, "big_select != 1");
+-
+- /***********************************************************************
+- That's it. Cleanup.
+- ***********************************************************************/
+-
+- return OK;
+-}
+-
+-static int test_change_user(MYSQL *mysql)
+-{
+- char buff[256];
+- const char *user_pw= "mysqltest_pw";
+- const char *user_no_pw= "mysqltest_no_pw";
+- const char *pw= "password";
+- const char *db= "mysqltest_user_test_database";
+- int rc;
+-
+- DBUG_ENTER("test_change_user");
+-
+- /* Prepare environment */
+- sprintf(buff, "drop database if exists %s", db);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- sprintf(buff, "create database %s", db);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- sprintf(buff,
+- "grant select on %s.* to %s@'%%' identified by '%s'",
+- db,
+- user_pw,
+- pw);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- sprintf(buff,
+- "grant select on %s.* to %s@'%%'",
+- db,
+- user_no_pw);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+-
+- /* Try some combinations */
+- rc= mysql_change_user(mysql, NULL, NULL, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+-
+- rc= mysql_change_user(mysql, "", NULL, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", "", NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", "", "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, NULL, "", "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+-
+- rc= mysql_change_user(mysql, NULL, NULL, "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", NULL, "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, NULL, "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, "", "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, "", NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, NULL, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, "", db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, NULL, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_pw, pw, db);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_pw, pw, NULL);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_pw, pw, "");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_no_pw, pw, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_no_pw, pw, "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_no_pw, pw, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user_no_pw, "", NULL);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_no_pw, "", "");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_no_pw, "", db);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, user_no_pw, NULL, db);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_change_user(mysql, "", pw, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", pw, "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", pw, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, NULL, pw, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, NULL, NULL, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, NULL, "", db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", "", db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- /* Cleanup the environment */
+-
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- sprintf(buff, "drop database %s", db);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- sprintf(buff, "drop user %s@'%%'", user_pw);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- sprintf(buff, "drop user %s@'%%'", user_no_pw);
+- rc= mysql_query(mysql, buff);
+- check_mysql_rc(rc, mysql)
+-
+- return OK;
+-}
+-
+-/**
+- Bug#31669 Buffer overflow in mysql_change_user()
+-*/
+-
+-#define LARGE_BUFFER_SIZE 2048
+-
+-static int test_bug31669(MYSQL *mysql)
+-{
+- int rc;
+- static char buff[LARGE_BUFFER_SIZE+1];
+- static char user[USERNAME_CHAR_LENGTH+1];
+- static char db[NAME_CHAR_LEN+1];
+- static char query[LARGE_BUFFER_SIZE*2];
+-
+- rc= mysql_change_user(mysql, NULL, NULL, NULL);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, "", "", "");
+- FAIL_UNLESS(rc, "Error expected");
+-
+- memset(buff, 'a', sizeof(buff));
+-
+- rc= mysql_change_user(mysql, buff, buff, buff);
+- FAIL_UNLESS(rc, "Error epected");
+-
+- rc = mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- memset(db, 'a', sizeof(db));
+- db[NAME_CHAR_LEN]= 0;
+- sprintf(query, "CREATE DATABASE IF NOT EXISTS %s", db);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- memset(user, 'b', sizeof(user));
+- user[USERNAME_CHAR_LENGTH]= 0;
+- memset(buff, 'c', sizeof(buff));
+- buff[LARGE_BUFFER_SIZE]= 0;
+- sprintf(query, "GRANT ALL PRIVILEGES ON *.* TO '%s'@'%%' IDENTIFIED BY '%s' WITH GRANT OPTION", user, buff);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "FLUSH PRIVILEGES");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_change_user(mysql, user, buff, db);
+- check_mysql_rc(rc, mysql);
+-
+- user[USERNAME_CHAR_LENGTH-1]= 'a';
+- rc= mysql_change_user(mysql, user, buff, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- user[USERNAME_CHAR_LENGTH-1]= 'b';
+- buff[LARGE_BUFFER_SIZE-1]= 'd';
+- rc= mysql_change_user(mysql, user, buff, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- buff[LARGE_BUFFER_SIZE-1]= 'c';
+- db[NAME_CHAR_LEN-1]= 'e';
+- rc= mysql_change_user(mysql, user, buff, db);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- db[NAME_CHAR_LEN-1]= 'a';
+- rc= mysql_change_user(mysql, user, buff, db);
+- FAIL_UNLESS(!rc, "Error expected");
+-
+- rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- rc = mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- sprintf(query, "DROP DATABASE %s", db);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- sprintf(query, "DELETE FROM mysql.user WHERE User='%s'", user);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+- FAIL_UNLESS(mysql_affected_rows(mysql) == 1, "");
+-
+- return OK;
+-}
+-
+-/**
+- Bug# 33831 mysql_real_connect() should fail if
+- given an already connected MYSQL handle.
+-*/
+-
+-static int test_bug33831(MYSQL *mysql)
+-{
+- FAIL_IF(mysql_real_connect(mysql, hostname, username,
+- password, schema, port, socketname, 0),
+- "Error expected");
+-
+- return OK;
+-}
+-
+-/* Test MYSQL_OPT_RECONNECT, Bug#15719 */
+-
+-static int test_opt_reconnect(MYSQL *mysql)
+-{
+- my_bool my_true= TRUE;
+- int rc;
+-
+- mysql= mysql_init(NULL);
+- FAIL_IF(!mysql, "not enough memory");
+-
+- FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
+-
+- rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, &my_true);
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1");
+-
+- if (!(mysql_real_connect(mysql, hostname, username,
+- password, schema, port,
+- socketname, 0)))
+- {
+- diag("connection failed");
+- mysql_close(mysql);
+- return FAIL;
+- }
+-
+- FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1");
+-
+- mysql_close(mysql);
+-
+- mysql= mysql_init(NULL);
+- FAIL_IF(!mysql, "not enough memory");
+-
+- FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
+-
+- if (!(mysql_real_connect(mysql, hostname, username,
+- password, schema, port,
+- socketname, 0)))
+- {
+- diag("connection failed");
+- mysql_close(mysql);
+- return FAIL;
+- }
+-
+- FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0");
+-
+- mysql_close(mysql);
+- return OK;
+-}
+-
+-static int test_compress(MYSQL *mysql)
+-{
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- int rc;
+-
+- mysql= mysql_init(NULL);
+- FAIL_IF(!mysql, "not enough memory");
+-
+- /* use compressed protocol */
+- rc= mysql_options(mysql, MYSQL_OPT_COMPRESS, NULL);
+-
+-
+-
+- if (!(mysql_real_connect(mysql, hostname, username,
+- password, schema, port,
+- socketname, 0)))
+- {
+- diag("connection failed");
+- return FAIL;
+- }
+-
+- rc= mysql_query(mysql, "SHOW STATUS LIKE 'compression'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- row= mysql_fetch_row(res);
+- FAIL_UNLESS(strcmp(row[1], "ON") == 0, "Compression off");
+- mysql_free_result(res);
+-
+- mysql_close(mysql);
+- return OK;
+-}
+-
+-struct my_tests_st my_tests[] = {
+- {"test_bug20023", test_bug20023, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_bug31669", test_bug31669, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_bug33831", test_bug33831, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_change_user", test_change_user, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_opt_reconnect", test_opt_reconnect, TEST_CONNECTION_NONE, 0, NULL, NULL},
+- {"test_compress", test_compress, TEST_CONNECTION_NONE, 0, NULL, NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/cursor.c mariadb-native-client.trunk/unittest/libmysql/cursor.c
+--- mariadb/unittest/libmysql/cursor.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/cursor.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1842 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/* helper functions */
+-enum { MAX_COLUMN_LENGTH= 255 };
+-
+-typedef struct st_stmt_fetch
+-{
+- const char *query;
+- unsigned stmt_no;
+- MYSQL_STMT *handle;
+- my_bool is_open;
+- MYSQL_BIND *bind_array;
+- char **out_data;
+- unsigned long *out_data_length;
+- unsigned column_count;
+- unsigned row_count;
+-} Stmt_fetch;
+-
+-MYSQL_STMT *open_cursor(MYSQL *mysql, const char *query)
+-{
+- int rc;
+- const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
+-
+- MYSQL_STMT *stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- return stmt;
+-}
+-
+-/*
+- Create statement handle, prepare it with statement, execute and allocate
+- fetch buffers.
+-*/
+-
+-int stmt_fetch_init(MYSQL *mysql, Stmt_fetch *fetch, unsigned stmt_no_arg,
+- const char *query_arg)
+-{
+- unsigned long type= CURSOR_TYPE_READ_ONLY;
+- int rc;
+- unsigned i;
+- MYSQL_RES *metadata;
+- DBUG_ENTER("stmt_fetch_init");
+-
+- /* Save query and statement number for error messages */
+- fetch->stmt_no= stmt_no_arg;
+- fetch->query= query_arg;
+-
+- fetch->handle= mysql_stmt_init(mysql);
+-
+- rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
+- FAIL_IF(rc, mysql_stmt_error(fetch->handle));
+-
+- /*
+- The attribute is sent to server on execute and asks to open read-only
+- for result set
+- */
+- mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
+- (const void*) &type);
+-
+- rc= mysql_stmt_execute(fetch->handle);
+- FAIL_IF(rc, mysql_stmt_error(fetch->handle));
+-
+- /* Find out total number of columns in result set */
+- metadata= mysql_stmt_result_metadata(fetch->handle);
+- fetch->column_count= mysql_num_fields(metadata);
+- mysql_free_result(metadata);
+-
+- /*
+- Now allocate bind handles and buffers for output data:
+- calloc memory to reduce number of MYSQL_BIND members we need to
+- set up.
+- */
+-
+- fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
+- fetch->column_count);
+- fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
+- fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
+- fetch->column_count);
+- for (i= 0; i < fetch->column_count; ++i)
+- {
+- fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
+- fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
+- fetch->bind_array[i].buffer= fetch->out_data[i];
+- fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
+- fetch->bind_array[i].length= fetch->out_data_length + i;
+- }
+-
+- mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
+-
+- fetch->row_count= 0;
+- fetch->is_open= TRUE;
+-
+- /* Ready for reading rows */
+- return OK;
+-}
+-
+-
+-int fill_tables(MYSQL *mysql, const char **query_list, unsigned query_count)
+-{
+- int rc;
+- const char **query;
+- DBUG_ENTER("fill_tables");
+- for (query= query_list; query < query_list + query_count;
+- ++query)
+- {
+- rc= mysql_query(mysql, *query);
+- check_mysql_rc(rc, mysql);
+- }
+- return OK;
+-}
+-
+-int stmt_fetch_fetch_row(Stmt_fetch *fetch)
+-{
+- int rc;
+- unsigned i;
+-
+- if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
+- {
+- ++fetch->row_count;
+- for (i= 0; i < fetch->column_count; ++i)
+- {
+- fetch->out_data[i][fetch->out_data_length[i]]= '\0';
+- }
+- }
+- else
+- fetch->is_open= FALSE;
+-
+- return rc;
+-}
+-
+-void stmt_fetch_close(Stmt_fetch *fetch)
+-{
+- unsigned i;
+-
+- for (i= 0; i < fetch->column_count; ++i)
+- free(fetch->out_data[i]);
+- free(fetch->out_data);
+- free(fetch->out_data_length);
+- free(fetch->bind_array);
+- mysql_stmt_close(fetch->handle);
+-}
+-
+-
+-
+-enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
+-
+-int fetch_n(MYSQL *mysql, const char **query_list, unsigned query_count,
+- enum fetch_type fetch_type)
+-{
+- unsigned open_statements= query_count;
+- int rc, error_count= 0;
+- Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
+- query_count);
+- Stmt_fetch *fetch;
+- DBUG_ENTER("fetch_n");
+-
+- for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+- {
+- if (stmt_fetch_init(mysql, fetch, fetch - fetch_array,
+- query_list[fetch - fetch_array]))
+- return FAIL;
+- }
+-
+- if (fetch_type == USE_STORE_RESULT)
+- {
+- for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+- {
+- rc= mysql_stmt_store_result(fetch->handle);
+- FAIL_IF(rc, mysql_stmt_error(fetch->handle));
+- }
+- }
+-
+- while (open_statements)
+- {
+- for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+- {
+- if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
+- {
+- open_statements--;
+- /*
+- We try to fetch from the rest of the statements in case of
+- error
+- */
+- if (rc != MYSQL_NO_DATA)
+- error_count++;
+- }
+- }
+- }
+- if (!error_count)
+- {
+- unsigned total_row_count= 0;
+- for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+- total_row_count+= fetch->row_count;
+- }
+- for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+- stmt_fetch_close(fetch);
+- free(fetch_array);
+-
+- return (error_count) ? FAIL:OK;
+-}
+-
+-static int test_basic_cursors(MYSQL *mysql)
+-{
+- const char *basic_tables[]=
+- {
+- "DROP TABLE IF EXISTS t1, t2",
+-
+- "CREATE TABLE t1 "
+- "(id INTEGER NOT NULL PRIMARY KEY, "
+- " name VARCHAR(20) NOT NULL)",
+-
+- "INSERT INTO t1 (id, name) VALUES "
+- " (2, 'Ja'), (3, 'Ede'), "
+- " (4, 'Haag'), (5, 'Kabul'), "
+- " (6, 'Almere'), (7, 'Utrecht'), "
+- " (8, 'Qandahar'), (9, 'Amsterdam'), "
+- " (10, 'Amersfoort'), (11, 'Constantine')",
+-
+- "CREATE TABLE t2 "
+- "(id INTEGER NOT NULL PRIMARY KEY, "
+- " name VARCHAR(20) NOT NULL)",
+-
+- "INSERT INTO t2 (id, name) VALUES "
+- " (4, 'Guam'), (5, 'Aruba'), "
+- " (6, 'Angola'), (7, 'Albania'), "
+- " (8, 'Anguilla'), (9, 'Argentina'), "
+- " (10, 'Azerbaijan'), (11, 'Afghanistan'), "
+- " (12, 'Burkina Faso'), (13, 'Faroe Islands')"
+- };
+-
+- const char *queries[]=
+- {
+- "SELECT * FROM t1",
+- "SELECT * FROM t2"
+- };
+-
+-
+- FAIL_IF(fill_tables(mysql, basic_tables, sizeof(basic_tables)/sizeof(*basic_tables)), "fill_tables failed");
+-
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
+- return OK;
+-}
+-
+-
+-static int test_cursors_with_union(MYSQL *mysql)
+-{
+- const char *queries[]=
+- {
+- "SELECT t1.name FROM t1 UNION SELECT t2.name FROM t2",
+- "SELECT t1.id FROM t1 WHERE t1.id < 5"
+- };
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
+-
+- return OK;
+-}
+-
+-
+-static int test_cursors_with_procedure(MYSQL *mysql)
+-{
+- const char *queries[]=
+- {
+- "SELECT * FROM t1 procedure analyse()"
+- };
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed");
+- FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed");
+-
+- return OK;
+-}
+-
+-/*
+- Bug#21206: memory corruption when too many cursors are opened at once
+-
+- Memory corruption happens when more than 1024 cursors are open
+- simultaneously.
+-*/
+-static int test_bug21206(MYSQL *mysql)
+-{
+- int retcode= OK;
+-
+- const size_t cursor_count= 1025;
+-
+- const char *create_table[]=
+- {
+- "DROP TABLE IF EXISTS t1",
+- "CREATE TABLE t1 (i INT)",
+- "INSERT INTO t1 VALUES (1), (2), (3)"
+- };
+- const char *query= "SELECT * FROM t1";
+-
+- Stmt_fetch *fetch_array=
+- (Stmt_fetch*) calloc(cursor_count, sizeof(Stmt_fetch));
+-
+- Stmt_fetch *fetch;
+-
+- FAIL_IF(fill_tables(mysql, create_table, sizeof(create_table) / sizeof(*create_table)), "fill_tables failed");
+-
+- for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch)
+- {
+- if ((retcode= stmt_fetch_init(mysql, fetch, fetch - fetch_array, query)))
+- break;
+- }
+-
+- for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch)
+- stmt_fetch_close(fetch);
+-
+- free(fetch_array);
+-
+- return retcode;
+-}
+-
+-static int test_bug10729(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char a[21];
+- int rc;
+- const char *stmt_text;
+- int i= 0;
+- const char *name_array[3]= { "aaa", "bbb", "ccc" };
+- ulong type;
+-
+- mysql_query(mysql, "drop table if exists t1");
+- mysql_query(mysql, "create table t1 (id integer not null primary key,"
+- "name VARCHAR(20) NOT NULL)");
+- rc= mysql_query(mysql, "insert into t1 (id, name) values "
+- "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "select name from t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void*) a;
+- my_bind[0].buffer_length= sizeof(a);
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int row_no= 0;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while ((rc= mysql_stmt_fetch(stmt)) == 0)
+- {
+- FAIL_UNLESS(strcmp(a, name_array[row_no]) == 0, "a != name_array[row_no]");
+- ++row_no;
+- }
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- }
+- rc= mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#10736: cursors and subqueries, memroot management */
+-
+-static int test_bug10736(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char a[21];
+- int rc;
+- const char *stmt_text;
+- int i= 0;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
+- "name VARCHAR(20) NOT NULL)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 (id, name) values "
+- "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "select name from t1 where name=(select name from t1 where id=2)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void*) a;
+- my_bind[0].buffer_length= sizeof(a);
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int row_no= 0;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while ((rc= mysql_stmt_fetch(stmt)) == 0)
+- ++row_no;
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- }
+- rc= mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#10794: cursors, packets out of order */
+-
+-static int test_bug10794(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt, *stmt1;
+- MYSQL_BIND my_bind[2];
+- char a[21];
+- int id_val;
+- ulong a_len;
+- int rc;
+- const char *stmt_text;
+- int i= 0;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
+- "name varchar(20) not null)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "insert into t1 (id, name) values (?, ?)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void*) &id_val;
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void*) a;
+- my_bind[1].length= &a_len;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- for (i= 0; i < 42; i++)
+- {
+- id_val= (i+1)*10;
+- sprintf(a, "a%d", i);
+- a_len= strlen(a); /* safety against broken sprintf */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+- stmt_text= "select name from t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- stmt1= mysql_stmt_init(mysql);
+- mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void*) a;
+- my_bind[0].buffer_length= sizeof(a);
+- my_bind[0].length= &a_len;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- /* Don't optimize: an attribute of the original test case */
+- mysql_stmt_free_result(stmt);
+- mysql_stmt_reset(stmt);
+- stmt_text= "select name from t1 where id=10";
+- rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_stmt_bind_result(stmt1, my_bind);
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+- while (1)
+- {
+- rc= mysql_stmt_fetch(stmt1);
+- if (rc == MYSQL_NO_DATA)
+- {
+- break;
+- }
+- check_stmt_rc(rc, stmt1);
+- }
+- mysql_stmt_close(stmt);
+- mysql_stmt_close(stmt1);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#10760: cursors, crash in a fetch after rollback. */
+-
+-static int test_bug10760(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- int rc;
+- const char *stmt_text;
+- char id_buf[20];
+- ulong id_len;
+- int i= 0;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- /* create tables */
+- rc= mysql_query(mysql, "create table t1 (id integer not null primary key)"
+- " engine=MyISAM");
+- check_mysql_rc(rc, mysql);;
+- for (; i < 42; ++i)
+- {
+- char buf[100];
+- sprintf(buf, "insert into t1 (id) values (%d)", i+1);
+- rc= mysql_query(mysql, buf);
+- check_mysql_rc(rc, mysql);;
+- }
+- mysql_autocommit(mysql, FALSE);
+- /* create statement */
+- stmt= mysql_stmt_init(mysql);
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+-
+- /*
+- 1: check that a deadlock within the same connection
+- is resolved and an error is returned. The deadlock is modelled
+- as follows:
+- con1: open cursor for select * from t1;
+- con1: insert into t1 (id) values (1)
+- */
+- stmt_text= "select id from t1 order by 1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);;
+- rc= mysql_query(mysql, "update t1 set id=id+100");
+- /*
+- If cursors are not materialized, the update will return an error;
+- we mainly test that it won't deadlock.
+- */
+- /* FAIL_IF(!rc, "Error expected"); */
+- /*
+- 2: check that MyISAM tables used in cursors survive
+- COMMIT/ROLLBACK.
+- */
+- rc= mysql_rollback(mysql); /* should not close the cursor */
+- check_mysql_rc(rc, mysql);;
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);;
+-
+- /*
+- 3: check that cursors to InnoDB tables are closed (for now) by
+- COMMIT/ROLLBACK.
+- */
+- if (check_variable(mysql, "@@have_innodb", "YES"))
+- {
+- stmt_text= "select id from t1 order by 1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);;
+-
+- rc= mysql_query(mysql, "alter table t1 engine=InnoDB");
+- check_mysql_rc(rc, mysql);;
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void*) id_buf;
+- my_bind[0].buffer_length= sizeof(id_buf);
+- my_bind[0].length= &id_len;
+- check_stmt_rc(rc, stmt);;
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_execute(stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- rc= mysql_rollback(mysql); /* should close the cursor */
+- }
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_autocommit(mysql, TRUE); /* restore default */
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#11172: cursors, crash on a fetch from a datetime column */
+-
+-static int test_bug11172(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND bind_in[1], bind_out[2];
+- MYSQL_TIME hired;
+- int rc;
+- const char *stmt_text;
+- int i= 0, id;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (id integer not null primary key,"
+- "hired date not null)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "insert into t1 (id, hired) values (1, '1933-08-24'), "
+- "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), "
+- "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')");
+- check_mysql_rc(rc, mysql);
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- stmt_text= "SELECT id, hired FROM t1 WHERE hired=?";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+-
+- memset(bind_in, '\0', sizeof(bind_in));
+- memset(bind_out, '\0', sizeof(bind_out));
+- memset(&hired, '\0', sizeof(hired));
+- hired.year= 1965;
+- hired.month= 1;
+- hired.day= 1;
+- bind_in[0].buffer_type= MYSQL_TYPE_DATE;
+- bind_in[0].buffer= (void*) &hired;
+- bind_in[0].buffer_length= sizeof(hired);
+- bind_out[0].buffer_type= MYSQL_TYPE_LONG;
+- bind_out[0].buffer= (void*) &id;
+- bind_out[1]= bind_in[0];
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_bind_param(stmt, bind_in);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_result(stmt, bind_out);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while ((rc= mysql_stmt_fetch(stmt)) == 0);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- if (!mysql_stmt_free_result(stmt))
+- mysql_stmt_reset(stmt);
+- }
+- mysql_stmt_close(stmt);
+- mysql_rollback(mysql);
+- mysql_rollback(mysql);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#11656: cursors, crash on a fetch from a query with distinct. */
+-
+-static int test_bug11656(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- int rc;
+- const char *stmt_text;
+- char buf[2][20];
+- int i= 0;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 ("
+- "server varchar(40) not null, "
+- "test_kind varchar(1) not null, "
+- "test_id varchar(30) not null , "
+- "primary key (server,test_kind,test_id))");
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "select distinct test_kind, test_id from t1 "
+- "where server in (?, ?)";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- strcpy(buf[0], "pcint502_MY2");
+- strcpy(buf[1], "*");
+- for (i=0; i < 2; i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[i].buffer= (uchar* *)&buf[i];
+- my_bind[i].buffer_length= strlen(buf[i]);
+- }
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Cursors: opening a cursor to a compilicated query with ORDER BY */
+-
+-static int test_bug11901(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- int rc;
+- char workdept[20];
+- ulong workdept_len;
+- uint32 empno;
+- const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
+- const char *stmt_text;
+-
+-
+- stmt_text= "drop table if exists t1, t2";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "create table t1 ("
+- " empno int(11) not null, firstname varchar(20) not null,"
+- " midinit varchar(20) not null, lastname varchar(20) not null,"
+- " workdept varchar(6) not null, salary double not null,"
+- " bonus float not null, primary key (empno), "
+- " unique key (workdept, empno) "
+- ") default charset=latin1 collate=latin1_bin";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "insert into t1 values "
+- "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000),"
+- "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), "
+- "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), "
+- "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
+- "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), "
+- "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), "
+- "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), "
+- "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), "
+- "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), "
+- "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), "
+- "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), "
+- "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), "
+- "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), "
+- "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), "
+- "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), "
+- "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), "
+- "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), "
+- "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), "
+- "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), "
+- "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), "
+- "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), "
+- "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), "
+- "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), "
+- "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), "
+- "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), "
+- "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), "
+- "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), "
+- "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), "
+- "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), "
+- "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), "
+- "(330, 'WING', '', 'LEE', 'E21', 25370, 500), "
+- "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)";
+-
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "create table t2 ("
+- " deptno varchar(6) not null, deptname varchar(20) not null,"
+- " mgrno int(11) not null, location varchar(20) not null,"
+- " admrdept varchar(6) not null, refcntd int(11) not null,"
+- " refcntu int(11) not null, primary key (deptno)"
+- ") default charset=latin1 collate=latin1_bin";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "insert into t2 values "
+- "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), "
+- "('B01', 'PLANNING', 20, '', 'A00', 0, 0), "
+- "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), "
+- "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0),"
+- "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), "
+- "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), "
+- "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), "
+- "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), "
+- "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "select t1.empno, t1.workdept "
+- "from (t1 left join t2 on t2.deptno = t1.workdept) "
+- "where t2.deptno in "
+- " (select t2.deptno "
+- " from (t1 left join t2 on t2.deptno = t1.workdept) "
+- " where t1.empno = ?) "
+- "order by 1";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- check_stmt_rc(rc, stmt);
+-
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= &empno;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[1].buffer= (void*) workdept;
+- my_bind[1].buffer_length= sizeof(workdept);
+- my_bind[1].length= &workdept_len;
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- empno= 10;
+-
+- /* ERROR: next statement causes a server crash */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#11904: mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY grouping wrong result */
+-
+-static int test_bug11904(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt1;
+- int rc;
+- const char *stmt_text;
+- const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
+- MYSQL_BIND my_bind[2];
+- int country_id=0;
+- char row_data[11]= {0};
+-
+- /* create tables */
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug11904b");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE bug11904b (id int, name char(10), primary key(id, name))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO bug11904b VALUES (1, 'sofia'), (1,'plovdiv'),"
+- " (1,'varna'), (2,'LA'), (2,'new york'), (3,'heidelberg'),"
+- " (3,'berlin'), (3, 'frankfurt')");
+-
+- check_mysql_rc(rc, mysql);
+- mysql_commit(mysql);
+- /* create statement */
+- stmt1= mysql_stmt_init(mysql);
+- mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+-
+- stmt_text= "SELECT id, MIN(name) FROM bug11904b GROUP BY id ORDER BY id";
+-
+- rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt1);
+-
+- memset(my_bind, 0, sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer=& country_id;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].length= 0;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer=& row_data;
+- my_bind[1].buffer_length= sizeof(row_data) - 1;
+- my_bind[1].length= 0;
+-
+- rc= mysql_stmt_bind_result(stmt1, my_bind);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+- FAIL_UNLESS(country_id == 1, "country_id != 1");
+- FAIL_UNLESS(memcmp(row_data, "plovdiv", 7) == 0, "row_data != 'plovdiv'");
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+- FAIL_UNLESS(country_id == 2, "country_id != 2");
+- FAIL_UNLESS(memcmp(row_data, "LA", 2) == 0, "row_data != 'LA'");
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+- FAIL_UNLESS(country_id == 3, "country_id != 3");
+- FAIL_UNLESS(memcmp(row_data, "berlin", 6) == 0, "row_data != 'Berlin'");
+-
+- rc= mysql_stmt_close(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_query(mysql, "drop table bug11904b");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-/* Bug#12243: multiple cursors, crash in a fetch after commit. */
+-
+-static int test_bug12243(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt1, *stmt2;
+- int rc;
+- const char *stmt_text;
+- ulong type;
+-
+- if (!check_variable(mysql, "@@have_innodb", "YES"))
+- {
+- diag("Skip -> Test required InnoDB");
+- return SKIP;
+- }
+-
+- /* create tables */
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (a int) engine=InnoDB");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)");
+- check_mysql_rc(rc, mysql);
+- mysql_autocommit(mysql, FALSE);
+- /* create statement */
+- stmt1= mysql_stmt_init(mysql);
+- stmt2= mysql_stmt_init(mysql);
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- check_stmt_rc(rc, stmt1);
+-
+- stmt_text= "select a from t1";
+-
+- rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt2);
+- rc= mysql_stmt_execute(stmt2);
+- check_stmt_rc(rc, stmt2);
+- rc= mysql_stmt_fetch(stmt2);
+- check_stmt_rc(rc, stmt2);
+-
+- rc= mysql_stmt_close(stmt1);
+- check_stmt_rc(rc, stmt1);
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+- rc= mysql_stmt_fetch(stmt2);
+- check_stmt_rc(rc, stmt2);
+-
+- mysql_stmt_close(stmt2);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- mysql_autocommit(mysql, TRUE); /* restore default */
+-
+- return OK;
+-}
+-
+-/* Bug#11909: wrong metadata if fetching from two cursors */
+-
+-static int test_bug11909(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt1, *stmt2;
+- MYSQL_BIND my_bind[7];
+- int rc;
+- char firstname[20], midinit[20], lastname[20], workdept[20];
+- ulong firstname_len, midinit_len, lastname_len, workdept_len;
+- uint32 empno;
+- double salary;
+- float bonus;
+- const char *stmt_text;
+- const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
+-
+-
+- stmt_text= "drop table if exists t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "create table t1 ("
+- " empno int(11) not null, firstname varchar(20) not null,"
+- " midinit varchar(20) not null, lastname varchar(20) not null,"
+- " workdept varchar(6) not null, salary double not null,"
+- " bonus float not null, primary key (empno)"
+- ") default charset=latin1 collate=latin1_bin";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "insert into t1 values "
+- "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), "
+- "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800),"
+- "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800),"
+- "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
+- "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- /* ****** Begin of trace ****** */
+-
+- stmt_text= "SELECT empno, firstname, midinit, lastname,"
+- "workdept, salary, bonus FROM t1 ORDER BY empno";
+- stmt1= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt1, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt1);
+- mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE,
+- (const void*) &type);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void*) &empno;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[1].buffer= (void*) firstname;
+- my_bind[1].buffer_length= sizeof(firstname);
+- my_bind[1].length= &firstname_len;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[2].buffer= (void*) midinit;
+- my_bind[2].buffer_length= sizeof(midinit);
+- my_bind[2].length= &midinit_len;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[3].buffer= (void*) lastname;
+- my_bind[3].buffer_length= sizeof(lastname);
+- my_bind[3].length= &lastname_len;
+-
+- my_bind[4].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[4].buffer= (void*) workdept;
+- my_bind[4].buffer_length= sizeof(workdept);
+- my_bind[4].length= &workdept_len;
+-
+- my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[5].buffer= (void*) &salary;
+-
+- my_bind[6].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[6].buffer= (void*) &bonus;
+- rc= mysql_stmt_bind_result(stmt1, my_bind);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- FAIL_UNLESS(empno == 10, "empno != 10");
+- FAIL_UNLESS(strcmp(firstname, "CHRISTINE""") == 0, "firstname != 'Christine'");
+- FAIL_UNLESS(strcmp(midinit, "I""") == 0, "");
+- FAIL_UNLESS(strcmp(lastname, "HAAS""") == 0, "lastname != 'HAAS'");
+- FAIL_UNLESS(strcmp(workdept, "A00""") == 0, "workdept != 'A00'");
+- FAIL_UNLESS(salary == (double) 52750.0, "salary != 52750");
+- FAIL_UNLESS(bonus == (float) 1000.0, "bonus =! 1000");
+-
+- stmt_text = "SELECT empno, firstname FROM t1";
+- stmt2= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt2, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt2);
+- mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE,
+- (const void*) &type);
+- rc= mysql_stmt_bind_result(stmt2, my_bind);
+- check_stmt_rc(rc, stmt2);
+-
+- rc= mysql_stmt_execute(stmt2);
+- check_stmt_rc(rc, stmt2);
+-
+- rc= mysql_stmt_fetch(stmt2);
+- FAIL_UNLESS(rc == 0, "rc != 0")
+-
+- FAIL_UNLESS(empno == 10, "empno != 10");
+- FAIL_UNLESS(strcmp(firstname, "CHRISTINE""") == 0, "firstname != 'Christine'");
+-
+- rc= mysql_stmt_reset(stmt2);
+- check_stmt_rc(rc, stmt2);
+-
+- /* ERROR: next statement should return 0 */
+-
+- rc= mysql_stmt_fetch(stmt1);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+-
+- mysql_stmt_close(stmt1);
+- mysql_stmt_close(stmt2);
+- rc= mysql_rollback(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#13488: wrong column metadata when fetching from cursor */
+-
+-static int test_bug13488(MYSQL *mysql)
+-{
+- MYSQL_BIND my_bind[3];
+- MYSQL_STMT *stmt1;
+- int rc, f1, f2, f3, i;
+- const ulong type= CURSOR_TYPE_READ_ONLY;
+- const char *query= "select f1, f2, f3 from t1 left join t2 on f1=f2 where f1=1";
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1, t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (f1 int not null primary key)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t2 (f2 int not null primary key, "
+- "f3 int not null)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1), (2)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (1,2), (2,4)");
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, 0, sizeof(my_bind));
+- for (i= 0; i < 3; i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[i].buffer_length= 4;
+- my_bind[i].length= 0;
+- }
+- my_bind[0].buffer=&f1;
+- my_bind[1].buffer=&f2;
+- my_bind[2].buffer=&f3;
+-
+- stmt1= mysql_stmt_init(mysql);
+- rc= mysql_stmt_attr_set(stmt1,STMT_ATTR_CURSOR_TYPE, (const void *)&type);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_prepare(stmt1, query, strlen(query));
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_bind_result(stmt1, my_bind);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_free_result(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_reset(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_close(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_UNLESS(f1 == 1, "f1 != 1");
+- FAIL_UNLESS(f2 == 1, "f2 != 1");
+- FAIL_UNLESS(f3 == 2, "f3 != 2");
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#13524: warnings of a previous command are not reset when fetching
+- from a cursor.
+-*/
+-
+-static int test_bug13524(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- unsigned int warning_count;
+- const ulong type= CURSOR_TYPE_READ_ONLY;
+- const char *query= "select * from t1";
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1, t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (a int not null primary key)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- warning_count= mysql_warning_count(mysql);
+- FAIL_UNLESS(warning_count == 0, "warning_count != 0");
+-
+- /* Check that DROP TABLE produced a warning (no such table) */
+- rc= mysql_query(mysql, "drop table if exists t2");
+- check_mysql_rc(rc, mysql);
+- warning_count= mysql_warning_count(mysql);
+- FAIL_UNLESS(warning_count == 1, "warning_count != 1");
+-
+- /*
+- Check that fetch from a cursor cleared the warning from the previous
+- command.
+- */
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- warning_count= mysql_warning_count(mysql);
+- FAIL_UNLESS(warning_count == 0, "warning_count != 0");
+-
+- /* Cleanup */
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0"
+-*/
+-
+-static int test_bug14845(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const ulong type= CURSOR_TYPE_READ_ONLY;
+- const char *query= "select count(*) from t1 where 1 = 0";
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (id int(11) default null, "
+- "name varchar(20) default null)"
+- "engine=MyISAM DEFAULT CHARSET=utf8");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1,'abc'),(2,'def')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
+-
+- /* Cleanup */
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/*
+- Bug#14210 "Simple query with > operator on large table gives server
+- crash"
+-*/
+-
+-static int test_bug14210(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *stmt_text;
+- ulong type;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- /*
+- To trigger the problem the table must be InnoDB, although the problem
+- itself is not InnoDB related. In case the table is MyISAM this test
+- is harmless.
+- */
+- rc= mysql_query(mysql, "create table t1 (a varchar(255)) engine=InnoDB");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 (a) values (repeat('a', 256))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "set @@session.max_heap_table_size=16384");
+-
+- /* Create a big enough table (more than max_heap_table_size) */
+- for (i= 0; i < 8; i++)
+- {
+- rc= mysql_query(mysql, "insert into t1 (a) select a from t1");
+- check_mysql_rc(rc, mysql);
+- }
+- /* create statement */
+- stmt= mysql_stmt_init(mysql);
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+-
+- stmt_text= "select a from t1";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- while ((rc= mysql_stmt_fetch(stmt)) == 0);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "set @@session.max_heap_table_size=default");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#24179 "select b into $var" fails with --cursor_protocol"
+- The failure is correct, check that the returned message is meaningful.
+-*/
+-
+-static int test_bug24179(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+-
+- stmt= open_cursor(mysql, "select 1 into @a");
+- rc= mysql_stmt_execute(stmt);
+- FAIL_UNLESS(rc, "Error expected");
+- FAIL_UNLESS(mysql_stmt_errno(stmt) == 1323, "stmt_errno != 1323");
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/**
+- Bug#32265 Server returns different metadata if prepared statement is used
+-*/
+-
+-static int test_bug32265(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- MYSQL_FIELD *field;
+- MYSQL_RES *metadata;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1");
+- rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= open_cursor(mysql, "SELECT * FROM t1");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_field(metadata);
+- FAIL_UNLESS(field, "couldn't fetch field");
+- FAIL_UNLESS(strcmp(field->table, "t1") == 0, "table != t1");
+- FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
+- FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
+- mysql_free_result(metadata);
+- mysql_stmt_close(stmt);
+-
+- stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_field(metadata);
+- FAIL_UNLESS(strcmp(field->table, "") == 0, "field != ''");
+- FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
+- FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
+- mysql_free_result(metadata);
+- mysql_stmt_close(stmt);
+-
+- stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_field(metadata);
+- FAIL_UNLESS(strcmp(field->table, "") == 0, "table != ''");
+- FAIL_UNLESS(strcmp(field->org_table, "t1") == 0, "org_table != t1");
+- FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
+- mysql_free_result(metadata);
+- mysql_stmt_close(stmt);
+-
+- stmt= open_cursor(mysql, "SELECT * FROM v1");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_field(metadata);
+- FAIL_UNLESS(strcmp(field->table, "v1") == 0, "table != v1");
+- FAIL_UNLESS(strcmp(field->org_table, "v1") == 0, "org_table != v1");
+- FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema");
+- mysql_free_result(metadata);
+- mysql_stmt_close(stmt);
+-
+- stmt= open_cursor(mysql, "SELECT * FROM v1 /* SIC */ GROUP BY 1");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_field(metadata);
+- FAIL_UNLESS(strcmp(field->table, "v1") == 0, "table != v1");
+- FAIL_UNLESS(strcmp(field->org_table, "v1") == 0, "org_table != v1");
+- FAIL_UNLESS(strcmp(field->db, schema) == 0, "schema != db");
+- mysql_free_result(metadata);
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/**
+- Bug#38486 Crash when using cursor protocol
+-*/
+-
+-static int test_bug38486(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- int rc;
+- unsigned long type= CURSOR_TYPE_READ_ONLY;
+-
+- DBUG_ENTER("test_bug38486");
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "CREATE TABLE t1 (a INT)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "INSERT INTO t1 VALUES (1)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug8880(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt_list[2], **stmt;
+- MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2;
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1,1)");
+- check_mysql_rc(rc, mysql);
+- /*
+- when inserting 2 rows everything works well
+- mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)");
+- */
+- for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+- *stmt= open_cursor(mysql, "select a from t1");
+- for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+- {
+- rc= mysql_stmt_execute(*stmt);
+- check_stmt_rc(rc, *stmt);
+- }
+- for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+- mysql_stmt_close(*stmt);
+- return OK;
+-}
+-
+-static int test_bug9159(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *stmt_text= "select a, b from t1";
+- const unsigned long type= CURSOR_TYPE_READ_ONLY;
+-
+-
+- mysql_query(mysql, "drop table if exists t1");
+- mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
+- rc= mysql_query(mysql, "insert into t1 values (1,1)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type);
+-
+- mysql_stmt_execute(stmt);
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/*
+- We can't have more than one cursor open for a prepared statement.
+- Test re-executions of a PS with cursor; mysql_stmt_reset must close
+- the cursor attached to the statement, if there is one.
+-*/
+-
+-static int test_bug9478(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char a[6];
+- ulong a_len;
+- int rc, i;
+- DBUG_ENTER("test_bug9478");
+-
+- mysql_query(mysql, "drop table if exists t1");
+- mysql_query(mysql, "create table t1 (id integer not null primary key, "
+- " name varchar(20) not null)");
+- rc= mysql_query(mysql, "insert into t1 (id, name) values "
+- " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= open_cursor(mysql, "select name from t1 where id=2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (char*) a;
+- my_bind[0].buffer_length= sizeof(a);
+- my_bind[0].length= &a_len;
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- for (i= 0; i < 5; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- The query above is a one-row result set. Therefore, there is no
+- cursor associated with it, as the server won't bother with opening
+- a cursor for a one-row result set. The first row was read from the
+- server in the fetch above. But there is eof packet pending in the
+- network. mysql_stmt_execute will flush the packet and successfully
+- execute the statement.
+- */
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- {
+- char buff[8];
+- /* Fill in the fetch packet */
+- int4store(buff, stmt->stmt_id);
+- buff[4]= 1; /* prefetch rows */
+-/* rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
+- (uchar*) buff,
+- sizeof(buff), 0,0,1,NULL) ||
+- (*mysql->methods->read_query_result)(mysql)); */
+- FAIL_UNLESS(rc, "error expected");
+- }
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_reset(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
+- }
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* Test the case with a server side cursor */
+- stmt= open_cursor(mysql, "select name from t1");
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- for (i= 0; i < 5; i++)
+- {
+- DBUG_PRINT("loop",("i: %d", i));
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- while (! (rc= mysql_stmt_fetch(stmt)));
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_reset(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
+- }
+-
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Crash when opening a cursor to a query with DISTICNT and no key */
+-
+-static int test_bug9520(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char a[6];
+- ulong a_len;
+- int rc, row_count= 0;
+-
+-
+- mysql_query(mysql, "drop table if exists t1");
+- mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5),"
+- " primary key (a, b, c))");
+- rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), "
+- " ('a', 'b', 'c'), ('k', 'l', 'm')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= open_cursor(mysql, "select distinct b from t1");
+-
+- /*
+- Not crashes with:
+- stmt= open_cursor(mysql, "select distinct a from t1");
+- */
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (char*) a;
+- my_bind[0].buffer_length= sizeof(a);
+- my_bind[0].length= &a_len;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- while (!(rc= mysql_stmt_fetch(stmt)))
+- row_count++;
+-
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- FAIL_UNLESS(row_count == 3, "row_count != 3");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/*
+- Error message is returned for unsupported features.
+- Test also cursors with non-default PREFETCH_ROWS
+-*/
+-
+-static int test_bug9643(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- int32 a;
+- int rc;
+- const char *stmt_text;
+- int num_rows= 0;
+- ulong type;
+- ulong prefetch_rows= 5;
+-
+-
+- mysql_query(mysql, "drop table if exists t1");
+- mysql_query(mysql, "create table t1 (id integer not null primary key)");
+- rc= mysql_query(mysql, "insert into t1 (id) values "
+- " (1), (2), (3), (4), (5), (6), (7), (8), (9)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- /* Not implemented in 5.0 */
+- type= (ulong) CURSOR_TYPE_SCROLLABLE;
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- type= (ulong) CURSOR_TYPE_READ_ONLY;
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS,
+- (void*) &prefetch_rows);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "select * from t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void*) &a;
+- my_bind[0].buffer_length= sizeof(a);
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- while ((rc= mysql_stmt_fetch(stmt)) == 0)
+- ++num_rows;
+- FAIL_UNLESS(num_rows == 9, "num_rows != 9");
+-
+- rc= mysql_stmt_close(stmt);
+- FAIL_UNLESS(rc == 0, "");
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_basic_cursors", test_basic_cursors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_cursors_with_union", test_cursors_with_union, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_cursors_with_procedure", test_cursors_with_procedure, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug21206", test_bug21206, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug10729", test_bug10729, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug10736", test_bug10736, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug10794", test_bug10794, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug10760", test_bug10760, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11172", test_bug11172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11656", test_bug11656, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11901", test_bug11901, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11904", test_bug11904, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug12243", test_bug12243, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11909", test_bug11909, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug13488", test_bug13488, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug13524", test_bug13524, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug14845", test_bug14845, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug14210", test_bug14210, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug24179", test_bug24179, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug32265", test_bug32265, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug38486", test_bug38486, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug8880", test_bug8880, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug9159", test_bug9159, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug9478", test_bug9478, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug9520", test_bug9520, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug9643", test_bug9643, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/data.csv mariadb-native-client.trunk/unittest/libmysql/data.csv
+--- mariadb/unittest/libmysql/data.csv 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/unittest/libmysql/data.csv 1970-01-01 01:00:00.000000000 +0100
+@@ -1,100 +0,0 @@
+-00000100,1,60000.000000
+-00000101,2,60000.000000
+-00000102,3,60000.000000
+-00000103,1,60000.000000
+-00000104,2,60000.000000
+-00000105,3,60000.000000
+-00000106,1,60000.000000
+-00000107,2,60000.000000
+-00000108,3,60000.000000
+-00000109,1,60000.000000
+-00000110,2,60000.000000
+-00000111,3,60000.000000
+-00000112,1,60000.000000
+-00000113,2,60000.000000
+-00000114,3,60000.000000
+-00000115,1,60000.000000
+-00000116,2,60000.000000
+-00000117,3,60000.000000
+-00000118,1,60000.000000
+-00000119,2,60000.000000
+-00000120,3,60000.000000
+-00000121,1,60000.000000
+-00000122,2,60000.000000
+-00000123,3,60000.000000
+-00000124,1,60000.000000
+-00000125,2,60000.000000
+-00000126,3,60000.000000
+-00000127,1,60000.000000
+-00000128,2,60000.000000
+-00000129,3,60000.000000
+-00000130,1,60000.000000
+-00000131,2,60000.000000
+-00000132,3,60000.000000
+-00000133,1,60000.000000
+-00000134,2,60000.000000
+-00000135,3,60000.000000
+-00000136,1,60000.000000
+-00000137,2,60000.000000
+-00000138,3,60000.000000
+-00000139,1,60000.000000
+-00000140,2,60000.000000
+-00000141,3,60000.000000
+-00000142,1,60000.000000
+-00000143,2,60000.000000
+-00000144,3,60000.000000
+-00000145,1,60000.000000
+-00000146,2,60000.000000
+-00000147,3,60000.000000
+-00000148,1,60000.000000
+-00000149,2,60000.000000
+-00000150,3,60000.000000
+-00000151,1,60000.000000
+-00000152,2,60000.000000
+-00000153,3,60000.000000
+-00000154,1,60000.000000
+-00000155,2,60000.000000
+-00000156,3,60000.000000
+-00000157,1,60000.000000
+-00000158,2,60000.000000
+-00000159,3,60000.000000
+-00000160,1,60000.000000
+-00000161,2,60000.000000
+-00000162,3,60000.000000
+-00000163,1,60000.000000
+-00000164,2,60000.000000
+-00000165,3,60000.000000
+-00000166,1,60000.000000
+-00000167,2,60000.000000
+-00000168,3,60000.000000
+-00000169,1,60000.000000
+-00000170,2,60000.000000
+-00000171,3,60000.000000
+-00000172,1,60000.000000
+-00000173,2,60000.000000
+-00000174,3,60000.000000
+-00000175,1,60000.000000
+-00000176,2,60000.000000
+-00000177,3,60000.000000
+-00000178,1,60000.000000
+-00000179,2,60000.000000
+-00000180,3,60000.000000
+-00000181,1,60000.000000
+-00000182,2,60000.000000
+-00000183,3,60000.000000
+-00000184,1,60000.000000
+-00000185,2,60000.000000
+-00000186,3,60000.000000
+-00000187,1,60000.000000
+-00000188,2,60000.000000
+-00000189,3,60000.000000
+-00000190,1,60000.000000
+-00000191,2,60000.000000
+-00000192,3,60000.000000
+-00000193,1,60000.000000
+-00000194,2,60000.000000
+-00000195,3,60000.000000
+-00000196,1,60000.000000
+-00000197,2,60000.000000
+-00000198,3,60000.000000
+-00000199,1,60000.000000
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/errors.c mariadb-native-client.trunk/unittest/libmysql/errors.c
+--- mariadb/unittest/libmysql/errors.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/errors.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,282 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/* Test warnings */
+-
+-static int test_client_warnings(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
+-
+- return OK;
+-}
+-
+-
+-static int test_ps_client_warnings(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- char *query= "DROP TABLE IF EXISTS test_non_exists";
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(rc, mysql_stmt_error(stmt));
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(rc, mysql_stmt_error(stmt));
+-
+- FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_server_warnings(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SHOW WARNINGS");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, mysql_error(mysql));
+- FAIL_IF(!mysql_num_rows(result), "Empty resultset");
+-
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-/* Test errors */
+-
+-static int test_client_errors(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_non_exists");
+- FAIL_IF(!rc, "Error expected");
+-
+- FAIL_IF(!mysql_errno(mysql), "Error expected");
+- FAIL_IF(!strlen(mysql_error(mysql)), "Empty errormsg");
+- FAIL_IF(strcmp(mysql_sqlstate(mysql), "00000") == 0, "Invalid SQLstate");
+-
+- return OK;
+-}
+-
+-static int test_ps_client_errors(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- char *query= "DROP TABLE test_non_exists";
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(rc, mysql_stmt_error(stmt));
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, mysql_stmt_error(stmt));
+-
+- FAIL_IF(!mysql_stmt_errno(stmt), "Error expected");
+- FAIL_IF(!strlen(mysql_stmt_error(stmt)), "Empty errormsg");
+- FAIL_IF(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Invalid SQLstate");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_server_errors(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+- rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_non_exists");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SHOW ERRORS");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, mysql_error(mysql));
+- FAIL_IF(!mysql_num_rows(result), "Empty resultset");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-/* Bug #16143: mysql_stmt_sqlstate returns an empty string instead of '00000' */
+-
+-static int test_bug16143(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- /* Check mysql_stmt_sqlstate return "no error" */
+- FAIL_UNLESS(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Expected SQLstate 000000");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/* Test warnings for cuted rows */
+-
+-static int test_cuted_rows(MYSQL *mysql)
+-{
+- int rc, count;
+- MYSQL_RES *result;
+-
+-
+- mysql_query(mysql, "DROP TABLE if exists t1");
+- mysql_query(mysql, "DROP TABLE if exists t2");
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1(c1 tinyint)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t2(c1 int not null)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO t1 values(10), (NULL), (NULL)");
+- check_mysql_rc(rc, mysql);
+-
+- count= mysql_warning_count(mysql);
+- FAIL_UNLESS(count == 0, "warnings != 0");
+-
+- rc= mysql_query(mysql, "INSERT INTO t2 SELECT * FROM t1");
+- check_mysql_rc(rc, mysql);
+-
+- count= mysql_warning_count(mysql);
+- FAIL_UNLESS(count == 2, "warnings != 2");
+-
+- rc= mysql_query(mysql, "SHOW WARNINGS");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 2, "rowcount != 2");
+- mysql_free_result(result);
+-
+- rc= mysql_query(mysql, "INSERT INTO t1 VALUES('junk'), (876789)");
+- check_mysql_rc(rc, mysql);
+-
+- count= mysql_warning_count(mysql);
+- FAIL_UNLESS(count == 2, "warnings != 2");
+-
+- rc= mysql_query(mysql, "SHOW WARNINGS");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 2, "rowcount != 2");
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-static int test_parse_error_and_bad_length(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+-
+- /* check that we get 4 syntax errors over the 4 calls */
+-
+- rc= mysql_query(mysql, "SHOW DATABAAAA");
+- FAIL_UNLESS(rc, "Error expected");
+- rc= mysql_real_query(mysql, "SHOW DATABASES", 100);
+- FAIL_UNLESS(rc, "Error expected");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SHOW DATABAAAA", strlen("SHOW DATABAAAA"));
+- FAIL_IF(!rc, "Error expected");
+- mysql_stmt_close(stmt);
+- stmt= mysql_stmt_init(mysql);
+- FAIL_UNLESS(stmt, "");
+- rc= mysql_stmt_prepare(stmt, "SHOW DATABASES", 100);
+- FAIL_IF(!rc, "Error expected");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_client_warnings", test_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ps_client_warnings", test_ps_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_server_warnings", test_server_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_client_errors", test_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ps_client_errors", test_ps_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_server_errors", test_server_errors, TEST_CONNECTION_DEFAULT, 0, NULL , "Open bug: #42364"},
+- {"test_bug16143", test_bug16143, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_cuted_rows", test_cuted_rows, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_parse_error_and_bad_length", test_parse_error_and_bad_length, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/fetch.c mariadb-native-client.trunk/unittest/libmysql/fetch.c
+--- mariadb/unittest/libmysql/fetch.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/fetch.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,904 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/* Generalized fetch conversion routine for all basic types */
+-
+-static int bind_fetch(MYSQL *mysql, int row_count)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i, count= row_count;
+- int32 data[10];
+- int8 i8_data;
+- int16 i16_data;
+- long i32_data;
+- longlong i64_data;
+- float f_data;
+- double d_data;
+- char s_data[10];
+- ulong length[10];
+- MYSQL_BIND my_bind[7];
+- my_bool is_null[7];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- strcpy(query, "INSERT INTO test_bind_fetch VALUES (?, ?, ?, ?, ?, ?, ?)");
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc,stmt);
+-
+- FAIL_UNLESS(mysql_stmt_param_count(stmt) == 7, "ParamCount != 7");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[i].buffer= (void *) &data[i];
+- }
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc,stmt);
+-
+- while (count--)
+- {
+- rc= 10+count;
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- data[i]= rc+i;
+- rc+= 12;
+- }
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+- }
+-
+- rc= mysql_commit(mysql);
+- check_stmt_rc(rc,stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= my_stmt_result(mysql, "SELECT * FROM test_bind_fetch");
+- FAIL_UNLESS(row_count == rc, "Wrong number of rows");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- strcpy(query, "SELECT * FROM test_bind_fetch");
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc,stmt);
+-
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].buffer= (void *) &data[i];
+- my_bind[i].length= &length[i];
+- my_bind[i].is_null= &is_null[i];
+- }
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&i8_data;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[1].buffer= (void *)&i16_data;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[2].buffer= (void *)&i32_data;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[3].buffer= (void *)&i64_data;
+-
+- my_bind[4].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[4].buffer= (void *)&f_data;
+-
+- my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[5].buffer= (void *)&d_data;
+-
+- my_bind[6].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[6].buffer= (void *)&s_data;
+- my_bind[6].buffer_length= sizeof(s_data);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- while (row_count--)
+- {
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= 10+row_count;
+-
+- /* TINY */
+- FAIL_UNLESS((int) i8_data == rc, "Invalid value for i8_data");
+- FAIL_UNLESS(length[0] == 1, "Invalid length");
+- rc+= 13;
+-
+- /* SHORT */
+- FAIL_UNLESS((int) i16_data == rc, "Invalid value for i16_data");
+- FAIL_UNLESS(length[1] == 2, "Invalid length");
+- rc+= 13;
+-
+- /* LONG */
+- FAIL_UNLESS((int) i32_data == rc, "Invalid value for i32_data");
+- FAIL_UNLESS(length[2] == 4, "Invalid length");
+- rc+= 13;
+-
+- /* LONGLONG */
+- FAIL_UNLESS((int) i64_data == rc, "Invalid value for i64_data");
+- FAIL_UNLESS(length[3] == 8, "Invalid length");
+- rc+= 13;
+-
+- /* FLOAT */
+- FAIL_UNLESS((int)f_data == rc, "Invalid value for f_data");
+- FAIL_UNLESS(length[4] == 4, "Invalid length");
+- rc+= 13;
+-
+- /* DOUBLE */
+- FAIL_UNLESS((int)d_data == rc, "Invalid value for d_data");
+- FAIL_UNLESS(length[5] == 8, "Invalid length");
+- rc+= 13;
+-
+- /* CHAR */
+- {
+- char buff[20];
+- long len= sprintf(buff, "%d", rc);
+- FAIL_UNLESS(strcmp(s_data, buff) == 0, "Invalid value for s_data");
+- FAIL_UNLESS(length[6] == (ulong) len, "Invalid length");
+- }
+- }
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-static int test_fetch_seek(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[3];
+- MYSQL_ROW_OFFSET row;
+- int rc;
+- int32 c1;
+- char c2[11], c3[20];
+- char *query = "SELECT * FROM t1";
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10), c3 timestamp)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql'), ('open'), ('source')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc,stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&c1;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)c2;
+- my_bind[1].buffer_length= sizeof(c2);
+-
+- my_bind[2]= my_bind[1];
+- my_bind[2].buffer= (void *)c3;
+- my_bind[2].buffer_length= sizeof(c3);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc,stmt);
+-
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- row= mysql_stmt_row_tell(stmt);
+-
+- row= mysql_stmt_row_seek(stmt, row);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- row= mysql_stmt_row_seek(stmt, row);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- mysql_stmt_data_seek(stmt, 0);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Test mysql_stmt_fetch_column() with offset */
+-
+-static int test_fetch_offset(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char data[11];
+- ulong length;
+- int rc;
+- my_bool is_null;
+- char *query = "SELECT * FROM t1";
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1(a char(10))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values('abcdefghij'), (null)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc,stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)data;
+- my_bind[0].buffer_length= 11;
+- my_bind[0].is_null= &is_null;
+- my_bind[0].length= &length;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- data[0]= '\0';
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc,stmt);
+-
+-
+- FAIL_IF(!(strncmp(data, "abcd", 4) == 0 && length == 10), "Wrong value");
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 5);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strncmp(data, "fg", 2) == 0 && length == 10), "Wrong value");
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 9);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strncmp(data, "j", 1) == 0 && length == 10), "Wrong value");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- is_null= 0;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc,stmt);
+-
+- FAIL_IF(is_null != 1, "Null flag not set");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Test mysql_stmt_fetch_column() */
+-
+-static int test_fetch_column(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- char c2[20], bc2[20];
+- ulong l1, l2, bl1, bl2;
+- int rc, c1, bc1;
+- char *query= "SELECT * FROM t1 ORDER BY c2 DESC";
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc,stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&bc1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &bl1;
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)bc2;
+- my_bind[1].buffer_length= 7;
+- my_bind[1].is_null= 0;
+- my_bind[1].length= &bl2;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); /* No-op at this point */
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- c2[0]= '\0'; l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)c2;
+- my_bind[0].buffer_length= 7;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strncmp(c2, "venu", 4) == 0 && l2 == 4), "Expected c2='venu'");
+-
+- c2[0]= '\0'; l2= 0;
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strcmp(c2, "venu") == 0 && l2 == 4), "Expected c2='venu'");
+-
+- c1= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&c1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l1;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(c1 == 1 && l1 == 4), "Expected c1=1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+-
+- c2[0]= '\0'; l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)c2;
+- my_bind[0].buffer_length= 7;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strncmp(c2, "mysq", 4) == 0 && l2 == 5), "Expected c2='mysql'");
+-
+- c2[0]= '\0'; l2= 0;
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(strcmp(c2, "mysql") == 0 && l2 == 5), "Expected c2='mysql'");
+-
+- c1= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&c1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l1;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc,stmt);
+- FAIL_IF(!(c1 == 2 && l1 == 4), "Expected c2=2");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_IF(rc!=MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Test fetch without prior bound buffers */
+-
+-static int test_fetch_nobuffs(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[4];
+- char str[4][50];
+- int rc;
+- char *query = "SELECT DATABASE(), CURRENT_USER(), \
+- CURRENT_DATE(), CURRENT_TIME()";
+-
+- stmt = mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+-
+- FAIL_IF(rc != 1, "Expected 1 row");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)str[0];
+- my_bind[0].buffer_length= sizeof(str[0]);
+- my_bind[1]= my_bind[2]= my_bind[3]= my_bind[0];
+- my_bind[1].buffer= (void *)str[1];
+- my_bind[2].buffer= (void *)str[2];
+- my_bind[3].buffer= (void *)str[3];
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- {
+- rc++;
+- }
+- FAIL_IF(rc != 1, "Expected 1 row");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/* Test fetch null */
+-
+-static int test_fetch_null(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- int i;
+- long nData;
+- MYSQL_BIND my_bind[11];
+- ulong length[11];
+- my_bool is_null[11];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_fetch_null");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_fetch_null("
+- " col1 tinyint, col2 smallint, "
+- " col3 int, col4 bigint, "
+- " col5 float, col6 double, "
+- " col7 date, col8 time, "
+- " col9 varbinary(10), "
+- " col10 varchar(50), "
+- " col11 char(20))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_fetch_null (col11) "
+- "VALUES (1000), (88), (389789)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- FAIL_IF(rc, mysql_error(mysql));
+-
+- /* fetch */
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[i].is_null= &is_null[i];
+- my_bind[i].length= &length[i];
+- }
+- my_bind[i-1].buffer= (void *)&nData; /* Last column is not null */
+-
+- strcpy((char *)query , "SELECT * FROM test_fetch_null");
+-
+- rc= my_stmt_result(mysql, query);
+- FAIL_UNLESS(rc == 3, "Exoected 3 rows");
+-
+- stmt = mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- {
+- rc++;
+- for (i= 0; i < 10; i++)
+- {
+- FAIL_IF(!is_null[i], "Expected is_null");
+- }
+- FAIL_UNLESS(nData == 1000 || nData == 88 || nData == 389789, "Wrong value for nData");
+- FAIL_UNLESS(is_null[i] == 0, "Exoected !is_null");
+- FAIL_UNLESS(length[i] == 4, "Expected length=4");
+- }
+- FAIL_UNLESS(rc == 3, "Expected 3 rows");
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/* Test fetching of date, time and ts */
+-
+-static int test_fetch_date(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- uint i;
+- int rc;
+- long year;
+- char date[25], my_time[25], ts[25], ts_4[25], ts_6[20], dt[20];
+- ulong d_length, t_length, ts_length, ts4_length, ts6_length,
+- dt_length, y_length;
+- MYSQL_BIND my_bind[8];
+- my_bool is_null[8];
+- ulong length[8];
+- char *query= "SELECT * FROM test_bind_result";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 date, c2 time, \
+- c3 timestamp, \
+- c4 year, \
+- c5 datetime, \
+- c6 timestamp, \
+- c7 timestamp)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SET SQL_MODE=''");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES('2002-01-02', \
+- '12:49:00', \
+- '2002-01-02 17:46:59', \
+- 2010, \
+- '2010-07-10', \
+- '2020', '1999-12-29')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- FAIL_IF(rc, mysql_error(mysql));
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < array_elements(my_bind); i++)
+- {
+- my_bind[i].is_null= &is_null[i];
+- my_bind[i].length= &length[i];
+- }
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1]= my_bind[2]= my_bind[0];
+-
+- my_bind[0].buffer= (void *)&date;
+- my_bind[0].buffer_length= sizeof(date);
+- my_bind[0].length= &d_length;
+-
+- my_bind[1].buffer= (void *)&my_time;
+- my_bind[1].buffer_length= sizeof(my_time);
+- my_bind[1].length= &t_length;
+-
+- my_bind[2].buffer= (void *)&ts;
+- my_bind[2].buffer_length= sizeof(ts);
+- my_bind[2].length= &ts_length;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[3].buffer= (void *)&year;
+- my_bind[3].length= &y_length;
+-
+- my_bind[4].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[4].buffer= (void *)&dt;
+- my_bind[4].buffer_length= sizeof(dt);
+- my_bind[4].length= &dt_length;
+-
+- my_bind[5].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[5].buffer= (void *)&ts_4;
+- my_bind[5].buffer_length= sizeof(ts_4);
+- my_bind[5].length= &ts4_length;
+-
+- my_bind[6].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[6].buffer= (void *)&ts_6;
+- my_bind[6].buffer_length= sizeof(ts_6);
+- my_bind[6].length= &ts6_length;
+-
+- rc= my_stmt_result(mysql, "SELECT * FROM test_bind_result");
+- FAIL_UNLESS(rc == 1, "Expected 1 row");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- ts_4[0]= '\0';
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(date, "2002-01-02") == 0, "date != '2002-01-02'");
+- FAIL_UNLESS(d_length == 10, "d_length != 10");
+-
+- FAIL_UNLESS(strcmp(my_time, "12:49:00") == 0, "mytime != '12:49:00'");
+- FAIL_UNLESS(t_length == 8, "t_length != 8");
+-
+- FAIL_UNLESS(strcmp(ts, "2002-01-02 17:46:59") == 0, "ts != '2002-01-02 17:46:59'");
+- FAIL_UNLESS(ts_length == 19, "ts_length != 19");
+-
+- FAIL_UNLESS(year == 2010, "year != 2010");
+- FAIL_UNLESS(y_length == 4, "y_length != 4");
+-
+- FAIL_UNLESS(strcmp(dt, "2010-07-10 00:00:00") == 0, "dt != 2010-07-10 00:00:00");
+- FAIL_UNLESS(dt_length == 19, "dt_length != 19");
+-
+- FAIL_UNLESS(strcmp(ts_4, "0000-00-00 00:00:00") == 0, "ts4 != '0000-00-00 00:00:00'");
+- FAIL_UNLESS(ts4_length == strlen("0000-00-00 00:00:00"), "ts4_length != 19");
+-
+- FAIL_UNLESS(strcmp(ts_6, "1999-12-29 00:00:00") == 0, "ts_6 != '1999-12-29 00:00:00'");
+- FAIL_UNLESS(ts6_length == 19, "ts6_length != 19");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/* Test fetching of str to all types */
+-
+-static int test_fetch_str(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 char(10), \
+- c2 char(10), \
+- c3 char(20), \
+- c4 char(20), \
+- c5 char(30), \
+- c6 char(40), \
+- c7 char(20))");
+- check_mysql_rc(rc, mysql);
+-
+- return bind_fetch(mysql, 3);
+-}
+-
+-/* Test fetching of long to all types */
+-
+-static int test_fetch_long(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 int unsigned, \
+- c2 int unsigned, \
+- c3 int, \
+- c4 int, \
+- c5 int, \
+- c6 int unsigned, \
+- c7 int)");
+- check_mysql_rc(rc, mysql);
+- return bind_fetch(mysql, 4);
+-}
+-
+-
+-/* Test fetching of short to all types */
+-
+-static int test_fetch_short(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 smallint unsigned, \
+- c2 smallint, \
+- c3 smallint unsigned, \
+- c4 smallint, \
+- c5 smallint, \
+- c6 smallint, \
+- c7 smallint unsigned)");
+- check_mysql_rc(rc, mysql);
+- return bind_fetch(mysql, 5);
+-}
+-
+-
+-/* Test fetching of tiny to all types */
+-
+-static int test_fetch_tiny(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 tinyint unsigned, \
+- c2 tinyint, \
+- c3 tinyint unsigned, \
+- c4 tinyint, \
+- c5 tinyint, \
+- c6 tinyint, \
+- c7 tinyint unsigned)");
+- check_mysql_rc(rc, mysql);
+- return bind_fetch(mysql, 3);
+-}
+-
+-
+-/* Test fetching of longlong to all types */
+-
+-static int test_fetch_bigint(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 bigint, \
+- c2 bigint, \
+- c3 bigint unsigned, \
+- c4 bigint unsigned, \
+- c5 bigint unsigned, \
+- c6 bigint unsigned, \
+- c7 bigint unsigned)");
+- check_mysql_rc(rc, mysql);
+- return bind_fetch(mysql, 2);
+-}
+-
+-
+-/* Test fetching of float to all types */
+-
+-static int test_fetch_float(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 float(3), \
+- c2 float, \
+- c3 float unsigned, \
+- c4 float, \
+- c5 float, \
+- c6 float, \
+- c7 float(10) unsigned)");
+- check_mysql_rc(rc, mysql);
+-
+- return bind_fetch(mysql, 2);
+-}
+-
+-
+-/* Test fetching of double to all types */
+-
+-static int test_fetch_double(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 double(5, 2), "
+- "c2 double unsigned, c3 double unsigned, "
+- "c4 double unsigned, c5 double unsigned, "
+- "c6 double unsigned, c7 double unsigned)");
+- check_mysql_rc(rc, mysql);
+- return bind_fetch(mysql, 3);
+-}
+-
+-struct my_tests_st my_tests[] = {
+- {"test_fetch_seek", test_fetch_seek, 1, 0, NULL , NULL},
+- {"test_fetch_offset", test_fetch_offset, 1, 0, NULL , NULL},
+- {"test_fetch_column", test_fetch_column, 1, 0, NULL , NULL},
+- {"test_fetch_nobuffs", test_fetch_nobuffs, 1, 0, NULL , NULL},
+- {"test_fetch_null", test_fetch_null, 1, 0, NULL , NULL},
+- {"test_fetch_date", test_fetch_date, 1, 0, NULL , NULL},
+- {"test_fetch_str", test_fetch_str, 1, 0, NULL , NULL},
+- {"test_fetch_long", test_fetch_long, 1, 0, NULL , NULL},
+- {"test_fetch_short", test_fetch_short, 1, 0, NULL , NULL},
+- {"test_fetch_tiny", test_fetch_tiny, 1, 0, NULL , NULL},
+- {"test_fetch_bigint", test_fetch_bigint, 1, 0, NULL , NULL},
+- {"test_fetch_float", test_fetch_float, 1, 0, NULL , NULL},
+- {"test_fetch_double", test_fetch_double, 1, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/logs.c mariadb-native-client.trunk/unittest/libmysql/logs.c
+--- mariadb/unittest/libmysql/logs.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/logs.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,213 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-static int enable_general_log(MYSQL *mysql, int truncate)
+-{
+- int rc;
+-
+- rc= mysql_query(mysql, "set @save_global_general_log=@@global.general_log");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "set @@global.general_log=on");
+- check_mysql_rc(rc, mysql);
+-
+- if (truncate)
+- {
+- rc= mysql_query(mysql, "truncate mysql.general_log");
+- check_mysql_rc(rc, mysql);
+- }
+-
+- return OK;
+-}
+-
+-
+-static int restore_general_log(MYSQL *mysql)
+-{
+- int rc;
+- rc= mysql_query(mysql, "set @@global.general_log=@save_global_general_log");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-/* Test update/binary logs */
+-
+-static int test_logs(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- char data[255];
+- ulong length;
+- int rc;
+- short id;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_logs");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_logs(id smallint, name varchar(20))");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy((char *)data, "INSERT INTO test_logs VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[0].buffer= (void *)&id;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)&data;
+- my_bind[1].buffer_length= 255;
+- my_bind[1].length= &length;
+-
+- id= 9876;
+- strcpy((char *)data, "MySQL - Open Source Database");
+- length= strlen(data);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy((char *)data, "'");
+- length= 1;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy((char *)data, "\"");
+- length= 1;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy((char *)data, "my\'sql\'");
+- length= strlen(data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy((char *)data, "my\"sql\"");
+- length= strlen(data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- strcpy((char *)data, "INSERT INTO test_logs VALUES(20, 'mysql')");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- strcpy((char *)data, "SELECT * FROM test_logs WHERE id=?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- my_bind[1].buffer_length= 255;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(id == 9876, "id != 9876");
+- FAIL_UNLESS(length == 19 || length == 20, "Invalid Length"); /* Due to VARCHAR(20) */
+- FAIL_UNLESS(strncmp(data, "MySQL - Open Source", 19) == 0, "data != 'MySQL - Open Source'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(length == 1, "length != 1");
+- FAIL_UNLESS(strcmp(data, "'") == 0, "data != '''");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(length == 1, "length != 1");
+- FAIL_UNLESS(strcmp(data, "\"") == 0, "data != '\"'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(length == 7, "length != 7");
+- FAIL_UNLESS(strcmp(data, "my\'sql\'") == 0, "data != my'sql'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(length == 7, "length != 7");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_logs");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_logs", test_logs, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/misc.c mariadb-native-client.trunk/unittest/libmysql/misc.c
+--- mariadb/unittest/libmysql/misc.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/misc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,839 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/*
+- Bug#28075 "COM_DEBUG crashes mysqld"
+-*/
+-
+-static int test_bug28075(MYSQL *mysql)
+-{
+- int rc;
+-
+- rc= mysql_dump_debug_info(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_ping(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#28505: mysql_affected_rows() returns wrong value if CLIENT_FOUND_ROWS
+- flag is set.
+-*/
+-
+-static int test_bug28505(MYSQL *mysql)
+-{
+- my_ulonglong res;
+- int rc;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- rc= mysql_query(mysql, "create table t1(f1 int primary key)");
+- rc= mysql_query(mysql, "insert into t1 values(1)");
+- rc= mysql_query(mysql, "insert into t1 values(1) on duplicate key update f1=1");
+- res= mysql_affected_rows(mysql);
+- FAIL_UNLESS(!res, "res != 0");
+- rc= mysql_query(mysql, "drop table t1");
+- return OK;
+-}
+-
+-/*
+- Bug #29692 Single row inserts can incorrectly report a huge number of
+- row insertions
+-*/
+-
+-static int test_bug29692(MYSQL *mysql)
+-{
+- int rc;
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1(f1 int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values(1)");
+- check_mysql_rc(rc, mysql);
+- FAIL_UNLESS(1 == mysql_affected_rows(mysql), "affected_rows != 1");
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int bug31418_impl()
+-{
+- my_bool is_null;
+- MYSQL *mysql;
+- int rc;
+-
+- /* Create a new connection. */
+-
+- mysql= test_connect(NULL);
+- if (!mysql)
+- return FAIL;
+-
+- /***********************************************************************
+- Check that lock is free:
+- - IS_FREE_LOCK() should return 1;
+- - IS_USED_LOCK() should return NULL;
+- ***********************************************************************/
+-
+- is_null= query_int_variable(mysql,
+- "IS_FREE_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(!is_null && rc, "rc = 0");
+-
+- is_null= query_int_variable(mysql,
+- "IS_USED_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(is_null, "rc = 0");
+-
+- /***********************************************************************
+- Acquire lock and check the lock status (the lock must be in use):
+- - IS_FREE_LOCK() should return 0;
+- - IS_USED_LOCK() should return non-zero thread id;
+- ***********************************************************************/
+-
+- query_int_variable(mysql, "GET_LOCK('bug31418', 1)", &rc);
+- FAIL_UNLESS(rc, "rc = 0");
+-
+- is_null= query_int_variable(mysql,
+- "IS_FREE_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(!is_null && !rc, "rc = 0");
+-
+- is_null= query_int_variable(mysql,
+- "IS_USED_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(!is_null && rc, "rc = 0");
+-
+- /***********************************************************************
+- Issue COM_CHANGE_USER command and check the lock status
+- (the lock must be free):
+- - IS_FREE_LOCK() should return 1;
+- - IS_USED_LOCK() should return NULL;
+- **********************************************************************/
+-
+- rc= mysql_change_user(mysql, username, password, schema ? schema : "test");
+- check_mysql_rc(rc, mysql);
+-
+- is_null= query_int_variable(mysql,
+- "IS_FREE_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(!is_null && rc, "rc = 0");
+-
+- is_null= query_int_variable(mysql,
+- "IS_USED_LOCK('bug31418')",
+- &rc);
+- FAIL_UNLESS(is_null, "rc = 0");
+-
+- /***********************************************************************
+- That's it. Cleanup.
+- ***********************************************************************/
+-
+- mysql_close(mysql);
+- return OK;
+-}
+-
+-static int test_bug31418(MYSQL *mysql)
+-{
+- int i;
+- /* Run test case for BUG#31418 for three different connections. */
+-
+- for (i=0; i < 3; i++)
+- if (bug31418_impl())
+- return FAIL;
+-
+- return OK;
+-}
+-
+-/*
+- Altough mysql_create_db(), mysql_rm_db() are deprecated since 4.0 they
+- should not crash server and should not hang in case of errors.
+-
+- Since those functions can't be seen in modern API (unless client library
+- was compiled with USE_OLD_FUNCTIONS define) we use simple_command() macro.
+-*/
+-static int test_bug6081(MYSQL *mysql)
+-{
+- int rc;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= simple_command(mysql, MYSQL_COM_DROP_DB, (char*) schema,
+- (ulong)strlen(schema), 0U);
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= simple_command(mysql, MYSQL_COM_CREATE_DB, (char*) schema,
+- (ulong)strlen(schema), 0U);
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_select_db(mysql, schema);
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Query processing */
+-
+-static int test_debug_example(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_debug_example");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_debug_example("
+- "id INT PRIMARY KEY AUTO_INCREMENT, "
+- "name VARCHAR(20), xxx INT)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_debug_example (name) "
+- "VALUES ('mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "UPDATE test_debug_example SET name='updated' "
+- "WHERE name='deleted'");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_debug_example where name='mysql'");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result));
+- mysql_free_result(result);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_debug_example");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/*
+- Test a crash when invalid/corrupted .frm is used in the
+- SHOW TABLE STATUS
+- bug #93 (reported by serg@mysql.com).
+-*/
+-
+-static int test_frm_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- MYSQL_RES *result;
+- MYSQL_ROW row;
+- FILE *test_file;
+- char data_dir[FN_REFLEN];
+- char test_frm[FN_REFLEN];
+- int rc;
+-
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- rc= mysql_query(mysql, "drop table if exists test_frm_bug");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "flush tables");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "show variables like 'datadir'", strlen("show variables like 'datadir'"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= data_dir;
+- my_bind[0].buffer_length= FN_REFLEN;
+- my_bind[1]= my_bind[0];
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- sprintf(test_frm, "%s/%s/test_frm_bug.frm", data_dir, schema);
+-
+-
+- if (!(test_file= my_fopen(test_frm, (int) (O_RDWR | O_CREAT), MYF(MY_WME))))
+- {
+- mysql_stmt_close(stmt);
+- diag("Can't write to file %s -> SKIP", test_frm);
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "SHOW TABLE STATUS like 'test_frm_bug'");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");/* It can't be NULL */
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 0");
+-
+- mysql_data_seek(result, 0);
+-
+- row= mysql_fetch_row(result);
+- FAIL_IF(!row, "couldn't fetch row");
+-
+- FAIL_UNLESS(row[17] != 0, "row[17] != 0");
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- my_fclose(test_file, MYF(0));
+- mysql_query(mysql, "drop table if exists test_frm_bug");
+- return OK;
+-}
+-
+-static int test_wl4166_1(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int int_data;
+- char str_data[50];
+- char tiny_data;
+- short small_data;
+- longlong big_data;
+- float real_data;
+- double double_data;
+- ulong length[7];
+- my_bool is_null[7];
+- MYSQL_BIND my_bind[7];
+- static char *query;
+- int rc;
+- int i;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS table_4166");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE table_4166(col1 tinyint NOT NULL, "
+- "col2 varchar(15), col3 int, "
+- "col4 smallint, col5 bigint, "
+- "col6 float, col7 double, "
+- "colX varchar(10) default NULL)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- query= "INSERT INTO table_4166(col1, col2, col3, col4, col5, col6, col7) "
+- "VALUES(?, ?, ?, ?, ?, ?, ?)";
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 7, "param_count != 7");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- /* tinyint */
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&tiny_data;
+- /* string */
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)str_data;
+- my_bind[1].buffer_length= 1000; /* Max string length */
+- /* integer */
+- my_bind[2].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[2].buffer= (void *)&int_data;
+- /* short */
+- my_bind[3].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[3].buffer= (void *)&small_data;
+- /* bigint */
+- my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[4].buffer= (void *)&big_data;
+- /* float */
+- my_bind[5].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[5].buffer= (void *)&real_data;
+- /* double */
+- my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[6].buffer= (void *)&double_data;
+-
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].length= &length[i];
+- my_bind[i].is_null= &is_null[i];
+- is_null[i]= 0;
+- }
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- int_data= 320;
+- small_data= 1867;
+- big_data= 1000;
+- real_data= 2;
+- double_data= 6578.001;
+-
+- /* now, execute the prepared statement to insert 10 records.. */
+- for (tiny_data= 0; tiny_data < 10; tiny_data++)
+- {
+- length[1]= sprintf(str_data, "MySQL%d", int_data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- int_data += 25;
+- small_data += 10;
+- big_data += 100;
+- real_data += 1;
+- double_data += 10.09;
+- }
+-
+- /* force a re-prepare with some DDL */
+-
+- rc= mysql_query(mysql,
+- "ALTER TABLE table_4166 change colX colX varchar(20) default NULL");
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- execute the prepared statement again,
+- without changing the types of parameters already bound.
+- */
+-
+- for (tiny_data= 50; tiny_data < 60; tiny_data++)
+- {
+- length[1]= sprintf(str_data, "MySQL%d", int_data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- int_data += 25;
+- small_data += 10;
+- big_data += 100;
+- real_data += 1;
+- double_data += 10.09;
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE table_4166");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-
+-static int test_wl4166_2(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int c_int;
+- MYSQL_TIME d_date;
+- MYSQL_BIND bind_out[2];
+- int rc;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (c_int int, d_date date)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "insert into t1 (c_int, d_date) values (42, '1948-05-15')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select * from t1", strlen("select * from t1"));
+- check_stmt_rc(rc, stmt);
+-
+- memset(bind_out, '\0', sizeof(bind_out));
+- bind_out[0].buffer_type= MYSQL_TYPE_LONG;
+- bind_out[0].buffer= (void*) &c_int;
+-
+- bind_out[1].buffer_type= MYSQL_TYPE_DATE;
+- bind_out[1].buffer= (void*) &d_date;
+-
+- rc= mysql_stmt_bind_result(stmt, bind_out);
+- check_stmt_rc(rc, stmt);
+-
+- /* int -> varchar transition */
+-
+- rc= mysql_query(mysql,
+- "alter table t1 change column c_int c_int varchar(11)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(c_int == 42, "c_int != 42");
+- FAIL_UNLESS(d_date.year == 1948, "y!=1948");
+- FAIL_UNLESS(d_date.month == 5, "m != 5");
+- FAIL_UNLESS(d_date.day == 15, "d != 15");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* varchar to int retrieval with truncation */
+-
+- rc= mysql_query(mysql, "update t1 set c_int='abcde'");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- FAIL_UNLESS(c_int == 0, "c != 0");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* alter table and increase the number of columns */
+- rc= mysql_query(mysql, "alter table t1 add column d_int int");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_stmt_reset(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* decrease the number of columns */
+- rc= mysql_query(mysql, "alter table t1 drop d_date, drop d_int");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_stmt_execute(stmt);
+- diag("rc=%d error: %d\n", rc, mysql_stmt_errno(stmt));
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-/**
+- Test how warnings generated during assignment of parameters
+- are (currently not) preserve in case of reprepare.
+-*/
+-
+-static int test_wl4166_3(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- MYSQL_TIME tm[1];
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (year datetime)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "insert into t1 (year) values (?)", strlen("insert into t1 (year) values (?)"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_DATETIME;
+- my_bind[0].buffer= &tm[0];
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- tm[0].year= 10000;
+- tm[0].month= 1; tm[0].day= 1;
+- tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1;
+- tm[0].second_part= 0; tm[0].neg= 0;
+-
+- /* Cause a statement reprepare */
+- rc= mysql_query(mysql, "alter table t1 add column c int");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /*
+- Sic: only one warning, instead of two. The warning
+- about data truncation when assigning a parameter is lost.
+- This is a bug.
+- */
+- FAIL_IF(mysql_warning_count(mysql) != 1, "warning count != 1");
+-
+- if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00")) {
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- return FAIL;
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-
+-/**
+- Test that long data parameters, as well as parameters
+- that were originally in a different character set, are
+- preserved in case of reprepare.
+-*/
+-
+-static int test_wl4166_4(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *stmt_text;
+- MYSQL_BIND bind_array[2];
+-
+- /* Represented as numbers to keep UTF8 tools from clobbering them. */
+- const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
+- const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
+- char buf1[16], buf2[16];
+- ulong buf1_len, buf2_len;
+-
+- if (mysql_get_server_version(mysql) < 50100) {
+- diag("Test requires MySQL Server version 5.1 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- Create table with binary columns, set session character set to cp1251,
+- client character set to koi8, and make sure that there is conversion
+- on insert and no conversion on select
+- */
+- rc= mysql_query(mysql,
+- "create table t1 (c1 varbinary(255), c2 varbinary(255))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "set character_set_client=koi8r, "
+- "character_set_connection=cp1251, "
+- "character_set_results=koi8r");
+- check_mysql_rc(rc, mysql);
+-
+- memset(bind_array, '\0', sizeof(bind_array));
+-
+- bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+-
+- bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[1].buffer= (void *) koi8;
+- bind_array[1].buffer_length= strlen(koi8);
+-
+- stmt= mysql_stmt_init(mysql);
+- check_stmt_rc(rc, stmt);
+-
+- stmt_text= "insert into t1 (c1, c2) values (?, ?)";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_bind_param(stmt, bind_array);
+-
+- mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+-
+- /* Cause a reprepare at statement execute */
+- rc= mysql_query(mysql, "alter table t1 add column d int");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- stmt_text= "select c1, c2 from t1";
+-
+- /* c1 and c2 are binary so no conversion will be done on select */
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- bind_array[0].buffer= buf1;
+- bind_array[0].buffer_length= sizeof(buf1);
+- bind_array[0].length= &buf1_len;
+-
+- bind_array[1].buffer= buf2;
+- bind_array[1].buffer_length= sizeof(buf2);
+- bind_array[1].length= &buf2_len;
+-
+- mysql_stmt_bind_result(stmt, bind_array);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(buf1_len == strlen(cp1251), "");
+- FAIL_UNLESS(buf2_len == strlen(cp1251), "");
+- FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "");
+- FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "set names default");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/**
+- Test that COM_REFRESH issues a implicit commit.
+-*/
+-
+-static int test_wl4284_1(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_ROW row;
+- MYSQL_RES *result;
+-
+- if (mysql_get_server_version(mysql) < 60000) {
+- diag("Test requires MySQL Server version 6.0 or above");
+- return SKIP;
+- }
+-
+- /* set AUTOCOMMIT to OFF */
+- rc= mysql_autocommit(mysql, FALSE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS trans");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE trans (a INT) ENGINE= InnoDB");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO trans VALUES(1)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_refresh(mysql, REFRESH_GRANT | REFRESH_TABLES);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_rollback(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT * FROM trans");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- row= mysql_fetch_row(result);
+- FAIL_IF(!row, "Can't fetch row");
+-
+- mysql_free_result(result);
+-
+- /* set AUTOCOMMIT to OFF */
+- rc= mysql_autocommit(mysql, FALSE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE trans");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug49694(MYSQL *mysql)
+-{
+- int rc;
+- int i;
+- FILE *fp;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS enclist");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE `enclist` ("
+- " `pat_id` int(11) NOT NULL,"
+- " `episode_id` int(11) NOT NULL,"
+- " `enc_id` double NOT NULL,"
+- " PRIMARY KEY (`pat_id`,`episode_id`,`enc_id`)"
+- ") ENGINE=MyISAM DEFAULT CHARSET=latin1");
+- check_mysql_rc(rc, mysql);
+-
+- fp= fopen("data.csv", "w");
+- FAIL_IF(!fp, "Can't open data.csv");
+-
+- for (i=0; i < 100; i++)
+- fprintf (fp, "%.08d,%d,%f\r\n", 100 + i, i % 3 + 1, 60000.0 + i/100);
+- fclose(fp);
+-
+- rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE './data.csv' INTO TABLE enclist "
+- "FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DELETE FROM enclist");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_IF(mysql_affected_rows(mysql) != 100, "Import failure. Expected 2 imported rows");
+-
+- rc= mysql_query(mysql, "DROP TABLE enclist");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-struct my_tests_st my_tests[] = {
+- {"test_bug28075", test_bug28075, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug28505", test_bug28505, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_debug_example", test_debug_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug29692", test_bug29692, TEST_CONNECTION_NEW, CLIENT_FOUND_ROWS, NULL, NULL},
+- {"test_bug31418", test_bug31418, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug6081", test_bug6081, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_frm_bug", test_frm_bug, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_wl4166_1", test_wl4166_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_wl4166_2", test_wl4166_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_wl4166_3", test_wl4166_3, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_wl4166_4", test_wl4166_4, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_wl4284_1", test_wl4284_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_bug49694", test_bug49694, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {NULL, NULL, 0, 0, NULL, 0}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/my_test.h mariadb-native-client.trunk/unittest/libmysql/my_test.h
+--- mariadb/unittest/libmysql/my_test.h 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/my_test.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,517 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include <my_global.h>
+-#include <my_sys.h>
+-#include <mysql.h>
+-#include <tap.h>
+-#include <getopt.h>
+-#include <memory.h>
+-#include <errmsg.h>
+-
+-#ifndef OK
+-# define OK 0
+-#endif
+-#ifndef FAIL
+-# define FAIL 1
+-#endif
+-#ifndef SKIP
+-# define SKIP -1
+-#endif
+-#ifndef FALSE
+-# define FALSE 0
+-#endif
+-#ifndef TRUE
+-# define TRUE 1
+-#endif
+-
+-#define MAX_KEY MAX_INDEXES
+-#define MAX_KEY_LENGTH_DECIMAL_WIDTH 4 /* strlen("4096") */
+-
+-#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
+-
+-#define check_mysql_rc(rc, mysql) \
+-if (rc)\
+-{\
+- diag("Error (%d): %s (%d) in %s line %d", rc, mysql_error(mysql), \
+- mysql_errno(mysql), __FILE__, __LINE__);\
+- return(FAIL);\
+-}
+-
+-#define check_stmt_rc(rc, stmt) \
+-if (rc)\
+-{\
+- diag("Error: %s (%s: %d)", mysql_stmt_error(stmt), __FILE__, __LINE__);\
+- return(FAIL);\
+-}
+-
+-#define FAIL_IF(expr, reason)\
+-if (expr)\
+-{\
+- diag("Error: %s (%s: %d)", (reason) ? reason : "", __FILE__, __LINE__);\
+- return FAIL;\
+-}
+-
+-#define FAIL_UNLESS(expr, reason)\
+-if (!(expr))\
+-{\
+- diag("Error: %s (%s: %d)", reason, __FILE__, __LINE__);\
+- return FAIL;\
+-}
+-
+-/* connection options */
+-#define TEST_CONNECTION_DEFAULT 1 /* default connection */
+-#define TEST_CONNECTION_NONE 2 /* tests creates own connection */
+-#define TEST_CONNECTION_NEW 4 /* create a separate connection */
+-#define TEST_CONNECTION_DONT_CLOSE 8 /* don't close connection */
+-
+-struct my_option_st
+-{
+- enum mysql_option option;
+- char *value;
+-};
+-
+-struct my_tests_st
+-{
+- const char *name;
+- int (*function)(MYSQL *);
+- int connection;
+- ulong connect_flags;
+- struct my_option_st *options;
+- char *skipmsg;
+-};
+-
+-static char *schema = "test";
+-static char *hostname = 0;
+-static char *password = 0;
+-static unsigned int port = 0;
+-static char *socketname = 0;
+-static char *username = 0;
+-/*
+-static struct my_option test_options[] =
+-{
+- {"schema", 'd', "database to use", (uchar **) &schema, (uchar **) &schema,
+- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+- {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
+- 0, 0, 0, 0, 0},
+- {"host", 'h', "Connect to host", (uchar **) &hostname, (uchar **) &hostname,
+- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+- {"password", 'p',
+- "Password to use when connecting to server.", (uchar **) &password, (uchar **) &password,
+- 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+- {"port", 'P', "Port number to use for connection or 0 for default to, in "
+- "order of preference, my.cnf, $MYSQL_TCP_PORT, "
+-#if MYSQL_PORT_DEFAULT == 0
+- "/etc/services, "
+-#endif
+- "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
+- (uchar **) &port,
+- (uchar **) &port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+- {"socket", 'S', "Socket file to use for connection",
+- (uchar **) &socketname, (uchar **) &socketname, 0, GET_STR,
+- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+- {"user", 'u', "User for login if not current user", (uchar **) &username,
+- (uchar **) &username, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+-};
+-*/
+-#define verify_prepare_field(result,no,name,org_name,type,table,\
+- org_table,db,length,def) \
+- do_verify_prepare_field((result),(no),(name),(org_name),(type), \
+- (table),(org_table),(db),(length),(def), \
+- __FILE__, __LINE__)
+-
+-int do_verify_prepare_field(MYSQL_RES *result,
+- unsigned int no, const char *name,
+- const char *org_name,
+- enum enum_field_types type,
+- const char *table,
+- const char *org_table, const char *db,
+- unsigned long length, const char *def,
+- const char *file, int line)
+-{
+- MYSQL_FIELD *field;
+-/* CHARSET_INFO *cs; */
+-
+- FAIL_IF(!(field= mysql_fetch_field_direct(result, no)), "FAILED to get result");
+-/* cs= mysql_find_charset_nr(field->charsetnr);
+- FAIL_UNLESS(cs, "Couldn't get character set"); */
+- FAIL_UNLESS(strcmp(field->name, name) == 0, "field->name differs");
+- FAIL_UNLESS(strcmp(field->org_name, org_name) == 0, "field->org_name differs");
+-/*
+- if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32)
+- expected_field_length= UINT_MAX32;
+-*/
+- /*
+- XXX: silent column specification change works based on number of
+- bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even
+- for CHAR(2) column if its character set is multibyte.
+- VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would
+- expect.
+- */
+-// if (cs->char_maxlen == 1)
+-// FAIL_UNLESS(field->type == type, "field->type differs");
+- if (table)
+- FAIL_UNLESS(strcmp(field->table, table) == 0, "field->table differs");
+- if (org_table)
+- FAIL_UNLESS(strcmp(field->org_table, org_table) == 0, "field->org_table differs");
+- FAIL_UNLESS(strcmp(field->db, db) == 0, "field->db differs");
+- /*
+- Character set should be taken into account for multibyte encodings, such
+- as utf8. Field length is calculated as number of characters * maximum
+- number of bytes a character can occupy.
+- */
+-
+- return OK;
+-}
+-
+-/* Prepare statement, execute, and process result set for given query */
+-
+-int my_stmt_result(MYSQL *mysql, const char *buff)
+-{
+- MYSQL_STMT *stmt;
+- int row_count= 0;
+- int rc;
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- rc= mysql_stmt_prepare(stmt, buff, strlen(buff));
+- FAIL_IF(rc, mysql_stmt_error(stmt));
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(rc, mysql_stmt_error(stmt));
+-
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- row_count++;
+-
+- mysql_stmt_close(stmt);
+-
+- return row_count;
+-}
+-/*
+-static my_bool
+-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+- char *argument)
+-{
+- switch (optid) {
+- case '?':
+- case 'I':
+- my_print_help(test_options);
+- exit(0);
+- break;
+- }
+- return 0;
+-}
+-*/
+-/* Utility function to verify a particular column data */
+-
+-int verify_col_data(MYSQL *mysql, const char *table, const char *col,
+- const char *exp_data)
+-{
+- static char query[MAX_TEST_QUERY_LENGTH];
+- MYSQL_RES *result;
+- MYSQL_ROW row;
+- int rc;
+-
+- if (table && col)
+- {
+- sprintf(query, "SELECT %s FROM %s LIMIT 1", col, table);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+- }
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- if (!(row= mysql_fetch_row(result)) || !row[0]) {
+- diag("Failed to get the result");
+- goto error;
+- }
+- if(strcmp(row[0], exp_data)) {
+- diag("Expected %s, got %s", exp_data, row[0]);
+- goto error;
+- }
+- mysql_free_result(result);
+-
+- return OK;
+-
+-error:
+- mysql_free_result(result);
+- return FAIL;
+-}
+-
+-my_bool query_int_variable(MYSQL *con, const char *var_name, int *var_value)
+-{
+- MYSQL_RES *rs;
+- MYSQL_ROW row;
+-
+- char query_buffer[MAX_TEST_QUERY_LENGTH];
+-
+- my_bool is_null;
+-
+- sprintf(query_buffer,
+- "SELECT %s",
+- (const char *) var_name);
+-
+- FAIL_IF(mysql_query(con, query_buffer), "Query failed");
+- FAIL_UNLESS(rs= mysql_store_result(con), "Invaliid result set");
+- FAIL_UNLESS(row= mysql_fetch_row(rs), "Nothing to fetch");
+-
+- is_null= row[0] == NULL;
+-
+- if (!is_null)
+- *var_value= atoi(row[0]);
+-
+- mysql_free_result(rs);
+-
+- return is_null;
+-}
+-
+-static void usage()
+-{
+- printf("Execute test with the following options:\n");
+- printf("-h hostname\n");
+- printf("-u username\n");
+- printf("-p password\n");
+- printf("-d database\n");
+- printf("-S socketname\n");
+- printf("-P port number\n");
+- printf("? displays this help and exits\n");
+-}
+-
+-void get_options(int argc, char **argv)
+-{
+- int c= 0;
+-
+- while ((c=getopt(argc,argv, "h:u:p:d:P:S:?")) >= 0)
+- {
+- switch(c) {
+- case 'h':
+- hostname= optarg;
+- break;
+- case 'u':
+- username= optarg;
+- break;
+- case 'p':
+- password= optarg;
+- break;
+- case 'd':
+- schema= optarg;
+- break;
+- case 'P':
+- port= atoi(optarg);
+- break;
+- case 'S':
+- socketname= optarg;
+- break;
+- case '?':
+- usage();
+- exit(0);
+- break;
+- default:
+- printf("Unknown option %c\n", c);
+- usage();
+- exit(0);
+- }
+- }
+-}
+-
+-
+-int check_variable(MYSQL *mysql, char *variable, char *value)
+-{
+- char query[MAX_TEST_QUERY_LENGTH];
+- MYSQL_RES *result;
+- MYSQL_ROW row;
+-
+- sprintf(query, "SELECT %s", variable);
+- result= mysql_store_result(mysql);
+- if (!result)
+- return FAIL;
+-
+- if ((row = mysql_fetch_row(result)))
+- if (strcmp(row[0], value) == 0) {
+- mysql_free_result(result);
+- return OK;
+- }
+- mysql_free_result(result);
+- return FAIL;
+-}
+-
+-/*
+- * function *test_connect
+- *
+- * returns a new connection. This function will be called, if the test doesn't
+- * use default_connection.
+- */
+-MYSQL *test_connect(struct my_tests_st *test) {
+- MYSQL *mysql;
+- char query[255];
+-
+- if (!(mysql = mysql_init(NULL))) {
+- diag("%s", "mysql_init failed - exiting");
+- return(NULL);
+- }
+-
+- mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, "1");
+-
+- /* option handling */
+- if (test && test->options) {
+- int i=0;
+-
+- while (test->options[i].option)
+- {
+- if (mysql_options(mysql, test->options[i].option, test->options[i].value)) {
+- diag("Couldn't set option %d. Error (%d) %s", test->options[i].option,
+- mysql_errno(mysql), mysql_error(mysql));
+- mysql_close(mysql);
+- return(NULL);
+- }
+- i++;
+- }
+- }
+-
+- if (!(mysql_real_connect(mysql, hostname, username, password,
+- NULL, port, socketname, (test) ? test->connect_flags:0)))
+- {
+- diag("Couldn't establish connection to server %s. Error (%d): %s",
+- hostname, mysql_errno(mysql), mysql_error(mysql));
+- mysql_close(mysql);
+- return(NULL);
+- }
+-
+- /* change database or create if it doesn't exist */
+- if (mysql_select_db(mysql, schema)) {
+- if(mysql_errno(mysql) == 1049) {
+- sprintf(query, "CREATE DATABASE %s", schema);
+- if (mysql_query(mysql, query)) {
+- diag("Can't create database %s", schema);
+- mysql_close(mysql);
+- return NULL;
+- }
+- } else {
+- diag("Error (%d): %s", mysql_errno(mysql), mysql_error(mysql));
+- mysql_close(mysql);
+- return NULL;
+- }
+- }
+-
+- return(mysql);
+-}
+-
+-static int reset_connection(MYSQL *mysql) {
+- int rc;
+-
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+- if (mysql_get_server_version(mysql) < 50400)
+- rc= mysql_query(mysql, "SET table_type='MyISAM'");
+- else
+- rc= mysql_query(mysql, "SET storage_engine='MyISAM'");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "SET sql_mode=''");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- * function get_envvars((
+- *
+- * checks for connection related environment variables
+- */
+-void get_envvars() {
+- char *envvar;
+-
+- if (!hostname && (envvar= getenv("MYSQL_TEST_HOST")))
+- hostname= envvar;
+- if (!username && (envvar= getenv("MYSQL_TEST_USER")))
+- username= envvar;
+- if (!password && (envvar= getenv("MYSQL_TEST_PASSWD")))
+- password= envvar;
+- if (!schema && (envvar= getenv("MYSQL_TEST_DB")))
+- schema= envvar;
+- if (!port && (envvar= getenv("MYSQL_TEST_PORT")))
+- port= atoi(envvar);
+- if (!socketname && (envvar= getenv("MYSQL_TEST_SOCKET")))
+- socketname= envvar;
+-}
+-
+-void run_tests(struct my_tests_st *test) {
+- int i, rc, total=0;
+- MYSQL *mysql, *mysql_default= NULL; /* default connection */
+-
+-
+- while (test[total].function)
+- total++;
+- plan(total);
+-
+- if ((mysql_default= test_connect(NULL)))
+- diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default));
+- else
+- {
+- diag("Can't connect to a server. Aborting....");
+- exit(0);
+- }
+-
+- for (i=0; i < total; i++) {
+- if (!mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT))
+- {
+- diag("MySQL server not running");
+- skip(1, test[i].name);
+- } else if (!test[i].skipmsg) {
+- mysql= mysql_default;
+- if (test[i].connection & TEST_CONNECTION_NEW)
+- mysql= test_connect(&test[i]);
+- if (test[i].connection & TEST_CONNECTION_NONE)
+- mysql= NULL;
+-
+- /* run test */
+- rc= test[i].function(mysql);
+-
+- if (rc == SKIP)
+- skip(1, test[i].name);
+- else
+- ok(rc == OK, test[i].name);
+-
+- /* if test failed, close and reopen default connection to prevent
+- errors for further tests */
+- if ((rc == FAIL || mysql_errno(mysql_default)) && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
+- mysql_close(mysql_default);
+- mysql_default= test_connect(&test[i]);
+- }
+- /* clear connection: reset default connection or close extra connection */
+- else if (mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
+- if (reset_connection(mysql))
+- return; /* default doesn't work anymore */
+- }
+- else if (mysql && !(test[i].connection & TEST_CONNECTION_DONT_CLOSE))
+- mysql_close(mysql);
+- } else {
+- skip(1, test[i].skipmsg);
+- }
+- }
+- if (mysql_default) {
+- mysql_close(mysql_default);
+- }
+- mysql_server_end();
+-}
+-
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/ps_bugs.c mariadb-native-client.trunk/unittest/libmysql/ps_bugs.c
+--- mariadb/unittest/libmysql/ps_bugs.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/ps_bugs.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,3779 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-#define MY_INT64_NUM_DECIMAL_DIGITS 21
+-#define MAX_INDEXES 64
+-
+-/* A workaround for Sun Forte 5.6 on Solaris x86 */
+-
+-static int cmp_double(double *a, double *b)
+-{
+- return *a == *b;
+- return OK;
+-}
+-
+-/* Test BUG#1115 (incorrect string parameter value allocation) */
+-
+-static int test_bug1115(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, rowcount;
+- MYSQL_BIND my_bind[1];
+- ulong length[1];
+- char szData[11];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(\
+-session_id char(9) NOT NULL, \
+- a int(8) unsigned NOT NULL, \
+- b int(5) NOT NULL, \
+- c int(5) NOT NULL, \
+- d datetime NOT NULL)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
+- "(\"abc\", 1, 2, 3, 2003-08-30), "
+- "(\"abd\", 1, 2, 3, 2003-08-30), "
+- "(\"abf\", 1, 2, 3, 2003-08-30), "
+- "(\"abg\", 1, 2, 3, 2003-08-30), "
+- "(\"abh\", 1, 2, 3, 2003-08-30), "
+- "(\"abj\", 1, 2, 3, 2003-08-30), "
+- "(\"abk\", 1, 2, 3, 2003-08-30), "
+- "(\"abl\", 1, 2, 3, 2003-08-30), "
+- "(\"abq\", 1, 2, 3, 2003-08-30) ");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
+- "(\"abw\", 1, 2, 3, 2003-08-30), "
+- "(\"abe\", 1, 2, 3, 2003-08-30), "
+- "(\"abr\", 1, 2, 3, 2003-08-30), "
+- "(\"abt\", 1, 2, 3, 2003-08-30), "
+- "(\"aby\", 1, 2, 3, 2003-08-30), "
+- "(\"abu\", 1, 2, 3, 2003-08-30), "
+- "(\"abi\", 1, 2, 3, 2003-08-30), "
+- "(\"abo\", 1, 2, 3, 2003-08-30), "
+- "(\"abp\", 1, 2, 3, 2003-08-30), "
+- "(\"abz\", 1, 2, 3, 2003-08-30), "
+- "(\"abx\", 1, 2, 3, 2003-08-30)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT * FROM test_select WHERE "
+- "CONVERT(session_id USING utf8)= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
+-
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+-
+- strcpy(szData, (char *)"abc");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 3;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount=%d != 1");
+-
+- strcpy(szData, (char *)"venu");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 4;
+- my_bind[0].is_null= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 0, "rowcount != 0");
+-
+- strcpy(szData, (char *)"abc");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 3;
+- my_bind[0].is_null= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-/* Test BUG#1180 (optimized away part of WHERE clause) */
+-
+-static int test_bug1180(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, rowcount;
+- MYSQL_BIND my_bind[1];
+- ulong length[1];
+- char szData[11];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(session_id char(9) NOT NULL)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES (\"abc\")");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT * FROM test_select WHERE ?= \"1111\" and "
+- "session_id= \"abc\"");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
+-
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+-
+- strcpy(szData, (char *)"abc");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 3;
+- my_bind[0].is_null= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 0, "rowcount != 0");
+-
+- strcpy(szData, (char *)"1111");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 4;
+- my_bind[0].is_null= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+-
+- strcpy(szData, (char *)"abc");
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)szData;
+- my_bind[0].buffer_length= 10;
+- my_bind[0].length= &length[0];
+- length[0]= 3;
+- my_bind[0].is_null= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 0, "rowcount != 0");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-
+-/*
+- Test BUG#1644 (Insertion of more than 3 NULL columns with parameter
+- binding fails)
+-*/
+-
+-static int test_bug1644(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- MYSQL_ROW row;
+- MYSQL_BIND my_bind[4];
+- int num;
+- my_bool isnull;
+- int rc, i;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS foo_dfr");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "CREATE TABLE foo_dfr(col1 int, col2 int, col3 int, col4 int);");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO foo_dfr VALUES (?, ?, ?, ? )");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 4, "Paramcount != 4");
+-
+- memset(my_bind, '\0', sizeof(MYSQL_BIND) * 4);
+-
+- num= 22;
+- isnull= 0;
+- for (i= 0 ; i < 4 ; i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[i].buffer= (void *)&num;
+- my_bind[i].is_null= &isnull;
+- }
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- isnull= 1;
+- for (i= 0 ; i < 4 ; i++)
+- my_bind[i].is_null= &isnull;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- isnull= 0;
+- num= 88;
+- for (i= 0 ; i < 4 ; i++)
+- my_bind[i].is_null= &isnull;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "SELECT * FROM foo_dfr");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid resultset");
+-
+- FAIL_IF(mysql_num_rows(result) != 3, "rowcount != 3");
+-
+- mysql_data_seek(result, 0);
+-
+- row= mysql_fetch_row(result);
+- FAIL_IF(!row, "row = NULL");
+- for (i= 0 ; i < 4 ; i++)
+- {
+- FAIL_UNLESS(strcmp(row[i], "22") == 0, "Wrong value");
+- }
+- row= mysql_fetch_row(result);
+- FAIL_IF(!row, "Invalid row");
+- for (i= 0 ; i < 4 ; i++)
+- {
+- FAIL_UNLESS(row[i] == 0, "row[i] != 0");
+- }
+- row= mysql_fetch_row(result);
+- FAIL_IF(!row, "Invalid row");
+- for (i= 0 ; i < 4 ; i++)
+- {
+- FAIL_UNLESS(strcmp(row[i], "88") == 0, "row[i] != 88");
+- }
+- row= mysql_fetch_row(result);
+- FAIL_IF(row, "row != NULL");
+-
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-static int test_bug11037(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *stmt_text;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (id int not null)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (1)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "select id FROM t1";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- /* expected error */
+- rc = mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc==1, "Error expedted");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc==MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */
+-
+-static int test_bug11183(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- char bug_statement[]= "insert into t1 values (1)";
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, bug_statement, strlen(bug_statement));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- /* Trying to execute statement that should fail on execute stage */
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_reset(stmt);
+- FAIL_IF(!mysql_stmt_errno(stmt) == 0, "stmt->error != 0");
+-
+- rc= mysql_query(mysql, "create table t1 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- /* Trying to execute statement that should pass ok */
+- if (mysql_stmt_execute(stmt))
+- {
+- mysql_stmt_reset(stmt);
+- FAIL_IF(mysql_stmt_errno(stmt) == 0, "stmt->error != 0");
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug12744(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt = NULL;
+- int rc;
+-
+- stmt = mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SET @a:=1", 9);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* set reconnect, kill and ping to reconnect */
+- rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_kill(mysql, mysql_thread_id(mysql));
+- check_mysql_rc(rc, mysql);
+-
+- sleep(2);
+- rc= mysql_ping(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_close(stmt);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug1500(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[3];
+- int rc;
+- int32 int_data[3]= {2, 3, 4};
+- const char *data;
+- const char *query;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (i INT)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bg1500 VALUES (1), (2)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- query= "SELECT i FROM test_bg1500 WHERE i IN (?, ?, ?)";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 3, "paramcount != 3");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)int_data;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[2]= my_bind[1]= my_bind[0];
+- my_bind[1].buffer= (void *)(int_data + 1);
+- my_bind[2].buffer= (void *)(int_data + 2);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_bg1500");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (s VARCHAR(25), FULLTEXT(s)) engine=MyISAM");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "INSERT INTO test_bg1500 VALUES ('Gravedigger'), ('Greed'), ('Hollow Dogs')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (?)";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");
+-
+- data= "Dogs";
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *) data;
+- my_bind[0].buffer_length= strlen(data);
+- my_bind[0].is_null= 0;
+- my_bind[0].length= 0;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- /* This should work too */
+- query= "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (CONCAT(?, 'digger'))";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "paramcount != 1");
+-
+- data= "Grave";
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *) data;
+- my_bind[0].buffer_length= strlen(data);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug15510(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *query= "select 1 from dual where 1/0";
+-
+-
+- rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(mysql_warning_count(mysql), "Warning expected");
+-
+- /* Cleanup */
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "set @@sql_mode=''");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug #15518 - Reusing a stmt that has failed during prepare
+- does not clear error
+-*/
+-
+-static int test_bug15518(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- /*
+- The prepare of foo should fail with errno 1064 since
+- it's not a valid query
+- */
+- rc= mysql_stmt_prepare(stmt, "foo", 3);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
+-
+- /*
+- Use the same stmt and reprepare with another query that
+- suceeds
+- */
+- rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
+- FAIL_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql), "Error expected");
+-
+- rc= mysql_stmt_close(stmt);
+- check_mysql_rc(rc, mysql);
+- /*
+- part2, when connection to server has been closed
+- after first prepare
+- */
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, "foo", 3);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
+-
+- /* Close connection to server */
+- mysql_close(mysql);
+-
+- /*
+- Use the same stmt and reprepare with another query that
+- suceeds. The prepare should fail with error 2013 since
+- connection to server has been closed.
+- */
+- rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/*
+- Bug #15613: "libmysqlclient API function mysql_stmt_prepare returns wrong
+- field length"
+-*/
+-
+-static int test_bug15613(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- MYSQL_RES *metadata;
+- MYSQL_FIELD *field;
+- int rc;
+-
+- /* I. Prepare the table */
+- rc= mysql_query(mysql, "set names latin1");
+- check_mysql_rc(rc, mysql);
+- mysql_query(mysql, "drop table if exists t1");
+- rc= mysql_query(mysql,
+- "create table t1 (t text character set utf8, "
+- "tt tinytext character set utf8, "
+- "mt mediumtext character set utf8, "
+- "lt longtext character set utf8, "
+- "vl varchar(255) character set latin1,"
+- "vb varchar(255) character set binary,"
+- "vu varchar(255) character set utf8)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- /* II. Check SELECT metadata */
+- stmt_text= ("select t, tt, mt, lt, vl, vb, vu from t1");
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- metadata= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_fields(metadata);
+- FAIL_UNLESS(field[0].length == 65535, "length != 65535");
+- FAIL_UNLESS(field[1].length == 255, "length != 244");
+- FAIL_UNLESS(field[2].length == 16777215, "length != 166777215");
+- FAIL_UNLESS(field[3].length == 4294967295UL, "length != 4294967295UL");
+- FAIL_UNLESS(field[4].length == 255, "length != 255");
+- FAIL_UNLESS(field[5].length == 255, "length != 255");
+- FAIL_UNLESS(field[6].length == 255, "length != 255");
+- mysql_free_result(metadata);
+- mysql_stmt_free_result(stmt);
+-
+- /* III. Cleanup */
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "set names default");
+- check_mysql_rc(rc, mysql);
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug16144(MYSQL *mysql)
+-{
+- const my_bool flag_orig= (my_bool) 0xde;
+- my_bool flag= flag_orig;
+- MYSQL_STMT *stmt;
+-
+- /* Check that attr_get returns correct data on little and big endian CPUs */
+- stmt= mysql_stmt_init(mysql);
+- mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void*) &flag);
+- mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &flag);
+- FAIL_UNLESS(flag == flag_orig, "flag != flag_orig");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/*
+- This tests for various mysql_stmt_send_long_data bugs described in #1664
+-*/
+-
+-static int test_bug1664(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, int_data;
+- const char *data;
+- const char *str_data= "Simple string";
+- MYSQL_BIND my_bind[2];
+- const char *query= "INSERT INTO test_long_data(col2, col1) VALUES(?, ?)";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, col2 long varchar)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Param count != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)str_data;
+- my_bind[0].buffer_length= strlen(str_data);
+-
+- my_bind[1].buffer= (void *)&int_data;
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- int_data= 1;
+-
+- /*
+- Let us supply empty long_data. This should work and should
+- not break following execution.
+- */
+- data= "";
+- rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- if (verify_col_data(mysql, "test_long_data", "col1", "1"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", ""))
+- goto error;
+- rc= mysql_query(mysql, "DELETE FROM test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- /* This should pass OK */
+- data= (char *)"Data";
+- rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- if (verify_col_data(mysql, "test_long_data", "col1", "1"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", "Data"))
+- goto error;
+-
+- /* clean up */
+- rc= mysql_query(mysql, "DELETE FROM test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- Now we are changing int parameter and don't do anything
+- with first parameter. Second mysql_stmt_execute() should run
+- OK treating this first parameter as string parameter.
+- */
+-
+- int_data= 2;
+- /* execute */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- if (verify_col_data(mysql, "test_long_data", "col1", "2"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", str_data))
+- goto error;
+-
+- /* clean up */
+- rc= mysql_query(mysql, "DELETE FROM test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- /*
+- Now we are sending other long data. It should not be
+- concatened to previous.
+- */
+-
+- data= (char *)"SomeOtherData";
+- rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- if (verify_col_data(mysql, "test_long_data", "col1", "2"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", "SomeOtherData"))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+-
+- /* clean up */
+- rc= mysql_query(mysql, "DELETE FROM test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- /* Now let us test how mysql_stmt_reset works. */
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- data= (char *)"SomeData";
+- rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_reset(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- if (verify_col_data(mysql, "test_long_data", "col1", "2"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", str_data))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+-
+- /* Final clean up */
+- rc= mysql_query(mysql, "DROP TABLE test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-
+-error:
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "DROP TABLE test_long_data");
+- return FAIL;
+-}
+-/* Test a misc bug */
+-
+-static int test_ushort_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[4];
+- ushort short_value;
+- uint32 long_value;
+- ulong s_length, l_length, ll_length, t_length;
+- ulonglong longlong_value;
+- int rc;
+- uchar tiny_value;
+- const char *query= "SELECT * FROM test_ushort";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_ushort(a smallint unsigned, \
+- b smallint unsigned, \
+- c smallint unsigned, \
+- d smallint unsigned)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[0].buffer= (void *)&short_value;
+- my_bind[0].is_unsigned= TRUE;
+- my_bind[0].length= &s_length;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[1].buffer= (void *)&long_value;
+- my_bind[1].length= &l_length;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[2].buffer= (void *)&longlong_value;
+- my_bind[2].length= &ll_length;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[3].buffer= (void *)&tiny_value;
+- my_bind[3].is_unsigned= TRUE;
+- my_bind[3].length= &t_length;
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(short_value == 35999, "short_value != 35999");
+- FAIL_UNLESS(s_length == 2, "length != 2");
+-
+- FAIL_UNLESS(long_value == 35999, "long_value != 35999");
+- FAIL_UNLESS(l_length == 4, "length != 4");
+-
+- FAIL_UNLESS(longlong_value == 35999, "longlong_value != 35999");
+- FAIL_UNLESS(ll_length == 8, "length != 8");
+-
+- FAIL_UNLESS(tiny_value == 200, "tiny_value != 200");
+- FAIL_UNLESS(t_length == 1, "length != 1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug1946(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *query= "INSERT INTO prepare_command VALUES (?)";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS prepare_command");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, "CREATE TABLE prepare_command(ID INT)");
+- check_mysql_rc(rc, mysql)
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_real_query(mysql, query, strlen(query));
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "DROP TABLE prepare_command");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug20152(MYSQL *mysql)
+-{
+- MYSQL_BIND my_bind[1];
+- MYSQL_STMT *stmt;
+- MYSQL_TIME tm;
+- int rc;
+- const char *query= "INSERT INTO t1 (f1) VALUES (?)";
+-
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_DATE;
+- my_bind[0].buffer= (void*)&tm;
+-
+- tm.year = 2006;
+- tm.month = 6;
+- tm.day = 18;
+- tm.hour = 14;
+- tm.minute = 9;
+- tm.second = 42;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql)
+- rc= mysql_query(mysql, "CREATE TABLE t1 (f1 DATE)");
+- check_mysql_rc(rc, mysql)
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql)
+- FAIL_UNLESS(tm.hour == 14 && tm.minute == 9 && tm.second == 42, "time != 14:09:42");
+- return OK;
+-}
+-
+-static int test_bug2247(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *res;
+- int rc;
+- int i;
+- const char *create= "CREATE TABLE bug2247(id INT UNIQUE AUTO_INCREMENT)";
+- const char *insert= "INSERT INTO bug2247 VALUES (NULL)";
+- const char *SELECT= "SELECT id FROM bug2247";
+- const char *update= "UPDATE bug2247 SET id=id+10";
+- const char *drop= "DROP TABLE IF EXISTS bug2247";
+- ulonglong exp_count;
+- enum { NUM_ROWS= 5 };
+-
+-
+- /* create table and insert few rows */
+- rc= mysql_query(mysql, drop);
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, create);
+- check_mysql_rc(rc, mysql)
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, insert, strlen(insert));
+- check_stmt_rc(rc, stmt);
+- for (i= 0; i < NUM_ROWS; ++i)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+- exp_count= mysql_stmt_affected_rows(stmt);
+- FAIL_UNLESS(exp_count == 1, "exp_count != 1");
+-
+- rc= mysql_query(mysql, SELECT);
+- check_mysql_rc(rc, mysql)
+- /*
+- mysql_store_result overwrites mysql->affected_rows. Check that
+- mysql_stmt_affected_rows() returns the same value, whereas
+- mysql_affected_rows() value is correct.
+- */
+- res= mysql_store_result(mysql);
+- FAIL_IF(!res, "Invalid result set");
+-
+- FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
+- FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
+-
+- rc= mysql_query(mysql, update);
+- check_mysql_rc(rc, mysql)
+- FAIL_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS, "affected_rows != NUM_ROWS");
+- FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
+-
+- mysql_free_result(res);
+- mysql_stmt_close(stmt);
+-
+- /* check that mysql_stmt_store_result modifies mysql_stmt_affected_rows */
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, SELECT, strlen(SELECT));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt); rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt); exp_count= mysql_stmt_affected_rows(stmt);
+- FAIL_UNLESS(exp_count == NUM_ROWS, "exp_count != NUM_ROWS");
+-
+- rc= mysql_query(mysql, insert);
+- check_mysql_rc(rc, mysql)
+- FAIL_UNLESS(mysql_affected_rows(mysql) == 1, "affected_rows != 1");
+- FAIL_UNLESS(exp_count == mysql_stmt_affected_rows(stmt), "affected_rows != exp_count");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/*
+- Test for bug#2248 "mysql_fetch without prior mysql_stmt_execute hangs"
+-*/
+-
+-static int test_bug2248(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *query1= "SELECT DATABASE()";
+- const char *query2= "INSERT INTO test_bug2248 VALUES (10)";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bug2248");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bug2248 (id int)");
+- check_mysql_rc(rc, mysql)
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query1, strlen(query1));
+- check_stmt_rc(rc, stmt);
+-
+- /* This should not hang */
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- /* And this too */
+- rc= mysql_stmt_store_result(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query2, strlen(query2));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* This too should not hang but should return proper error */
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 1, "rc != 1");
+-
+- /* This too should not hang but should not bark */
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+- /* This should return proper error */
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 1, "rc != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_bug2248");
+- check_mysql_rc(rc, mysql)
+- return OK;
+-}
+-
+-/*
+- BUG#23383: mysql_affected_rows() returns different values than
+- mysql_stmt_affected_rows()
+-
+- Test that both mysql_affected_rows() and mysql_stmt_affected_rows()
+- return -1 on error, 0 when no rows were affected, and (positive) row
+- count when some rows were affected.
+-*/
+-static int test_bug23383(MYSQL *mysql)
+-{
+- const char *insert_query= "INSERT INTO t1 VALUES (1), (2)";
+- const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3";
+- MYSQL_STMT *stmt;
+- my_ulonglong row_count;
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, insert_query);
+- check_mysql_rc(rc, mysql);
+- row_count= mysql_affected_rows(mysql);
+- FAIL_UNLESS(row_count == 2, "row_count != 2");
+-
+- rc= mysql_query(mysql, insert_query);
+- FAIL_IF(!rc, "Error expected");
+- row_count= mysql_affected_rows(mysql);
+- FAIL_UNLESS(row_count == (my_ulonglong)-1, "rowcount != -1");
+-
+- rc= mysql_query(mysql, update_query);
+- check_mysql_rc(rc, mysql);
+- row_count= mysql_affected_rows(mysql);
+- FAIL_UNLESS(row_count == 0, "");
+-
+- rc= mysql_query(mysql, "DELETE FROM t1");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+-
+- rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- row_count= mysql_stmt_affected_rows(stmt);
+- FAIL_UNLESS(row_count == 2, "row_count != 2");
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_UNLESS(rc != 0, "");
+- row_count= mysql_stmt_affected_rows(stmt);
+- FAIL_UNLESS(row_count == (my_ulonglong)-1, "rowcount != -1");
+-
+- rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- row_count= mysql_stmt_affected_rows(stmt);
+- FAIL_UNLESS(row_count == 0, "rowcount != 0");
+-
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#27592 (stack overrun when storing datetime value using prepared statements)
+-*/
+-
+-static int test_bug27592(MYSQL *mysql)
+-{
+- const int NUM_ITERATIONS= 40;
+- int i;
+- int rc;
+- MYSQL_STMT *stmt= NULL;
+- MYSQL_BIND bind[1];
+- MYSQL_TIME time_val;
+-
+- mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- mysql_query(mysql, "CREATE TABLE t1(c2 DATETIME)");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "INSERT INTO t1 VALUES (?)", strlen("INSERT INTO t1 VALUES (?)"));
+- check_stmt_rc(rc, stmt);
+-
+- memset(bind, '\0', sizeof(bind));
+-
+- bind[0].buffer_type= MYSQL_TYPE_DATETIME;
+- bind[0].buffer= (char *) &time_val;
+- bind[0].length= NULL;
+-
+- for (i= 0; i < NUM_ITERATIONS; i++)
+- {
+- time_val.year= 2007;
+- time_val.month= 6;
+- time_val.day= 7;
+- time_val.hour= 18;
+- time_val.minute= 41;
+- time_val.second= 3;
+-
+- time_val.second_part=0;
+- time_val.neg=0;
+-
+- rc= mysql_stmt_bind_param(stmt, bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#28934: server crash when receiving malformed com_execute packets
+-*/
+-
+-static int test_bug28934(MYSQL *mysql)
+-{
+- my_bool error= 0;
+- MYSQL_BIND bind[5];
+- MYSQL_STMT *stmt;
+- int rc, cnt;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1(id int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values(1),(2),(3),(4),(5)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select * from t1 where id in(?,?,?,?,?)", strlen("select * from t1 where id in(?,?,?,?,?)"));
+- check_stmt_rc(rc, stmt);
+-
+- memset (&bind, '\0', sizeof (bind));
+- for (cnt= 0; cnt < 5; cnt++)
+- {
+- bind[cnt].buffer_type= MYSQL_TYPE_LONG;
+- bind[cnt].buffer= (char*)&cnt;
+- bind[cnt].buffer_length= 0;
+- }
+- rc= mysql_stmt_bind_param(stmt, bind);
+- check_stmt_rc(rc, stmt);
+-
+- stmt->param_count=2;
+- error= mysql_stmt_execute(stmt);
+- FAIL_UNLESS(error != 0, "Error expected");
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug3035(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- MYSQL_BIND bind_array[12], *my_bind= bind_array, *bind_end= my_bind + 12;
+- int8 int8_val;
+- uint8 uint8_val;
+- int16 int16_val;
+- uint16 uint16_val;
+- int32 int32_val;
+- uint32 uint32_val;
+- longlong int64_val;
+- ulonglong uint64_val;
+- double double_val, udouble_val, double_tmp;
+- char longlong_as_string[22], ulonglong_as_string[22];
+-
+- /* mins and maxes */
+- const int8 int8_min= -128;
+- const int8 int8_max= 127;
+- const uint8 uint8_min= 0;
+- const uint8 uint8_max= 255;
+-
+- const int16 int16_min= -32768;
+- const int16 int16_max= 32767;
+- const uint16 uint16_min= 0;
+- const uint16 uint16_max= 65535;
+-
+- const int32 int32_max= 2147483647L;
+- const int32 int32_min= -int32_max - 1;
+- const uint32 uint32_min= 0;
+- const uint32 uint32_max= 4294967295U;
+-
+- /* it might not work okay everyplace */
+- const longlong int64_max= 9223372036854775807LL;
+- const longlong int64_min= -int64_max - 1;
+-
+- const ulonglong uint64_min= 0U;
+- const ulonglong uint64_max= 18446744073709551615ULL;
+-
+- const char *stmt_text;
+-
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "CREATE TABLE t1 (i8 TINYINT, ui8 TINYINT UNSIGNED, "
+- "i16 SMALLINT, ui16 SMALLINT UNSIGNED, "
+- "i32 INT, ui32 INT UNSIGNED, "
+- "i64 BIGINT, ui64 BIGINT UNSIGNED, "
+- "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- memset(bind_array, '\0', sizeof(bind_array));
+- for (my_bind= bind_array; my_bind < bind_end; my_bind++)
+- my_bind->error= &my_bind->error_value;
+-
+- bind_array[0].buffer_type= MYSQL_TYPE_TINY;
+- bind_array[0].buffer= (void *) &int8_val;
+-
+- bind_array[1].buffer_type= MYSQL_TYPE_TINY;
+- bind_array[1].buffer= (void *) &uint8_val;
+- bind_array[1].is_unsigned= 1;
+-
+- bind_array[2].buffer_type= MYSQL_TYPE_SHORT;
+- bind_array[2].buffer= (void *) &int16_val;
+-
+- bind_array[3].buffer_type= MYSQL_TYPE_SHORT;
+- bind_array[3].buffer= (void *) &uint16_val;
+- bind_array[3].is_unsigned= 1;
+-
+- bind_array[4].buffer_type= MYSQL_TYPE_LONG;
+- bind_array[4].buffer= (void *) &int32_val;
+-
+- bind_array[5].buffer_type= MYSQL_TYPE_LONG;
+- bind_array[5].buffer= (void *) &uint32_val;
+- bind_array[5].is_unsigned= 1;
+-
+- bind_array[6].buffer_type= MYSQL_TYPE_LONGLONG;
+- bind_array[6].buffer= (void *) &int64_val;
+-
+- bind_array[7].buffer_type= MYSQL_TYPE_LONGLONG;
+- bind_array[7].buffer= (void *) &uint64_val;
+- bind_array[7].is_unsigned= 1;
+-
+- stmt= mysql_stmt_init(mysql);
+- check_stmt_rc(rc, stmt);
+-
+- stmt_text= "INSERT INTO t1 (i8, ui8, i16, ui16, i32, ui32, i64, ui64) "
+- "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_bind_param(stmt, bind_array);
+-
+- int8_val= int8_min;
+- uint8_val= uint8_min;
+- int16_val= int16_min;
+- uint16_val= uint16_min;
+- int32_val= int32_min;
+- uint32_val= uint32_min;
+- int64_val= int64_min;
+- uint64_val= uint64_min;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- int8_val= int8_max;
+- uint8_val= uint8_max;
+- int16_val= int16_max;
+- uint16_val= uint16_max;
+- int32_val= int32_max;
+- uint32_val= uint32_max;
+- int64_val= int64_max;
+- uint64_val= uint64_max;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- stmt_text= "SELECT i8, ui8, i16, ui16, i32, ui32, i64, ui64, ui64, "
+- "cast(ui64 as signed), ui64, cast(ui64 as signed)"
+- "FROM t1 ORDER BY id ASC";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- bind_array[8].buffer_type= MYSQL_TYPE_DOUBLE;
+- bind_array[8].buffer= (void *) &udouble_val;
+-
+- bind_array[9].buffer_type= MYSQL_TYPE_DOUBLE;
+- bind_array[9].buffer= (void *) &double_val;
+-
+- bind_array[10].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[10].buffer= (void *) &ulonglong_as_string;
+- bind_array[10].buffer_length= sizeof(ulonglong_as_string);
+-
+- bind_array[11].buffer_type= MYSQL_TYPE_STRING;
+- bind_array[11].buffer= (void *) &longlong_as_string;
+- bind_array[11].buffer_length= sizeof(longlong_as_string);
+-
+- mysql_stmt_bind_result(stmt, bind_array);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(int8_val == int8_min, "int8_val != int8_min");
+- FAIL_UNLESS(uint8_val == uint8_min, "uint8_val != uint8_min");
+- FAIL_UNLESS(int16_val == int16_min, "int16_val != int16_min");
+- FAIL_UNLESS(uint16_val == uint16_min, "uint16_val != uint16_min");
+- FAIL_UNLESS(int32_val == int32_min, "int32_val != int32_min");
+- FAIL_UNLESS(uint32_val == uint32_min, "uint32_val != uint32_min");
+- FAIL_UNLESS(int64_val == int64_min, "int64_val != int64_min");
+- FAIL_UNLESS(uint64_val == uint64_min, "uint64_val != uint64_min");
+- FAIL_UNLESS(double_val == (longlong) uint64_min, "double_val != uint64_min");
+- double_tmp= ulonglong2double(uint64_val);
+- FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
+- FAIL_UNLESS(!strcmp(longlong_as_string, "0"), "longlong_as_string != '0'");
+- FAIL_UNLESS(!strcmp(ulonglong_as_string, "0"), "ulonglong_as_string != '0'");
+-
+- rc= mysql_stmt_fetch(stmt);
+-
+- FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED || rc == 0, "rc != 0,MYSQL_DATA_TRUNCATED");
+-
+- FAIL_UNLESS(int8_val == int8_max, "int8_val != int8_max");
+- FAIL_UNLESS(uint8_val == uint8_max, "uint8_val != uint8_max");
+- FAIL_UNLESS(int16_val == int16_max, "int16_val != int16_max");
+- FAIL_UNLESS(uint16_val == uint16_max, "uint16_val != uint16_max");
+- FAIL_UNLESS(int32_val == int32_max, "int32_val != int32_max");
+- FAIL_UNLESS(uint32_val == uint32_max, "uint32_val != uint32_max");
+- FAIL_UNLESS(int64_val == int64_max, "int64_val != int64_max");
+- FAIL_UNLESS(uint64_val == uint64_max, "uint64_val != uint64_max");
+- FAIL_UNLESS(double_val == (longlong) uint64_val, "double_val != uint64_val");
+- double_tmp= ulonglong2double(uint64_val);
+- FAIL_UNLESS(cmp_double(&udouble_val,&double_tmp), "udouble_val != double_tmp");
+- FAIL_UNLESS(!strcmp(longlong_as_string, "-1"), "longlong_as_string != '-1'");
+- FAIL_UNLESS(!strcmp(ulonglong_as_string, "18446744073709551615"), "ulonglong_as_string != '18446744073709551615'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
+-
+- mysql_stmt_close(stmt);
+-
+- stmt_text= "DROP TABLE t1";
+- mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- return OK;
+-}
+-
+-/*
+- Test for BUG#3420 ("select id1, value1 from t where id= ? or value= ?"
+- returns all rows in the table)
+-*/
+-
+-static int test_ps_conj_select(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- MYSQL_BIND my_bind[2];
+- int32 int_data;
+- char str_data[32];
+- unsigned long str_length;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
+- "value2 varchar(100), value1 varchar(100))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
+- "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "select id1, value1 from t1 where id1= ? or "
+- "CONVERT(value1 USING utf8)= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
+-
+- /* Always bzero all members of bind parameter */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&int_data;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[1].buffer= (void *)str_data;
+- my_bind[1].buffer_length= array_elements(str_data);
+- my_bind[1].length= &str_length;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- int_data= 1;
+- strcpy(str_data, "hh");
+- str_length= strlen(str_data);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc=0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 3, "rc != 3");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test for NULL as PS parameter (BUG#3367, BUG#3371) */
+-
+-static int test_ps_null_param(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+-
+- MYSQL_BIND in_bind;
+- my_bool in_is_null;
+- long int in_long;
+-
+- MYSQL_BIND out_bind;
+- ulong out_length;
+- my_bool out_is_null;
+- char out_str_data[20];
+-
+- const char *queries[]= {"select ?", "select ?+1",
+- "select col1 from test_ps_nulls where col1 <=> ?",
+- NULL
+- };
+- const char **cur_query= queries;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ps_nulls");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_ps_nulls(col1 int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_ps_nulls values (1), (null)");
+- check_mysql_rc(rc, mysql);
+-
+- /* Always bzero all members of bind parameter */
+- memset(&in_bind, '\0', sizeof(in_bind));
+- memset(&out_bind, '\0', sizeof(out_bind));
+- in_bind.buffer_type= MYSQL_TYPE_LONG;
+- in_bind.is_null= &in_is_null;
+- in_bind.length= 0;
+- in_bind.buffer= (void *)&in_long;
+- in_is_null= 1;
+- in_long= 1;
+-
+- out_bind.buffer_type= MYSQL_TYPE_STRING;
+- out_bind.is_null= &out_is_null;
+- out_bind.length= &out_length;
+- out_bind.buffer= out_str_data;
+- out_bind.buffer_length= array_elements(out_str_data);
+-
+- /* Execute several queries, all returning NULL in result. */
+- for(cur_query= queries; *cur_query; cur_query++)
+- {
+- char query[MAX_TEST_QUERY_LENGTH];
+- strcpy(query, *cur_query);
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
+-
+- rc= mysql_stmt_bind_param(stmt, &in_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_result(stmt, &out_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc != MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- FAIL_UNLESS(out_is_null, "!out_is_null");
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- mysql_stmt_close(stmt);
+- }
+- return OK;
+-}
+-
+-/*
+- utility for the next test; expects 3 rows in the result from a SELECT,
+- compares each row/field with an expected value.
+- */
+-#define test_ps_query_cache_result(i1,s1,l1,i2,s2,l2,i3,s3,l3) \
+- r_metadata= mysql_stmt_result_metadata(stmt); \
+- FAIL_UNLESS(r_metadata != NULL, ""); \
+- rc= mysql_stmt_fetch(stmt); \
+- check_stmt_rc(rc,stmt); \
+- FAIL_UNLESS((r_int_data == i1) && (r_str_length == l1) && \
+- (strcmp(r_str_data, s1) == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt); \
+- check_stmt_rc(rc,stmt); \
+- FAIL_UNLESS((r_int_data == i2) && (r_str_length == l2) && \
+- (strcmp(r_str_data, s2) == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt); \
+- check_stmt_rc(rc,stmt); \
+- FAIL_UNLESS((r_int_data == i3) && (r_str_length == l3) && \
+- (strcmp(r_str_data, s3) == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt); \
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA"); \
+- mysql_free_result(r_metadata);
+-
+-/* reads Qcache_hits from server and returns its value */
+-static int query_cache_hits(MYSQL *mysql)
+-{
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- int rc;
+- uint result;
+-
+- rc= mysql_query(mysql, "show status like 'qcache_hits'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_use_result(mysql);
+-
+- row= mysql_fetch_row(res);
+-
+- result= atoi(row[1]);
+- mysql_free_result(res);
+- return result;
+-}
+-
+-
+-/*
+- Test that prepared statements make use of the query cache just as normal
+- statements (BUG#735).
+-*/
+-static int test_ps_query_cache(MYSQL *mysql)
+-{
+- MYSQL *lmysql= mysql;
+- MYSQL_STMT *stmt;
+- int rc;
+- MYSQL_BIND p_bind[2],r_bind[2]; /* p: param bind; r: result bind */
+- int32 p_int_data, r_int_data;
+- char p_str_data[32], r_str_data[32];
+- unsigned long p_str_length, r_str_length;
+- MYSQL_RES *r_metadata;
+- char query[MAX_TEST_QUERY_LENGTH];
+- uint hits1, hits2;
+- enum enum_test_ps_query_cache
+- {
+- /*
+- We iterate the same prepare/executes block, but have iterations where
+- we vary the query cache conditions.
+- */
+- /* the query cache is enabled for the duration of prep&execs: */
+- TEST_QCACHE_ON= 0,
+- /*
+- same but using a new connection (to see if qcache serves results from
+- the previous connection as it should):
+- */
+- TEST_QCACHE_ON_WITH_OTHER_CONN,
+- /*
+- First border case: disables the query cache before prepare and
+- re-enables it before execution (to test if we have no bug then):
+- */
+- TEST_QCACHE_OFF_ON,
+- /*
+- Second border case: enables the query cache before prepare and
+- disables it before execution:
+- */
+- TEST_QCACHE_ON_OFF
+- };
+- enum enum_test_ps_query_cache iteration;
+-
+-
+- /* prepare the table */
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
+- "value2 varchar(100), value1 varchar(100))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
+- "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
+- check_mysql_rc(rc, mysql);
+-
+- for (iteration= TEST_QCACHE_ON; iteration <= TEST_QCACHE_ON_OFF; iteration++)
+- {
+- switch (iteration) {
+- case TEST_QCACHE_ON:
+- case TEST_QCACHE_ON_OFF:
+- rc= mysql_query(lmysql, "set global query_cache_size=1000000");
+- check_mysql_rc(rc, mysql);
+- break;
+- case TEST_QCACHE_OFF_ON:
+- rc= mysql_query(lmysql, "set global query_cache_size=0");
+- check_mysql_rc(rc, mysql);
+- break;
+- case TEST_QCACHE_ON_WITH_OTHER_CONN:
+- lmysql= test_connect(NULL);
+- FAIL_IF(!lmysql, "Opening new connection failed");
+- break;
+- }
+-
+- strcpy(query, "select id1, value1 from t1 where id1= ? or "
+- "CONVERT(value1 USING utf8)= ?");
+- stmt= mysql_stmt_init(lmysql);
+- FAIL_IF(!stmt, mysql_error(lmysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
+-
+- switch (iteration) {
+- case TEST_QCACHE_OFF_ON:
+- rc= mysql_query(lmysql, "set global query_cache_size=1000000");
+- check_mysql_rc(rc, mysql);
+- break;
+- case TEST_QCACHE_ON_OFF:
+- rc= mysql_query(lmysql, "set global query_cache_size=0");
+- check_mysql_rc(rc, mysql);
+- default:
+- break;
+- }
+-
+- memset(p_bind, '\0', sizeof(p_bind));
+- p_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- p_bind[0].buffer= (void *)&p_int_data;
+- p_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- p_bind[1].buffer= (void *)p_str_data;
+- p_bind[1].buffer_length= array_elements(p_str_data);
+- p_bind[1].length= &p_str_length;
+-
+- rc= mysql_stmt_bind_param(stmt, p_bind);
+- check_stmt_rc(rc, stmt);
+- p_int_data= 1;
+- strcpy(p_str_data, "hh");
+- p_str_length= strlen(p_str_data);
+-
+- memset(r_bind, '\0', sizeof(r_bind));
+- r_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- r_bind[0].buffer= (void *)&r_int_data;
+- r_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- r_bind[1].buffer= (void *)r_str_data;
+- r_bind[1].buffer_length= array_elements(r_str_data);
+- r_bind[1].length= &r_str_length;
+-
+- rc= mysql_stmt_bind_result(stmt, r_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-// test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
+- r_metadata= mysql_stmt_result_metadata(stmt);
+- FAIL_UNLESS(r_metadata != NULL, "");
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+- FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
+- (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+- FAIL_UNLESS((r_int_data == 2) && (r_str_length == 2) &&
+- (strcmp(r_str_data, "hh") == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc,stmt);
+- FAIL_UNLESS((r_int_data == 1) && (r_str_length == 2) &&
+- (strcmp(r_str_data, "ii") == 0), "test_ps_query_cache_result failure"); \
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- mysql_free_result(r_metadata);
+-
+-
+- /* now retry with the same parameter values and see qcache hits */
+- hits1= query_cache_hits(lmysql);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt); test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
+- hits2= query_cache_hits(lmysql);
+- switch(iteration) {
+- case TEST_QCACHE_ON_WITH_OTHER_CONN:
+- case TEST_QCACHE_ON: /* should have hit */
+- FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1 + 1");
+- break;
+- case TEST_QCACHE_OFF_ON:
+- case TEST_QCACHE_ON_OFF: /* should not have hit */
+- FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
+- break;
+- }
+-
+- /* now modify parameter values and see qcache hits */
+- strcpy(p_str_data, "ii");
+- p_str_length= strlen(p_str_data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
+- hits1= query_cache_hits(lmysql);
+-
+- switch(iteration) {
+- case TEST_QCACHE_ON:
+- case TEST_QCACHE_OFF_ON:
+- case TEST_QCACHE_ON_OFF: /* should not have hit */
+- FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
+- break;
+- case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
+- FAIL_UNLESS(hits1-hits2 == 1, "hits2 != hits1+1");
+- break;
+- }
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
+- hits2= query_cache_hits(lmysql);
+-
+- mysql_stmt_close(stmt);
+-
+- switch(iteration) {
+- case TEST_QCACHE_ON: /* should have hit */
+- FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
+- break;
+- case TEST_QCACHE_OFF_ON:
+- case TEST_QCACHE_ON_OFF: /* should not have hit */
+- FAIL_UNLESS(hits2-hits1 == 0, "hits2 != hits1");
+- break;
+- case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
+- FAIL_UNLESS(hits2-hits1 == 1, "hits2 != hits1+1");
+- break;
+- }
+-
+- } /* for(iteration=...) */
+-
+- if (lmysql != mysql)
+- mysql_close(lmysql);
+-
+- rc= mysql_query(mysql, "set global query_cache_size=0");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug3117(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND buffer;
+- longlong lii;
+- ulong length;
+- my_bool is_null;
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1 (id int auto_increment primary key)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT LAST_INSERT_ID()", strlen("SELECT LAST_INSERT_ID()"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- memset(&buffer, '\0', sizeof(buffer));
+- buffer.buffer_type= MYSQL_TYPE_LONGLONG;
+- buffer.buffer_length= sizeof(lii);
+- buffer.buffer= (void *)&lii;
+- buffer.length= &length;
+- buffer.is_null= &is_null;
+-
+- rc= mysql_stmt_bind_result(stmt, &buffer);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(is_null == 0 && lii == 1, "is_null != 0 || lii != 1");
+-
+- rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(is_null == 0 && lii == 2, "is_null != 0 || lii != 2");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/**
+- Bug#36004 mysql_stmt_prepare resets the list of warnings
+-*/
+-
+-static int test_bug36004(MYSQL *mysql)
+-{
+- int rc, warning_count= 0;
+- MYSQL_STMT *stmt;
+-
+-
+- if (mysql_get_server_version(mysql) < 60000) {
+- diag("Test requires MySQL Server version 6.0 or above");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "drop table if exists inexistant");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_UNLESS(mysql_warning_count(mysql) == 1, "");
+- query_int_variable(mysql, "@@warning_count", &warning_count);
+- FAIL_UNLESS(warning_count, "Warning expected");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select 1", strlen("select 1"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
+- query_int_variable(mysql, "@@warning_count", &warning_count);
+- FAIL_UNLESS(warning_count, "warning expected");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(mysql_warning_count(mysql) == 0, "No warning expected");
+- mysql_stmt_close(stmt);
+-
+- query_int_variable(mysql, "@@warning_count", &warning_count);
+- FAIL_UNLESS(warning_count, "Warning expected");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "drop table if exists inexistant", strlen("drop table if exists inexistant"));
+- check_stmt_rc(rc, stmt);
+-
+- query_int_variable(mysql, "@@warning_count", &warning_count);
+- FAIL_UNLESS(warning_count == 0, "No warning expected");
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug3796(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- const char *concat_arg0= "concat_with_";
+- enum { OUT_BUFF_SIZE= 30 };
+- char out_buff[OUT_BUFF_SIZE];
+- char canonical_buff[OUT_BUFF_SIZE];
+- ulong out_length;
+- const char *stmt_text;
+- int rc;
+-
+-
+- /* Create and fill test table */
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "CREATE TABLE t1 (a INT, b VARCHAR(30))";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "INSERT INTO t1 VALUES(1, 'ONE'), (2, 'TWO')";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- /* Create statement handle and prepare it with select */
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT concat(?, b) FROM t1";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- /* Bind input buffers */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *) concat_arg0;
+- my_bind[0].buffer_length= strlen(concat_arg0);
+-
+- mysql_stmt_bind_param(stmt, my_bind);
+-
+- /* Execute the select statement */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- my_bind[0].buffer= (void *) out_buff;
+- my_bind[0].buffer_length= OUT_BUFF_SIZE;
+- my_bind[0].length= &out_length;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- strcpy(canonical_buff, concat_arg0);
+- strcat(canonical_buff, "ONE");
+- FAIL_UNLESS(strlen(canonical_buff) == out_length &&
+- strncmp(out_buff, canonical_buff, out_length) == 0, "");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- strcpy(canonical_buff + strlen(concat_arg0), "TWO");
+- FAIL_UNLESS(strlen(canonical_buff) == out_length &&
+- strncmp(out_buff, canonical_buff, out_length) == 0, "");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug4026(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- MYSQL_TIME time_in, time_out;
+- MYSQL_TIME datetime_in, datetime_out;
+- const char *stmt_text;
+- int rc;
+-
+-
+- /* Check that microseconds are inserted and selected successfully */
+-
+- /* Create a statement handle and prepare it with select */
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT ?, ?";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- /* Bind input buffers */
+- memset(my_bind, '\0', sizeof(my_bind));
+- memset(&time_in, '\0', sizeof(time_in));
+- memset(&time_out, '\0', sizeof(time_out));
+- memset(&datetime_in, '\0', sizeof(datetime_in));
+- memset(&datetime_out, '\0', sizeof(datetime_out));
+- my_bind[0].buffer_type= MYSQL_TYPE_TIME;
+- my_bind[0].buffer= (void *) &time_in;
+- my_bind[1].buffer_type= MYSQL_TYPE_DATETIME;
+- my_bind[1].buffer= (void *) &datetime_in;
+-
+- time_in.hour= 23;
+- time_in.minute= 59;
+- time_in.second= 59;
+- time_in.second_part= 123456;
+- /*
+- This is not necessary, just to make DIE_UNLESS below work: this field
+- is filled in when time is received from server
+- */
+- time_in.time_type= MYSQL_TIMESTAMP_TIME;
+-
+- datetime_in= time_in;
+- datetime_in.year= 2003;
+- datetime_in.month= 12;
+- datetime_in.day= 31;
+- datetime_in.time_type= MYSQL_TIMESTAMP_DATETIME;
+-
+- mysql_stmt_bind_param(stmt, my_bind);
+-
+- /* Execute the select statement */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- my_bind[0].buffer= (void *) &time_out;
+- my_bind[1].buffer= (void *) &datetime_out;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- FAIL_UNLESS(memcmp(&time_in, &time_out, sizeof(time_in)) == 0, "time_in != time_out");
+- FAIL_UNLESS(memcmp(&datetime_in, &datetime_out, sizeof(datetime_in)) == 0, "datetime_in != datetime_out");
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug4030(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[3];
+- MYSQL_TIME time_canonical, time_out;
+- MYSQL_TIME date_canonical, date_out;
+- MYSQL_TIME datetime_canonical, datetime_out;
+- const char *stmt_text;
+- int rc;
+-
+-
+- /* Check that microseconds are inserted and selected successfully */
+-
+- /* Execute a query with time values in prepared mode */
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT '23:59:59.123456', '2003-12-31', "
+- "'2003-12-31 23:59:59.123456'";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* Bind output buffers */
+- memset(my_bind, '\0', sizeof(my_bind));
+- memset(&time_canonical, '\0', sizeof(time_canonical));
+- memset(&time_out, '\0', sizeof(time_out));
+- memset(&date_canonical, '\0', sizeof(date_canonical));
+- memset(&date_out, '\0', sizeof(date_out));
+- memset(&datetime_canonical, '\0', sizeof(datetime_canonical));
+- memset(&datetime_out, '\0', sizeof(datetime_out));
+- my_bind[0].buffer_type= MYSQL_TYPE_TIME;
+- my_bind[0].buffer= (void *) &time_out;
+- my_bind[1].buffer_type= MYSQL_TYPE_DATE;
+- my_bind[1].buffer= (void *) &date_out;
+- my_bind[2].buffer_type= MYSQL_TYPE_DATETIME;
+- my_bind[2].buffer= (void *) &datetime_out;
+-
+- time_canonical.hour= 23;
+- time_canonical.minute= 59;
+- time_canonical.second= 59;
+- time_canonical.second_part= 123456;
+- time_canonical.time_type= MYSQL_TIMESTAMP_TIME;
+-
+- date_canonical.year= 2003;
+- date_canonical.month= 12;
+- date_canonical.day= 31;
+- date_canonical.time_type= MYSQL_TIMESTAMP_DATE;
+-
+- datetime_canonical= time_canonical;
+- datetime_canonical.year= 2003;
+- datetime_canonical.month= 12;
+- datetime_canonical.day= 31;
+- datetime_canonical.time_type= MYSQL_TIMESTAMP_DATETIME;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- FAIL_UNLESS(memcmp(&time_canonical, &time_out, sizeof(time_out)) == 0, "time_canonical != time_out");
+- FAIL_UNLESS(memcmp(&date_canonical, &date_out, sizeof(date_out)) == 0, "date_canoncical != date_out");
+- FAIL_UNLESS(memcmp(&datetime_canonical, &datetime_out, sizeof(datetime_out)) == 0, "datetime_canonical != datetime_out");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug4079(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- const char *stmt_text;
+- uint32 res;
+- int rc;
+-
+- /* Create and fill table */
+- mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- mysql_query(mysql, "CREATE TABLE t1 (a int)");
+- mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2)");
+-
+- /* Prepare erroneous statement */
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT 1 < (SELECT a FROM t1)";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- /* Execute the select statement */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* Bind input buffers */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *) &res;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- /* buggy version of libmysql hanged up here */
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug4172(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[3];
+- const char *stmt_text;
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- int rc;
+- char f[100], d[100], e[100];
+- ulong f_len, d_len, e_len;
+-
+-
+- mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- mysql_query(mysql, "CREATE TABLE t1 (f float, d double, e decimal(10,4))");
+- mysql_query(mysql, "INSERT INTO t1 VALUES (12345.1234, 123456.123456, "
+- "123456.1234)");
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT f, d, e FROM t1";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= f;
+- my_bind[0].buffer_length= sizeof(f);
+- my_bind[0].length= &f_len;
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= d;
+- my_bind[1].buffer_length= sizeof(d);
+- my_bind[1].length= &d_len;
+- my_bind[2].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[2].buffer= e;
+- my_bind[2].buffer_length= sizeof(e);
+- my_bind[2].length= &e_len;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- mysql_stmt_store_result(stmt);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- row= mysql_fetch_row(res);
+-
+- diag("expected %s %s %s", row[0], row[1], row[2]);
+- FAIL_UNLESS(!strcmp(f, row[0]) && !strcmp(d, row[1]) && !strcmp(e, row[2]), "");
+-
+- mysql_free_result(res);
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug4231(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- MYSQL_TIME tm[2];
+- const char *stmt_text;
+- int rc;
+-
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "CREATE TABLE t1 (a int)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "INSERT INTO t1 VALUES (1)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT a FROM t1 WHERE ? = ?";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- /* Bind input buffers */
+- memset(my_bind, '\0', sizeof(my_bind)); memset(tm, '\0', sizeof(tm));
+- my_bind[0].buffer_type= MYSQL_TYPE_DATE;
+- my_bind[0].buffer= &tm[0];
+- my_bind[1].buffer_type= MYSQL_TYPE_DATE;
+- my_bind[1].buffer= &tm[1];
+-
+- mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- /*
+- First set server-side params to some non-zero non-equal values:
+- then we will check that they are not used when client sends
+- new (zero) times.
+- */
+- tm[0].time_type = MYSQL_TIMESTAMP_DATE;
+- tm[0].year = 2000;
+- tm[0].month = 1;
+- tm[0].day = 1;
+- tm[1]= tm[0];
+- --tm[1].year; /* tm[0] != tm[1] */
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+-
+- /* binds are unequal, no rows should be returned */
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* Set one of the dates to zero */
+- tm[0].year= tm[0].month= tm[0].day= 0;
+- tm[1]= tm[0];
+- mysql_stmt_execute(stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+-
+- mysql_stmt_close(stmt);
+- stmt_text= "DROP TABLE t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug4236(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt, *stmt1;
+- const char *stmt_text;
+- int rc;
+- MYSQL_STMT backup;
+- MYSQL *mysql1;
+-
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- /* mysql_stmt_execute() of statement with statement id= 0 crashed server */
+- stmt_text= "SELECT 1";
+- /* We need to prepare statement to pass by possible check in libmysql */
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt); /* Hack to check that server works OK if statement wasn't found */
+- backup.stmt_id= stmt->stmt_id;
+- stmt->stmt_id= 0;
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- /* lets try to hack with a new connection */
+- mysql1= test_connect(NULL);
+- stmt1= mysql_stmt_init(mysql1);
+- stmt_text= "SELECT 2";
+- rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- stmt->stmt_id= stmt1->stmt_id;
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Error expected");
+-
+- mysql_stmt_close(stmt1);
+- mysql_close(mysql1);
+-
+- /* Restore original statement id to be able to reprepare it */
+- stmt->stmt_id= backup.stmt_id;
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug5126(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- int32 c1, c2;
+- const char *stmt_text;
+- int rc;
+-
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "CREATE TABLE t1 (a mediumint, b int)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "INSERT INTO t1 VALUES (8386608, 1)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT a, b FROM t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- /* Bind output buffers */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= &c1;
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[1].buffer= &c2;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- FAIL_UNLESS(c1 == 8386608 && c2 == 1, "c1 != 8386608 || c2 != 1");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug5194(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND *my_bind;
+- char *query;
+- char *param_str;
+- int param_str_length;
+- const char *stmt_text;
+- int rc;
+- float float_array[250] =
+- {
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25,
+- 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25
+- };
+- float *fa_ptr= float_array;
+- /* Number of columns per row */
+- const int COLUMN_COUNT= sizeof(float_array)/sizeof(*float_array);
+- /* Number of rows per bulk insert to start with */
+- const int MIN_ROWS_PER_INSERT= 262;
+- /* Max number of rows per bulk insert to end with */
+- const int MAX_ROWS_PER_INSERT= 300;
+- const int MAX_PARAM_COUNT= COLUMN_COUNT*MAX_ROWS_PER_INSERT;
+- const char *query_template= "insert into t1 values %s";
+- const int CHARS_PER_PARAM= 5; /* space needed to place ", ?" in the query */
+- const int uint16_max= 65535;
+- int nrows, i;
+-
+-
+- stmt_text= "drop table if exists t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+-
+- stmt_text= "create table if not exists t1"
+- "(c1 float, c2 float, c3 float, c4 float, c5 float, c6 float, "
+- "c7 float, c8 float, c9 float, c10 float, c11 float, c12 float, "
+- "c13 float, c14 float, c15 float, c16 float, c17 float, c18 float, "
+- "c19 float, c20 float, c21 float, c22 float, c23 float, c24 float, "
+- "c25 float, c26 float, c27 float, c28 float, c29 float, c30 float, "
+- "c31 float, c32 float, c33 float, c34 float, c35 float, c36 float, "
+- "c37 float, c38 float, c39 float, c40 float, c41 float, c42 float, "
+- "c43 float, c44 float, c45 float, c46 float, c47 float, c48 float, "
+- "c49 float, c50 float, c51 float, c52 float, c53 float, c54 float, "
+- "c55 float, c56 float, c57 float, c58 float, c59 float, c60 float, "
+- "c61 float, c62 float, c63 float, c64 float, c65 float, c66 float, "
+- "c67 float, c68 float, c69 float, c70 float, c71 float, c72 float, "
+- "c73 float, c74 float, c75 float, c76 float, c77 float, c78 float, "
+- "c79 float, c80 float, c81 float, c82 float, c83 float, c84 float, "
+- "c85 float, c86 float, c87 float, c88 float, c89 float, c90 float, "
+- "c91 float, c92 float, c93 float, c94 float, c95 float, c96 float, "
+- "c97 float, c98 float, c99 float, c100 float, c101 float, c102 float, "
+- "c103 float, c104 float, c105 float, c106 float, c107 float, c108 float, "
+- "c109 float, c110 float, c111 float, c112 float, c113 float, c114 float, "
+- "c115 float, c116 float, c117 float, c118 float, c119 float, c120 float, "
+- "c121 float, c122 float, c123 float, c124 float, c125 float, c126 float, "
+- "c127 float, c128 float, c129 float, c130 float, c131 float, c132 float, "
+- "c133 float, c134 float, c135 float, c136 float, c137 float, c138 float, "
+- "c139 float, c140 float, c141 float, c142 float, c143 float, c144 float, "
+- "c145 float, c146 float, c147 float, c148 float, c149 float, c150 float, "
+- "c151 float, c152 float, c153 float, c154 float, c155 float, c156 float, "
+- "c157 float, c158 float, c159 float, c160 float, c161 float, c162 float, "
+- "c163 float, c164 float, c165 float, c166 float, c167 float, c168 float, "
+- "c169 float, c170 float, c171 float, c172 float, c173 float, c174 float, "
+- "c175 float, c176 float, c177 float, c178 float, c179 float, c180 float, "
+- "c181 float, c182 float, c183 float, c184 float, c185 float, c186 float, "
+- "c187 float, c188 float, c189 float, c190 float, c191 float, c192 float, "
+- "c193 float, c194 float, c195 float, c196 float, c197 float, c198 float, "
+- "c199 float, c200 float, c201 float, c202 float, c203 float, c204 float, "
+- "c205 float, c206 float, c207 float, c208 float, c209 float, c210 float, "
+- "c211 float, c212 float, c213 float, c214 float, c215 float, c216 float, "
+- "c217 float, c218 float, c219 float, c220 float, c221 float, c222 float, "
+- "c223 float, c224 float, c225 float, c226 float, c227 float, c228 float, "
+- "c229 float, c230 float, c231 float, c232 float, c233 float, c234 float, "
+- "c235 float, c236 float, c237 float, c238 float, c239 float, c240 float, "
+- "c241 float, c242 float, c243 float, c244 float, c245 float, c246 float, "
+- "c247 float, c248 float, c249 float, c250 float)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- my_bind= (MYSQL_BIND*) malloc(MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
+- query= (char*) malloc(strlen(query_template) +
+- MAX_PARAM_COUNT * CHARS_PER_PARAM + 1);
+- param_str= (char*) malloc(COLUMN_COUNT * CHARS_PER_PARAM);
+-
+- FAIL_IF(my_bind == 0 || query == 0 || param_str == 0, "Not enought memory")
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- /* setup a template for one row of parameters */
+- sprintf(param_str, "(");
+- for (i= 1; i < COLUMN_COUNT; ++i)
+- strcat(param_str, "?, ");
+- strcat(param_str, "?)");
+- param_str_length= strlen(param_str);
+-
+- /* setup bind array */
+- memset(my_bind, '\0', MAX_PARAM_COUNT * sizeof(MYSQL_BIND));
+- for (i= 0; i < MAX_PARAM_COUNT; ++i)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[i].buffer= fa_ptr;
+- if (++fa_ptr == float_array + COLUMN_COUNT)
+- fa_ptr= float_array;
+- }
+-
+- /*
+- Test each number of rows per bulk insert, so that we can see where
+- MySQL fails.
+- */
+- for (nrows= MIN_ROWS_PER_INSERT; nrows <= MAX_ROWS_PER_INSERT; ++nrows)
+- {
+- char *query_ptr;
+- /* Create statement text for current number of rows */
+- sprintf(query, query_template, param_str);
+- query_ptr= query + strlen(query);
+- for (i= 1; i < nrows; ++i)
+- {
+- memcpy(query_ptr, ", ", 2);
+- query_ptr+= 2;
+- memcpy(query_ptr, param_str, param_str_length);
+- query_ptr+= param_str_length;
+- }
+- *query_ptr= '\0';
+-
+- rc= mysql_stmt_prepare(stmt, query, query_ptr - query);
+-
+- if (rc && nrows * COLUMN_COUNT > uint16_max) /* expected error */
+- break;
+-
+- check_stmt_rc(rc, stmt);
+-
+- /* bind the parameter array and execute the query */
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_reset(stmt);
+- }
+-
+- free(param_str);
+- free(query);
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+- free(my_bind);
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_bug5315(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- int rc;
+-
+-
+- stmt_text= "SELECT 1";
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_change_user(mysql, username, password, schema);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_UNLESS(rc != 0, "Error expected");
+-
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug5399(MYSQL *mysql)
+-{
+- /*
+- Ascii 97 is 'a', which gets mapped to Ascii 65 'A' unless internal
+- statement id hash in the server uses binary collation.
+- */
+-#define NUM_OF_USED_STMT 97
+- MYSQL_STMT *stmt_list[NUM_OF_USED_STMT];
+- MYSQL_STMT **stmt;
+- MYSQL_BIND my_bind[1];
+- char buff[600];
+- int rc;
+- int32 no;
+-
+-
+- memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= &no;
+-
+- for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
+- {
+- sprintf(buff, "select %d", (int) (stmt - stmt_list));
+- *stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(*stmt, buff, strlen(buff));
+- check_stmt_rc(rc, *stmt); mysql_stmt_bind_result(*stmt, my_bind);
+- }
+-
+- for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
+- {
+- rc= mysql_stmt_execute(*stmt);
+- check_stmt_rc(rc, *stmt);
+- rc= mysql_stmt_store_result(*stmt);
+- check_stmt_rc(rc, *stmt);
+- rc= mysql_stmt_fetch(*stmt);
+- FAIL_UNLESS((int32) (stmt - stmt_list) == no, "");
+- }
+-
+- for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
+- mysql_stmt_close(*stmt);
+-#undef NUM_OF_USED_STMT
+- return OK;
+-}
+-
+-static int test_bug6046(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- int rc;
+- short b= 1;
+- MYSQL_BIND my_bind[1];
+-
+-
+- stmt_text= "DROP TABLE IF EXISTS t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "CREATE TABLE t1 (a int, b int)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "INSERT INTO t1 VALUES (1,1),(2,2),(3,1),(4,2)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 "
+- "WHERE t1.b > ? ORDER BY t1.a";
+-
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- b= 1;
+- memset(my_bind, '\0', sizeof(my_bind)); my_bind[0].buffer= &b;
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+-
+- mysql_stmt_bind_param(stmt, my_bind);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_store_result(stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug6049(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- const char *stmt_text;
+- char buffer[30];
+- ulong length;
+- int rc;
+-
+-
+- stmt_text= "SELECT MAKETIME(-25, 12, 12)";
+-
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- row= mysql_fetch_row(res);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type = MYSQL_TYPE_STRING;
+- my_bind[0].buffer = &buffer;
+- my_bind[0].buffer_length = sizeof(buffer);
+- my_bind[0].length = &length;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(row[0], (char*) buffer) == 0, "row[0] != buffer");
+-
+- mysql_free_result(res);
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug6058(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- const char *stmt_text;
+- char buffer[30];
+- ulong length;
+- int rc;
+-
+-
+- stmt_text= "SELECT CAST('0000-00-00' AS DATE)";
+-
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- row= mysql_fetch_row(res);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type = MYSQL_TYPE_STRING;
+- my_bind[0].buffer = &buffer;
+- my_bind[0].buffer_length = sizeof(buffer);
+- my_bind[0].length = &length;
+-
+- mysql_stmt_bind_result(stmt, my_bind);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(row[0], buffer) == 0, "row[0] != buffer");
+-
+- mysql_free_result(res);
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-static int test_bug6059(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *stmt_text;
+- int rc;
+-
+- stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'";
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(mysql_stmt_field_count(stmt) == 0, "");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug6096(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *query_result, *stmt_metadata;
+- const char *stmt_text;
+- MYSQL_BIND my_bind[12];
+- MYSQL_FIELD *query_field_list, *stmt_field_list;
+- ulong query_field_count, stmt_field_count;
+- int rc;
+- my_bool update_max_length= TRUE;
+- uint i;
+-
+-
+- stmt_text= "drop table if exists t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- mysql_query(mysql, "set sql_mode=''");
+- stmt_text= "create table t1 (c_tinyint tinyint, c_smallint smallint, "
+- " c_mediumint mediumint, c_int int, "
+- " c_bigint bigint, c_float float, "
+- " c_double double, c_varchar varchar(20), "
+- " c_char char(20), c_time time, c_date date, "
+- " c_datetime datetime)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "insert into t1 values (-100, -20000, 30000000, 4, 8, 1.0, "
+- "2.0, 'abc', 'def', now(), now(), now())";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "select * from t1";
+-
+- /* Run select in prepared and non-prepared mode and compare metadata */
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- query_result= mysql_store_result(mysql);
+- query_field_list= mysql_fetch_fields(query_result);
+- query_field_count= mysql_num_fields(query_result);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt); mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
+- (void*) &update_max_length);
+- mysql_stmt_store_result(stmt);
+- stmt_metadata= mysql_stmt_result_metadata(stmt);
+- stmt_field_list= mysql_fetch_fields(stmt_metadata);
+- stmt_field_count= mysql_num_fields(stmt_metadata);
+- FAIL_UNLESS(stmt_field_count == query_field_count, "");
+-
+-
+- /* Bind and fetch the data */
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < stmt_field_count; ++i)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[i].buffer_length= stmt_field_list[i].max_length + 1;
+- my_bind[i].buffer= malloc(my_bind[i].buffer_length);
+- }
+- mysql_stmt_bind_result(stmt, my_bind);
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* Clean up */
+-
+- for (i= 0; i < stmt_field_count; ++i)
+- free(my_bind[i].buffer);
+- mysql_stmt_close(stmt);
+- mysql_free_result(query_result);
+- mysql_free_result(stmt_metadata);
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Bug#7990 - mysql_stmt_close doesn't reset mysql->net.last_error */
+-
+-static int test_bug7990(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, "foo", 3);
+- /*
+- XXX: the fact that we store errno both in STMT and in
+- MYSQL is not documented and is subject to change in 5.0
+- */
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql), "Error expected");
+- mysql_stmt_close(stmt);
+- FAIL_UNLESS(!mysql_errno(mysql), "errno != 0");
+- return OK;
+-}
+-
+-/* Bug#8330 - mysql_stmt_execute crashes (libmysql) */
+-
+-static int test_bug8330(MYSQL *mysql)
+-{
+- const char *stmt_text;
+- MYSQL_STMT *stmt[2];
+- int i, rc;
+- const char *query= "select a,b from t1 where a=?";
+- MYSQL_BIND my_bind[2];
+- long lval[2];
+-
+- stmt_text= "drop table if exists t1";
+- /* in case some previos test failed */
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "create table t1 (a int, b int)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i=0; i < 2; i++)
+- {
+- stmt[i]= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt[i], query, strlen(query));
+- check_stmt_rc(rc, stmt[i]);
+- my_bind[i].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[i].buffer= (void*) &lval[i];
+- my_bind[i].is_null= 0;
+- mysql_stmt_bind_param(stmt[i], &my_bind[i]);
+- }
+-
+- rc= mysql_stmt_execute(stmt[0]);
+- check_stmt_rc(rc, stmt[0]);
+- rc= mysql_stmt_execute(stmt[1]);
+- FAIL_UNLESS(rc && mysql_stmt_errno(stmt[1]) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
+- rc= mysql_stmt_execute(stmt[0]);
+- check_stmt_rc(rc, stmt[0]);
+- mysql_stmt_close(stmt[0]);
+- mysql_stmt_close(stmt[1]);
+-
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test misc field information, bug: #74 */
+-
+-static int test_field_misc(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "SELECT @@autocommit");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- verify_prepare_field(result, 0,
+- "@@autocommit", "", /* field and its org name */
+- MYSQL_TYPE_LONGLONG, /* field type */
+- "", "", /* table and its org name */
+- "", 1, 0); /* db name, length(its bool flag)*/
+-
+- mysql_free_result(result);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT @@autocommit", strlen("SELECT @@autocommit"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- verify_prepare_field(result, 0,
+- "@@autocommit", "", /* field and its org name */
+- MYSQL_TYPE_LONGLONG, /* field type */
+- "", "", /* table and its org name */
+- "", 1, 0); /* db name, length(its bool flag)*/
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT @@max_error_count", strlen("SELECT @@max_error_count"));
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- if (verify_prepare_field(result, 0,
+- "@@max_error_count", "", /* field and its org name */
+- MYSQL_TYPE_LONGLONG, /* field type */
+- "", "", /* table and its org name */
+- /* db name, length */
+- "", MY_INT64_NUM_DECIMAL_DIGITS , 0))
+- goto error;
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT @@max_allowed_packet", strlen("SELECT @@max_allowed_packet"));
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- if (verify_prepare_field(result, 0,
+- "@@max_allowed_packet", "", /* field and its org name */
+- MYSQL_TYPE_LONGLONG, /* field type */
+- "", "", /* table and its org name */
+- /* db name, length */
+- "", MY_INT64_NUM_DECIMAL_DIGITS, 0))
+- goto error;
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT @@sql_warnings", strlen("SELECT @@sql_warnings"));
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- if (verify_prepare_field(result, 0,
+- "@@sql_warnings", "", /* field and its org name */
+- MYSQL_TYPE_LONGLONG, /* field type */
+- "", "", /* table and its org name */
+- "", 1, 0)) /* db name, length */
+- goto error;
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+- return OK;
+-
+-error:
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+- return FAIL;
+-}
+-
+-/* Test a memory ovverun bug */
+-
+-static int test_mem_overun(MYSQL *mysql)
+-{
+- char buffer[10000], field[12];
+- MYSQL_STMT *stmt;
+- MYSQL_RES *field_res, *res;
+- int rc, i, length;
+-
+- /*
+- Test a memory ovverun bug when a table had 1000 fields with
+- a row of data
+- */
+- rc= mysql_query(mysql, "drop table if exists t_mem_overun");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(buffer, "create table t_mem_overun(");
+- for (i= 0; i < 1000; i++)
+- {
+- sprintf(field, "c%d int, ", i);
+- strcat(buffer, field);
+- }
+- length= strlen(buffer);
+- buffer[length-2]= ')';
+- buffer[--length]= '\0';
+-
+- rc= mysql_real_query(mysql, buffer, length);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(buffer, "insert into t_mem_overun values(");
+- for (i= 0; i < 1000; i++)
+- {
+- strcat(buffer, "1, ");
+- }
+- length= strlen(buffer);
+- buffer[length-2]= ')';
+- buffer[--length]= '\0';
+-
+- rc= mysql_real_query(mysql, buffer, length);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "select * from t_mem_overun");
+- check_mysql_rc(rc, mysql);
+-
+- res= mysql_store_result(mysql);
+- rc= 0;
+- while (mysql_fetch_row(res))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- mysql_free_result(res);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select * from t_mem_overun", strlen("select * from t_mem_overun"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- field_res= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!field_res, "Invalid result set");
+-
+- FAIL_UNLESS( 1000 == mysql_num_fields(field_res), "fields != 1000");
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
+-
+- mysql_free_result(field_res);
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug8722(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *stmt_text;
+-
+- /* Prepare test data */
+- stmt_text= "drop table if exists t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "drop view if exists v1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "CREATE TABLE t1 (c1 varchar(10), c2 varchar(10), c3 varchar(10),"
+- " c4 varchar(10), c5 varchar(10), c6 varchar(10),"
+- " c7 varchar(10), c8 varchar(10), c9 varchar(10),"
+- "c10 varchar(10))";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "CREATE VIEW v1 AS SELECT * FROM t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "select * from v1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+- stmt_text= "drop table if exists t1, v1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test DECIMAL conversion */
+-
+-static int test_decimal_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char data[30];
+- int rc;
+- my_bool is_null;
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- rc= mysql_query(mysql, "drop table if exists test_decimal_bug");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table test_decimal_bug(c1 decimal(10, 2))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into test_decimal_bug value(8), (10.22), (5.61)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select c1 from test_decimal_bug where c1=?",
+- strlen("select c1 from test_decimal_bug where c1=?"));
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL;
+- my_bind[0].buffer= (void *)data;
+- my_bind[0].buffer_length= 25;
+- my_bind[0].is_null= &is_null;
+-
+- is_null= 0;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy(data, "8.0");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- data[0]= 0;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(data, "8.00") == 0, "data != '8.00'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- strcpy(data, "5.61");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- data[0]= 0;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(data, "5.61") == 0, "data != '5.61'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- is_null= 1;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- strcpy(data, "10.22"); is_null= 0;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- data[0]= 0;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(data, "10.22") == 0, "data != '10.22'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test EXPLAIN bug (#115, reported by mark@mysql.com & georg@php.net). */
+-
+-static int test_explain_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- int rc;
+-
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_explain");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_explain(id int, name char(2))");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "explain test_explain", strlen("explain test_explain"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 2, "rowcount != 2");
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- FAIL_UNLESS(6 == mysql_num_fields(result), "fields != 6");
+-
+- if (verify_prepare_field(result, 0, "Field", "COLUMN_NAME",
+- mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 64, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 0, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 2, "Null", "IS_NULLABLE",
+- mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 3, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 3, "Key", "COLUMN_KEY",
+- mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 3, 0))
+- goto error;
+-
+- if ( mysql_get_server_version(mysql) >= 50027 )
+- {
+- /* The patch for bug#23037 changes column type of DEAULT to blob */
+- if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
+- MYSQL_TYPE_BLOB, 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 0, 0))
+- goto error;
+- }
+- else
+- {
+- if (verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
+- mysql_get_server_version(mysql) >= 50027 ?
+- MYSQL_TYPE_BLOB :
+- mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- mysql_get_server_version(mysql) >= 50027 ? 0 :64, 0))
+- goto error;
+- }
+-
+- if (verify_prepare_field(result, 5, "Extra", "EXTRA",
+- mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+- 0, 0,
+- mysql_get_server_version(mysql) <= 50400 ? "" : "information_schema",
+- 27, 0))
+- goto error;
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "explain select id, name FROM test_explain", strlen("explain select id, name FROM test_explain"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid result set");
+-
+- FAIL_UNLESS(10 == mysql_num_fields(result), "fields != 10");
+-
+- if (verify_prepare_field(result, 0, "id", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 1, "select_type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 19, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 2, "table", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 10, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
+- goto error;
+-
+- if ( verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN, 0))
+- goto error;
+-
+- if (mysql_get_server_version(mysql) <= 50000)
+- {
+- if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_LONGLONG, "", "", "", 3, 0))
+- goto error;
+- }
+- else if (mysql_get_server_version(mysql) <= 60000)
+- {
+- if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_CHAR_LEN*MAX_KEY, 0))
+- goto error;
+- }
+- else
+- {
+- if (verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", "", "", (MAX_KEY_LENGTH_DECIMAL_WIDTH + 1) * MAX_KEY, 0))
+- goto error;
+- }
+-
+- if (verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "",
+- NAME_CHAR_LEN*16, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, "", "", "", 10, 0))
+- goto error;
+-
+- if (verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, "", "", "", 255, 0))
+- goto error;
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+- return OK;
+-error:
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+- return FAIL;
+-}
+-
+-static int test_sshort_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[4];
+- short short_value;
+- int32 long_value;
+- ulong s_length, l_length, ll_length, t_length;
+- ulonglong longlong_value;
+- int rc;
+- uchar tiny_value;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sshort");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_sshort(a smallint signed, \
+- b smallint signed, \
+- c smallint unsigned, \
+- d smallint unsigned)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_sshort VALUES(-5999, -5999, 35999, 200)");
+- check_mysql_rc(rc, mysql);
+-
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_sshort", strlen("SELECT * FROM test_sshort"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[0].buffer= (void *)&short_value;
+- my_bind[0].length= &s_length;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[1].buffer= (void *)&long_value;
+- my_bind[1].length= &l_length;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[2].buffer= (void *)&longlong_value;
+- my_bind[2].length= &ll_length;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[3].buffer= (void *)&tiny_value;
+- my_bind[3].is_unsigned= TRUE;
+- my_bind[3].length= &t_length;
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(short_value == -5999, "sv != -5999");
+- FAIL_UNLESS(s_length == 2, "s_length != 2");
+-
+- FAIL_UNLESS(long_value == -5999, "l_v != -5999");
+- FAIL_UNLESS(l_length == 4, "l_length != 4");
+-
+- FAIL_UNLESS(longlong_value == 35999, "llv != 35999");
+- FAIL_UNLESS(ll_length == 8, "ll_length != 8");
+-
+- FAIL_UNLESS(tiny_value == 200, "t_v != 200");
+- FAIL_UNLESS(t_length == 1, "t_length != 1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-/* Test a misc tinyint-signed conversion bug */
+-
+-static int test_stiny_bug(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[4];
+- short short_value;
+- int32 long_value;
+- ulong s_length, l_length, ll_length, t_length;
+- ulonglong longlong_value;
+- int rc;
+- uchar tiny_value;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stiny");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_stiny(a tinyint signed, \
+- b tinyint signed, \
+- c tinyint unsigned, \
+- d tinyint unsigned)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_stiny VALUES(-128, -127, 255, 0)");
+- check_mysql_rc(rc, mysql);
+-
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_stiny", strlen("SELECT * FROM test_stiny"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[0].buffer= (void *)&short_value;
+- my_bind[0].length= &s_length;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[1].buffer= (void *)&long_value;
+- my_bind[1].length= &l_length;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[2].buffer= (void *)&longlong_value;
+- my_bind[2].length= &ll_length;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[3].buffer= (void *)&tiny_value;
+- my_bind[3].length= &t_length;
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(short_value == -128, "s_v != -128");
+- FAIL_UNLESS(s_length == 2, "s_length != 2");
+-
+- FAIL_UNLESS(long_value == -127, "l_v != -127");
+- FAIL_UNLESS(l_length == 4, "l_length != 4");
+-
+- FAIL_UNLESS(longlong_value == 255, "llv != 255");
+- FAIL_UNLESS(ll_length == 8, "ll_length != 8");
+-
+- FAIL_UNLESS(tiny_value == 0, "t_v != 0");
+- FAIL_UNLESS(t_length == 1, "t_length != 1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bug53311(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+- int i;
+- char *query= "INSERT INTO bug53311 VALUES (1)";
+-
+- rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug53311");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE bug53311 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i=0; i < 2; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- /* kill connection */
+- rc= mysql_kill(mysql, mysql_thread_id(mysql));
+- check_mysql_rc(rc, mysql);
+- sleep(1);
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(rc == 0, "Error expected");
+- FAIL_IF(mysql_stmt_errno(stmt) == 0, "Errno != 0 expected");
+- rc= mysql_stmt_close(stmt);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-struct my_tests_st my_tests[] = {
+- {"test_bug1115", test_bug1115, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug1180", test_bug1180, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug1644", test_bug1644, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11037", test_bug11037, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11183", test_bug11183, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug12744", test_bug12744, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug1500", test_bug1500, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug15510", test_bug15510, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug15518", test_bug15518, TEST_CONNECTION_NEW | TEST_CONNECTION_DONT_CLOSE, CLIENT_MULTI_STATEMENTS, NULL , NULL},
+- {"test_bug15613", test_bug15613, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug16144", test_bug16144, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug1664", test_bug1664, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug1946", test_bug1946, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug2247", test_bug2247, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug2248", test_bug2248, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug20152", test_bug20152, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug23383", test_bug23383, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug27592", test_bug27592, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug28934", test_bug28934, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug36004", test_bug36004, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug3035", test_bug3035, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug3117", test_bug3117, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug3796", test_bug3796, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4026", test_bug4026, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4030", test_bug4030, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4079", test_bug4079, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4172", test_bug4172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4231", test_bug4231, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug4236", test_bug4236, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug5126", test_bug5126, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug5194", test_bug5194, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug5315", test_bug5315, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug5399", test_bug5399, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug6046", test_bug6046, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug6049", test_bug6049, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug6058", test_bug6058, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug6059", test_bug6059, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug6096", test_bug6096, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug7990", test_bug7990, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug8330", test_bug8330, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug8722", test_bug8722, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ps_conj_select", test_ps_conj_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ps_null_param", test_ps_null_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ps_query_cache", test_ps_query_cache, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_ushort_bug", test_ushort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_field_misc", test_field_misc, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_mem_overun", test_mem_overun, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_decimal_bug", test_decimal_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_explain_bug", test_explain_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_sshort_bug", test_sshort_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_stiny_bug", test_stiny_bug, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug53311", test_bug53311, TEST_CONNECTION_NEW, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/ps.c mariadb-native-client.trunk/unittest/libmysql/ps.c
+--- mariadb/unittest/libmysql/ps.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/ps.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,4619 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/* Utility function to verify the field members */
+-
+-
+-static int test_prepare_insert_update(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- int i;
+- const char *testcase[]= {
+- "CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B))",
+- "INSERT t1 VALUES (1,2,10), (3,4,20)",
+- "INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100",
+- "SELECT * FROM t1",
+- "INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0",
+- "SELECT * FROM t1",
+- "INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a)",
+- NULL};
+- const char **cur_query;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- for (cur_query= testcase; *cur_query; cur_query++)
+- {
+- char query[MAX_TEST_QUERY_LENGTH];
+- strcpy(query, *cur_query);
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount is not 0");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* try the last query several times */
+- if (!cur_query[1])
+- {
+- for (i=0; i < 3;i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+- }
+- mysql_stmt_close(stmt);
+- }
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Generalized conversion routine to handle DATE, TIME and DATETIME
+- conversion using MYSQL_TIME structure
+-*/
+-
+-static int test_bind_date_conv(MYSQL *mysql, uint row_count)
+-{
+- MYSQL_STMT *stmt= 0;
+- uint rc, i, count= row_count;
+- ulong length[4];
+- MYSQL_BIND my_bind[4];
+- my_bool is_null[4]= {0};
+- MYSQL_TIME tm[4];
+- ulong second_part;
+- uint year, month, day, hour, minute, sec;
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "INSERT INTO test_date VALUES(?, ?, ?, ?)", strlen("INSERT INTO test_date VALUES(?, ?, ?, ?)"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 4, "param_count != 4");
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP;
+- my_bind[1].buffer_type= MYSQL_TYPE_TIME;
+- my_bind[2].buffer_type= MYSQL_TYPE_DATETIME;
+- my_bind[3].buffer_type= MYSQL_TYPE_DATE;
+-
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].buffer= (void *) &tm[i];
+- my_bind[i].is_null= &is_null[i];
+- my_bind[i].length= &length[i];
+- my_bind[i].buffer_length= 30;
+- length[i]= 20;
+- }
+-
+- second_part= 0;
+-
+- year= 2000;
+- month= 01;
+- day= 10;
+-
+- hour= 11;
+- minute= 16;
+- sec= 20;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (count= 0; count < row_count; count++)
+- {
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- tm[i].neg= 0;
+- tm[i].second_part= second_part+count;
+- if (my_bind[i].buffer_type != MYSQL_TYPE_TIME)
+- {
+- tm[i].year= year+count;
+- tm[i].month= month+count;
+- tm[i].day= day+count;
+- }
+- else
+- tm[i].year= tm[i].month= tm[i].day= 0;
+- if (my_bind[i].buffer_type != MYSQL_TYPE_DATE)
+- {
+- tm[i].hour= hour+count;
+- tm[i].minute= minute+count;
+- tm[i].second= sec+count;
+- }
+- else
+- tm[i].hour= tm[i].minute= tm[i].second= 0;
+- }
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= my_stmt_result(mysql, "SELECT * FROM test_date");
+- FAIL_UNLESS(row_count == rc, "rowcount != rc");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_date", strlen("SELECT * FROM test_date"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- for (count= 0; count < row_count; count++)
+- {
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == 0 || rc == MYSQL_DATA_TRUNCATED, "rc != 0 | rc != MYSQL_DATA_TRUNCATED");
+-
+- for (i= 0; i < array_elements(my_bind); i++)
+- {
+- FAIL_UNLESS(tm[i].year == 0 || tm[i].year == year+count, "wrong value for year");
+- FAIL_UNLESS(tm[i].month == 0 || tm[i].month == month+count, "wrong value for month");
+- FAIL_UNLESS(tm[i].day == 0 || tm[i].day == day+count, "wrong value for day");
+-
+- FAIL_UNLESS(tm[i].hour == 0 || tm[i].hour == hour+count, "wrong value for hour");
+- FAIL_UNLESS(tm[i].minute == 0 || tm[i].minute == minute+count, "wrong value for minute");
+- FAIL_UNLESS(tm[i].second == 0 || tm[i].second == sec+count, "wrong value for second");
+- FAIL_UNLESS(tm[i].second_part == 0 ||
+- tm[i].second_part == second_part+count, "wrong value for second_part");
+- }
+- }
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-/* Test simple prepares of all DML statements */
+-
+-static int test_prepare_simple(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_simple");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prepare_simple("
+- "id int, name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert */
+- strcpy(query, "INSERT INTO test_prepare_simple VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount is not 2");
+- mysql_stmt_close(stmt);
+-
+- /* update */
+- strcpy(query, "UPDATE test_prepare_simple SET id=? "
+- "WHERE id=? AND CONVERT(name USING utf8)= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 3, "Paramcount is not 3");
+- mysql_stmt_close(stmt);
+-
+- /* delete */
+- strcpy(query, "DELETE FROM test_prepare_simple WHERE id=10");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount is not 0");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- /* delete */
+- strcpy(query, "DELETE FROM test_prepare_simple WHERE id=?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- /* select */
+- strcpy(query, "SELECT * FROM test_prepare_simple WHERE id=? "
+- "AND CONVERT(name USING utf8)= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_prepare_field_result(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_field_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prepare_field_result(int_c int, "
+- "var_c varchar(50), ts_c timestamp, "
+- "char_c char(4), date_c date, extra tinyint)");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert */
+- strcpy(query, "SELECT int_c, var_c, date_c as date, ts_c, char_c FROM "
+- " test_prepare_field_result as t1 WHERE int_c=?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, mysql_stmt_error(stmt));
+-
+- if (verify_prepare_field(result, 0, "int_c", "int_c", MYSQL_TYPE_LONG,
+- "t1", "test_prepare_field_result", schema, 11, 0))
+- goto error;
+- if (verify_prepare_field(result, 1, "var_c", "var_c", MYSQL_TYPE_VAR_STRING,
+- "t1", "test_prepare_field_result", schema, 50, 0))
+- goto error;
+- if (verify_prepare_field(result, 2, "date", "date_c", MYSQL_TYPE_DATE,
+- "t1", "test_prepare_field_result", schema, 10, 0))
+- goto error;
+- if (verify_prepare_field(result, 3, "ts_c", "ts_c", MYSQL_TYPE_TIMESTAMP,
+- "t1", "test_prepare_field_result", schema, 19, 0))
+- goto error;
+- if (verify_prepare_field(result, 4, "char_c", "char_c",
+- (mysql_get_server_version(mysql) <= 50000 ?
+- MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING),
+- "t1", "test_prepare_field_result", schema, 4, 0))
+- goto error;
+-
+- FAIL_IF(mysql_num_fields(result) != 5, "Paramcount != 5");
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-
+-error:
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+- return FAIL;
+-}
+-
+-
+-/* Test simple prepare field results */
+-
+-static int test_prepare_syntax(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_syntax");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prepare_syntax("
+- "id int, name varchar(50), extra int)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_prepare_syntax VALUES(?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "error expected");
+-
+- strcpy(query, "SELECT id, name FROM test_prepare_syntax WHERE id=? AND WHERE");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "error expected");
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_prepare(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- int int_data, o_int_data;
+- char str_data[50], data[50];
+- char tiny_data, o_tiny_data;
+- short small_data, o_small_data;
+- longlong big_data, o_big_data;
+- float real_data, o_real_data;
+- double double_data, o_double_data;
+- ulong length[7], len;
+- my_bool is_null[7];
+- MYSQL_BIND my_bind[7];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 tinyint, "
+- "col2 varchar(15), col3 int, "
+- "col4 smallint, col5 bigint, "
+- "col6 float, col7 double )");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare */
+- strcpy(query, "INSERT INTO my_prepare VALUES(?, ?, ?, ?, ?, ?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 7, "Paramcount != 7");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* tinyint */
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&tiny_data;
+- /* string */
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)str_data;
+- my_bind[1].buffer_length= 1000; /* Max string length */
+- /* integer */
+- my_bind[2].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[2].buffer= (void *)&int_data;
+- /* short */
+- my_bind[3].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[3].buffer= (void *)&small_data;
+- /* bigint */
+- my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[4].buffer= (void *)&big_data;
+- /* float */
+- my_bind[5].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[5].buffer= (void *)&real_data;
+- /* double */
+- my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[6].buffer= (void *)&double_data;
+-
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].length= &length[i];
+- my_bind[i].is_null= &is_null[i];
+- is_null[i]= 0;
+- }
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- int_data= 320;
+- small_data= 1867;
+- big_data= 1000;
+- real_data= 2;
+- double_data= 6578.001;
+-
+- /* now, execute the prepared statement to insert 10 records.. */
+- for (tiny_data= 0; tiny_data < 100; tiny_data++)
+- {
+- length[1]= sprintf(str_data, "MySQL%d", int_data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- int_data += 25;
+- small_data += 10;
+- big_data += 100;
+- real_data += 1;
+- double_data += 10.09;
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= my_stmt_result(mysql, "SELECT * FROM my_prepare");
+- FAIL_UNLESS(rc != 1, "rowcount != 1");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM my_prepare", 25);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /* get the result */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- o_int_data= 320;
+- o_small_data= 1867;
+- o_big_data= 1000;
+- o_real_data= 2;
+- o_double_data= 6578.001;
+-
+- /* now, execute the prepared statement to insert 10 records.. */
+- for (o_tiny_data= 0; o_tiny_data < 100; o_tiny_data++)
+- {
+- len= sprintf(data, "MySQL%d", o_int_data);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(tiny_data == o_tiny_data, "Wrong value for tiny_data");
+- FAIL_UNLESS(is_null[0] == 0, "Wrong value for is_null");
+- FAIL_UNLESS(length[0] == 1, "length != 0");
+-
+- FAIL_UNLESS(int_data == o_int_data, "Wrong value for int_data");
+- FAIL_UNLESS(length[2] == 4, "length != 4");
+-
+- FAIL_UNLESS(small_data == o_small_data, "Wrong value for small_data");
+- FAIL_UNLESS(length[3] == 2, "length != 2");
+-
+- FAIL_UNLESS(big_data == o_big_data, "Wrong value for big_data");
+- FAIL_UNLESS(length[4] == 8, "length != 8");
+-
+- FAIL_UNLESS(real_data == o_real_data, "Wrong value for real_data");
+- FAIL_UNLESS(length[5] == 4, "length != 4");
+-
+- FAIL_UNLESS(double_data == o_double_data, "Wrong value for double_data");
+- FAIL_UNLESS(length[6] == 8, "length != 8");
+-
+- FAIL_UNLESS(strcmp(data, str_data) == 0, "Wrong value for data");
+- FAIL_UNLESS(length[1] == len, "length != len");
+-
+- o_int_data += 25;
+- o_small_data += 10;
+- o_big_data += 100;
+- o_real_data += 1;
+- o_double_data += 10.09;
+- }
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_prepare_multi_statements(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- char query[MAX_TEST_QUERY_LENGTH];
+- int rc;
+-
+- strcpy(query, "select 1; select 'another value'");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "Error expected");
+-
+- return OK;
+-}
+-
+-static int test_prepare_ext(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char *sql;
+- int nData= 1;
+- char tData= 1;
+- short sData= 10;
+- longlong bData= 20;
+- int rowcount= 0;
+- MYSQL_BIND my_bind[6];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_ext");
+- check_mysql_rc(rc, mysql)
+-
+- sql= (char *)"CREATE TABLE test_prepare_ext"
+- "("
+- " c1 tinyint,"
+- " c2 smallint,"
+- " c3 mediumint,"
+- " c4 int,"
+- " c5 integer,"
+- " c6 bigint,"
+- " c7 float,"
+- " c8 double,"
+- " c9 double precision,"
+- " c10 real,"
+- " c11 decimal(7, 4),"
+- " c12 numeric(8, 4),"
+- " c13 date,"
+- " c14 datetime,"
+- " c15 timestamp,"
+- " c16 time,"
+- " c17 year,"
+- " c18 bit,"
+- " c19 bool,"
+- " c20 char,"
+- " c21 char(10),"
+- " c22 varchar(30),"
+- " c23 tinyblob,"
+- " c24 tinytext,"
+- " c25 blob,"
+- " c26 text,"
+- " c27 mediumblob,"
+- " c28 mediumtext,"
+- " c29 longblob,"
+- " c30 longtext,"
+- " c31 enum('one', 'two', 'three'),"
+- " c32 set('monday', 'tuesday', 'wednesday'))";
+-
+- rc= mysql_query(mysql, sql);
+- check_mysql_rc(rc, mysql)
+-
+- /* insert by prepare - all integers */
+- strcpy(query, "INSERT INTO test_prepare_ext(c1, c2, c3, c4, c5, c6) VALUES(?, ?, ?, ?, ?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 6, "Paramcount != 6");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /*tinyint*/
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&tData;
+-
+- /*smallint*/
+- my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[1].buffer= (void *)&sData;
+-
+- /*mediumint*/
+- my_bind[2].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[2].buffer= (void *)&nData;
+-
+- /*int*/
+- my_bind[3].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[3].buffer= (void *)&nData;
+-
+- /*integer*/
+- my_bind[4].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[4].buffer= (void *)&nData;
+-
+- /*bigint*/
+- my_bind[5].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[5].buffer= (void *)&bData;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- * integer to integer
+- */
+- for (nData= 0; nData<10; nData++, tData++, sData++, bData++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+-
+- strcpy(query, "SELECT c1, c2, c3, c4, c5, c6 FROM test_prepare_ext");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- /* get the result */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+-
+- FAIL_UNLESS(nData == rowcount, "Invalid rowcount");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_prepare_alter(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL *mysql_new;
+- int rc, id;
+- MYSQL_BIND my_bind[1];
+- my_bool is_null;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_alter");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prep_alter(id int, name char(20))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_prep_alter values(10, 'venu'), (20, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_prep_alter VALUES(?, 'monty')");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "Paramcount != 1");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- is_null= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[0].buffer= (void *)&id;
+- my_bind[0].is_null= &is_null;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- id= 30;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+-
+- mysql_new= mysql_init(NULL);
+- FAIL_IF(!mysql_new, "mysql_init failed");
+- FAIL_IF(!(mysql_real_connect(mysql_new, hostname, username, password,
+- schema, port, socketname, 0)), "mysql_real_connect failed");
+- rc= mysql_query(mysql_new, "ALTER TABLE test_prep_alter change id id_new varchar(20)");
+- check_mysql_rc(rc, mysql_new);
+- mysql_close(mysql_new);
+-
+- is_null= 1;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= my_stmt_result(mysql, "SELECT * FROM test_prep_alter");
+- FAIL_UNLESS(rc == 4, "rowcount != 4");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_prepare_resultset(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- MYSQL_RES *result;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_resultset");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prepare_resultset(id int, \
+- name varchar(50), extra double)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- strcpy(query, "SELECT * FROM test_prepare_resultset");
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt), "Paramcount != 0");
+-
+- result= mysql_stmt_result_metadata(stmt);
+- FAIL_IF(!result, "Invalid resultset");
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-/* Test the direct query execution in the middle of open stmts */
+-
+-static int test_open_direct(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_open_direct");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_open_direct(id int, name char(6))");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_open_direct values(10, 'mysql')");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "invalid resultset");
+-
+- FAIL_IF(mysql_num_rows(result), "rowcount != 0");
+- mysql_free_result(result);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "affected rows != 1");
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "invalid resultset");
+-
+- FAIL_IF(mysql_num_rows(result) != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "affected rows != 1");
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_open_direct");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid resultset");
+- FAIL_IF(mysql_num_rows(result) != 2, "rowcount != 2");
+-
+- mysql_free_result(result);
+-
+- mysql_stmt_close(stmt);
+-
+- /* run a direct query in the middle of a fetch */
+-
+- strcpy(query, "SELECT * FROM test_open_direct");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)");
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)");
+- check_mysql_rc(rc, mysql);
+-
+- /* run a direct query with store result */
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "drop table test_open_direct");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- return OK;
+-}
+-
+-static int test_select_show(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+- int rowcount;
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_show");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_show(id int(4) NOT NULL primary "
+- " key, name char(2))");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "show columns from test_show");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 2, "rowcount != 2");
+-
+- mysql_stmt_close(stmt);
+-
+- strcpy(query, "show tables from mysql like ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "Error expected");
+-
+- strcpy(query, "show tables like \'test_show\'");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_stmt_close(stmt);
+-
+- strcpy(query, "describe test_show");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 2, "rowcount != 2");
+- mysql_stmt_close(stmt);
+-
+- strcpy(query, "show keys from test_show");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rowcount= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_simple_update(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char szData[25];
+- int nData= 1;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- ulong length[2];
+- int rowcount= 0;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_update(col1 int, "
+- " col2 varchar(50), col3 int )");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_update VALUES(1, 'MySQL', 100)");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_IF(mysql_affected_rows(mysql) != 1, "Affected rows != 1");
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare */
+- strcpy(query, "UPDATE test_update SET col2= ? WHERE col1= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- nData= 1;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= szData; /* string data */
+- my_bind[0].buffer_length= sizeof(szData);
+- my_bind[0].length= &length[0];
+- length[0]= sprintf(szData, "updated-data");
+-
+- my_bind[1].buffer= (void *) &nData;
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected_rows != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM test_update");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid resultset");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+-
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-/* Test simple long data handling */
+-
+-static int test_long_data(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, int_data;
+- char *data= NullS;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[3];
+- int rowcount;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, "
+- " col2 long varchar, col3 long varbinary)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_long_data(col1, col2) VALUES(?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy(query, "INSERT INTO test_long_data(col1, col2, col3) VALUES(?, ?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 3, "Paramcount != 3");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)&int_data;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+-
+- my_bind[2]= my_bind[1];
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- int_data= 999;
+- data= (char *)"Michael";
+-
+- /* supply data in pieces */
+- rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+- data= (char *)" 'Monty' Widenius";
+- rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_send_long_data(stmt, 2, "Venu (venu@mysql.com)", 4);
+- check_stmt_rc(rc, stmt);
+-
+- /* execute */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* now fetch the results ..*/
+- rc= mysql_query(mysql, "SELECT * FROM test_long_data");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rowcount= 0;
+- while (mysql_fetch_row(result))
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- if (verify_col_data(mysql, "test_long_data", "col1", "999"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col2", "Michael 'Monty' Widenius"))
+- goto error;
+- if (verify_col_data(mysql, "test_long_data", "col3", "Venu"))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-
+-error:
+- mysql_stmt_close(stmt);
+- return FAIL;
+-}
+-
+-
+-/* Test long data (string) handling */
+-
+-static int test_long_data_str(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i, rowcount= 0;
+- char data[255];
+- long length;
+- ulong length1;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- my_bool is_null[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(id int, longstr long varchar)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_long_data_str VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)&length;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].is_null= &is_null[0];
+- is_null[0]= 0;
+- length= 0;
+-
+- my_bind[1].buffer= data; /* string data */
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].length= &length1;
+- my_bind[1].is_null= &is_null[1];
+- is_null[1]= 0;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- length= 40;
+- strcpy(data, "MySQL AB");
+-
+- /* supply data in pieces */
+- for(i= 0; i < 4; i++)
+- {
+- rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 5);
+- check_stmt_rc(rc, stmt);
+- }
+- /* execute */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* now fetch the results ..*/
+- rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr FROM test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+-
+- mysql_free_result(result);
+-
+- sprintf(data, "%d", i*5);
+- if (verify_col_data(mysql, "test_long_data_str", "LENGTH(longstr)", data))
+- goto error;
+- strcpy(data, "MySQLMySQLMySQLMySQL");
+- if (verify_col_data(mysql, "test_long_data_str", "longstr", data))
+- goto error;
+-
+- rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-
+-error:
+- rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
+- check_mysql_rc(rc, mysql);
+- return FAIL;
+-}
+-
+-
+-/* Test long data (string) handling */
+-
+-static int test_long_data_str1(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i, rowcount= 0;
+- char data[255];
+- long length;
+- ulong max_blob_length, blob_length, length1;
+- my_bool true_value;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- MYSQL_FIELD *field;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(longstr long varchar, blb long varbinary)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_long_data_str VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= data; /* string data */
+- my_bind[0].buffer_length= sizeof(data);
+- my_bind[0].length= &length1;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- length1= 0;
+-
+- my_bind[1]= my_bind[0];
+- my_bind[1].buffer_type= MYSQL_TYPE_BLOB;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- length= sprintf(data, "MySQL AB");
+-
+- /* supply data in pieces */
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_send_long_data(stmt, 0, data, length);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_send_long_data(stmt, 1, data, 2);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- /* execute */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* now fetch the results ..*/
+- rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr, LENGTH(blb), blb FROM test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+-
+- mysql_field_seek(result, 1);
+- field= mysql_fetch_field(result);
+- max_blob_length= field->max_length;
+-
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- sprintf(data, "%ld", (long)i*length);
+- if (verify_col_data(mysql, "test_long_data_str", "length(longstr)", data))
+- return FAIL;
+-
+- sprintf(data, "%d", i*2);
+- if (verify_col_data(mysql, "test_long_data_str", "length(blb)", data))
+- return FAIL;
+-
+- /* Test length of field->max_length */
+- strcpy(query, "SELECT * from test_long_data_str");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_fields(result);
+-
+- /* First test what happens if STMT_ATTR_UPDATE_MAX_LENGTH is not used */
+- FAIL_IF(field->max_length != 0, "field->max_length != 0");
+- mysql_free_result(result);
+-
+- /* Enable updating of field->max_length */
+- true_value= 1;
+- mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &true_value);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- result= mysql_stmt_result_metadata(stmt);
+- field= mysql_fetch_fields(result);
+-
+- FAIL_UNLESS(field->max_length == max_blob_length, "field->max_length != max_blob_length");
+-
+- /* Fetch results into a data buffer that is smaller than data */
+- memset(my_bind, '\0', sizeof(*my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_BLOB;
+- my_bind[0].buffer= (void *) &data; /* this buffer won't be altered */
+- my_bind[0].buffer_length= 16;
+- my_bind[0].length= &blob_length;
+- my_bind[0].error= &my_bind[0].error_value;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- data[16]= 0;
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "truncation expected");
+- FAIL_UNLESS(my_bind[0].error_value, "No error value");
+- FAIL_UNLESS(strlen(data) == 16, "Invalid string length");
+- FAIL_UNLESS(blob_length == max_blob_length, "blob_length != max_blob_length");
+-
+- /* Fetch all data */
+- memset((my_bind+1), '\0', sizeof(*my_bind));
+- my_bind[1].buffer_type= MYSQL_TYPE_BLOB;
+- my_bind[1].buffer= (void *) &data; /* this buffer won't be altered */
+- my_bind[1].buffer_length= sizeof(data);
+- my_bind[1].length= &blob_length;
+- memset(data, '\0', sizeof(data));
+- mysql_stmt_fetch_column(stmt, my_bind+1, 0, 0);
+- FAIL_UNLESS(strlen(data) == max_blob_length, "strlen(data) != max_blob_length");
+-
+- mysql_free_result(result);
+- mysql_stmt_close(stmt);
+-
+- /* Drop created table */
+- rc= mysql_query(mysql, "DROP TABLE test_long_data_str");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-/* Test long data (binary) handling */
+-
+-static int test_long_data_bin(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, rowcount= 0;
+- char data[255];
+- long length;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_bin");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_long_data_bin(id int, longbin long varbinary)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_long_data_bin VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)&length;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- length= 0;
+-
+- my_bind[1].buffer= data; /* string data */
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG_BLOB;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- length= 10;
+- strcpy(data, "MySQL AB");
+-
+- /* supply data in pieces */
+- {
+- int i;
+- for (i= 0; i < 100; i++)
+- {
+- rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 4);
+- check_stmt_rc(rc, stmt);
+- }
+- }
+- /* execute */
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* now fetch the results ..*/
+- rc= mysql_query(mysql, "SELECT LENGTH(longbin), longbin FROM test_long_data_bin");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-/* Test simple delete */
+-
+-static int test_simple_delete(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, rowcount= 0;
+- char szData[30]= {0};
+- int nData= 1;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- ulong length[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_simple_delete");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_simple_delete(col1 int, \
+- col2 varchar(50), col3 int )");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_simple_delete VALUES(1, 'MySQL', 100)");
+- check_mysql_rc(rc, mysql);
+-
+- FAIL_IF(mysql_affected_rows(mysql) != 1, "Affected rows != 1");
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare */
+- strcpy(query, "DELETE FROM test_simple_delete WHERE col1= ? AND "
+- "CONVERT(col2 USING utf8)= ? AND col3= 100");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt)
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- nData= 1;
+- strcpy(szData, "MySQL");
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= szData; /* string data */
+- my_bind[1].buffer_length= sizeof(szData);
+- my_bind[1].length= &length[1];
+- length[1]= 5;
+-
+- my_bind[0].buffer= (void *)&nData;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM test_simple_delete");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount, "rowcount > 0");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-static int test_update(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char szData[25];
+- int nData= 1, rowcount= 0;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- ulong length[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_update("
+- "col1 int primary key auto_increment, "
+- "col2 varchar(50), col3 int )");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_update(col2, col3) VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* string data */
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= szData;
+- my_bind[0].buffer_length= sizeof(szData);
+- my_bind[0].length= &length[0];
+- length[0]= sprintf(szData, "inserted-data");
+-
+- my_bind[1].buffer= (void *)&nData;
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- nData= 100;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
+- mysql_stmt_close(stmt);
+-
+- strcpy(query, "UPDATE test_update SET col2= ? WHERE col3= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Paramcount != 2");
+- nData= 100;
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= szData;
+- my_bind[0].buffer_length= sizeof(szData);
+- my_bind[0].length= &length[0];
+- length[0]= sprintf(szData, "updated-data");
+-
+- my_bind[1].buffer= (void *)&nData;
+- my_bind[1].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "Affected rows != 1");
+-
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM test_update");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-/* Test prepare without parameters */
+-
+-static int test_prepare_noparam(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, rowcount= 0;
+- MYSQL_RES *result;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare");
+- check_mysql_rc(rc, mysql);
+-
+-
+- rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 int, col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare */
+- strcpy(query, "INSERT INTO my_prepare VALUES(10, 'venu')");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 0, "Paramcount != 0");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM my_prepare");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 1, "rowcount != 1");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-
+-/* Test simple bind result */
+-
+-static int test_bind_result(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- int nData;
+- ulong length1;
+- char szData[100];
+- MYSQL_BIND my_bind[2];
+- my_bool is_null[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_result(col1 int , col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(10, 'venu')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(20, 'MySQL')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result(col2) VALUES('monty')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* fetch */
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *) &nData; /* integer data */
+- my_bind[0].is_null= &is_null[0];
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= szData; /* string data */
+- my_bind[1].buffer_length= sizeof(szData);
+- my_bind[1].length= &length1;
+- my_bind[1].is_null= &is_null[1];
+-
+- strcpy(query, "SELECT * FROM test_bind_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 10, "nData != 10");
+- FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
+- FAIL_UNLESS(length1 == 4, "length1 != 4");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 20, "nData != 20");
+- FAIL_UNLESS(strcmp(szData, "MySQL") == 0, "szData != 'MySQL'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(is_null[0], "null flag not set");
+- FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'Monty'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bind_result_ext(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- uchar t_data;
+- short s_data;
+- int i_data;
+- longlong b_data;
+- float f_data;
+- double d_data;
+- char szData[20], bData[20];
+- ulong szLength, bLength;
+- MYSQL_BIND my_bind[8];
+- ulong length[8];
+- my_bool is_null[8];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, "
+- " c2 smallint, "
+- " c3 int, c4 bigint, "
+- " c5 float, c6 double, "
+- " c7 varbinary(10), "
+- " c8 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result "
+- "VALUES (19, 2999, 3999, 4999999, "
+- " 2345.6, 5678.89563, 'venu', 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < (int) array_elements(my_bind); i++)
+- {
+- my_bind[i].length= &length[i];
+- my_bind[i].is_null= &is_null[i];
+- }
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&t_data;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[2].buffer_type= MYSQL_TYPE_LONG;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG;
+- my_bind[1].buffer= (void *)&s_data;
+-
+- my_bind[2].buffer= (void *)&i_data;
+- my_bind[3].buffer= (void *)&b_data;
+-
+- my_bind[4].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[4].buffer= (void *)&f_data;
+-
+- my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[5].buffer= (void *)&d_data;
+-
+- my_bind[6].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[6].buffer= (void *)szData;
+- my_bind[6].buffer_length= sizeof(szData);
+- my_bind[6].length= &szLength;
+-
+- my_bind[7].buffer_type= MYSQL_TYPE_TINY_BLOB;
+- my_bind[7].buffer= (void *)&bData;
+- my_bind[7].length= &bLength;
+- my_bind[7].buffer_length= sizeof(bData);
+-
+- strcpy(query, "select * from test_bind_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(t_data == 19, "tdata != 19");
+- FAIL_UNLESS(s_data == 2999, "s_data != 2999");
+- FAIL_UNLESS(i_data == 3999, "i_data != 3999");
+- FAIL_UNLESS(b_data == 4999999, "b_data != 4999999");
+- FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
+- FAIL_UNLESS(strncmp(bData, "mysql", 5) == 0, "nData != 'mysql'");
+- FAIL_UNLESS(szLength == 4, "szLength != 4");
+- FAIL_UNLESS(bLength == 5, "bLength != 5");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-
+-/* Test ext bind result */
+-
+-static int test_bind_result_ext1(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- uint i;
+- int rc;
+- char t_data[20];
+- float s_data;
+- short i_data;
+- uchar b_data;
+- int f_data;
+- long bData;
+- char d_data[20];
+- double szData;
+- MYSQL_BIND my_bind[8];
+- ulong length[8];
+- my_bool is_null[8];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, c2 smallint, \
+- c3 int, c4 bigint, \
+- c5 float, c6 double, \
+- c7 varbinary(10), \
+- c8 varchar(10))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(120, 2999, 3999, 54, \
+- 2.6, 58.89, \
+- '206', '6.7')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *) t_data;
+- my_bind[0].buffer_length= sizeof(t_data);
+- my_bind[0].error= &my_bind[0].error_value;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_FLOAT;
+- my_bind[1].buffer= (void *)&s_data;
+- my_bind[1].buffer_length= 0;
+- my_bind[1].error= &my_bind[1].error_value;
+-
+- my_bind[2].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[2].buffer= (void *)&i_data;
+- my_bind[2].buffer_length= 0;
+- my_bind[2].error= &my_bind[2].error_value;
+-
+- my_bind[3].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[3].buffer= (void *)&b_data;
+- my_bind[3].buffer_length= 0;
+- my_bind[3].error= &my_bind[3].error_value;
+-
+- my_bind[4].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[4].buffer= (void *)&f_data;
+- my_bind[4].buffer_length= 0;
+- my_bind[4].error= &my_bind[4].error_value;
+-
+- my_bind[5].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[5].buffer= (void *)d_data;
+- my_bind[5].buffer_length= sizeof(d_data);
+- my_bind[5].error= &my_bind[5].error_value;
+-
+- my_bind[6].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[6].buffer= (void *)&bData;
+- my_bind[6].buffer_length= 0;
+- my_bind[6].error= &my_bind[6].error_value;
+-
+- my_bind[7].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[7].buffer= (void *)&szData;
+- my_bind[7].buffer_length= 0;
+- my_bind[7].error= &my_bind[7].error_value;
+-
+- for (i= 0; i < array_elements(my_bind); i++)
+- {
+- my_bind[i].is_null= &is_null[i];
+- my_bind[i].length= &length[i];
+- }
+-
+- strcpy(query, "select * from test_bind_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(strcmp(t_data, "120") == 0, "t_data != 120");
+- FAIL_UNLESS(i_data == 3999, "i_data != 3999");
+- FAIL_UNLESS(f_data == 2, "f_data != 2");
+- FAIL_UNLESS(strcmp(d_data, "58.89") == 0, "d_data != 58.89");
+- FAIL_UNLESS(b_data == 54, "b_data != 54");
+-
+- FAIL_UNLESS(length[0] == 3, "Wrong length");
+- FAIL_UNLESS(length[1] == 4, "Wrong length");
+- FAIL_UNLESS(length[2] == 2, "Wrong length");
+- FAIL_UNLESS(length[3] == 1, "Wrong length");
+- FAIL_UNLESS(length[4] == 4, "Wrong length");
+- FAIL_UNLESS(length[5] == 5, "Wrong length");
+- FAIL_UNLESS(length[6] == 4, "Wrong length");
+- FAIL_UNLESS(length[7] == 8, "Wrong length");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "MYSQL_NO_DATA expected");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_bind_negative(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- char *query;
+- int rc;
+- MYSQL_BIND my_bind[1];
+- int32 my_val= 0;
+- ulong my_length= 0L;
+- my_bool my_null= FALSE;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create temporary table t1 (c1 int unsigned)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (-1)");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"INSERT INTO t1 VALUES (?)";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- /* bind parameters */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&my_val;
+- my_bind[0].length= &my_length;
+- my_bind[0].is_null= (char*)&my_null;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- my_val= -1;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_buffers(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- int rc;
+- ulong length;
+- my_bool is_null;
+- char buffer[20];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_buffer");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_buffer(str varchar(20))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into test_buffer values('MySQL')\
+- , ('Database'), ('Open-Source'), ('Popular')");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "select str from test_buffer");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(buffer, '\0', sizeof(buffer)); /* Avoid overruns in printf() */
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].length= &length;
+- my_bind[0].is_null= &is_null;
+- my_bind[0].buffer_length= 1;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)buffer;
+- my_bind[0].error= &my_bind[0].error_value;
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- buffer[1]= 'X';
+- rc= mysql_stmt_fetch(stmt);
+-
+- FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "rc != MYSQL_DATA_TRUNCATED");
+- FAIL_UNLESS(my_bind[0].error_value, "Errorflag not set");
+- FAIL_UNLESS(buffer[0] == 'M', "buffer[0] != M");
+- FAIL_UNLESS(buffer[1] == 'X', "buffer[1] != X");
+- FAIL_UNLESS(length == 5, "length != 5");
+-
+- my_bind[0].buffer_length= 8;
+- rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(strncmp(buffer, "Database", 8) == 0, "buffer != 'Database'");
+- FAIL_UNLESS(length == 8, "length != 8");
+-
+- my_bind[0].buffer_length= 12;
+- rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(strcmp(buffer, "Open-Source") == 0, "buffer != 'Open-Source'");
+- FAIL_UNLESS(length == 11, "Length != 11");
+-
+- my_bind[0].buffer_length= 6;
+- rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "rc != MYSQL_DATA_TRUNCATED");
+- FAIL_UNLESS(my_bind[0].error_value, "Errorflag not set");
+- FAIL_UNLESS(strncmp(buffer, "Popula", 6) == 0, "buffer != 'Popula'");
+- FAIL_UNLESS(length == 7, "length != 7");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_xjoin(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query=
+- "select t.id, p1.value, n1.value, p2.value, n2.value from t3 t LEFT JOIN t1 p1 ON (p1.id=t.param1_id) LEFT JOIN t2 p2 ON (p2.id=t.param2_id) LEFT JOIN t4 n1 ON (n1.id=p1.name_id) LEFT JOIN t4 n2 ON (n2.id=p2.name_id) where t.id=1";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t3 (id int(8), param1_id int(8), param2_id int(8)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 ( id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t2 (id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t4(id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t3 values (1, 1, 1), (2, 2, null)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (1, 1, 'aaa'), (2, null, 'bbb')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t2 values (1, 2, 'ccc')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t4 values (1, 'Name1'), (2, null)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1, t2, t3, t4");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_union_param(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- char *query;
+- int rc, i;
+- MYSQL_BIND my_bind[2];
+- char my_val[4];
+- ulong my_length= 3L;
+- my_bool my_null= FALSE;
+-
+- strcpy(my_val, "abc");
+-
+- query= (char*)"select ? as my_col union distinct select ?";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* bind parameters */
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (char*) &my_val;
+- my_bind[0].buffer_length= 4;
+- my_bind[0].length= &my_length;
+- my_bind[0].is_null= (char*)&my_null;
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (char*) &my_val;
+- my_bind[1].buffer_length= 4;
+- my_bind[1].length= &my_length;
+- my_bind[1].is_null= (char*)&my_null;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_union(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- const char *query= "SELECT t1.name FROM t1 UNION "
+- "SELECT t2.name FROM t2";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "CREATE TABLE t1 "
+- "(id INTEGER NOT NULL PRIMARY KEY, "
+- " name VARCHAR(20) NOT NULL)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "INSERT INTO t1 (id, name) VALUES "
+- "(2, 'Ja'), (3, 'Ede'), "
+- "(4, 'Haag'), (5, 'Kabul'), "
+- "(6, 'Almere'), (7, 'Utrecht'), "
+- "(8, 'Qandahar'), (9, 'Amsterdam'), "
+- "(10, 'Amersfoort'), (11, 'Constantine')");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE TABLE t2 "
+- "(id INTEGER NOT NULL PRIMARY KEY, "
+- " name VARCHAR(20) NOT NULL)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "INSERT INTO t2 (id, name) VALUES "
+- "(4, 'Guam'), (5, 'Aruba'), "
+- "(6, 'Angola'), (7, 'Albania'), "
+- "(8, 'Anguilla'), (9, 'Argentina'), "
+- "(10, 'Azerbaijan'), (11, 'Afghanistan'), "
+- "(12, 'Burkina Faso'), (13, 'Faroe Islands')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 20, "rc != 20");
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_union2(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query= "select col1 FROM t1 where col1=1 union distinct "
+- "select col1 FROM t1 where col1=2";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1(col1 INT, \
+- col2 VARCHAR(40), \
+- col3 SMALLINT, \
+- col4 TIMESTAMP)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 0, "rowcount != 0");
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Misc tests to keep pure coverage happy */
+-
+-static int test_pure_coverage(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- int rc;
+- ulong length;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_pure");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_pure(c1 int, c2 varchar(20))");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "insert into test_pure(c67788) values(10)", strlen("insert into test_pure(c67788) values(10)"));
+- FAIL_IF(!rc, "Error expected");
+- mysql_stmt_close(stmt);
+-
+- /* Query without params and result should allow to bind 0 arrays */
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "insert into test_pure(c2) values(10)", strlen("insert into test_pure(c2) values(10)"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, (MYSQL_BIND*)0);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_result(stmt, (MYSQL_BIND*)0);
+- FAIL_UNLESS(rc == 1, "");
+-
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "insert into test_pure(c2) values(?)", strlen("insert into test_pure(c2) values(?)"));
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].length= &length;
+- my_bind[0].is_null= 0;
+- my_bind[0].buffer_length= 0;
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- FAIL_IF(!rc, "Error expected");
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "select * from test_pure", strlen("select * from test_pure"));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_stmt_store_result(stmt);
+- FAIL_UNLESS(rc, "");
+-
+- rc= mysql_stmt_store_result(stmt);
+- FAIL_UNLESS(rc, ""); /* Old error must be reset first */
+-
+- mysql_stmt_close(stmt);
+-
+- mysql_query(mysql, "DROP TABLE test_pure");
+- return OK;
+-}
+-
+-static int test_insert_select(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt_insert, *stmt_select;
+- char *query;
+- int rc;
+- uint i;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t2 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t2 values (1)");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"insert into t1 select a from t2";
+- stmt_insert= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_insert, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_insert, query, strlen(query));
+- check_stmt_rc(rc, stmt_insert);
+-
+- query= (char*)"select * from t1";
+- stmt_select= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_select, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_select, query, strlen(query));
+- check_stmt_rc(rc, stmt_select);
+-
+- for(i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt_insert);
+- check_stmt_rc(rc, stmt_insert);
+-
+- rc= mysql_stmt_execute(stmt_select);
+- check_stmt_rc(rc, stmt_select);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == (int)(i+1), "rc != i+1");
+- }
+-
+- mysql_stmt_close(stmt_insert);
+- mysql_stmt_close(stmt_select);
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test simple prepare-insert */
+-
+-static int test_insert(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char str_data[50];
+- char tiny_data;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[2];
+- ulong length;
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_insert");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_prep_insert(col1 tinyint, \
+- col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare */
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "INSERT INTO test_prep_insert VALUES(?, ?)",
+- strlen("INSERT INTO test_prep_insert VALUES(?, ?)"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "Param_count != 2");
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* tinyint */
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&tiny_data;
+-
+- /* string */
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= str_data;
+- my_bind[1].buffer_length= sizeof(str_data);;
+- my_bind[1].length= &length;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /* now, execute the prepared statement to insert 10 records.. */
+- for (tiny_data= 0; tiny_data < 3; tiny_data++)
+- {
+- length= sprintf(str_data, "MySQL%d", tiny_data);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM test_prep_insert");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS((int) tiny_data == rc, "rowcount != tinydata");
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-static int test_join(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i, j;
+- const char *query[]= {"SELECT * FROM t2 join t1 on (t1.a=t2.a)",
+- "SELECT * FROM t2 natural join t1",
+- "SELECT * FROM t2 join t1 using(a)",
+- "SELECT * FROM t2 left join t1 on(t1.a=t2.a)",
+- "SELECT * FROM t2 natural left join t1",
+- "SELECT * FROM t2 left join t1 using(a)",
+- "SELECT * FROM t2 right join t1 on(t1.a=t2.a)",
+- "SELECT * FROM t2 natural right join t1",
+- "SELECT * FROM t2 right join t1 using(a)"};
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t2 (a int , c int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "insert into t2 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);");
+- check_mysql_rc(rc, mysql);
+-
+- for (j= 0; j < 9; j++)
+- {
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query[j], strlen(query[j]));
+- check_stmt_rc(rc, stmt);
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 5, "rowcount != 5");
+- }
+- mysql_stmt_close(stmt);
+- }
+-
+- rc= mysql_query(mysql, "DROP TABLE t1, t2");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_left_join_view(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query=
+- "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
+-
+-
+- rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
+- check_mysql_rc(rc, mysql);
+-
+- rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
+- check_mysql_rc(rc, mysql);
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 3, "rowcount != 3");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test simple sample - manual */
+-
+-static int test_manual_sample(MYSQL *mysql)
+-{
+- unsigned int param_count;
+- MYSQL_STMT *stmt;
+- short small_data;
+- int int_data;
+- int rc;
+- char str_data[50];
+- ulonglong affected_rows;
+- MYSQL_BIND my_bind[3];
+- my_bool is_null;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- /*
+- Sample which is incorporated directly in the manual under Prepared
+- statements section (Example from mysql_stmt_execute()
+- */
+-
+- memset(str_data, 0, sizeof(str_data));
+- mysql_autocommit(mysql, 1);
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE test_table(col1 int, col2 varchar(50), \
+- col3 smallint, \
+- col4 timestamp)");
+- check_mysql_rc(rc, mysql);
+-
+- /* Prepare a insert query with 3 parameters */
+- strcpy(query, "INSERT INTO test_table(col1, col2, col3) values(?, ?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- /* Get the parameter count from the statement */
+- param_count= mysql_stmt_param_count(stmt);
+- FAIL_IF(param_count != 3, "param_count != 3");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* INTEGER PART */
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&int_data;
+-
+- /* STRING PART */
+- my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+- my_bind[1].buffer= (void *)str_data;
+- my_bind[1].buffer_length= sizeof(str_data);
+-
+- /* SMALLINT PART */
+- my_bind[2].buffer_type= MYSQL_TYPE_SHORT;
+- my_bind[2].buffer= (void *)&small_data;
+- my_bind[2].is_null= &is_null;
+- is_null= 0;
+-
+- /* Bind the buffers */
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /* Specify the data */
+- int_data= 10; /* integer */
+- strcpy(str_data, "MySQL"); /* string */
+-
+- /* INSERT SMALLINT data as NULL */
+- is_null= 1;
+-
+- /* Execute the insert statement - 1*/
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* Get the total rows affected */
+- affected_rows= mysql_stmt_affected_rows(stmt);
+- FAIL_IF(affected_rows != 1, "affected-rows != 1");
+-
+- /* Re-execute the insert, by changing the values */
+- int_data= 1000;
+- strcpy(str_data, "The most popular open source database");
+- small_data= 1000; /* smallint */
+- is_null= 0; /* reset */
+-
+- /* Execute the insert statement - 2*/
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* Get the total rows affected */
+- affected_rows= mysql_stmt_affected_rows(stmt);
+-
+- FAIL_IF(affected_rows != 1, "affected_rows != 1");
+-
+- /* Close the statement */
+- rc= mysql_stmt_close(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- /* DROP THE TABLE */
+- rc= mysql_query(mysql, "DROP TABLE test_table");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_create_drop(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select;
+- char *query;
+- int rc, i;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t2 (a int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (a int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t2 values (3), (2), (1);");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"create table t1 (a int)";
+- stmt_create= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_create, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_create, query, strlen(query));
+- check_stmt_rc(rc, stmt_create);
+-
+- query= (char*)"drop table t1";
+- stmt_drop= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_drop, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_drop, query, strlen(query));
+- check_stmt_rc(rc, stmt_drop);
+-
+- query= (char*)"select a in (select a from t2) from t1";
+- stmt_select= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_select, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_select, query, strlen(query));
+- check_stmt_rc(rc, stmt_select);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"create table t1 select a from t2";
+- stmt_create_select= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_create_select, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_create_select, query, strlen(query));
+- check_stmt_rc(rc, stmt_create_select);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt_create);
+- check_stmt_rc(rc, stmt_create);
+-
+- rc= mysql_stmt_execute(stmt_select);
+- check_stmt_rc(rc, stmt_select);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 0, "rowcount != 0");
+-
+- rc= mysql_stmt_execute(stmt_drop);
+- check_stmt_rc(rc, stmt_drop);
+-
+- rc= mysql_stmt_execute(stmt_create_select);
+- check_stmt_rc(rc, stmt_create);
+-
+- rc= mysql_stmt_execute(stmt_select);
+- check_stmt_rc(rc, stmt_select);
+- rc= 0;
+- while (mysql_stmt_fetch(stmt_select) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 3, "rowcount != 3");
+-
+- rc= mysql_stmt_execute(stmt_drop);
+- check_stmt_rc(rc, stmt_drop);
+- }
+-
+- mysql_stmt_close(stmt_create);
+- mysql_stmt_close(stmt_drop);
+- mysql_stmt_close(stmt_select);
+- mysql_stmt_close(stmt_create_select);
+-
+- rc= mysql_query(mysql, "DROP TABLE t2");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test DATE, TIME, DATETIME and TS with MYSQL_TIME conversion */
+-
+-static int test_date(MYSQL *mysql)
+-{
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \
+- c2 TIME, \
+- c3 DATETIME, \
+- c4 DATE)");
+-
+- check_mysql_rc(rc, mysql);
+-
+- return test_bind_date_conv(mysql, 5);
+-}
+-
+-
+-/* Test all time types to DATE and DATE to all types */
+-
+-static int test_date_date(MYSQL *mysql)
+-{
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_date(c1 DATE, \
+- c2 DATE, \
+- c3 DATE, \
+- c4 DATE)");
+-
+- check_mysql_rc(rc, mysql);
+-
+- return test_bind_date_conv(mysql, 3);
+-}
+-
+-/* Test all time types to TIMESTAMP and TIMESTAMP to all types */
+-
+-static int test_date_ts(MYSQL *mysql)
+-{
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \
+- c2 TIMESTAMP, \
+- c3 TIMESTAMP, \
+- c4 TIMESTAMP)");
+-
+- check_mysql_rc(rc, mysql);
+-
+- return test_bind_date_conv(mysql, 2);
+-}
+-
+-
+-/* Test all time types to DATETIME and DATETIME to all types */
+-
+-static int test_date_dt(MYSQL *mysql)
+-{
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_date(c1 datetime, "
+- " c2 datetime, c3 datetime, c4 date)");
+- check_mysql_rc(rc, mysql);
+-
+- return test_bind_date_conv(mysql, 2);
+-}
+-
+-/* Test all time types to TIME and TIME to all types */
+-
+-static int test_date_time(MYSQL *mysql)
+-{
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIME, \
+- c2 TIME, \
+- c3 TIME, \
+- c4 TIME)");
+-
+- check_mysql_rc(rc, mysql);
+-
+- return test_bind_date_conv(mysql, 3);
+-}
+-
+-/*
+- Test of basic checks that are performed in server for components
+- of MYSQL_TIME parameters.
+-*/
+-
+-static int test_datetime_ranges(MYSQL *mysql)
+-{
+- const char *stmt_text;
+- int rc, i;
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[6];
+- MYSQL_TIME tm[6];
+-
+-
+- stmt_text= "drop table if exists t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "create table t1 (year datetime, month datetime, day datetime, "
+- "hour datetime, min datetime, sec datetime)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- stmt_text= "INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_stmt_param_count(stmt) != 6, "param_count != 6");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < 6; i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_DATETIME;
+- my_bind[i].buffer= &tm[i];
+- }
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10;
+- tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
+- tm[0].second_part= 0; tm[0].neg= 0;
+-
+- tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
+- tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32;
+- tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_warning_count(mysql) != 12, "warning count != 12");
+-
+- if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "month", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "day", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "hour", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "min", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "sec", "0000-00-00 00:00:00"))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+-
+- stmt_text= "delete from t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "INSERT INTO t1 (year, month, day) VALUES (?, ?, ?)";
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- /*
+- We reuse contents of bind and tm arrays left from previous part of test.
+- */
+- for (i= 0; i < 3; i++)
+- my_bind[i].buffer_type= MYSQL_TYPE_DATE;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_warning_count(mysql) != 6, "warning count != 6");
+-
+- if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "month", "0000-00-00 00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "day", "0000-00-00 00:00:00"))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+-
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- stmt_text= "INSERT INTO t1 VALUES (?,?,?,?,?)";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_stmt_param_count(stmt) != 5, "param_count != 5");
+-
+- /*
+- Again we reuse what we can from previous part of test.
+- */
+- for (i= 0; i < 5; i++)
+- my_bind[i].buffer_type= MYSQL_TYPE_TIME;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- tm[0].year= 0; tm[0].month= 0; tm[0].day= 10;
+- tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
+- tm[0].second_part= 0; tm[0].neg= 0;
+-
+- tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
+- tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_IF(mysql_warning_count(mysql) != 2, "warning_count != 2");
+-
+- if (verify_col_data(mysql, "t1", "day_ovfl", "838:59:59"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "day", "828:30:30"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "hour", "270:30:30"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "min", "00:00:00"))
+- goto error;
+- if (verify_col_data(mysql, "t1", "sec", "00:00:00"))
+- goto error;
+-
+- mysql_stmt_close(stmt);
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-error:
+- mysql_stmt_close(stmt);
+- stmt_text= "drop table t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_derived(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- MYSQL_BIND my_bind[1];
+- int32 my_val= 0;
+- ulong my_length= 0L;
+- my_bool my_null= FALSE;
+- const char *query=
+- "select count(1) from (select f.id from t1 f where f.id=?) as x";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (id int(8), primary key (id)) \
+-ENGINE=InnoDB DEFAULT CHARSET=utf8");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (1)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&my_val;
+- my_bind[0].length= &my_length;
+- my_bind[0].is_null= (char*)&my_null;
+- my_val= 1;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_distinct(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query=
+- "SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), \
+-(1, 10), (2, 20), (3, 30), (4, 40), (5, 50);");
+- check_mysql_rc(rc, mysql);
+-
+- for (i= 0; i < 3; i++)
+- {
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 5, "rowcount != 5");
+- mysql_stmt_close(stmt);
+- }
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_do_set(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt_do, *stmt_set;
+- char *query;
+- int rc, i;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"do @var:=(1 in (select * from t1))";
+- stmt_do= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_do, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_do, query, strlen(query));
+- check_stmt_rc(rc, stmt_do);
+-
+- query= (char*)"set @var=(1 in (select * from t1))";
+- stmt_set= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_set, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_set, query, strlen(query));
+- check_stmt_rc(rc, stmt_set);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt_do);
+- check_stmt_rc(rc, stmt_do);
+- rc= mysql_stmt_execute(stmt_set);
+- check_stmt_rc(rc, stmt_set);
+- }
+-
+- mysql_stmt_close(stmt_do);
+- mysql_stmt_close(stmt_set);
+- return OK;
+-}
+-
+-static int test_double_compare(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char real_data[10], tiny_data;
+- double double_data;
+- MYSQL_RES *result;
+- MYSQL_BIND my_bind[3];
+- ulong length[3];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_double_compare");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_double_compare(col1 tinyint, "
+- " col2 float, col3 double )");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_double_compare "
+- "VALUES (1, 10.2, 34.5)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "UPDATE test_double_compare SET col1=100 "
+- "WHERE col1 = ? AND col2 = ? AND COL3 = ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 3, "param_count != 3");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* tinyint */
+- my_bind[0].buffer_type= MYSQL_TYPE_TINY;
+- my_bind[0].buffer= (void *)&tiny_data;
+-
+- /* string->float */
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)&real_data;
+- my_bind[1].buffer_length= sizeof(real_data);
+- my_bind[1].length= &length[1];
+- length[1]= 10;
+-
+- /* double */
+- my_bind[2].buffer_type= MYSQL_TYPE_DOUBLE;
+- my_bind[2].buffer= (void *)&double_data;
+-
+- tiny_data= 1;
+- strcpy(real_data, "10.2");
+- double_data= 34.5;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt), "affected_rows != 0");
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* test the results now, only one row should exist */
+- rc= mysql_query(mysql, "SELECT * FROM test_double_compare");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS((int)tiny_data == rc, "rowcount != tinydata");
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-static int test_multi(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt_delete, *stmt_update, *stmt_select1, *stmt_select2;
+- char *query;
+- MYSQL_BIND my_bind[1];
+- int rc, i;
+- int32 param= 1;
+- ulong length= 1;
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&param;
+- my_bind[0].length= &length;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1 (a int, b int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t2 (a int, b int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t1 values (3, 3), (2, 2), (1, 1)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into t2 values (3, 3), (2, 2), (1, 1)");
+- check_mysql_rc(rc, mysql);
+-
+- query= (char*)"delete t1, t2 from t1, t2 where t1.a=t2.a and t1.b=10";
+- stmt_delete= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_delete, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_delete, query, strlen(query));
+- check_stmt_rc(rc, stmt_delete);
+-
+- query= (char*)"update t1, t2 set t1.b=10, t2.b=10 where t1.a=t2.a and t1.b=?";
+- stmt_update= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_update, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_update, query, strlen(query));
+- check_stmt_rc(rc, stmt_update);
+-
+- query= (char*)"select * from t1";
+- stmt_select1= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_select1, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_select1, query, strlen(query));
+- check_stmt_rc(rc, stmt_select1);
+-
+- query= (char*)"select * from t2";
+- stmt_select2= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_select2, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_select2, query, strlen(query));
+- check_stmt_rc(rc, stmt_select2);
+-
+- for(i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_bind_param(stmt_update, my_bind);
+- check_stmt_rc(rc, stmt_update);
+-
+- rc= mysql_stmt_execute(stmt_update);
+- check_stmt_rc(rc, stmt_update);
+-
+- rc= mysql_stmt_execute(stmt_delete);
+- check_stmt_rc(rc, stmt_delete);
+-
+- rc= mysql_stmt_execute(stmt_select1);
+- check_stmt_rc(rc, stmt_select1);
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt_select1))
+- rc++;
+- FAIL_UNLESS(rc == 3-param, "rc != 3 - param");
+-
+- rc= mysql_stmt_execute(stmt_select2);
+- check_stmt_rc(rc, stmt_select2);
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt_select2))
+- rc++;
+- FAIL_UNLESS(rc == 3-param, "rc != 3 - param");
+-
+- param++;
+- }
+-
+- mysql_stmt_close(stmt_delete);
+- mysql_stmt_close(stmt_update);
+- mysql_stmt_close(stmt_select1);
+- mysql_stmt_close(stmt_select2);
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/* Multiple stmts .. */
+-
+-static int test_multi_stmt(MYSQL *mysql)
+-{
+-
+- MYSQL_STMT *stmt, *stmt1, *stmt2;
+- int rc;
+- uint32 id;
+- char name[50];
+- MYSQL_BIND my_bind[2];
+- ulong length[2];
+- my_bool is_null[2];
+- static char *query;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_multi_table");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_multi_table(id int, name char(20))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_multi_table values(10, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- query= "SELECT * FROM test_multi_table WHERE id=?";
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- stmt2= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt2, mysql_error(mysql));
+- query= "UPDATE test_multi_table SET name='updated' WHERE id=10";
+- rc= mysql_stmt_prepare(stmt2, query, strlen(query));
+- check_stmt_rc(rc, stmt2);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 1, "param_count != 1");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&id;
+- my_bind[0].is_null= &is_null[0];
+- my_bind[0].length= &length[0];
+- is_null[0]= 0;
+- length[0]= 0;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)name;
+- my_bind[1].buffer_length= sizeof(name);
+- my_bind[1].length= &length[1];
+- my_bind[1].is_null= &is_null[1];
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- id= 10;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- id= 999;
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(id == 10, "id != 10");
+- FAIL_UNLESS(strcmp(name, "mysql") == 0, "name != 'mysql'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "");
+-
+- /* alter the table schema now */
+- stmt1= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt1, mysql_error(mysql));
+- query= "DELETE FROM test_multi_table WHERE id=? AND CONVERT(name USING utf8)=?";
+- rc= mysql_stmt_prepare(stmt1, query, strlen(query));
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt1) != 2, "param_count != 2");
+-
+- rc= mysql_stmt_bind_param(stmt1, my_bind);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_execute(stmt2);
+- check_stmt_rc(rc, stmt2);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt2) != 1, "affected_rows != 1");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(id == 10, "id != 10");
+- FAIL_UNLESS(strcmp(name, "updated") == 0, "name != 'updated'");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt1) != 1, "affected_rows != 1");
+-
+- mysql_stmt_close(stmt1);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= my_stmt_result(mysql, "SELECT * FROM test_multi_table");
+- FAIL_UNLESS(rc == 0, "rc != 0");
+-
+- mysql_stmt_close(stmt);
+- mysql_stmt_close(stmt2);
+-
+- return OK;
+-}
+-
+-/* Test 'n' statements create and close */
+-
+-static int test_nstmts(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- char query[255];
+- int rc;
+- static uint i, total_stmts= 2000;
+- MYSQL_BIND my_bind[1];
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_nstmts");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_nstmts(id int)");
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)&i;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+-
+- for (i= 0; i < total_stmts; i++)
+- {
+- strcpy(query, "insert into test_nstmts values(?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+- }
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, " select count(*) from test_nstmts", strlen(" select count(*) from test_nstmts"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- i= 0;
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS( i == total_stmts, "total_stmts != i");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_nstmts");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test simple null */
+-
+-static int test_null(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- uint nData;
+- MYSQL_BIND my_bind[2];
+- my_bool is_null[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_null");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_null(col1 int, col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert by prepare, wrong column name */
+- strcpy(query, "INSERT INTO test_null(col3, col2) VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- FAIL_IF(!rc, "Error expected");
+- mysql_stmt_close(stmt);
+-
+- strcpy(query, "INSERT INTO test_null(col1, col2) VALUES(?, ?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].is_null= &is_null[0];
+- is_null[0]= 1;
+- my_bind[1]= my_bind[0];
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /* now, execute the prepared statement to insert 10 records.. */
+- for (nData= 0; nData<10; nData++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- /* Re-bind with MYSQL_TYPE_NULL */
+- my_bind[0].buffer_type= MYSQL_TYPE_NULL;
+- is_null[0]= 0; /* reset */
+- my_bind[1]= my_bind[0];
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (nData= 0; nData<10; nData++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- /* now fetch the results ..*/
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- nData*= 2;
+- rc= my_stmt_result(mysql, "SELECT * FROM test_null");;
+- FAIL_UNLESS((int) nData == rc, "rc != ndata");
+-
+- /* Fetch results */
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&nData; /* this buffer won't be altered */
+- my_bind[0].length= 0;
+- my_bind[1]= my_bind[0];
+- my_bind[0].is_null= &is_null[0];
+- my_bind[1].is_null= &is_null[1];
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_null", strlen("SELECT * FROM test_null"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- is_null[0]= is_null[1]= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- {
+- FAIL_UNLESS(is_null[0], "!is_null");
+- FAIL_UNLESS(is_null[1], "!is_null");
+- rc++;
+- is_null[0]= is_null[1]= 0;
+- }
+- FAIL_UNLESS(rc == (int) nData, "rc != nData");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_order_param(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- static char *query;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1(a INT, b char(10))");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- query= "select sum(a) + 200, 1 from t1 "
+- " union distinct "
+- "select sum(a) + 200, 1 from t1 group by b ";
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- query= "select sum(a) + 200, ? from t1 group by b "
+- " union distinct "
+- "select sum(a) + 200, 1 from t1 group by b ";
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- query= "select sum(a) + 200, ? from t1 "
+- " union distinct "
+- "select sum(a) + 200, 1 from t1 group by b ";
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_rename(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- const char *query= "rename table t1 to t2, t3 to t4";
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "create table t1 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Errr expected");
+-
+- rc= mysql_query(mysql, "create table t3 (a int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- FAIL_IF(!rc, "Errr expected");
+-
+- rc= mysql_query(mysql, "rename table t2 to t1, t4 to t3");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t2, t4");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_rewind(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind;
+- int rc = 0;
+- const char *stmt_text;
+- long unsigned int length=4, Data=0;
+- my_bool isnull=0;
+-
+-
+- stmt_text= "CREATE TABLE t1 (a int)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- stmt_text= "INSERT INTO t1 VALUES(2),(3),(4)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- stmt_text= "SELECT * FROM t1";
+- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+- check_stmt_rc(rc, stmt);
+-
+- memset(&my_bind, '\0', sizeof(MYSQL_BIND));
+- my_bind.buffer_type= MYSQL_TYPE_LONG;
+- my_bind.buffer= (void *)&Data; /* this buffer won't be altered */
+- my_bind.length= &length;
+- my_bind.is_null= &isnull;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, &my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- /* retreive all result sets till we are at the end */
+- while(!(rc=mysql_stmt_fetch(stmt)));
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* seek to the first row */
+- mysql_stmt_data_seek(stmt, 0);
+-
+- /* now we should be able to fetch the results again */
+- /* but mysql_stmt_fetch returns MYSQL_NO_DATA */
+- while(!(rc= mysql_stmt_fetch(stmt)));
+-
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- stmt_text= "DROP TABLE t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- rc= mysql_stmt_free_result(stmt);
+- rc= mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test simple select */
+-
+-static int test_select(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char szData[25];
+- int nData= 1;
+- MYSQL_BIND my_bind[2];
+- ulong length[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert a row and commit the transaction */
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')");
+- check_mysql_rc(rc, mysql);
+-
+- /* now insert the second row, and roll back the transaction */
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES(20, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT * FROM test_select WHERE id= ? "
+- "AND CONVERT(name USING utf8) =?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt) != 2, "param_count != 2");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- /* string data */
+- nData= 10;
+- strcpy(szData, (char *)"venu");
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)szData;
+- my_bind[1].buffer_length= 4;
+- my_bind[1].length= &length[1];
+- length[1]= 4;
+-
+- my_bind[0].buffer= (void *)&nData;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rc != 1");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test simple select with prepare */
+-
+-static int test_select_prepare(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_STMT *stmt;
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert a row and commit the transaction */
+- rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_select", strlen("SELECT * FROM test_select"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE test_select");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_select(id tinyint, id1 int, "
+- " id2 float, id3 float, "
+- " name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* insert a row and commit the transaction */
+- rc= mysql_query(mysql, "INSERT INTO test_select(id, id1, id2, name) VALUES(10, 5, 2.3, 'venu')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_select", strlen("SELECT * FROM test_select"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rowcount != 1");
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test simple show */
+-
+-static int test_select_show_table(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SHOW TABLES FROM mysql", strlen("SHOW TABLES FROM mysql"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt), "param_count != 0");
+-
+- for (i= 1; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- }
+-
+- while (!mysql_stmt_fetch(stmt));
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test simple select */
+-
+-static int test_select_version(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+-
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT @@version", strlen("SELECT @@version"));
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt), "param_count != 0");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- while (!mysql_stmt_fetch(stmt));
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-static int test_selecttmp(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query= "select a, (select count(distinct t1.b) as sum from t1, t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3";
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t2 (a int, b int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t3 (a int, b int);");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,
+- "insert into t1 values (0, 100), (1, 2), (1, 3), (2, 2), (2, 7), \
+-(2, -1), (3, 10);");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "insert into t2 values (0, 0), (1, 1), (2, 1), (3, 1), (4, 1);");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "insert into t3 values (3, 3), (2, 2), (1, 1);");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 3, "rowcount != 3");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1, t2, t3");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-static int test_set_option(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_RES *result;
+- int rc;
+-
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- /* LIMIT the rows count to 2 */
+- rc= mysql_query(mysql, "SET OPTION SQL_SELECT_LIMIT= 2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_limit");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_limit(a tinyint)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_limit VALUES(10), (20), (30), (40)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT * FROM test_limit");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 2, "rowcunt != 2");
+- mysql_free_result(result);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_limit", strlen("SELECT * FROM test_limit"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 2, "");
+-
+- mysql_stmt_close(stmt);
+-
+- /* RESET the LIMIT the rows count to 0 */
+- rc= mysql_query(mysql, "SET OPTION SQL_SELECT_LIMIT=DEFAULT");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "SELECT * FROM test_limit", strlen("SELECT * FROM test_limit"));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (!mysql_stmt_fetch(stmt))
+- rc++;
+- FAIL_UNLESS(rc == 4, "rowcount != 4");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test simple set-variable prepare */
+-
+-static int test_set_variable(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt, *stmt1;
+- int rc;
+- int set_count, def_count, get_count;
+- ulong length;
+- char var[NAME_LEN+1];
+- MYSQL_BIND set_bind[1], get_bind[2];
+-
+-
+- mysql_autocommit(mysql, TRUE);
+-
+- stmt1= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt1, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt1, "show variables like 'max_error_count'", strlen("show variables like 'max_error_count'"));
+- check_stmt_rc(rc, stmt1);
+-
+- memset(get_bind, '\0', sizeof(get_bind));
+-
+- get_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- get_bind[0].buffer= (void *)var;
+- get_bind[0].length= &length;
+- get_bind[0].buffer_length= (int)NAME_LEN;
+- length= NAME_LEN;
+-
+- get_bind[1].buffer_type= MYSQL_TYPE_LONG;
+- get_bind[1].buffer= (void *)&get_count;
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_bind_result(stmt1, get_bind);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- def_count= get_count;
+-
+- FAIL_UNLESS(strcmp(var, "max_error_count") == 0, "var != max_error_count");
+- rc= mysql_stmt_fetch(stmt1);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, "set max_error_count=?", strlen("set max_error_count=?"));
+- check_stmt_rc(rc, stmt);
+-
+- memset(set_bind, '\0', sizeof(set_bind));
+-
+- set_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- set_bind[0].buffer= (void *)&set_count;
+-
+- rc= mysql_stmt_bind_param(stmt, set_bind);
+- check_stmt_rc(rc, stmt);
+-
+- set_count= 31;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_commit(mysql);
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_UNLESS(get_count == set_count, "get_count != set_count");
+-
+- rc= mysql_stmt_fetch(stmt1);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- /* restore back to default */
+- set_count= def_count;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- rc= mysql_stmt_fetch(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_UNLESS(get_count == set_count, "get_count != set_count");
+-
+- rc= mysql_stmt_fetch(stmt1);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- mysql_stmt_close(stmt1);
+- return OK;
+-}
+-
+-/* Test SQLmode */
+-
+-static int test_sqlmode(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- char c1[5], c2[5];
+- int rc;
+- int ignore_space= 0;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_piping");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_piping(name varchar(10))");
+- check_mysql_rc(rc, mysql);
+-
+- /* PIPES_AS_CONCAT */
+- strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\"");
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)c1;
+- my_bind[0].buffer_length= 2;
+-
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= (void *)c2;
+- my_bind[1].buffer_length= 3;
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy(c1, "My"); strcpy(c2, "SQL");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- if (verify_col_data(mysql, "test_piping", "name", "MySQL"))
+- return FAIL;
+-
+- rc= mysql_query(mysql, "DELETE FROM test_piping");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT connection_id ()");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- /* ANSI */
+- strcpy(query, "SET SQL_MODE= \"ANSI\"");
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- strcpy(c1, "My"); strcpy(c2, "SQL");
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- mysql_stmt_close(stmt);
+- if (verify_col_data(mysql, "test_piping", "name", "MySQL"))
+- return FAIL;
+-
+- /* ANSI mode spaces ...
+- skip, if ignore_space was set
+- */
+- query_int_variable(mysql, "@@sql_mode LIKE '%IGNORE_SPACE%'", &ignore_space);
+-
+- if (!ignore_space)
+- {
+- strcpy(query, "SELECT connection_id ()");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- }
+- /* IGNORE SPACE MODE */
+- strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\"");
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT connection_id ()");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+- return OK;
+-}
+-
+-/* Test mysql_stmt_close for open stmts */
+-
+-static int test_stmt_close(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt1, *stmt2, *stmt3, *stmt_x;
+- MYSQL_BIND my_bind[1];
+- MYSQL_RES *result;
+- unsigned int count;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+-
+- mysql->reconnect= 1;
+-
+- /* set AUTOCOMMIT to ON*/
+- mysql_autocommit(mysql, TRUE);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stmt_close");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_stmt_close(id int)");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "DO \"nothing\"");
+- stmt1= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt1, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt1, query, strlen(query));
+- check_stmt_rc(rc, stmt1);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt1), "param_count != 0");
+-
+- strcpy(query, "INSERT INTO test_stmt_close(id) VALUES(?)");
+- stmt_x= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt_x, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt_x, query, strlen(query));
+- check_stmt_rc(rc, stmt_x);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt_x) != 1, "param_count != 1");
+-
+- strcpy(query, "UPDATE test_stmt_close SET id= ? WHERE id= ?");
+- stmt3= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt3, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt3, query, strlen(query));
+- check_stmt_rc(rc, stmt3);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt3) != 2, "param_count != 2");
+-
+- strcpy(query, "SELECT * FROM test_stmt_close WHERE id= ?");
+- stmt2= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt2, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt2, query, strlen(query));
+- check_stmt_rc(rc, stmt2);
+-
+- FAIL_IF(mysql_stmt_param_count(stmt2) != 1, "param_count != 1");
+-
+- rc= mysql_stmt_close(stmt1);
+- check_stmt_rc(rc, stmt1);
+-
+- /*
+- Originally we were going to close all statements automatically in
+- mysql_close(). This proved to not work well - users weren't able to
+- close statements by hand once mysql_close() had been called.
+- Now mysql_close() doesn't free any statements, so this test doesn't
+- serve its original designation any more.
+- Here we free stmt2 and stmt3 by hand to avoid memory leaks.
+- */
+- mysql_stmt_close(stmt2);
+- mysql_stmt_close(stmt3);
+-
+- /*
+- We need to bzero bind structure because mysql_stmt_bind_param checks all
+- its members.
+- */
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer= (void *)&count;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- count= 100;
+-
+- rc= mysql_stmt_bind_param(stmt_x, my_bind);
+- check_stmt_rc(rc, stmt_x);
+-
+- rc= mysql_stmt_execute(stmt_x);
+- check_stmt_rc(rc, stmt_x);
+-
+- FAIL_IF(mysql_stmt_affected_rows(stmt_x) != 1, "affected_rows != 1");
+-
+- rc= mysql_stmt_close(stmt_x);
+- check_stmt_rc(rc, stmt_x);
+-
+- rc= mysql_query(mysql, "SELECT id FROM test_stmt_close");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 1, "rwcount != 1");
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_prepare_insert_update", test_prepare_insert_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_simple", test_prepare_simple, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_syntax", test_prepare_syntax, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_field_result", test_prepare_field_result, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare", test_prepare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_ext", test_prepare_ext, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_multi_statements", test_prepare_multi_statements, TEST_CONNECTION_NEW, 0, NULL , NULL},
+- {"test_prepare_alter", test_prepare_alter, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_resultset", test_prepare_resultset, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_open_direct", test_open_direct, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_select_show", test_select_show, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_select", test_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_long_data", test_long_data, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_long_data_str", test_long_data_str, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_long_data_str1", test_long_data_str1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_long_data_bin", test_long_data_bin, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_simple_update", test_simple_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_simple_delete", test_simple_delete, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_update", test_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_prepare_noparam", test_prepare_noparam, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bind_result", test_bind_result, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bind_result_ext", test_bind_result_ext, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bind_result_ext1", test_bind_result_ext1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bind_negative", test_bind_negative, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_buffers", test_buffers, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_xjoin", test_xjoin, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_union", test_union, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_union2", test_union2, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_union_param", test_union_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_pure_coverage", test_pure_coverage, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_insert_select", test_insert_select, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_insert", test_insert, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_join", test_join, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_left_join_view", test_left_join_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_manual_sample", test_manual_sample, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_create_drop", test_create_drop, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_date", test_date, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_date_ts", test_date_ts, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_date_dt", test_date_dt, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_date_date", test_date_date, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_date_time", test_date_time, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_datetime_ranges", test_datetime_ranges, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_derived", test_derived, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_distinct", test_distinct, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_do_set", test_do_set, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_double_compare", test_double_compare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_multi", test_multi, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_multi_stmt", test_multi_stmt, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_nstmts", test_nstmts, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_null", test_null, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_order_param", test_order_param, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_rename", test_rename, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_rewind", test_rewind, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_select_prepare", test_select_prepare, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_select_show_table", test_select_show_table, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_select_version", test_select_version, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_selecttmp", test_selecttmp, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_set_option", test_set_option, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_set_variable", test_set_variable, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_sqlmode", test_sqlmode, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_stmt_close", test_stmt_close, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/result.c mariadb-native-client.trunk/unittest/libmysql/result.c
+--- mariadb/unittest/libmysql/result.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/result.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1064 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-/**
+- Some basic tests of the client API.
+-*/
+-
+-#include "my_test.h"
+-
+-static int client_store_result(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- int rc, rowcount= 0;
+-
+- rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL UNION SELECT 'bar' FROM DUAL");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- /* since we use store result, we should be able execute other api calls */
+- rc= mysql_ping(mysql);
+- FAIL_IF(rc, "mysql_ping failed");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 2, "rowcount != 2");
+-
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-static int client_use_result(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- int rc, rowcount= 0;
+-
+- rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL UNION SELECT 'bar' FROM DUAL");
+- check_mysql_rc(rc, mysql);
+-
+- /* get the result */
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- /* since we use use result, we shouldn't be able execute other api calls */
+- rc= mysql_ping(mysql);
+- FAIL_IF(!rc, "Error expected");
+-
+- while (mysql_fetch_row(result))
+- rowcount++;
+-
+- FAIL_IF(rowcount != 2, "rowcount != 2");
+-
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-static int test_free_result(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char c2[5];
+- ulong bl1, l2;
+- int rc, c1, bc1;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "drop table if exists test_free_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table test_free_result("
+- "c1 int primary key auto_increment)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into test_free_result values(), (), ()");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "select * from test_free_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&bc1;
+- my_bind[0].length= &bl1;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- c2[0]= '\0'; l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)c2;
+- my_bind[0].buffer_length= 7;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(strncmp(c2, "1", 1) == 0, "c2 != '1'");
+- FAIL_UNLESS(l2 == 1, "l2 != 1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- c1= 0, l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&c1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(c1 == 2, "c1 != 2");
+- FAIL_UNLESS(l2 == 4, "l2 != 4");
+-
+- rc= mysql_query(mysql, "drop table test_free_result");
+- FAIL_IF(!rc, "Error commands out of sync expected");
+-
+- rc= mysql_stmt_free_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "drop table test_free_result");
+- check_mysql_rc(rc, mysql); /* should be successful */
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-
+-/* Test mysql_stmt_store_result() */
+-
+-static int test_free_store_result(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[1];
+- char c2[5];
+- ulong bl1, l2;
+- int rc, c1, bc1;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "drop table if exists test_free_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table test_free_result(c1 int primary key auto_increment)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "insert into test_free_result values(), (), ()");
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "select * from test_free_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&bc1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &bl1;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- c2[0]= '\0'; l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (void *)c2;
+- my_bind[0].buffer_length= 7;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(strncmp(c2, "1", 1) == 0, "c2 != '1'");
+- FAIL_UNLESS(l2 == 1, "l2 != 1");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- c1= 0, l2= 0;
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *)&c1;
+- my_bind[0].buffer_length= 0;
+- my_bind[0].is_null= 0;
+- my_bind[0].length= &l2;
+-
+- rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(c1 == 2, "c1 != 2");
+- FAIL_UNLESS(l2 == 4, "l2 != 4");
+-
+- rc= mysql_stmt_free_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_query(mysql, "drop table test_free_result");
+- check_mysql_rc(rc, mysql);
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_store_result(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- int32 nData;
+- char szData[100];
+- MYSQL_BIND my_bind[2];
+- ulong length, length1;
+- my_bool is_null[2];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- /* fetch */
+- memset(my_bind, '\0', sizeof(my_bind));
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *) &nData; /* integer data */
+- my_bind[0].length= &length;
+- my_bind[0].is_null= &is_null[0];
+-
+- length= 0;
+- my_bind[1].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[1].buffer= szData; /* string data */
+- my_bind[1].buffer_length= sizeof(szData);
+- my_bind[1].length= &length1;
+- my_bind[1].is_null= &is_null[1];
+- length1= 0;
+-
+- strcpy(query, "SELECT * FROM test_store_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 10, "nData != 10");
+- FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
+- FAIL_UNLESS(length1 == 4, "length1 != 4");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 20, "nData != 20");
+- FAIL_UNLESS(strcmp(szData, "mysql") == 0, "szDaza != 'mysql'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- length= 99;
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(is_null[0], "isnull set");
+- FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'monty'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 10, "nData != 10");
+- FAIL_UNLESS(strcmp(szData, "venu") == 0, "szData != 'Venu'");
+- FAIL_UNLESS(length1 == 4, "length1 != 4");
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 20, "nData != 20");
+- FAIL_UNLESS(strcmp(szData, "mysql") == 0, "szDaza != 'mysql'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- length= 99;
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(is_null[0], "isnull set");
+- FAIL_UNLESS(strcmp(szData, "monty") == 0, "szData != 'monty'");
+- FAIL_UNLESS(length1 == 5, "length1 != 5");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-
+-/* Test simple bind store result */
+-
+-static int test_store_result1(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- strcpy(query, "SELECT * FROM test_store_result");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 3, "rowcount != 3");
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= 0;
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rc++;
+- FAIL_UNLESS(rc == 3, "rowcount != 3");
+-
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-
+-/* Another test for bind and store result */
+-
+-static int test_store_result2(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc;
+- int nData;
+- ulong length;
+- MYSQL_BIND my_bind[1];
+- char query[MAX_TEST_QUERY_LENGTH];
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_commit(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+-
+- my_bind[0].buffer_type= MYSQL_TYPE_LONG;
+- my_bind[0].buffer= (void *) &nData; /* integer data */
+- my_bind[0].length= &length;
+- my_bind[0].is_null= 0;
+-
+- strcpy((char *)query , "SELECT col1 FROM test_store_result where col1= ?");
+- stmt= mysql_stmt_init(mysql);
+- FAIL_IF(!stmt, mysql_error(mysql));
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- nData= 10; length= 0;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- nData= 0;
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 10, "nData != 10");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+-
+- nData= 20;
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- nData= 0;
+- rc= mysql_stmt_store_result(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- FAIL_UNLESS(nData == 20, "nData != 20");
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+- mysql_stmt_close(stmt);
+-
+- return OK;
+-}
+-
+-static int test_bug11718(MYSQL *mysql)
+-{
+- MYSQL_RES *res;
+- int rc;
+- const char *query= "select str_to_date(concat(f3),'%Y%m%d') from t1,t2 "
+- "where f1=f2 order by f1";
+-
+- rc= mysql_query(mysql, "drop table if exists t1, t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (f1 int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t2 (f2 int, f3 numeric(8))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1), (2)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (1,20050101), (2,20050202)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, query);
+- check_mysql_rc(rc, mysql);
+- res = mysql_store_result(mysql);
+-
+- FAIL_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE, "type != MYSQL_TYPE_DATE");
+- mysql_free_result(res);
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug19671(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- int rc;
+-
+- mysql_query(mysql, "set sql_mode=''");
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, "drop view if exists v1");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, "create table t1(f1 int)");
+- check_mysql_rc(rc, mysql)
+-
+- rc= mysql_query(mysql, "create view v1 as select va.* from t1 va");
+- check_mysql_rc(rc, mysql)
+-
+- result= mysql_list_fields(mysql, "v1", NULL);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 0, "");
+-
+- if (verify_prepare_field(result, 0, "f1", "f1", MYSQL_TYPE_LONG,
+- "v1", "v1", schema, 11, "0")) {
+- mysql_free_result(result);
+- diag("verify_prepare_field failed");
+- return FAIL;
+- }
+-
+- mysql_free_result(result);
+- check_mysql_rc(mysql_query(mysql, "drop view v1"), mysql)
+- check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql)
+- return OK;
+-}
+-
+-/*
+- Bug#21726: Incorrect result with multiple invocations of
+- LAST_INSERT_ID
+-
+- Test that client gets updated value of insert_id on UPDATE that uses
+- LAST_INSERT_ID(expr).
+- select_query added to test for bug
+- #26921 Problem in mysql_insert_id() Embedded C API function
+-*/
+-static int test_bug21726(MYSQL *mysql)
+-{
+- const char *create_table[]=
+- {
+- "DROP TABLE IF EXISTS t1",
+- "CREATE TABLE t1 (i INT)",
+- "INSERT INTO t1 VALUES (1)",
+- };
+- const char *update_query= "UPDATE t1 SET i= LAST_INSERT_ID(i + 1)";
+- int rc;
+- my_ulonglong insert_id;
+- const char *select_query= "SELECT * FROM t1";
+- MYSQL_RES *result;
+-
+- rc= mysql_query(mysql, create_table[0]);
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, create_table[1]);
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, create_table[2]);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, update_query);
+- check_mysql_rc(rc, mysql)
+- insert_id= mysql_insert_id(mysql);
+- FAIL_UNLESS(insert_id == 2, "insert_id != 2");
+-
+- rc= mysql_query(mysql, update_query);
+- check_mysql_rc(rc, mysql)
+- insert_id= mysql_insert_id(mysql);
+- FAIL_UNLESS(insert_id == 3, "insert_id != 3");
+-
+- rc= mysql_query(mysql, select_query);
+- check_mysql_rc(rc, mysql)
+- insert_id= mysql_insert_id(mysql);
+- FAIL_UNLESS(insert_id == 3, "insert_id != 3");
+- result= mysql_store_result(mysql);
+- mysql_free_result(result);
+-
+- return OK;
+-}
+-
+-/* Bug#6761 - mysql_list_fields doesn't work */
+-
+-static int test_bug6761(MYSQL *mysql)
+-{
+- const char *stmt_text;
+- MYSQL_RES *res;
+- int rc;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+- check_mysql_rc(rc, mysql);
+-
+- stmt_text= "CREATE TABLE t1 (a int, b char(255), c decimal)";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+-
+- res= mysql_list_fields(mysql, "t1", "%");
+- FAIL_UNLESS(res && mysql_num_fields(res) == 3, "num_fields != 3");
+- mysql_free_result(res);
+-
+- stmt_text= "DROP TABLE t1";
+- rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+- check_mysql_rc(rc, mysql);
+- return OK;
+-}
+-
+-/* Test field flags (verify .NET provider) */
+-
+-static int test_field_flags(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+- MYSQL_FIELD *field;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_flags");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_field_flags(id int NOT NULL AUTO_INCREMENT PRIMARY KEY, \
+- id1 int NOT NULL, \
+- id2 int UNIQUE, \
+- id3 int, \
+- id4 int NOT NULL, \
+- id5 int, \
+- KEY(id3, id4))");
+- check_mysql_rc(rc, mysql);
+-
+- /* with table name included with TRUE column name */
+- rc= mysql_query(mysql, "SELECT * FROM test_field_flags");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- mysql_field_seek(result, 0);
+-
+- field= mysql_fetch_field(result);
+- FAIL_UNLESS(field->flags & NOT_NULL_FLAG &&
+- field->flags & PRI_KEY_FLAG &&
+- field->flags & AUTO_INCREMENT_FLAG, "Wrong flags for field 0");
+-
+- field= mysql_fetch_field(result);
+- FAIL_UNLESS(field->flags & NOT_NULL_FLAG, "Wrong flags for field 1");
+-
+- field= mysql_fetch_field(result);
+- FAIL_UNLESS(field->flags & UNIQUE_KEY_FLAG, "Wrong flags for field 2");
+-
+- field= mysql_fetch_field(result);
+- FAIL_UNLESS(field->flags & MULTIPLE_KEY_FLAG, "Wrong flags for field 3");
+-
+- field= mysql_fetch_field(result);
+- FAIL_UNLESS(field->flags & NOT_NULL_FLAG, "Wrong flags for field 4");
+-
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-/* Test real and alias names */
+-
+-static int test_field_names(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+-
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names2");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_field_names1(id int, name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_field_names2(id int, name varchar(50))");
+- check_mysql_rc(rc, mysql);
+-
+- /* with table name included with TRUE column name */
+- rc= mysql_query(mysql, "SELECT id as 'id-alias' FROM test_field_names1");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 0, "rowcount != 0");
+- mysql_free_result(result);
+-
+- /* with table name included with TRUE column name */
+- rc= mysql_query(mysql, "SELECT t1.id as 'id-alias', test_field_names2.name FROM test_field_names1 t1, test_field_names2");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_use_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 0, "rowcount != 0");
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-/* Test FUNCTION field info / DATE_FORMAT() table_name . */
+-
+-static int test_func_fields(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *result;
+- MYSQL_FIELD *field;
+-
+-
+- rc= mysql_autocommit(mysql, TRUE);
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_dateformat");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "CREATE TABLE test_dateformat(id int, \
+- ts timestamp)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "INSERT INTO test_dateformat(id) values(10)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT ts FROM test_dateformat");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(!field, "Invalid field");
+- FAIL_UNLESS(strcmp(field->table, "test_dateformat") == 0, "field->table != 'test_dateformat'");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(field, "no more fields expected");
+-
+- mysql_free_result(result);
+-
+- /* DATE_FORMAT */
+- rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'venu' FROM test_dateformat");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(!field, "Invalid field");
+- FAIL_UNLESS(field->table[0] == '\0', "field->table != ''");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(field, "no more fields expected");
+-
+- mysql_free_result(result);
+-
+- /* FIELD ALIAS TEST */
+- rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'YEAR' FROM test_dateformat");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(!field, "Invalid field");
+- FAIL_UNLESS(strcmp(field->name, "YEAR") == 0, "name != 'YEAR'");
+- FAIL_UNLESS(field->org_name[0] == '\0', "org_name != ''");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(field, "no more fields expected");
+-
+- mysql_free_result(result);
+- return OK;
+-}
+-
+-/* Test mysql_list_fields() */
+-
+-static int test_list_fields(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- int rc;
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10) default 'mysql')");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_list_fields(mysql, "t1", NULL);
+- FAIL_IF(!result, "Invalid result set");
+-
+- rc= 0;
+- while (mysql_fetch_row(result))
+- rc++;
+- FAIL_UNLESS(rc == 0, "rowcount != 0");
+-
+- if (verify_prepare_field(result, 0, "c1", "c1", MYSQL_TYPE_LONG,
+- "t1", "t1",
+- schema, 11, "0"))
+- goto error;
+-
+- if (verify_prepare_field(result, 1, "c2", "c2", MYSQL_TYPE_STRING,
+- "t1", "t1",
+- schema, 10, "mysql"))
+- goto error;
+-
+- mysql_free_result(result);
+- check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql);
+- return OK;
+-
+-error:
+- mysql_free_result(result);
+- check_mysql_rc(mysql_query(mysql, "drop table t1"), mysql);
+- return FAIL;
+-}
+-
+-/* Test correct max length for MEDIUMTEXT and LONGTEXT columns */
+-
+-static int test_bug9735(MYSQL *mysql)
+-{
+- MYSQL_RES *res;
+- int rc;
+-
+-
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (a mediumtext, b longtext) "
+- "character set latin1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "select * from t1");
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- if (verify_prepare_field(res, 0, "a", "a", MYSQL_TYPE_BLOB,
+- "t1", "t1", schema, (1U << 24)-1, 0))
+- goto error;
+- if (verify_prepare_field(res, 1, "b", "b", MYSQL_TYPE_BLOB,
+- "t1", "t1", schema, ~0U, 0))
+- goto error;
+- mysql_free_result(res);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+- return OK;
+-error:
+- mysql_free_result(res);
+- rc= mysql_query(mysql, "drop table t1");
+- return FAIL;
+-}
+-
+-/*
+- Check that mysql_next_result works properly in case when one of
+- the statements used in a multi-statement query is erroneous
+-*/
+-
+-static int test_bug9992(MYSQL *mysql)
+-{
+- MYSQL_RES* res ;
+- int rc;
+-
+- /* Sic: SHOW DATABASE is incorrect syntax. */
+- rc= mysql_query(mysql, "SHOW TABLES; SHOW DATABASE; SELECT 1;");
+- check_mysql_rc(rc, mysql);
+-
+- res= mysql_store_result(mysql);
+- FAIL_UNLESS(res, "Invalid resultset");
+- mysql_free_result(res);
+- rc= mysql_next_result(mysql);
+- FAIL_UNLESS(rc == 1, "Error expected"); /* Got errors, as expected */
+-
+- return OK;
+-}
+-
+-/* Test the support of multi-statement executions */
+-
+-static int test_multi_statements(MYSQL *mysql)
+-{
+- MYSQL *mysql_local;
+- MYSQL_RES *result;
+- int rc;
+-
+- const char *query= "\
+-DROP TABLE IF EXISTS test_multi_tab;\
+-CREATE TABLE test_multi_tab(id int, name char(20));\
+-INSERT INTO test_multi_tab(id) VALUES(10), (20);\
+-INSERT INTO test_multi_tab VALUES(20, 'insert;comma');\
+-SELECT * FROM test_multi_tab;\
+-UPDATE test_multi_tab SET name='new;name' WHERE id=20;\
+-DELETE FROM test_multi_tab WHERE name='new;name';\
+-SELECT * FROM test_multi_tab;\
+-DELETE FROM test_multi_tab WHERE id=10;\
+-SELECT * FROM test_multi_tab;\
+-DROP TABLE test_multi_tab;\
+-select 1;\
+-DROP TABLE IF EXISTS test_multi_tab";
+- uint count, exp_value;
+- uint rows[]= {0, 0, 2, 1, 3, 2, 2, 1, 1, 0, 0, 1, 0};
+-
+- /*
+- First test that we get an error for multi statements
+- (Because default connection is not opened with CLIENT_MULTI_STATEMENTS)
+- */
+- mysql_local= mysql;
+- mysql = test_connect(NULL);
+- rc= mysql_query(mysql, query); /* syntax error */
+- FAIL_IF(!rc, "Error expected");
+-
+- rc= mysql_next_result(mysql);
+- FAIL_UNLESS(rc == -1, "rc != -1");
+- rc= mysql_more_results(mysql);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+-
+- mysql_close(mysql);
+- mysql= mysql_local;
+-
+- mysql_local->reconnect= 1;
+-
+- rc= mysql_query(mysql_local, query);
+- check_mysql_rc(rc, mysql);
+-
+- for (count= 0 ; count < array_elements(rows) ; count++)
+- {
+- if ((result= mysql_store_result(mysql_local)))
+- {
+- mysql_free_result(result);
+- }
+-
+- exp_value= (uint) mysql_affected_rows(mysql_local);
+- FAIL_IF(rows[count] != exp_value, "row[count] != exp_value");
+- if (count != array_elements(rows) -1)
+- {
+- rc= mysql_more_results(mysql_local);
+- FAIL_IF(!rc, "More results expected");
+- rc= mysql_next_result(mysql_local);
+- check_mysql_rc(rc, mysql_local);
+- }
+- else
+- {
+- rc= mysql_more_results(mysql_local);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- rc= mysql_next_result(mysql_local);
+- FAIL_UNLESS(rc == -1, "rc != -1");
+- }
+- }
+-
+- /* check that errors abort multi statements */
+-
+- rc= mysql_query(mysql_local, "select 1+1+a;select 1+1");
+- FAIL_IF(!rc, "Error expected");
+- rc= mysql_more_results(mysql_local);
+- FAIL_UNLESS(rc == 0, "rc != 0");
+- rc= mysql_next_result(mysql_local);
+- FAIL_UNLESS(rc == -1, "rc != -1");
+-
+- rc= mysql_query(mysql_local, "select 1+1;select 1+1+a;select 1");
+- check_mysql_rc(rc, mysql);
+- result= mysql_store_result(mysql_local);
+- FAIL_IF(!result, "Invalid result set");
+- mysql_free_result(result);
+- rc= mysql_more_results(mysql_local);
+- FAIL_UNLESS(rc == 1, "rc != 1");
+- rc= mysql_next_result(mysql_local);
+- FAIL_UNLESS(rc > 0, "rc <= 0");
+-
+- /*
+- Ensure that we can now do a simple query (this checks that the server is
+- not trying to send us the results for the last 'select 1'
+- */
+- rc= mysql_query(mysql_local, "select 1+1+1");
+- check_mysql_rc(rc, mysql);
+- result= mysql_store_result(mysql_local);
+- FAIL_IF(!result, "Invalid result set");
+- mysql_free_result(result);
+-
+- /*
+- Check if errors in one of the queries handled properly.
+- */
+- rc= mysql_query(mysql_local, "select 1; select * from not_existing_table");
+- check_mysql_rc(rc, mysql);
+- result= mysql_store_result(mysql_local);
+- mysql_free_result(result);
+-
+- rc= mysql_next_result(mysql_local);
+- FAIL_UNLESS(rc > 0, "rc <= 0");
+-
+- rc= mysql_next_result(mysql_local);
+- FAIL_UNLESS(rc < 0, "rc >= 0");
+-
+- return OK;
+-}
+-
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"client_store_result", client_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"client_use_result", client_use_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_free_result", test_free_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_free_store_result", test_free_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_store_result", test_store_result, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_store_result1", test_store_result1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_store_result2", test_store_result2, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug11718", test_bug11718, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug19671", test_bug19671, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug21726", test_bug21726, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug6761", test_bug6761, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_field_flags", test_field_flags, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_field_names", test_field_names, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_func_fields", test_func_fields, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_list_fields", test_list_fields, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug9735", test_bug9735, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+- {"test_bug9992", test_bug9992, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
+- {"test_multi_statements", test_multi_statements, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/sp.c mariadb-native-client.trunk/unittest/libmysql/sp.c
+--- mariadb/unittest/libmysql/sp.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/sp.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,91 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-/* Bug#15752 "Lost connection to MySQL server when calling a SP from C API" */
+-
+-static int test_bug15752(MYSQL *mysql)
+-{
+- int rc, i;
+- const int ITERATION_COUNT= 100;
+- const char *query= "CALL p1()";
+-
+-
+- rc= mysql_query(mysql, "drop procedure if exists p1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create procedure p1() select 1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_real_query(mysql, query, strlen(query));
+- check_mysql_rc(rc, mysql);
+- mysql_free_result(mysql_store_result(mysql));
+-
+- rc= mysql_real_query(mysql, query, strlen(query));
+- FAIL_UNLESS(rc && mysql_errno(mysql) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
+-
+- rc= mysql_next_result(mysql);
+- check_mysql_rc(rc, mysql);
+-
+- mysql_free_result(mysql_store_result(mysql));
+-
+- rc= mysql_next_result(mysql);
+- FAIL_IF(rc != -1, "rc != -1");
+-
+- for (i = 0; i < ITERATION_COUNT; i++)
+- {
+- rc= mysql_real_query(mysql, query, strlen(query));
+- check_mysql_rc(rc, mysql);
+- mysql_free_result(mysql_store_result(mysql));
+- rc= mysql_next_result(mysql);
+- check_mysql_rc(rc, mysql);
+- mysql_free_result(mysql_store_result(mysql));
+- rc= mysql_next_result(mysql);
+- FAIL_IF(rc != -1, "rc != -1");
+-
+- }
+- rc= mysql_query(mysql, "drop procedure p1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_bug15752", test_bug15752, TEST_CONNECTION_NEW, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/ssl.c mariadb-native-client.trunk/unittest/libmysql/ssl.c
+--- mariadb/unittest/libmysql/ssl.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/ssl.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,239 +0,0 @@
+-/************************************************************************************
+- Copyright (C) 2012 Monty Program AB
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public
+- License as published by the Free Software Foundation; either
+- version 2 of the License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; if not see <http://www.gnu.org/licenses>
+- or write to the Free Software Foundation, Inc.,
+- 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+- *************************************************************************************/
+-
+-#include "my_test.h"
+-#include <my_pthread.h>
+-
+-static int skip_ssl= 1;
+-
+-#ifdef THREAD
+-pthread_mutex_t LOCK_test;
+-#endif
+-
+-int check_skip_ssl()
+-{
+-#ifndef HAVE_OPENSSL
+- diag("client library built without OpenSSL support -> skip");
+- return 1;
+-#endif
+- if (skip_ssl)
+- {
+- diag("server doesn't support SSL -> skip");
+- return 1;
+- }
+- return 0;
+-}
+-
+-static int test_ssl(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+-
+- rc= mysql_query(mysql, "SELECT @@have_ssl");
+- check_mysql_rc(rc, mysql);
+-
+- res= mysql_store_result(mysql);
+- FAIL_IF(!res, mysql_error(mysql));
+-
+- if ((row= mysql_fetch_row(res)))
+- {
+- if (!strcmp(row[0], "YES"))
+- skip_ssl= 0;
+- diag("SSL: %s", row[0]);
+- }
+- mysql_free_result(res);
+-
+- return OK;
+-}
+-
+-static int test_ssl_cipher(MYSQL *unused)
+-{
+- MYSQL *my;
+- char *cipher;
+-
+- if (check_skip_ssl())
+- return SKIP;
+-
+- my= mysql_init(NULL);
+- FAIL_IF(!my, "mysql_init() failed");
+-
+- mysql_ssl_set(my,0, 0, "./ca.pem", 0);
+-
+- FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
+- port, socketname, 0), mysql_error(my));
+-
+- cipher= (char *)mysql_get_ssl_cipher(my);
+- FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
+- mysql_close(my);
+- return OK;
+-}
+-
+-static int test_multi_ssl_connections(MYSQL *unused)
+-{
+- MYSQL *mysql[50], *my;
+- char *cipher;
+- int i, rc;
+- int old_connections= 0, new_connections= 0;
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+-
+- if (check_skip_ssl())
+- return SKIP;
+-
+- my= mysql_init(NULL);
+- FAIL_IF(!my,"mysql_init() failed");
+- FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema,
+- port, socketname, 0), mysql_error(my));
+-
+- rc= mysql_query(my, "SHOW STATUS LIKE 'Ssl_accepts'");
+- check_mysql_rc(rc, my);
+-
+- res= mysql_store_result(my);
+- if ((row= mysql_fetch_row(res)))
+- old_connections= atoi(row[1]);
+- mysql_free_result(res);
+-
+- for (i=0; i < 50; i++)
+- {
+- mysql[i]= mysql_init(NULL);
+- FAIL_IF(!mysql[i],"mysql_init() failed");
+-
+- mysql_ssl_set(mysql[i], 0, 0, "./ca.pem", 0);
+-
+- FAIL_IF(!mysql_real_connect(mysql[i], hostname, username, password, schema,
+- port, socketname, 0), mysql_error(mysql[i]));
+-
+- cipher= (char *)mysql_get_ssl_cipher(mysql[i]);
+- FAIL_IF(strcmp(cipher, "DHE-RSA-AES256-SHA") != 0, "Cipher != DHE-RSA-AES256-SHA");
+- }
+- for (i=0; i < 50; i++)
+- mysql_close(mysql[i]);
+-
+- rc= mysql_query(my, "SHOW STATUS LIKE 'Ssl_accepts'");
+- check_mysql_rc(rc, my);
+-
+- res= mysql_store_result(my);
+- if ((row= mysql_fetch_row(res)))
+- new_connections= atoi(row[1]);
+- mysql_free_result(res);
+-
+- mysql_close(my);
+-
+- FAIL_IF(new_connections - old_connections < 50, "new_connections should be at least old_connections + 50");
+- diag("%d SSL connections processed", new_connections - old_connections);
+- return OK;
+-}
+-
+-#ifndef WIN32
+-#ifdef THREAD
+-static void ssl_thread(void)
+-{
+- MYSQL *mysql;
+-
+- mysql_thread_init();
+-
+- if (!(mysql= mysql_init(NULL)))
+- {
+- mysql_thread_end();
+- pthread_exit(-1);
+- }
+- mysql_ssl_set(mysql, 0, 0, "./ca.pem", 0);
+-
+- if(!mysql_real_connect(mysql, hostname, username, password, schema,
+- port, socketname, 0))
+- {
+- diag("Error: %s", mysql_error(mysql));
+- mysql_close(mysql);
+- mysql_thread_end();
+- pthread_exit(-1);
+- }
+-
+- pthread_mutex_lock(&LOCK_test);
+- mysql_query(mysql, "UPDATE ssltest SET a=a+1");
+- pthread_mutex_unlock(&LOCK_test);
+- mysql_close(mysql);
+- mysql_thread_end();
+- pthread_exit(0);
+-}
+-#endif
+-
+-static int test_ssl_threads(MYSQL *mysql)
+-{
+-#ifdef THREAD
+- int i, rc;
+- pthread_t thread[50];
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+-
+- rc= mysql_query(mysql, "DROP TABLE IF exists ssltest");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE ssltest (a int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT into ssltest VALUES (0)");
+- check_mysql_rc(rc, mysql);
+-
+- pthread_mutex_init(&LOCK_test, NULL);
+-
+- for (i=0; i < 50; i++)
+- pthread_create(&thread[i], NULL, (void *)&ssl_thread, NULL);
+- for (i=0; i < 50; i++)
+- pthread_join(thread[i], NULL);
+-
+- pthread_mutex_destroy(&LOCK_test);
+-
+- rc= mysql_query(mysql, "SELECT a FROM ssltest");
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- row= mysql_fetch_row(res);
+- diag("Found: %s", row[0]);
+- FAIL_IF(strcmp(row[0], "50") != 0, "Expected 50");
+- mysql_free_result(res);
+- return OK;
+-#else
+- diag("no thread support -> skip");
+- return SKIP;
+-#endif
+-}
+-#endif
+-
+-struct my_tests_st my_tests[] = {
+- {"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
+- {"test_ssl_cipher", test_ssl_cipher, TEST_CONNECTION_NONE, 0, NULL, NULL},
+- {"test_multi_ssl_connections", test_multi_ssl_connections, TEST_CONNECTION_NONE, 0, NULL, NULL},
+-#ifndef WIN32
+- {"test_ssl_threads", test_ssl_threads, TEST_CONNECTION_NEW, 0, NULL, NULL},
+-#endif
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-
+-int main(int argc, char **argv)
+-{
+- get_envvars();
+-
+- if (argc > 1)
+- get_options(argc, argv);
+-
+-
+- run_tests(my_tests);
+-
+- mysql_server_end();
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/unittest/libmysql/view.c mariadb-native-client.trunk/unittest/libmysql/view.c
+--- mariadb/unittest/libmysql/view.c 2013-10-19 08:05:08.000000000 +0200
++++ mariadb/unittest/libmysql/view.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,700 +0,0 @@
+-/*
+-Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+-
+-The MySQL Connector/C is licensed under the terms of the GPLv2
+-<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+-MySQL Connectors. There are special exceptions to the terms and
+-conditions of the GPLv2 as it is applied to this software, see the
+-FLOSS License Exception
+-<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published
+-by the Free Software Foundation; version 2 of the License.
+-
+-This program is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+-for more details.
+-
+-You should have received a copy of the GNU General Public License along
+-with this program; if not, write to the Free Software Foundation, Inc.,
+-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-*/
+-#include "my_test.h"
+-
+-static int test_view(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- MYSQL_BIND my_bind[1];
+- char str_data[50];
+- ulong length = 0L;
+- long is_null = 0L;
+- const char *query=
+- "SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?";
+-
+- rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3,v1");
+- check_mysql_rc(rc, mysql);
+-
+- rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1,t2,t3");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE TABLE t1 ("
+- " SERVERGRP varchar(20) NOT NULL default '', "
+- " DBINSTANCE varchar(20) NOT NULL default '', "
+- " PRIMARY KEY (SERVERGRP)) "
+- " CHARSET=latin1 collate=latin1_bin");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE TABLE t2 ("
+- " SERVERNAME varchar(20) NOT NULL, "
+- " SERVERGRP varchar(20) NOT NULL, "
+- " PRIMARY KEY (SERVERNAME)) "
+- " CHARSET=latin1 COLLATE latin1_bin");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE TABLE t3 ("
+- " SERVERGRP varchar(20) BINARY NOT NULL, "
+- " TABNAME varchar(30) NOT NULL, MAPSTATE char(1) NOT NULL, "
+- " ACTSTATE char(1) NOT NULL , "
+- " LOCAL_NAME varchar(30) NOT NULL, "
+- " CHG_DATE varchar(8) NOT NULL default '00000000', "
+- " CHG_TIME varchar(6) NOT NULL default '000000', "
+- " MXUSER varchar(12) NOT NULL default '', "
+- " PRIMARY KEY (SERVERGRP, TABNAME, MAPSTATE, ACTSTATE, "
+- " LOCAL_NAME)) CHARSET=latin1 COLLATE latin1_bin");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE VIEW v1 AS select sql_no_cache"
+- " T0001.SERVERNAME AS SERVERNAME, T0003.TABNAME AS"
+- " TABNAME,T0003.LOCAL_NAME AS LOCAL_NAME,T0002.DBINSTANCE AS"
+- " DBINSTANCE from t2 T0001 join t1 T0002 join t3 T0003 where"
+- " ((T0002.SERVERGRP = T0001.SERVERGRP) and"
+- " (T0002.SERVERGRP = T0003.SERVERGRP)"
+- " and (T0003.MAPSTATE = _latin1'A') and"
+- " (T0003.ACTSTATE = _latin1' '))");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- strcpy(str_data, "TEST");
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+- my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[0].buffer= (char *)&str_data;
+- my_bind[0].buffer_length= 50;
+- my_bind[0].length= &length;
+- length= 4;
+- my_bind[0].is_null= (char*)&is_null;
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int rowcount= 0;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_IF(rowcount != 1, "Expected 1 row");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1,t2,t3");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_view_where(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query=
+- "select v1.c,v2.c from v1, v2";
+-
+- rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1,v2");
+- check_mysql_rc(rc, mysql);
+-
+- rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,v2,t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE TABLE t1 (a int, b int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"create view v1 (c) as select b from t1 where a<3");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"create view v2 (c) as select b from t1 where a>=3");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int rowcount= 0;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_UNLESS(4 == rowcount, "Expected 4 rows");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW v1, v2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_view_2where(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- MYSQL_BIND my_bind[8];
+- char parms[8][100];
+- ulong length[8];
+- const char *query=
+- "select relid, report, handle, log_group, username, variant, type, "
+- "version, erfdat, erftime, erfname, aedat, aetime, aename, dependvars, "
+- "inactive from V_LTDX where mandt = ? and relid = ? and report = ? and "
+- "handle = ? and log_group = ? and username in ( ? , ? ) and type = ?";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS LTDX");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS V_LTDX");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE TABLE LTDX (MANDT char(3) NOT NULL default '000', "
+- " RELID char(2) NOT NULL, REPORT varchar(40) NOT NULL,"
+- " HANDLE varchar(4) NOT NULL, LOG_GROUP varchar(4) NOT NULL,"
+- " USERNAME varchar(12) NOT NULL,"
+- " VARIANT varchar(12) NOT NULL,"
+- " TYPE char(1) NOT NULL, SRTF2 int(11) NOT NULL,"
+- " VERSION varchar(6) NOT NULL default '000000',"
+- " ERFDAT varchar(8) NOT NULL default '00000000',"
+- " ERFTIME varchar(6) NOT NULL default '000000',"
+- " ERFNAME varchar(12) NOT NULL,"
+- " AEDAT varchar(8) NOT NULL default '00000000',"
+- " AETIME varchar(6) NOT NULL default '000000',"
+- " AENAME varchar(12) NOT NULL,"
+- " DEPENDVARS varchar(10) NOT NULL,"
+- " INACTIVE char(1) NOT NULL, CLUSTR smallint(6) NOT NULL,"
+- " CLUSTD blob,"
+- " PRIMARY KEY (MANDT, RELID, REPORT, HANDLE, LOG_GROUP, "
+- "USERNAME, VARIANT, TYPE, SRTF2))"
+- " CHARSET=latin1 COLLATE latin1_bin");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE VIEW V_LTDX AS select T0001.MANDT AS "
+- " MANDT,T0001.RELID AS RELID,T0001.REPORT AS "
+- " REPORT,T0001.HANDLE AS HANDLE,T0001.LOG_GROUP AS "
+- " LOG_GROUP,T0001.USERNAME AS USERNAME,T0001.VARIANT AS "
+- " VARIANT,T0001.TYPE AS TYPE,T0001.VERSION AS "
+- " VERSION,T0001.ERFDAT AS ERFDAT,T0001.ERFTIME AS "
+- " ERFTIME,T0001.ERFNAME AS ERFNAME,T0001.AEDAT AS "
+- " AEDAT,T0001.AETIME AS AETIME,T0001.AENAME AS "
+- " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS "
+- " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)");
+- check_mysql_rc(rc, mysql);
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+- for (i=0; i < 8; i++) {
+- strcpy(parms[i], "1");
+- my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+- my_bind[i].buffer = (char *)&parms[i];
+- my_bind[i].buffer_length = 100;
+- my_bind[i].is_null = 0;
+- my_bind[i].length = &length[i];
+- length[i] = 1;
+- }
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP VIEW V_LTDX");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE LTDX");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_view_star(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- MYSQL_BIND my_bind[8];
+- char parms[8][100];
+- ulong length[8];
+- const char *query= "SELECT * FROM vt1 WHERE a IN (?,?)";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, vt1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, vt1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
+- check_mysql_rc(rc, mysql);
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+- for (i= 0; i < 2; i++) {
+- sprintf((char *)&parms[i], "%d", i);
+- my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+- my_bind[i].buffer = (char *)&parms[i];
+- my_bind[i].buffer_length = 100;
+- my_bind[i].is_null = 0;
+- my_bind[i].length = &length[i];
+- length[i] = 1;
+- }
+-
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_fetch(stmt);
+- FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
+- }
+-
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW vt1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_view_insert(MYSQL *mysql)
+-{
+- MYSQL_STMT *insert_stmt, *select_stmt;
+- int rc, i;
+- MYSQL_BIND my_bind[1];
+- int my_val = 0;
+- ulong my_length = 0L;
+- long my_null = 0L;
+- const char *query=
+- "insert into v1 values (?)";
+-
+- rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
+- check_mysql_rc(rc, mysql);
+- rc = mysql_query(mysql, "DROP VIEW IF EXISTS t1,v1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql,"create table t1 (a int, primary key (a))");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create view v1 as select a from t1 where a>=1");
+- check_mysql_rc(rc, mysql);
+-
+- insert_stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(insert_stmt, query, strlen(query));
+- check_stmt_rc(rc, insert_stmt);
+- query= "select * from t1";
+- select_stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(select_stmt, query, strlen(query));
+- check_stmt_rc(rc, select_stmt);
+-
+- memset(my_bind, '\0', sizeof(MYSQL_BIND));
+- my_bind[0].buffer_type = MYSQL_TYPE_LONG;
+- my_bind[0].buffer = (char *)&my_val;
+- my_bind[0].length = &my_length;
+- my_bind[0].is_null = (char*)&my_null;
+- rc= mysql_stmt_bind_param(insert_stmt, my_bind);
+- check_stmt_rc(rc, select_stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int rowcount= 0;
+- my_val= i;
+-
+- rc= mysql_stmt_execute(insert_stmt);
+- check_stmt_rc(rc, insert_stmt);;
+-
+- rc= mysql_stmt_execute(select_stmt);
+- check_stmt_rc(rc, select_stmt);;
+- while (mysql_stmt_fetch(select_stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_UNLESS((i+1) == rowcount, "rowcount != i+1");
+- }
+- mysql_stmt_close(insert_stmt);
+- mysql_stmt_close(select_stmt);
+-
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_left_join_view(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- int rc, i;
+- const char *query=
+- "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
+-
+- rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
+- check_mysql_rc(rc, mysql);
+-
+- rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
+- check_mysql_rc(rc, mysql);
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+-
+- for (i= 0; i < 3; i++)
+- {
+- int rowcount= 0;
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_UNLESS(3 == rowcount, "Expected 3 rows");
+- }
+- mysql_stmt_close(stmt);
+-
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-static int test_view_insert_fields(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- char parm[11][1000];
+- ulong l[11];
+- int rc, i;
+- int rowcount= 0;
+- MYSQL_BIND my_bind[11];
+- const char *query= "INSERT INTO `v1` ( `K1C4` ,`K2C4` ,`K3C4` ,`K4N4` ,`F1C4` ,`F2I4` ,`F3N5` ,`F7F8` ,`F6N4` ,`F5C8` ,`F9D8` ) VALUES( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )";
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE TABLE t1 (K1C4 varchar(4) NOT NULL,"
+- "K2C4 varchar(4) NOT NULL, K3C4 varchar(4) NOT NULL,"
+- "K4N4 varchar(4) NOT NULL default '0000',"
+- "F1C4 varchar(4) NOT NULL, F2I4 int(11) NOT NULL,"
+- "F3N5 varchar(5) NOT NULL default '00000',"
+- "F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) NOT NULL,"
+- "F6N4 varchar(4) NOT NULL default '0000',"
+- "F7F8 double NOT NULL default '0',"
+- "F8F8 double NOT NULL default '0',"
+- "F9D8 decimal(8,2) NOT NULL default '0.00',"
+- "PRIMARY KEY (K1C4,K2C4,K3C4,K4N4)) "
+- "CHARSET=latin1 COLLATE latin1_bin");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql,
+- "CREATE VIEW v1 AS select sql_no_cache "
+- " K1C4 AS K1C4, K2C4 AS K2C4, K3C4 AS K3C4, K4N4 AS K4N4, "
+- " F1C4 AS F1C4, F2I4 AS F2I4, F3N5 AS F3N5,"
+- " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8"
+- " from t1 T0001");
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i= 0; i < 11; i++)
+- {
+- l[i]= 20;
+- my_bind[i].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[i].is_null= 0;
+- my_bind[i].buffer= (char *)&parm[i];
+-
+- strcpy(parm[i], "1");
+- my_bind[i].buffer_length= 2;
+- my_bind[i].length= &l[i];
+- }
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_bind_param(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- mysql_stmt_close(stmt);
+-
+- query= "select * from t1";
+- stmt= mysql_stmt_init(mysql);
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+- while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+- rowcount++;
+- FAIL_UNLESS(1 == rowcount, "Expected 1 row");
+-
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_view_sp_list_fields(MYSQL *mysql)
+-{
+- int rc;
+- MYSQL_RES *res;
+- MYSQL_ROW row;
+- int skip;
+-
+- /* skip this test if bin_log is on */
+- rc= mysql_query(mysql, "SHOW VARIABLES LIKE 'log_bin'");
+- check_mysql_rc(rc, mysql);
+- res= mysql_store_result(mysql);
+- FAIL_IF(!res, "empty/invalid resultset");
+- row = mysql_fetch_row(res);
+- skip= (strcmp((char *)row[1], "ON") == 0);
+- mysql_free_result(res);
+-
+- if (skip) {
+- diag("bin_log is ON -> skip");
+- return SKIP;
+- }
+-
+- rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create function f1 () returns int return 5");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t2 (s1 int);");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \
+-count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \
+-from t2);");
+- check_mysql_rc(rc, mysql);
+- res= mysql_list_fields(mysql, "v1", NullS);
+- FAIL_UNLESS(res != 0 && mysql_num_fields(res) != 0, "0 Fields");
+- rc= mysql_query(mysql, "DROP FUNCTION f1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP TABLE t1, t2");
+- mysql_free_result(res);
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-static int test_bug19671(MYSQL *mysql)
+-{
+- MYSQL_RES *result;
+- MYSQL_FIELD *field;
+- int rc, retcode= OK;
+-
+-
+- rc= mysql_query(mysql, "set sql_mode=''");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "drop table if exists t1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "drop view if exists v1");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create table t1(f1 int)");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "create view v1 as select va.* from t1 va");
+- check_mysql_rc(rc, mysql);
+-
+- rc= mysql_query(mysql, "SELECT * FROM v1");
+- check_mysql_rc(rc, mysql);
+-
+- result= mysql_store_result(mysql);
+- FAIL_IF(!result, "Invalid result set");
+-
+- field= mysql_fetch_field(result);
+- FAIL_IF(!field, "Can't fetch field");
+-
+- if (strcmp(field->table, "v1") != 0) {
+- diag("Wrong value '%s' for field_table. Expected 'v1'. (%s: %d)", field->table, __FILE__, __LINE__);
+- retcode= FAIL;
+- }
+-
+- mysql_free_result(result);
+-
+- rc= mysql_query(mysql, "drop view v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "drop table t1");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/*
+- Bug#11111: fetch from view returns wrong data
+-*/
+-
+-static int test_bug11111(MYSQL *mysql)
+-{
+- MYSQL_STMT *stmt;
+- MYSQL_BIND my_bind[2];
+- char buf[2][20];
+- ulong len[2];
+- int i;
+- int rc;
+- const char *query= "SELECT DISTINCT f1,ff2 FROM v1";
+-
+- rc= mysql_query(mysql, "drop table if exists t1, t2, v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "drop view if exists t1, t2, v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t1 (f1 int, f2 int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create table t2 (ff1 int, ff2 int)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "create view v1 as select * from t1, t2 where f1=ff1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t1 values (1,1), (2,2), (3,3)");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "insert into t2 values (1,1), (2,2), (3,3)");
+- check_mysql_rc(rc, mysql);
+-
+- stmt= mysql_stmt_init(mysql);
+-
+- rc= mysql_stmt_prepare(stmt, query, strlen(query));
+- check_stmt_rc(rc, stmt);
+- rc= mysql_stmt_execute(stmt);
+- check_stmt_rc(rc, stmt);
+-
+- memset(my_bind, '\0', sizeof(my_bind));
+- for (i=0; i < 2; i++)
+- {
+- my_bind[i].buffer_type= MYSQL_TYPE_STRING;
+- my_bind[i].buffer= (uchar* *)&buf[i];
+- my_bind[i].buffer_length= 20;
+- my_bind[i].length= &len[i];
+- }
+-
+- rc= mysql_stmt_bind_result(stmt, my_bind);
+- check_stmt_rc(rc, stmt);
+-
+- rc= mysql_stmt_fetch(stmt);
+- check_stmt_rc(rc, stmt);
+- FAIL_UNLESS(!strcmp(buf[1],"1"), "buf[1] != '1'");
+- mysql_stmt_close(stmt);
+- rc= mysql_query(mysql, "drop view v1");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "drop table t1, t2");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-/**
+- Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW
+-*/
+-
+-static int test_bug29306(MYSQL *mysql)
+-{
+- MYSQL_FIELD *field;
+- int rc;
+- MYSQL_RES *res;
+-
+- DBUG_ENTER("test_bug29306");
+-
+- rc= mysql_query(mysql, "DROP TABLE IF EXISTS tab17557");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW IF EXISTS view17557");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE TABLE tab17557 (dd decimal (3,1))");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "CREATE VIEW view17557 as SELECT dd FROM tab17557");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "INSERT INTO tab17557 VALUES (7.6)");
+- check_mysql_rc(rc, mysql);
+-
+- /* Checking the view */
+- res= mysql_list_fields(mysql, "view17557", NULL);
+- while ((field= mysql_fetch_field(res)))
+- {
+- FAIL_UNLESS(field->decimals == 1, "field->decimals != 1");
+- }
+- mysql_free_result(res);
+-
+- rc= mysql_query(mysql, "DROP TABLE tab17557");
+- check_mysql_rc(rc, mysql);
+- rc= mysql_query(mysql, "DROP VIEW view17557");
+- check_mysql_rc(rc, mysql);
+-
+- return OK;
+-}
+-
+-
+-struct my_tests_st my_tests[] = {
+- {"test_view", test_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_where", test_view_where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_2where", test_view_2where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_star", test_view_star, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_insert", test_view_insert, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_left_join_view", test_left_join_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_insert_fields", test_view_insert_fields, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_view_sp_list_fields", test_view_sp_list_fields,TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug19671", test_bug19671, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug29306", test_bug29306, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {"test_bug11111", test_bug11111, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
+- {NULL, NULL, 0, 0, NULL, NULL}
+-};
+-
+-int main(int argc, char **argv)
+-{
+-// if (argc > 1)
+-// get_options(&argc, &argv);
+-
+- get_envvars();
+-
+- run_tests(my_tests);
+-
+- return(exit_status());
+-}
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win/packaging/CMakeLists.txt mariadb-native-client.trunk/win/packaging/CMakeLists.txt
+--- mariadb/win/packaging/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win/packaging/CMakeLists.txt 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,46 @@
++SET(CLIENT_LIB_DIR ${CMAKE_BINARY_DIR}/libmariadb/${CMAKE_BUILD_TYPE})
++SET(CLIENT_DBG_DIR ${CMAKE_BINARY_DIR}/libmariadb/Debug)
++SET(CLIENT_INC_DIR ${CMAKE_SOURCE_DIR}/include)
++
++SET(PRODUCT_NAME "MariaDB C Client Library")
++SET(PRODUCT_MANUFACTURER "MariaDB")
++SET(PRODUCT_VERSION "${MYSQL_CLIENT_VERSION_MAJOR}.${MYSQL_CLIENT_VERSION_MINOR}.${MYSQL_CLIENT_VERSION_PATCH}")
++
++MESSAGE(STATUS "sizeof ${CMAKE_SIZEOF_VOID_P}")
++
++IF(${MSI_64})
++ SET(PRODUCT_NAME "${PRODUCT_NAME} 64-bit")
++ SET(PLATFORM "win64")
++ SET(IS_WIN64 "yes")
++ SET(WIXPLATFORM "x64")
++ SET(FOLDER "ProgramFiles64Folder")
++ELSE()
++ SET(PLATFORM "win32")
++ SET(IS_WIN64 "no")
++ SET(WIXPLATFORM "x86")
++ SET(FOLDER "ProgramFilesFolder")
++ENDIF()
++
++FOREACH(src ${MARIADB_CLIENT_INCLUDES})
++ STRING(REPLACE "-" "_" src_id ${src})
++ SET(MARIADB_INCLUDE_FILES "${MARIADB_INCLUDE_FILES} <File Id=\"${src_id}\" Name=\"${src}\" DiskId=\"1\" Source=\"${CMAKE_SOURCE_DIR}/include/${src}\"/>\n")
++ENDFOREACH()
++
++CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/win/packaging/mariadb-native-client.xml.in
++ ${CMAKE_BINARY_DIR}/win/packaging/mariadb-native-client.xml)
++SET(MSI_PACKAGE "mariadb-native-client-${PRODUCT_VERSION}-${PLATFORM}.msi")
++
++ADD_CUSTOM_TARGET(
++ MSI_PACKAGE_ALL
++ DEPENDS ${MSI_PACKAGE})
++
++ADD_CUSTOM_COMMAND(
++ OUTPUT ${MSI_PACKAGE}
++ DEPENDS mariadb-native-client.wixobj
++ COMMAND light.exe -ext WixUIExtension mariadb-native-client.wixobj -o ${MSI_PACKAGE})
++
++ADD_CUSTOM_COMMAND(
++ OUTPUT mariadb-native-client.wixobj
++ DEPENDS mariadb-native-client.xml
++ COMMAND candle.exe mariadb-native-client.xml -o mariadb-native-client.wixobj)
++
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win/packaging/license.rtf mariadb-native-client.trunk/win/packaging/license.rtf
+--- mariadb/win/packaging/license.rtf 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win/packaging/license.rtf 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,181 @@
++{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
++{\*\generator Msftedit 5.41.21.2509;}\viewkind4\uc1\pard\lang1031\f0\fs22 GNU LESSER GENERAL PUBLIC LICENSE\par
++ Version 2.1, February 1999\par
++\par
++ Copyright (C) 1991, 1999 Free Software Foundation, Inc.\par
++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\par
++ Everyone is permitted to copy and distribute verbatim copies\par
++ of this license document, but changing it is not allowed.\par
++\par
++[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.]\par
++\par
++ Preamble\par
++\par
++ The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.\par
++\par
++ This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.\par
++\par
++ When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.\par
++\par
++ To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. \par
++ For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.\par
++\par
++ We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.\par
++\par
++ Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.\par
++\par
++ Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.\par
++\par
++ When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.\par
++\par
++ We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.\par
++\par
++ For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.\par
++\par
++ In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.\par
++\par
++ Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.\par
++\par
++ The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.\par
++\page\par
++ GNU LESSER GENERAL PUBLIC LICENSE\par
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\par
++\par
++ 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".\par
++\par
++ A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.\par
++\par
++ The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)\par
++\par
++ "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.\par
++\par
++ Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.\par
++\par
++ 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.\par
++\par
++ You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\par
++\page\par
++ 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\par
++\par
++ a) The modified work must itself be a software library.\par
++\par
++ b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.\par
++\par
++ c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.\par
++\par
++ d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.\par
++\par
++ (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)\par
++\par
++These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\par
++\par
++Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.\par
++\par
++In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\par
++\par
++ 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in\par
++these notices.\par
++\par
++ Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.\par
++\par
++ This option is useful when you wish to copy part of the code of the Library into a program that is not a library.\par
++\par
++ 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.\par
++\par
++ If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.\par
++\par
++ 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.\par
++\par
++ However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.\par
++\par
++ When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.\par
++\par
++ If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)\par
++\par
++ Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.\par
++\par
++ 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.\par
++\par
++ You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:\par
++\par
++ a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)\par
++\par
++ b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.\par
++\par
++ c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.\par
++\par
++ d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.\par
++\par
++ e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.\par
++\par
++ For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\par
++\par
++ It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.\par
++\par
++ 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:\par
++\par
++ a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.\par
++\par
++ b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\par
++\par
++ 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\par
++\par
++ 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.\par
++\par
++ 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.\par
++\par
++ 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.\par
++\par
++If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.\par
++\par
++It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\par
++\par
++This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\par
++\par
++ 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\par
++\par
++ 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\par
++\par
++Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.\par
++\par
++ 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\par
++\par
++ NO WARRANTY\par
++\par
++ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\par
++\par
++ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\par
++DAMAGES.\par
++\par
++ END OF TERMS AND CONDITIONS\par
++\par
++ How to Apply These Terms to Your New Libraries\par
++\par
++ If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).\par
++\par
++ To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.\par
++\par
++ <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author>\par
++\par
++ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.\par
++\par
++ This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.\par
++\par
++ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software\par
++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\par
++\par
++Also add information on how to contact you by electronic and paper mail.\par
++\par
++You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if\par
++necessary. Here is a sample; alter the names:\par
++\par
++ Yoyodyne, Inc., hereby disclaims all copyright interest in the\par
++ library `Frob' (a library for tweaking knobs) written by James Random Hacker.\par
++\par
++ <signature of Ty Coon>, 1 April 1990\par
++ Ty Coon, President of Vice\par
++\par
++That's all there is to it!\par
++\par
++}
++
+\ No newline at end of file
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win/packaging/mariadb-native-client.xml.in mariadb-native-client.trunk/win/packaging/mariadb-native-client.xml.in
+--- mariadb/win/packaging/mariadb-native-client.xml.in 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win/packaging/mariadb-native-client.xml.in 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,70 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
++ <Product Id="*" Name="@PRODUCT_NAME@" Language="1033"
++ Version="@PRODUCT_VERSION@"
++ Manufacturer="@PRODUCT_MANUFACTURER@" UpgradeCode="E4CC4F1C-3991-49D9-85A7-7AA76C5DC67A">
++ <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Platform="@WIXPLATFORM@"/>
++
++ <MajorUpgrade DowngradeErrorMessage="A newer version of @PRODUCT_NAME@ is already installed." />
++ <MediaTemplate EmbedCab="yes" />
++
++ <UIRef Id="WixUI_Mondo" />
++ <WixVariable Id="WixUILicenseRtf" Value="@CMAKE_SOURCE_DIR@/win/packaging/license.rtf" />
++ <WixVariable Id="WixUIBannerBmp" Value="@CMAKE_SOURCE_DIR@/win/packaging/WixUIBannerBmp.jpg" />
++ <WixVariable Id="WixUIDialogBmp" Value="@CMAKE_SOURCE_DIR@/win/packaging/WixUIDialogBmp.jpg" />
++
++ <Feature Id="ProductFeature" Title="@PRODUCT_NAME@ @PRODUCT_VERSION@" Level="1">
++ <ComponentRef Id="RegistryKeys" />
++ <ComponentRef Id="Library"/>
++ <ComponentRef Id="DebugLibrary" />
++ <Feature Id="DebugFeature" Title="Debug Information" Level="2">
++ <ComponentRef Id="Debug" />
++ </Feature>
++ </Feature>
++ <Feature Id="IncludeFeature" Title="Include Files" Level="1">
++ <ComponentRef Id="Includes"/>
++ </Feature>
++ </Product>
++
++ <Fragment>
++ <Directory Id="TARGETDIR" Name="SourceDir">
++ <Directory Id="@FOLDER@">
++ <Directory Id="Mariadb" Name="@PRODUCT_MANUFACTURER@">
++ <Directory Id="INSTALLFOLDER" Name="@PRODUCT_NAME@" >
++ <Directory Id="instlib" Name="lib">
++ <Directory Id="instlib_debug" Name="debug"/>
++ </Directory>
++ <Directory Id="instinclude" Name="include" />
++ </Directory>
++ </Directory>
++ </Directory>
++ </Directory>
++ </Fragment>
++
++ <Fragment>
++ <!--<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">-->
++ <Component Id="RegistryKeys" Guid="755726EA-9706-413D-86B3-E70582FF2819" DiskId="1" Directory="INSTALLFOLDER" Win64="@IS_WIN64@">
++ <RegistryKey Id="Version" Root="HKLM" Key="SOFTWARE\@PRODUCT_MANUFACTURER@\@PRODUCT_NAME@" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
++ <RegistryValue Name="Version" Type="string" Value="@PRODUCT_VERSION@"/>
++ </RegistryKey>
++ </Component>
++ <Component Id="Library" Guid="89E28283-23AE-4F10-B743-B5FA485E9F9A" KeyPath="yes" DiskId="1" Directory="instlib" Win64="@IS_WIN64@">
++ <File Id="libdll" Name="libmariadb.dll" DiskId="1" Source="@CLIENT_LIB_DIR@/libmariadb.dll" />
++ <File Id="libdllimp" Name="libmariadb.lib" DiskId="1" Source="@CLIENT_LIB_DIR@/libmariadb.lib" />
++ <File Id="libstatic" Name="mariadbclient.lib" DiskId="1" Source="@CLIENT_LIB_DIR@/mariadbclient.lib" />
++ </Component>
++ <Component Id="DebugLibrary" Guid="1b8f741d-e7d9-48f1-9e11-9270216d1dc7" KeyPath="yes" DiskId="1" Directory="instlib_debug" Win64="@IS_WIN64@">
++ <File Id="dlibdll" Name="libmariadb.dll" DiskId="1" Source="@CLIENT_DBG_DIR@/libmariadb.dll" />
++ <File Id="dlibdllimp" Name="libmariadb.lib" DiskId="1" Source="@CLIENT_DBG_DIR@/libmariadb.lib" />
++ <File Id="dlibstatic" Name="mariadbclient.lib" DiskId="1" Source="@CLIENT_DBG_DIR@/mariadbclient.lib" />
++ </Component>
++ <Component Id="Debug" Guid="FFAFCCCC-4E0C-4A87-840C-53B63C8A427A" KeyPath="yes" Directory="instlib" DiskId="1" Win64="@IS_WIN64@">
++ <File Id="libdllpdb" Name="libmariadb.pdb" DiskId="1" Source="@CLIENT_LIB_DIR@/libmariadb.pdb" />
++ <File Id="libstaticpdb" Name="mariadbclient.pdb" DiskId="1" Source="@CLIENT_LIB_DIR@/mariadbclient.pdb" />
++ </Component>
++ <Component Id="Includes" Guid="5CFB93CC-FC30-4E13-B665-E52690AB56E3" KeyPath="yes" Directory="instinclude" DiskId="1" Win64="@IS_WIN64@">
++@MARIADB_INCLUDE_FILES@
++ </Component>
++ <!-- </ComponentGroup> -->
++ </Fragment>
++</Wix>
+Binary files mariadb-native-client.release/win/packaging/WixUIBannerBmp.jpg and mariadb-native-client.trunk/win/packaging/WixUIBannerBmp.jpg differ
+Binary files mariadb-native-client.release/win/packaging/WixUIDialogBmp.jpg and mariadb-native-client.trunk/win/packaging/WixUIDialogBmp.jpg differ
+diff -x .bzr -u --recursive -N mariadb-native-client.release/WindowsCache.cmake mariadb-native-client.trunk/WindowsCache.cmake
+--- mariadb/WindowsCache.cmake 2013-10-19 08:00:51.000000000 +0200
++++ mariadb/WindowsCache.cmake 1970-01-01 01:00:00.000000000 +0100
+@@ -1,392 +0,0 @@
+-IF(MSVC)
+-SET(BFD_H_EXISTS 0 CACHE INTERNAL "")
+-SET(HAVE_ACCESS 1 CACHE INTERNAL "")
+-SET(HAVE_AIO_H CACHE INTERNAL "")
+-SET(HAVE_AIO_READ CACHE INTERNAL "")
+-SET(HAVE_ALARM CACHE INTERNAL "")
+-SET(HAVE_ALLOCA_H CACHE INTERNAL "")
+-SET(HAVE_ARPA_INET_H CACHE INTERNAL "")
+-SET(HAVE_ASM_MSR_H CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE_SYMBOLS CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE INTERNAL "")
+-SET(HAVE_BFILL CACHE INTERNAL "")
+-SET(HAVE_BMOVE CACHE INTERNAL "")
+-SET(HAVE_BSD_SIGNALS CACHE INTERNAL "")
+-SET(HAVE_BSEARCH 1 CACHE INTERNAL "")
+-SET(HAVE_BSS_START CACHE INTERNAL "")
+-SET(HAVE_BZERO CACHE INTERNAL "")
+-SET(HAVE_CHOWN CACHE INTERNAL "")
+-SET(HAVE_CLOCK_GETTIME CACHE INTERNAL "")
+-SET(HAVE_COMPRESS CACHE INTERNAL "")
+-SET(HAVE_CRYPT CACHE INTERNAL "")
+-SET(HAVE_CRYPT_H CACHE INTERNAL "")
+-SET(HAVE_CUSERID CACHE INTERNAL "")
+-SET(HAVE_CXX_NEW 1 CACHE INTERNAL "")
+-SET(HAVE_DECL_MADVISE CACHE INTERNAL "")
+-SET(HAVE_DIRECTIO CACHE INTERNAL "")
+-SET(HAVE_DIRENT_H CACHE INTERNAL "")
+-SET(HAVE_DLERROR CACHE INTERNAL "")
+-SET(HAVE_DLFCN_H CACHE INTERNAL "")
+-SET(HAVE_DLOPEN CACHE INTERNAL "")
+-SET(HAVE_DOPRNT CACHE INTERNAL "")
+-SET(HAVE_EXECINFO_H CACHE INTERNAL "")
+-SET(HAVE_FCHMOD CACHE INTERNAL "")
+-SET(HAVE_FCNTL CACHE INTERNAL "")
+-SET(HAVE_FCNTL_H 1 CACHE INTERNAL "")
+-SET(HAVE_FCNTL_NONBLOCK CACHE INTERNAL "")
+-SET(HAVE_FCONVERT CACHE INTERNAL "")
+-SET(HAVE_FDATASYNC CACHE INTERNAL "")
+-SET(HAVE_DECL_FDATASYNC CACHE INTERNAL "")
+-SET(HAVE_FEDISABLEEXCEPT CACHE INTERNAL "")
+-SET(HAVE_FENV_H CACHE INTERNAL "")
+-SET(HAVE_FESETROUND CACHE INTERNAL "")
+-SET(HAVE_FGETLN CACHE INTERNAL "")
+-SET(HAVE_FINITE CACHE INTERNAL "")
+-SET(HAVE_FINITE_IN_MATH_H CACHE INTERNAL "")
+-SET(HAVE_FLOATINGPOINT_H CACHE INTERNAL "")
+-SET(HAVE_FLOAT_H 1 CACHE INTERNAL "")
+-SET(HAVE_FLOCKFILE CACHE INTERNAL "")
+-SET(HAVE_FNMATCH_H CACHE INTERNAL "")
+-SET(HAVE_FPSETMASK CACHE INTERNAL "")
+-SET(HAVE_FPU_CONTROL_H CACHE INTERNAL "")
+-SET(HAVE_FSEEKO CACHE INTERNAL "")
+-SET(HAVE_FSYNC CACHE INTERNAL "")
+-SET(HAVE_FTIME 1 CACHE INTERNAL "")
+-SET(HAVE_FTRUNCATE CACHE INTERNAL "")
+-SET(HAVE_GETADDRINFO 1 CACHE INTERNAL "")
+-SET(HAVE_GETCWD 1 CACHE INTERNAL "")
+-SET(HAVE_GETHOSTBYADDR_R CACHE INTERNAL "")
+-SET(HAVE_GETHRTIME CACHE INTERNAL "")
+-SET(HAVE_GETLINE CACHE INTERNAL "")
+-SET(HAVE_GETNAMEINFO CACHE INTERNAL "")
+-SET(HAVE_GETPAGESIZE CACHE INTERNAL "")
+-SET(HAVE_GETPASS CACHE INTERNAL "")
+-SET(HAVE_GETPASSPHRASE CACHE INTERNAL "")
+-SET(HAVE_GETPWNAM CACHE INTERNAL "")
+-SET(HAVE_GETPWUID CACHE INTERNAL "")
+-SET(HAVE_GETRLIMIT CACHE INTERNAL "")
+-SET(HAVE_GETRUSAGE CACHE INTERNAL "")
+-SET(HAVE_GETTIMEOFDAY CACHE INTERNAL "")
+-SET(HAVE_GETWD CACHE INTERNAL "")
+-SET(HAVE_GMTIME_R CACHE INTERNAL "")
+-SET(HAVE_GRP_H CACHE INTERNAL "")
+-SET(HAVE_IA64INTRIN_H CACHE INTERNAL "")
+-SET(HAVE_IEEEFP_H CACHE INTERNAL "")
+-SET(HAVE_INDEX CACHE INTERNAL "")
+-SET(HAVE_INITGROUPS CACHE INTERNAL "")
+-SET(HAVE_INTTYPES_H CACHE INTERNAL "")
+-SET(HAVE_IPPROTO_IPV6 CACHE INTERNAL "")
+-SET(HAVE_IPV6 TRUE CACHE INTERNAL "")
+-SET(HAVE_IPV6_V6ONLY 1 CACHE INTERNAL "")
+-SET(HAVE_ISINF CACHE INTERNAL "")
+-SET(HAVE_ISNAN CACHE INTERNAL "")
+-SET(HAVE_ISSETUGID CACHE INTERNAL "")
+-SET(HAVE_GETUID CACHE INTERNAL "")
+-SET(HAVE_GETEUID CACHE INTERNAL "")
+-SET(HAVE_GETGID CACHE INTERNAL "")
+-SET(HAVE_GETEGID CACHE INTERNAL "")
+-SET(HAVE_LANGINFO_H CACHE INTERNAL "")
+-SET(HAVE_LDIV 1 CACHE INTERNAL "")
+-SET(HAVE_LIMITS_H 1 CACHE INTERNAL "")
+-SET(HAVE_LOCALE_H 1 CACHE INTERNAL "")
+-SET(HAVE_LOCALTIME_R CACHE INTERNAL "")
+-SET(HAVE_LOG2 CACHE INTERNAL "")
+-SET(HAVE_LONGJMP 1 CACHE INTERNAL "")
+-SET(HAVE_LRAND48 CACHE INTERNAL "")
+-SET(HAVE_LSTAT CACHE INTERNAL "")
+-SET(HAVE_MADVISE CACHE INTERNAL "")
+-SET(HAVE_MALLINFO CACHE INTERNAL "")
+-SET(HAVE_MALLOC_H 1 CACHE INTERNAL "")
+-SET(HAVE_MEMALIGN CACHE INTERNAL "")
+-SET(HAVE_MEMCPY 1 CACHE INTERNAL "")
+-SET(HAVE_MEMMOVE 1 CACHE INTERNAL "")
+-SET(HAVE_MEMORY_H 1 CACHE INTERNAL "")
+-SET(HAVE_MKSTEMP CACHE INTERNAL "")
+-SET(HAVE_MLOCK CACHE INTERNAL "")
+-SET(HAVE_MLOCKALL CACHE INTERNAL "")
+-SET(HAVE_MMAP CACHE INTERNAL "")
+-SET(HAVE_MMAP64 CACHE INTERNAL "")
+-SET(HAVE_NETDB_H CACHE INTERNAL "")
+-SET(HAVE_NETINET_IN6_H CACHE INTERNAL "")
+-SET(HAVE_NETINET_IN_H CACHE INTERNAL "")
+-SET(HAVE_NL_LANGINFO CACHE INTERNAL "")
+-SET(HAVE_PASE_ENVIRONMENT CACHE INTERNAL "")
+-SET(HAVE_PATHS_H CACHE INTERNAL "")
+-SET(HAVE_PCLOSE CACHE INTERNAL "")
+-SET(HAVE_PERROR 1 CACHE INTERNAL "")
+-SET(HAVE_PEERCRED CACHE INTERNAL "")
+-SET(HAVE_PAM_APPL_H CACHE INTERNAL "")
+-SET(HAVE_POLL_H CACHE INTERNAL "")
+-SET(HAVE_POPEN CACHE INTERNAL "")
+-SET(HAVE_POLL CACHE INTERNAL "")
+-SET(HAVE_PORT_CREATE CACHE INTERNAL "")
+-SET(HAVE_PORT_H CACHE INTERNAL "")
+-SET(HAVE_POSIX_FALLOCATE CACHE INTERNAL "")
+-SET(HAVE_POSIX_SIGNALS CACHE INTERNAL "")
+-SET(HAVE_PREAD CACHE INTERNAL "")
+-SET(HAVE_PRINTSTACK CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_CREATE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_GETSTACKSIZE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_SETSCOPE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_SETSTACKSIZE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_CONDATTR_CREATE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_CONDATTR_SETCLOCK CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_INIT CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_KEY_DELETE CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_RWLOCK_RDLOCK CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_SIGMASK CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_THREADMASK CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_YIELD_NP CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_YIELD_ZERO_ARG CACHE INTERNAL "")
+-SET(HAVE_PUTENV 1 CACHE INTERNAL "")
+-SET(HAVE_PWD_H CACHE INTERNAL "")
+-SET(HAVE_RDTSCLL CACHE INTERNAL "")
+-SET(HAVE_READDIR_R CACHE INTERNAL "")
+-SET(HAVE_READLINK CACHE INTERNAL "")
+-SET(HAVE_READ_REAL_TIME CACHE INTERNAL "")
+-SET(HAVE_REALPATH CACHE INTERNAL "")
+-SET(HAVE_REGCOMP CACHE INTERNAL "")
+-SET(HAVE_RENAME 1 CACHE INTERNAL "")
+-SET(HAVE_RE_COMP CACHE INTERNAL "")
+-SET(HAVE_RINT CACHE INTERNAL "")
+-SET(HAVE_RWLOCK_INIT CACHE INTERNAL "")
+-SET(HAVE_SCHED_H CACHE INTERNAL "")
+-SET(HAVE_SCHED_YIELD CACHE INTERNAL "")
+-SET(HAVE_SELECT 1 CACHE INTERNAL "")
+-SET(HAVE_SELECT_H CACHE INTERNAL "")
+-SET(HAVE_SEMAPHORE_H CACHE INTERNAL "")
+-SET(HAVE_SETENV CACHE INTERNAL "")
+-SET(HAVE_SETFD CACHE INTERNAL "")
+-SET(HAVE_SETLOCALE 1 CACHE INTERNAL "")
+-SET(HAVE_SHMAT CACHE INTERNAL "")
+-SET(HAVE_SHMCTL CACHE INTERNAL "")
+-SET(HAVE_SHMDT CACHE INTERNAL "")
+-SET(HAVE_SHMGET CACHE INTERNAL "")
+-SET(HAVE_SIGACTION CACHE INTERNAL "")
+-SET(HAVE_SIGADDSET CACHE INTERNAL "")
+-SET(HAVE_SIGEMPTYSET CACHE INTERNAL "")
+-SET(HAVE_SIGHOLD CACHE INTERNAL "")
+-SET(HAVE_SIGINT 1 CACHE INTERNAL "")
+-SET(HAVE_SIGPIPE CACHE INTERNAL "")
+-SET(HAVE_SIGQUIT CACHE INTERNAL "")
+-SET(HAVE_SIGSET CACHE INTERNAL "")
+-SET(HAVE_SIGTERM 1 CACHE INTERNAL "")
+-SET(HAVE_SIGTHREADMASK CACHE INTERNAL "")
+-SET(HAVE_SIGWAIT CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_BOOL FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_CHAR TRUE CACHE INTERNAL "")
+-SET(SIZEOF_CHAR 1 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_CHARP TRUE CACHE INTERNAL "")
+-SET(SIZEOF_CHARP ${CMAKE_SIZEOF_VOID_P} CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_IN6_ADDR TRUE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_INT TRUE CACHE INTERNAL "")
+-SET(SIZEOF_INT 4 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_INT16 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_INT32 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_INT64 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_INT8 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_LONG TRUE CACHE INTERNAL "")
+-SET(SIZEOF_LONG 4 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_LONG_LONG TRUE CACHE INTERNAL "")
+-SET(SIZEOF_LONG_LONG 8 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_MODE_T FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_OFF_T TRUE CACHE INTERNAL "")
+-SET(SIZEOF_OFF_T 4 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_SHORT TRUE CACHE INTERNAL "")
+-SET(SIZEOF_SHORT 2 CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_SIGSET_T FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_SIZE_T TRUE CACHE INTERNAL "")
+-SET(SIZEOF_SIZE_T ${CMAKE_SIZEOF_VOID_P} CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_SOCKADDR_IN6 TRUE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_SOCKLEN_T FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UCHAR FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UINT FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UINT16 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UINT32 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UINT64 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_UINT8 FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_ULONG FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZEOF_U_INT32_T FALSE CACHE INTERNAL "")
+-SET(HAVE_SIZE_OF_SSIZE_T FALSE CACHE INTERNAL "")
+-SET(HAVE_SLEEP CACHE INTERNAL "")
+-SET(HAVE_SNPRINTF CACHE INTERNAL "")
+-SET(HAVE_SOCKADDR_STORAGE_SS_FAMILY 1 CACHE INTERNAL "")
+-SET(HAVE_SOLARIS_STYLE_GETHOST CACHE INTERNAL "")
+-SET(STACK_DIRECTION -1 CACHE INTERNAL "")
+-SET(HAVE_STDARG_H 1 CACHE INTERNAL "")
+-SET(HAVE_STDDEF_H 1 CACHE INTERNAL "")
+-SET(HAVE_STDINT_H CACHE INTERNAL "")
+-SET(HAVE_STDLIB_H 1 CACHE INTERNAL "")
+-SET(HAVE_STPCPY CACHE INTERNAL "")
+-SET(HAVE_STRCASECMP CACHE INTERNAL "")
+-SET(HAVE_STRCOLL 1 CACHE INTERNAL "")
+-SET(HAVE_STRDUP 1 CACHE INTERNAL "")
+-SET(HAVE_STRERROR 1 CACHE INTERNAL "")
+-SET(HAVE_STRINGS_H CACHE INTERNAL "")
+-SET(HAVE_STRING_H 1 CACHE INTERNAL "")
+-SET(HAVE_STRLCAT CACHE INTERNAL "")
+-SET(HAVE_STRLCPY CACHE INTERNAL "")
+-SET(HAVE_STRNCASECMP CACHE INTERNAL "")
+-SET(HAVE_STRNDUP CACHE INTERNAL "")
+-IF(MSVC_VERSION GREATER 1310)
+-SET(HAVE_STRNLEN 1 CACHE INTERNAL "")
+-ENDIF()
+-SET(HAVE_STRPBRK 1 CACHE INTERNAL "")
+-SET(HAVE_STRSEP CACHE INTERNAL "")
+-SET(HAVE_STRSIGNAL CACHE INTERNAL "")
+-SET(HAVE_STRSTR 1 CACHE INTERNAL "")
+-SET(HAVE_STRTOK_R CACHE INTERNAL "")
+-SET(HAVE_STRTOL 1 CACHE INTERNAL "")
+-SET(HAVE_STRTOLL CACHE INTERNAL "")
+-SET(HAVE_STRTOUL 1 CACHE INTERNAL "")
+-SET(HAVE_STRTOULL CACHE INTERNAL "")
+-SET(HAVE_SVR3_SIGNALS CACHE INTERNAL "")
+-SET(HAVE_SYNCH_H CACHE INTERNAL "")
+-SET(HAVE_SYSENT_H CACHE INTERNAL "")
+-SET(HAVE_SYS_CDEFS_H CACHE INTERNAL "")
+-SET(HAVE_SYS_DIR_H CACHE INTERNAL "")
+-SET(HAVE_SYS_ERRLIST CACHE INTERNAL "")
+-SET(HAVE_SYS_FILE_H CACHE INTERNAL "")
+-SET(HAVE_SYS_FPU_H CACHE INTERNAL "")
+-SET(HAVE_SYS_IOCTL_H CACHE INTERNAL "")
+-SET(HAVE_SYS_IPC_H CACHE INTERNAL "")
+-SET(HAVE_SYS_MALLOC_H CACHE INTERNAL "")
+-SET(HAVE_SYS_MMAN_H CACHE INTERNAL "")
+-SET(HAVE_SYS_PARAM_H CACHE INTERNAL "")
+-SET(HAVE_SYS_PRCTL_H CACHE INTERNAL "")
+-SET(HAVE_SYS_PTEM_H CACHE INTERNAL "")
+-SET(HAVE_SYS_PTE_H CACHE INTERNAL "")
+-SET(HAVE_SYS_RESOURCE_H CACHE INTERNAL "")
+-SET(HAVE_SYS_SELECT_H CACHE INTERNAL "")
+-SET(HAVE_SYS_SHM_H CACHE INTERNAL "")
+-SET(HAVE_SYS_SOCKIO_H CACHE INTERNAL "")
+-SET(HAVE_SYS_SOCKET_H CACHE INTERNAL "")
+-SET(HAVE_SYS_STAT_H 1 CACHE INTERNAL "")
+-SET(HAVE_SYS_STREAM_H CACHE INTERNAL "")
+-SET(HAVE_SYS_TERMCAP_H CACHE INTERNAL "")
+-SET(HAVE_SYS_TIMEB_H 1 CACHE INTERNAL "")
+-SET(HAVE_SYS_TIMES_H CACHE INTERNAL "")
+-SET(HAVE_SYS_TIME_H CACHE INTERNAL "")
+-SET(HAVE_SYS_TYPES_H 1 CACHE INTERNAL "")
+-SET(HAVE_SYS_UN_H CACHE INTERNAL "")
+-SET(HAVE_SYS_UTIME_H 1 CACHE INTERNAL "")
+-SET(HAVE_SYS_VADVISE_H CACHE INTERNAL "")
+-SET(HAVE_SYS_WAIT_H CACHE INTERNAL "")
+-SET(HAVE_TCGETATTR CACHE INTERNAL "")
+-SET(HAVE_TELL 1 CACHE INTERNAL "")
+-SET(HAVE_TEMPNAM 1 CACHE INTERNAL "")
+-SET(HAVE_TERMCAP_H CACHE INTERNAL "")
+-SET(HAVE_TERMIOS_H CACHE INTERNAL "")
+-SET(HAVE_TERMIO_H CACHE INTERNAL "")
+-SET(HAVE_TERM_H CACHE INTERNAL "")
+-SET(HAVE_THR_SETCONCURRENCY CACHE INTERNAL "")
+-SET(HAVE_THR_YIELD CACHE INTERNAL "")
+-SET(HAVE_TIME 1 CACHE INTERNAL "")
+-SET(HAVE_TIMES CACHE INTERNAL "")
+-SET(HAVE_TIMESPEC_TS_SEC CACHE INTERNAL "")
+-SET(HAVE_TIME_H 1 CACHE INTERNAL "")
+-SET(HAVE_TZNAME 1 CACHE INTERNAL "")
+-SET(HAVE_UNISTD_H CACHE INTERNAL "")
+-SET(HAVE_UTIME_H CACHE INTERNAL "")
+-SET(HAVE_VALLOC CACHE INTERNAL "")
+-SET(HAVE_VARARGS_H 1 CACHE INTERNAL "")
+-SET(HAVE_VASPRINTF CACHE INTERNAL "")
+-SET(HAVE_VPRINTF 1 CACHE INTERNAL "")
+-IF(MSVC_VERSION GREATER 1310)
+-SET(HAVE_VSNPRINTF 1 CACHE INTERNAL "")
+-ENDIF()
+-SET(HAVE_WEAK_SYMBOL CACHE INTERNAL "")
+-SET(HAVE_WORDS_BIGENDIAN TRUE CACHE INTERNAL "")
+-SET(WORDS_BIGENDIAN CACHE INTERNAL "")
+-SET(HAVE__S_IFIFO 1 CACHE INTERNAL "")
+-SET(HAVE__S_IREAD 1 CACHE INTERNAL "")
+-SET(HAVE__finite 1 CACHE INTERNAL "")
+-SET(HAVE__isnan 1 CACHE INTERNAL "")
+-SET(HAVE__pclose 1 CACHE INTERNAL "")
+-SET(HAVE__popen 1 CACHE INTERNAL "")
+-SET(HAVE__snprintf 1 CACHE INTERNAL "")
+-SET(HAVE__stricmp 1 CACHE INTERNAL "")
+-SET(HAVE__strnicmp 1 CACHE INTERNAL "")
+-SET(HAVE__strtoi64 1 CACHE INTERNAL "")
+-SET(HAVE__strtoui64 1 CACHE INTERNAL "")
+-IF(MSVC_VERSION GREATER 1310)
+- SET(HAVE_strtok_s 1 CACHE INTERNAL "")
+-ENDIF()
+-SET(STDC_HEADERS CACHE 1 INTERNAL "")
+-SET(STRUCT_DIRENT_HAS_D_INO CACHE INTERNAL "")
+-SET(STRUCT_DIRENT_HAS_D_INO CACHE INTERNAL "")
+-SET(STRUCT_DIRENT_HAS_D_NAMLEN CACHE INTERNAL "")
+-SET(TIME_WITH_SYS_TIME CACHE INTERNAL "")
+-SET(TIME_T_UNSIGNED 1 CACHE INTERNAL "")
+-SET(TIOCSTAT_IN_SYS_IOCTL CACHE INTERNAL "")
+-SET(HAVE_S_IROTH CACHE INTERNAL "")
+-SET(HAVE_S_IFIFO CACHE INTERNAL "")
+-SET(QSORT_TYPE_IS_VOID 1 CACHE INTERNAL "")
+-SET(SIGNAL_RETURN_TYPE_IS_VOID 1 CACHE INTERNAL "")
+-SET(C_HAS_inline CACHE INTERNAL "")
+-SET(C_HAS___inline 1 CACHE INTERNAL "")
+-SET(FIONREAD_IN_SYS_IOCTL CACHE INTERNAL "")
+-SET(FIONREAD_IN_SYS_FILIO CACHE INTERNAL "")
+-SET(GWINSZ_IN_SYS_IOCTL CACHE INTERNAL "")
+-SET(HAVE_CXXABI_H CACHE INTERNAL "")
+-SET(HAVE_NDIR_H CACHE INTERNAL "")
+-SET(HAVE_SYS_NDIR_H CACHE INTERNAL "")
+-SET(HAVE_SYS_NDIR_H CACHE INTERNAL "")
+-SET(HAVE_ASM_TERMBITS_H CACHE INTERNAL "")
+-SET(HAVE_TERMBITS_H CACHE INTERNAL "")
+-SET(HAVE_VIS_H CACHE INTERNAL "")
+-SET(HAVE_WCHAR_H 1 CACHE INTERNAL "")
+-SET(HAVE_WCTYPE_H 1 CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP CACHE INTERNAL "")
+-SET(HAVE_SOCKADDR_IN_SIN_LEN CACHE INTERNAL "")
+-SET(HAVE_SOCKADDR_IN6_SIN6_LEN CACHE INTERNAL "")
+-SET(HAVE_VALGRIND CACHE INTERNAL "")
+-SET(HAVE_EVENT_H CACHE INTERNAL "")
+-SET(HAVE_LINUX_UNISTD_H CACHE INTERNAL "")
+-SET(HAVE_SYS_UTSNAME_H CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_GETGUARDSIZE CACHE INTERNAL "")
+-SET(FIONREAD_IN_SYS_FILIO CACHE INTERNAL "")
+-SET(FIONREAD_IN_SYS_IOCTL CACHE INTERNAL "")
+-SET(GWINSZ_IN_SYS_IOCTL CACHE INTERNAL "")
+-SET(HAVE_ACCESS 1 CACHE INTERNAL "")
+-SET(HAVE_AIOWAIT CACHE INTERNAL "")
+-SET(HAVE_AIO_H CACHE INTERNAL "")
+-SET(HAVE_AIO_READ CACHE INTERNAL "")
+-SET(HAVE_ALARM CACHE INTERNAL "")
+-SET(HAVE_ALLOCA CACHE INTERNAL "")
+-SET(HAVE_ALLOCA_H CACHE INTERNAL "")
+-SET(HAVE_ARPA_INET_H CACHE INTERNAL "")
+-SET(HAVE_ASM_MSR_H CACHE INTERNAL "")
+-SET(HAVE_ASM_TERMBITS_H CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE_SYMBOLS CACHE INTERNAL "")
+-SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE INTERNAL "")
+-SET(HAVE_BCMP CACHE INTERNAL "")
+-SET(HAVE_BFILL CACHE INTERNAL "")
+-SET(HAVE_BMOVE CACHE INTERNAL "")
+-SET(HAVE_BSD_SIGNALS CACHE INTERNAL "")
+-SET(HAVE_BSEARCH CACHE INTERNAL "")
+-SET(HAVE_BSS_START CACHE INTENAL "")
+-SET(HAVE_BZERO CACHE INTERNAL "")
+-SET(HAVE_CHOWN CACHE INTERNAL "")
+-SET(HAVE_CLOCK_GETTIME CACHE INTERNAL "")
+-SET(HAVE_COMPRESS CACHE INTERNAL "")
+-SET(HAVE_CRYPT CACHE INTERNAL "")
+-SET(HAVE_CRYPT_H CACHE INTERNAL "")
+-SET(HAVE_CUSERID CACHE INTERNAL "")
+-SET(HAVE_CXXABI_H CACHE INTERNAL "")
+-SET(HAVE_CXX_NEW CACHE INTERNAL "")
+-SET(HAVE_DECL_FDATASYNC CACHE INTERNAL "")
+-SET(HAVE_SIGNAL_H 1 CACHE INTERNAL "")
+-SET(HAVE_GETHOSTBYNAME_R CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_SETPRIO CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_ATTR_SETSCHEDPARAM CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_KILL CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_SETPRIO_NP CACHE INTERNAL "")
+-SET(HAVE_PTHREAD_SETSCHEDPARAM CACHE INTERNAL "")
+-SET(HAVE_SETFILEPOINTER CACHE INTERNAL "")
+-SET(SIZEOF_U_INT32_T CACHE INTERNAL "")
+-SET(IS_VOID_SIGNAL 1 CACHE INTERNAL "")
+-SET(IS_VOID_QSORT 1 CACHE INTERNAL "")
+-ENDIF()
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win-iconv/iconv.h mariadb-native-client.trunk/win-iconv/iconv.h
+--- mariadb/win-iconv/iconv.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win-iconv/iconv.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,14 @@
++#ifndef _LIBICONV_H
++#define _LIBICONV_H
++#include <stddef.h>
++#ifdef __cplusplus
++extern "C" {
++#endif
++typedef void* iconv_t;
++iconv_t iconv_open(const char *tocode, const char *fromcode);
++int iconv_close(iconv_t cd);
++size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
++#ifdef __cplusplus
++}
++#endif
++#endif//_LIBICONV_H
+\ No newline at end of file
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win-iconv/mlang.h mariadb-native-client.trunk/win-iconv/mlang.h
+--- mariadb/win-iconv/mlang.h 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win-iconv/mlang.h 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,54 @@
++HRESULT WINAPI ConvertINetString(
++ LPDWORD lpdwMode,
++ DWORD dwSrcEncoding,
++ DWORD dwDstEncoding,
++ LPCSTR lpSrcStr,
++ LPINT lpnSrcSize,
++ LPBYTE lpDstStr,
++ LPINT lpnDstSize
++);
++
++HRESULT WINAPI ConvertINetMultiByteToUnicode(
++ LPDWORD lpdwMode,
++ DWORD dwSrcEncoding,
++ LPCSTR lpSrcStr,
++ LPINT lpnMultiCharCount,
++ LPWSTR lpDstStr,
++ LPINT lpnWideCharCount
++);
++
++HRESULT WINAPI ConvertINetUnicodeToMultiByte(
++ LPDWORD lpdwMode,
++ DWORD dwEncoding,
++ LPCWSTR lpSrcStr,
++ LPINT lpnWideCharCount,
++ LPSTR lpDstStr,
++ LPINT lpnMultiCharCount
++);
++
++HRESULT WINAPI IsConvertINetStringAvailable(
++ DWORD dwSrcEncoding,
++ DWORD dwDstEncoding
++);
++
++HRESULT WINAPI LcidToRfc1766A(
++ LCID Locale,
++ LPSTR pszRfc1766,
++ int nChar
++);
++
++HRESULT WINAPI LcidToRfc1766W(
++ LCID Locale,
++ LPWSTR pszRfc1766,
++ int nChar
++);
++
++HRESULT WINAPI Rfc1766ToLcidA(
++ LCID *pLocale,
++ LPSTR pszRfc1766
++);
++
++HRESULT WINAPI Rfc1766ToLcidW(
++ LCID *pLocale,
++ LPWSTR pszRfc1766
++);
+diff -x .bzr -u --recursive -N mariadb-native-client.release/win-iconv/win_iconv.c mariadb-native-client.trunk/win-iconv/win_iconv.c
+--- mariadb/win-iconv/win_iconv.c 1970-01-01 01:00:00.000000000 +0100
++++ mariadb/win-iconv/win_iconv.c 2013-10-19 07:29:16.000000000 +0200
+@@ -0,0 +1,2051 @@
++/*
++ * iconv implementation using Win32 API to convert.
++ *
++ * This file is placed in the public domain.
++ */
++
++/* for WC_NO_BEST_FIT_CHARS */
++#ifndef WINVER
++# define WINVER 0x0500
++#endif
++
++#define STRICT
++#include <windows.h>
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++
++#ifdef __GNUC__
++#define UNUSED __attribute__((unused))
++#else
++#define UNUSED
++#endif
++
++/* WORKAROUND: */
++#ifndef UNDER_CE
++#define GetProcAddressA GetProcAddress
++#endif
++
++#if 0
++# define MAKE_EXE
++# define MAKE_DLL
++# define USE_LIBICONV_DLL
++#endif
++
++#if !defined(DEFAULT_LIBICONV_DLL)
++# define DEFAULT_LIBICONV_DLL ""
++#endif
++
++#define MB_CHAR_MAX 16
++
++#define UNICODE_MODE_BOM_DONE 1
++#define UNICODE_MODE_SWAPPED 2
++
++#define FLAG_USE_BOM 1
++#define FLAG_TRANSLIT 2 /* //TRANSLIT */
++#define FLAG_IGNORE 4 /* //IGNORE */
++
++typedef unsigned char uchar;
++typedef unsigned short ushort;
++typedef unsigned int uint;
++
++typedef void* iconv_t;
++
++iconv_t iconv_open(const char *tocode, const char *fromcode);
++int iconv_close(iconv_t cd);
++size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
++
++/* libiconv interface for vim */
++#if defined(MAKE_DLL)
++int
++iconvctl (iconv_t cd, int request, void* argument)
++{
++ /* not supported */
++ return 0;
++}
++#endif
++
++typedef struct compat_t compat_t;
++typedef struct csconv_t csconv_t;
++typedef struct rec_iconv_t rec_iconv_t;
++
++typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
++typedef int (*f_iconv_close)(iconv_t cd);
++typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
++typedef int* (*f_errno)(void);
++typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
++typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
++
++#define COMPAT_IN 1
++#define COMPAT_OUT 2
++
++/* unicode mapping for compatibility with other conversion table. */
++struct compat_t {
++ uint in;
++ uint out;
++ uint flag;
++};
++
++struct csconv_t {
++ int codepage;
++ int flags;
++ f_mbtowc mbtowc;
++ f_wctomb wctomb;
++ f_mblen mblen;
++ f_flush flush;
++ DWORD mode;
++ compat_t *compat;
++};
++
++struct rec_iconv_t {
++ iconv_t cd;
++ f_iconv_close iconv_close;
++ f_iconv iconv;
++ f_errno _errno;
++ csconv_t from;
++ csconv_t to;
++#if defined(USE_LIBICONV_DLL)
++ HMODULE hlibiconv;
++#endif
++};
++
++static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
++static int win_iconv_close(iconv_t cd);
++static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
++
++static int load_mlang(void);
++static int make_csconv(const char *name, csconv_t *cv);
++static int name_to_codepage(const char *name);
++static uint utf16_to_ucs4(const ushort *wbuf);
++static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
++static int mbtowc_flags(int codepage);
++static int must_use_null_useddefaultchar(int codepage);
++static char *strrstr(const char *str, const char *token);
++static char *xstrndup(const char *s, size_t n);
++static int seterror(int err);
++
++#if defined(USE_LIBICONV_DLL)
++static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
++static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
++static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);
++
++static HMODULE hwiniconv;
++#endif
++
++static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
++static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
++static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
++static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
++static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
++
++static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
++static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
++static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
++
++static struct {
++ int codepage;
++ const char *name;
++} codepage_alias[] = {
++ {65001, "CP65001"},
++ {65001, "UTF8"},
++ {65001, "UTF-8"},
++
++ {1200, "CP1200"},
++ {1200, "UTF16LE"},
++ {1200, "UTF-16LE"},
++ {1200, "UCS2LE"},
++ {1200, "UCS-2LE"},
++
++ {1201, "CP1201"},
++ {1201, "UTF16BE"},
++ {1201, "UTF-16BE"},
++ {1201, "UCS2BE"},
++ {1201, "UCS-2BE"},
++ {1201, "unicodeFFFE"},
++
++ {12000, "CP12000"},
++ {12000, "UTF32LE"},
++ {12000, "UTF-32LE"},
++ {12000, "UCS4LE"},
++ {12000, "UCS-4LE"},
++
++ {12001, "CP12001"},
++ {12001, "UTF32BE"},
++ {12001, "UTF-32BE"},
++ {12001, "UCS4BE"},
++ {12001, "UCS-4BE"},
++
++#ifndef GLIB_COMPILATION
++ /*
++ * Default is big endian.
++ * See rfc2781 4.3 Interpreting text labelled as UTF-16.
++ */
++ {1201, "UTF16"},
++ {1201, "UTF-16"},
++ {1201, "UCS2"},
++ {1201, "UCS-2"},
++ {12001, "UTF32"},
++ {12001, "UTF-32"},
++ {12001, "UCS-4"},
++ {12001, "UCS4"},
++#else
++ /* Default is little endian, because the platform is */
++ {1200, "UTF16"},
++ {1200, "UTF-16"},
++ {1200, "UCS2"},
++ {1200, "UCS-2"},
++ {12000, "UTF32"},
++ {12000, "UTF-32"},
++ {12000, "UCS4"},
++ {12000, "UCS-4"},
++#endif
++
++ /* copy from libiconv `iconv -l` */
++ /* !IsValidCodePage(367) */
++ {20127, "ANSI_X3.4-1968"},
++ {20127, "ANSI_X3.4-1986"},
++ {20127, "ASCII"},
++ {20127, "CP367"},
++ {20127, "IBM367"},
++ {20127, "ISO-IR-6"},
++ {20127, "ISO646-US"},
++ {20127, "ISO_646.IRV:1991"},
++ {20127, "US"},
++ {20127, "US-ASCII"},
++ {20127, "CSASCII"},
++
++ /* !IsValidCodePage(819) */
++ {1252, "CP819"},
++ {1252, "IBM819"},
++ {28591, "ISO-8859-1"},
++ {28591, "ISO-IR-100"},
++ {28591, "ISO8859-1"},
++ {28591, "ISO_8859-1"},
++ {28591, "ISO_8859-1:1987"},
++ {28591, "L1"},
++ {28591, "LATIN1"},
++ {28591, "CSISOLATIN1"},
++
++ {1250, "CP1250"},
++ {1250, "MS-EE"},
++ {1250, "WINDOWS-1250"},
++
++ {1251, "CP1251"},
++ {1251, "MS-CYRL"},
++ {1251, "WINDOWS-1251"},
++
++ {1252, "CP1252"},
++ {1252, "MS-ANSI"},
++ {1252, "WINDOWS-1252"},
++
++ {1253, "CP1253"},
++ {1253, "MS-GREEK"},
++ {1253, "WINDOWS-1253"},
++
++ {1254, "CP1254"},
++ {1254, "MS-TURK"},
++ {1254, "WINDOWS-1254"},
++
++ {1255, "CP1255"},
++ {1255, "MS-HEBR"},
++ {1255, "WINDOWS-1255"},
++
++ {1256, "CP1256"},
++ {1256, "MS-ARAB"},
++ {1256, "WINDOWS-1256"},
++
++ {1257, "CP1257"},
++ {1257, "WINBALTRIM"},
++ {1257, "WINDOWS-1257"},
++
++ {1258, "CP1258"},
++ {1258, "WINDOWS-1258"},
++
++ {850, "850"},
++ {850, "CP850"},
++ {850, "IBM850"},
++ {850, "CSPC850MULTILINGUAL"},
++
++ /* !IsValidCodePage(862) */
++ {862, "862"},
++ {862, "CP862"},
++ {862, "IBM862"},
++ {862, "CSPC862LATINHEBREW"},
++
++ {866, "866"},
++ {866, "CP866"},
++ {866, "IBM866"},
++ {866, "CSIBM866"},
++
++ /* !IsValidCodePage(154) */
++ {154, "CP154"},
++ {154, "CYRILLIC-ASIAN"},
++ {154, "PT154"},
++ {154, "PTCP154"},
++ {154, "CSPTCP154"},
++
++ /* !IsValidCodePage(1133) */
++ {1133, "CP1133"},
++ {1133, "IBM-CP1133"},
++
++ {874, "CP874"},
++ {874, "WINDOWS-874"},
++
++ /* !IsValidCodePage(51932) */
++ {51932, "CP51932"},
++ {51932, "MS51932"},
++ {51932, "WINDOWS-51932"},
++ {51932, "EUC-JP"},
++
++ {932, "CP932"},
++ {932, "MS932"},
++ {932, "SHIFFT_JIS"},
++ {932, "SHIFFT_JIS-MS"},
++ {932, "SJIS"},
++ {932, "SJIS-MS"},
++ {932, "SJIS-OPEN"},
++ {932, "SJIS-WIN"},
++ {932, "WINDOWS-31J"},
++ {932, "WINDOWS-932"},
++ {932, "CSWINDOWS31J"},
++
++ {50221, "CP50221"},
++ {50221, "ISO-2022-JP"},
++ {50221, "ISO-2022-JP-MS"},
++ {50221, "ISO2022-JP"},
++ {50221, "ISO2022-JP-MS"},
++ {50221, "MS50221"},
++ {50221, "WINDOWS-50221"},
++
++ {936, "CP936"},
++ {936, "GBK"},
++ {936, "MS936"},
++ {936, "WINDOWS-936"},
++
++ {950, "CP950"},
++ {950, "BIG5"},
++ {950, "BIG5HKSCS"},
++ {950, "BIG5-HKSCS"},
++
++ {949, "CP949"},
++ {949, "UHC"},
++ {949, "EUC-KR"},
++
++ {1361, "CP1361"},
++ {1361, "JOHAB"},
++
++ {437, "437"},
++ {437, "CP437"},
++ {437, "IBM437"},
++ {437, "CSPC8CODEPAGE437"},
++
++ {737, "CP737"},
++
++ {775, "CP775"},
++ {775, "IBM775"},
++ {775, "CSPC775BALTIC"},
++
++ {852, "852"},
++ {852, "CP852"},
++ {852, "IBM852"},
++ {852, "CSPCP852"},
++
++ /* !IsValidCodePage(853) */
++ {853, "CP853"},
++
++ {855, "855"},
++ {855, "CP855"},
++ {855, "IBM855"},
++ {855, "CSIBM855"},
++
++ {857, "857"},
++ {857, "CP857"},
++ {857, "IBM857"},
++ {857, "CSIBM857"},
++
++ /* !IsValidCodePage(858) */
++ {858, "CP858"},
++
++ {860, "860"},
++ {860, "CP860"},
++ {860, "IBM860"},
++ {860, "CSIBM860"},
++
++ {861, "861"},
++ {861, "CP-IS"},
++ {861, "CP861"},
++ {861, "IBM861"},
++ {861, "CSIBM861"},
++
++ {863, "863"},
++ {863, "CP863"},
++ {863, "IBM863"},
++ {863, "CSIBM863"},
++
++ {864, "CP864"},
++ {864, "IBM864"},
++ {864, "CSIBM864"},
++
++ {865, "865"},
++ {865, "CP865"},
++ {865, "IBM865"},
++ {865, "CSIBM865"},
++
++ {869, "869"},
++ {869, "CP-GR"},
++ {869, "CP869"},
++ {869, "IBM869"},
++ {869, "CSIBM869"},
++
++ /* !IsValidCodePage(1152) */
++ {1125, "CP1125"},
++
++ /*
++ * Code Page Identifiers
++ * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
++ */
++ {37, "IBM037"}, /* IBM EBCDIC US-Canada */
++ {437, "IBM437"}, /* OEM United States */
++ {500, "IBM500"}, /* IBM EBCDIC International */
++ {708, "ASMO-708"}, /* Arabic (ASMO 708) */
++ /* 709 Arabic (ASMO-449+, BCON V4) */
++ /* 710 Arabic - Transparent Arabic */
++ {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
++ {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
++ {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
++ {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
++ {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
++ {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
++ {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
++ {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
++ {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
++ {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
++ {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
++ {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
++ {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
++ {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
++ {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
++ {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
++ {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
++ {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
++ {875, "cp875"}, /* IBM EBCDIC Greek Modern */
++ {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
++ {932, "shift-jis"}, /* alternative name for it */
++ {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
++ {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
++ {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
++ {950, "big5hkscs"}, /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */
++ {950, "big5-hkscs"}, /* alternative name for it */
++ {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
++ {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
++ {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
++ {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
++ {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
++ {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
++ {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
++ {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
++ {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
++ {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
++ {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
++ {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
++ {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
++ {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
++ {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
++ {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
++ {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
++ {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
++ {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
++ {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
++ {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
++ {1361, "Johab"}, /* Korean (Johab) */
++ {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
++ {10001, "x-mac-japanese"}, /* Japanese (Mac) */
++ {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
++ {10003, "x-mac-korean"}, /* Korean (Mac) */
++ {10004, "x-mac-arabic"}, /* Arabic (Mac) */
++ {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
++ {10006, "x-mac-greek"}, /* Greek (Mac) */
++ {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
++ {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
++ {10010, "x-mac-romanian"}, /* Romanian (Mac) */
++ {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
++ {10021, "x-mac-thai"}, /* Thai (Mac) */
++ {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
++ {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
++ {10081, "x-mac-turkish"}, /* Turkish (Mac) */
++ {10082, "x-mac-croatian"}, /* Croatian (Mac) */
++ {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
++ {20001, "x-cp20001"}, /* TCA Taiwan */
++ {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
++ {20003, "x-cp20003"}, /* IBM5550 Taiwan */
++ {20004, "x-cp20004"}, /* TeleText Taiwan */
++ {20005, "x-cp20005"}, /* Wang Taiwan */
++ {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
++ {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
++ {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
++ {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
++ {20127, "us-ascii"}, /* US-ASCII (7-bit) */
++ {20261, "x-cp20261"}, /* T.61 */
++ {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
++ {20273, "IBM273"}, /* IBM EBCDIC Germany */
++ {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
++ {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
++ {20280, "IBM280"}, /* IBM EBCDIC Italy */
++ {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
++ {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
++ {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
++ {20297, "IBM297"}, /* IBM EBCDIC France */
++ {20420, "IBM420"}, /* IBM EBCDIC Arabic */
++ {20423, "IBM423"}, /* IBM EBCDIC Greek */
++ {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
++ {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
++ {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
++ {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
++ {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
++ {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
++ {20905, "IBM905"}, /* IBM EBCDIC Turkish */
++ {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
++ {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
++ {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
++ {20949, "x-cp20949"}, /* Korean Wansung */
++ {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
++ /* 21027 (deprecated) */
++ {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
++ {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
++ {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
++ {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
++ {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
++ {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
++ {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
++ {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
++ {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
++ {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
++ {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
++ {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
++ {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
++ {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
++ {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
++ {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
++ {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
++ {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
++ {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
++ {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
++ {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
++ {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
++ {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
++ {29001, "x-Europa"}, /* Europa 3 */
++ {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
++ {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
++ {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
++ {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
++ {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
++ {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
++ {50225, "iso2022-kr"}, /* ISO 2022 Korean */
++ {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
++ /* 50229 ISO 2022 Traditional Chinese */
++ /* 50930 EBCDIC Japanese (Katakana) Extended */
++ /* 50931 EBCDIC US-Canada and Japanese */
++ /* 50933 EBCDIC Korean Extended and Korean */
++ /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */
++ /* 50936 EBCDIC Simplified Chinese */
++ /* 50937 EBCDIC US-Canada and Traditional Chinese */
++ /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */
++ {51932, "euc-jp"}, /* EUC Japanese */
++ {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
++ {51949, "euc-kr"}, /* EUC Korean */
++ /* 51950 EUC Traditional Chinese */
++ {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
++ {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
++ {57002, "x-iscii-de"}, /* ISCII Devanagari */
++ {57003, "x-iscii-be"}, /* ISCII Bengali */
++ {57004, "x-iscii-ta"}, /* ISCII Tamil */
++ {57005, "x-iscii-te"}, /* ISCII Telugu */
++ {57006, "x-iscii-as"}, /* ISCII Assamese */
++ {57007, "x-iscii-or"}, /* ISCII Oriya */
++ {57008, "x-iscii-ka"}, /* ISCII Kannada */
++ {57009, "x-iscii-ma"}, /* ISCII Malayalam */
++ {57010, "x-iscii-gu"}, /* ISCII Gujarati */
++ {57011, "x-iscii-pa"}, /* ISCII Punjabi */
++
++ {0, NULL}
++};
++
++/*
++ * SJIS SHIFTJIS table CP932 table
++ * ---- --------------------------- --------------------------------
++ * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
++ * 7E U+203E OVERLINE U+007E TILDE
++ * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR
++ * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
++ * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE
++ * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
++ * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS
++ * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN
++ * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN
++ * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN
++ *
++ * EUC-JP and ISO-2022-JP should be compatible with CP932.
++ *
++ * Kernel and MLang have different Unicode mapping table. Make sure
++ * which API is used.
++ */
++static compat_t cp932_compat[] = {
++ {0x00A5, 0x005C, COMPAT_OUT},
++ {0x203E, 0x007E, COMPAT_OUT},
++ {0x2014, 0x2015, COMPAT_OUT},
++ {0x301C, 0xFF5E, COMPAT_OUT},
++ {0x2016, 0x2225, COMPAT_OUT},
++ {0x2212, 0xFF0D, COMPAT_OUT},
++ {0x00A2, 0xFFE0, COMPAT_OUT},
++ {0x00A3, 0xFFE1, COMPAT_OUT},
++ {0x00AC, 0xFFE2, COMPAT_OUT},
++ {0, 0, 0}
++};
++
++static compat_t cp20932_compat[] = {
++ {0x00A5, 0x005C, COMPAT_OUT},
++ {0x203E, 0x007E, COMPAT_OUT},
++ {0x2014, 0x2015, COMPAT_OUT},
++ {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
++ {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
++ {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
++ {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
++ {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
++ {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
++ {0, 0, 0}
++};
++
++static compat_t *cp51932_compat = cp932_compat;
++
++/* cp20932_compat for kernel. cp932_compat for mlang. */
++static compat_t *cp5022x_compat = cp932_compat;
++
++typedef HRESULT (WINAPI *CONVERTINETSTRING)(
++ LPDWORD lpdwMode,
++ DWORD dwSrcEncoding,
++ DWORD dwDstEncoding,
++ LPCSTR lpSrcStr,
++ LPINT lpnSrcSize,
++ LPBYTE lpDstStr,
++ LPINT lpnDstSize
++);
++typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
++ LPDWORD lpdwMode,
++ DWORD dwSrcEncoding,
++ LPCSTR lpSrcStr,
++ LPINT lpnMultiCharCount,
++ LPWSTR lpDstStr,
++ LPINT lpnWideCharCount
++);
++typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
++ LPDWORD lpdwMode,
++ DWORD dwEncoding,
++ LPCWSTR lpSrcStr,
++ LPINT lpnWideCharCount,
++ LPSTR lpDstStr,
++ LPINT lpnMultiCharCount
++);
++typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
++ DWORD dwSrcEncoding,
++ DWORD dwDstEncoding
++);
++typedef HRESULT (WINAPI *LCIDTORFC1766A)(
++ LCID Locale,
++ LPSTR pszRfc1766,
++ int nChar
++);
++typedef HRESULT (WINAPI *LCIDTORFC1766W)(
++ LCID Locale,
++ LPWSTR pszRfc1766,
++ int nChar
++);
++typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
++ LCID *pLocale,
++ LPSTR pszRfc1766
++);
++typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
++ LCID *pLocale,
++ LPWSTR pszRfc1766
++);
++static CONVERTINETSTRING ConvertINetString;
++static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
++static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
++static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
++static LCIDTORFC1766A LcidToRfc1766A;
++static RFC1766TOLCIDA Rfc1766ToLcidA;
++
++static int
++load_mlang(void)
++{
++ HMODULE h;
++ if (ConvertINetString != NULL)
++ return TRUE;
++ h = LoadLibrary(TEXT("mlang.dll"));
++ if (!h)
++ return FALSE;
++ ConvertINetString = (CONVERTINETSTRING)GetProcAddressA(h, "ConvertINetString");
++ ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode");
++ ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte");
++ IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddressA(h, "IsConvertINetStringAvailable");
++ LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddressA(h, "LcidToRfc1766A");
++ Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddressA(h, "Rfc1766ToLcidA");
++ return TRUE;
++}
++
++iconv_t
++iconv_open(const char *tocode, const char *fromcode)
++{
++ rec_iconv_t *cd;
++
++ cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
++ if (cd == NULL)
++ return (iconv_t)(-1);
++
++#if defined(USE_LIBICONV_DLL)
++ errno = 0;
++ if (libiconv_iconv_open(cd, tocode, fromcode))
++ return (iconv_t)cd;
++#endif
++
++ /* reset the errno to prevent reporting wrong error code.
++ * 0 for unsorted error. */
++ errno = 0;
++ if (win_iconv_open(cd, tocode, fromcode))
++ return (iconv_t)cd;
++
++ free(cd);
++
++ return (iconv_t)(-1);
++}
++
++int
++iconv_close(iconv_t _cd)
++{
++ rec_iconv_t *cd = (rec_iconv_t *)_cd;
++ int r = cd->iconv_close(cd->cd);
++ int e = *(cd->_errno());
++#if defined(USE_LIBICONV_DLL)
++ if (cd->hlibiconv != NULL)
++ FreeLibrary(cd->hlibiconv);
++#endif
++ free(cd);
++ errno = e;
++ return r;
++}
++
++size_t
++iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
++{
++ rec_iconv_t *cd = (rec_iconv_t *)_cd;
++ size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
++ errno = *(cd->_errno());
++ return r;
++}
++
++static int
++win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
++{
++ if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))
++ return FALSE;
++ cd->iconv_close = win_iconv_close;
++ cd->iconv = win_iconv;
++ cd->_errno = _errno;
++ cd->cd = (iconv_t)cd;
++ return TRUE;
++}
++
++static int
++win_iconv_close(iconv_t cd UNUSED)
++{
++ return 0;
++}
++
++static size_t
++win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
++{
++ rec_iconv_t *cd = (rec_iconv_t *)_cd;
++ ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
++ int insize;
++ int outsize;
++ int wsize;
++ DWORD frommode;
++ DWORD tomode;
++ uint wc;
++ compat_t *cp;
++ int i;
++
++ if (inbuf == NULL || *inbuf == NULL)
++ {
++ if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
++ {
++ tomode = cd->to.mode;
++ outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
++ if (outsize == -1)
++ {
++ if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
++ {
++ outsize = 0;
++ }
++ else
++ {
++ cd->to.mode = tomode;
++ return (size_t)(-1);
++ }
++ }
++ *outbuf += outsize;
++ *outbytesleft -= outsize;
++ }
++ cd->from.mode = 0;
++ cd->to.mode = 0;
++ return 0;
++ }
++
++ while (*inbytesleft != 0)
++ {
++ frommode = cd->from.mode;
++ tomode = cd->to.mode;
++ wsize = MB_CHAR_MAX;
++
++ insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
++ if (insize == -1)
++ {
++ if (cd->to.flags & FLAG_IGNORE)
++ {
++ cd->from.mode = frommode;
++ insize = 1;
++ wsize = 0;
++ }
++ else
++ {
++ cd->from.mode = frommode;
++ return (size_t)(-1);
++ }
++ }
++
++ if (wsize == 0)
++ {
++ *inbuf += insize;
++ *inbytesleft -= insize;
++ continue;
++ }
++
++ if (cd->from.compat != NULL)
++ {
++ wc = utf16_to_ucs4(wbuf);
++ cp = cd->from.compat;
++ for (i = 0; cp[i].in != 0; ++i)
++ {
++ if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
++ {
++ ucs4_to_utf16(cp[i].in, wbuf, &wsize);
++ break;
++ }
++ }
++ }
++
++ if (cd->to.compat != NULL)
++ {
++ wc = utf16_to_ucs4(wbuf);
++ cp = cd->to.compat;
++ for (i = 0; cp[i].in != 0; ++i)
++ {
++ if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
++ {
++ ucs4_to_utf16(cp[i].out, wbuf, &wsize);
++ break;
++ }
++ }
++ }
++
++ outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
++ if (outsize == -1)
++ {
++ if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
++ {
++ cd->to.mode = tomode;
++ outsize = 0;
++ }
++ else
++ {
++ cd->from.mode = frommode;
++ cd->to.mode = tomode;
++ return (size_t)(-1);
++ }
++ }
++
++ *inbuf += insize;
++ *outbuf += outsize;
++ *inbytesleft -= insize;
++ *outbytesleft -= outsize;
++ }
++
++ return 0;
++}
++
++static int
++make_csconv(const char *_name, csconv_t *cv)
++{
++ CPINFO cpinfo;
++ int use_compat = TRUE;
++ int flag = 0;
++ char *name;
++ char *p;
++
++ name = xstrndup(_name, strlen(_name));
++ if (name == NULL)
++ return FALSE;
++
++ /* check for option "enc_name//opt1//opt2" */
++ while ((p = strrstr(name, "//")) != NULL)
++ {
++ if (_stricmp(p + 2, "nocompat") == 0)
++ use_compat = FALSE;
++ else if (_stricmp(p + 2, "translit") == 0)
++ flag |= FLAG_TRANSLIT;
++ else if (_stricmp(p + 2, "ignore") == 0)
++ flag |= FLAG_IGNORE;
++ *p = 0;
++ }
++
++ cv->mode = 0;
++ cv->flags = flag;
++ cv->mblen = NULL;
++ cv->flush = NULL;
++ cv->compat = NULL;
++ cv->codepage = name_to_codepage(name);
++ if (cv->codepage == 1200 || cv->codepage == 1201)
++ {
++ cv->mbtowc = utf16_mbtowc;
++ cv->wctomb = utf16_wctomb;
++ if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 ||
++ _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0)
++ cv->flags |= FLAG_USE_BOM;
++ }
++ else if (cv->codepage == 12000 || cv->codepage == 12001)
++ {
++ cv->mbtowc = utf32_mbtowc;
++ cv->wctomb = utf32_wctomb;
++ if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 ||
++ _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0)
++ cv->flags |= FLAG_USE_BOM;
++ }
++ else if (cv->codepage == 65001)
++ {
++ cv->mbtowc = kernel_mbtowc;
++ cv->wctomb = kernel_wctomb;
++ cv->mblen = utf8_mblen;
++ }
++ else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
++ {
++ cv->mbtowc = iso2022jp_mbtowc;
++ cv->wctomb = iso2022jp_wctomb;
++ cv->flush = iso2022jp_flush;
++ }
++ else if (cv->codepage == 51932 && load_mlang())
++ {
++ cv->mbtowc = mlang_mbtowc;
++ cv->wctomb = mlang_wctomb;
++ cv->mblen = eucjp_mblen;
++ }
++ else if (IsValidCodePage(cv->codepage)
++ && GetCPInfo(cv->codepage, &cpinfo) != 0)
++ {
++ cv->mbtowc = kernel_mbtowc;
++ cv->wctomb = kernel_wctomb;
++ if (cpinfo.MaxCharSize == 1)
++ cv->mblen = sbcs_mblen;
++ else if (cpinfo.MaxCharSize == 2)
++ cv->mblen = dbcs_mblen;
++ else
++ cv->mblen = mbcs_mblen;
++ }
++ else
++ {
++ /* not supported */
++ free(name);
++ errno = EINVAL;
++ return FALSE;
++ }
++
++ if (use_compat)
++ {
++ switch (cv->codepage)
++ {
++ case 932: cv->compat = cp932_compat; break;
++ case 20932: cv->compat = cp20932_compat; break;
++ case 51932: cv->compat = cp51932_compat; break;
++ case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
++ }
++ }
++
++ free(name);
++
++ return TRUE;
++}
++
++static int
++name_to_codepage(const char *name)
++{
++ int i;
++
++ if (*name == '\0' ||
++ strcmp(name, "char") == 0)
++ return GetACP();
++ else if (strcmp(name, "wchar_t") == 0)
++ return 1200;
++ else if (_strnicmp(name, "cp", 2) == 0)
++ return atoi(name + 2); /* CP123 */
++ else if ('0' <= name[0] && name[0] <= '9')
++ return atoi(name); /* 123 */
++ else if (_strnicmp(name, "xx", 2) == 0)
++ return atoi(name + 2); /* XX123 for debug */
++
++ for (i = 0; codepage_alias[i].name != NULL; ++i)
++ if (_stricmp(name, codepage_alias[i].name) == 0)
++ return codepage_alias[i].codepage;
++ return -1;
++}
++
++/*
++ * http://www.faqs.org/rfcs/rfc2781.html
++ */
++static uint
++utf16_to_ucs4(const ushort *wbuf)
++{
++ uint wc = wbuf[0];
++ if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
++ wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
++ return wc;
++}
++
++static void
++ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
++{
++ if (wc < 0x10000)
++ {
++ wbuf[0] = wc;
++ *wbufsize = 1;
++ }
++ else
++ {
++ wc -= 0x10000;
++ wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
++ wbuf[1] = 0xDC00 | (wc & 0x3FF);
++ *wbufsize = 2;
++ }
++}
++
++/*
++ * Check if codepage is one of those for which the dwFlags parameter
++ * to MultiByteToWideChar() must be zero. Return zero or
++ * MB_ERR_INVALID_CHARS. The docs in Platform SDK for for Windows
++ * Server 2003 R2 claims that also codepage 65001 is one of these, but
++ * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
++ * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
++ * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
++ * from UTF-8.
++ */
++static int
++mbtowc_flags(int codepage)
++{
++ return (codepage == 50220 || codepage == 50221 ||
++ codepage == 50222 || codepage == 50225 ||
++ codepage == 50227 || codepage == 50229 ||
++ codepage == 52936 || codepage == 54936 ||
++ (codepage >= 57002 && codepage <= 57011) ||
++ codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
++}
++
++/*
++ * Check if codepage is one those for which the lpUsedDefaultChar
++ * parameter to WideCharToMultiByte() must be NULL. The docs in
++ * Platform SDK for for Windows Server 2003 R2 claims that this is the
++ * list below, while the MSDN docs for MSVS2008 claim that it is only
++ * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
++ * SDK seems to be correct, at least for XP.
++ */
++static int
++must_use_null_useddefaultchar(int codepage)
++{
++ return (codepage == 65000 || codepage == 65001 ||
++ codepage == 50220 || codepage == 50221 ||
++ codepage == 50222 || codepage == 50225 ||
++ codepage == 50227 || codepage == 50229 ||
++ codepage == 52936 || codepage == 54936 ||
++ (codepage >= 57002 && codepage <= 57011) ||
++ codepage == 42);
++}
++
++static char *
++strrstr(const char *str, const char *token)
++{
++ int len = strlen(token);
++ const char *p = str + strlen(str);
++
++ while (str <= --p)
++ if (p[0] == token[0] && strncmp(p, token, len) == 0)
++ return (char *)p;
++ return NULL;
++}
++
++static char *
++xstrndup(const char *s, size_t n)
++{
++ char *p;
++
++ p = (char *)malloc(n + 1);
++ if (p == NULL)
++ return NULL;
++ memcpy(p, s, n);
++ p[n] = '\0';
++ return p;
++}
++
++static int
++seterror(int err)
++{
++ errno = err;
++ return -1;
++}
++
++#if defined(USE_LIBICONV_DLL)
++static int
++libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
++{
++ HMODULE hlibiconv = NULL;
++ HMODULE hmsvcrt = NULL;
++ char *dllname;
++ const char *p;
++ const char *e;
++ f_iconv_open _iconv_open;
++
++ /*
++ * always try to load dll, so that we can switch dll in runtime.
++ */
++
++ /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
++ p = getenv("WINICONV_LIBICONV_DLL");
++ if (p == NULL)
++ p = DEFAULT_LIBICONV_DLL;
++ /* parse comma separated value */
++ for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
++ {
++ e = strchr(p, ',');
++ if (p == e)
++ continue;
++ else if (e == NULL)
++ e = p + strlen(p);
++ dllname = xstrndup(p, e - p);
++ if (dllname == NULL)
++ return FALSE;
++ hlibiconv = LoadLibraryA(dllname);
++ free(dllname);
++ if (hlibiconv != NULL)
++ {
++ if (hlibiconv == hwiniconv)
++ {
++ FreeLibrary(hlibiconv);
++ hlibiconv = NULL;
++ continue;
++ }
++ break;
++ }
++ }
++
++ if (hlibiconv == NULL)
++ goto failed;
++
++ hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");
++ if (hmsvcrt == NULL)
++ goto failed;
++
++ _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "libiconv_open");
++ if (_iconv_open == NULL)
++ _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "iconv_open");
++ cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "libiconv_close");
++ if (cd->iconv_close == NULL)
++ cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "iconv_close");
++ cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "libiconv");
++ if (cd->iconv == NULL)
++ cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "iconv");
++ cd->_errno = (f_errno)GetProcAddressA(hmsvcrt, "_errno");
++ if (_iconv_open == NULL || cd->iconv_close == NULL
++ || cd->iconv == NULL || cd->_errno == NULL)
++ goto failed;
++
++ cd->cd = _iconv_open(tocode, fromcode);
++ if (cd->cd == (iconv_t)(-1))
++ goto failed;
++
++ cd->hlibiconv = hlibiconv;
++ return TRUE;
++
++failed:
++ if (hlibiconv != NULL)
++ FreeLibrary(hlibiconv);
++ /* do not free hmsvcrt which is obtained by GetModuleHandle() */
++ return FALSE;
++}
++
++/*
++ * Reference:
++ * http://forums.belution.com/ja/vc/000/234/78s.shtml
++ * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
++ *
++ * The formal way is
++ * imagehlp.h or dbghelp.h
++ * imagehlp.lib or dbghelp.lib
++ * ImageDirectoryEntryToData()
++ */
++#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
++#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
++static PVOID
++MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
++{
++ /* TODO: MappedAsImage? */
++ PIMAGE_DATA_DIRECTORY p;
++ p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
++ if (p->VirtualAddress == 0) {
++ *Size = 0;
++ return NULL;
++ }
++ *Size = p->Size;
++ return (PVOID)((LPBYTE)Base + p->VirtualAddress);
++}
++
++static HMODULE
++find_imported_module_by_funcname(HMODULE hModule, const char *funcname)
++{
++ DWORD_PTR Base;
++ ULONG Size;
++ PIMAGE_IMPORT_DESCRIPTOR Imp;
++ PIMAGE_THUNK_DATA Name; /* Import Name Table */
++ PIMAGE_IMPORT_BY_NAME ImpName;
++
++ Base = (DWORD_PTR)hModule;
++ Imp = (PIMAGE_IMPORT_DESCRIPTOR)MyImageDirectoryEntryToData(
++ (LPVOID)Base,
++ TRUE,
++ IMAGE_DIRECTORY_ENTRY_IMPORT,
++ &Size);
++ if (Imp == NULL)
++ return NULL;
++ for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
++ {
++ Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
++ for ( ; Name->u1.Ordinal != 0; ++Name)
++ {
++ if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
++ {
++ ImpName = (PIMAGE_IMPORT_BY_NAME)
++ (Base + (DWORD_PTR)Name->u1.AddressOfData);
++ if (strcmp((char *)ImpName->Name, funcname) == 0)
++ return GetModuleHandleA((char *)(Base + Imp->Name));
++ }
++ }
++ }
++ return NULL;
++}
++#endif
++
++static int
++sbcs_mblen(csconv_t *cv UNUSED, const uchar *buf UNUSED, int bufsize UNUSED)
++{
++ return 1;
++}
++
++static int
++dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
++{
++ int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
++ if (bufsize < len)
++ return seterror(EINVAL);
++ return len;
++}
++
++static int
++mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
++{
++ int len = 0;
++
++ if (cv->codepage == 54936) {
++ if (buf[0] <= 0x7F) len = 1;
++ else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
++ bufsize >= 2 &&
++ ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
++ (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;
++ else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
++ bufsize >= 4 &&
++ buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;
++ else
++ return seterror(EINVAL);
++ return len;
++ }
++ else
++ return seterror(EINVAL);
++}
++
++static int
++utf8_mblen(csconv_t *cv UNUSED, const uchar *buf, int bufsize)
++{
++ int len = 0;
++
++ if (buf[0] < 0x80) len = 1;
++ else if ((buf[0] & 0xE0) == 0xC0) len = 2;
++ else if ((buf[0] & 0xF0) == 0xE0) len = 3;
++ else if ((buf[0] & 0xF8) == 0xF0) len = 4;
++ else if ((buf[0] & 0xFC) == 0xF8) len = 5;
++ else if ((buf[0] & 0xFE) == 0xFC) len = 6;
++
++ if (len == 0)
++ return seterror(EILSEQ);
++ else if (bufsize < len)
++ return seterror(EINVAL);
++ return len;
++}
++
++static int
++eucjp_mblen(csconv_t *cv UNUSED, const uchar *buf, int bufsize)
++{
++ if (buf[0] < 0x80) /* ASCII */
++ return 1;
++ else if (buf[0] == 0x8E) /* JIS X 0201 */
++ {
++ if (bufsize < 2)
++ return seterror(EINVAL);
++ else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
++ return seterror(EILSEQ);
++ return 2;
++ }
++ else if (buf[0] == 0x8F) /* JIS X 0212 */
++ {
++ if (bufsize < 3)
++ return seterror(EINVAL);
++ else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
++ || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
++ return seterror(EILSEQ);
++ return 3;
++ }
++ else /* JIS X 0208 */
++ {
++ if (bufsize < 2)
++ return seterror(EINVAL);
++ else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
++ || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
++ return seterror(EILSEQ);
++ return 2;
++ }
++}
++
++static int
++kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
++{
++ int len;
++
++ len = cv->mblen(cv, buf, bufsize);
++ if (len == -1)
++ return -1;
++ *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
++ (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
++ if (*wbufsize == 0)
++ return seterror(EILSEQ);
++ return len;
++}
++
++static int
++kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
++{
++ BOOL usedDefaultChar = 0;
++ BOOL *p = NULL;
++ int flags = 0;
++ int len;
++
++ if (bufsize == 0)
++ return seterror(E2BIG);
++ if (!must_use_null_useddefaultchar(cv->codepage))
++ {
++ p = &usedDefaultChar;
++#ifdef WC_NO_BEST_FIT_CHARS
++ if (!(cv->flags & FLAG_TRANSLIT))
++ flags |= WC_NO_BEST_FIT_CHARS;
++#endif
++ }
++ len = WideCharToMultiByte(cv->codepage, flags,
++ (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
++ if (len == 0)
++ {
++ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
++ return seterror(E2BIG);
++ return seterror(EILSEQ);
++ }
++ else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT))
++ return seterror(EILSEQ);
++ else if (cv->mblen(cv, buf, len) != len) /* validate result */
++ return seterror(EILSEQ);
++ return len;
++}
++
++/*
++ * It seems that the mode (cv->mode) is fixnum.
++ * For example, when converting iso-2022-jp(cp50221) to unicode:
++ * in ascii sequence: mode=0xC42C0000
++ * in jisx0208 sequence: mode=0xC42C0001
++ * "C42C" is same for each convert session.
++ * It should be: ((codepage-1)<<16)|state
++ */
++static int
++mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
++{
++ int len;
++ int insize;
++ HRESULT hr;
++
++ len = cv->mblen(cv, buf, bufsize);
++ if (len == -1)
++ return -1;
++ insize = len;
++ hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
++ (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
++ if (hr != S_OK || insize != len)
++ return seterror(EILSEQ);
++ return len;
++}
++
++static int
++mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
++{
++ char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
++ int tmpsize = MB_CHAR_MAX;
++ int insize = wbufsize;
++ HRESULT hr;
++
++ hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
++ (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
++ if (hr != S_OK || insize != wbufsize)
++ return seterror(EILSEQ);
++ else if (bufsize < tmpsize)
++ return seterror(E2BIG);
++ else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
++ return seterror(EILSEQ);
++ memcpy(buf, tmpbuf, tmpsize);
++ return tmpsize;
++}
++
++static int
++utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
++{
++ int codepage = cv->codepage;
++
++ /* swap endian: 1200 <-> 1201 */
++ if (cv->mode & UNICODE_MODE_SWAPPED)
++ codepage ^= 1;
++
++ if (bufsize < 2)
++ return seterror(EINVAL);
++ if (codepage == 1200) /* little endian */
++ wbuf[0] = (buf[1] << 8) | buf[0];
++ else if (codepage == 1201) /* big endian */
++ wbuf[0] = (buf[0] << 8) | buf[1];
++
++ if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
++ {
++ cv->mode |= UNICODE_MODE_BOM_DONE;
++ if (wbuf[0] == 0xFFFE)
++ {
++ cv->mode |= UNICODE_MODE_SWAPPED;
++ *wbufsize = 0;
++ return 2;
++ }
++ else if (wbuf[0] == 0xFEFF)
++ {
++ *wbufsize = 0;
++ return 2;
++ }
++ }
++
++ if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
++ return seterror(EILSEQ);
++ if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
++ {
++ if (bufsize < 4)
++ return seterror(EINVAL);
++ if (codepage == 1200) /* little endian */
++ wbuf[1] = (buf[3] << 8) | buf[2];
++ else if (codepage == 1201) /* big endian */
++ wbuf[1] = (buf[2] << 8) | buf[3];
++ if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
++ return seterror(EILSEQ);
++ *wbufsize = 2;
++ return 4;
++ }
++ *wbufsize = 1;
++ return 2;
++}
++
++static int
++utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
++{
++ if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
++ {
++ int r;
++
++ cv->mode |= UNICODE_MODE_BOM_DONE;
++ if (bufsize < 2)
++ return seterror(E2BIG);
++ if (cv->codepage == 1200) /* little endian */
++ memcpy(buf, "\xFF\xFE", 2);
++ else if (cv->codepage == 1201) /* big endian */
++ memcpy(buf, "\xFE\xFF", 2);
++
++ r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
++ if (r == -1)
++ return -1;
++ return r + 2;
++ }
++
++ if (bufsize < 2)
++ return seterror(E2BIG);
++ if (cv->codepage == 1200) /* little endian */
++ {
++ buf[0] = (wbuf[0] & 0x00FF);
++ buf[1] = (wbuf[0] & 0xFF00) >> 8;
++ }
++ else if (cv->codepage == 1201) /* big endian */
++ {
++ buf[0] = (wbuf[0] & 0xFF00) >> 8;
++ buf[1] = (wbuf[0] & 0x00FF);
++ }
++ if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
++ {
++ if (bufsize < 4)
++ return seterror(E2BIG);
++ if (cv->codepage == 1200) /* little endian */
++ {
++ buf[2] = (wbuf[1] & 0x00FF);
++ buf[3] = (wbuf[1] & 0xFF00) >> 8;
++ }
++ else if (cv->codepage == 1201) /* big endian */
++ {
++ buf[2] = (wbuf[1] & 0xFF00) >> 8;
++ buf[3] = (wbuf[1] & 0x00FF);
++ }
++ return 4;
++ }
++ return 2;
++}
++
++static int
++utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
++{
++ int codepage = cv->codepage;
++ uint wc;
++
++ /* swap endian: 12000 <-> 12001 */
++ if (cv->mode & UNICODE_MODE_SWAPPED)
++ codepage ^= 1;
++
++ if (bufsize < 4)
++ return seterror(EINVAL);
++ if (codepage == 12000) /* little endian */
++ wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
++ else if (codepage == 12001) /* big endian */
++ wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
++
++ if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
++ {
++ cv->mode |= UNICODE_MODE_BOM_DONE;
++ if (wc == 0xFFFE0000)
++ {
++ cv->mode |= UNICODE_MODE_SWAPPED;
++ *wbufsize = 0;
++ return 4;
++ }
++ else if (wc == 0x0000FEFF)
++ {
++ *wbufsize = 0;
++ return 4;
++ }
++ }
++
++ if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
++ return seterror(EILSEQ);
++ ucs4_to_utf16(wc, wbuf, wbufsize);
++ return 4;
++}
++
++static int
++utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
++{
++ uint wc;
++
++ if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
++ {
++ int r;
++
++ cv->mode |= UNICODE_MODE_BOM_DONE;
++ if (bufsize < 4)
++ return seterror(E2BIG);
++ if (cv->codepage == 12000) /* little endian */
++ memcpy(buf, "\xFF\xFE\x00\x00", 4);
++ else if (cv->codepage == 12001) /* big endian */
++ memcpy(buf, "\x00\x00\xFE\xFF", 4);
++
++ r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
++ if (r == -1)
++ return -1;
++ return r + 4;
++ }
++
++ if (bufsize < 4)
++ return seterror(E2BIG);
++ wc = utf16_to_ucs4(wbuf);
++ if (cv->codepage == 12000) /* little endian */
++ {
++ buf[0] = wc & 0x000000FF;
++ buf[1] = (wc & 0x0000FF00) >> 8;
++ buf[2] = (wc & 0x00FF0000) >> 16;
++ buf[3] = (wc & 0xFF000000) >> 24;
++ }
++ else if (cv->codepage == 12001) /* big endian */
++ {
++ buf[0] = (wc & 0xFF000000) >> 24;
++ buf[1] = (wc & 0x00FF0000) >> 16;
++ buf[2] = (wc & 0x0000FF00) >> 8;
++ buf[3] = wc & 0x000000FF;
++ }
++ return 4;
++}
++
++/*
++ * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
++ * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
++ * 1 byte Kana)
++ * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
++ * Kana - SO/SI)
++ *
++ * MultiByteToWideChar() and WideCharToMultiByte() behave differently
++ * depending on Windows version. On XP, WideCharToMultiByte() doesn't
++ * terminate result sequence with ascii escape. But Vista does.
++ * Use MLang instead.
++ */
++
++#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
++#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
++#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
++
++#define ISO2022_SI 0
++#define ISO2022_SO 1
++
++/* shift in */
++static const char iso2022_SI_seq[] = "\x0F";
++/* shift out */
++static const char iso2022_SO_seq[] = "\x0E";
++
++typedef struct iso2022_esc_t iso2022_esc_t;
++struct iso2022_esc_t {
++ const char *esc;
++ int esc_len;
++ int len;
++ int cs;
++};
++
++#define ISO2022JP_CS_ASCII 0
++#define ISO2022JP_CS_JISX0201_ROMAN 1
++#define ISO2022JP_CS_JISX0201_KANA 2
++#define ISO2022JP_CS_JISX0208_1978 3
++#define ISO2022JP_CS_JISX0208_1983 4
++#define ISO2022JP_CS_JISX0212 5
++
++static iso2022_esc_t iso2022jp_esc[] = {
++ {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
++ {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
++ {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
++ {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
++ {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
++ {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
++ {NULL, 0, 0, 0}
++};
++
++static int
++iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
++{
++ iso2022_esc_t *iesc = iso2022jp_esc;
++ char tmp[MB_CHAR_MAX];
++ int insize;
++ HRESULT hr;
++ DWORD dummy = 0;
++ int len;
++ int esc_len;
++ int cs;
++ int shift;
++ int i;
++
++ if (buf[0] == 0x1B)
++ {
++ for (i = 0; iesc[i].esc != NULL; ++i)
++ {
++ esc_len = iesc[i].esc_len;
++ if (bufsize < esc_len)
++ {
++ if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
++ return seterror(EINVAL);
++ }
++ else
++ {
++ if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
++ {
++ cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
++ *wbufsize = 0;
++ return esc_len;
++ }
++ }
++ }
++ /* not supported escape sequence */
++ return seterror(EILSEQ);
++ }
++ else if (buf[0] == iso2022_SO_seq[0])
++ {
++ cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
++ *wbufsize = 0;
++ return 1;
++ }
++ else if (buf[0] == iso2022_SI_seq[0])
++ {
++ cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
++ *wbufsize = 0;
++ return 1;
++ }
++
++ cs = ISO2022_MODE_CS(cv->mode);
++ shift = ISO2022_MODE_SHIFT(cv->mode);
++
++ /* reset the mode for informal sequence */
++ if (buf[0] < 0x20)
++ {
++ cs = ISO2022JP_CS_ASCII;
++ shift = ISO2022_SI;
++ }
++
++ len = iesc[cs].len;
++ if (bufsize < len)
++ return seterror(EINVAL);
++ for (i = 0; i < len; ++i)
++ if (!(buf[i] < 0x80))
++ return seterror(EILSEQ);
++ esc_len = iesc[cs].esc_len;
++ memcpy(tmp, iesc[cs].esc, esc_len);
++ if (shift == ISO2022_SO)
++ {
++ memcpy(tmp + esc_len, iso2022_SO_seq, 1);
++ esc_len += 1;
++ }
++ memcpy(tmp + esc_len, buf, len);
++
++ if ((cv->codepage == 50220 || cv->codepage == 50221
++ || cv->codepage == 50222) && shift == ISO2022_SO)
++ {
++ /* XXX: shift-out cannot be used for mbtowc (both kernel and
++ * mlang) */
++ esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
++ memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
++ memcpy(tmp + esc_len, buf, len);
++ }
++
++ insize = len + esc_len;
++ hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
++ (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
++ if (hr != S_OK || insize != len + esc_len)
++ return seterror(EILSEQ);
++
++ /* Check for conversion error. Assuming defaultChar is 0x3F. */
++ /* ascii should be converted from ascii */
++ if (wbuf[0] == buf[0]
++ && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
++ return seterror(EILSEQ);
++
++ /* reset the mode for informal sequence */
++ if (cv->mode != ISO2022_MODE(cs, shift))
++ cv->mode = ISO2022_MODE(cs, shift);
++
++ return len;
++}
++
++static int
++iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
++{
++ iso2022_esc_t *iesc = iso2022jp_esc;
++ char tmp[MB_CHAR_MAX];
++ int tmpsize = MB_CHAR_MAX;
++ int insize = wbufsize;
++ HRESULT hr;
++ DWORD dummy = 0;
++ int len;
++ int esc_len;
++ int cs;
++ int shift;
++ int i;
++
++ /*
++ * MultiByte = [escape sequence] + character + [escape sequence]
++ *
++ * Whether trailing escape sequence is added depends on which API is
++ * used (kernel or MLang, and its version).
++ */
++ hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
++ (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
++ if (hr != S_OK || insize != wbufsize)
++ return seterror(EILSEQ);
++ else if (bufsize < tmpsize)
++ return seterror(E2BIG);
++
++ if (tmpsize == 1)
++ {
++ cs = ISO2022JP_CS_ASCII;
++ esc_len = 0;
++ }
++ else
++ {
++ for (i = 1; iesc[i].esc != NULL; ++i)
++ {
++ esc_len = iesc[i].esc_len;
++ if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
++ {
++ cs = iesc[i].cs;
++ break;
++ }
++ }
++ if (iesc[i].esc == NULL)
++ /* not supported escape sequence */
++ return seterror(EILSEQ);
++ }
++
++ shift = ISO2022_SI;
++ if (tmp[esc_len] == iso2022_SO_seq[0])
++ {
++ shift = ISO2022_SO;
++ esc_len += 1;
++ }
++
++ len = iesc[cs].len;
++
++ /* Check for converting error. Assuming defaultChar is 0x3F. */
++ /* ascii should be converted from ascii */
++ if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
++ return seterror(EILSEQ);
++ else if (tmpsize < esc_len + len)
++ return seterror(EILSEQ);
++
++ if (cv->mode == ISO2022_MODE(cs, shift))
++ {
++ /* remove escape sequence */
++ if (esc_len != 0)
++ memmove(tmp, tmp + esc_len, len);
++ esc_len = 0;
++ }
++ else
++ {
++ if (cs == ISO2022JP_CS_ASCII)
++ {
++ esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
++ memmove(tmp + esc_len, tmp, len);
++ memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
++ }
++ if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
++ {
++ /* shift-in before changing to other mode */
++ memmove(tmp + 1, tmp, len + esc_len);
++ memcpy(tmp, iso2022_SI_seq, 1);
++ esc_len += 1;
++ }
++ }
++
++ if (bufsize < len + esc_len)
++ return seterror(E2BIG);
++ memcpy(buf, tmp, len + esc_len);
++ cv->mode = ISO2022_MODE(cs, shift);
++ return len + esc_len;
++}
++
++static int
++iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
++{
++ iso2022_esc_t *iesc = iso2022jp_esc;
++ int esc_len;
++
++ if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
++ {
++ esc_len = 0;
++ if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
++ esc_len += 1;
++ if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
++ esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
++ if (bufsize < esc_len)
++ return seterror(E2BIG);
++
++ esc_len = 0;
++ if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
++ {
++ memcpy(buf, iso2022_SI_seq, 1);
++ esc_len += 1;
++ }
++ if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
++ {
++ memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
++ iesc[ISO2022JP_CS_ASCII].esc_len);
++ esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
++ }
++ return esc_len;
++ }
++ return 0;
++}
++
++#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
++BOOL WINAPI
++DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
++{
++ switch( fdwReason )
++ {
++ case DLL_PROCESS_ATTACH:
++ hwiniconv = (HMODULE)hinstDLL;
++ break;
++ case DLL_THREAD_ATTACH:
++ case DLL_THREAD_DETACH:
++ case DLL_PROCESS_DETACH:
++ break;
++ }
++ return TRUE;
++}
++#endif
++
++#if defined(MAKE_EXE)
++#include <stdio.h>
++#include <fcntl.h>
++#include <io.h>
++int
++main(int argc, char **argv)
++{
++ char *fromcode = NULL;
++ char *tocode = NULL;
++ int i;
++ char inbuf[BUFSIZ];
++ char outbuf[BUFSIZ];
++ char *pin;
++ char *pout;
++ size_t inbytesleft;
++ size_t outbytesleft;
++ size_t rest = 0;
++ iconv_t cd;
++ size_t r;
++ FILE *in = stdin;
++ FILE *out = stdout;
++ int ignore = 0;
++ char *p;
++
++ _setmode(_fileno(stdin), _O_BINARY);
++ _setmode(_fileno(stdout), _O_BINARY);
++
++ for (i = 1; i < argc; ++i)
++ {
++ if (strcmp(argv[i], "-l") == 0)
++ {
++ for (i = 0; codepage_alias[i].name != NULL; ++i)
++ printf("%s\n", codepage_alias[i].name);
++ return 0;
++ }
++
++ if (strcmp(argv[i], "-f") == 0)
++ fromcode = argv[++i];
++ else if (strcmp(argv[i], "-t") == 0)
++ tocode = argv[++i];
++ else if (strcmp(argv[i], "-c") == 0)
++ ignore = 1;
++ else if (strcmp(argv[i], "--output") == 0)
++ {
++ out = fopen(argv[++i], "wb");
++ if(out == NULL)
++ {
++ fprintf(stderr, "cannot open %s\n", argv[i]);
++ return 1;
++ }
++ }
++ else
++ {
++ in = fopen(argv[i], "rb");
++ if (in == NULL)
++ {
++ fprintf(stderr, "cannot open %s\n", argv[i]);
++ return 1;
++ }
++ break;
++ }
++ }
++
++ if (fromcode == NULL || tocode == NULL)
++ {
++ printf("usage: %s [-c] -f from-enc -t to-enc [file]\n", argv[0]);
++ return 0;
++ }
++
++ if (ignore)
++ {
++ p = tocode;
++ tocode = (char *)malloc(strlen(p) + strlen("//IGNORE") + 1);
++ if (tocode == NULL)
++ {
++ perror("fatal error");
++ return 1;
++ }
++ strcpy(tocode, p);
++ strcat(tocode, "//IGNORE");
++ }
++
++ cd = iconv_open(tocode, fromcode);
++ if (cd == (iconv_t)(-1))
++ {
++ perror("iconv_open error");
++ return 1;
++ }
++
++ while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
++ || rest != 0)
++ {
++ inbytesleft += rest;
++ pin = inbuf;
++ pout = outbuf;
++ outbytesleft = sizeof(outbuf);
++ r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
++ fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
++ if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))
++ {
++ perror("conversion error");
++ return 1;
++ }
++ memmove(inbuf, pin, inbytesleft);
++ rest = inbytesleft;
++ }
++ pout = outbuf;
++ outbytesleft = sizeof(outbuf);
++ r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
++ fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
++ if (r == (size_t)(-1))
++ {
++ perror("conversion error");
++ return 1;
++ }
++
++ iconv_close(cd);
++
++ return 0;
++}
++#endif
++