diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d21bd6f..b8e45c18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ # This is the LGPL libmariadb project. PROJECT(mariadb-connector-c C) +SET(PACKAGE_STATUS_SUFFIX "alpha") + SET(CPACK_PACKAGE_VERSION_MAJOR 3) SET(CPACK_PACKAGE_VERSION_MINOR 0) SET(CPACK_PACKAGE_VERSION_PATCH 0) @@ -154,6 +156,10 @@ IF(CMAKE_HAVE_PTHREAD_H) SET(CMAKE_REQUIRED_INCLUDES pthread.h) ENDIF() +IF(DBUG_OFF) + ADD_DEFINITIONS(-DDBUG_OFF=1) +ENDIF() + IF(WIN32) SET(HAVE_THREADS 1) ADD_DEFINITIONS(-DHAVE_DLOPEN) @@ -271,12 +277,16 @@ SET(CPACK_PACKAGE_VENDOR "MariaDB Corporation Ab") SET(CPACK_PACKAGE_DESCRIPTION "MariaDB Connector/C. A library for connecting to MariaDB and MySQL servers") SET(CPACK_PACKAGE_NAME "mariadb_connector_c") STRING(TOLOWER ${CMAKE_SYSTEM_NAME} system_name) -SET(CPACK_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-${system_name}-${CMAKE_SYSTEM_PROCESSOR}") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING.LIB") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") INCLUDE(cmake/ConnectorName.cmake) -SET(CPACK_SOURCE_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-src") - +IF(NOT PACKAGE_STATUS_SUFFIX) + SET(CPACK_SOURCE_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-src") + SET(CPACK_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-${system_name}-${CMAKE_SYSTEM_PROCESSOR}") +ELSE() + SET(CPACK_SOURCE_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-${PACKAGE_STATUS_SUFFIX}-src") + SET(CPACK_PACKAGE_FILE_NAME "mariadb-connector-c-${CPACK_PACKAGE_VERSION}-${PACKAGE_STATUS_SUFFIX}-${system_name}-${CMAKE_SYSTEM_PROCESSOR}") +ENDIF() # Build source packages IF(GIT_BUILD_SRCPKG) # get branch name @@ -285,10 +295,10 @@ IF(GIT_BUILD_SRCPKG) STRING(REGEX REPLACE "\\[|\\]" "" GIT_BRANCH ${git_branch}) MESSAGE(STATUS "${GIT_BRANCH}") IF(WIN32) - EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=zip --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.zip) + EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=zip --prefix=${CPACK_SOURCE_PACKAGE_FILE_NAME}/ --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.zip) ELSE() - EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=zip --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.zip) - EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=tar --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar) + EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=zip --prefix=${CPACK_SOURCE_PACKAGE_FILE_NAME}/ --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.zip) + EXECUTE_PROCESS(COMMAND git archive ${GIT_BRANCH} --format=tar --prefix=${CPACK_SOURCE_PACKAGE_FILE_NAME}/ --output=${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar) EXECUTE_PROCESS(COMMAND gzip -9 -f ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar) ENDIF() ENDIF() diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..89566c92 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,29 @@ +version: 3.0.0.{build} +branches: + only: + - master +os: Visual Studio 2015 +configuration: RelWithDebInfo +platform: x64 +clone_folder: c:\projects\mariadb-connector-c +environment: + MYSQL_TEST_USER: root + MYSQL_TEST_HOST: 127.0.0.1 + MYSQL_TEST_PASSWD: Password12! +services: mysql56 +before_build: +- ps: >- + cd c:\projects\mariadb-connector-c + + echo running cmake + + cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=RelWithDebInfo +build: + project: mariadb-connector-c.sln + parallel: true + verbosity: minimal +test_script: +- cmd: >- + cd c:\projects\mariadb-connector-c\unittest\libmariadb + + ctest -V diff --git a/cmake/plugins.cmake b/cmake/plugins.cmake index 47e15597..a68bd509 100644 --- a/cmake/plugins.cmake +++ b/cmake/plugins.cmake @@ -1,12 +1,16 @@ # plugin configuration MACRO(REGISTER_PLUGIN name source struct type target allow) + SET(PLUGIN_TYPE ${${name}}) + IF(NOT PLUGIN_TYPE STREQUAL "OFF") + SET(PLUGIN_TYPE ${type}) + ENDIF() IF(PLUGINS) LIST(REMOVE_ITEM PLUGINS ${name}) ENDIF() SET(${name}_PLUGIN_SOURCE ${source}) MARK_AS_ADVANCED(${name}_PLUGIN_SOURCE}) - SET(${name}_PLUGIN_TYPE ${type}) + SET(${name}_PLUGIN_TYPE ${PLUGIN_TYPE}) IF(NOT ${target} STREQUAL "") SET(${name}_PLUGIN_TARGET ${target}) ENDIF() @@ -40,7 +44,8 @@ ENDIF() REGISTER_PLUGIN("TRACE_EXAMPLE" "${CMAKE_SOURCE_DIR}/plugins/trace/trace_example.c" "trace_example_plugin" "DYNAMIC" "trace_example" 1) #Connection -REGISTER_PLUGIN("REPLICATION" "${CMAKE_SOURCE_DIR}/plugins/connection/replication.c" "connection_replication_plugin" "STATIC" "" 1) +REGISTER_PLUGIN("REPLICATION" "${CMAKE_SOURCE_DIR}/plugins/connection/replication.c" "connection_replication_plugin" "DYNAMIC" "" 1) +REGISTER_PLUGIN("AURORA" "${CMAKE_SOURCE_DIR}/plugins/connection/aurora.c" "connection_aurora_plugin" "DYNAMIC" "" 1) # Allow registration of additional plugins IF(PLUGIN_CONF_FILE) @@ -50,7 +55,7 @@ ENDIF() SET(LIBMARIADB_SOURCES "") -MESSAGE(STATUS "Plugin configuration") +MESSAGE(STATUS "Plugin configuration:") FOREACH(PLUGIN ${PLUGINS}) IF(WITH_${PLUGIN}_PLUGIN AND ${${PLUGIN}_PLUGIN_CHG} GREATER 0) SET(${PLUGIN}_PLUGIN_TYPE ${WITH_${PLUGIN}_PLUGIN}) @@ -72,6 +77,6 @@ ENDIF() LIST(REMOVE_DUPLICATES LIBMARIADB_SOURCES) CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/libmariadb/client_plugin.c.in - ${CMAKE_BINARY_DIR}/libmariadb/client_plugin.c) + ${CMAKE_BINARY_DIR}/libmariadb/client_plugin.c) MARK_AS_ADVANCED(LIBMARIADB_SOURCES) diff --git a/include/errmsg.h b/include/errmsg.h index 8a91519a..0af17b20 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -84,7 +84,8 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_EVENT_CREATE_FAILED 5000 #define CR_BIND_ADDR_FAILED 5001 -#define CR_FUNCTION_NOT_SUPPORTED 5002 +#define CR_ASYNC_NOT_SUPPORTED 5002 +#define CR_FUNCTION_NOT_SUPPORTED 5003 #define SQLSTATE_UNKNOWN "HY000" diff --git a/include/ma_common.h b/include/ma_common.h index 6d61f1f0..ff5837f9 100644 --- a/include/ma_common.h +++ b/include/ma_common.h @@ -48,12 +48,15 @@ struct st_mysql_options_extension { double progress, const char *proc_info, unsigned int proc_info_length); - MARIADB_DB_DRIVER *db_driver; + MARIADB_DB_DRIVER *db_driver; char *ssl_fp; /* finger print of server certificate */ char *ssl_fp_list; /* white list of finger prints */ char *ssl_pw; /* password for encrypted certificates */ my_bool multi_command; /* indicates if client wants to send multiple commands in one packet */ + char *url; /* for connection handler we need to save URL for reconnect */ + my_bool read_only; + HASH userdata; }; #define OPT_HAS_EXT_VAL(a,key) \ diff --git a/include/ma_pvio.h b/include/ma_pvio.h index 0fada961..7ac4be94 100644 --- a/include/ma_pvio.h +++ b/include/ma_pvio.h @@ -50,7 +50,8 @@ enum enum_pvio_io_event enum enum_pvio_type { PVIO_TYPE_UNIXSOCKET= 0, PVIO_TYPE_SOCKET, - PVIO_TYPE_NAMEDPIPE + PVIO_TYPE_NAMEDPIPE, + PVIO_TYPE_SHAREDMEM, }; enum enum_pvio_operation { diff --git a/include/ma_ssl.h b/include/ma_ssl.h index ded44e3e..b994f08c 100644 --- a/include/ma_ssl.h +++ b/include/ma_ssl.h @@ -16,6 +16,11 @@ typedef struct st_ma_pvio_ssl { void *ssl; } MARIADB_SSL; +struct st_ssl_version { + unsigned int iversion; + char *cversion; +}; + /* Function prototypes */ /* ma_ssl_start @@ -124,6 +129,17 @@ const char *ma_ssl_get_cipher(MARIADB_SSL *ssl); */ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsigned int fp_len); +/* ma_ssl_get_protocol_version + returns protocol version in use + Parameter: + MARIADB_SSL MariaDB SSL container + version pointer to ssl version info + Returns: + 0 success + 1 error +*/ +my_bool ma_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version); + /* Function prototypes */ MARIADB_SSL *ma_pvio_ssl_init(MYSQL *mysql); my_bool ma_pvio_ssl_connect(MARIADB_SSL *cssl); @@ -134,5 +150,6 @@ int ma_pvio_ssl_verify_server_cert(MARIADB_SSL *cssl); const char *ma_pvio_ssl_cipher(MARIADB_SSL *cssl); my_bool ma_pvio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_list); my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio); +my_bool ma_pvio_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version); #endif /* _ma_ssl_h_ */ diff --git a/include/my_context.h b/include/my_context.h index 591a064a..b66482a4 100644 --- a/include/my_context.h +++ b/include/my_context.h @@ -112,7 +112,6 @@ struct my_context { }; #endif - /* Initialize an asynchroneous context object. Returns 0 on success, non-zero on failure. diff --git a/include/my_stmt.h b/include/my_stmt.h index 77046caf..0dfb1ba1 100644 --- a/include/my_stmt.h +++ b/include/my_stmt.h @@ -165,6 +165,7 @@ struct st_mysqlnd_stmt_methods my_bool (*get_attribute)(const MYSQL_STMT * stmt, enum enum_stmt_attr_type attr_type, const void * value); my_bool (*set_attribute)(const MYSQL_STMT * stmt, enum enum_stmt_attr_type attr_type, const void * value); + void (*set_error)(MYSQL_STMT *stmt, unsigned int error_nr, const char *sqlstate, const char *format, ...); }; typedef int (*mysql_stmt_fetch_row_func)(MYSQL_STMT *stmt, unsigned char **row); diff --git a/include/mysql.h b/include/mysql.h index b262af85..57d4da76 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -215,7 +215,38 @@ extern unsigned int mariadb_deinitialize_ssl; MARIADB_OPT_SSL_FP_LIST, /* finger print white list for server certificate verification */ MARIADB_OPT_SSL_PASSWORD, /* password for encrypted certificates */ MARIADB_OPT_COM_MULTI, - MARIADB_OPT_CONNECTION_READ_ONLY + MARIADB_OPT_CONNECTION_READ_ONLY, + MYSQL_OPT_CONNECT_ATTRS, /* for mysql_get_optionv */ + MARIADB_OPT_USERDATA + }; + + enum mariadb_value { + MARIADB_CHARSET_ID, + MARIADB_CHARSET_INFO, + MARIADB_CHARSET_NAME, + MARIADB_CLIENT_ERRORS, + MARIADB_CLIENT_VERSION, + MARIADB_CLIENT_VERSION_ID, + MARIADB_CONNECTION_ASYNC_TIMEOUT, + MARIADB_CONNECTION_ASYNC_TIMEOUT_MS, + MARIADB_CONNECTION_HOST, + MARIADB_CONNECTION_INFO, + MARIADB_CONNECTION_PORT, + MARIADB_CONNECTION_PROTOCOL_VERSION_ID, + MARIADB_CONNECTION_PVIO_TYPE, + MARIADB_CONNECTION_SCHEMA, + MARIADB_CONNECTION_SERVER_TYPE, + MARIADB_CONNECTION_SERVER_VERSION, + MARIADB_CONNECTION_SERVER_VERSION_ID, + MARIADB_CONNECTION_SOCKET, + MARIADB_CONNECTION_SSL_CIPHER, + MARIADB_CONNECTION_SSL_VERSION, + MARIADB_CONNECTION_SSL_VERSION_ID, + MARIADB_CONNECTION_TYPE, + MARIADB_CONNECTION_UNIX_SOCKET, + MARIADB_CONNECTION_USER, + MARIADB_MAX_ALLOWED_PACKET, + MARIADB_NET_BUFFER_LENGTH }; enum mysql_status { MYSQL_STATUS_READY, @@ -407,12 +438,13 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql); void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs); int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); +my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...); +my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg); MYSQL * STDCALL mysql_init(MYSQL *mysql); int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); -int STDCALL mysql_ssl_clear(MYSQL *mysql); MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, @@ -471,7 +503,6 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, void STDCALL mysql_debug(const char *debug); #define mysql_debug_init(A) mysql_debug((A)); void STDCALL mysql_debug_end(void); -void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_sqlstate(MYSQL *mysql); @@ -485,16 +516,19 @@ const char * STDCALL mysql_get_client_info(void); unsigned long STDCALL mysql_get_client_version(void); my_bool STDCALL mariadb_connection(MYSQL *mysql); const char * STDCALL mysql_get_server_name(MYSQL *mysql); -CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *csname); -CHARSET_INFO * STDCALL mysql_get_charset_by_nr(unsigned int csnr); +CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname); +CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr); size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs, char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode); int STDCALL mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...); +int STDCALL mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...); +int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg); MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); unsigned long STDCALL mysql_hex_string(char *to, const char *from, size_t len); -my_socket STDCALL mysql_get_socket(const MYSQL *mysql); +my_socket STDCALL mysql_get_socket(MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value_ms(const MYSQL *mysql); +my_bool STDCALL mysql_reconnect(MYSQL *mysql); /* Async API */ int STDCALL mysql_close_start(MYSQL *sock); @@ -607,6 +641,128 @@ int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt, int status); +/* API function calls (used by dynmic plugins) */ +struct st_mariadb_api { + my_ulonglong (STDCALL *mysql_num_rows)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_num_fields)(MYSQL_RES *res); + my_bool (STDCALL *mysql_eof)(MYSQL_RES *res); + MYSQL_FIELD *(STDCALL *mysql_fetch_field_direct)(MYSQL_RES *res, unsigned int fieldnr); + MYSQL_FIELD * (STDCALL *mysql_fetch_fields)(MYSQL_RES *res); + MYSQL_ROWS * (STDCALL *mysql_row_tell)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_field_tell)(MYSQL_RES *res); + unsigned int (STDCALL *mysql_field_count)(MYSQL *mysql); + my_bool (STDCALL *mysql_more_results)(MYSQL *mysql); + int (STDCALL *mysql_next_result)(MYSQL *mysql); + my_ulonglong (STDCALL *mysql_affected_rows)(MYSQL *mysql); + my_bool (STDCALL *mysql_autocommit)(MYSQL *mysql, my_bool mode); + my_bool (STDCALL *mysql_commit)(MYSQL *mysql); + my_bool (STDCALL *mysql_rollback)(MYSQL *mysql); + my_ulonglong (STDCALL *mysql_insert_id)(MYSQL *mysql); + unsigned int (STDCALL *mysql_errno)(MYSQL *mysql); + char * (STDCALL *mysql_error)(MYSQL *mysql); + char * (STDCALL *mysql_info)(MYSQL *mysql); + unsigned long (STDCALL *mysql_thread_id)(MYSQL *mysql); + const char * (STDCALL *mysql_character_set_name)(MYSQL *mysql); + void (STDCALL *mysql_get_character_set_info)(MYSQL *mysql, MY_CHARSET_INFO *cs); + int (STDCALL *mysql_set_character_set)(MYSQL *mysql, const char *csname); + my_bool (STDCALL *mariadb_get_infov)(MYSQL *mysql, enum mariadb_value value, void *arg, ...); + my_bool (STDCALL *mariadb_get_info)(MYSQL *mysql, enum mariadb_value value, void *arg); + MYSQL * (STDCALL *mysql_init)(MYSQL *mysql); + int (STDCALL *mysql_ssl_set)(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); + const char * (STDCALL *mysql_get_ssl_cipher)(MYSQL *mysql); + MYSQL * (STDCALL *mysql_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd); + my_bool (STDCALL *mysql_change_user)(MYSQL *mysql, const char *user, const char *passwd, const char *db); + MYSQL * (STDCALL *mysql_real_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); + void (STDCALL *mysql_close)(MYSQL *sock); + int (STDCALL *mysql_select_db)(MYSQL *mysql, const char *db); + int (STDCALL *mysql_query)(MYSQL *mysql, const char *q); + int (STDCALL *mysql_send_query)(MYSQL *mysql, const char *q, size_t length); + my_bool (STDCALL *mysql_read_query_result)(MYSQL *mysql); + int (STDCALL *mysql_real_query)(MYSQL *mysql, const char *q, size_t length); + int (STDCALL *mysql_create_db)(MYSQL *mysql, const char *DB); + int (STDCALL *mysql_drop_db)(MYSQL *mysql, const char *DB); + int (STDCALL *mysql_shutdown)(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); + int (STDCALL *mysql_dump_debug_info)(MYSQL *mysql); + int (STDCALL *mysql_refresh)(MYSQL *mysql, unsigned int refresh_options); + int (STDCALL *mysql_kill)(MYSQL *mysql,unsigned long pid); + int (STDCALL *mysql_ping)(MYSQL *mysql); + char * (STDCALL *mysql_stat)(MYSQL *mysql); + char * (STDCALL *mysql_get_server_info)(MYSQL *mysql); + unsigned long (STDCALL *mysql_get_server_version)(MYSQL *mysql); + char * (STDCALL *mysql_get_host_info)(MYSQL *mysql); + unsigned int (STDCALL *mysql_get_proto_info)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_list_dbs)(MYSQL *mysql,const char *wild); + MYSQL_RES * (STDCALL *mysql_list_tables)(MYSQL *mysql,const char *wild); + MYSQL_RES * (STDCALL *mysql_list_fields)(MYSQL *mysql, const char *table, const char *wild); + MYSQL_RES * (STDCALL *mysql_list_processes)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_store_result)(MYSQL *mysql); + MYSQL_RES * (STDCALL *mysql_use_result)(MYSQL *mysql); + int (STDCALL *mysql_options)(MYSQL *mysql,enum mysql_option option, const void *arg); + void (STDCALL *mysql_free_result)(MYSQL_RES *result); + void (STDCALL *mysql_data_seek)(MYSQL_RES *result, my_ulonglong offset); + MYSQL_ROW_OFFSET (STDCALL *mysql_row_seek)(MYSQL_RES *result, MYSQL_ROW_OFFSET); + MYSQL_FIELD_OFFSET (STDCALL *mysql_field_seek)(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); + MYSQL_ROW (STDCALL *mysql_fetch_row)(MYSQL_RES *result); + unsigned long * (STDCALL *mysql_fetch_lengths)(MYSQL_RES *result); + MYSQL_FIELD * (STDCALL *mysql_fetch_field)(MYSQL_RES *result); + unsigned long (STDCALL *mysql_escape_string)(char *to,const char *from, unsigned long from_length); + unsigned long (STDCALL *mysql_real_escape_string)(MYSQL *mysql, char *to,const char *from, unsigned long length); + void (STDCALL *mysql_debug)(const char *debug); + void (STDCALL *mysql_debug_end)(void); + unsigned int (STDCALL *mysql_thread_safe)(void); + unsigned int (STDCALL *mysql_warning_count)(MYSQL *mysql); + const char * (STDCALL *mysql_sqlstate)(MYSQL *mysql); + int (STDCALL *mysql_server_init)(int argc, char **argv, char **groups); + void (STDCALL *mysql_server_end)(void); + void (STDCALL *mysql_thread_end)(void); + my_bool (STDCALL *mysql_thread_init)(void); + int (STDCALL *mysql_set_server_option)(MYSQL *mysql, enum enum_mysql_set_option option); + const char * (STDCALL *mysql_get_client_info)(void); + unsigned long (STDCALL *mysql_get_client_version)(void); + my_bool (STDCALL *mariadb_connection)(MYSQL *mysql); + const char * (STDCALL *mysql_get_server_name)(MYSQL *mysql); + CHARSET_INFO * (STDCALL *mariadb_get_charset_by_name)(const char *csname); + CHARSET_INFO * (STDCALL *mariadb_get_charset_by_nr)(unsigned int csnr); + size_t (STDCALL *mariadb_convert_string)(const char *from, size_t *from_len, CHARSET_INFO *from_cs, char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode); + int (STDCALL *mysql_optionsv)(MYSQL *mysql,enum mysql_option option, ...); + int (STDCALL *mysql_get_optionv)(MYSQL *mysql, enum mysql_option option, void *arg, ...); + int (STDCALL *mysql_get_option)(MYSQL *mysql, enum mysql_option option, void *arg); + MYSQL_PARAMETERS *(STDCALL *mysql_get_parameters)(void); + unsigned long (STDCALL *mysql_hex_string)(char *to, const char *from, size_t len); + my_socket (STDCALL *mysql_get_socket)(MYSQL *mysql); + unsigned int (STDCALL *mysql_get_timeout_value)(const MYSQL *mysql); + unsigned int (STDCALL *mysql_get_timeout_value_ms)(const MYSQL *mysql); + my_bool (STDCALL *mysql_reconnect)(MYSQL *mysql); + MYSQL_STMT * (STDCALL *mysql_stmt_init)(MYSQL *mysql); + int (STDCALL *mysql_stmt_prepare)(MYSQL_STMT *stmt, const char *query, size_t length); + int (STDCALL *mysql_stmt_execute)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_fetch)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_fetch_column)(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); + int (STDCALL *mysql_stmt_store_result)(MYSQL_STMT *stmt); + unsigned long (STDCALL *mysql_stmt_param_count)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_attr_set)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); + my_bool (STDCALL *mysql_stmt_attr_get)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); + my_bool (STDCALL *mysql_stmt_bind_param)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); + my_bool (STDCALL *mysql_stmt_bind_result)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); + my_bool (STDCALL *mysql_stmt_close)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_reset)(MYSQL_STMT * stmt); + my_bool (STDCALL *mysql_stmt_free_result)(MYSQL_STMT *stmt); + my_bool (STDCALL *mysql_stmt_send_long_data)(MYSQL_STMT *stmt, unsigned int param_number, const char *data, size_t length); + MYSQL_RES *(STDCALL *mysql_stmt_result_metadata)(MYSQL_STMT *stmt); + MYSQL_RES *(STDCALL *mysql_stmt_param_metadata)(MYSQL_STMT *stmt); + unsigned int (STDCALL *mysql_stmt_errno)(MYSQL_STMT * stmt); + const char *(STDCALL *mysql_stmt_error)(MYSQL_STMT * stmt); + const char *(STDCALL *mysql_stmt_sqlstate)(MYSQL_STMT * stmt); + MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_seek)(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); + MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_tell)(MYSQL_STMT *stmt); + void (STDCALL *mysql_stmt_data_seek)(MYSQL_STMT *stmt, my_ulonglong offset); + my_ulonglong (STDCALL *mysql_stmt_num_rows)(MYSQL_STMT *stmt); + my_ulonglong (STDCALL *mysql_stmt_affected_rows)(MYSQL_STMT *stmt); + my_ulonglong (STDCALL *mysql_stmt_insert_id)(MYSQL_STMT *stmt); + unsigned int (STDCALL *mysql_stmt_field_count)(MYSQL_STMT *stmt); + int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt); + my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt); +}; /* these methods can be overwritten by db plugins */ struct st_mysql_methods { @@ -630,6 +786,8 @@ struct st_mysql_methods { int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row); void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt); void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); + void (*invalidate_stmts)(MYSQL *mysql, const char *function_name); + struct st_mariadb_api *api; }; /* synonyms/aliases functions */ diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h index f9c4199b..616de69e 100644 --- a/include/mysql/client_plugin.h +++ b/include/mysql/client_plugin.h @@ -95,6 +95,7 @@ typedef struct st_ma_connection_plugin int (*options)(MYSQL *mysql, enum mysql_option, void *arg); int (*set_connection)(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg); + my_bool (*reconnect)(MYSQL *mysql); } MARIADB_CONNECTION_PLUGIN; #define MARIADB_DB_DRIVER(a) ((a)->ext_db) diff --git a/include/mysql_com.h b/include/mysql_com.h index 045e4d72..84e39635 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -240,6 +240,7 @@ typedef struct st_connection_handler { struct st_ma_connection_plugin *plugin; void *data; + my_bool active; my_bool free_data; } MA_CONNECTION_HANDLER; @@ -375,6 +376,12 @@ typedef struct st_udf_init my_bool const_item; /* 0 if result is independent of arguments */ } UDF_INIT; +/* Connection types */ +#define MARIADB_CONNECTION_UNIXSOCKET 0 +#define MARIADB_CONNECTION_TCP 1 +#define MARIADB_CONNECTION_NAMEDPIPE 2 +#define MARIADB_CONNECTION_SHAREDMEM 3 + /* Constants when using compression */ #define NET_HEADER_SIZE 4 /* standard header size */ #define COMP_HEADER_SIZE 3 /* compression header extra size */ diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt index 9de5f7d0..92333cce 100644 --- a/libmariadb/CMakeLists.txt +++ b/libmariadb/CMakeLists.txt @@ -35,7 +35,10 @@ SET(EXPORT_SYMBOLS mariadb_dyncol_val_long mariadb_dyncol_val_str mariadb_flush_multi_command - myodbc_remove_escape + mariadb_get_charset_by_name + mariadb_get_charset_by_nr + mariadb_get_info + mariadb_get_infov mysql_affected_rows mysql_autocommit mysql_autocommit_cont @@ -80,6 +83,8 @@ SET(EXPORT_SYMBOLS mysql_get_client_info mysql_get_client_version mysql_get_host_info + mysql_get_option + mysql_get_optionv mysql_get_parameters mysql_get_proto_info mysql_get_server_info @@ -125,6 +130,7 @@ SET(EXPORT_SYMBOLS mysql_query mysql_query_cont mysql_query_start + mysql_reconnect mysql_read_query_result mysql_read_query_result_cont mysql_read_query_result_start diff --git a/libmariadb/errmsg.c b/libmariadb/errmsg.c index d228d6b3..936db98e 100644 --- a/libmariadb/errmsg.c +++ b/libmariadb/errmsg.c @@ -149,7 +149,8 @@ const char *mariadb_client_errors[] = { /* 5000 */ "Creating an event failed (Errorcode: %d)", /* 5001 */ "Bind to local interface '-.%64s' failed (Errorcode: %d)", - /* 5002 */ "Server doesn't support function '%s'", + /* 5002 */ "Connection type doesn't support asynchronous IO operations", + /* 5003 */ "Server doesn't support function '%s'", "" }; diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index d2409b35..3e5319f3 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -37,6 +37,7 @@ #include #include #include + #ifdef HAVE_PWD_H #include #endif @@ -66,6 +67,9 @@ #include #endif #include +#ifdef HAVE_SSL +#include +#endif #include #include @@ -127,11 +131,14 @@ struct st_mysql_methods MARIADB_DEFAULT_METHODS; #define native_password_plugin_name "mysql_native_password" +#define IS_CONNHDLR_ACTIVE(mysql)\ + ((mysql)->net.conn_hdlr && (mysql)->net.conn_hdlr->active) + static void end_server(MYSQL *mysql); static void mysql_close_memory(MYSQL *mysql); void read_user_name(char *name); static void append_wild(char *to,char *end,const char *wild); -static my_bool mysql_reconnect(MYSQL *mysql); +my_bool STDCALL mysql_reconnect(MYSQL *mysql); static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length); extern int mysql_client_plugin_init(); @@ -164,7 +171,7 @@ void net_get_error(char *buf, size_t buf_len, else { *error_no= CR_UNKNOWN_ERROR; - memcpy(sqlstate, unknown_sqlstate, SQLSTATE_LENGTH); + memcpy(sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH); } } @@ -208,7 +215,7 @@ restart: if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1))) { /* Wrong packet */ - my_set_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate, 0); + my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0); return (packet_error); } goto restart; @@ -367,13 +374,6 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, DBUG_RETURN(net_add_multi_command(&mysql->net, command, arg, length)); } - if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data) - { - result= mysql->net.conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg); - if (result== -1) - DBUG_RETURN(result); - } - if (mysql->net.pvio == 0) { /* Do reconnect if possible */ if (mysql_reconnect(mysql)) @@ -385,10 +385,17 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, if (mysql->status != MYSQL_STATUS_READY || mysql->server_status & SERVER_MORE_RESULTS_EXIST) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); goto end; } + if (IS_CONNHDLR_ACTIVE(mysql)) + { + result= mysql->net.conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg); + if (result== -1) + DBUG_RETURN(result); + } + CLEAR_CLIENT_ERROR(mysql); mysql->info=0; @@ -397,13 +404,6 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, if (!arg) arg=""; - /* check if connection kills itself */ - if (command == COM_PROCESS_KILL) - { - unsigned long thread_id= uint4korr(arg); - if (thread_id == mysql->thread_id) - skipp_check= 1; - } if (net_write_command(net,(uchar) command,arg, length ? length : (ulong) strlen(arg))) { @@ -532,7 +532,7 @@ append_wild(char *to, char *end, const char *wild) /************************************************************************** ** Init debugging if MYSQL_DEBUG environment variable is found **************************************************************************/ -void STDCALL mysql_debug_end() +void STDCALL mysql_debug_end(void) { #ifndef DBUG_OFF DEBUGGER_OFF; @@ -1014,7 +1014,7 @@ MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), MYF(MY_WME | MY_ZEROFILL)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ @@ -1033,7 +1033,7 @@ MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, (fields+1)*sizeof(char *)+fields+pkt_len)))) { free_rows(result); - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } *prev_ptr=cur; @@ -1052,7 +1052,7 @@ MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, if (len > (ulong) (end_to - to)) { free_rows(result); - SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } memcpy(to,(char*) cp,len); to[len]=0; @@ -1158,6 +1158,7 @@ mysql_init(MYSQL *mysql) bzero((char*) (mysql),sizeof(*(mysql))); mysql->options.connect_timeout=CONNECT_TIMEOUT; mysql->charset= default_charset_info; + mysql->methods= &MARIADB_DEFAULT_METHODS; strmov(mysql->net.sqlstate, "00000"); mysql->net.last_error[0]= mysql->net.last_errno= 0; @@ -1244,15 +1245,13 @@ uchar *ma_send_connect_attr(MYSQL *mysql, uchar *buffer) size_t len; uchar *p= hash_element(&mysql->options.extension->connect_attrs, i); - len= *(size_t *)p; + len= strlen((char *)p); buffer= mysql_net_store_length(buffer, len); - p+= sizeof(size_t); memcpy(buffer, p, len); - buffer+= len; - p+= len; - len= *(size_t *)p; + buffer+= (len); + p+= (len + 1); + len= strlen(p); buffer= mysql_net_store_length(buffer, len); - p+= sizeof(size_t); memcpy(buffer, p, len); buffer+= len; } @@ -1304,9 +1303,38 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, uint port, const char *unix_socket,unsigned long client_flag) { + char *end; + if (!mysql->methods) mysql->methods= &MARIADB_DEFAULT_METHODS; + if (host && (end= strstr(host, "://"))) + { + MARIADB_CONNECTION_PLUGIN *plugin; + char plugin_name[64]; + + bzero(plugin_name, 64); + strncpy(plugin_name, host, MIN(end - host, 63)); + end+= 3; + + if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN))) + return NULL; + + if (!(mysql->net.conn_hdlr= (MA_CONNECTION_HANDLER *)my_malloc(sizeof(MA_CONNECTION_HANDLER), MYF(MY_ZEROFILL)))) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + return NULL; + } + + /* save URL for reconnect */ + OPT_SET_EXTENDED_VALUE_STR(&mysql->options, url, host); + + mysql->net.conn_hdlr->plugin= plugin; + + if (plugin && plugin->connect) + return plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag); + } + return mysql->methods->db_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag); } @@ -1334,32 +1362,6 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, if (!mysql->methods) mysql->methods= &MARIADB_DEFAULT_METHODS; - /* special case: - * If hostname contains "://", e.g. "repl://localhost", we need to process connection - * by connection plugin - */ - if (host && (end= strstr(host, "://"))) - { - MARIADB_CONNECTION_PLUGIN *plugin; - char plugin_name[64]; - - bzero(plugin_name, 64); - strncpy(plugin_name, host, MIN(end - host, 63)); - end+= 3; - if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN))) - DBUG_RETURN(NULL); - - if (!(mysql->net.conn_hdlr= (MA_CONNECTION_HANDLER *)my_malloc(sizeof(MA_CONNECTION_HANDLER), MYF(MY_ZEROFILL)))) - { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); - DBUG_RETURN(NULL); - } - - mysql->net.conn_hdlr->plugin= plugin; - - if (plugin->connect) - return plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag); - } ma_set_connect_attrs(mysql); @@ -1534,7 +1536,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, !(mysql->user=my_strdup(user,MYF(0))) || !(mysql->passwd=my_strdup(passwd,MYF(0)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto error; } strmov(mysql->host_info,host_info); @@ -1550,7 +1552,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, { if (!(mysql->server_version= my_strdup(end + sizeof(MA_RPL_VERSION_HACK), 0))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto error; } is_maria= 1; @@ -1559,7 +1561,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, { if (!(mysql->server_version= my_strdup(end, MYF(0)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto error; } } @@ -1622,7 +1624,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION; if (mysql->options.secure_auth) { - SET_CLIENT_ERROR(mysql, CR_SECURE_AUTH, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_SECURE_AUTH, SQLSTATE_UNKNOWN, 0); goto error; } } @@ -1658,7 +1660,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, { if (mysql_select_db(mysql, db)) { - my_set_error(mysql, CR_SERVER_LOST, unknown_sqlstate, + my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, ER(CR_SERVER_LOST_EXTENDED), "Setting intital database", errno); @@ -1680,7 +1682,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, mysql->reconnect= 0; for (;begin < end; begin++) - { + { if (mysql_real_query(mysql, *begin, (unsigned long)strlen(*begin))) goto error; @@ -1736,14 +1738,22 @@ my_suspend_hook(my_bool suspend, void *data) } -static my_bool mysql_reconnect(MYSQL *mysql) +my_bool STDCALL mysql_reconnect(MYSQL *mysql) { MYSQL tmp_mysql; struct my_hook_data hook_data; struct mysql_async_context *ctxt= NULL; + LIST *li_stmt= mysql->stmts; DBUG_ENTER("mysql_reconnect"); + /* check if connection handler is active */ + if (IS_CONNHDLR_ACTIVE(mysql)) + { + if (mysql->net.conn_hdlr->plugin && mysql->net.conn_hdlr->plugin->connect) + DBUG_RETURN(mysql->net.conn_hdlr->plugin->reconnect(mysql)); + } + if (!mysql->reconnect || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) { @@ -1755,6 +1765,13 @@ static my_bool mysql_reconnect(MYSQL *mysql) mysql_init(&tmp_mysql); tmp_mysql.options=mysql->options; + if (mysql->net.conn_hdlr) + { + tmp_mysql.net.conn_hdlr= mysql->net.conn_hdlr; + mysql->net.conn_hdlr= 0; + } + + /* don't reread options from configuration files */ tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL; @@ -1783,6 +1800,17 @@ static my_bool mysql_reconnect(MYSQL *mysql) DBUG_RETURN(1); } + for (;li_stmt;li_stmt= li_stmt->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; + + if (stmt->state != MYSQL_STMT_INITTED) + { + stmt->state= MYSQL_STMT_INITTED; + SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); + } + } + tmp_mysql.reconnect= mysql->reconnect; tmp_mysql.free_me= mysql->free_me; tmp_mysql.stmts= mysql->stmts; @@ -1799,8 +1827,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) DBUG_RETURN(0); } - -static void ma_invalidate_stmts(MYSQL *mysql, const char *function_name) +void ma_invalidate_stmts(MYSQL *mysql, const char *function_name) { if (mysql->stmts) { @@ -1863,7 +1890,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, if (db && !(mysql->db= my_strdup(db,MYF(MY_WME)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); rc= 1; } } else @@ -1944,8 +1971,11 @@ static void mysql_close_options(MYSQL *mysql) my_free(mysql->options.extension->ssl_fp); my_free(mysql->options.extension->ssl_fp_list); my_free(mysql->options.extension->ssl_pw); + my_free(mysql->options.extension->url); if(hash_inited(&mysql->options.extension->connect_attrs)) hash_free(&mysql->options.extension->connect_attrs); + if (hash_inited(&mysql->options.extension->userdata)) + hash_free(&mysql->options.extension->userdata); if ((ctxt = mysql->options.extension->async_context) != 0) { my_context_destroy(&ctxt->async_context); @@ -2006,7 +2036,8 @@ mysql_close(MYSQL *mysql) DBUG_ENTER("mysql_close"); if (mysql) /* Some simple safety */ { - if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data) + + if (IS_CONNHDLR_ACTIVE(mysql)) { void *p= (void *)mysql->net.conn_hdlr; mysql->net.conn_hdlr->plugin->close(mysql); @@ -2019,6 +2050,7 @@ mysql_close(MYSQL *mysql) /* reset the connection in all active statements */ ma_invalidate_stmts(mysql, "mysql_close()"); + mysql_close_memory(mysql); mysql_close_options(mysql); mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; @@ -2069,7 +2101,9 @@ int mthd_my_read_query_result(MYSQL *mysql) DBUG_ENTER("mthd_my_read_query_result"); if (!mysql || (length = net_safe_read(mysql)) == packet_error) + { DBUG_RETURN(1); + } free_old_query(mysql); /* Free old result */ get_info: pos=(uchar*) mysql->net.read_pos; @@ -2151,7 +2185,7 @@ mysql_store_result(MYSQL *mysql) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } mysql->status=MYSQL_STATUS_READY; /* server is ready */ @@ -2159,7 +2193,7 @@ mysql_store_result(MYSQL *mysql) sizeof(ulong)*mysql->field_count, MYF(MY_WME | MY_ZEROFILL)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } result->eof=1; /* Marker for buffered */ @@ -2201,7 +2235,7 @@ mysql_use_result(MYSQL *mysql) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(0); } if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+ @@ -2518,13 +2552,12 @@ mysql_stat(MYSQL *mysql) mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */ if (!mysql->net.read_pos[0]) { - SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , SQLSTATE_UNKNOWN, 0); return mysql->net.last_error; } DBUG_RETURN((char*) mysql->net.read_pos); } - int STDCALL mysql_ping(MYSQL *mysql) { @@ -2538,16 +2571,15 @@ mysql_ping(MYSQL *mysql) return rc; } - char * STDCALL mysql_get_server_info(MYSQL *mysql) { return((char*) mysql->server_version); } -unsigned long STDCALL mysql_get_server_version(MYSQL *mysql) +static size_t mariadb_server_version_id(MYSQL *mysql) { - long major, minor, patch; + size_t major, minor, patch; char *p; if (!(p = mysql->server_version)) { @@ -2560,7 +2592,12 @@ unsigned long STDCALL mysql_get_server_version(MYSQL *mysql) p += 1; /* consume the dot */ patch = strtol(p, &p, 10); - return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch)); + return (major * 10000L + (unsigned long)(minor * 100L + patch)); +} + +unsigned long STDCALL mysql_get_server_version(MYSQL *mysql) +{ + return (unsigned long)mariadb_server_version_id(mysql); } @@ -2595,21 +2632,17 @@ static size_t get_store_length(size_t length) return 9; } -uchar *ma_get_hash_key(const uchar *hash_entry, +uchar *ma_get_hash_keyval(const uchar *hash_entry, unsigned int *length, my_bool not_used __attribute__((unused))) { /* Hash entry has the following format: - Offset: 0 key length - sizeof(size_t) key - key_length + - sizeof(size_t) value length - value + Offset: 0 key (\0 terminated) + key_length + 1 value (\0 terminated) */ uchar *p= (uchar *)hash_entry; - size_t len=*((size_t*)p); - p+= sizeof(size_t); - *length= (uint)len; + size_t len= strlen(p); + *length= (unsigned int)len; return p; } @@ -2747,7 +2780,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) if (!(ctxt= (struct mysql_async_context *) my_malloc(sizeof(*ctxt), MYF(MY_ZEROFILL)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } stacksize= 0; @@ -2765,7 +2798,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) my_malloc(sizeof(struct st_mysql_options_extension), MYF(MY_WME | MY_ZEROFILL)))) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } mysql->options.extension->async_context= ctxt; @@ -2807,19 +2840,19 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) break; case MYSQL_OPT_CONNECT_ATTR_DELETE: { - uchar *p; + uchar *h; CHECK_OPT_EXTENSION_SET(&mysql->options); if (hash_inited(&mysql->options.extension->connect_attrs) && - (p= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg1, + (h= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg1, arg1 ? (uint)strlen((char *)arg1) : 0))) { - size_t key_len= *(size_t *)p; - mysql->options.extension->connect_attrs_len-= key_len; - mysql->options.extension->connect_attrs_len-= get_store_length(key_len); - key_len= *(size_t *)(p + sizeof(size_t) + key_len); - mysql->options.extension->connect_attrs_len-= key_len; - mysql->options.extension->connect_attrs_len-= get_store_length(key_len); - hash_delete(&mysql->options.extension->connect_attrs, p); + uchar *p= h; + size_t key_len= strlen(p); + mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len); + p+= key_len + 1; + key_len= strlen(p); + mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len); + hash_delete(&mysql->options.extension->connect_attrs, h); } } @@ -2832,6 +2865,42 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.extension->connect_attrs_len= 0; } break; + case MARIADB_OPT_USERDATA: + { + void *data= va_arg(ap, void *); + uchar *buffer, *p; + char *key= (char *)arg1; + + if (!key || !data) + { + SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); + goto end; + } + + CHECK_OPT_EXTENSION_SET(&mysql->options); + if (!hash_inited(&mysql->options.extension->userdata)) + { + if (_hash_init(&mysql->options.extension->userdata, + 0, 0, 0, ma_get_hash_keyval, ma_hash_free, 0) || + !(buffer= (uchar *)my_malloc(strlen(key) + 1 + sizeof(void *), MYF(MY_ZEROFILL)))) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + goto end; + } + } + p= buffer; + strcpy(p, key); + p+= strlen(key) + 1; + memcpy(p, &data, sizeof(void *)); + + if (hash_insert(&mysql->options.extension->userdata, buffer)) + { + my_free(buffer); + SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); + goto end; + } + } + break; case MYSQL_OPT_CONNECT_ATTR_ADD: { uchar *buffer; @@ -2841,48 +2910,49 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) size_t storage_len= key_len + value_len + get_store_length(key_len) + get_store_length(value_len); + + /* since we store terminating zero character in hash, we need + * to increase lengths */ + key_len++; + value_len++; CHECK_OPT_EXTENSION_SET(&mysql->options); if (!key_len || storage_len + mysql->options.extension->connect_attrs_len > 0xFFFF) { - SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); goto end; } if (!hash_inited(&mysql->options.extension->connect_attrs)) { if (_hash_init(&mysql->options.extension->connect_attrs, - 0, 0, 0, ma_get_hash_key, ma_hash_free, 0)) + 0, 0, 0, ma_get_hash_keyval, ma_hash_free, 0)) { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } } - if ((buffer= (uchar *)my_malloc(2 * sizeof(size_t) + key_len + value_len, + if ((buffer= (uchar *)my_malloc(key_len + value_len, MYF(MY_WME | MY_ZEROFILL)))) { uchar *p= buffer; - *((size_t *)p)= key_len; - p+= sizeof(size_t); - memcpy(p, arg1, key_len); - p+= key_len; - *((size_t *)p)= value_len; - p+= sizeof(size_t); + strcpy(p, arg1); + p+= (strlen(arg1) + 1); if (arg2) - memcpy(p, arg2, value_len); + strcpy(p, arg2); if (hash_insert(&mysql->options.extension->connect_attrs, buffer)) { my_free(buffer); - SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); goto end; } mysql->options.extension->connect_attrs_len+= storage_len; } else { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } } @@ -2905,11 +2975,6 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) case MARIADB_OPT_SSL_PASSWORD: OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_pw, (char *)arg1); break; - case MARIADB_OPT_CONNECTION_READ_ONLY: - if (mysql->net.conn_hdlr) - DBUG_RETURN(mysql->net.conn_hdlr->plugin->options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, arg1)); - else - return -1; case MARIADB_OPT_COM_MULTI: if (&mysql->net.pvio && (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)) @@ -2919,6 +2984,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) else DBUG_RETURN(-1); break; + case MARIADB_OPT_CONNECTION_READ_ONLY: + OPT_SET_EXTENDED_VALUE_INT(&mysql->options, read_only, *(my_bool *)arg1); + break; default: va_end(ap); DBUG_RETURN(-1); @@ -2930,6 +2998,200 @@ end: DBUG_RETURN(1); } +int STDCALL +mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) +{ + va_list ap; + + DBUG_ENTER("mariadb_get_optionv"); + DBUG_PRINT("enter",("option: %d",(int) option)); + + va_start(ap, arg); + + switch(option) { + case MYSQL_OPT_CONNECT_TIMEOUT: + *((uint *)arg)= mysql->options.connect_timeout; + break; + case MYSQL_OPT_COMPRESS: + *((my_bool *)arg)= mysql->options.compress; + break; + case MYSQL_OPT_NAMED_PIPE: + *((my_bool *)arg)= mysql->options.named_pipe; + break; + case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/ + *((uint *)arg)= test(mysql->options.client_flag & CLIENT_LOCAL_FILES); + break; + case MYSQL_INIT_COMMAND: + /* mysql_get_optionsv(mysql, MYSQL_INIT_COMMAND, commands, elements) */ + { + unsigned int *elements; + if (arg) + *((char **)arg)= mysql->options.init_command ? mysql->options.init_command->buffer : NULL; + if ((elements= va_arg(ap, unsigned int *))) + *elements= mysql->options.init_command ? mysql->options.init_command->elements : 0; + } + break; + case MYSQL_READ_DEFAULT_FILE: + *((char **)arg)= mysql->options.my_cnf_file; + break; + case MYSQL_READ_DEFAULT_GROUP: + *((char **)arg)= mysql->options.my_cnf_group; + break; + case MYSQL_SET_CHARSET_DIR: + /* not supported in this version. Since all character sets + are internally available, we don't throw an error */ + *((char **)arg)= NULL; + break; + case MYSQL_SET_CHARSET_NAME: + *((char **)arg)= mysql->options.charset_name; + break; + case MYSQL_OPT_RECONNECT: + *((uint *)arg)= mysql->reconnect; + break; + case MYSQL_OPT_PROTOCOL: + *((uint *)arg)= mysql->options.protocol; + break; + case MYSQL_OPT_READ_TIMEOUT: + *((uint *)arg)= mysql->options.read_timeout; + break; + case MYSQL_OPT_WRITE_TIMEOUT: + *((uint *)arg)= mysql->options.write_timeout; + break; + case MYSQL_REPORT_DATA_TRUNCATION: + *((uint *)arg)= mysql->options.report_data_truncation; + break; + case MYSQL_PROGRESS_CALLBACK: + *((void (**)(const MYSQL *, uint, uint, double, const char *, uint))arg)= + mysql->options.extension ? mysql->options.extension->report_progress : NULL; + break; + case MYSQL_PLUGIN_DIR: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->plugin_dir : NULL; + break; + case MYSQL_DEFAULT_AUTH: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->default_auth : NULL; + break; + case MYSQL_OPT_NONBLOCK: + *((my_bool *)arg)= test(mysql->options.extension && mysql->options.extension->async_context); + break; + case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: + *((my_bool *)arg)= test(mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT); + break; + case MYSQL_OPT_SSL_KEY: + *((char **)arg)= mysql->options.ssl_key; + break; + case MYSQL_OPT_SSL_CERT: + *((char **)arg)= mysql->options.ssl_cert; + break; + case MYSQL_OPT_SSL_CA: + *((char **)arg)= mysql->options.ssl_ca; + break; + case MYSQL_OPT_SSL_CAPATH: + *((char **)arg)= mysql->options.ssl_capath; + break; + case MYSQL_OPT_SSL_CIPHER: + *((char **)arg)= mysql->options.ssl_cipher; + break; + case MYSQL_OPT_SSL_CRL: + *((char **)arg)= mysql->options.extension ? mysql->options.ssl_cipher : NULL; + break; + case MYSQL_OPT_SSL_CRLPATH: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL; + break; + case MYSQL_OPT_CONNECT_ATTRS: + /* mysql_get_optionsv(mysql, MYSQL_OPT_CONNECT_ATTRS, keys, vals, elements) */ + { + int i, *elements; + char **key= NULL; + void *arg1; + char **val= NULL; + + if (arg) + key= *(char ***)arg; + + arg1= va_arg(ap, char **); + if (arg1) + val= *(char ***)arg1; + + if (!(elements= va_arg(ap, unsigned int *))) + goto error; + + if (!elements) + goto error; + + *elements= 0; + + if (!mysql->options.extension || + !hash_inited(&mysql->options.extension->connect_attrs)) + break; + + *elements= mysql->options.extension->connect_attrs.records; + + if (val || key) + { + for (i=0; i < *elements; i++) + { + uchar *p= hash_element(&mysql->options.extension->connect_attrs, i); + if (key) + key[i]= p; + p+= strlen(p) + 1; + if (val) + val[i]= p; + } + } + } + break; + case MYSQL_SECURE_AUTH: + *((my_bool *)arg)= mysql->options.secure_auth; + break; + case MYSQL_OPT_BIND: + *((char **)arg)= mysql->options.bind_address; + break; + case MARIADB_OPT_SSL_FP: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_fp : NULL; + break; + case MARIADB_OPT_SSL_FP_LIST: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_fp_list : NULL; + break; + case MARIADB_OPT_SSL_PASSWORD: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_pw : NULL; + break; + /* todo + case MARIADB_OPT_CONNECTION_READ_ONLY: + break; + */ + case MARIADB_OPT_USERDATA: + /* nysql_get_optionv(mysql, MARIADB_OPT_USERDATA, key, value) */ + { + uchar *p; + void *data= va_arg(ap, void *); + char *key= (char *)arg; + if (key && data && mysql->options.extension && hash_inited(&mysql->options.extension->userdata) && + (p= (uchar *)hash_search(&mysql->options.extension->userdata, (uchar *)key, + (uint)strlen((char *)key)))) + { + p+= strlen(key) + 1; + *((void **)data)= *((void **)p); + break; + } + if (data) + *((void **)data)= NULL; + } + break; + default: + va_end(ap); + DBUG_RETURN(-1); + } + va_end(ap); + DBUG_RETURN(0); +error: + va_end(ap); + DBUG_RETURN(-1); +} + +int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg) +{ + return mysql_get_optionv(mysql, option, arg); +} int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) @@ -2937,7 +3199,6 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) return mysql_optionsv(mysql, option, arg); } - /**************************************************************************** ** Functions to get information from the MySQL structure ** These are functions to make shared libraries more usable. @@ -3044,7 +3305,7 @@ int STDCALL mysql_next_result(MYSQL *mysql) /* make sure communication is not blocking */ if (mysql->status != MYSQL_STATUS_READY) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, 0); + SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); DBUG_RETURN(1); } @@ -3106,35 +3367,9 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return (ulong)mysql_cset_escape_slashes(mysql->charset, to, from, length); } -void STDCALL -myodbc_remove_escape(MYSQL *mysql,char *name) +static void mariadb_get_charset_info(MYSQL *mysql, MY_CHARSET_INFO *cs) { - char *to; - my_bool use_mb_flag= (mysql->charset->char_maxlen > 1); - char *end= 0; - if (use_mb_flag) - for (end=name; *end ; end++) ; - - for (to=name ; *name ; name++) - { - int l; - if (use_mb_flag && (l = mysql->charset->mb_valid(name , end))) - { - while (l--) - *to++ = *name++; - name--; - continue; - } - if (*name == '\\' && name[1]) - name++; - *to++= *name; - } - *to=0; -} - -void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs) -{ - DBUG_ENTER("mysql_get_character_set_info"); + DBUG_ENTER("mariadb_get_charset_info"); if (!cs) DBUG_VOID_RETURN; @@ -3151,6 +3386,11 @@ void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs) DBUG_VOID_RETURN; } +void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs) +{ + mariadb_get_charset_info(mysql, cs); +} + int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname) { const CHARSET_INFO *cs; @@ -3247,7 +3487,7 @@ void STDCALL mysql_server_end() my_init_done= 0; } -my_bool STDCALL mysql_thread_init() +my_bool STDCALL mysql_thread_init(void) { #ifdef THREAD return my_thread_init(); @@ -3255,7 +3495,7 @@ my_bool STDCALL mysql_thread_init() return 0; } -void STDCALL mysql_thread_end() +void STDCALL mysql_thread_end(void) { #ifdef THREAD my_thread_end(); @@ -3312,8 +3552,7 @@ mysql_get_parameters(void) return &mariadb_internal_parameters; } -my_socket STDCALL -mysql_get_socket(const MYSQL *mysql) +static my_socket mariadb_get_socket(MYSQL *mysql) { my_socket sock= INVALID_SOCKET; if (mysql->net.pvio) @@ -3350,6 +3589,339 @@ int STDCALL mariadb_flush_multi_command(MYSQL *mysql) return rc; } +my_socket STDCALL +mysql_get_socket(MYSQL *mysql) +{ + return mariadb_get_socket(mysql); +} + +CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname) +{ + return (CHARSET_INFO *)mysql_find_charset_name(csname); +} + +CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr) +{ + return (CHARSET_INFO *)mysql_find_charset_nr(csnr); +} + +my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...) +{ + va_list ap; + + DBUG_ENTER("mariadb_get_valuev"); + DBUG_PRINT("enter",("value: %d",(int) value)); + + va_start(ap, arg); + + switch(value) { + case MARIADB_MAX_ALLOWED_PACKET: + *((size_t *)arg)= (size_t)max_allowed_packet; + break; + case MARIADB_NET_BUFFER_LENGTH: + *((size_t *)arg)= (size_t)net_buffer_length; + break; + case MARIADB_CONNECTION_SSL_VERSION: + #ifdef HAVE_SSL + if (mysql && mysql->net.pvio && mysql->net.pvio->cssl) + { + struct st_ssl_version version; + if (!ma_pvio_ssl_get_protocol_version(mysql->net.pvio->cssl, &version)) + *((char **)arg)= version.cversion; + } + else + #endif + goto error; + break; + case MARIADB_CONNECTION_SSL_VERSION_ID: + #ifdef HAVE_SSL + if (mysql && mysql->net.pvio && mysql->net.pvio->cssl) + { + struct st_ssl_version version; + if (!ma_pvio_ssl_get_protocol_version(mysql->net.pvio->cssl, &version)) + *((unsigned int *)arg)= version.iversion; + } + else + #endif + goto error; + break; + case MARIADB_CLIENT_VERSION: + *((char **)arg)= MYSQL_CLIENT_VERSION; + break; + case MARIADB_CLIENT_VERSION_ID: + *((size_t *)arg)= MYSQL_VERSION_ID; + break; + case MARIADB_CONNECTION_SERVER_VERSION: + if (mysql) + *((char **)arg)= mysql->server_version; + else + goto error; + break; + case MARIADB_CONNECTION_SERVER_TYPE: + if (mysql) + *((char **)arg)= mariadb_connection(mysql) ? "MariaDB" : "MySQL"; + else + goto error; + break; + case MARIADB_CONNECTION_SERVER_VERSION_ID: + if (mysql) + *((size_t *)arg)= mariadb_server_version_id(mysql); + else + goto error; + break; + case MARIADB_CONNECTION_PROTOCOL_VERSION_ID: + if (mysql) + *((unsigned int *)arg)= mysql->protocol_version; + else + goto error; + break; + case MARIADB_CHARSET_INFO: + if (mysql) + mariadb_get_charset_info(mysql, (MY_CHARSET_INFO *)arg); + else + goto error; + break; + case MARIADB_CONNECTION_SOCKET: + if (mysql) + *((my_socket *)arg)= mariadb_get_socket(mysql); + else + goto error; + break; + case MARIADB_CONNECTION_TYPE: + if (mysql && mysql->net.pvio) + *((int *)arg)= (int)mysql->net.pvio->type; + else + goto error; + break; + case MARIADB_CONNECTION_ASYNC_TIMEOUT_MS: + if (mysql && mysql->options.extension && mysql->options.extension->async_context) + *((unsigned int *)arg)= mysql->options.extension->async_context->timeout_value; + else + goto error; + break; + case MARIADB_CONNECTION_ASYNC_TIMEOUT: + if (mysql && mysql->options.extension && mysql->options.extension->async_context) + { + unsigned int timeout= mysql->options.extension->async_context->timeout_value; + if (timeout > UINT_MAX - 999) + *((unsigned int *)arg)= (timeout - 1)/1000 + 1; + else + *((unsigned int *)arg)= (timeout+999)/1000; + } + else + goto error; + break; + case MARIADB_CHARSET_NAME: + { + char *name; + name= va_arg(ap, char *); + if (name) + *((CHARSET_INFO **)arg)= (CHARSET_INFO *)mysql_find_charset_name(name); + else + goto error; + } + break; + case MARIADB_CHARSET_ID: + { + unsigned int nr; + nr= va_arg(ap, unsigned int); + *((CHARSET_INFO **)arg)= (CHARSET_INFO *)mysql_find_charset_nr(nr); + } + break; + case MARIADB_CONNECTION_SSL_CIPHER: + #ifdef HAVE_SSL + if (mysql && mysql->net.pvio && mysql->net.pvio->cssl) + *((char **)arg)= (char *)ma_pvio_ssl_cipher(mysql->net.pvio->cssl); + else + #endif + goto error; + break; + case MARIADB_CLIENT_ERRORS: + *((char ***)arg)= (char **)client_errors; + break; + case MARIADB_CONNECTION_INFO: + if (mysql) + *((char **)arg)= (char *)mysql->info; + else + goto error; + break; + case MARIADB_CONNECTION_PVIO_TYPE: + if (mysql && !mysql->net.pvio) + *((unsigned int *)arg)= (unsigned int)mysql->net.pvio->type; + else + goto error; + break; + case MARIADB_CONNECTION_SCHEMA: + if (mysql) + *((char **)arg)= mysql->db; + else + goto error; + break; + case MARIADB_CONNECTION_USER: + if (mysql) + *((char **)arg)= mysql->user; + else + goto error; + break; + case MARIADB_CONNECTION_PORT: + if (mysql) + *((unsigned int *)arg)= mysql->port; + else + goto error; + break; + case MARIADB_CONNECTION_UNIX_SOCKET: + if (mysql) + *((char **)arg)= mysql->unix_socket; + else + goto error; + break; + case MARIADB_CONNECTION_HOST: + if (mysql) + *((char **)arg)= mysql->host; + else + goto error; + break; + default: + va_end(ap); + DBUG_RETURN(-1); + } + va_end(ap); + DBUG_RETURN(0); +error: + va_end(ap); + DBUG_RETURN(-1); +} + +my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg) +{ + return mariadb_get_infov(mysql, value, arg); +} + +#undef STDCALL +/* API functions for usage in dynamic plugins */ +struct st_mariadb_api MARIADB_API= +{ + mysql_num_rows, + mysql_num_fields, + mysql_eof, + mysql_fetch_field_direct, + mysql_fetch_fields, + mysql_row_tell, + mysql_field_tell, + mysql_field_count, + mysql_more_results, + mysql_next_result, + mysql_affected_rows, + mysql_autocommit, + mysql_commit, + mysql_rollback, + mysql_insert_id, + mysql_errno, + mysql_error, + mysql_info, + mysql_thread_id, + mysql_character_set_name, + mysql_get_character_set_info, + mysql_set_character_set, + mariadb_get_infov, + mariadb_get_info, + mysql_init, + mysql_ssl_set, + mysql_get_ssl_cipher, + mysql_connect, + mysql_change_user, + mysql_real_connect, + mysql_close, + mysql_select_db, + mysql_query, + mysql_send_query, + mysql_read_query_result, + mysql_real_query, + mysql_create_db, + mysql_drop_db, + mysql_shutdown, + mysql_dump_debug_info, + mysql_refresh, + mysql_kill, + mysql_ping, + mysql_stat, + mysql_get_server_info, + mysql_get_server_version, + mysql_get_host_info, + mysql_get_proto_info, + mysql_list_dbs, + mysql_list_tables, + mysql_list_fields, + mysql_list_processes, + mysql_store_result, + mysql_use_result, + mysql_options, + mysql_free_result, + mysql_data_seek, + mysql_row_seek, + mysql_field_seek, + mysql_fetch_row, + mysql_fetch_lengths, + mysql_fetch_field, + mysql_escape_string, + mysql_real_escape_string, + mysql_debug, + mysql_debug_end, + mysql_thread_safe, + mysql_warning_count, + mysql_sqlstate, + mysql_server_init, + mysql_server_end, + mysql_thread_end, + mysql_thread_init, + mysql_set_server_option, + mysql_get_client_info, + mysql_get_client_version, + mariadb_connection, + mysql_get_server_name, + mariadb_get_charset_by_name, + mariadb_get_charset_by_nr, + mariadb_convert_string, + mysql_optionsv, + mysql_get_optionv, + mysql_get_option, + mysql_get_parameters, + mysql_hex_string, + mysql_get_socket, + mysql_get_timeout_value, + mysql_get_timeout_value_ms, + mysql_reconnect, + mysql_stmt_init, + mysql_stmt_prepare, + mysql_stmt_execute, + mysql_stmt_fetch, + mysql_stmt_fetch_column, + mysql_stmt_store_result, + mysql_stmt_param_count, + mysql_stmt_attr_set, + mysql_stmt_attr_get, + mysql_stmt_bind_param, + mysql_stmt_bind_result, + mysql_stmt_close, + mysql_stmt_reset, + mysql_stmt_free_result, + mysql_stmt_send_long_data, + mysql_stmt_result_metadata, + mysql_stmt_param_metadata, + mysql_stmt_errno, + mysql_stmt_error, + mysql_stmt_sqlstate, + mysql_stmt_row_seek, + mysql_stmt_row_tell, + mysql_stmt_data_seek, + mysql_stmt_num_rows, + mysql_stmt_affected_rows, + mysql_stmt_insert_id, + mysql_stmt_field_count, + mysql_stmt_next_result, + mysql_stmt_more_results +}; + /* * Default methods for a connection. These methods are * stored in mysql->methods and can be overwritten by @@ -3387,5 +3959,10 @@ struct st_mysql_methods MARIADB_DEFAULT_METHODS = { /* store values in bind buffer */ mthd_stmt_fetch_to_bind, /* skip unbuffered stmt result */ - mthd_stmt_flush_unbuffered + mthd_stmt_flush_unbuffered, + /* set error */ + my_set_error, + /* invalidate statements */ + ma_invalidate_stmts, + &MARIADB_API }; diff --git a/libmariadb/ma_dyncol.c b/libmariadb/ma_dyncol.c index c7c3b66d..aa8391b6 100644 --- a/libmariadb/ma_dyncol.c +++ b/libmariadb/ma_dyncol.c @@ -1114,7 +1114,7 @@ dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here, #ifndef LIBMARIADB store_it_here->x.string.charset= get_charset_by_nr(charset_nr); #else - store_it_here->x.string.charset= mysql_get_charset_by_nr(charset_nr); + store_it_here->x.string.charset= mariadb_get_charset_by_nr(charset_nr); #endif if (store_it_here->x.string.charset == NULL) return ER_DYNCOL_UNKNOWN_CHARSET; diff --git a/libmariadb/ma_pvio.c b/libmariadb/ma_pvio.c index 2f9d2744..054ef45d 100644 --- a/libmariadb/ma_pvio.c +++ b/libmariadb/ma_pvio.c @@ -71,7 +71,7 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) * pvio_socket * pvio_namedpipe */ - char *pvio_plugins[] = {"pvio_socket", "pvio_npipe"}; + char *pvio_plugins[] = {"pvio_socket", "pvio_npipe", "pvio_shmem"}; int type; MARIADB_PVIO_PLUGIN *pvio_plugin; MARIADB_PVIO *pvio= NULL; @@ -86,6 +86,9 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) case PVIO_TYPE_NAMEDPIPE: type= 1; break; + case PVIO_TYPE_SHAREDMEM: + type= 2; + break; #endif default: return NULL; @@ -96,7 +99,6 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) pvio_plugins[type], MARIADB_CLIENT_PVIO_PLUGIN))) { - /* error handling */ return NULL; } @@ -111,6 +113,7 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) /* register error routine and methods */ pvio->methods= pvio_plugin->methods; pvio->set_error= my_set_error; + pvio->type= cinfo->type; /* set tineouts */ if (pvio->methods->set_timeout) @@ -180,9 +183,14 @@ static size_t ma_pvio_read_async(MARIADB_PVIO *pvio, uchar *buffer, size_t lengt struct mysql_async_context *b= pvio->mysql->options.extension->async_context; int timeout= pvio->timeout[PVIO_READ_TIMEOUT]; + if (!pvio->methods->async_read) + { + PVIO_SET_ERROR(pvio->mysql, CR_ASYNC_NOT_SUPPORTED, unknown_sqlstate, 0); + return -1; + } + for (;;) { - /* todo: async */ if (pvio->methods->async_read) res= pvio->methods->async_read(pvio, buffer, length); if (res >= 0 || IS_BLOCKING_ERROR()) @@ -482,7 +490,7 @@ my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) /* check if we still have unread data in cache */ if (pvio->cache) if (pvio->cache_pos > pvio->cache) - return pvio->cache_pos - pvio->cache; + return test(pvio->cache_pos - pvio->cache); if (pvio && pvio->methods->has_data) return pvio->methods->has_data(pvio, data_len); return 1; diff --git a/libmariadb/ma_ssl.c b/libmariadb/ma_ssl.c index 3ea613e3..2ea474a8 100644 --- a/libmariadb/ma_ssl.c +++ b/libmariadb/ma_ssl.c @@ -51,6 +51,8 @@ my_bool ma_ssl_initialized= FALSE; unsigned int mariadb_deinitialize_ssl= 1; +char *ssl_protocol_version[5]= {"unknown", "SSL3", "TLS1.0", "TLS1.1", "TLS1.2"}; + MARIADB_SSL *ma_pvio_ssl_init(MYSQL *mysql) { MARIADB_SSL *cssl= NULL; @@ -104,6 +106,11 @@ const char *ma_pvio_ssl_cipher(MARIADB_SSL *cssl) return ma_ssl_get_cipher(cssl); } +my_bool ma_pvio_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) +{ + return ma_ssl_get_protocol_version(cssl, version); +} + static my_bool ma_pvio_ssl_compare_fp(char *fp1, unsigned int fp1_len, char *fp2, unsigned int fp2_len) { diff --git a/libmariadb/my_static.c b/libmariadb/my_static.c index 61d25574..9a892996 100644 --- a/libmariadb/my_static.c +++ b/libmariadb/my_static.c @@ -73,8 +73,6 @@ uint sf_malloc_prehunc=0, /* If you have problem with core- */ size_t lCurMemory = 0L; /* Current memory usage */ size_t lMaxMemory = 0L; /* Maximum memory usage */ uint cNewCount = 0; /* Number of times NEW() was called */ -unsigned char *sf_min_adress= (unsigned char*) ~(unsigned long) 0L, - *sf_max_adress= (unsigned char*) 0L; /* Root of the linked list of remembers */ struct remember *pRememberRoot = NULL; diff --git a/libmariadb/my_static.h b/libmariadb/my_static.h index a30b462d..8a6be025 100644 --- a/libmariadb/my_static.h +++ b/libmariadb/my_static.h @@ -61,7 +61,6 @@ extern uint my_once_extra; extern int _my_tempnam_used; #endif -extern unsigned char *sf_min_adress,*sf_max_adress; extern uint cNewCount; extern struct remember *pRememberRoot; diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index 7f0355b5..58a5c951 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -416,7 +416,6 @@ int store_param(MYSQL_STMT *stmt, int column, unsigned char **p) { DBUG_ENTER("store_param"); DBUG_PRINT("info", ("column: %d type: %d", column, stmt->params[column].buffer_type)); - printf("type: %d\n", column, stmt->params[column].buffer_type); switch (stmt->params[column].buffer_type) { case MYSQL_TYPE_TINY: int1store(*p, *(uchar *)stmt->params[column].buffer); diff --git a/libmariadb/mysql_async.c b/libmariadb/mysql_async.c index 4a86ab90..f7dfc998 100644 --- a/libmariadb/mysql_async.c +++ b/libmariadb/mysql_async.c @@ -394,7 +394,7 @@ MK_ASYNC_CONT_BODY( struct mysql_real_query_params { MYSQL *mysql; const char *stmt_str; - unsigned long length; + size_t length; }; static void mysql_real_query_start_internal(void *d) @@ -578,7 +578,7 @@ MK_ASYNC_CONT_BODY( struct mysql_send_query_params { MYSQL *mysql; const char *q; - unsigned long length; + size_t length; }; static void mysql_send_query_start_internal(void *d) @@ -1311,7 +1311,7 @@ MK_ASYNC_CONT_BODY( struct mysql_stmt_prepare_params { MYSQL_STMT *stmt; const char *query; - unsigned long length; + size_t length; }; static void mysql_stmt_prepare_start_internal(void *d) @@ -1614,7 +1614,7 @@ struct mysql_stmt_send_long_data_params { MYSQL_STMT *stmt; unsigned int param_number; const char *data; - unsigned long length; + size_t length; }; static void mysql_stmt_send_long_data_start_internal(void *d) diff --git a/libmariadb/net.c b/libmariadb/net.c index df75c8c0..9788906a 100644 --- a/libmariadb/net.c +++ b/libmariadb/net.c @@ -193,10 +193,11 @@ static my_bool net_realloc(NET *net, my_bool is_multi, size_t length) } /* Remove unwanted characters from connection */ - void net_clear(NET *net) { + size_t len; DBUG_ENTER("net_clear"); + ma_pvio_has_data(net->pvio, &len); net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */ net->write_pos=net->buff; if (net->mbuff) @@ -204,13 +205,12 @@ void net_clear(NET *net) DBUG_VOID_RETURN; } - /* Flush write_buffer if not empty. */ - int net_flush(NET *net) { int error=0; DBUG_ENTER("net_flush"); + if (net->buff != net->write_pos) { error=net_real_write(net,(char*) net->buff, @@ -222,12 +222,10 @@ int net_flush(NET *net) DBUG_RETURN(error); } - /***************************************************************************** ** Write something to server/client buffer *****************************************************************************/ - /* ** Write a logical packet with packet header ** Format: Packet length (3 bytes), packet number(1 byte) diff --git a/libmariadb/secure/gnutls.c b/libmariadb/secure/gnutls.c index cfa89006..5b955e1b 100644 --- a/libmariadb/secure/gnutls.c +++ b/libmariadb/secure/gnutls.c @@ -423,5 +423,13 @@ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsig } } -#endif /* HAVE_GNUTLS */ +my_bool ma_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) +{ + if (!cssl || !cssl->ssl) + return 1; + version->iversion= gnutls_protocol_get_version(cssl->ssl); + version->cversion= (char *)gnutls_protocol_get_name(version->iversion); + return 0; +} +#endif /* HAVE_GNUTLS */ diff --git a/libmariadb/secure/ma_schannel.c b/libmariadb/secure/ma_schannel.c index 065a9ab7..063ce361 100644 --- a/libmariadb/secure/ma_schannel.c +++ b/libmariadb/secure/ma_schannel.c @@ -338,7 +338,7 @@ my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, CERT_CONTEXT *ctx, char goto end; } /* ... and import the private key */ - if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, NULL, 0, (HCRYPTKEY *)&crypt_key)) + if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, 0, 0, (HCRYPTKEY *)&crypt_key)) { ma_schannel_set_win_error(pvio); goto end; @@ -427,7 +427,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe { if(fDoRead) { - cbData = pvio->methods->read(pvio, IoBuffer + cbIoBuffer, (size_t)(SC_IO_BUFFER_SIZE - cbIoBuffer)); + cbData = (DWORD)pvio->methods->read(pvio, IoBuffer + cbIoBuffer, (size_t)(SC_IO_BUFFER_SIZE - cbIoBuffer)); if (cbData == SOCKET_ERROR || cbData == 0) { rc = SEC_E_INTERNAL_ERROR; @@ -486,7 +486,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe { if(OutBuffers[0].cbBuffer && OutBuffers[0].pvBuffer) { - cbData= pvio->methods->write(pvio, (uchar *)OutBuffers[0].pvBuffer, (size_t)OutBuffers[0].cbBuffer); + cbData= (DWORD)pvio->methods->write(pvio, (uchar *)OutBuffers[0].pvBuffer, (size_t)OutBuffers[0].cbBuffer); if(cbData == SOCKET_ERROR || cbData == 0) { FreeContextBuffer(OutBuffers[0].pvBuffer); @@ -626,18 +626,10 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl) return sRet; } - /* Allocate IO-Buffer */ - sctx->IoBufferSize= 2 * net_buffer_length; - if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(LMEM_ZEROINIT, sctx->IoBufferSize))) - { - sRet= SEC_E_INSUFFICIENT_MEMORY; - goto end; - } - /* send client hello packaet */ if(BuffersOut[0].cbBuffer != 0 && BuffersOut[0].pvBuffer != NULL) { - r= pvio->methods->write(pvio, (uchar *)BuffersOut[0].pvBuffer, (size_t)BuffersOut[0].cbBuffer); + r= (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut[0].pvBuffer, (size_t)BuffersOut[0].cbBuffer); if (r <= 0) { sRet= SEC_E_INTERNAL_ERROR; @@ -646,11 +638,17 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl) } sRet= ma_schannel_handshake_loop(pvio, TRUE, &ExtraData); - /* Reallocate IO-Buffer for write operations: After handshake + /* allocate IO-Buffer for write operations: After handshake was successfull, we are able now to calculate payload */ - QueryContextAttributes( &sctx->ctxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes ); + if ((sRet = QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes ))) + goto end; + sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes); - sctx->IoBuffer= LocalReAlloc(sctx->IoBuffer, sctx->IoBufferSize, LMEM_ZEROINIT); + if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, sctx->IoBufferSize))) + { + sRet= SEC_E_INSUFFICIENT_MEMORY; + goto end; + } return sRet; end: @@ -697,7 +695,6 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio, SECURITY_STATUS sRet= 0; SecBufferDesc Msg; SecBuffer Buffers[4], - ExtraBuffer, *pData, *pExtra; int i; @@ -711,18 +708,18 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio, { if (!dwBytesRead || sRet == SEC_E_INCOMPLETE_MESSAGE) { - dwBytesRead= pvio->methods->read(pvio, sctx->IoBuffer + dwOffset, (size_t)(sctx->IoBufferSize - dwOffset)); + dwBytesRead= (DWORD)pvio->methods->read(pvio, sctx->IoBuffer + dwOffset, (size_t)(sctx->IoBufferSize - dwOffset)); if (dwBytesRead == 0) { /* server closed connection */ // todo: error - return NULL; + return SEC_E_INVALID_HANDLE; } if (dwBytesRead < 0) { /* socket error */ // todo: error - return NULL; + return SEC_E_INVALID_HANDLE; } dwOffset+= dwBytesRead; } @@ -777,6 +774,7 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio, dwOffset= 0; } } +/* }}} */ my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags) { @@ -863,7 +861,7 @@ size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio, SECURITY_STATUS scRet; SecBufferDesc Message; SecBuffer Buffers[4]; - DWORD cbMessage, cbData; + DWORD cbMessage; PBYTE pbMessage; SC_CTX *sctx= (SC_CTX *)pvio->cssl->ssl; size_t payload; @@ -898,8 +896,45 @@ size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio, return -1; if (pvio->methods->write(pvio, sctx->IoBuffer, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer)) - return payload; + return payload; return 0; } /* }}} */ +extern char *ssl_protocol_version[5]; + +/* {{{ ma_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) */ +my_bool ma_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) +{ + SC_CTX *sctx; + SecPkgContext_ConnectionInfo ConnectionInfo; + if (!cssl->ssl) + return 1; + + sctx= (SC_CTX *)cssl->ssl; + + if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_CONNECTION_INFO, &ConnectionInfo) != SEC_E_OK) + return 1; + + switch(ConnectionInfo.dwProtocol) + { + case SP_PROT_SSL3_CLIENT: + version->iversion= 1; + break; + case SP_PROT_TLS1_CLIENT: + version->iversion= 2; + break; + case SP_PROT_TLS1_1_CLIENT: + version->iversion= 3; + break; + case SP_PROT_TLS1_2_CLIENT: + version->iversion= 4; + break; + default: + version->iversion= 0; + break; + } + version->cversion= ssl_protocol_version[version->iversion]; + return 0; +} +/* }}} */ diff --git a/libmariadb/secure/openssl.c b/libmariadb/secure/openssl.c index 37256efc..e659a1a1 100644 --- a/libmariadb/secure/openssl.c +++ b/libmariadb/secure/openssl.c @@ -177,8 +177,11 @@ int ma_ssl_start(char *errmsg, size_t errmsg_len) SSL_load_error_strings(); /* digests and ciphers */ OpenSSL_add_all_algorithms(); - - if (!(SSL_context= SSL_CTX_new(TLSv1_client_method()))) +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + if (!(SSL_context= SSL_CTX_new(TLS_client_method()))) +#else + if (!(SSL_context= SSL_CTX_new(SSLv23_client_method()))) +#endif { ma_ssl_get_error(errmsg, errmsg_len); goto end; @@ -464,9 +467,13 @@ int ma_ssl_verify_server_cert(MARIADB_SSL *cssl) { X509 *cert; MYSQL *mysql; - MARIADB_PVIO *pvio; + X509_NAME *x509sn; + int cn_pos; + X509_NAME_ENTRY *cn_entry; + ASN1_STRING *cn_asn1; + const char *cn_str; SSL *ssl; - char *p1, *p2, buf[256]; + MARIADB_PVIO *pvio; if (!cssl || !cssl->ssl) return 1; @@ -477,33 +484,46 @@ int ma_ssl_verify_server_cert(MARIADB_SSL *cssl) if (!mysql->host) { - pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, - "Invalid (empty) hostname"); + pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), "Invalid (empty) hostname"); return 1; } if (!(cert= SSL_get_peer_certificate(ssl))) { - pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, - "Unable to get server certificate"); + pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), "Unable to get server certificate"); return 1; } - X509_NAME_oneline(X509_get_subject_name(cert), buf, 256); + x509sn= X509_get_subject_name(cert); + + if ((cn_pos= X509_NAME_get_index_by_NID(x509sn, NID_commonName, -1)) < 0) + goto error; + + if (!(cn_entry= X509_NAME_get_entry(x509sn, cn_pos))) + goto error; + + if (!(cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry))) + goto error; + + cn_str = (char *)ASN1_STRING_data(cn_asn1); + + /* Make sure there is no embedded \0 in the CN */ + if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn_str)) + goto error; + + if (strcmp(cn_str, mysql->host)) + goto error; + X509_free(cert); - /* Extract the server name from buffer: - Format: ....CN=/hostname/.... */ - if ((p1= strstr(buf, "/CN="))) - { - p1+= 4; - if ((p2= strchr(p1, '/'))) - *p2= 0; - if (!strcmp(mysql->host, p1)) - return(0); - } - pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, - "Validation of SSL server certificate failed"); + return 0; +error: + X509_free(cert); + + pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), "Validation of SSL server certificate failed"); return 1; } @@ -552,3 +572,37 @@ unsigned int ma_ssl_get_finger_print(MARIADB_SSL *cssl, unsigned char *fp, unsig } return (fp_len); } + + +extern char *ssl_protocol_version[5]; + +my_bool ma_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) +{ + SSL *ssl; + + if (!cssl || !cssl->ssl) + return 1; + + ssl = (SSL *)cssl->ssl; + switch(ssl->version) + { + case SSL3_VERSION: + version->iversion= 1; + break; + case TLS1_VERSION: + version->iversion= 2; + break; + case TLS1_1_VERSION: + version->iversion= 3; + break; + case TLS1_2_VERSION: + version->iversion= 4; + break; + default: + version->iversion= 0; + break; + } + version->cversion= ssl_protocol_version[version->iversion]; + return 0; +} + diff --git a/libmariadb/secure/schannel.c b/libmariadb/secure/schannel.c index cc0fd4e2..3f84c17f 100644 --- a/libmariadb/secure/schannel.c +++ b/libmariadb/secure/schannel.c @@ -284,7 +284,7 @@ my_bool ma_ssl_connect(MARIADB_SSL *cssl) Cred.cCreds = 1; Cred.paCred = &sctx->client_cert_ctx; } - Cred.grbitEnabledProtocols= SP_PROT_TLS1; + Cred.grbitEnabledProtocols= SP_PROT_TLS1_1PLUS; if ((sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL)) != SEC_E_OK) diff --git a/mariadb_config/libmariadb.pc.in b/mariadb_config/libmariadb.pc.in new file mode 100644 index 00000000..e9161554 --- /dev/null +++ b/mariadb_config/libmariadb.pc.in @@ -0,0 +1,19 @@ +# +# pkg_config.pc.in +# +# pkg_config configuration file +# For a detailled description of options, please visit +# Dan Nicholson’s Guide to pkg-config (http://www.freedesktop.org/wiki/Software/pkg-config/) +# + +includedir=@PREFIX_INSTALL_DIR@/@INCLUDE_INSTALL_DIR@/@SUFFIX_INSTALL_DIR@ +libdir=@PREFIX_INSTALL_DIR@/@INCLUDE_INSTALL_DIR@/@SUFFIX_INSTALL_DIR@ +prefix=@PREFIX_INSTALL_DIR@ + +Name: libmariadb +Version: @LIBMARIADB_VERSION@ +Description: MariaDB Connector/C dynamic library +Cflags: -I@PREFIX_INSTALL_DIR@/@INCLUDE_INSTALL_DIR@/@SUFFIX_INSTALL_DIR@ @CMAKE_C_FLAGS@ +Libs: -L@PREFIX_INSTALL_DIR@/@LIB_INSTALL_DIR@/@SUFFIX_INSTALL_DIR@ -lmariadb @extra_dynamic_LDFLAGS@ + + diff --git a/plugins/connection/CMakeLists.txt b/plugins/connection/CMakeLists.txt index f5d7cc19..4ccdd611 100644 --- a/plugins/connection/CMakeLists.txt +++ b/plugins/connection/CMakeLists.txt @@ -13,10 +13,30 @@ IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC") "FILE_DESCRIPTION:Connection plugin for master/slave environment") ENDIF() ADD_DEFINITIONS(-DHAVE_REPLICATION_DYNAMIC=1) - ADD_LIBRARY(replication SHARED replication.c ${EXPORT_FILE}) + ADD_LIBRARY(replication SHARED ${replication_RC} replication.c ${EXPORT_FILE}) + IF(WIN32) + TARGET_LINK_LIBRARIES(replication libmariadb) + ENDIF() SET(INSTALL_LIBS replication) ENDIF() +IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC") + IF(WIN32) + SET_VERSION_INFO("TARGET:aurora" + "FILE_TYPE:VFT_DLL" + "SOURCE_FILE:plugins/connection/aurora.c" + "ORIGINAL_FILE_NAME:aurora.dll" + "FILE_DESCRIPTION:Connection plugin for Amazon AWS Aurora") + ENDIF() + ADD_DEFINITIONS(-DHAVE_AURORA_DYNAMIC=1) + ADD_LIBRARY(aurora SHARED ${aurora_RC} aurora.c ${EXPORT_FILE}) + IF(WIN32) + TARGET_LINK_LIBRARIES(aurora libmariadb) + ENDIF() + SET(INSTALL_LIBS ${INSTALL_LIBS} aurora) +ENDIF() + + IF(INSTALL_LIBS) INSTALL(TARGETS ${INSTALL_LIBS} diff --git a/plugins/connection/aurora.c b/plugins/connection/aurora.c new file mode 100644 index 00000000..524f4364 --- /dev/null +++ b/plugins/connection/aurora.c @@ -0,0 +1,819 @@ +/************************************************************************************ + Copyright (C) 2015 MariaDB Corporation AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA + + Part of this code includes code from the PHP project which + is freely available from http://www.php.net + *************************************************************************************/ + +/* MariaDB Connection plugin for Aurora failover */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +/* function prototypes */ +int aurora_init(char *errormsg, size_t errormsg_size, + int unused __attribute__((unused)), + va_list unused1 __attribute__((unused))); + +MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, + const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); +void aurora_close(MYSQL *mysql); +int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + size_t length, my_bool skipp_check, void *opt_arg); +int aurora_set_options(MYSQL *msql, enum mysql_option option, void *arg); +my_bool aurora_reconnect(MYSQL *mysql); + +#define AURORA_MAX_INSTANCES 16 + +#define AURORA_UNKNOWN -1 +#define AURORA_PRIMARY 0 +#define AURORA_REPLICA 1 +#define AURORA_UNAVAILABLE 2 + +#define ENABLE_AURORA(mysql)\ + (mysql)->net.conn_hdlr->active= 1; +#define DISABLE_AURORA(mysql)\ + (mysql)->net.conn_hdlr->active= 0; + +#ifndef HAVE_AURORA_DYNAMIC +MARIADB_CONNECTION_PLUGIN connection_aurora_plugin = +#else +MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ = +#endif +{ + MARIADB_CLIENT_CONNECTION_PLUGIN, + MARIADB_CLIENT_CONNECTION_PLUGIN_INTERFACE_VERSION, + "aurora", + "Georg Richter", + "MariaDB connection plugin for Aurora failover", + {1, 0, 0}, + "LGPL", + aurora_init, + NULL, + aurora_connect, + aurora_close, + aurora_set_options, + aurora_command, + aurora_reconnect +}; + +struct st_mariadb_api *mariadb_api= NULL; + +typedef struct st_aurora_instance { + char *host; + int port; + time_t blacklisted; + int type; +} AURORA_INSTANCE; + +typedef struct st_conn_aurora { + MARIADB_PVIO *pvio[2]; + MYSQL *mysql[2]; + my_bool active[2]; + char *url; + unsigned int num_instances; + AURORA_INSTANCE instance[AURORA_MAX_INSTANCES]; + char *username, *password, *database; + unsigned int port; + unsigned long client_flag; + unsigned int last_instance_type; /* Primary or Replica */ + char primary_id[100]; +} AURORA; + +#define AURORA_BLACKLIST_TIMEOUT 150 + +#define AURORA_IS_BLACKLISTED(a, i) \ + ((time(NULL) - (a)->instance[(i)].blacklisted) < AURORA_BLACKLIST_TIMEOUT) + +/* {{{ my_bool aurora_swutch_connection */ +my_bool aurora_switch_connection(MYSQL *mysql, AURORA *aurora, int type) +{ + switch (type) + { + case AURORA_REPLICA: + if (aurora->mysql[AURORA_REPLICA]) + { + mysql->net.pvio= aurora->pvio[AURORA_REPLICA]; + aurora->pvio[AURORA_REPLICA]->mysql= mysql; + mysql->thread_id= aurora->mysql[AURORA_REPLICA]->thread_id; + aurora->last_instance_type= AURORA_REPLICA; + } + break; + case AURORA_PRIMARY: + if (aurora->mysql[AURORA_PRIMARY]) + { + if (aurora->mysql[AURORA_REPLICA]) + aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA]; + mysql->net.pvio= aurora->pvio[AURORA_PRIMARY]; + mysql->thread_id= aurora->mysql[AURORA_PRIMARY]->thread_id; + aurora->last_instance_type= AURORA_PRIMARY; + } + break; + default: + return 1; + } + return 0; +} +/* }}} */ + +/* {{{ int aurora_init + * + * plugin initialization function + */ +int aurora_init(char *errormsg, size_t errormsg_size, + int unused __attribute__((unused)), + va_list unused1 __attribute__((unused))) +{ + /* random generator initialization */ +#ifndef WIN32 + struct timeval tp; + gettimeofday(&tp,NULL); + srand(tp.tv_usec / 1000 + tp.tv_sec * 1000); +#else + srand(GetTickCount()); +#endif + return 0; +} +/* }}} */ + +/* {{{ void aurora_close_memory */ +void aurora_close_memory(AURORA *aurora) +{ + free(aurora->url); + free(aurora->username); + free(aurora->password); + free(aurora->database); + free(aurora); +} +/* }}} */ + +/* {{{ my_bool aurora_parse_url + * + * parse url + * Url has the following format: + * instance1:port, instance2:port, .., instanceN:port + * + */ +my_bool aurora_parse_url(const char *url, AURORA *aurora) +{ + char *p, *c; + unsigned int i; + + if (!url || url[0] == 0) + return 1; + + bzero(aurora->instance, (AURORA_MAX_INSTANCES + 1) * sizeof(char *)); + bzero(&aurora->port, (AURORA_MAX_INSTANCES + 1) * sizeof(int)); + + if (aurora->url) + free(aurora->url); + + aurora->url= strdup(url); + c= aurora->url; + + /* get instances */ + while((c)) + { + if (p= strchr(c, ',')) + { + *p= '\0'; + p++; + } + if (*c) + { + aurora->instance[aurora->num_instances].host= c; + aurora->num_instances++; + } + c= p; + } + + if (!aurora->num_instances) + return 0; + + /* check ports */ + for (i=0; i < aurora->num_instances && aurora->instance[i].host; i++) + { + aurora->instance[i].type= AURORA_UNKNOWN; + + /* We need to be aware of IPv6 addresses: According to RFC3986 sect. 3.2.2 + hostnames have to be enclosed in square brackets if a port is given */ + if (aurora->instance[i].host[0]== '[' && + strchr(aurora->instance[i].host, ':') && + (p= strchr(aurora->instance[i].host,']'))) + { + /* ignore first square bracket */ + memmove(aurora->instance[i].host, + aurora->instance[i].host+1, + strlen(aurora->instance[i].host) - 1); + p= strchr(aurora->instance[i].host,']'); + *p= 0; + p++; + } + else + p= aurora->instance[i].host; + if (p && (p= strchr(p, ':'))) + { + *p= '\0'; + p++; + aurora->instance[i].port= atoi(p); + } + } + return 0; +} +/* }}} */ + +/* {{{ int aurora_get_instance_type + * + * RETURNS: + * + * AURORA_PRIMARY + * AURORA_REPLICA + * -1 on error + */ +int aurora_get_instance_type(MYSQL *mysql) +{ + int rc; + char *query= "select variable_value from information_schema.global_variables where variable_name='INNODB_READ_ONLY' AND variable_value='OFF'"; + + if (!mariadb_api->mysql_query(mysql, query)) + { + MYSQL_RES *res= mysql_store_result(mysql); + rc= mysql_num_rows(res) ? AURORA_PRIMARY : AURORA_REPLICA; + mysql_free_result(res); + return rc; + } + return -1; +} +/* }}} */ + +/* {{{ my_bool aurora_get_primary_id + * + * try to find primary instance from slave by retrieving + * primary_id information_schema.replica_host_status information + * + * If the function succeeds, primary_id will be copied into + * aurora->primary_id + * + * Returns: + * 1 on success + * 0 if an error occured or primary_id couldn't be + * found + */ +my_bool aurora_get_primary_id(MYSQL *mysql, AURORA *aurora) +{ + my_bool rc= 0; + + if (!mariadb_api->mysql_query(mysql, "select server_id from information_schema.replica_host_status " + "where session_id = 'MASTER_SESSION_ID'")) + { + MYSQL_RES *res; + MYSQL_ROW row; + + if ((res= mysql_store_result(mysql))) + { + if ((row= mysql_fetch_row(res))) + { + if (row[0]) + { + strcpy(aurora->primary_id, row[0]); + rc= 1; + } + } + mysql_free_result(res); + } + } + return rc; +} +/* }}} */ + +/* {{{ unsigned int aurora_get_valid_instances + * + * returns the number of instances which are + * not blacklisted or don't have a type assigned. + */ +static unsigned int aurora_get_valid_instances(AURORA *aurora, AURORA_INSTANCE **instances) +{ + unsigned int i, valid_instances= 0; + + memset(instances, 0, sizeof(AURORA_INSTANCE *) * AURORA_MAX_INSTANCES); + + for (i=0; i < aurora->num_instances; i++) + { + if (aurora->instance[i].type != AURORA_UNAVAILABLE) + { + if (aurora->instance[i].type == AURORA_PRIMARY && aurora->active[AURORA_PRIMARY]) + continue; + instances[valid_instances]= &aurora->instance[i]; + valid_instances++; + } + } + return valid_instances; +} +/* }}} */ + +/* {{{ void aurora_refresh_blacklist() */ +void aurora_refresh_blacklist(AURORA *aurora) +{ + unsigned int i; + for (i=0; i < aurora->num_instances; i++) + { + if (aurora->instance[i].blacklisted && + !(AURORA_IS_BLACKLISTED(aurora, i))) + { + aurora->instance[i].blacklisted= 0; + aurora->instance[i].type= AURORA_UNKNOWN; + } + } +} +/* }}} */ + +/* {{{ MYSQL *aurora_connect_instance() */ +MYSQL *aurora_connect_instance(AURORA *aurora, AURORA_INSTANCE *instance, MYSQL *mysql) +{ + if (!mysql->methods->db_connect(mysql, + instance->host, + aurora->username, + aurora->password, + aurora->database, + instance->port ? instance->port : aurora->port, + NULL, + aurora->client_flag)) + { + /* connection not available */ + instance->blacklisted= time(NULL); + instance->type= AURORA_UNAVAILABLE; + return NULL; + } + + /* check if we are slave or master */ + switch (aurora_get_instance_type(mysql)) + { + case AURORA_PRIMARY: + instance->type= AURORA_PRIMARY; + return mysql; + break; + case AURORA_REPLICA: + instance->type= AURORA_REPLICA; + break; + default: + instance->type= AURORA_UNAVAILABLE; + instance->blacklisted= time(NULL); + return NULL; + } + if (!aurora->primary_id[0]) + aurora_get_primary_id(mysql, aurora); + return mysql; +} +/* }}} */ + +/* {{{ void aurora_copy_mysql() */ +void aurora_copy_mysql(MYSQL *from, MYSQL *to) +{ + /* invalidate statements */ + to->methods->invalidate_stmts(to, "aurora connect/reconnect"); + + from->free_me= to->free_me; + from->reconnect= to->reconnect; + from->net.conn_hdlr= to->net.conn_hdlr; + from->stmts= to->stmts; + to->stmts= NULL; + + memset(&to->options, 0, sizeof(to->options)); + to->free_me= 0; + to->net.conn_hdlr= 0; + mariadb_api->mysql_close(to); + *to= *from; + to->net.pvio= from->net.pvio; + to->net.pvio->mysql= to; + from->net.pvio= NULL; +} +/* }}} */ + +/* {{{ my_bool aurora_find_replica() */ +my_bool aurora_find_replica(AURORA *aurora) +{ + int valid_instances; + my_bool replica_found= 0; + AURORA_INSTANCE *instance[AURORA_MAX_INSTANCES]; + MYSQL mysql; + + if (aurora->num_instances < 2) + return 0; + + mariadb_api->mysql_init(&mysql); + mysql.options= aurora->mysql[AURORA_PRIMARY]->options; + + /* don't execute init_command on slave */ + mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr; + + valid_instances= aurora_get_valid_instances(aurora, instance); + + while (valid_instances && !replica_found) + { + int random_pick= rand() % valid_instances; + if ((aurora_connect_instance(aurora, instance[random_pick], &mysql))) + { + switch (instance[random_pick]->type) { + case AURORA_REPLICA: + if (!aurora->mysql[AURORA_REPLICA]) + { + aurora->mysql[AURORA_REPLICA]= mysql_init(NULL); + } + aurora_copy_mysql(&mysql, aurora->mysql[AURORA_REPLICA]); + aurora->active[AURORA_REPLICA]= 1; + return 1; + break; + case AURORA_PRIMARY: + aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); + aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio; + aurora->active[AURORA_PRIMARY]= 1; + continue; + break; + default: + mysql_close(&mysql); + return 0; + break; + } + } + valid_instances= aurora_get_valid_instances(aurora, instance); + } + return 0; +} +/* }}} */ + +/* {{{ AURORA_INSTANCE aurora_get_primary_id_instance() */ +AURORA_INSTANCE *aurora_get_primary_id_instance(AURORA *aurora) +{ + unsigned int i; + + if (!aurora->primary_id[0]) + return 0; + + for (i=0; i < aurora->num_instances; i++) + { + if (!strncmp(aurora->instance[i].host, aurora->primary_id, strlen(aurora->primary_id))) + return &aurora->instance[i]; + } + return NULL; +} +/* }}} */ + +/* {{{ my_bool aurora_find_primary() */ +my_bool aurora_find_primary(AURORA *aurora) +{ + unsigned int i; + AURORA_INSTANCE *instance= NULL; + MYSQL mysql; + my_bool check_primary= 1; + + if (!aurora->num_instances) + return 0; + + mariadb_api->mysql_init(&mysql); + mysql.options= aurora->mysql[AURORA_PRIMARY]->options; + mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr; + + for (i=0; i < aurora->num_instances; i++) + { + if (check_primary && aurora->primary_id[0]) + { + if ((instance= aurora_get_primary_id_instance(aurora)) && + aurora_connect_instance(aurora, instance, &mysql) && + instance->type == AURORA_PRIMARY) + { + aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); + aurora->active[AURORA_PRIMARY]= 1; + return 1; + } + /* primary id connect failed, don't try again */ + aurora->primary_id[0]= 0; + check_primary= 0; + } + if (aurora->instance[i].type != AURORA_UNAVAILABLE) + { + if (aurora_connect_instance(aurora, &aurora->instance[i], &mysql) + && aurora->instance[i].type == AURORA_PRIMARY) + { + aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); + aurora->active[AURORA_PRIMARY]= 1; + return 1; + } + } + } + return 0; +} +/* }}} */ + +/* {{{ void aurora_close_replica() */ +void aurora_close_replica(MYSQL *mysql, AURORA *aurora) +{ + if (aurora->mysql[AURORA_REPLICA]) + { + aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA]; + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0; + mariadb_api->mysql_close(aurora->mysql[AURORA_REPLICA]); + aurora->pvio[AURORA_REPLICA]= 0; + aurora->mysql[AURORA_REPLICA]= NULL; + } +} +/* }}} */ + +/* {{{ MYSQL *aurora_connect */ +MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, + const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) +{ + AURORA *aurora= NULL; + MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; + my_bool is_reconnect= 0; + + if (!mariadb_api) + mariadb_api= mysql->methods->api; + + mariadb_api->mariadb_get_info(mysql, MARIADB_CLIENT_ERRORS, &client_errors); + + if ((aurora= (AURORA *)hdlr->data)) + { + aurora_refresh_blacklist(aurora); + if (aurora->mysql[aurora->last_instance_type]->net.pvio) + { + SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0); + return NULL; + } + is_reconnect= 1; + } + else + { + if (!(aurora= (AURORA *)calloc(1, sizeof(AURORA)))) + { + mysql->methods->set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + return NULL; + } + + mysql->net.conn_hdlr->data= (void *)aurora; + + aurora->mysql[AURORA_PRIMARY]= mysql; + + if (aurora_parse_url(host, aurora)) + { + goto error; + } + + if (user) + aurora->username= strdup(user); + if (passwd) + aurora->password= strdup(passwd); + if (db) + aurora->database= strdup(db); + aurora->port= port; + aurora->client_flag= client_flag; + aurora->pvio[AURORA_PRIMARY]= aurora->pvio[AURORA_REPLICA]= NULL; + hdlr->data= aurora; + } + + + /* In case of reconnect, close broken connection first */ + if (is_reconnect) + { + DISABLE_AURORA(mysql); + switch (aurora->last_instance_type) { + case AURORA_REPLICA: + aurora_close_replica(mysql, aurora); + aurora->pvio[AURORA_REPLICA]= NULL; + break; + case AURORA_PRIMARY: + /* pvio will be closed in mysql_reconnect() */ + aurora->pvio[AURORA_PRIMARY]= NULL; + aurora->primary_id[0]= 0; + break; + } + aurora->active[aurora->last_instance_type]= 0; + } + + if (!aurora->active[AURORA_REPLICA]) + { + if (aurora_find_replica(aurora)) + { + aurora->pvio[AURORA_REPLICA]= aurora->mysql[AURORA_REPLICA]->net.pvio; + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= mysql->net.conn_hdlr; + } + else + aurora->pvio[AURORA_REPLICA]= NULL; + } + + if (!aurora->active[AURORA_PRIMARY]) + { + if (aurora_find_primary(aurora)) + { + aurora->active[AURORA_PRIMARY]= 1; + aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio; + } + } + + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + ENABLE_AURORA(mysql); + return mysql; +error: + aurora_close_memory(aurora); + return NULL; +} +/* }}} */ + +/* {{{ my_bool aurora_reconnect */ +my_bool aurora_reconnect(MYSQL *mysql) +{ + AURORA *aurora; + MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; + my_bool rc= 1; + + aurora= (AURORA *)hdlr->data; + + DISABLE_AURORA(mysql); + switch (aurora->last_instance_type) + { + case AURORA_REPLICA: + if (!(rc= mariadb_api->mysql_reconnect(aurora->mysql[aurora->last_instance_type]))) + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + break; + case AURORA_PRIMARY: + if (!(rc= mysql_reconnect(aurora->mysql[aurora->last_instance_type]))) + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + break; + default: + /* todo: error message */ + break; + } + ENABLE_AURORA(mysql); + return rc; +} +/* }}} */ + +/* {{{ void aurora_close */ +void aurora_close(MYSQL *mysql) +{ + MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; + AURORA *aurora= (AURORA *)hdlr->data; + + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + + /* if the connection is not active yet, just return */ + if (!aurora->active[1]) + return; + + if (aurora->mysql[AURORA_REPLICA]) + { + /* we got options from primary, so don't free it twice */ + memset(&aurora->mysql[AURORA_REPLICA]->options, 0, sizeof(mysql->options)); + /* connection handler wull be freed in mariadb_api->mysql_close() */ + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0; + + mysql_close(aurora->mysql[AURORA_REPLICA]); + } + + if (aurora->mysql[AURORA_PRIMARY]) + { + /* connection handler wull be freed in mysql_close() */ + aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0; + + aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY]; + + mysql_close(aurora->mysql[AURORA_PRIMARY]); + } + + + +/* + if (aurora->mysql[AURORA_PRIMARY]) + { + aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY]; + aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0; + mysql_close(aurora->mysql[AURORA_PRIMARY]); + } +*/ + /* free masrwe information */ + aurora_close_memory(aurora); +} +/* }}} */ + +/* {{{ my_bool is_replica_command */ +my_bool is_replica_command(const char *buffer, size_t buffer_len) +{ + const char *buffer_end= buffer + buffer_len; + + for (; buffer < buffer_end; ++buffer) + { + char c; + if (isalpha(c=*buffer)) + { + if (tolower(c) == 's') + return 1; + return 0; + } + } + return 0; +} +/* }}} */ + +/* {{{ my_bool is_replica_stmt */ +my_bool is_replica_stmt(MYSQL *mysql, const char *buffer) +{ + unsigned long stmt_id= uint4korr(buffer); + LIST *stmt_list= mysql->stmts; + + for (; stmt_list; stmt_list= stmt_list->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *)stmt_list->data; + if (stmt->stmt_id == stmt_id) + return 1; + } + return 0; +} +/* }}} */ + +/* {{{ int aurora_command */ +int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + size_t length, my_bool skipp_check, void *opt_arg) +{ + AURORA *aurora= (AURORA *)mysql->net.conn_hdlr->data; + + /* if we don't have slave or slave became unavailable root traffic to master */ + if (!aurora->mysql[AURORA_REPLICA] || !OPT_HAS_EXT_VAL(mysql, read_only)) + { + if (command != COM_INIT_DB) + { + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + return 0; + } + } + + switch(command) { + case COM_INIT_DB: + /* we need to change default database on primary and replica */ + if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA) + { + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + DISABLE_AURORA(mysql); + mariadb_api->mysql_select_db(aurora->mysql[AURORA_REPLICA], arg); + ENABLE_AURORA(mysql); + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + } + break; + case COM_QUERY: + case COM_STMT_PREPARE: + if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA) + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + break; + case COM_STMT_EXECUTE: + case COM_STMT_FETCH: + if (aurora->pvio[AURORA_REPLICA]->mysql->stmts && is_replica_stmt(aurora->pvio[AURORA_REPLICA]->mysql, arg)) + { + if (aurora->last_instance_type != AURORA_REPLICA) + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + } + else + { + if (aurora->last_instance_type != AURORA_PRIMARY) + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + } + + default: + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + break; + } + return 0; +} +/* }}} */ + +/* {{{ int aurora_set_options() */ +int aurora_set_options(MYSQL *mysql, enum mysql_option option, void *arg) +{ + switch(option) { + default: + return -1; + } +} +/* }}} */ diff --git a/plugins/connection/replication.c b/plugins/connection/replication.c index cf5320ec..9b4d1865 100644 --- a/plugins/connection/replication.c +++ b/plugins/connection/replication.c @@ -42,16 +42,11 @@ int repl_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg); int repl_set_options(MYSQL *msql, enum mysql_option option, void *arg); -#ifdef HAVE_REPLICATION_DYNAMIC - -#undef my_free -#define my_malloc(a,b) malloc(a) -#define my_free(a) free(a) -#endif - #define MARIADB_MASTER 0 #define MARIADB_SLAVE 1 +struct st_mariadb_api *mariadb_api= NULL; + #ifndef HAVE_REPLICATION_DYNAMIC MARIADB_CONNECTION_PLUGIN connection_replication_plugin = #else @@ -70,7 +65,8 @@ MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ = repl_connect, repl_close, repl_set_options, - repl_command + repl_command, + NULL }; typedef struct st_conn_repl { @@ -81,10 +77,20 @@ typedef struct st_conn_repl { char *url; char *host[2]; int port[2]; + unsigned int current_type; } REPL_DATA; -#define SET_SLAVE(mysql, data) mysql->net.pvio= data->pvio[MARIADB_SLAVE] -#define SET_MASTER(mysql, data) mysql->net.pvio= data->pvio[MARIADB_MASTER] +#define SET_SLAVE(mysql, data)\ +{\ + mysql->net.pvio= data->pvio[MARIADB_SLAVE]; \ + data->current_type= MARIADB_SLAVE;\ +} + +#define SET_MASTER(mysql, data)\ +{\ + mysql->net.pvio= data->pvio[MARIADB_MASTER];\ + data->current_type= MARIADB_MASTER;\ +} /* parse url @@ -108,10 +114,8 @@ my_bool repl_parse_url(const char *url, REPL_DATA *data) memset(data->host, 0, 2 * sizeof(char *)); memset(data->port, 0, 2 * sizeof(int)); - if (data->url) - my_free(data->url); - - data->url= my_strdup(url, MYF(0)); + if (!data->url) + data->url= strdup(url); data->host[MARIADB_MASTER]= p= data->url; /* get slaves */ @@ -150,10 +154,11 @@ my_bool repl_parse_url(const char *url, REPL_DATA *data) { /* We need to be aware of IPv6 addresses: According to RFC3986 sect. 3.2.2 hostnames have to be enclosed in square brackets if a port is given */ - if (data->host[i][0]= '[' && strchr(data->host[i], ':') && (p= strchr(data->host[i],']'))) + if (data->host[i][0]== '[' && strchr(data->host[i], ':') && (p= strchr(data->host[i],']'))) { /* ignore first square bracket */ - data->host[i]++; + memmove(data->host[i], data->host[i]+1, strlen(data->host[i]) - 1); + p= strchr(data->host[i],']'); *p= 0; p++; } @@ -176,12 +181,21 @@ MYSQL *repl_connect(MYSQL *mysql, const char *host, const char *user, const char REPL_DATA *data= NULL; MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; + if (!mariadb_api) + mariadb_api= mysql->methods->api; + + if ((data= (REPL_DATA *)hdlr->data)) + { + data->pvio[MARIADB_MASTER]->methods->close(data->pvio[MARIADB_MASTER]); + data->pvio[MARIADB_MASTER]= 0; + repl_close(mysql); + } + if (!(data= calloc(1, sizeof(REPL_DATA)))) { mysql->methods->set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return NULL; } - memset(data->pvio, 0, 2 * sizeof(MARIADB_PVIO *)); if (repl_parse_url(host, data)) @@ -194,17 +208,18 @@ MYSQL *repl_connect(MYSQL *mysql, const char *host, const char *user, const char data->pvio[MARIADB_MASTER]= mysql->net.pvio; hdlr->data= data; + SET_MASTER(mysql, data); /* to allow immediate access without connection delay, we will start * connecting to slave(s) in background */ /* if slave connection will fail, we will not return error but use master instead */ - if (!(data->slave_mysql= mysql_init(NULL)) || + if (!(data->slave_mysql= mariadb_api->mysql_init(NULL)) || !(mysql->methods->db_connect(data->slave_mysql, data->host[MARIADB_SLAVE], user, passwd, db, data->port[MARIADB_SLAVE] ? data->port[MARIADB_SLAVE] : port, unix_socket, clientflag))) { if (data->slave_mysql) - mysql_close(data->slave_mysql); + mariadb_api->mysql_close(data->slave_mysql); data->pvio[MARIADB_SLAVE]= NULL; } else @@ -217,8 +232,8 @@ error: if (data) { if (data->url) - my_free(data->url); - my_free(data); + free(data->url); + free(data); } return NULL; } @@ -236,16 +251,15 @@ void repl_close(MYSQL *mysql) { /* restore mysql */ data->pvio[MARIADB_SLAVE]->mysql= data->slave_mysql; - mysql_close(data->slave_mysql); + mariadb_api->mysql_close(data->slave_mysql); data->pvio[MARIADB_SLAVE]= NULL; data->slave_mysql= NULL; } /* free masrwe information and close connection */ - my_free(data->url); - my_free(data); + free(data->url); + free(data); mysql->net.conn_hdlr->data= NULL; - mysql_close(mysql); } static my_bool is_slave_command(const char *buffer, size_t buffer_len) @@ -295,20 +309,20 @@ int repl_command(MYSQL *mysql,enum enum_server_command command, const char *arg, case COM_QUERY: case COM_STMT_PREPARE: if (is_slave_command(arg, length)) - SET_SLAVE(mysql, data); + SET_SLAVE(mysql, data) else - SET_MASTER(mysql,data); + SET_MASTER(mysql,data) break; case COM_STMT_EXECUTE: case COM_STMT_FETCH: if (data->pvio[MARIADB_SLAVE]->mysql->stmts && is_slave_stmt(data->pvio[MARIADB_SLAVE]->mysql, arg)) - SET_SLAVE(mysql, data); + SET_SLAVE(mysql, data) else - SET_MASTER(mysql,data); + SET_MASTER(mysql,data) break; default: - SET_MASTER(mysql,data); + SET_MASTER(mysql,data) break; } return 0; diff --git a/plugins/pvio/pvio_npipe.c b/plugins/pvio/pvio_npipe.c index 95b11a0b..623f6ba9 100644 --- a/plugins/pvio/pvio_npipe.c +++ b/plugins/pvio/pvio_npipe.c @@ -34,7 +34,9 @@ my_bool pvio_npipe_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout); int pvio_npipe_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); size_t pvio_npipe_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); +size_t pvio_npipe_async_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); size_t pvio_npipe_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); +size_t pvio_npipe_async_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int pvio_npipe_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); my_bool pvio_npipe_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); @@ -118,10 +120,10 @@ size_t pvio_npipe_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length) goto end; } if (GetLastError() == ERROR_IO_PENDING) - r= pvio_npipe_wait_io_or_timeout(pvio, 1, 0); - - if (!r) - r= cpipe->rw_size; + { + if (!pvio_npipe_wait_io_or_timeout(pvio, 1, 0)) + r= cpipe->rw_size; + } end: return r; } @@ -143,10 +145,10 @@ size_t pvio_npipe_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length) goto end; } if (GetLastError() == ERROR_IO_PENDING) - r= pvio_npipe_wait_io_or_timeout(pvio, 1, 0); - - if (!r) - r= cpipe->rw_size; + { + if (!pvio_npipe_wait_io_or_timeout(pvio, 1, 0)) + r= cpipe->rw_size; + } end: return r; } @@ -216,7 +218,7 @@ my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) if (!pvio || !cinfo) return 1; - if (!(cpipe= (struct st_pvio_npipe *)LocalAlloc(sizeof(struct st_pvio_npipe), 0))) + if (!(cpipe= (struct st_pvio_npipe *)LocalAlloc(LMEM_ZEROINIT, sizeof(struct st_pvio_npipe)))) { PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0, ""); return 1; @@ -249,7 +251,7 @@ my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) 0, /* no sharing */ NULL, /* default security attributes */ OPEN_EXISTING, - 0, /* default attributes */ + FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE) break; diff --git a/plugins/pvio/pvio_socket.c b/plugins/pvio/pvio_socket.c index 01df4775..809a6b97 100644 --- a/plugins/pvio/pvio_socket.c +++ b/plugins/pvio/pvio_socket.c @@ -948,7 +948,7 @@ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio) my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) { struct st_pvio_socket *csock= NULL; - char tmp_buf[1024]; + char tmp_buf; ssize_t len; my_bool mode; diff --git a/unittest/libmariadb/CMakeLists.txt b/unittest/libmariadb/CMakeLists.txt index d8a8e695..7d1c0be4 100644 --- a/unittest/libmariadb/CMakeLists.txt +++ b/unittest/libmariadb/CMakeLists.txt @@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/unittest/mytap) ADD_DEFINITIONS(-DLIBMARIADB) -SET(API_TESTS "features-10_2" "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" +SET(API_TESTS "t_aurora" "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol") # Get finger print from server certificate @@ -31,18 +31,15 @@ IF(WITH_SSL) IF(EXISTS "${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs/server-cert.pem") MESSAGE(STATUS "certificates already exist") ELSE() - MESSAGE(STATUS "cerating certificates") - EXECUTE_PROCESS(COMMAND openssl req -x509 -newkey rsa:1024 -keyout server-key-enc.pem -out server-cert.pem -subj "/DC=com/DC=example/CN=server" -passout pass:qwerty - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs) - EXECUTE_PROCESS(COMMAND openssl rsa -in server-key-enc.pem -out server-key.pem -passin pass:qwerty -passout pass: - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs) - EXECUTE_PROCESS(COMMAND openssl req -x509 -newkey rsa:1024 -keyout client-key-enc.pem -out client-cert.pem -subj "/DC=com/DC=example/CN=client" -passout pass:qwerty - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs) - EXECUTE_PROCESS(COMMAND openssl rsa -in client-key-enc.pem -out client-key.pem -passin pass:qwerty -passout pass: - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs) - FILE(READ ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs/server-cert.pem F1) - FILE(READ ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs/client-cert.pem F2) - FILE(WRITE ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs/ca-cert.pem ${F1} ${F2}) + MESSAGE(STATUS "creating certificates") + IF(WIN32) + EXECUTE_PROCESS(COMMAND create_certs.bat + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs + OUTPUT_FILE x.1 ERROR_FILE x.2) + ELSE() + EXECUTE_PROCESS(COMMAND ./create_certs.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unittest/libmariadb/certs) + ENDIF() ENDIF() EXECUTE_PROCESS(COMMAND openssl x509 -in server-cert.pem -sha1 -fingerprint -noout @@ -60,8 +57,8 @@ IF(WITH_SSL) ENDIF() FOREACH(API_TEST ${API_TESTS}) - ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c) - TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient ) + ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c ${CMAKE_SOURCE_DIR}/libmariadb/getopt.c) + TARGET_LINK_LIBRARIES(${API_TEST} mytap libmariadb) ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST}) SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120) ENDFOREACH(API_TEST) diff --git a/unittest/libmariadb/async.c b/unittest/libmariadb/async.c index a0c3381b..c9f6c49b 100644 --- a/unittest/libmariadb/async.c +++ b/unittest/libmariadb/async.c @@ -30,6 +30,20 @@ #define SL(s) (s), sizeof(s) +my_bool skip_async= 0; + +static int test_async(MYSQL *mysql) +{ + int type; + mariadb_get_info(mysql, MARIADB_CONNECTION_PVIO_TYPE, &type); + if (type > MARIADB_CONNECTION_TCP) + { + skip_async= 1; + diag("Asnyc IO not supported"); + } + return OK; +} + static int wait_for_mysql(MYSQL *mysql, int status) { @@ -126,6 +140,9 @@ static int async1(MYSQL *my) uint default_timeout; int i; + if (skip_async) + return SKIP; + for (i=0; i < 100; i++) { @@ -196,7 +213,12 @@ static int test_conc131(MYSQL *my) { int rc; /* this test needs to run under valgrind */ - MYSQL *mysql=mysql_init(NULL); + MYSQL *mysql; + + if (skip_async) + return SKIP; + + mysql= mysql_init(NULL); rc= mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0); check_mysql_rc(rc, mysql); mysql_close(mysql); @@ -205,13 +227,19 @@ static int test_conc131(MYSQL *my) static int test_conc129(MYSQL *my) { - MYSQL *mysql= mysql_init(NULL); + MYSQL *mysql; + + if (skip_async) + return SKIP; + + mysql= mysql_init(NULL); FAIL_IF(mysql_close_start(mysql), "No error expected"); return OK; } struct my_tests_st my_tests[] = { + {"test_async", test_async, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"async1", async1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc131", test_conc131, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc129", test_conc129, TEST_CONNECTION_NONE, 0, NULL, NULL}, diff --git a/unittest/libmariadb/basic-t.c b/unittest/libmariadb/basic-t.c index 4e535852..02dcc294 100644 --- a/unittest/libmariadb/basic-t.c +++ b/unittest/libmariadb/basic-t.c @@ -55,13 +55,17 @@ static int test_conc75(MYSQL *my) { ulong thread_id= mysql_thread_id(mysql); /* force reconnect */ + mysql->reconnect= 1; + diag("killing connection"); mysql_kill(my, thread_id); - sleep(1); + sleep(2); + mysql_ping(mysql); rc= mysql_query(mysql, "load data local infile './nonexistingfile.csv' into table a (`a`)"); FAIL_IF(!test(mysql->options.client_flag | CLIENT_LOCAL_FILES), "client_flags not correct"); + diag("thread1: %d %d", thread_id, mysql_thread_id(mysql)); FAIL_IF(thread_id == mysql_thread_id(mysql), "new thread id expected"); - diag("cs: %s", mysql->charset->csname); - FAIL_IF(strcmp(mysql->charset->csname, "utf8"), "wrong character set"); + //diag("cs: %s", mysql->charset->csname); + //FAIL_IF(strcmp(mysql->charset->csname, "utf8"), "wrong character set"); } mysql_close(mysql); return OK; @@ -76,7 +80,12 @@ static int test_conc74(MYSQL *my) mysql= mysql_init(NULL); - mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS); + if (!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS)) + { + diag("Error: %s", mysql_error(mysql)); + mysql_close(mysql); + return FAIL; + } rc= mysql_query(mysql, "DROP TABLE IF EXISTS a"); check_mysql_rc(rc, mysql); @@ -128,7 +137,11 @@ static int test_conc70(MYSQL *my) int rc; MYSQL_RES *res; MYSQL_ROW row; - MYSQL *mysql= mysql_init(NULL); + MYSQL *mysql; + + SKIP_CONNECTION_HANDLER; + + mysql= mysql_init(NULL); rc= mysql_query(my, "SET @a:=@@max_allowed_packet"); check_mysql_rc(rc, my); @@ -148,6 +161,14 @@ static int test_conc70(MYSQL *my) rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))"); check_mysql_rc(rc, mysql); + if (mysql_warning_count(mysql)) + { + diag("server doesn't accept package size"); + return SKIP; + } + + sleep(20); + rc= mysql_query(mysql, "SELECT a FROM t1"); check_mysql_rc(rc, mysql); @@ -175,7 +196,11 @@ static int test_conc68(MYSQL *my) int rc; MYSQL_RES *res; MYSQL_ROW row; - MYSQL *mysql= mysql_init(NULL); + MYSQL *mysql; + + SKIP_CONNECTION_HANDLER; + + mysql= mysql_init(NULL); rc= mysql_query(my, "SET @a:=@@max_allowed_packet"); check_mysql_rc(rc, my); @@ -193,6 +218,11 @@ static int test_conc68(MYSQL *my) rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))"); check_mysql_rc(rc, mysql); + if (mysql_warning_count(mysql)) + { + diag("server doesn't accept package size"); + return SKIP; + } rc= mysql_query(mysql, "SELECT a FROM t1"); check_mysql_rc(rc, mysql); @@ -427,7 +457,7 @@ static int test_mysql_insert_id(MYSQL *mysql) FAIL_UNLESS(res == 400, ""); /* table with auto_increment column */ - rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))"); + rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255)) engine=MyISAM"); check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "insert into t2 values (1,'a')"); check_mysql_rc(rc, mysql); @@ -504,12 +534,13 @@ static int test_mysql_insert_id(MYSQL *mysql) according to the manual, this might be 20 or 300, but it looks like auto_increment column takes priority over last_insert_id(). */ + diag("res: %d", res); FAIL_UNLESS(res == 20, ""); /* If first autogenerated number fails and 2nd works: */ rc= mysql_query(mysql, "drop table t2"); check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "create table t2 (f1 int not null primary key " - "auto_increment, f2 varchar(255), unique (f2))"); + "auto_increment, f2 varchar(255), unique (f2)) engine=MyISAM"); check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "insert into t2 values (null,'e')"); res= mysql_insert_id(mysql); @@ -618,12 +649,9 @@ static int bug_conc1(MYSQL *mysql) { mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0); + diag("errno: %d", mysql_errno(mysql)); FAIL_IF(mysql_errno(mysql) != CR_ALREADY_CONNECTED, "Expected errno=CR_ALREADY_CONNECTED"); - FAIL_IF(strcmp(mysql_error(mysql), ER(CR_ALREADY_CONNECTED)) != 0, - "Wrong error message"); - FAIL_IF(strcmp(ER(CR_ALREADY_CONNECTED), "Can't connect twice. Already connected") != 0, - "wrong error message"); return OK; } @@ -668,11 +696,14 @@ static int test_reconnect_maxpackage(MYSQL *my) { int rc; ulong max_packet= 0; - MYSQL *mysql= mysql_init(NULL); + MYSQL *mysql; MYSQL_RES *res; MYSQL_ROW row; char *query; + SKIP_CONNECTION_HANDLER; + mysql= mysql_init(NULL); + FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql)); @@ -770,6 +801,8 @@ int main(int argc, char **argv) get_envvars(); + diag("user: %s", username); + run_tests(my_tests); return(exit_status()); diff --git a/unittest/libmariadb/certs/create_certs.sh b/unittest/libmariadb/certs/create_certs.sh deleted file mode 100755 index 47ea98e8..00000000 --- a/unittest/libmariadb/certs/create_certs.sh +++ /dev/null @@ -1,15 +0,0 @@ -openssl req -x509 -newkey rsa:1024 \ --keyout server-key-enc.pem -out server-cert.pem \ --subj '/DC=com/DC=example/CN=server' -passout pass:qwerty - -openssl rsa -in server-key-enc.pem -out server-key.pem \ --passin pass:qwerty -passout pass: - -openssl req -x509 -newkey rsa:1024 \ --keyout client-key-enc.pem -out client-cert.pem \ --subj '/DC=com/DC=example/CN=client' -passout pass:qwerty - -openssl rsa -in client-key-enc.pem -out client-key.pem \ --passin pass:qwerty -passout pass: - -cat server-cert.pem client-cert.pem > ca-cert.pem diff --git a/unittest/libmariadb/certs/dummy.pem b/unittest/libmariadb/certs/dummy.pem deleted file mode 100644 index 1fc34aa1..00000000 --- a/unittest/libmariadb/certs/dummy.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDXTCCAkWgAwIBAgIJAL4tmDe5DR0sMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTUwMzEwMjAyMDI4WhcNMTYwMzA5MjAyMDI4WjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEApV9UfWmeXYdexOEn+adOm6FdJUhKMrjTiycwETmDXRVpY4wl+LNGsANp -ohSRovDjFiFO+Ti0bUhpf552oE23wYw+P6f0UY0KkV/PgSght1Ezfffe0BaEjI0X -tA5zdNmxzL3OUWJVcg+I4UE3rbYFHUgymu72P0IRXjmJv1tToNxUxbTBLxU/KAlq -Uy49upB3q3/IPOdP9UzAZDHnRv1gjwUzNgumfcc5d5lSsGpwLDYCQs4I539fCkBD -MfU2BN/qpmPhb/nm5ZUdFUFYGN+XxVPVpJLmeWVRwMSQR2LN5CkqnK9e2Q/QaJ53 -G3AAng+fpfEGPpjQdFWuhFjQozOD0wIDAQABo1AwTjAdBgNVHQ4EFgQUyg6WfzL2 -JhhjKm1Ex28s4Y3vNGQwHwYDVR0jBBgwFoAUyg6WfzL2JhhjKm1Ex28s4Y3vNGQw -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAIrj/bHiRf8UJIfv8hyZ1 -dXEqvqjxUMXtJ/QhhCQs42p9pHv+mPTkeXh0K18Oj6k/Vp4J1/0mp/kqiQUHt9yO -/3pJPc+JordTjlVLgb95cfBIs4yiPT9biGaA7j0Dh9EcDBOCT4v56Z9BLqGMfBUK -YeZ7ZecWmZCZOYk/X+CPB30GxLy5Wm9D50qEUXXBPZ9Bie6FYaQYOFlQlqxYuLX0 -NVqLDvX6zz6FMsgqoyDJ1BMuMsjPDUUUrwGY+R3YqiqkPRbDkr8zvzpqiYvjTZi0 -LTJO7GRfwzfhkeEPL/hl/TYdB1GZHixMrAKx1HGKHAa0sgWTWxQGYhfclH8DI7AR -Tw== ------END CERTIFICATE----- diff --git a/unittest/libmariadb/charset.c b/unittest/libmariadb/charset.c index b5cdbf89..0226bc18 100644 --- a/unittest/libmariadb/charset.c +++ b/unittest/libmariadb/charset.c @@ -679,7 +679,7 @@ static int test_utf16_utf32_noboms(MYSQL *mysql) for (i= 0; i < sizeof(csname)/sizeof(char*); ++i) { - csinfo[i]= mysql_find_charset_name(csname[i]); + csinfo[i]= mariadb_get_charset_by_name(csname[i]); if (csinfo[i] == NULL) { diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 11452977..0ce22450 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -32,6 +32,7 @@ static int test_conc66(MYSQL *my) MYSQL *mysql= mysql_init(NULL); int rc; FILE *fp; + char query[1024]; if (!(fp= fopen("./my.cnf", "w"))) return FAIL; @@ -47,7 +48,8 @@ static int test_conc66(MYSQL *my) rc= mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "./my.cnf"); check_mysql_rc(rc, mysql); - rc= mysql_query(my, "GRANT ALL ON test.* TO 'conc66'@'localhost' IDENTIFIED BY 'test\";#test'"); + sprintf(query, "GRANT ALL ON %s.* TO 'conc66'@'%s' IDENTIFIED BY 'test\";#test'", schema, hostname); + rc= mysql_query(my, query); check_mysql_rc(rc, my); rc= mysql_query(my, "FLUSH PRIVILEGES"); check_mysql_rc(rc, my); @@ -57,7 +59,8 @@ static int test_conc66(MYSQL *my) diag("Error: %s", mysql_error(mysql)); return FAIL; } - rc= mysql_query(my, "DROP USER conc66@localhost"); + sprintf(query, "DROP user conc66@%s", hostname); + rc= mysql_query(my, query); check_mysql_rc(rc, my); mysql_close(mysql); @@ -561,6 +564,8 @@ static int test_reconnect(MYSQL *mysql) mysql_kill(mysql, mysql_thread_id(mysql1)); sleep(4); + mysql_ping(mysql1); + rc= mysql_query(mysql1, "SELECT 1 FROM DUAL LIMIT 0"); check_mysql_rc(rc, mysql1); diag("Thread_id after kill: %lu", mysql_thread_id(mysql1)); @@ -649,6 +654,8 @@ static int test_conc118(MYSQL *mysql) rc= mysql_kill(mysql, mysql_thread_id(mysql)); sleep(2); + mysql_ping(mysql); + rc= mysql_query(mysql, "SET @a:=1"); check_mysql_rc(rc, mysql); @@ -657,12 +664,7 @@ static int test_conc118(MYSQL *mysql) rc= mysql_kill(mysql, mysql_thread_id(mysql)); sleep(2); - mysql->host= "foo"; - - rc= mysql_query(mysql, "SET @a:=1"); - FAIL_IF(!rc, "error expected"); - - mysql->host= hostname; + mysql_ping(mysql); rc= mysql_query(mysql, "SET @a:=1"); check_mysql_rc(rc, mysql); @@ -740,7 +742,92 @@ static int test_bind_address(MYSQL *my) return OK; } +static int test_get_options(MYSQL *my) +{ + MYSQL *mysql= mysql_init(NULL); + int options_int[]= {MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_RECONNECT, MYSQL_OPT_PROTOCOL, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, 0}; + my_bool options_bool[]= {MYSQL_OPT_COMPRESS, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_SECURE_AUTH, +#ifdef _WIN32 + MYSQL_OPT_NAMED_PIPE, +#endif + 0}; + int options_char[]= {MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, MYSQL_SET_CHARSET_NAME, + MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CAPATH, + MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_BIND, MARIADB_OPT_SSL_FP, MARIADB_OPT_SSL_FP_LIST, + MARIADB_OPT_SSL_PASSWORD, 0}; + + char *init_command[3]= {"SET @a:=1", "SET @b:=2", "SET @c:=3"}; + int elements= 0; + char **command; + + + int intval[2]= {1, 0}; + my_bool boolval[2]= {1, 0}; + char *char1= "test", *char2; + int i; + MYSQL *userdata; + char *attr_key[] = {"foo1", "foo2", "foo3"}; + char *attr_val[] = {"bar1", "bar2", "bar3"}; + char **key, **val; + + for (i=0; options_int[i]; i++) + { + mysql_options(mysql, options_int[i], &intval[0]); + intval[1]= 0; + mysql_get_optionv(mysql, options_int[i], &intval[1]); + FAIL_IF(intval[0] != intval[1], "mysql_get_optionv (int) failed"); + } + for (i=0; options_bool[i]; i++) + { + mysql_options(mysql, options_bool[i], &boolval[0]); + intval[1]= 0; + mysql_get_optionv(mysql, options_bool[i], &boolval[1]); + FAIL_IF(boolval[0] != boolval[1], "mysql_get_optionv (my_bool) failed"); + } + for (i=0; options_char[i]; i++) + { + mysql_options(mysql, options_char[i], char1); + char2= NULL; + mysql_get_optionv(mysql, options_char[i], (void *)&char2); + FAIL_IF(strcmp(char1, char2), "mysql_get_optionv (char) failed"); + } + + for (i=0; i < 3; i++) + mysql_options(mysql, MYSQL_INIT_COMMAND, init_command[i]); + + mysql_get_optionv(mysql, MYSQL_INIT_COMMAND, &command, &elements); + FAIL_IF(elements != 3, "expected 3 elements"); + for (i=0; i < 3; i++) + FAIL_IF(strcmp(init_command[i], command[i]), "wrong init command"); + for (i=0; i < 3; i++) + mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, attr_key[i], attr_val[i]); + + mysql_get_optionv(mysql, MYSQL_OPT_CONNECT_ATTRS, NULL, NULL, &elements); + FAIL_IF(elements != 3, "expected 3 connection attributes"); + + key= (char **)malloc(sizeof(char *) * elements); + val= (char **)malloc(sizeof(char *) * elements); + + mysql_get_optionv(mysql, MYSQL_OPT_CONNECT_ATTRS, &key, &val, &elements); + for (i=0; i < elements; i++) + { + diag("%s => %s", key[i], val[i]); + } + + free(key); + free(val); + + mysql_optionsv(mysql, MARIADB_OPT_USERDATA, "my_app", (void *)mysql); + mysql_get_optionv(mysql, MARIADB_OPT_USERDATA, "my_app", &userdata); + + FAIL_IF(mysql != userdata, "wrong userdata"); + mysql_close(mysql); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_get_options", test_get_options, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_wrong_bind_address", test_wrong_bind_address, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_bind_address", test_bind_address, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc118", test_conc118, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/cursor.c b/unittest/libmariadb/cursor.c index 97a75bc2..97bafd2e 100644 --- a/unittest/libmariadb/cursor.c +++ b/unittest/libmariadb/cursor.c @@ -59,12 +59,12 @@ MYSQL_STMT *open_cursor(MYSQL *mysql, const char *query) fetch buffers. */ -int stmt_fetch_init(MYSQL *mysql, Stmt_fetch *fetch, unsigned stmt_no_arg, +int stmt_fetch_init(MYSQL *mysql, Stmt_fetch *fetch, unsigned int stmt_no_arg, const char *query_arg) { unsigned long type= CURSOR_TYPE_READ_ONLY; int rc; - unsigned i; + unsigned int i; MYSQL_RES *metadata; /* Save query and statement number for error messages */ @@ -180,7 +180,7 @@ int fetch_n(MYSQL *mysql, const char **query_list, unsigned query_count, for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) { - if (stmt_fetch_init(mysql, fetch, fetch - fetch_array, + if (stmt_fetch_init(mysql, fetch, (unsigned int)(fetch - fetch_array), query_list[fetch - fetch_array])) return FAIL; } @@ -322,7 +322,7 @@ static int test_bug21206(MYSQL *mysql) for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch) { - if ((retcode= stmt_fetch_init(mysql, fetch, fetch - fetch_array, query))) + if ((retcode= stmt_fetch_init(mysql, fetch, (unsigned int)(fetch - fetch_array), query))) break; } diff --git a/unittest/libmariadb/logs.c b/unittest/libmariadb/logs.c index 534feeb2..38dfd8a7 100644 --- a/unittest/libmariadb/logs.c +++ b/unittest/libmariadb/logs.c @@ -89,7 +89,7 @@ static int test_logs(MYSQL *mysql) my_bind[1].buffer_type= MYSQL_TYPE_STRING; my_bind[1].buffer= (void *)&data; my_bind[1].buffer_length= 255; - my_bind[1].length= &length; + my_bind[1].length= (unsigned long *)&length; id= 9876; strcpy((char *)data, "MySQL - Open Source Database"); diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index ede78ace..1dd9f478 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -266,7 +266,7 @@ static int test_frm_bug(MYSQL *mysql) sprintf(test_frm, "%s/%s/test_frm_bug.frm", data_dir, schema); - if (!(test_file= my_fopen(test_frm, (int) (O_RDWR | O_CREAT), MYF(MY_WME)))) + if (!(test_file= fopen(test_frm, "rw"))) { mysql_stmt_close(stmt); diag("Can't write to file %s -> SKIP", test_frm); @@ -294,7 +294,7 @@ static int test_frm_bug(MYSQL *mysql) mysql_free_result(result); mysql_stmt_close(stmt); - my_fclose(test_file, MYF(0)); + fclose(test_file); mysql_query(mysql, "drop table if exists test_frm_bug"); return OK; } @@ -1021,11 +1021,74 @@ static int test_remote2(MYSQL *my) } #endif +static int test_get_info(MYSQL *mysql) +{ + size_t sval; + unsigned int ival; + char *cval; + int rc; + MY_CHARSET_INFO cs; + CHARSET_INFO *ci; + char **errors; + + rc= mariadb_get_infov(mysql, MARIADB_MAX_ALLOWED_PACKET, &sval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("max_allowed_packet: %d", sval); + rc= mariadb_get_infov(mysql, MARIADB_NET_BUFFER_LENGTH, &sval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("net_buffer_length: %d", sval); + rc= mariadb_get_infov(mysql, MARIADB_CLIENT_VERSION_ID, &sval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("client_version_id: %d", sval); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_VERSION_ID, &sval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("server_version_id: %d", sval); + rc= mariadb_get_infov(mysql, MARIADB_CHARSET_INFO, &cs); + FAIL_IF(rc, "mysql_get_info failed"); + diag("charset name: %s", cs.csname); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_PVIO_TYPE, &ival); + FAIL_IF(rc, "mysql_get_info failed"); + diag("connection type: %d", ival); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_PROTOCOL_VERSION_ID, &ival); + FAIL_IF(rc, "mysql_get_info failed"); + diag("protocol_version: %d", ival); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_TYPE, &cval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("server_type: %s", cval); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_VERSION, &cval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("server_version: %s", cval); + rc= mariadb_get_infov(mysql, MARIADB_CLIENT_VERSION, &cval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("client_version: %s", cval); + rc= mariadb_get_infov(mysql, MARIADB_CHARSET_NAME, &ci, "utf8"); + FAIL_IF(rc, "mysql_get_info failed"); + diag("charset_name: %s", ci->csname); + diag("charset_nr: %d", ci->nr); + rc= mariadb_get_infov(mysql, MARIADB_CHARSET_ID, &ci, 63); + FAIL_IF(rc, "mysql_get_info failed"); + diag("charset_name: %s", ci->csname); + rc= mariadb_get_infov(mysql, MARIADB_CLIENT_ERRORS, &errors); + FAIL_IF(rc, "mysql_get_info failed"); + diag("error[0]: %s", errors[0]); + rc= mysql_query(mysql, "DROP TABLE IF exists t1"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE t1 (a int)"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1),(2)"); + check_mysql_rc(rc, mysql); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_INFO, &cval); + FAIL_IF(rc, "mysql_get_info failed"); + diag("mariadb_info: %s", cval); + return OK; +} + struct my_tests_st my_tests[] = { #ifdef HAVE_REMOTEIO {"test_remote1", test_remote1, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_remote2", test_remote2, TEST_CONNECTION_NEW, 0, NULL, NULL}, #endif + {"test_get_info", test_get_info, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc117", test_conc117, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc_114", test_conc_114, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_connect_attrs", test_connect_attrs, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/my_test.h b/unittest/libmariadb/my_test.h index e862ced1..e0db2beb 100644 --- a/unittest/libmariadb/my_test.h +++ b/unittest/libmariadb/my_test.h @@ -82,6 +82,13 @@ if (!(expr))\ return FAIL;\ } +#define SKIP_CONNECTION_HANDLER \ + if (hostname && strstr(hostname, "://"))\ + {\ + diag("Test skipped (connection handler)");\ + return SKIP;\ + } + /* connection options */ #define TEST_CONNECTION_DEFAULT 1 /* default connection */ #define TEST_CONNECTION_NONE 2 /* tests creates own connection */ @@ -104,7 +111,7 @@ struct my_tests_st char *skipmsg; }; -static char *schema = "test_c"; +static char *schema = 0; static char *hostname = 0; static char *password = 0; static unsigned int port = 0; @@ -368,18 +375,19 @@ int check_variable(MYSQL *mysql, char *variable, char *value) MYSQL *test_connect(struct my_tests_st *test) { MYSQL *mysql; char query[255]; - int i= 1; + int i= 0; + int timeout= 10; + int truncation_report= 1; if (!(mysql = mysql_init(NULL))) { diag("%s", "mysql_init failed - exiting"); return(NULL); } - mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &i); - mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i); + mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &truncation_report); + mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); /* option handling */ if (test && test->options) { - int i=0; while (test->options[i].option) { @@ -403,6 +411,8 @@ MYSQL *test_connect(struct my_tests_st *test) { /* change database or create if it doesn't exist */ if (mysql_select_db(mysql, schema)) { + diag("Error number: %d", mysql_errno(mysql)); + if(mysql_errno(mysql) == 1049) { sprintf(query, "CREATE DATABASE %s", schema); if (mysql_query(mysql, query)) { @@ -425,11 +435,6 @@ static int reset_connection(MYSQL *mysql) { rc= mysql_change_user(mysql, username, password, schema); check_mysql_rc(rc, mysql); - if (mysql_get_server_version(mysql) < 50400) - rc= mysql_query(mysql, "SET table_type='MyISAM'"); - else - rc= mysql_query(mysql, "SET storage_engine='MyISAM'"); - check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "SET sql_mode=''"); check_mysql_rc(rc, mysql); @@ -452,6 +457,8 @@ void get_envvars() { password= envvar; if (!schema && (envvar= getenv("MYSQL_TEST_DB"))) schema= envvar; + if (!schema) + schema= "testc"; if (!port && (envvar= getenv("MYSQL_TEST_PORT"))) port= atoi(envvar); if (!socketname && (envvar= getenv("MYSQL_TEST_SOCKET"))) @@ -470,7 +477,8 @@ void run_tests(struct my_tests_st *test) { if ((mysql_default= test_connect(NULL))) { diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default)); - diag("Host %s", mysql_get_host_info(mysql_default)); + diag("Host: %s", mysql_get_host_info(mysql_default)); + diag("Client library: %s", mysql_get_client_info()); } else { diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index 1c96baca..add7a493 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -64,7 +64,10 @@ static int test_conc83(MYSQL *my) /* 1. Status is inited, so prepare should work */ rc= mysql_kill(mysql, mysql_thread_id(mysql)); - sleep(2); + sleep(5); + + rc= mysql_ping(mysql); + check_mysql_rc(rc, mysql); rc= mysql_stmt_prepare(stmt, query, strlen(query)); check_stmt_rc(rc, stmt); @@ -1383,7 +1386,7 @@ static int test_long_data_str1(MYSQL *mysql) my_bind[0].buffer= data; /* string data */ my_bind[0].buffer_length= sizeof(data); - my_bind[0].length= &length1; + my_bind[0].length= (unsigned long *)&length1; my_bind[0].buffer_type= MYSQL_TYPE_STRING; length1= 0; @@ -1482,7 +1485,7 @@ static int test_long_data_str1(MYSQL *mysql) my_bind[0].buffer_type= MYSQL_TYPE_BLOB; my_bind[0].buffer= (void *) &data; /* this buffer won't be altered */ my_bind[0].buffer_length= 16; - my_bind[0].length= &blob_length; + my_bind[0].length= (unsigned long *)&blob_length; my_bind[0].error= &my_bind[0].error_value; rc= mysql_stmt_bind_result(stmt, my_bind); data[16]= 0; @@ -1498,7 +1501,7 @@ static int test_long_data_str1(MYSQL *mysql) my_bind[1].buffer_type= MYSQL_TYPE_BLOB; my_bind[1].buffer= (void *) &data; /* this buffer won't be altered */ my_bind[1].buffer_length= sizeof(data); - my_bind[1].length= &blob_length; + my_bind[1].length= (unsigned long *)&blob_length; memset(data, '\0', sizeof(data)); mysql_stmt_fetch_column(stmt, my_bind+1, 0, 0); FAIL_UNLESS(strlen(data) == max_blob_length, "strlen(data) != max_blob_length"); diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index bd072646..e5204ea4 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -528,9 +528,8 @@ static int test_bug12744(MYSQL *mysql) rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1"); check_mysql_rc(rc, mysql); rc= mysql_kill(mysql, mysql_thread_id(mysql)); - check_mysql_rc(rc, mysql); - sleep(2); + sleep(4); rc= mysql_ping(mysql); check_mysql_rc(rc, mysql); @@ -644,7 +643,7 @@ static int test_bug1500(MYSQL *mysql) data= "Grave"; my_bind[0].buffer_type= MYSQL_TYPE_STRING; my_bind[0].buffer= (void *) data; - my_bind[0].buffer_length= strlen(data); + my_bind[0].buffer_length= (unsigned long)strlen(data); rc= mysql_stmt_bind_param(stmt, my_bind); check_stmt_rc(rc, stmt); @@ -2652,7 +2651,7 @@ static int test_bug5194(MYSQL *mysql) for (i= 1; i < COLUMN_COUNT; ++i) strcat(param_str, "?, "); strcat(param_str, "?)"); - param_str_length= strlen(param_str); + param_str_length= (int)strlen(param_str); /* setup bind array */ memset(my_bind, '\0', MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); @@ -3230,7 +3229,7 @@ static int test_mem_overun(MYSQL *mysql) sprintf(field, "c%d int, ", i); strcat(buffer, field); } - length= strlen(buffer); + length= (int)strlen(buffer); buffer[length-2]= ')'; buffer[--length]= '\0'; @@ -3242,7 +3241,7 @@ static int test_mem_overun(MYSQL *mysql) { strcat(buffer, "1, "); } - length= strlen(buffer); + length= (int)strlen(buffer); buffer[length-2]= ')'; buffer[--length]= '\0'; diff --git a/unittest/libmariadb/ssl.c.in b/unittest/libmariadb/ssl.c.in index b6e51965..6982e41b 100644 --- a/unittest/libmariadb/ssl.c.in +++ b/unittest/libmariadb/ssl.c.in @@ -51,12 +51,20 @@ static int check_cipher(MYSQL *mysql) char *cipher= (char *)mysql_get_ssl_cipher(mysql); if (!cipher) return 1; + diag("cipher: %s", cipher); + #ifdef HAVE_GNUTLS - return strcmp(cipher, "AES-128-GCM"); -#endif -#ifdef HAVE_OPENSSL - return strcmp(cipher, "DHE-RSA-AES256-SHA"); + { + return strcmp(cipher, "AES-128-GCM"); + } +#elif HAVE_OPENSSL + if (!strcmp(cipher, "DHE-RSA-AES256-SHA") || + !strcmp(cipher, "DHE-RSA-AES256-GCM-SHA384")) + return 0; +#elif HAVE_SCHANNEL + return strcmp(cipher, "CALG_AES_256"); #endif + return 1; } static int create_ssl_user(const char *ssluser, my_bool is_X509) @@ -105,6 +113,14 @@ static int test_ssl(MYSQL *mysql) } mysql_free_result(res); +#ifdef HAVE_GNUTLS + diag("SSL library: GNUTLS"); +#elif HAVE_OPENSSL + diag("SSL library: OPENSSL"); +#elif HAVE_SCHANNEL + diag("SSL library: SCHANNEL"); +#endif + sslhost[0]= 0; if (!skip_ssl) @@ -127,6 +143,9 @@ static int test_ssl(MYSQL *mysql) static int test_ssl_cipher(MYSQL *unused) { MYSQL *my; + MYSQL_RES *res; + MYSQL_ROW row; + int rc; if (check_skip_ssl()) return SKIP; @@ -139,6 +158,14 @@ static int test_ssl_cipher(MYSQL *unused) FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema, port, socketname, 0), mysql_error(my)); + rc= mysql_query(my, "SHOW session status like 'Ssl_version'"); + check_mysql_rc(rc, my); + res= mysql_store_result(my); + row= mysql_fetch_row(res); + diag("%s: %s", row[0], row[1]); + diag("cipher: %s", mysql_get_ssl_cipher(my)); + mysql_free_result(res); + FAIL_IF(check_cipher(my) != 0, "Invalid cipher"); mysql_close(my); return OK; @@ -268,6 +295,7 @@ DWORD WINAPI ssl_thread(void *dummy) mysql_close(mysql); mysql_thread_end(); pthread_exit(0); + return; } static int test_ssl_threads(MYSQL *mysql) @@ -291,6 +319,7 @@ static int test_ssl_threads(MYSQL *mysql) check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "INSERT into ssltest VALUES (0)"); check_mysql_rc(rc, mysql); + pthread_mutex_init(&LOCK_test, NULL); pthread_mutex_init(&LOCK_test, NULL); @@ -478,7 +507,7 @@ static int test_conc50_3(MYSQL *my) mysql_ssl_set(mysql, NULL, NULL, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", NULL, NULL); - mysql_real_connect(mysql, hostname, "ssltest", NULL, schema, + mysql_real_connect(mysql, hostname, ssluser, sslpw, schema, port, socketname, 0); diag("Error: %s<", mysql_error(mysql)); FAIL_IF(mysql_errno(mysql), "No error expected"); @@ -640,12 +669,16 @@ static int test_conc_102(MYSQL *mysql) DWORD threads[50]; #endif + if (check_skip_ssl()) + return SKIP; + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t_conc102"); check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "CREATE TABLE t_conc102 ( a int)"); check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "INSERT INTO t_conc102 VALUES (0)"); check_mysql_rc(rc, mysql); + pthread_mutex_init(&LOCK_test, NULL); for (i=0; i < 50; i++) { @@ -665,6 +698,7 @@ static int test_conc_102(MYSQL *mysql) WaitForSingleObject(hthreads[i], INFINITE); #endif } + pthread_mutex_destroy(&LOCK_test); rc= mysql_query(mysql, "SELECT a FROM t_conc102"); check_mysql_rc(rc, mysql); res= mysql_store_result(mysql); @@ -699,10 +733,10 @@ static int test_ssl_fp(MYSQL *unused) FAIL_IF(check_cipher(my) != 0, "Invalid cipher"); - mysql_query(my, "SET @a:=1"); + rc= mysql_query(my, "SET @a:=1"); check_mysql_rc(rc, my); - mysql_query(my, "SELECT @a"); + rc= mysql_query(my, "SELECT @a"); check_mysql_rc(rc, my); if ((res= mysql_store_result(my))) @@ -738,7 +772,33 @@ static int test_ssl_fp_list(MYSQL *unused) return OK; } +static int test_ssl_version(MYSQL *mysql) +{ + unsigned int iversion; + char *version; + MYSQL *my; + if (check_skip_ssl()) + return SKIP; + + my= mysql_init(NULL); + FAIL_IF(!my, "mysql_init() failed"); + + mysql_ssl_set(my,0, 0, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", 0, 0); + FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema, + port, socketname, 0), mysql_error(my)); + + diag("cipher: %s", mysql_get_ssl_cipher(my)); + mariadb_get_infov(my, MARIADB_CONNECTION_SSL_VERSION_ID, &iversion); + diag("protocol: %d", iversion); + mariadb_get_infov(my, MARIADB_CONNECTION_SSL_VERSION, &version); + diag("protocol: %s", version); + + mysql_close(my); + + return OK; +} + struct my_tests_st my_tests[] = { {"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL}, @@ -757,9 +817,11 @@ struct my_tests_st my_tests[] = { {"test_ssl_cipher", test_ssl_cipher, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_multi_ssl_connections", test_multi_ssl_connections, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc_102", test_conc_102, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {"test_ssl_version", test_ssl_version, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_ssl_threads", test_ssl_threads, TEST_CONNECTION_NEW, 0, NULL, NULL}, +#ifndef HAVE_SCHANNEL {"test_password_protected", test_password_protected, TEST_CONNECTION_NEW, 0, NULL, NULL}, - +#endif {NULL, NULL, 0, 0, NULL, NULL} }; diff --git a/unittest/libmariadb/t_aurora.c b/unittest/libmariadb/t_aurora.c new file mode 100644 index 00000000..d9c89c45 --- /dev/null +++ b/unittest/libmariadb/t_aurora.c @@ -0,0 +1,67 @@ +/* +*/ + +#include "my_test.h" + +static int aurora1(MYSQL *mysql) +{ + int rc; + my_bool read_only= 1; + char *primary, *replica; + MYSQL_RES *res; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b varchar(20))"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1, 'foo'), (2, 'bar')"); + check_mysql_rc(rc, mysql); + + primary= mysql->host; + diag("primary: %s", primary); + + mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only); + + /* ensure, that this is a replica, so INSERT should fail */ + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (3, 'error')"); + if (rc) + diag("Expected error: %s", mysql_error(mysql)); + + rc= mysql_query(mysql, "SELECT a, b FROM t1"); + check_mysql_rc(rc, mysql); + + res= mysql_store_result(mysql); + + diag("Num_rows: %d", mysql_num_rows(res)); + mysql_free_result(res); + + replica= mysql->host; + diag("replica: %s", replica); + diag("db: %s", mysql->db); + + return OK; +} + +struct my_tests_st my_tests[] = { + {"aurora1", aurora1, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {NULL, NULL, 0, 0, NULL, NULL} +}; + + +int main(int argc, char **argv) +{ + + mysql_library_init(0,0,NULL); + + if (argc > 1) + get_options(argc, argv); + + get_envvars(); + + run_tests(my_tests); + + mysql_server_end(); + return(exit_status()); +} diff --git a/win-iconv/win_iconv.c b/win-iconv/win_iconv.c index 6699c022..d1740fe1 100644 --- a/win-iconv/win_iconv.c +++ b/win-iconv/win_iconv.c @@ -789,7 +789,7 @@ win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, s if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL) { tomode = cd->to.mode; - outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft); + outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, (int)*outbytesleft); if (outsize == -1) { if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) @@ -816,7 +816,7 @@ win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, s tomode = cd->to.mode; wsize = MB_CHAR_MAX; - insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize); + insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, (int)*inbytesleft, wbuf, &wsize); if (insize == -1) { if (cd->to.flags & FLAG_IGNORE) @@ -867,7 +867,7 @@ win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, s } } - outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft); + outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, (int)*outbytesleft); if (outsize == -1) { if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) diff --git a/win/packaging/CMakeLists.txt b/win/packaging/CMakeLists.txt index ec1ba8b3..6decef34 100644 --- a/win/packaging/CMakeLists.txt +++ b/win/packaging/CMakeLists.txt @@ -57,7 +57,11 @@ IF(NOT WIX_DIR) SET(WIX_DIR $ENV{WIX}/bin) ENDIF() -SET(MSI_PACKAGE "mariadb-connector-c-${PRODUCT_VERSION}-${PLATFORM}.msi") +IF(NOT PACKAGE_STATUS_SUFFIX) + SET(MSI_PACKAGE "mariadb-connector-c-${PRODUCT_VERSION}-${PLATFORM}.msi") +ELSE() + SET(MSI_PACKAGE "mariadb-connector-c-${PRODUCT_VERSION}-${PACKAGE_STATUS_SUFFIX}-${PLATFORM}.msi") +ENDIF() IF(WITH_SIGNCODE) IF(EXISTS "/tools/sign.bat")