summaryrefslogtreecommitdiff
path: root/libmysql
diff options
context:
space:
mode:
Diffstat (limited to 'libmysql')
-rw-r--r--libmysql/.cvsignore10
-rw-r--r--[-rwxr-xr-x]libmysql/CMakeLists.txt336
-rw-r--r--libmysql/Makefile.am116
-rw-r--r--libmysql/Makefile.shared118
-rw-r--r--libmysql/acinclude.m491
-rw-r--r--libmysql/authentication_win/CMakeLists.txt33
-rw-r--r--libmysql/authentication_win/common.cc510
-rw-r--r--libmysql/authentication_win/common.h324
-rw-r--r--libmysql/authentication_win/handshake.cc289
-rw-r--r--libmysql/authentication_win/handshake.h181
-rw-r--r--libmysql/authentication_win/handshake_client.cc393
-rw-r--r--libmysql/authentication_win/log_client.cc65
-rw-r--r--libmysql/authentication_win/plugin_client.cc68
-rw-r--r--libmysql/client_settings.h43
-rw-r--r--libmysql/dll.c124
-rw-r--r--libmysql/errmsg.c146
-rw-r--r--libmysql/get_password.c18
-rw-r--r--libmysql/libmysql.c816
-rw-r--r--libmysql/libmysql.def47
-rw-r--r--libmysql/manager.c269
20 files changed, 2331 insertions, 1666 deletions
diff --git a/libmysql/.cvsignore b/libmysql/.cvsignore
deleted file mode 100644
index a58235fee47..00000000000
--- a/libmysql/.cvsignore
+++ /dev/null
@@ -1,10 +0,0 @@
-*.lo
-.deps
-.libs
-Makefile
-Makefile.in
-conf_to_src
-config.status
-configure
-ctype_extra_sources.c
-libmysqlclient.la
diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt
index b61215a9678..1d7a134aefa 100755..100644
--- a/libmysql/CMakeLists.txt
+++ b/libmysql/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2012, Oracle and/or its affiliates. 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
@@ -11,121 +11,227 @@
#
# 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("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+INCLUDE_DIRECTORIES(
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/libmysql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/strings
+ ${SSL_INCLUDE_DIRS}
+ ${SSL_INTERNAL_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIR})
+ADD_DEFINITIONS(${SSL_DEFINES})
+
+SET(CLIENT_API_FUNCTIONS
+get_tty_password
+handle_options
+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_embedded
+mysql_server_init
+mysql_server_end
+mysql_set_character_set
+mysql_get_character_set_info
+mysql_stmt_next_result
+
+CACHE INTERNAL "Functions exported by client API"
+
+)
+
+SET(CLIENT_SOURCES
+ get_password.c
+ libmysql.c
+ errmsg.c
+ ../sql-common/client.c
+ ../sql-common/my_time.c
+ ../sql-common/client_plugin.c
+ ../sql/net_serv.cc
+ ../sql-common/pack.c
+ ../sql/password.c
+)
+ADD_CONVENIENCE_LIBRARY(clientlib ${CLIENT_SOURCES})
+DTRACE_INSTRUMENT(clientlib)
+ADD_DEPENDENCIES(clientlib GenError)
+
+SET(LIBS clientlib dbug strings vio mysys ${ZLIB_LIBRARY} ${SSL_LIBRARIES} ${LIBDL})
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-
-# Note that we don't link with the libraries "strings" or "mysys"
-# here, instead we recompile the files needed and include them
-# directly. This means we don't have to worry here about if these
-# libraries are compiled defining USE_TLS or not. Not that it *should*
-# have been a problem anyway, they don't use thread local storage.
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/libmysql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/strings)
-
-# We include the source file listing instead of referencing the
-# libraries. At least with CMake 2.4 and Visual Studio 2005 a static
-# library created from other static libraries would not be complete,
-# i.e. the libraries listed in TARGET_LINK_LIBRARIES() were just
-# ignored.
-
-
-# Include and add the directory path
-SET(SOURCE_SUBLIBS TRUE)
-SET(LIB_SOURCES "")
-
-INCLUDE(${CMAKE_SOURCE_DIR}/zlib/CMakeLists.txt)
-FOREACH(rpath ${ZLIB_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../zlib/${rpath})
-ENDFOREACH(rpath)
-
-# FIXME only needed if build type is "Debug", but CMAKE_BUILD_TYPE is
-# not set during configure time.
-INCLUDE(${CMAKE_SOURCE_DIR}/dbug/CMakeLists.txt)
-FOREACH(rpath ${DBUG_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../dbug/${rpath})
-ENDFOREACH(rpath)
-
-INCLUDE(${CMAKE_SOURCE_DIR}/extra/yassl/taocrypt/CMakeLists.txt)
-FOREACH(rpath ${TAOCRYPT_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../extra/yassl/taocrypt/${rpath})
-ENDFOREACH(rpath)
-
-INCLUDE(${CMAKE_SOURCE_DIR}/extra/yassl/CMakeLists.txt)
-FOREACH(rpath ${YASSL_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../extra/yassl/${rpath})
-ENDFOREACH(rpath)
-
-SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
- ../strings/bmove_upp.c ../mysys/charset-def.c ../mysys/charset.c
- ../sql-common/client.c ../strings/ctype-big5.c ../strings/ctype-bin.c
- ../strings/ctype-cp932.c ../strings/ctype-czech.c ../strings/ctype-euc_kr.c
- ../strings/ctype-eucjpms.c ../strings/ctype-extra.c ../strings/ctype-gb2312.c
- ../strings/ctype-gbk.c ../strings/ctype-latin1.c ../strings/ctype-mb.c
- ../strings/ctype-simple.c ../strings/ctype-sjis.c ../strings/ctype-tis620.c
- ../strings/ctype-uca.c ../strings/ctype-ucs2.c ../strings/ctype-ujis.c
- ../strings/ctype-utf8.c ../strings/ctype-win1250ch.c ../strings/ctype.c
- ../mysys/default.c errmsg.c ../mysys/errors.c
- ../mysys/hash.c ../mysys/my_sleep.c ../mysys/default_modify.c
- get_password.c ../strings/int2str.c ../strings/is_prefix.c
- libmysql.c ../mysys/list.c ../strings/llstr.c
- ../strings/longlong2str.c manager.c ../mysys/mf_arr_appstr.c ../mysys/mf_cache.c
- ../mysys/mf_dirname.c ../mysys/mf_fn_ext.c ../mysys/mf_format.c
- ../mysys/mf_iocache.c ../mysys/mf_iocache2.c ../mysys/mf_loadpath.c
- ../mysys/mf_pack.c ../mysys/mf_path.c ../mysys/mf_tempfile.c ../mysys/mf_unixpath.c
- ../mysys/mf_wcomp.c ../mysys/mulalloc.c ../mysys/my_access.c ../mysys/my_alloc.c
- ../mysys/my_chsize.c ../mysys/my_compress.c ../mysys/my_create.c
- ../mysys/my_delete.c ../mysys/my_div.c ../mysys/my_error.c ../mysys/my_file.c
- ../mysys/my_fopen.c ../mysys/my_fstream.c
- ../mysys/my_getopt.c ../mysys/my_getwd.c ../mysys/my_init.c ../mysys/my_lib.c
- ../mysys/my_malloc.c ../mysys/my_messnc.c ../mysys/my_net.c ../mysys/my_once.c
- ../mysys/my_open.c ../mysys/my_pread.c ../mysys/my_pthread.c ../mysys/my_read.c
- ../mysys/my_realloc.c ../mysys/my_rename.c ../mysys/my_seek.c
- ../mysys/my_static.c ../strings/my_strtoll10.c ../mysys/my_symlink.c
- ../mysys/my_symlink2.c ../mysys/my_thr_init.c ../sql-common/my_time.c
- ../strings/my_vsnprintf.c ../mysys/my_wincond.c ../mysys/my_winthread.c
- ../mysys/my_write.c ../sql/net_serv.cc ../sql-common/pack.c ../sql/password.c
- ../mysys/safemalloc.c ../mysys/sha1.c ../strings/str2int.c
- ../strings/str_alloc.c ../strings/strcend.c ../strings/strcont.c ../strings/strend.c
- ../strings/strfill.c ../mysys/string.c ../strings/strinstr.c ../strings/strmake.c
- ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c
- ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c
- ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c
- ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c
- ../mysys/my_getsystime.c ../mysys/my_sync.c ${LIB_SOURCES})
-
-# Need to set USE_TLS for building the DLL, since __declspec(thread)
-# approach to thread local storage does not work properly in DLLs.
#
-# The static library might be used to form another DLL, as is the case
-# with the ODBC driver, so it has to be compiled with USE_TLS as well.
+# On Windows platform client library includes the client-side
+# Windows Native Authentication plugin.
#
-# We create a third library without USE_TLS for internal use. We can't
-# be sure that some client application part of this build doesn't go
-# beond the documented API, and try access the Thread Local Storage.
-# The "_notls" means no Tls*() functions used, i.e. "static" TLS.
-
-ADD_LIBRARY(mysqlclient STATIC ${CLIENT_SOURCES})
-ADD_DEPENDENCIES(mysqlclient GenError)
-TARGET_LINK_LIBRARIES(mysqlclient)
-
-ADD_LIBRARY(mysqlclient_notls STATIC ${CLIENT_SOURCES})
-ADD_DEPENDENCIES(mysqlclient_notls GenError)
-TARGET_LINK_LIBRARIES(mysqlclient_notls)
-
-ADD_LIBRARY(libmysql SHARED ${CLIENT_SOURCES} dll.c libmysql.def)
IF(WIN32)
- SET_TARGET_PROPERTIES(libmysql mysqlclient PROPERTIES COMPILE_FLAGS "-DUSE_TLS")
-ENDIF(WIN32)
-ADD_DEPENDENCIES(libmysql GenError)
-TARGET_LINK_LIBRARIES(libmysql wsock32)
-
-IF(EMBED_MANIFESTS)
- MYSQL_EMBED_MANIFEST("myTest" "asInvoker")
-ENDIF(EMBED_MANIFESTS)
+ ADD_DEFINITIONS(-DAUTHENTICATION_WIN)
+ ADD_SUBDIRECTORY(authentication_win)
+ LIST(APPEND LIBS auth_win_client)
+ENDIF()
+
+# Merge several convenience libraries into one big mysqlclient
+# and link them together into shared library.
+MERGE_LIBRARIES(mysqlclient STATIC ${LIBS} COMPONENT Development)
+
+# Visual Studio users need debug static library for debug projects
+IF(MSVC)
+ INSTALL_DEBUG_TARGET(mysqlclient DESTINATION ${INSTALL_LIBDIR}/debug)
+ENDIF()
+
+IF(UNIX)
+ MACRO(GET_VERSIONED_LIBNAME LIBNAME EXTENSION VERSION OUTNAME)
+ SET(DOT_VERSION ".${VERSION}")
+ IF(DOT_VERSION STREQUAL ".")
+ SET(DOT_VERSION "")
+ ENDIF()
+ IF(APPLE)
+ SET(${OUTNAME} ${LIBNAME}${DOT_VERSION}${EXTENSION})
+ ELSE()
+ SET(${OUTNAME} ${LIBNAME}${EXTENSION}${DOT_VERSION})
+ ENDIF()
+ ENDMACRO()
+ INSTALL_SYMLINK(${CMAKE_STATIC_LIBRARY_PREFIX}mysqlclient_r.a mysqlclient ${INSTALL_LIBDIR} Development)
+ENDIF()
+
+IF(NOT DISABLE_SHARED)
+ MERGE_LIBRARIES(libmysql SHARED ${LIBS} EXPORTS ${CLIENT_API_FUNCTIONS} COMPONENT SharedLibraries)
+ IF(UNIX)
+ # libtool compatability
+ IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR APPLE)
+ SET(OS_SHARED_LIB_VERSION "${SHARED_LIB_MAJOR_VERSION}")
+ ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP-UX")
+ SET(OS_SHARED_LIB_VERSION "${SHARED_LIB_MAJOR_VERSION}.0")
+ ELSE()
+ SET(OS_SHARED_LIB_VERSION "${SHARED_LIB_MAJOR_VERSION}.0.0")
+ ENDIF()
+ # Name of shared library is mysqlclient on Unix
+ SET_TARGET_PROPERTIES(libmysql PROPERTIES
+ OUTPUT_NAME mysqlclient
+ VERSION "${OS_SHARED_LIB_VERSION}"
+ SOVERSION "${SHARED_LIB_MAJOR_VERSION}")
+ IF(LINK_FLAG_NO_UNDEFINED)
+ GET_TARGET_PROPERTY(libmysql_link_flags libmysql LINK_FLAGS)
+ IF(NOT libmysql_link_flag)
+ SET(libmysql_link_flags)
+ ENDIF()
+ SET_TARGET_PROPERTIES(libmysql PROPERTIES LINK_FLAGS
+ "${libmysql_link_flags} ${LINK_FLAG_NO_UNDEFINED}")
+ ENDIF()
+ # clean direct output needs to be set several targets have the same name
+ #(mysqlclient in this case)
+ SET_TARGET_PROPERTIES(mysqlclient PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ SET_TARGET_PROPERTIES(libmysql PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+
+ # Install links to libmysqlclient.so (client_r)
+ GET_VERSIONED_LIBNAME(
+ "${CMAKE_SHARED_LIBRARY_PREFIX}mysqlclient_r"
+ "${CMAKE_SHARED_LIBRARY_SUFFIX}"
+ ""
+ linkname)
+ INSTALL_SYMLINK(${linkname} libmysql ${INSTALL_LIBDIR} SharedLibraries)
+ SET(OS_SHARED_LIB_SYMLINKS "${SHARED_LIB_MAJOR_VERSION}" "${OS_SHARED_LIB_VERSION}")
+ LIST(REMOVE_DUPLICATES OS_SHARED_LIB_SYMLINKS)
+ FOREACH(ver ${OS_SHARED_LIB_SYMLINKS})
+ GET_VERSIONED_LIBNAME(
+ "${CMAKE_SHARED_LIBRARY_PREFIX}mysqlclient_r"
+ "${CMAKE_SHARED_LIBRARY_SUFFIX}"
+ "${ver}"
+ linkname)
+ INSTALL_SYMLINK(${linkname} libmysql ${INSTALL_LIBDIR} SharedLibraries)
+ ENDFOREACH()
+ ENDIF()
+ENDIF()
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
deleted file mode 100644
index 2453547cac8..00000000000
--- a/libmysql/Makefile.am
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright (c) 2000-2007 MySQL AB, 2009 Sun Microsystems, Inc.
-# Use is subject to license terms.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of version 2 GNU General Public License as
-# published by the Free Software Foundation.
-#
-# There are special exceptions to the terms and conditions of the GPL as it
-# is applied to this software.
-#
-# 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., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301, USA
-#
-# This file is public domain and comes with NO WARRANTY of any kind
-
-target = libmysqlclient.la
-target_defs = -DMYSQL_CLIENT_NO_THREADS -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
-LIBS = @CLIENT_LIBS@
-INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
- $(openssl_includes) @ZLIB_INCLUDES@
-
-include $(srcdir)/Makefile.shared
-
-libmysqlclient_la_SOURCES = $(target_sources)
-libmysqlclient_la_LIBADD = $(target_libadd) $(yassl_las)
-libmysqlclient_la_LDFLAGS = $(target_ldflags)
-EXTRA_DIST = Makefile.shared libmysql.def dll.c CMakeLists.txt
-noinst_HEADERS = client_settings.h
-
-link_sources:
- set -x; \
- ss=`echo $(mystringsobjects) | sed "s;\.lo;.c;g"`; \
- ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \
- ms=`echo $(mysysobjects) | sed "s;\.lo;.c;g"`; \
- vs=`echo $(vio_objects) | sed "s;\.lo;.c;g"`; \
- scs=`echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"`; \
- for f in $$ss; do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \
- done; \
- for f in $$vs $(vioheaders); do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/vio/$$f $$f; \
- done; \
- for f in $$scs; do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/sql-common/$$f $$f; \
- done; \
- for f in $(mystringsextra); do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \
- done; \
- for f in $$ds; do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/dbug/$$f $$f; \
- done; \
- for f in $$ms $(mysysheaders); do \
- rm -f $$f; \
- @LN_CP_F@ $(top_srcdir)/mysys/$$f $$f; \
- done; \
- rm -f net.c; \
- @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net.c ; \
- rm -f password.c; \
- @LN_CP_F@ $(top_srcdir)/sql/password.c password.c
- echo timestamp > link_sources
-
-# This part requires GNUmake
-#
-# This makes a distribution file with only the files needed to compile
-# a minimal MySQL client library
-#
-# For a really minimal distribution (without debugging code) we could
-# keep only the stubs for safemalloc.c and debug.c
-#
-# A list of needed headers collected from the deps information 000213
-nh = my_global.h config-win32.h dbug.h errmsg.h \
- m_ctype.h m_string.h \
- my_alarm.h my_config.h my_dir.h my_list.h my_net.h my_sys.h \
- mysql.h mysql_com.h mysql_version.h mysqld_error.h \
- mysys_err.h my_pthread.h thr_alarm.h violite.h hash.h \
- sql_common.h ../libmysql/client_settings.h
-# Get a list of the needed objects
-lobjs = $(mysysobjects1) $(dbugobjects) $(mystringsobjects) $(sqlobjects)
-
-do-lib-dist:
- dir=libmysql-$(MYSQL_NO_DASH_VERSION); \
- srcs1=`echo $(lobjs) | sed "s;\.lo;.c;g"`; \
- srcs2=$(target_sources); \
- srcs="$$srcs1 $$srcs2"; \
- objs1=`echo $(lobjs) | sed "s;\.lo;.o;g"`; \
- objs2=`echo $(target_sources) | sed "s;\.c;.o;g"`; \
- objs="$$objs1 $$objs2"; \
- rm -rf $$dir; \
- mkdir $$dir; \
- $(INSTALL_DATA) $$srcs $(mysysheaders) $$dir; \
- for i in $(nh); do $(INSTALL_DATA) ../include/$$i $$dir; done; \
- echo "# A very minimal Makefile to compile" > $$dir/Makefile; \
- echo "# the minimized libmysql library" >> $$dir/Makefile; \
- echo "# This file is autogenerated from Makefile.am" >> $$dir/Makefile; \
- echo 'CFLAGS= -I. -DMYSQL_CLIENT_NO_THREADS' >>$$dir/Makefile; \
- echo "obj=$$objs" >>$$dir/Makefile; \
- echo 'all: libmysql.a' >>$$dir/Makefile; \
- echo 'libmysql.a: $$(obj)' >>$$dir/Makefile; \
- echo ' $$(AR) r $$@ $$?' >>$$dir/Makefile; \
- gtar cvzf $$dir.tar.gz $$dir; \
- cd $$dir; gmake
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared
deleted file mode 100644
index 8934c19b5aa..00000000000
--- a/libmysql/Makefile.shared
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of version 2 GNU General Public License as
-# published by the Free Software Foundation.
-#
-# There are special exceptions to the terms and conditions of the GPL as it
-# is applied to this software.
-#
-# 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., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301, USA
-#
-# This file is public domain and comes with NO WARRANTY of any kind
-
-MYSQLDATAdir = $(localstatedir)
-MYSQLSHAREdir = $(pkgdatadir)
-MYSQLBASEdir= $(prefix)
-## We'll use CLIENT_EXTRA_LDFLAGS for threaded and non-threaded
-## until someone complains that they need separate options.
-LDADD = @CLIENT_EXTRA_LDFLAGS@ $(target)
-pkglib_LTLIBRARIES = $(target)
-
-noinst_PROGRAMS = conf_to_src
-
-
-target_sources = libmysql.c password.c manager.c \
- get_password.c errmsg.c
-
-mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
- strmake.lo strend.lo strtod.lo \
- strnlen.lo strfill.lo is_prefix.lo \
- int2str.lo str2int.lo strinstr.lo strcont.lo \
- strcend.lo ctype-latin1.lo \
- bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
- strtoull.lo strtoll.lo llstr.lo my_vsnprintf.lo \
- ctype.lo ctype-simple.lo ctype-bin.lo ctype-mb.lo \
- ctype-big5.lo ctype-czech.lo ctype-cp932.lo ctype-eucjpms.lo ctype-euc_kr.lo \
- ctype-win1250ch.lo ctype-utf8.lo ctype-extra.lo \
- ctype-ucs2.lo ctype-gb2312.lo ctype-gbk.lo \
- ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo \
- ctype-uca.lo xml.lo my_strtoll10.lo str_alloc.lo
-
-mystringsextra= strto.c
-dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
-mysysheaders = mysys_priv.h my_static.h
-vioheaders = vio_priv.h
-mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
- my_create.lo my_delete.lo mf_tempfile.lo my_open.lo \
- my_file.lo my_read.lo my_write.lo errors.lo \
- my_error.lo my_getwd.lo my_div.lo \
- mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\
- mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \
- mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.lo \
- my_symlink.lo my_fstream.lo mf_arr_appstr.lo \
- mf_loadpath.lo my_pthread.lo my_thr_init.lo \
- thr_mutex.lo mulalloc.lo string.lo \
- default.lo default_modify.lo \
- my_compress.lo array.lo my_once.lo list.lo my_net.lo \
- charset.lo charset-def.lo hash.lo mf_iocache.lo \
- mf_iocache2.lo my_seek.lo my_sleep.lo \
- my_pread.lo mf_cache.lo md5.lo sha1.lo \
- my_getopt.lo \
- my_rename.lo my_chsize.lo my_sync.lo my_getsystime.lo
-sqlobjects = net.lo
-sql_cmn_objects = pack.lo client.lo my_time.lo
-
-# Not needed in the minimum library
-mysysobjects2 = my_lib.lo mf_qsort.lo
-mysysobjects = $(mysysobjects1) $(mysysobjects2)
-target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \
- $(sql_cmn_objects) $(vio_objects) $(sqlobjects)
-target_ldflags = -version-info @SHARED_LIB_VERSION@ @LD_VERSION_SCRIPT@
-vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo
-
-BUILT_SOURCES = link_sources
-
-CLEANFILES = $(target_libadd) $(SHLIBOBJS) \
- $(target) $(BUILT_SOURCES)
-DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
- -DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
- -DDEFAULT_HOME_ENV=MYSQL_HOME \
- -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \
- -DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \
- -DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs)
-
-if HAVE_YASSL
-yassl_las = $(top_builddir)/extra/yassl/src/libyassl.la \
- $(top_builddir)/extra/yassl/taocrypt/src/libtaocrypt.la
-endif
-
-# The automatic dependencies miss this
-#bmove_upp.lo: $(LTCHARSET_OBJS)
-
-clean-local:
- rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \
- `echo $(dbugobjects) | sed "s;\.lo;.c;g"` \
- `echo $(mysysobjects) | sed "s;\.lo;.c;g"` \
- `echo $(vio_objects) | sed "s;\.lo;.c;g"` \
- `echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"` \
- $(CHARSET_SRCS) $(CHARSET_OBJS) \
- $(mystringsextra) $(mysysheaders) $(vioheaders) \
- net.c
-
-conf_to_src_SOURCES = conf_to_src.c
-conf_to_src_LDADD=
-#force static linking of conf_to_src - essential when linking against
-#custom installation of libc
-conf_to_src_LDFLAGS=@NOINST_LDFLAGS@
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/libmysql/acinclude.m4 b/libmysql/acinclude.m4
deleted file mode 100644
index c0211f3759f..00000000000
--- a/libmysql/acinclude.m4
+++ /dev/null
@@ -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 --git a/libmysql/authentication_win/CMakeLists.txt b/libmysql/authentication_win/CMakeLists.txt
new file mode 100644
index 00000000000..80cd14780e6
--- /dev/null
+++ b/libmysql/authentication_win/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. 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
+
+#
+# Configuration for building Windows Authentication Plugin (client-side)
+#
+
+ADD_DEFINITIONS(-DSECURITY_WIN32)
+ADD_DEFINITIONS(-DDEBUG_ERRROR_LOG) # no error logging in production builds
+ADD_DEFINITIONS(-DWINAUTH_USE_DBUG_LIB) # it is OK to use dbug library in statically
+ # linked plugin
+
+SET(HEADERS common.h handshake.h)
+SET(PLUGIN_SOURCES plugin_client.cc handshake_client.cc log_client.cc common.cc handshake.cc)
+
+ADD_CONVENIENCE_LIBRARY(auth_win_client ${PLUGIN_SOURCES} ${HEADERS})
+TARGET_LINK_LIBRARIES(auth_win_client Secur32)
+
+# In IDE, group headers in a separate folder.
+
+SOURCE_GROUP(Headers REGULAR_EXPRESSION ".*h$")
diff --git a/libmysql/authentication_win/common.cc b/libmysql/authentication_win/common.cc
new file mode 100644
index 00000000000..9544e7734f5
--- /dev/null
+++ b/libmysql/authentication_win/common.cc
@@ -0,0 +1,510 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "common.h"
+#include <sddl.h> // for ConvertSidToStringSid()
+#include <secext.h> // for GetUserNameEx()
+
+
+template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
+
+/**
+ Option indicating desired level of logging. Values:
+
+ 0 - no logging
+ 1 - log only error messages
+ 2 - additionally log warnings
+ 3 - additionally log info notes
+ 4 - also log debug messages
+
+ Value of this option should be taken into account in the
+ implementation of error_log_vprint() function (see
+ log_client.cc).
+
+ Note: No error or debug messages are logged in production code
+ (see logging macros in common.h).
+*/
+int opt_auth_win_log_level= 2;
+
+
+/** Connection class **************************************************/
+
+/**
+ Create connection out of an active MYSQL_PLUGIN_VIO object.
+
+ @param[in] vio pointer to a @c MYSQL_PLUGIN_VIO object used for
+ connection - it can not be NULL
+*/
+
+Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
+{
+ DBUG_ASSERT(vio);
+}
+
+
+/**
+ Write data to the connection.
+
+ @param[in] blob data to be written
+
+ @return 0 on success, VIO error code on failure.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+int Connection::write(const Blob &blob)
+{
+ m_error= m_vio->write_packet(m_vio, blob.ptr(), blob.len());
+
+#ifndef DBUG_OFF
+ if (m_error)
+ DBUG_PRINT("error", ("vio write error %d", m_error));
+#endif
+
+ return m_error;
+}
+
+
+/**
+ Read data from connection.
+
+ @return A Blob containing read packet or null Blob in case of error.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+Blob Connection::read()
+{
+ unsigned char *ptr;
+ int len= m_vio->read_packet(m_vio, &ptr);
+
+ if (len < 0)
+ {
+ m_error= true;
+ return Blob();
+ }
+
+ return Blob(ptr, len);
+}
+
+
+/** Sid class *****************************************************/
+
+
+/**
+ Create Sid object corresponding to a given account name.
+
+ @param[in] account_name name of a Windows account
+
+ The account name can be in any form accepted by @c LookupAccountName()
+ function.
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(const wchar_t *account_name): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD sid_size= 0, domain_size= 0;
+ bool success;
+
+ // Determine required buffer sizes
+
+ success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
+ NULL, &domain_size, &m_type);
+
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "LookupAccountName() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ // Query for SID (domain is ignored)
+
+ wchar_t *domain= new wchar_t[domain_size];
+ m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof(TOKEN_USER)];
+ m_data->User.Sid= (BYTE*)m_data + sizeof(TOKEN_USER);
+
+ success= LookupAccountNameW(NULL, account_name,
+ m_data->User.Sid, &sid_size,
+ domain, &domain_size,
+ &m_type);
+
+ if (!success || !is_valid())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID of '%S', "
+ "LookupAccountName() failed with error %X (%s)",
+ account_name, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+ goto fail;
+ }
+
+ goto end;
+
+fail:
+ if (m_data)
+ delete [] m_data;
+ m_data= NULL;
+
+end:
+ if (domain)
+ delete [] domain;
+}
+
+
+/**
+ Create Sid object corresponding to a given security token.
+
+ @param[in] token security token of a Windows account
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(HANDLE token): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD req_size= 0;
+ bool success;
+
+ // Determine required buffer size
+
+ success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ m_data= (TOKEN_USER*) new BYTE[req_size];
+ success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
+
+ if (!success || !is_valid())
+ {
+ delete [] m_data;
+ m_data= NULL;
+#ifndef DBUG_OFF
+ if (!success)
+ {
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not read SID from security token, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+ }
+#endif
+ }
+}
+
+
+Sid::~Sid()
+{
+ if (m_data)
+ delete [] m_data;
+#ifndef DBUG_OFF
+ if (m_as_string)
+ LocalFree(m_as_string);
+#endif
+}
+
+/// Check if Sid object is valid.
+bool Sid::is_valid(void) const
+{
+ return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Produces string representation of the SID.
+
+ @return String representation of the SID or NULL in case of errors.
+
+ @note Memory allocated for the string is automatically freed in Sid's
+ destructor.
+*/
+
+const char* Sid::as_string()
+{
+ if (!m_data)
+ return NULL;
+
+ if (!m_as_string)
+ {
+ bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
+
+ if (!success)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not get textual representation of a SID, "
+ "ConvertSidToStringSid() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ m_as_string= NULL;
+ return NULL;
+ }
+ }
+
+ return m_as_string;
+}
+
+#endif
+
+
+bool Sid::operator ==(const Sid &other)
+{
+ if (!is_valid() || !other.is_valid())
+ return false;
+
+ return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
+}
+
+
+/** Generating User Principal Name *************************/
+
+/**
+ Call Windows API functions to get UPN of the current user and store it
+ in internal buffer.
+*/
+
+UPN::UPN(): m_buf(NULL)
+{
+ wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
+
+ // First we try to use GetUserNameEx.
+
+ m_len= sizeof(buf1)/sizeof(wchar_t);
+
+ if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
+ {
+ if (GetLastError())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("note", ("When determining UPN"
+ ", GetUserNameEx() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ if (ERROR_MORE_DATA == GetLastError())
+ ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
+ " need %ul characters but have %ul",
+ m_len, sizeof(buf1)/sizeof(WCHAR)));
+ }
+
+ m_len= 0; // m_len == 0 indicates invalid UPN
+ return;
+ }
+
+ /*
+ UPN is stored in buf1 in wide-char format - convert it to utf8
+ for sending over network.
+ */
+
+ m_buf= wchar_to_utf8(buf1, &m_len);
+
+ if(!m_buf)
+ ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
+
+ // Note: possible error would be indicated by the fact that m_buf is NULL.
+ return;
+}
+
+
+UPN::~UPN()
+{
+ if (m_buf)
+ free(m_buf);
+}
+
+
+/**
+ Convert a wide-char string to utf8 representation.
+
+ @param[in] string null-terminated wide-char string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in bytes, excluding terminating
+ null character) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing utf8 representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+char* wchar_to_utf8(const wchar_t *string, size_t *len)
+{
+ char *buf= NULL;
+ size_t str_len= len && *len ? *len : wcslen(string);
+
+ /*
+ A conversion from utf8 to wchar_t will never take more than 3 bytes per
+ character, so a buffer of length 3 * str_len schould be sufficient.
+ We check that assumption with an assertion later.
+ */
+
+ size_t buf_len= 3 * str_len;
+
+ buf= (char*)malloc(buf_len + 1);
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
+ string));
+ return NULL;
+ }
+
+ int res= WideCharToMultiByte(CP_UTF8, // convert to UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ str_len, // its length
+ buf, buf_len, // output buffer and its size
+ NULL, NULL); // default character (not used)
+
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // res is 0 which indicates error
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert string '%S' to utf8"
+ ", WideCharToMultiByte() failed with error %X (%s)",
+ string, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/**
+ Convert an utf8 string to a wide-char string.
+
+ @param[in] string null-terminated utf8 string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in chars) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing wide-char representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+wchar_t* utf8_to_wchar(const char *string, size_t *len)
+{
+ size_t buf_len;
+
+ /*
+ Note: length (in bytes) of an utf8 string is always bigger than the
+ number of characters in this string. Hence a buffer of size len will
+ be sufficient. We add 1 for the terminating null character.
+ */
+
+ buf_len= len && *len ? *len : strlen(string);
+ wchar_t *buf= (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
+
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
+ " to wide-char representation", string));
+ return NULL;
+ }
+
+ size_t res;
+ res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ buf_len, // its size
+ buf, buf_len); // output buffer and its size
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // error in MultiByteToWideChar()
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert UPN from UTF-8"
+ ", MultiByteToWideChar() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/** Error handling ****************************************************/
+
+
+/**
+ Returns error message corresponding to the last Windows error given
+ by GetLastError().
+
+ @note Error message is overwritten by next call to
+ @c get_last_error_message().
+*/
+
+const char* get_last_error_message(Error_message_buf buf)
+{
+ int error= GetLastError();
+
+ buf[0]= '\0';
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)buf, sizeof(buf), NULL );
+
+ return buf;
+}
diff --git a/libmysql/authentication_win/common.h b/libmysql/authentication_win/common.h
new file mode 100644
index 00000000000..7f7aa1d2dff
--- /dev/null
+++ b/libmysql/authentication_win/common.h
@@ -0,0 +1,324 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <my_global.h>
+#include <windows.h>
+#include <sspi.h> // for CtxtHandle
+#include <mysql/plugin_auth.h> // for MYSQL_PLUGIN_VIO
+
+/// Maximum length of the target service name.
+#define MAX_SERVICE_NAME_LENGTH 1024
+
+
+/** Debugging and error reporting infrastructure ***************************/
+
+/*
+ Note: We use plugin local logging and error reporting mechanisms until
+ WL#2940 (plugin service: error reporting) is available.
+*/
+
+#undef INFO
+#undef WARNING
+#undef ERROR
+
+struct error_log_level
+{
+ typedef enum {INFO, WARNING, ERROR} type;
+};
+
+extern "C" int opt_auth_win_log_level;
+unsigned int get_log_level(void);
+void set_log_level(unsigned int);
+
+
+/*
+ If DEBUG_ERROR_LOG is defined then error logging happens only
+ in debug-copiled code. Otherwise ERROR_LOG() expands to
+ error_log_print() even in production code.
+
+ Note: Macro ERROR_LOG() can use printf-like format string like this:
+
+ ERROR_LOG(Level, ("format string", args));
+
+ The implementation should handle it correctly. Currently it is passed
+ to fprintf() (see error_log_vprint() function).
+*/
+
+#if defined(DEBUG_ERROR_LOG) && defined(DBUG_OFF)
+#define ERROR_LOG(Level, Msg) do {} while (0)
+#else
+#define ERROR_LOG(Level, Msg) error_log_print< error_log_level::Level > Msg
+#endif
+
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args);
+
+template <error_log_level::type Level>
+void error_log_print(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ error_log_vprint(Level, fmt, args);
+ va_end(args);
+}
+
+typedef char Error_message_buf[1024];
+const char* get_last_error_message(Error_message_buf);
+
+
+/*
+ Internal implementation of debug message printing which does not use
+ dbug library. This is invoked via macro:
+
+ DBUG_PRINT_DO(Keyword, ("format string", args));
+
+ This is supposed to be used as an implementation of DBUG_PRINT() macro,
+ unless the dbug library implementation is used or debug messages are disabled.
+*/
+
+#ifndef DBUG_OFF
+
+#define DBUG_PRINT_DO(Keyword, Msg) \
+ do { \
+ if (4 > get_log_level()) break; \
+ fprintf(stderr, "winauth: %s: ", Keyword); \
+ debug_msg Msg; \
+ } while (0)
+
+inline
+void debug_msg(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+ va_end(args);
+}
+
+#else
+#define DBUG_PRINT_DO(K, M) do {} while (0)
+#endif
+
+
+#ifndef WINAUTH_USE_DBUG_LIB
+
+#undef DBUG_PRINT
+#define DBUG_PRINT(Keyword, Msg) DBUG_PRINT_DO(Keyword, Msg)
+
+/*
+ Redefine few more debug macros to make sure that no symbols from
+ dbug library are used.
+*/
+
+#undef DBUG_ENTER
+#define DBUG_ENTER(X) do {} while (0)
+
+#undef DBUG_RETURN
+#define DBUG_RETURN(X) return (X)
+
+#undef DBUG_ASSERT
+#ifndef DBUG_OFF
+#define DBUG_ASSERT(X) assert (X)
+#else
+#define DBUG_ASSERT(X) do {} while (0)
+#endif
+
+#undef DBUG_DUMP
+#define DBUG_DUMP(A,B,C) do {} while (0)
+
+#endif
+
+
+/** Blob class *************************************************************/
+
+typedef unsigned char byte;
+
+/**
+ Class representing a region of memory (e.g., a string or binary buffer).
+
+ @note This class does not allocate memory. It merely describes a region
+ of memory which must be allocated externally (if it is dynamic memory).
+*/
+
+class Blob
+{
+ byte *m_ptr; ///< Pointer to the first byte of the memory region.
+ size_t m_len; ///< Length of the memory region.
+
+public:
+
+ Blob(): m_ptr(NULL), m_len(0)
+ {}
+
+ Blob(const byte *ptr, const size_t len)
+ : m_ptr(const_cast<byte*>(ptr)), m_len(len)
+ {}
+
+ Blob(const char *str): m_ptr((byte*)str)
+ {
+ m_len= strlen(str);
+ }
+
+ byte* ptr() const
+ {
+ return m_ptr;
+ }
+
+ size_t len() const
+ {
+ return m_len;
+ }
+
+ byte& operator[](unsigned pos) const
+ {
+ static byte out_of_range= 0; // alas, no exceptions...
+ return pos < len() ? m_ptr[pos] : out_of_range;
+ }
+
+ bool is_null() const
+ {
+ return m_ptr == NULL;
+ }
+
+ void trim(size_t l)
+ {
+ m_len= l;
+ }
+};
+
+
+/** Connection class *******************************************************/
+
+/**
+ Convenience wrapper around MYSQL_PLUGIN_VIO object providing basic
+ read/write operations.
+*/
+
+class Connection
+{
+ MYSQL_PLUGIN_VIO *m_vio; ///< Pointer to @c MYSQL_PLUGIN_VIO structure.
+
+ /**
+ If non-zero, indicates that connection is broken. If this has happened
+ because of failed operation, stores non-zero error code from that failure.
+ */
+ int m_error;
+
+public:
+
+ Connection(MYSQL_PLUGIN_VIO *vio);
+ int write(const Blob&);
+ Blob read();
+
+ int error() const
+ {
+ return m_error;
+ }
+};
+
+
+/** Sid class **************************************************************/
+
+/**
+ Class for storing and manipulating Windows security identifiers (SIDs).
+*/
+
+class Sid
+{
+ TOKEN_USER *m_data; ///< Pointer to structure holding identifier's data.
+ SID_NAME_USE m_type; ///< Type of identified entity.
+
+public:
+
+ Sid(const wchar_t*);
+ Sid(HANDLE sec_token);
+ ~Sid();
+
+ bool is_valid(void) const;
+
+ bool is_group(void) const
+ {
+ return m_type == SidTypeGroup
+ || m_type == SidTypeWellKnownGroup
+ || m_type == SidTypeAlias;
+ }
+
+ bool is_user(void) const
+ {
+ return m_type == SidTypeUser;
+ }
+
+ bool operator==(const Sid&);
+
+ operator PSID() const
+ {
+ return (PSID)m_data->User.Sid;
+ }
+
+#ifndef DBUG_OFF
+
+private:
+ char *m_as_string; ///< Cached string representation of the SID.
+public:
+ const char* as_string();
+
+#endif
+};
+
+
+/** UPN class **************************************************************/
+
+/**
+ An object of this class obtains and stores User Principal Name of the
+ account under which current process is running.
+*/
+
+class UPN
+{
+ char *m_buf; ///< Pointer to UPN in utf8 representation.
+ size_t m_len; ///< Length of the name.
+
+public:
+
+ UPN();
+ ~UPN();
+
+ bool is_valid() const
+ {
+ return m_len > 0;
+ }
+
+ const Blob as_blob() const
+ {
+ return m_len ? Blob((byte*)m_buf, m_len) : Blob();
+ }
+
+ const char* as_string() const
+ {
+ return (const char*)m_buf;
+ }
+
+};
+
+
+char* wchar_to_utf8(const wchar_t*, size_t*);
+wchar_t* utf8_to_wchar(const char*, size_t*);
+
+#endif
diff --git a/libmysql/authentication_win/handshake.cc b/libmysql/authentication_win/handshake.cc
new file mode 100644
index 00000000000..ec665af9ef9
--- /dev/null
+++ b/libmysql/authentication_win/handshake.cc
@@ -0,0 +1,289 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "handshake.h"
+
+
+/** Handshake class implementation **********************************/
+
+/**
+ Create common part of handshake context.
+
+ @param[in] ssp name of the SSP (Security Service Provider) to
+ be used for authentication
+ @param[in] side is this handshake object used for server- or
+ client-side handshake
+
+ Prepare for handshake using the @c ssp security module. We use
+ "Negotiate" which picks best available module. Parameter @c side
+ tells if this is preparing for server or client side authentication
+ and is used to prepare appropriate credentials.
+*/
+
+Handshake::Handshake(const char *ssp, side_t side)
+: m_atts(0L), m_error(0), m_complete(FALSE),
+ m_have_credentials(false), m_have_sec_context(false)
+#ifndef DBUG_OFF
+ , m_ssp_info(NULL)
+#endif
+{
+ SECURITY_STATUS ret;
+
+ // Obtain credentials for the authentication handshake.
+
+ ret= AcquireCredentialsHandle(NULL, (SEC_CHAR*)ssp,
+ side == SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
+ NULL, NULL, NULL, NULL, &m_cred, &m_expire);
+
+ if (ret != SEC_E_OK)
+ {
+ DBUG_PRINT("error", ("AcqireCredentialsHandle() failed"
+ " with error %X", ret));
+ ERROR_LOG(ERROR, ("Could not obtain local credentials"
+ " required for authentication"));
+ m_error= ret;
+ }
+
+ m_have_credentials= true;
+}
+
+
+Handshake::~Handshake()
+{
+ if (m_have_credentials)
+ FreeCredentialsHandle(&m_cred);
+ if (m_have_sec_context)
+ DeleteSecurityContext(&m_sctx);
+ m_output.free();
+
+#ifndef DBUG_OFF
+ if (m_ssp_info)
+ FreeContextBuffer(m_ssp_info);
+#endif
+}
+
+
+/**
+ Read and process data packets from the other end of a connection.
+
+ @param[IN] con a connection to read packets from
+
+ Packets are read and processed until authentication handshake is
+ complete. It is assumed that the peer will send at least one packet.
+ Packets are processed with @c process_data() method. If new data is
+ generated during packet processing, this data is sent to the peer and
+ another round of packet exchange starts.
+
+ @return 0 on success.
+
+ @note In case of error, appropriate error message is logged.
+*/
+int Handshake::packet_processing_loop()
+{
+ m_round= 0;
+
+ do {
+ ++m_round;
+ // Read packet send by the peer
+
+ DBUG_PRINT("info", ("Waiting for packet"));
+ Blob packet= read_packet();
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error reading packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Got packet of length %d", packet.len()));
+
+ /*
+ Process received data, possibly generating new data to be sent.
+ */
+
+ Blob new_data= process_data(packet);
+
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error processing packet in round %d", m_round));
+ return 1;
+ }
+
+ /*
+ If new data has been generated, send it to the peer. Otherwise
+ handshake must be completed.
+ */
+
+ if (!new_data.is_null())
+ {
+ DBUG_PRINT("info", ("Round %d started", m_round));
+
+ DBUG_PRINT("info", ("Sending packet of length %d", new_data.len()));
+ int ret= write_packet(new_data);
+ if (ret)
+ {
+ ERROR_LOG(ERROR, ("Error writing packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Data sent"));
+ }
+ else if (!is_complete())
+ {
+ ERROR_LOG(ERROR, ("No data to send in round %d"
+ " but handshake is not complete", m_round));
+ return 1;
+ }
+
+ /*
+ To protect against malicious clients, break handshake exchange if
+ too many rounds.
+ */
+
+ if (m_round > MAX_HANDSHAKE_ROUNDS)
+ {
+ ERROR_LOG(ERROR, ("Authentication handshake could not be completed"
+ " after %d rounds", m_round));
+ return 1;
+ }
+
+ } while(!is_complete());
+
+ ERROR_LOG(INFO, ("Handshake completed after %d rounds", m_round));
+ return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Get name of the security package which was used in authentication.
+
+ This method should be called only after handshake was completed. It is
+ available only in debug builds.
+
+ @return Name of security package or NULL if it can not be obtained.
+*/
+
+const char* Handshake::ssp_name()
+{
+ if (!m_ssp_info && m_complete)
+ {
+ SecPkgContext_PackageInfo pinfo;
+
+ int ret= QueryContextAttributes(&m_sctx, SECPKG_ATTR_PACKAGE_INFO, &pinfo);
+
+ if (SEC_E_OK == ret)
+ {
+ m_ssp_info= pinfo.PackageInfo;
+ }
+ else
+ DBUG_PRINT("error",
+ ("Could not obtain SSP info from authentication context"
+ ", QueryContextAttributes() failed with error %X", ret));
+ }
+
+ return m_ssp_info ? m_ssp_info->Name : NULL;
+}
+
+#endif
+
+
+/**
+ Process result of @c {Initialize,Accept}SecurityContext() function.
+
+ @param[in] ret return code from @c {Initialize,Accept}SecurityContext()
+ function
+
+ This function analyses return value of Windows
+ @c {Initialize,Accept}SecurityContext() function. A call to
+ @c CompleteAuthToken() is done if requested. If authentication is complete,
+ this fact is marked in the internal state of the Handshake object.
+ If errors are detected the object is moved to error state.
+
+ @return True if error has been detected.
+*/
+
+bool Handshake::process_result(int ret)
+{
+ /*
+ First check for errors and set the m_complete flag if the result
+ indicates that handshake is complete.
+ */
+
+ switch (ret)
+ {
+ case SEC_E_OK:
+ case SEC_I_COMPLETE_NEEDED:
+ // Handshake completed
+ m_complete= true;
+ break;
+
+ case SEC_I_CONTINUE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ break;
+
+ default:
+ m_error= ret;
+ return true;
+ }
+
+ m_have_sec_context= true;
+
+ /*
+ If the result indicates a need for this, complete the authentication
+ token.
+ */
+
+ switch (ret)
+ {
+ case SEC_I_COMPLETE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ ret= CompleteAuthToken(&m_sctx, &m_output);
+ if (ret != 0)
+ {
+ DBUG_PRINT("error", ("CompleteAuthToken() failed with error %X", ret));
+ m_error= ret;
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/** Security_buffer class implementation **********************************/
+
+
+Security_buffer::Security_buffer(const Blob &blob): m_allocated(false)
+{
+ init(blob.ptr(), blob.len());
+}
+
+
+Security_buffer::Security_buffer(): m_allocated(true)
+{
+ init(NULL, 0);
+}
+
+
+void Security_buffer::free(void)
+{
+ if (!m_allocated)
+ return;
+ if (!ptr())
+ return;
+ FreeContextBuffer(ptr());
+ m_allocated= false;
+}
diff --git a/libmysql/authentication_win/handshake.h b/libmysql/authentication_win/handshake.h
new file mode 100644
index 00000000000..5292948b583
--- /dev/null
+++ b/libmysql/authentication_win/handshake.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef HANDSHAKE_H
+#define HANDSHAKE_H
+
+#include "common.h"
+
+/**
+ Name of the SSP (Security Support Provider) to be used for authentication.
+
+ We use "Negotiate" which will find the most secure SSP which can be used
+ and redirect to that SSP.
+*/
+#define SSP_NAME "Negotiate"
+
+/**
+ Maximal number of rounds in authentication handshake.
+
+ Server will interrupt authentication handshake with error if client's
+ identity can not be determined within this many rounds.
+*/
+#define MAX_HANDSHAKE_ROUNDS 50
+
+
+/// Convenience wrapper around @c SecBufferDesc.
+
+class Security_buffer: public SecBufferDesc
+{
+ SecBuffer m_buf; ///< A @c SecBuffer instance.
+
+ void init(byte *ptr, size_t len)
+ {
+ ulVersion= 0;
+ cBuffers= 1;
+ pBuffers= &m_buf;
+
+ m_buf.BufferType= SECBUFFER_TOKEN;
+ m_buf.pvBuffer= ptr;
+ m_buf.cbBuffer= len;
+ }
+
+ /// If @c false, no deallocation will be done in the destructor.
+ bool m_allocated;
+
+ public:
+
+ Security_buffer(const Blob&);
+ Security_buffer();
+
+ ~Security_buffer()
+ {
+ free();
+ }
+
+ byte* ptr() const
+ {
+ return (byte*)m_buf.pvBuffer;
+ }
+
+ size_t len() const
+ {
+ return m_buf.cbBuffer;
+ }
+
+ bool is_valid() const
+ {
+ return ptr() != NULL;
+ }
+
+ const Blob as_blob() const
+ {
+ return Blob(ptr(), len());
+ }
+
+ void free(void);
+};
+
+
+/// Common base for Handshake_{server,client}.
+
+class Handshake
+{
+public:
+
+ typedef enum {CLIENT, SERVER} side_t;
+
+ Handshake(const char *ssp, side_t side);
+ virtual ~Handshake();
+
+ int Handshake::packet_processing_loop();
+
+ bool virtual is_complete() const
+ {
+ return m_complete;
+ }
+
+ int error() const
+ {
+ return m_error;
+ }
+
+protected:
+
+ /// Security context object created during the handshake.
+ CtxtHandle m_sctx;
+
+ /// Credentials of the principal performing this handshake.
+ CredHandle m_cred;
+
+ /// Stores expiry date of the created security context.
+ TimeStamp m_expire;
+
+ /// Stores attributes of the created security context.
+ ULONG m_atts;
+
+ /**
+ Round of the handshake (starting from round 1). One round
+ consist of reading packet from the other side, processing it and
+ optionally sending a reply (see @c packet_processing_loop()).
+ */
+ unsigned int m_round;
+
+ /// If non-zero, stores error code of the last failed operation.
+ int m_error;
+
+ /// @c true when handshake is complete.
+ bool m_complete;
+
+ /// @c true when the principal credentials has been determined.
+ bool m_have_credentials;
+
+ /// @c true when the security context has been created.
+ bool m_have_sec_context;
+
+ /// Buffer for data to be send to the other side.
+ Security_buffer m_output;
+
+ bool process_result(int);
+
+ /**
+ This method is used inside @c packet_processing_loop to process
+ data packets received from the other end.
+
+ @param[IN] data data to be processed
+
+ @return A blob with data to be sent to the other end or null blob if
+ no more data needs to be exchanged.
+ */
+ virtual Blob process_data(const Blob &data) =0;
+
+ /// Read packet from the other end.
+ virtual Blob read_packet() =0;
+
+ /// Write packet to the other end.
+ virtual int write_packet(Blob &data) =0;
+
+#ifndef DBUG_OFF
+
+private:
+ SecPkgInfo *m_ssp_info;
+public:
+ const char* ssp_name();
+
+#endif
+};
+
+
+#endif
diff --git a/libmysql/authentication_win/handshake_client.cc b/libmysql/authentication_win/handshake_client.cc
new file mode 100644
index 00000000000..02e5483da29
--- /dev/null
+++ b/libmysql/authentication_win/handshake_client.cc
@@ -0,0 +1,393 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "handshake.h"
+
+#include <mysql.h> // for MYSQL structure
+
+
+/// Client-side context for authentication handshake
+
+class Handshake_client: public Handshake
+{
+ /**
+ Name of the server's service for which we authenticate.
+
+ The service name is sent by server in the initial packet. If no
+ service name is used, this member is @c NULL.
+ */
+ SEC_WCHAR *m_service_name;
+
+ /// Buffer for storing service name obtained from server.
+ SEC_WCHAR m_service_name_buf[MAX_SERVICE_NAME_LENGTH];
+
+ Connection &m_con;
+
+public:
+
+ Handshake_client(Connection &con, const char *target, size_t len);
+ ~Handshake_client();
+
+ Blob first_packet();
+ Blob process_data(const Blob&);
+
+ Blob read_packet();
+ int write_packet(Blob &data);
+};
+
+
+/**
+ Create authentication handshake context for client.
+
+ @param con connection for communication with the peer
+ @param target name of the target service with which we will authenticate
+ (can be NULL if not used)
+
+ Some security packages (like Kerberos) require providing explicit name
+ of the service with which a client wants to authenticate. The server-side
+ authentication plugin sends this name in the greeting packet
+ (see @c win_auth_handshake_{server,client}() functions).
+*/
+
+Handshake_client::Handshake_client(Connection &con,
+ const char *target, size_t len)
+: Handshake(SSP_NAME, CLIENT), m_service_name(NULL), m_con(con)
+{
+ if (!target || 0 == len)
+ return;
+
+ // Convert received UPN to internal WCHAR representation.
+
+ m_service_name= utf8_to_wchar(target, &len);
+
+ if (m_service_name)
+ DBUG_PRINT("info", ("Using target service: %S\n", m_service_name));
+ else
+ {
+ /*
+ Note: we ignore errors here - m_target will be NULL, the target name
+ will not be used and system will fall-back to NTLM authentication. But
+ we leave trace in error log.
+ */
+ ERROR_LOG(WARNING, ("Could not decode UPN sent by the server"
+ "; target service name will not be used"
+ " and Kerberos authentication will not work"));
+ }
+}
+
+
+Handshake_client::~Handshake_client()
+{
+ if (m_service_name)
+ free(m_service_name);
+}
+
+
+Blob Handshake_client::read_packet()
+{
+ /*
+ We do a fake read in the first round because first
+ packet from the server containing UPN must be read
+ before the handshake context is created and the packet
+ processing loop starts. We return an empty blob here
+ and process_data() function will ignore it.
+ */
+ if (m_round == 1)
+ return Blob();
+
+ // Otherwise we read packet from the connection.
+
+ Blob packet= m_con.read();
+ m_error= m_con.error();
+ if (!m_error && packet.is_null())
+ m_error= true; // (no specific error code assigned)
+
+ if (m_error)
+ return Blob();
+
+ DBUG_PRINT("dump", ("Got the following bytes"));
+ DBUG_DUMP("dump", packet.ptr(), packet.len());
+ return packet;
+}
+
+
+
+int Handshake_client::write_packet(Blob &data)
+{
+ /*
+ Length of the first data payload send by client authentication plugin is
+ limited to 255 bytes (because it is wrapped inside client authentication
+ packet and is length-encoded with 1 byte for the length).
+
+ If the data payload is longer than 254 bytes, then it is sent in two parts:
+ first part of length 255 will be embedded in the authentication packet,
+ second part will be sent in the following packet. Byte 255 of the first
+ part contains information about the total length of the payload. It is a
+ number of blocks of size 512 bytes which is sufficient to store the
+ combined packets.
+
+ Server's logic for reading first client's payload is as follows
+ (see Handshake_server::read_packet()):
+ 1. Read data from the authentication packet, if it is shorter than 255 bytes
+ then that is all data sent by client.
+ 2. If there is 255 bytes of data in the authentication packet, read another
+ packet and append it to the data, skipping byte 255 of the first packet
+ which can be used to allocate buffer of appropriate size.
+ */
+
+ size_t len2= 0; // length of the second part of first data payload
+ byte saved_byte; // for saving byte 255 in which data length is stored
+
+ if (m_round == 1 && data.len() > 254)
+ {
+ len2= data.len() - 254;
+ DBUG_PRINT("info", ("Splitting first packet of length %lu"
+ ", %lu bytes will be sent in a second part",
+ data.len(), len2));
+ /*
+ Store in byte 255 the number of 512b blocks that are needed to
+ keep all the data.
+ */
+ unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0);
+
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+
+ /*
+ For testing purposes, use wrong block count to see how server
+ handles this.
+ */
+ DBUG_EXECUTE_IF("winauth_first_packet_test",{
+ block_count= data.len() == 601 ? 0 :
+ data.len() == 602 ? 1 :
+ block_count;
+ });
+
+#endif
+
+ DBUG_ASSERT(block_count < (unsigned)0x100);
+ saved_byte= data[254];
+ data[254] = block_count;
+
+ data.trim(255);
+ }
+
+ DBUG_PRINT("dump", ("Sending the following data"));
+ DBUG_DUMP("dump", data.ptr(), data.len());
+ int ret= m_con.write(data);
+
+ if (ret)
+ return ret;
+
+ // Write second part if it is present.
+ if (len2)
+ {
+ data[254]= saved_byte;
+ Blob data2(data.ptr() + 254, len2);
+ DBUG_PRINT("info", ("Sending second part of data"));
+ DBUG_DUMP("info", data2.ptr(), data2.len());
+ ret= m_con.write(data2);
+ }
+
+ return ret;
+}
+
+
+/**
+ Process data sent by server.
+
+ @param[in] data blob with data from server
+
+ This method analyses data sent by server during authentication handshake.
+ If client should continue packet exchange, this method returns data to
+ be sent to the server next. If no more data needs to be exchanged, an
+ empty blob is returned and @c is_complete() is @c true. In case of error
+ an empty blob is returned and @c error() gives non-zero error code.
+
+ When invoked for the first time (in the first round of the handshake)
+ there is no data from the server (data blob is null) and the intial
+ packet is generated without an input.
+
+ @return Data to be sent to the server next or null blob if no more data
+ needs to be exchanged or in case of error.
+*/
+
+Blob Handshake_client::process_data(const Blob &data)
+{
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+ /*
+ Code for testing the logic for sending the first client payload.
+
+ A fake data of length given by environment variable TEST_PACKET_LENGTH
+ (or default 255 bytes) is sent to the server. First 2 bytes of the
+ payload contain its total length (LSB first). The length of test data
+ is limited to 2048 bytes.
+
+ Upon receiving test data, server will check that data is correct and
+ refuse connection. If server detects data errors it will crash on
+ assertion.
+
+ This code is executed if debug flag "winauth_first_packet_test" is
+ set, e.g. using client option:
+
+ --debug="d,winauth_first_packet_test"
+
+ The same debug flag must be enabled in the server, e.g. using
+ statement:
+
+ SET GLOBAL debug= '+d,winauth_first_packet_test';
+ */
+
+ static byte test_buf[2048];
+
+ if (m_round == 1
+ && DBUG_EVALUATE_IF("winauth_first_packet_test", true, false))
+ {
+ const char *env= getenv("TEST_PACKET_LENGTH");
+ size_t len= env ? atoi(env) : 0;
+ if (!len)
+ len= 255;
+ if (len > sizeof(test_buf))
+ len= sizeof(test_buf);
+
+ // Store data length in first 2 bytes.
+ byte *ptr= test_buf;
+ *ptr++= len & 0xFF;
+ *ptr++= len >> 8;
+
+ // Fill remaining bytes with known values.
+ for (byte b= 0; ptr < test_buf + len; ++ptr, ++b)
+ *ptr= b;
+
+ return Blob(test_buf, len);
+ };
+
+#endif
+
+ Security_buffer input(data);
+ SECURITY_STATUS ret;
+
+ m_output.free();
+
+ ret= InitializeSecurityContextW(
+ &m_cred,
+ m_round == 1 ? NULL : &m_sctx, // partial context
+ m_service_name, // service name
+ ASC_REQ_ALLOCATE_MEMORY, // requested attributes
+ 0, // reserved
+ SECURITY_NETWORK_DREP, // data representation
+ m_round == 1 ? NULL : &input, // input data
+ 0, // reserved
+ &m_sctx, // context
+ &m_output, // output data
+ &m_atts, // attributes
+ &m_expire); // expire date
+
+ if (process_result(ret))
+ {
+ DBUG_PRINT("error",
+ ("InitializeSecurityContext() failed with error %X", ret));
+ return Blob();
+ }
+
+ return m_output.as_blob();
+}
+
+
+/**********************************************************************/
+
+
+/**
+ Perform authentication handshake from client side.
+
+ @param[in] vio pointer to @c MYSQL_PLUGIN_VIO instance to be used
+ for communication with the server
+ @param[in] mysql pointer to a MySQL connection for which we authenticate
+
+ After reading the initial packet from server, containing its UPN to be
+ used as service name, client starts packet exchange by sending the first
+ packet in this exchange. While handshake is not yet completed, client
+ reads packets sent by the server and process them, possibly generating new
+ data to be sent to the server.
+
+ This function reports errors.
+
+ @return 0 on success.
+*/
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ DBUG_ENTER("win_auth_handshake_client");
+
+ /*
+ Check if we should enable logging.
+ */
+ {
+ const char *opt= getenv("AUTHENTICATION_WIN_LOG");
+ int opt_val= opt ? atoi(opt) : 0;
+ if (opt && !opt_val)
+ {
+ if (!strncasecmp("on", opt, 2)) opt_val= 2;
+ if (!strncasecmp("yes", opt, 3)) opt_val= 2;
+ if (!strncasecmp("true", opt, 4)) opt_val= 2;
+ if (!strncasecmp("debug", opt, 5)) opt_val= 4;
+ if (!strncasecmp("dbug", opt, 4)) opt_val= 4;
+ }
+ set_log_level(opt_val);
+ }
+
+ ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user));
+
+ // Create connection object.
+
+ Connection con(vio);
+ DBUG_ASSERT(!con.error());
+
+ // Read initial packet from server containing service name.
+
+ Blob service_name= con.read();
+
+ if (con.error() || service_name.is_null())
+ {
+ ERROR_LOG(ERROR, ("Error reading initial packet"));
+ DBUG_RETURN(CR_ERROR);
+ }
+ DBUG_PRINT("info", ("Got initial packet of length %d", service_name.len()));
+
+ // Create authentication handshake context using the given service name.
+
+ Handshake_client hndshk(con,
+ service_name[0] ? (char *)service_name.ptr() : NULL,
+ service_name.len());
+ if (hndshk.error())
+ {
+ ERROR_LOG(ERROR, ("Could not create authentication handshake context"));
+ DBUG_RETURN(CR_ERROR);
+ }
+
+ DBUG_ASSERT(!hndshk.error());
+
+ /*
+ Read and process packets from server until handshake is complete.
+ Note that the first read from server is dummy
+ (see Handshake_client::read_packet()) as we already have read the
+ first packet to establish service name.
+ */
+ if (hndshk.packet_processing_loop())
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_ASSERT(!hndshk.error() && hndshk.is_complete());
+
+ DBUG_RETURN(CR_OK);
+}
diff --git a/libmysql/authentication_win/log_client.cc b/libmysql/authentication_win/log_client.cc
new file mode 100644
index 00000000000..8a49c4220bb
--- /dev/null
+++ b/libmysql/authentication_win/log_client.cc
@@ -0,0 +1,65 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include "common.h"
+
+
+// Client-side logging function
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args)
+{
+ const char *level_string= "";
+ int log_level= get_log_level();
+
+ switch (level)
+ {
+ case error_log_level::INFO:
+ if (3 > log_level)
+ return;
+ level_string= "Note";
+ break;
+ case error_log_level::WARNING:
+ if (2 > log_level)
+ return;
+ level_string= "Warning";
+ break;
+ case error_log_level::ERROR:
+ if (1 > log_level)
+ return;
+ level_string= "ERROR";
+ break;
+ }
+
+ fprintf(stderr, "Windows Authentication Plugin %s: ", level_string);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+}
+
+
+// Trivial implementation of log-level setting storage.
+
+void set_log_level(unsigned int level)
+{
+ opt_auth_win_log_level= level;
+}
+
+
+unsigned int get_log_level(void)
+{
+ return opt_auth_win_log_level;
+}
diff --git a/libmysql/authentication_win/plugin_client.cc b/libmysql/authentication_win/plugin_client.cc
new file mode 100644
index 00000000000..30dc5b1493d
--- /dev/null
+++ b/libmysql/authentication_win/plugin_client.cc
@@ -0,0 +1,68 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+
+#include "common.h"
+
+/*
+ The following MS C++ specific pragma embeds a comment in the resulting
+ object file. A "lib" comment tells the linker to use the specified
+ library, thus the dependency is handled automagically.
+*/
+
+#ifdef _MSC_VER
+#pragma comment(lib, "Secur32")
+#endif
+
+static int win_auth_client_plugin_init(char*, size_t, int, va_list)
+{
+ return 0;
+}
+
+
+static int win_auth_client_plugin_deinit()
+{
+ return 0;
+}
+
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+
+
+/*
+ Client plugin declaration. This is added to mysql_client_builtins[]
+ in sql-common/client.c
+*/
+
+extern "C"
+st_mysql_client_plugin_AUTHENTICATION win_auth_client_plugin=
+{
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+ "authentication_windows_client",
+ "Rafal Somla",
+ "Windows Authentication Plugin - client side",
+ {0,1,0},
+ "GPL",
+ NULL,
+ win_auth_client_plugin_init,
+ win_auth_client_plugin_deinit,
+ NULL, // option handling
+ win_auth_handshake_client
+};
diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h
index f87e625771f..ecc9a7773ca 100644
--- a/libmysql/client_settings.h
+++ b/libmysql/client_settings.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2005 MySQL AB
+/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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
@@ -11,34 +11,35 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef CLIENT_SETTINGS_INCLUDED
+#define CLIENT_SETTINGS_INCLUDED
+#else
+#error You have already included an client_settings.h and it should not be included twice
+#endif /* CLIENT_SETTINGS_INCLUDED */
extern uint mysql_port;
extern char * mysql_unix_port;
-#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
- CLIENT_TRANSACTIONS | \
- CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
+/*
+ Note: CLIENT_CAPABILITIES is also defined in sql/client_settings.h.
+ When adding capabilities here, consider if they should be also added to
+ the server's version.
+*/
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \
+ CLIENT_LONG_FLAG | \
+ CLIENT_TRANSACTIONS | \
+ CLIENT_PROTOCOL_41 | \
+ CLIENT_SECURE_CONNECTION | \
+ CLIENT_MULTI_RESULTS | \
+ CLIENT_PS_MULTI_RESULTS | \
+ CLIENT_PLUGIN_AUTH)
sig_handler my_pipe_sig_handler(int sig);
void read_user_name(char *name);
my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
-/*
- 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(__WIN__) && 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, my_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
-
void mysql_read_default_options(struct st_mysql_options *options,
const char *filename,const char *group);
void mysql_detach_stmt_list(LIST **stmt_list, const char *func_name);
@@ -57,7 +58,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt);
int cli_read_binary_rows(MYSQL_STMT *stmt);
int cli_unbuffered_fetch(MYSQL *mysql, char **row);
const char * cli_read_statistics(MYSQL *mysql);
-int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd);
+int cli_read_change_user_result(MYSQL *mysql);
#ifdef EMBEDDED_LIBRARY
int init_embedded_server(int argc, char **argv, char **groups);
diff --git a/libmysql/dll.c b/libmysql/dll.c
deleted file mode 100644
index 8654c035c63..00000000000
--- a/libmysql/dll.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Copyright (C) 2000-2004 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation.
-
- There are special exceptions to the terms and conditions of the GPL as it
- is applied to this software.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
-** Handling initialization of the dll library
-*/
-
-#include <my_global.h>
-#include <my_sys.h>
-#include <my_pthread.h>
-
-static my_bool libmysql_inited=0;
-
-void libmysql_init(void)
-{
- if (libmysql_inited)
- return;
- libmysql_inited=1;
- my_init();
- {
- DBUG_ENTER("libmysql_init");
-#ifdef LOG_ALL
- DBUG_PUSH("d:t:S:O,c::\\tmp\\libmysql.log");
-#else
- if (getenv("LIBMYSQL_LOG") != NULL)
- DBUG_PUSH(getenv("LIBMYSQL_LOG"));
-#endif
- DBUG_VOID_RETURN;
- }
-}
-
-#ifdef __WIN__
-
-static int inited=0,threads=0;
-HINSTANCE NEAR s_hModule; /* Saved module handle */
-DWORD main_thread;
-
-BOOL APIENTRY LibMain(HANDLE hInst,DWORD ul_reason_being_called,
- LPVOID lpReserved)
-{
- switch (ul_reason_being_called) {
- case DLL_PROCESS_ATTACH: /* case of libentry call in win 3.x */
- if (!inited++)
- {
- s_hModule=hInst;
- libmysql_init();
- main_thread=GetCurrentThreadId();
- }
- break;
- case DLL_THREAD_ATTACH:
- threads++;
- my_thread_init();
- break;
- case DLL_PROCESS_DETACH: /* case of wep call in win 3.x */
- if (!--inited) /* Safety */
- {
- /* my_thread_init() */ /* This may give extra safety */
- my_end(0);
- }
- break;
- case DLL_THREAD_DETACH:
- /* Main thread will free by my_end() */
- threads--;
- if (main_thread != GetCurrentThreadId())
- my_thread_end();
- break;
- default:
- break;
- } /* switch */
-
- return TRUE;
-
- UNREFERENCED_PARAMETER(lpReserved);
-} /* LibMain */
-
-
-static BOOL do_libmain;
-int __stdcall DllMain(HANDLE hInst,DWORD ul_reason_being_called,LPVOID lpReserved)
-{
- /*
- Unless environment variable LIBMYSQL_DLLINIT is set, do nothing.
- The environment variable is checked once, during the first call to DllMain()
- (in DLL_PROCESS_ATTACH hook).
- */
- if (ul_reason_being_called == DLL_PROCESS_ATTACH)
- do_libmain = (getenv("LIBMYSQL_DLLINIT") != NULL);
- if (do_libmain)
- return LibMain(hInst,ul_reason_being_called,lpReserved);
- return TRUE;
-}
-
-#elif defined(WINDOWS)
-
-/****************************************************************************
-** This routine is called by LIBSTART.ASM at module load time. All it
-** does in this sample is remember the DLL module handle. The module
-** handle is needed if you want to do things like load stuff from the
-** resource file (for instance string resources).
-****************************************************************************/
-
-int _export FAR PASCAL libmain(HANDLE hModule,short cbHeapSize,
- UCHAR FAR *lszCmdLine)
-{
- s_hModule = hModule;
- libmysql_init();
- return TRUE;
-}
-
-#endif
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 163632127c3..498ba6e9829 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2004 MySQL AB
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Error messages for MySQL clients */
/* (Error messages for the daemon are in share/language/errmsg.sys) */
@@ -23,137 +23,6 @@
#include <my_sys.h>
#include "errmsg.h"
-#ifdef GERMAN
-const char *client_errors[]=
-{
- "Unbekannter MySQL Fehler",
- "Kann UNIX-Socket nicht anlegen (%d)",
- "Keine Verbindung zu lokalem MySQL Server, socket: '%-.100s' (%d)",
- "Keine Verbindung zu MySQL Server auf %-.100s (%d)",
- "Kann TCP/IP-Socket nicht anlegen (%d)",
- "Unbekannter MySQL Server Host (%-.100s) (%d)",
- "MySQL Server nicht vorhanden",
- "Protokolle ungleich; Server Version = %d, Client Version = %d",
- "MySQL client ran out of memory",
- "Wrong host info",
- "Localhost via UNIX socket",
- "%-.100s 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: %-.32s",
- "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 %-.32s (path: %-.100s)",
- "Got packet bigger than 'max_allowed_packet' bytes",
- "Embedded server",
- "Error on SHOW SLAVE STATUS:",
- "Error on SHOW SLAVE HOSTS:",
- "Error connecting to slave:",
- "Error connecting to master:",
- "SSL connection error",
- "Malformed packet",
- "This client library is licensed only for use with MySQL servers having '%s' license",
- "Invalid use of null pointer",
- "Statement not prepared",
- "No data supplied for parameters in prepared statement",
- "Data truncated",
- "No parameters exist in the statement",
- "Invalid parameter number",
- "Can't send long data for non-string/non-binary data types (parameter: %d)",
- "Using unsupported buffer type: %d (parameter: %d)",
- "Shared memory: %-.100s",
- "Can't open shared memory; client could not create request event (%lu)",
- "Can't open shared memory; no answer event received from server (%lu)",
- "Can't open shared memory; server could not allocate file mapping (%lu)",
- "Can't open shared memory; server could not get pointer to file mapping (%lu)",
- "Can't open shared memory; client could not allocate file mapping (%lu)",
- "Can't open shared memory; client could not get pointer to file mapping (%lu)",
- "Can't open shared memory; client could not create %s event (%lu)",
- "Can't open shared memory; no answer from server (%lu)",
- "Can't open shared memory; cannot send request event to server (%lu)",
- "Wrong or unknown protocol",
- "Invalid connection handle",
- "Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
- "Row retrieval was canceled by mysql_stmt_close() call",
- "Attempt to read column without prior row fetch",
- "Prepared statement contains no metadata",
- "Attempt to read a row while there is no result set associated with the statement",
- "This feature is not implemented yet",
- "Lost connection to MySQL server at '%s', system error: %d",
- "Statement closed indirectly because of a preceeding %s() call",
- "The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
- ""
-};
-
-/* 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",
- "Não pode criar 'UNIX socket' (%d)",
- "Não pode se conectar ao servidor MySQL local através do 'socket' '%-.100s' (%d)",
- "Não pode se conectar ao servidor MySQL em '%-.100s' (%d)",
- "Não pode criar 'socket TCP/IP' (%d)",
- "'Host' servidor MySQL '%-.100s' (%d) desconhecido",
- "Servidor MySQL desapareceu",
- "Incompatibilidade de protocolos; versão do servidor = %d, versão do cliente = %d",
- "Cliente do MySQL com falta de memória",
- "Informação inválida de 'host'",
- "Localhost via 'UNIX socket'",
- "%-.100s via 'TCP/IP'",
- "Erro na negociação de acesso ao servidor",
- "Conexão perdida com servidor MySQL durante 'query'",
- "Comandos fora de sincronismo; você não pode executar este comando agora",
- "Named pipe: %-.32s",
- "Não pode esperar pelo 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
- "Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
- "Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)",
- "Não pode inicializar conjunto de caracteres %-.32s (caminho %-.100s)",
- "Obteve pacote maior do que 'max_allowed_packet' bytes",
- "Embedded server"
- "Error on SHOW SLAVE STATUS:",
- "Error on SHOW SLAVE HOSTS:",
- "Error connecting to slave:",
- "Error connecting to master:",
- "SSL connection error",
- "Malformed packet",
- "This client library is licensed only for use with MySQL servers having '%s' license",
- "Invalid use of null pointer",
- "Statement not prepared",
- "No data supplied for parameters in prepared statement",
- "Data truncated",
- "No parameters exist in the statement",
- "Invalid parameter number",
- "Can't send long data for non-string/non-binary data types (parameter: %d)",
- "Using unsupported buffer type: %d (parameter: %d)",
- "Shared memory: %-.100s",
- "Can't open shared memory; client could not create request event (%lu)",
- "Can't open shared memory; no answer event received from server (%lu)",
- "Can't open shared memory; server could not allocate file mapping (%lu)",
- "Can't open shared memory; server could not get pointer to file mapping (%lu)",
- "Can't open shared memory; client could not allocate file mapping (%lu)",
- "Can't open shared memory; client could not get pointer to file mapping (%lu)",
- "Can't open shared memory; client could not create %s event (%lu)",
- "Can't open shared memory; no answer from server (%lu)",
- "Can't open shared memory; cannot send request event to server (%lu)",
- "Wrong or unknown protocol",
- "Invalid connection handle",
- "Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
- "Row retrieval was canceled by mysql_stmt_close() call",
- "Attempt to read column without prior row fetch",
- "Prepared statement contains no metadata",
- "Attempt to read a row while there is no result set associated with the statement",
- "This feature is not implemented yet",
- "Lost connection to MySQL server at '%s', system error: %d",
- "Statement closed indirectly because of a preceeding %s() call",
- "The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
- ""
-};
-
-#else /* ENGLISH */
const char *client_errors[]=
{
"Unknown MySQL error",
@@ -182,7 +51,7 @@ const char *client_errors[]=
"Error on SHOW SLAVE HOSTS:",
"Error connecting to slave:",
"Error connecting to master:",
- "SSL connection error",
+ "SSL connection error: %-.100s",
"Malformed packet",
"This client library is licensed only for use with MySQL servers having '%s' license",
"Invalid use of null pointer",
@@ -214,10 +83,15 @@ const char *client_errors[]=
"Lost connection to MySQL server at '%s', system error: %d",
"Statement closed indirectly because of a preceeding %s() call",
"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again",
+ "This handle is already connected. Use a separate handle for each connection.",
+ "Authentication plugin '%s' cannot be loaded: %s",
""
};
-#endif
+const char** get_client_errmsgs()
+{
+ return client_errors;
+}
/*
Register client error messages for use with my_error().
@@ -231,7 +105,7 @@ const char *client_errors[]=
void init_client_errs(void)
{
- (void) my_error_register(client_errors, CR_ERROR_FIRST, CR_ERROR_LAST);
+ (void) my_error_register(get_client_errmsgs, CR_ERROR_FIRST, CR_ERROR_LAST);
}
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
index 63d4e68541f..55b7bf41cee 100644
--- a/libmysql/get_password.c
+++ b/libmysql/get_password.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2004 MySQL AB
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
** Ask for a password from tty
@@ -35,7 +35,7 @@
#include <pwd.h>
#endif /* HAVE_PWD_H */
#else /* ! HAVE_GETPASS */
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
#include <sys/ioctl.h>
#ifdef HAVE_TERMIOS_H /* For tty-password */
#include <termios.h>
@@ -54,9 +54,7 @@
#include <asm/termiobits.h>
#endif
#else
-#ifndef __NETWARE__
#include <conio.h>
-#endif /* __NETWARE__ */
#endif /* __WIN__ */
#endif /* HAVE_GETPASS */
@@ -64,16 +62,8 @@
#define getpass(A) getpassphrase(A)
#endif
-#if defined( __WIN__) || defined(__NETWARE__)
+#if defined(__WIN__)
/* were just going to fake it here and get input from the keyboard */
-
-#ifdef __NETWARE__
-#undef _getch
-#undef _cputs
-#define _getch getcharacter
-#define _cputs(A) putstring(A)
-#endif
-
char *get_tty_password(const char *opt_message)
{
char to[80];
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 562da594fea..9f5e6cc5f1a 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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
@@ -33,7 +33,7 @@
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -44,14 +44,14 @@
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
-#endif /* !defined(MSDOS) && !defined(__WIN__) */
+#endif /* !defined(__WIN__) */
#ifdef HAVE_POLL
#include <sys/poll.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
-#if defined(THREAD) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <my_pthread.h> /* because of signal() */
#endif
#ifndef INADDR_NONE
@@ -73,7 +73,7 @@ ulong max_allowed_packet= 1024L*1024L*1024L;
my_bool net_flush(NET *net);
#endif
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
/* socket_errno is defined in my_global.h for all platforms */
#define perror(A)
#else
@@ -94,6 +94,11 @@ sig_handler my_pipe_sig_handler(int sig);
static my_bool mysql_client_init= 0;
static my_bool org_my_init_done= 0;
+typedef struct st_mysql_stmt_extension
+{
+ MEM_ROOT fields_mem_root;
+} MYSQL_STMT_EXT;
+
/*
Initialize the MySQL client library
@@ -125,33 +130,33 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)),
if (my_init()) /* Will init threads */
return 1;
init_client_errs();
+ if (mysql_client_plugin_init())
+ return 1;
if (!mysql_port)
{
+ char *env;
+ struct servent *serv_ptr __attribute__((unused));
+
mysql_port = MYSQL_PORT;
-#ifndef MSDOS
- {
- char *env;
- struct servent *serv_ptr __attribute__((unused));
- /*
- if builder specifically requested a default port, use that
- (even if it coincides with our factory default).
- only if they didn't do we check /etc/services (and, failing
- on that, fall back to the factory default of 3306).
- either default can be overridden by the environment variable
- MYSQL_TCP_PORT, which in turn can be overridden with command
- line options.
- */
+ /*
+ if builder specifically requested a default port, use that
+ (even if it coincides with our factory default).
+ only if they didn't do we check /etc/services (and, failing
+ on that, fall back to the factory default of 3306).
+ either default can be overridden by the environment variable
+ MYSQL_TCP_PORT, which in turn can be overridden with command
+ line options.
+ */
#if MYSQL_PORT_DEFAULT == 0
- if ((serv_ptr = getservbyname("mysql", "tcp")))
- mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
-#endif
- if ((env = getenv("MYSQL_TCP_PORT")))
- mysql_port =(uint) atoi(env);
- }
+ if ((serv_ptr= getservbyname("mysql", "tcp")))
+ mysql_port= (uint) ntohs((ushort) serv_ptr->s_port);
#endif
+ if ((env= getenv("MYSQL_TCP_PORT")))
+ mysql_port=(uint) atoi(env);
}
+
if (!mysql_unix_port)
{
char *env;
@@ -164,7 +169,7 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)),
mysql_unix_port = env;
}
mysql_debug(NullS);
-#if defined(SIGPIPE) && !defined(__WIN__) && !defined(__NETWARE__)
+#if defined(SIGPIPE) && !defined(__WIN__)
(void) signal(SIGPIPE, SIG_IGN);
#endif
#ifdef EMBEDDED_LIBRARY
@@ -172,10 +177,8 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)),
result= init_embedded_server(argc, argv, groups);
#endif
}
-#ifdef THREAD
else
result= (int)my_thread_init(); /* Init if new thread */
-#endif
return result;
}
@@ -197,6 +200,8 @@ void STDCALL mysql_server_end()
if (!mysql_client_init)
return;
+ mysql_client_plugin_deinit();
+
#ifdef EMBEDDED_LIBRARY
end_embedded_server();
#endif
@@ -215,13 +220,6 @@ void STDCALL mysql_server_end()
}
mysql_client_init= org_my_init_done= 0;
-#ifdef EMBEDDED_SERVER
- if (stderror_file)
- {
- fclose(stderror_file);
- stderror_file= 0;
- }
-#endif
}
static MYSQL_PARAMETERS mysql_internal_parameters=
@@ -234,30 +232,14 @@ MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void)
my_bool STDCALL mysql_thread_init()
{
-#ifdef THREAD
return my_thread_init();
-#else
- return 0;
-#endif
}
void STDCALL mysql_thread_end()
{
-#ifdef THREAD
my_thread_end();
-#endif
}
-/*
- 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.
-*/
-static MYSQL* spawn_init(MYSQL* parent, const char* host,
- unsigned int port,
- const char* user,
- const char* passwd);
-
-
/*
Expand wildcard to a sql string
@@ -319,7 +301,7 @@ mysql_debug(const char *debug __attribute__((unused)))
/**************************************************************************
- Close the server connection if we get a SIGPIPE
+ Ignore SIGPIPE handler
ARGSUSED
**************************************************************************/
@@ -332,305 +314,6 @@ my_pipe_sig_handler(int sig __attribute__((unused)))
#endif
}
-/* perform query on master */
-my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q,
- unsigned long length)
-{
- DBUG_ENTER("mysql_master_query");
- if (mysql_master_send_query(mysql, q, length))
- DBUG_RETURN(1);
- DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
-}
-
-my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
- unsigned long length)
-{
- MYSQL *master = mysql->master;
- DBUG_ENTER("mysql_master_send_query");
- if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
- DBUG_RETURN(1);
- master->reconnect= 1;
- mysql->last_used_con = master;
- DBUG_RETURN(simple_command(master, COM_QUERY, (const uchar*) q, length, 1));
-}
-
-
-/* perform query on slave */
-my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
- unsigned long length)
-{
- DBUG_ENTER("mysql_slave_query");
- if (mysql_slave_send_query(mysql, q, length))
- DBUG_RETURN(1);
- DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
-}
-
-
-my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
- unsigned long length)
-{
- MYSQL* last_used_slave, *slave_to_use = 0;
- DBUG_ENTER("mysql_slave_send_query");
-
- if ((last_used_slave = mysql->last_used_slave))
- slave_to_use = last_used_slave->next_slave;
- else
- slave_to_use = mysql->next_slave;
- /*
- Next_slave is always safe to use - we have a circular list of slaves
- if there are no slaves, mysql->next_slave == mysql
- */
- mysql->last_used_con = mysql->last_used_slave = slave_to_use;
- if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
- 0,0,0,0))
- DBUG_RETURN(1);
- slave_to_use->reconnect= 1;
- DBUG_RETURN(simple_command(slave_to_use, COM_QUERY, (const uchar*) q,
- length, 1));
-}
-
-
-/* enable/disable parsing of all queries to decide
- if they go on master or slave */
-void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
-{
- mysql->options.rpl_parse = 1;
-}
-
-void STDCALL mysql_disable_rpl_parse(MYSQL* mysql)
-{
- mysql->options.rpl_parse = 0;
-}
-
-/* get the value of the parse flag */
-int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql)
-{
- return mysql->options.rpl_parse;
-}
-
-/* enable/disable reads from master */
-void STDCALL mysql_enable_reads_from_master(MYSQL* mysql)
-{
- mysql->options.no_master_reads = 0;
-}
-
-void STDCALL mysql_disable_reads_from_master(MYSQL* mysql)
-{
- mysql->options.no_master_reads = 1;
-}
-
-/* get the value of the master read flag */
-my_bool STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
-{
- return !(mysql->options.no_master_reads);
-}
-
-
-/*
- We may get an error while doing replication internals.
- In this case, we add a special explanation to the original
- error
-*/
-
-static void expand_error(MYSQL* mysql, int error)
-{
- char tmp[MYSQL_ERRMSG_SIZE];
- char *p;
- uint err_length;
- strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
- p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
- err_length= (uint) (p - mysql->net.last_error);
- strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
- mysql->net.last_errno = error;
-}
-
-/*
- This function assumes we have just called SHOW SLAVE STATUS and have
- read the given result and row
-*/
-
-static my_bool get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
-{
- MYSQL* master;
- DBUG_ENTER("get_master");
- if (mysql_num_fields(res) < 3)
- DBUG_RETURN(1); /* safety */
-
- /* use the same username and password as the original connection */
- if (!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
- DBUG_RETURN(1);
- mysql->master = master;
- DBUG_RETURN(0);
-}
-
-
-/*
- Assuming we already know that mysql points to a master connection,
- retrieve all the slaves
-*/
-
-static my_bool get_slaves_from_master(MYSQL* mysql)
-{
- MYSQL_RES* res = 0;
- MYSQL_ROW row;
- my_bool error = 1;
- int has_auth_info;
- int port_ind;
- DBUG_ENTER("get_slaves_from_master");
-
- if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
- {
- expand_error(mysql, CR_PROBE_MASTER_CONNECT);
- DBUG_RETURN(1);
- }
- mysql->reconnect= 1;
-
- if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
- !(res = mysql_store_result(mysql)))
- {
- expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
- DBUG_RETURN(1);
- }
-
- switch (mysql_num_fields(res)) {
- case 5:
- has_auth_info = 0;
- port_ind=2;
- break;
- case 7:
- has_auth_info = 1;
- port_ind=4;
- break;
- default:
- goto err;
- }
-
- while ((row = mysql_fetch_row(res)))
- {
- MYSQL* slave;
- const char* tmp_user, *tmp_pass;
-
- if (has_auth_info)
- {
- tmp_user = row[2];
- tmp_pass = row[3];
- }
- else
- {
- tmp_user = mysql->user;
- tmp_pass = mysql->passwd;
- }
-
- if (!(slave = spawn_init(mysql, row[1], atoi(row[port_ind]),
- tmp_user, tmp_pass)))
- goto err;
-
- /* Now add slave into the circular linked list */
- slave->next_slave = mysql->next_slave;
- mysql->next_slave = slave;
- }
- error = 0;
-err:
- if (res)
- mysql_free_result(res);
- DBUG_RETURN(error);
-}
-
-
-my_bool STDCALL mysql_rpl_probe(MYSQL* mysql)
-{
- MYSQL_RES *res= 0;
- MYSQL_ROW row;
- my_bool error= 1;
- DBUG_ENTER("mysql_rpl_probe");
-
- /*
- First determine the replication role of the server we connected to
- the most reliable way to do this is to run SHOW SLAVE STATUS and see
- if we have a non-empty master host. This is still not fool-proof -
- it is not a sin to have a master that has a dormant slave thread with
- a non-empty master host. However, it is more reliable to check
- for empty master than whether the slave thread is actually running
- */
- if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
- !(res = mysql_store_result(mysql)))
- {
- expand_error(mysql, CR_PROBE_SLAVE_STATUS);
- DBUG_RETURN(1);
- }
-
- row= mysql_fetch_row(res);
- /*
- Check master host for emptiness/NULL
- For MySQL 4.0 it's enough to check for row[0]
- */
- if (row && row[0] && *(row[0]))
- {
- /* this is a slave, ask it for the master */
- if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
- goto err;
- }
- else
- {
- mysql->master = mysql;
- if (get_slaves_from_master(mysql))
- goto err;
- }
-
- error = 0;
-err:
- if (res)
- mysql_free_result(res);
- DBUG_RETURN(error);
-}
-
-
-/*
- Make a not so fool-proof decision on where the query should go, to
- the master or the slave. Ideally the user should always make this
- decision himself with mysql_master_query() or mysql_slave_query().
- However, to be able to more easily port the old code, we support the
- option of an educated guess - this should work for most applications,
- however, it may make the wrong decision in some particular cases. If
- that happens, the user would have to change the code to call
- mysql_master_query() or mysql_slave_query() explicitly in the place
- where we have made the wrong decision
-*/
-
-enum mysql_rpl_type
-STDCALL mysql_rpl_query_type(const char* q, int len)
-{
- const char *q_end= q + len;
- for (; q < q_end; ++q)
- {
- char c;
- if (my_isalpha(&my_charset_latin1, (c= *q)))
- {
- switch (my_tolower(&my_charset_latin1,c)) {
- case 'i': /* insert */
- case 'u': /* update or unlock tables */
- case 'l': /* lock tables or load data infile */
- case 'd': /* drop or delete */
- case 'a': /* alter */
- return MYSQL_RPL_MASTER;
- case 'c': /* create or check */
- return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
- MYSQL_RPL_MASTER;
- case 's': /* select or show */
- return my_tolower(&my_charset_latin1,q[1]) == 'h' ? MYSQL_RPL_ADMIN :
- MYSQL_RPL_SLAVE;
- case 'f': /* flush */
- case 'r': /* repair */
- case 'g': /* grant */
- return MYSQL_RPL_ADMIN;
- default:
- return MYSQL_RPL_SLAVE;
- }
- }
- }
- return MYSQL_RPL_MASTER; /* By default, send to master */
-}
-
/**************************************************************************
Connect to sql server
@@ -649,7 +332,7 @@ mysql_connect(MYSQL *mysql,const char *host,
if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
{
if (mysql->free_me)
- my_free((uchar*) mysql,MYF(0));
+ my_free(mysql);
}
mysql->reconnect= 1;
DBUG_RETURN(res);
@@ -662,44 +345,14 @@ mysql_connect(MYSQL *mysql,const char *host,
Change user and database
**************************************************************************/
-int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
-{
- NET *net= &mysql->net;
- ulong pkt_length;
-
- pkt_length= cli_safe_read(mysql);
-
- if (pkt_length == packet_error)
- return 1;
-
- if (pkt_length == 1 && net->read_pos[0] == 254 &&
- mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
- {
- /*
- By sending this very specific reply server asks us to send scrambled
- password in old format. The reply contains scramble_323.
- */
- scramble_323(buff, mysql->scramble, passwd);
- if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) ||
- net_flush(net))
- {
- set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
- return 1;
- }
- /* Read what server thinks about out new auth message report */
- if (cli_safe_read(mysql) == packet_error)
- return 1;
- }
- return 0;
-}
-
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
- char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
- char *end= buff;
int rc;
CHARSET_INFO *saved_cs= mysql->charset;
+ char *saved_user= mysql->user;
+ char *saved_passwd= mysql->passwd;
+ char *saved_db= mysql->db;
DBUG_ENTER("mysql_change_user");
@@ -713,49 +366,11 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* Use an empty string instead of NULL. */
- if (!user)
- user="";
- if (!passwd)
- passwd="";
-
- /*
- Store user into the buffer.
- Advance position as strmake returns a pointer to the closing NUL.
- */
- end= strmake(end, user, USERNAME_LENGTH) + 1;
-
- /* write scrambled password according to server capabilities */
- if (passwd[0])
- {
- if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
- {
- *end++= SCRAMBLE_LENGTH;
- scramble(end, mysql->scramble, passwd);
- end+= SCRAMBLE_LENGTH;
- }
- else
- {
- scramble_323(end, mysql->scramble, passwd);
- end+= SCRAMBLE_LENGTH_323 + 1;
- }
- }
- else
- *end++= '\0'; /* empty password */
- /* Add database if needed */
- end= strmake(end, db ? db : "", NAME_LEN) + 1;
-
- /* Add character set number. */
+ mysql->user= (char*)(user ? user : "");
+ mysql->passwd= (char*)(passwd ? passwd : "");
+ mysql->db= 0;
- if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
- {
- int2store(end, (ushort) mysql->charset->number);
- end+= 2;
- }
-
- /* Write authentication package */
- simple_command(mysql,COM_CHANGE_USER, (uchar*) buff, (ulong) (end-buff), 1);
-
- rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
+ rc= run_plugin_auth(mysql, 0, 0, 0, db);
/*
The server will close all statements no matter was the attempt
@@ -765,18 +380,21 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
if (rc == 0)
{
/* Free old connect information */
- 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(saved_user);
+ my_free(saved_passwd);
+ my_free(saved_db);
/* alloc new connect information */
- 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;
+ mysql->user= my_strdup(mysql->user, MYF(MY_WME));
+ mysql->passwd= my_strdup(mysql->passwd, MYF(MY_WME));
+ mysql->db= db ? my_strdup(db, MYF(MY_WME)) : 0;
}
else
{
mysql->charset= saved_cs;
+ mysql->user= saved_user;
+ mysql->passwd= saved_passwd;
+ mysql->db= saved_db;
}
DBUG_RETURN(rc);
@@ -787,15 +405,7 @@ struct passwd *getpwuid(uid_t);
char* getlogin(void);
#endif
-#if defined(__NETWARE__)
-/* Default to value of USER on NetWare, if unset use "UNKNOWN_USER" */
-void read_user_name(char *name)
-{
- char *str=getenv("USER");
- strmake(name, str ? str : "UNKNOWN_USER", USERNAME_LENGTH);
-}
-
-#elif !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__)
+#if !defined(__WIN__)
void read_user_name(char *name)
{
@@ -825,7 +435,7 @@ void read_user_name(char *name)
DBUG_VOID_RETURN;
}
-#else /* If MSDOS || VMS */
+#else /* If Windows */
void read_user_name(char *name)
{
@@ -867,7 +477,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
if ((*options->local_infile_init)(&li_ptr, net_filename,
options->local_infile_userdata))
{
- VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */
+ (void) my_net_write(net,(const uchar*) "",0); /* Server needs one packet */
net_flush(net);
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=
@@ -912,7 +522,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
err:
/* free up memory allocated with _init, usually */
(*options->local_infile_end)(li_ptr);
- my_free(buf, MYF(0));
+ my_free(buf);
DBUG_RETURN(result);
}
@@ -1023,7 +633,7 @@ static void default_local_infile_end(void *ptr)
{
if (data->fd >= 0)
my_close(data->fd, MYF(MY_WME));
- my_free(ptr, MYF(MY_WME));
+ my_free(ptr);
}
}
@@ -1095,68 +705,6 @@ mysql_query(MYSQL *mysql, const char *query)
}
-static MYSQL* spawn_init(MYSQL* parent, const char* host,
- unsigned int port, const char* user,
- const char* passwd)
-{
- MYSQL* child;
- DBUG_ENTER("spawn_init");
- if (!(child= mysql_init(0)))
- DBUG_RETURN(0);
-
- child->options.user= my_strdup((user) ? user :
- (parent->user ? parent->user :
- parent->options.user), MYF(0));
- child->options.password= my_strdup((passwd) ? passwd :
- (parent->passwd ?
- parent->passwd :
- parent->options.password), MYF(0));
- child->options.port= port;
- child->options.host= my_strdup((host) ? host :
- (parent->host ?
- parent->host :
- parent->options.host), MYF(0));
- if (parent->db)
- child->options.db= my_strdup(parent->db, MYF(0));
- else if (parent->options.db)
- child->options.db= my_strdup(parent->options.db, MYF(0));
-
- /*
- rpl_pivot is set to 1 in mysql_init(); Reset it as we are not doing
- replication here
- */
- child->rpl_pivot= 0;
- DBUG_RETURN(child);
-}
-
-
-int
-STDCALL mysql_set_master(MYSQL* mysql, const char* host,
- unsigned int port, const char* user,
- const char* passwd)
-{
- if (mysql->master != mysql && !mysql->master->rpl_pivot)
- mysql_close(mysql->master);
- if (!(mysql->master = spawn_init(mysql, host, port, user, passwd)))
- return 1;
- return 0;
-}
-
-
-int
-STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
- unsigned int port,
- const char* user,
- const char* passwd)
-{
- MYSQL* slave;
- if (!(slave = spawn_init(mysql, host, port, user, passwd)))
- return 1;
- slave->next_slave = mysql->next_slave;
- mysql->next_slave = slave;
- return 0;
-}
-
/**************************************************************************
Return next field of the query results
**************************************************************************/
@@ -1485,17 +1033,17 @@ MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res)
unsigned int STDCALL mysql_field_count(MYSQL *mysql)
{
- return mysql->last_used_con->field_count;
+ return mysql->field_count;
}
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
{
- return mysql->last_used_con->affected_rows;
+ return mysql->affected_rows;
}
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
{
- return mysql->last_used_con->insert_id;
+ return mysql->insert_id;
}
const char *STDCALL mysql_sqlstate(MYSQL *mysql)
@@ -1541,11 +1089,7 @@ void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo)
uint STDCALL mysql_thread_safe(void)
{
-#ifdef THREAD
return 1;
-#else
- return 0;
-#endif
}
@@ -1860,7 +1404,6 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
MYSQL_DATA *fields_data;
DBUG_ENTER("cli_read_prepare_result");
- mysql= mysql->last_used_con;
if ((packet_length= cli_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
mysql->warning_count= 0;
@@ -1942,11 +1485,16 @@ mysql_stmt_init(MYSQL *mysql)
MYSQL_STMT *stmt;
DBUG_ENTER("mysql_stmt_init");
- if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT),
+ if (!(stmt=
+ (MYSQL_STMT *) my_malloc(sizeof (MYSQL_STMT),
+ MYF(MY_WME | MY_ZEROFILL))) ||
+ !(stmt->extension=
+ (MYSQL_STMT_EXT *) my_malloc(sizeof (MYSQL_STMT_EXT),
MYF(MY_WME | MY_ZEROFILL))))
{
set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
- DBUG_RETURN(0);
+ my_free(stmt);
+ DBUG_RETURN(NULL);
}
init_alloc_root(&stmt->mem_root, 2048, 2048);
@@ -1961,6 +1509,8 @@ mysql_stmt_init(MYSQL *mysql)
strmov(stmt->sqlstate, not_error_sqlstate);
/* The rest of statement members was bzeroed inside malloc */
+ init_alloc_root(&stmt->extension->fields_mem_root, 2048, 0);
+
DBUG_RETURN(stmt);
}
@@ -2033,6 +1583,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
stmt->bind_param_done= stmt->bind_result_done= FALSE;
stmt->param_count= stmt->field_count= 0;
free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
+ free_root(&stmt->extension->fields_mem_root, MYF(0));
int4store(buff, stmt->stmt_id);
@@ -2093,19 +1644,21 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
static void alloc_stmt_fields(MYSQL_STMT *stmt)
{
MYSQL_FIELD *fields, *field, *end;
- MEM_ROOT *alloc= &stmt->mem_root;
- MYSQL *mysql= stmt->mysql->last_used_con;
+ MEM_ROOT *fields_mem_root= &stmt->extension->fields_mem_root;
+ MYSQL *mysql= stmt->mysql;
- stmt->field_count= mysql->field_count;
+ DBUG_ASSERT(stmt->field_count);
+
+ free_root(fields_mem_root, MYF(0));
/*
Get the field information for non-select statements
like SHOW and DESCRIBE commands
*/
- if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc,
+ if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(fields_mem_root,
sizeof(MYSQL_FIELD) *
stmt->field_count)) ||
- !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc,
+ !(stmt->bind= (MYSQL_BIND *) alloc_root(fields_mem_root,
sizeof(MYSQL_BIND) *
stmt->field_count)))
{
@@ -2117,18 +1670,39 @@ static void alloc_stmt_fields(MYSQL_STMT *stmt)
field= stmt->fields;
field && fields < end; fields++, field++)
{
- field->db = strdup_root(alloc,fields->db);
- field->table = strdup_root(alloc,fields->table);
- field->org_table= strdup_root(alloc,fields->org_table);
- field->name = strdup_root(alloc,fields->name);
- field->org_name = strdup_root(alloc,fields->org_name);
- field->charsetnr= fields->charsetnr;
- field->length = fields->length;
- field->type = fields->type;
- field->flags = fields->flags;
- field->decimals = fields->decimals;
- field->def = fields->def ? strdup_root(alloc,fields->def): 0;
- field->max_length= 0;
+ *field= *fields; /* To copy all numeric parts. */
+ field->catalog= strmake_root(fields_mem_root,
+ fields->catalog,
+ fields->catalog_length);
+ field->db= strmake_root(fields_mem_root,
+ fields->db,
+ fields->db_length);
+ field->table= strmake_root(fields_mem_root,
+ fields->table,
+ fields->table_length);
+ field->org_table= strmake_root(fields_mem_root,
+ fields->org_table,
+ fields->org_table_length);
+ field->name= strmake_root(fields_mem_root,
+ fields->name,
+ fields->name_length);
+ field->org_name= strmake_root(fields_mem_root,
+ fields->org_name,
+ fields->org_name_length);
+ if (fields->def)
+ {
+ field->def= strmake_root(fields_mem_root,
+ fields->def,
+ fields->def_length);
+ field->def_length= fields->def_length;
+ }
+ else
+ {
+ field->def= NULL;
+ field->def_length= 0;
+ }
+ field->extension= 0; /* Avoid dangling links. */
+ field->max_length= 0; /* max_length is set in mysql_stmt_store_result() */
}
}
@@ -2481,7 +2055,6 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
DBUG_ENTER("execute");
DBUG_DUMP("packet", (uchar *) packet, length);
- mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
buff[4]= (char) stmt->flags;
int4store(buff+5, 1); /* iteration count */
@@ -2580,7 +2153,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
}
result= execute(stmt, param_data, length);
stmt->send_types_to_server=0;
- my_free(param_data, MYF(MY_WME));
+ my_free(param_data);
DBUG_RETURN(result);
}
DBUG_RETURN((int) execute(stmt,0,0));
@@ -2845,6 +2418,9 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt)
prepared statements can't send result set metadata for these queries
on prepare stage. Read it now.
*/
+
+ stmt->field_count= stmt->mysql->field_count;
+
alloc_stmt_fields(stmt);
}
else
@@ -2862,12 +2438,39 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt)
previous branch always works.
TODO: send metadata only when it's really necessary and add a warning
'Metadata changed' when it's sent twice.
- */
+ */
update_stmt_fields(stmt);
}
}
+static void prepare_to_fetch_result(MYSQL_STMT *stmt)
+{
+ if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
+ {
+ stmt->mysql->status= MYSQL_STATUS_READY;
+ stmt->read_row_func= stmt_read_row_from_cursor;
+ }
+ else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
+ {
+ /*
+ 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.
+ */
+ mysql_stmt_store_result(stmt);
+ }
+ else
+ {
+ stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
+ stmt->unbuffered_fetch_cancelled= FALSE;
+ stmt->read_row_func= stmt_read_row_unbuffered;
+ }
+}
+
+
/*
Send placeholders data to server (if there are placeholders)
and execute prepared statement.
@@ -2935,28 +2538,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
if (mysql->field_count)
{
reinit_result_set_metadata(stmt);
- if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
- {
- mysql->status= MYSQL_STATUS_READY;
- stmt->read_row_func= stmt_read_row_from_cursor;
- }
- else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
- {
- /*
- 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.
- */
- mysql_stmt_store_result(stmt);
- }
- else
- {
- stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
- stmt->unbuffered_fetch_cancelled= FALSE;
- stmt->read_row_func= stmt_read_row_unbuffered;
- }
+ prepare_to_fetch_result(stmt);
}
DBUG_RETURN(test(stmt->last_errno));
}
@@ -3754,12 +3336,13 @@ static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
param output buffer descriptor
field column metadata
value column data
- width default number of significant digits used when converting
- float/double to string
+ type either MY_GCVT_ARG_FLOAT or MY_GCVT_ARG_DOUBLE.
+ Affects the maximum number of significant digits
+ returned by my_gcvt().
*/
static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
- double value, int width)
+ double value, my_gcvt_arg_type type)
{
char *buffer= (char *)param->buffer;
double val64 = (value < 0 ? -floor(-value) : floor(value));
@@ -3843,42 +3426,24 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
floating point -> string conversion nicely, honor all typecodes
and param->offset possibly set in mysql_stmt_fetch_column
*/
- char buff[MAX_DOUBLE_STRING_REP_LENGTH];
- char *end;
- /* TODO: move this to a header shared between client and server. */
-#define NOT_FIXED_DEC 31
+ char buff[FLOATING_POINT_BUFFER];
+ size_t len;
if (field->decimals >= NOT_FIXED_DEC)
-#undef NOT_FIXED_DEC
- {
- /*
- DBL_DIG below is to ensure that the server and client has the same
- precisions. This will ensure that on the same machine you get the
- same value as a string independent of the protocol you use.
- */
- sprintf(buff, "%-*.*g", (int) min(sizeof(buff)-1,
- param->buffer_length),
- min(DBL_DIG, width), value);
- end= strcend(buff, ' ');
- *end= 0;
- }
+ len= my_gcvt(value, type,
+ (int) min(sizeof(buff)-1, param->buffer_length),
+ buff, NULL);
else
- {
- sprintf(buff, "%.*f", (int) field->decimals, value);
- end= strend(buff);
- }
+ len= my_fcvt(value, (int) field->decimals, buff, NULL);
+ if (field->flags & ZEROFILL_FLAG && len < field->length &&
+ field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1)
{
- size_t length= end - buff;
- if (field->flags & ZEROFILL_FLAG && length < field->length &&
- field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1)
- {
- bmove_upp((uchar*) buff + field->length, (uchar*) buff + length,
- length);
- bfill((char*) buff, field->length - length, '0');
- length= field->length;
- }
- fetch_string_with_conversion(param, buff, length);
+ bmove_upp((uchar*) buff + field->length, (uchar*) buff + len,
+ len);
+ bfill((char*) buff, field->length - len, '0');
+ len= field->length;
}
+ fetch_string_with_conversion(param, buff, len);
break;
}
@@ -3923,7 +3488,7 @@ static void fetch_datetime_with_conversion(MYSQL_BIND *param,
{
ulonglong value= TIME_to_ulonglong(my_time);
fetch_float_with_conversion(param, field,
- ulonglong2double(value), DBL_DIG);
+ ulonglong2double(value), MY_GCVT_ARG_DOUBLE);
break;
}
case MYSQL_TYPE_TINY:
@@ -4017,7 +3582,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
{
float value;
float4get(value,*row);
- fetch_float_with_conversion(param, field, value, FLT_DIG);
+ fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_FLOAT);
*row+= 4;
break;
}
@@ -4025,7 +3590,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
{
double value;
float8get(value,*row);
- fetch_float_with_conversion(param, field, value, DBL_DIG);
+ fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_DOUBLE);
*row+= 8;
break;
}
@@ -4708,7 +4273,6 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
}
net = &mysql->net;
- mysql= mysql->last_used_con;
while ((pkt_len= cli_safe_read(mysql)) != packet_error)
{
@@ -4806,8 +4370,6 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
DBUG_RETURN(1);
}
- mysql= mysql->last_used_con;
-
if (!stmt->field_count)
DBUG_RETURN(0);
@@ -5014,7 +4576,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
if (stmt->field_count && mysql->status != MYSQL_STATUS_READY)
{
/* There is a result set and it belongs to this statement */
- (*mysql->methods->flush_use_result)(mysql);
+ (*mysql->methods->flush_use_result)(mysql, FALSE);
if (mysql->unbuffered_fetch_owner)
*mysql->unbuffered_fetch_owner= TRUE;
mysql->status= MYSQL_STATUS_READY;
@@ -5077,6 +4639,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
free_root(&stmt->result.alloc, MYF(0));
free_root(&stmt->mem_root, MYF(0));
+ free_root(&stmt->extension->fields_mem_root, MYF(0));
if (mysql)
{
@@ -5098,7 +4661,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
Flush result set of the connection. If it does not belong
to this statement, set a warning.
*/
- (*mysql->methods->flush_use_result)(mysql);
+ (*mysql->methods->flush_use_result)(mysql, TRUE);
if (mysql->unbuffered_fetch_owner)
*mysql->unbuffered_fetch_owner= TRUE;
mysql->status= MYSQL_STATUS_READY;
@@ -5111,7 +4674,8 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
}
}
- my_free((uchar*) stmt, MYF(MY_WME));
+ my_free(stmt->extension);
+ my_free(stmt);
DBUG_RETURN(test(rc));
}
@@ -5217,8 +4781,7 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql)
my_bool res;
DBUG_ENTER("mysql_more_results");
- res= ((mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) ?
- 1: 0);
+ res= ((mysql->server_status & SERVER_MORE_RESULTS_EXISTS) ? 1: 0);
DBUG_PRINT("exit",("More results exists ? %d", res));
DBUG_RETURN(res);
}
@@ -5240,13 +4803,56 @@ int STDCALL mysql_next_result(MYSQL *mysql)
net_clear_error(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
- if (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS)
+ if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
DBUG_RETURN((*mysql->methods->next_result)(mysql));
DBUG_RETURN(-1); /* No more results */
}
+int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
+{
+ MYSQL *mysql= stmt->mysql;
+ int rc;
+ DBUG_ENTER("mysql_stmt_next_result");
+
+ if (!mysql)
+ DBUG_RETURN(1);
+
+ if (stmt->last_errno)
+ DBUG_RETURN(stmt->last_errno);
+
+ if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
+ {
+ if (reset_stmt_handle(stmt, RESET_STORE_RESULT))
+ DBUG_RETURN(1);
+ }
+
+ rc= mysql_next_result(mysql);
+
+ if (rc)
+ {
+ set_stmt_errmsg(stmt, &mysql->net);
+ DBUG_RETURN(rc);
+ }
+
+ if (mysql->status == MYSQL_STATUS_GET_RESULT)
+ mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
+
+ stmt->state= MYSQL_STMT_EXECUTE_DONE;
+ stmt->bind_result_done= FALSE;
+ stmt->field_count= mysql->field_count;
+
+ if (mysql->field_count)
+ {
+ alloc_stmt_fields(stmt);
+ prepare_to_fetch_result(stmt);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql)
{
return (*mysql->methods->use_result)(mysql);
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
index 81f86dc8726..ce85d2a4086 100644
--- a/libmysql/libmysql.def
+++ b/libmysql/libmysql.def
@@ -1,33 +1,7 @@
LIBRARY LIBMYSQL
VERSION 6.0
EXPORTS
- _dig_vec_lower
- _dig_vec_upper
- bmove_upp
- delete_dynamic
- free_defaults
- getopt_compare_strings
- getopt_ull_limit_value
- handle_options
- init_dynamic_array
- insert_dynamic
- int2str
- is_prefix
- list_add
- list_delete
load_defaults
- my_end
- my_getopt_print_errors
- my_init
- my_malloc
- my_memdup
- my_no_flags_free
- my_path
- mysql_get_parameters
- my_print_help
- my_print_variables
- my_realloc
- my_strdup
mysql_thread_end
mysql_thread_init
myodbc_remove_escape
@@ -117,37 +91,16 @@ EXPORTS
mysql_stmt_sqlstate
mysql_sqlstate
mysql_get_server_version
- set_dynamic
- strcend
- strcont
- strdup_root
- strfill
- strinstr
- strmake
- strmov
- strxmov
mysql_stmt_prepare
mysql_stmt_init
mysql_stmt_insert_id
mysql_stmt_attr_get
mysql_stmt_attr_set
mysql_stmt_field_count
- client_errors
mysql_set_local_infile_default
mysql_set_local_infile_handler
- mysql_disable_reads_from_master
- mysql_disable_rpl_parse
- mysql_enable_reads_from_master
- mysql_enable_rpl_parse
- mysql_master_query
- mysql_rpl_parse_enabled
- mysql_rpl_probe
- mysql_rpl_query_type
- mysql_slave_query
mysql_embedded
mysql_server_init
mysql_server_end
mysql_set_character_set
mysql_get_character_set_info
- get_defaults_options
- modify_defaults_file
diff --git a/libmysql/manager.c b/libmysql/manager.c
deleted file mode 100644
index 335323cb31d..00000000000
--- a/libmysql/manager.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* Copyright (c) 2001-2004, 2006-2008 MySQL AB, 2009 Sun Microsystems, Inc.
- Use is subject to license terms.
-
- 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.
-
- There are special exceptions to the terms and conditions of the GPL as it
- is applied to this software.
-
- 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>
-#if defined(THREAD)
-#include <my_pthread.h> /* because of signal() */
-#endif
-#include "mysql.h"
-#include "mysql_version.h"
-#include "mysqld_error.h"
-#include <my_sys.h>
-#include <mysys_err.h>
-#include <m_string.h>
-#include <m_ctype.h>
-#include <my_net.h>
-#include <errmsg.h>
-#include <violite.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <errno.h>
-
-#if defined(__NETWARE__)
-#include <netdb.h>
-#include <sys/select.h>
-#include <sys/utsname.h>
-#elif !defined( __WIN__)
-#include <sys/resource.h>
-#ifdef HAVE_SYS_UN_H
-# include <sys/un.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_SELECT_H
-# include <select.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#include <sys/utsname.h>
-#endif /* __WIN__ */
-
-#ifndef INADDR_NONE
-#define INADDR_NONE -1
-#endif
-
-#define RES_BUF_SHIFT 5
-#define NET_BUF_SIZE 2048
-
-MYSQL_MANAGER* STDCALL mysql_manager_init(MYSQL_MANAGER* con)
-{
- int net_buf_size=NET_BUF_SIZE;
- if (!con)
- {
- if (!(con=(MYSQL_MANAGER*)my_malloc(sizeof(*con)+net_buf_size,
- MYF(MY_WME|MY_ZEROFILL))))
- return 0;
- con->free_me=1;
- con->net_buf=(char*)con+sizeof(*con);
- }
- else
- {
- bzero((char*)con,sizeof(*con));
- if (!(con->net_buf=my_malloc(net_buf_size,MYF(0))))
- return 0;
- }
- con->net_buf_pos=con->net_data_end=con->net_buf;
- con->net_buf_size=net_buf_size;
- return con;
-}
-
-MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
- const char* host,
- const char* user,
- const char* passwd,
- unsigned int port)
-{
- my_socket sock;
- struct sockaddr_in sock_addr;
- in_addr_t ip_addr;
- char msg_buf[MAX_MYSQL_MANAGER_MSG];
- int msg_len;
- Vio* vio;
- my_bool not_used;
-
- if (!host)
- host="localhost";
- if (!user)
- user="root";
- if (!passwd)
- passwd="";
-
- if ((sock=(my_socket)socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
- {
- con->last_errno=errno;
- strmov(con->last_error,"Cannot create socket");
- goto err;
- }
- if (!(vio=vio_new(sock,VIO_TYPE_TCPIP,FALSE)))
- {
- con->last_errno=ENOMEM;
- strmov(con->last_error,"Cannot create network I/O object");
- goto err;
- }
- vio_blocking(vio, TRUE, &not_used);
- my_net_init(&con->net,vio);
- bzero((char*) &sock_addr,sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- 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)
- {
- con->last_errno=tmp_errno;
- sprintf(con->last_error,"Could not resolve host '%-.64s'",host);
- my_gethostbyname_r_free();
- goto err;
- }
- 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 (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
- 0))
- {
- con->last_errno=errno;
- sprintf(con->last_error ,"Could not connect to %-.64s", host);
- goto err;
- }
- /* read the greating */
- if (my_net_read(&con->net) == packet_error)
- {
- con->last_errno=errno;
- strmov(con->last_error,"Read error on socket");
- goto err;
- }
- sprintf(msg_buf,"%-.16s %-.16s\n",user,passwd);
- msg_len=strlen(msg_buf);
- if (my_net_write(&con->net,(uchar*) msg_buf,msg_len) || net_flush(&con->net))
- {
- con->last_errno=con->net.last_errno;
- strmov(con->last_error,"Write error on socket");
- goto err;
- }
- if (my_net_read(&con->net) == packet_error)
- {
- con->last_errno=errno;
- strmov(con->last_error,"Read error on socket");
- goto err;
- }
- if ((con->cmd_status=atoi((char*) con->net.read_pos)) != MANAGER_OK)
- {
- strmov(con->last_error,"Access denied");
- goto err;
- }
- if (!my_multi_malloc(MYF(0), &con->host, (uint)strlen(host)+1,
- &con->user, (uint)strlen(user)+1,
- &con->passwd, (uint)strlen(passwd)+1,
- NullS))
- {
- con->last_errno=ENOMEM;
- strmov(con->last_error,"Out of memory");
- goto err;
- }
- strmov(con->host,host);
- strmov(con->user,user);
- strmov(con->passwd,passwd);
- return con;
-
-err:
- {
- my_bool free_me=con->free_me;
- con->free_me=0;
- mysql_manager_close(con);
- con->free_me=free_me;
- }
- return 0;
-}
-
-void STDCALL mysql_manager_close(MYSQL_MANAGER* con)
-{
- /*
- No need to free con->user and con->passwd, because they were
- allocated in my_multimalloc() along with con->host, freeing
- con->hosts frees the whole block
- */
- my_free((uchar*)con->host,MYF(MY_ALLOW_ZERO_PTR));
- net_end(&con->net);
- if (con->free_me)
- my_free((uchar*)con,MYF(0));
-}
-
-
-int STDCALL mysql_manager_command(MYSQL_MANAGER* con,const char* cmd,
- int cmd_len)
-{
- if (!cmd_len)
- cmd_len=strlen(cmd);
- if (my_net_write(&con->net,(const uchar*)cmd,cmd_len) || net_flush(&con->net))
- {
- con->last_errno=errno;
- strmov(con->last_error,"Write error on socket");
- return 1;
- }
- con->eof=0;
- return 0;
-}
-
-
-int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, char* res_buf,
- int res_buf_size)
-{
- char* res_buf_end=res_buf+res_buf_size;
- char* net_buf=(char*) con->net.read_pos, *net_buf_end;
- int res_buf_shift=RES_BUF_SHIFT;
- ulong num_bytes;
-
- if (res_buf_size<RES_BUF_SHIFT)
- {
- con->last_errno=ENOMEM;
- strmov(con->last_error,"Result buffer too small");
- return 1;
- }
-
- if ((num_bytes=my_net_read(&con->net)) == packet_error)
- {
- con->last_errno=errno;
- strmov(con->last_error,"socket read failed");
- return 1;
- }
-
- net_buf_end=net_buf+num_bytes;
-
- if ((con->eof=(net_buf[3]==' ')))
- res_buf_shift--;
- net_buf+=res_buf_shift;
- res_buf_end[-1]=0;
- for (;net_buf<net_buf_end && res_buf < res_buf_end;res_buf++,net_buf++)
- {
- if ((*res_buf=*net_buf) == '\r')
- {
- *res_buf=0;
- break;
- }
- }
- return 0;
-}