diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-09-04 13:35:14 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-09-12 17:51:49 +0200 |
commit | ed0b84a0270bd99b001dd00654875d26e29b9432 (patch) | |
tree | ecdff364c7f3e6816bcdeae3e32d325b0681c01e /libmysql | |
parent | 4ba198c6e3c7ccf4da2a87c14043bb3be08915f7 (diff) | |
download | mariadb-git-ed0b84a0270bd99b001dd00654875d26e29b9432.tar.gz |
remove libmysql/
also disable server's client plugins when C/C has the same
Diffstat (limited to 'libmysql')
-rw-r--r-- | libmysql/CMakeLists.txt | 427 | ||||
-rw-r--r-- | libmysql/client_settings.h | 72 | ||||
-rw-r--r-- | libmysql/conf_to_src.c | 144 | ||||
-rw-r--r-- | libmysql/errmsg.c | 129 | ||||
-rw-r--r-- | libmysql/get_password.c | 227 | ||||
-rw-r--r-- | libmysql/libmysql.c | 4922 | ||||
-rw-r--r-- | libmysql/libmysql.def | 107 | ||||
-rw-r--r-- | libmysql/libmysql_versions.ld.in | 33 |
8 files changed, 0 insertions, 6061 deletions
diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt deleted file mode 100644 index 41710bf08a7..00000000000 --- a/libmysql/CMakeLists.txt +++ /dev/null @@ -1,427 +0,0 @@ -# Copyright (c) 2006, 2013, Oracle and/or its affiliates. -# Copyright (c) 2009, 2013, SkySQL Ab. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -INCLUDE_DIRECTORIES( - ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/libmysql - ${PCRE_INCLUDES} - ${CMAKE_SOURCE_DIR}/strings - ${SSL_INCLUDE_DIRS} - ${SSL_INTERNAL_INCLUDE_DIRS} - ${ZLIB_INCLUDE_DIR}) -ADD_DEFINITIONS(${SSL_DEFINES}) - -SET(CLIENT_API_FUNCTIONS_5_1 -get_tty_password -mysql_thread_end -mysql_thread_init -myodbc_remove_escape -mysql_affected_rows -mysql_autocommit -mysql_stmt_bind_param -mysql_stmt_bind_result -mysql_change_user -mysql_character_set_name -mysql_close -mysql_commit -mysql_data_seek -mysql_debug -mysql_dump_debug_info -mysql_eof -mysql_errno -mysql_error -mysql_escape_string -mysql_hex_string -mysql_stmt_execute -mysql_stmt_fetch -mysql_stmt_fetch_column -mysql_fetch_field -mysql_fetch_field_direct -mysql_fetch_fields -mysql_fetch_lengths -mysql_fetch_row -mysql_field_count -mysql_field_seek -mysql_field_tell -mysql_free_result -mysql_get_parameters -mysql_get_client_info -mysql_get_host_info -mysql_get_proto_info -mysql_get_server_info -mysql_get_client_version -mysql_get_ssl_cipher -mysql_info -mysql_init -mysql_insert_id -mysql_kill -mysql_set_server_option -mysql_list_dbs -mysql_list_fields -mysql_list_processes -mysql_list_tables -mysql_more_results -mysql_next_result -mysql_num_fields -mysql_num_rows -mysql_options -mysql_stmt_param_count -mysql_stmt_param_metadata -mysql_ping -mysql_stmt_result_metadata -mysql_query -mysql_read_query_result -mysql_real_connect -mysql_real_escape_string -mysql_real_query -mysql_refresh -mysql_rollback -mysql_row_seek -mysql_row_tell -mysql_select_db -mysql_stmt_send_long_data -mysql_send_query -mysql_shutdown -mysql_ssl_set -mysql_stat -mysql_stmt_affected_rows -mysql_stmt_close -mysql_stmt_reset -mysql_stmt_data_seek -mysql_stmt_errno -mysql_stmt_error -mysql_stmt_free_result -mysql_stmt_num_rows -mysql_stmt_row_seek -mysql_stmt_row_tell -mysql_stmt_store_result -mysql_store_result -mysql_thread_id -mysql_thread_safe -mysql_use_result -mysql_warning_count -mysql_stmt_sqlstate -mysql_sqlstate -mysql_get_server_version -mysql_stmt_prepare -mysql_stmt_init -mysql_stmt_insert_id -mysql_stmt_attr_get -mysql_stmt_attr_set -mysql_stmt_field_count -mysql_set_local_infile_default -mysql_set_local_infile_handler -mysql_embedded -mysql_server_init -mysql_server_end -mysql_set_character_set -mysql_get_character_set_info -# These are documented in Paul DuBois' MySQL book, -# so we treat them as part of the de-facto API. -handle_options -load_defaults -free_defaults -my_print_help -) - -SET(CLIENT_API_FUNCTIONS_5_5 -my_progname -mysql_stmt_next_result -# Charsets -my_charset_bin -my_charset_latin1 -my_charset_utf8_general_ci -# Client plugins -mysql_client_find_plugin -mysql_client_register_plugin -mysql_load_plugin -mysql_load_plugin_v -mysql_plugin_options -# Async API -mysql_get_timeout_value -mysql_get_timeout_value_ms -mysql_get_socket -mysql_autocommit_cont -mysql_autocommit_start -mysql_change_user_cont -mysql_change_user_start -mysql_close_cont -mysql_close_start -mysql_commit_cont -mysql_commit_start -mysql_dump_debug_info_cont -mysql_dump_debug_info_start -mysql_fetch_row_cont -mysql_fetch_row_start -mysql_free_result_cont -mysql_free_result_start -mysql_kill_cont -mysql_kill_start -mysql_list_dbs_cont -mysql_list_dbs_start -mysql_list_fields_cont -mysql_list_fields_start -mysql_list_processes_cont -mysql_list_processes_start -mysql_list_tables_cont -mysql_list_tables_start -mysql_next_result_cont -mysql_next_result_start -mysql_ping_cont -mysql_ping_start -mysql_query_cont -mysql_query_start -mysql_read_query_result_cont -mysql_read_query_result_start -mysql_real_connect_cont -mysql_real_connect_start -mysql_real_query_cont -mysql_real_query_start -mysql_refresh_cont -mysql_refresh_start -mysql_rollback_cont -mysql_rollback_start -mysql_select_db_cont -mysql_select_db_start -mysql_send_query_cont -mysql_send_query_start -mysql_set_character_set_cont -mysql_set_character_set_start -mysql_set_server_option_cont -mysql_set_server_option_start -mysql_shutdown_cont -mysql_shutdown_start -mysql_stat_cont -mysql_stat_start -mysql_stmt_close_cont -mysql_stmt_close_start -mysql_stmt_execute_cont -mysql_stmt_execute_start -mysql_stmt_fetch_cont -mysql_stmt_fetch_start -mysql_stmt_free_result_cont -mysql_stmt_free_result_start -mysql_stmt_next_result_cont -mysql_stmt_next_result_start -mysql_stmt_prepare_cont -mysql_stmt_prepare_start -mysql_stmt_reset_cont -mysql_stmt_reset_start -mysql_stmt_send_long_data_cont -mysql_stmt_send_long_data_start -mysql_stmt_store_result_cont -mysql_stmt_store_result_start -mysql_store_result_cont -mysql_store_result_start -#dynamic columns api -dynamic_column_create -dynamic_column_create_many -dynamic_column_update -dynamic_column_update_many -dynamic_column_exists -dynamic_column_list -dynamic_column_get -dynamic_column_prepare_decimal -mariadb_dyncol_create_many_num -mariadb_dyncol_create_many_named -mariadb_dyncol_update_many_num -mariadb_dyncol_update_many_named -mariadb_dyncol_exists_num -mariadb_dyncol_exists_named -mariadb_dyncol_free -mariadb_dyncol_list_num -mariadb_dyncol_list_named -mariadb_dyncol_get_num -mariadb_dyncol_get_named -mariadb_dyncol_has_names -mariadb_dyncol_check -mariadb_dyncol_json -mariadb_dyncol_val_str -mariadb_dyncol_val_long -mariadb_dyncol_val_double -mariadb_dyncol_unpack -mariadb_dyncol_unpack_free -mariadb_dyncol_column_cmp_named -mariadb_dyncol_column_count -mariadb_dyncol_prepare_decimal -# -mariadb_deinitialize_ssl -# low-level API to MySQL protocol -mysql_net_read_packet -mysql_net_field_length -# Added in MariaDB-10.0 to stay compatible with MySQL-5.6, yuck! -mysql_options4 -) - -SET(CLIENT_API_FUNCTIONS - ${CLIENT_API_FUNCTIONS_5_1} - ${CLIENT_API_FUNCTIONS_5_5} - CACHE INTERNAL - "Client functions" -) - -IF(CMAKE_SYSTEM_NAME MATCHES "Linux") - IF (NOT DISABLE_LIBMYSQLCLIENT_SYMBOL_VERSIONING) - - INCLUDE (CheckCSourceCompiles) - FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.ld" - "VERSION {\nlibmysqlclient_18 {\nglobal: *;\n};\n}\n") - SET(CMAKE_REQUIRED_LIBRARIES "-Wl,src.ld") - CHECK_C_SOURCE_COMPILES("int main() { return 0; }" - SUPPORTS_VERSION_IN_LINK_SCRIPT) - SET(CMAKE_REQUIRED_LIBRARIES) - - IF (NOT SUPPORTS_VERSION_IN_LINK_SCRIPT) - # https://sourceware.org/bugzilla/show_bug.cgi?id=16895 - MESSAGE(SEND_ERROR "Your current linker does not support VERSION " - "command in linker scripts like a GNU ld or any compatible linker " - "should. Perhaps you're using gold? Either switch to GNU ld compatible " - "linker or run cmake with -DDISABLE_LIBMYSQLCLIENT_SYMBOL_VERSIONING=TRUE " - "to be able to complete the build") - ENDIF (NOT SUPPORTS_VERSION_IN_LINK_SCRIPT) - - # When building RPM, or DEB package on Debian, use ELF symbol versioning - # for compatibility with distribution packages, so client shared library can - # painlessly replace the one supplied by the distribution. - - # Also list of exported symbols in distributions may differ from what is - # considered official API. Define CLIENT_API_5_1_EXTRA for the set of - # symbols, that required to be exported on different platforms. - - # Fedora & Co declared following functions as part of API - SET(CLIENT_API_5_1_EXTRA - # why does Fedora export these? - _fini - _init - my_init - - # mysql-connector-odbc requires these - mysql_default_charset_info - mysql_get_charset - mysql_get_charset_by_csname - mysql_net_realloc - - # PHP's mysqli.so requires this (via the ER() macro) - mysql_client_errors - - # Also export the non-renamed variants - # (in case someone wants to rebuild mysqli-php or something similar) - # See MDEV-4127 - default_charset_info - get_charset - get_charset_by_csname - net_realloc - client_errors - - # pure-ftpd requires this - my_make_scrambled_password - - # hydra requires this - scramble - - # ODB requires this: https://bugzilla.redhat.com/show_bug.cgi?id=846602 - THR_KEY_mysys - - # DBD::mysql requires this - is_prefix - ) - - - # And even more so on Debian - SET(CLIENT_API_5_5_EXTRA - # libmyodbc. Argh! - alloc_dynamic - alloc_root - delete_dynamic - dynstr_append - dynstr_append_mem - dynstr_append_os_quoted - dynstr_free - dynstr_realloc - free_root - get_dynamic - init_dynamic_array2 - init_dynamic_string - int2str - list_add - list_delete - my_end - my_free - my_malloc - my_memdup - my_realloc - my_strdup - set_dynamic - strdup_root - strend - strfill - strmake - strmake_root - strxmov - - # pam_mysql.so - make_scrambled_password - make_scrambled_password_323 - ) - - # Generate version script. - # Create semicolon separated lists of functions to export from - # Since RPM packages use separate versioning for 5.1 API - # and 5.5 API (libmysqlclient_16 vs libmysqlclient_18), - # we need 2 lists. - SET (VERSION_HEADER -"VERSION { - libmysqlclient_18 { - global:") - SET (VERSION_FOOTER -" local: - *; - }; - - libmysqlclient_16 { - /* empty here. aliases are added above */ - }; -} -") - - SET (CLIENT_API_5_1_LIST) - SET (CLIENT_API_5_1_ALIASES) - FOREACH (f ${CLIENT_API_FUNCTIONS_5_1} ${CLIENT_API_5_1_EXTRA}) - SET(CLIENT_API_5_1_LIST "${CLIENT_API_5_1_LIST}\t${f};\n") - SET(CLIENT_API_5_1_ALIASES "${CLIENT_API_5_1_ALIASES}\"${f}@libmysqlclient_16\" = ${f};\n") - ENDFOREACH() - - SET (CLIENT_API_5_5_LIST) - FOREACH (f ${CLIENT_API_FUNCTIONS_5_5} ${CLIENT_API_5_5_EXTRA}) - SET(CLIENT_API_5_5_LIST "${CLIENT_API_5_5_LIST}\t${f};\n") - ENDFOREACH() - - ELSE (NOT DISABLE_LIBMYSQLCLIENT_SYMBOL_VERSIONING) - SET (CLIENT_API_5_1_ALIASES "/* Versioning disabled per user request. MDEV-5982 */") - ENDIF (NOT DISABLE_LIBMYSQLCLIENT_SYMBOL_VERSIONING) - - # Linker script to version symbols in Fedora- and Debian- compatible way, MDEV-5529 - SET(VERSION_SCRIPT_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/libmysql_versions.ld.in) - - CONFIGURE_FILE( - ${VERSION_SCRIPT_TEMPLATE} - ${CMAKE_CURRENT_BINARY_DIR}/libmysql_versions.ld - @ONLY - ) - SET(VERSION_SCRIPT_LINK_FLAGS - "-Wl,${CMAKE_CURRENT_BINARY_DIR}/libmysql_versions.ld") - -ENDIF() diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h deleted file mode 100644 index 2577870bfa3..00000000000 --- a/libmysql/client_settings.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifndef CLIENT_SETTINGS_INCLUDED -#define CLIENT_SETTINGS_INCLUDED -#else -#error You have already included an client_settings.h and it should not be included twice -#endif /* CLIENT_SETTINGS_INCLUDED */ - -extern uint mysql_port; -extern char * mysql_unix_port; - -/* - Note: CLIENT_CAPABILITIES is also defined in sql/client_settings.h. - When adding capabilities here, consider if they should be also added to - the server's version. -*/ -#define CLIENT_CAPABILITIES (CLIENT_MYSQL | \ - CLIENT_LONG_FLAG | \ - CLIENT_TRANSACTIONS | \ - CLIENT_PROTOCOL_41 | \ - CLIENT_SECURE_CONNECTION | \ - CLIENT_MULTI_RESULTS | \ - CLIENT_PS_MULTI_RESULTS | \ - CLIENT_PLUGIN_AUTH | \ - CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ - CLIENT_CONNECT_ATTRS) - -sig_handler my_pipe_sig_handler(int sig); -void read_user_name(char *name); -my_bool handle_local_infile(MYSQL *mysql, const char *net_filename); - -void mysql_read_default_options(struct st_mysql_options *options, - const char *filename,const char *group); -void mysql_detach_stmt_list(LIST **stmt_list, const char *func_name); -MYSQL * STDCALL -cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user, - const char *passwd, const char *db, - uint port, const char *unix_socket,ulong client_flag); - -void cli_mysql_close(MYSQL *mysql); - -MYSQL_FIELD * cli_list_fields(MYSQL *mysql); -my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt); -MYSQL_DATA * cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - uint fields); -int cli_stmt_execute(MYSQL_STMT *stmt); -int cli_read_binary_rows(MYSQL_STMT *stmt); -int cli_unbuffered_fetch(MYSQL *mysql, char **row); -const char * cli_read_statistics(MYSQL *mysql); -int cli_read_change_user_result(MYSQL *mysql); - -#ifdef EMBEDDED_LIBRARY -int init_embedded_server(int argc, char **argv, char **groups); -void end_embedded_server(); -#endif /*EMBEDDED_LIBRARY*/ - -C_MODE_START -extern int mysql_init_character_set(MYSQL *mysql); -C_MODE_END diff --git a/libmysql/conf_to_src.c b/libmysql/conf_to_src.c deleted file mode 100644 index 0e92388c93c..00000000000 --- a/libmysql/conf_to_src.c +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation. - - There are special exceptions to the terms and conditions of the GPL as it - is applied to this software. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ - -/* can't use -lmysys because this prog is used to create -lstrings */ - - -#include <my_global.h> -#include <ctype.h> -#include <string.h> -#include <unistd.h> - -#define CHARSETS_SUBDIR "sql/share/charsets" -#define CTYPE_TABLE_SIZE 257 -#define TO_LOWER_TABLE_SIZE 256 -#define TO_UPPER_TABLE_SIZE 256 -#define SORT_ORDER_TABLE_SIZE 256 -#define ROW_LEN 16 - -void print_arrays_for(char *set); - -char *prog; -char buf[1024], *p, *endptr; - -int -main(int argc, char **argv) -{ - prog = *argv; - - if (argc < 2) { - fprintf(stderr, "usage: %s source-dir [charset [, charset]]\n", prog); - exit(EXIT_FAILURE); - } - - --argc; ++argv; /* skip program name */ - - if (chdir(*argv) != 0) { - fprintf(stderr, "%s: can't cd to %s\n", prog, *argv); - exit(EXIT_FAILURE); - } - --argc; ++argv; - - if (chdir(CHARSETS_SUBDIR) != 0) { - fprintf(stderr, "%s: can't cd to %s\n", prog, CHARSETS_SUBDIR); - exit(EXIT_FAILURE); - } - - while (argc--) - print_arrays_for(*argv++); - - exit(EXIT_SUCCESS); -} - -void -print_array(FILE *f, const char *set, const char *name, int n) -{ - int i; - char val[100]; - - printf("uchar %s_%s[] = {\n", name, set); - - p = buf; - *buf = '\0'; - for (i = 0; i < n; ++i) - { - /* get a word from f */ - endptr = p; - for (;;) - { - while (isspace(*endptr)) - ++endptr; - if (*endptr && *endptr != '#') /* not comment */ - break; - if ((fgets(buf, sizeof(buf), f)) == NULL) - return; /* XXX: break silently */ - endptr = buf; - } - - p = val; - while (!isspace(*endptr)) - *p++ = *endptr++; - *p = '\0'; - p = endptr; - - /* write the value out */ - - if (i == 0 || i % ROW_LEN == n % ROW_LEN) - printf(" "); - - printf("%3d", (unsigned char) strtol(val, (char **) NULL, 16)); - - if (i < n - 1) - printf(","); - - if ((i+1) % ROW_LEN == n % ROW_LEN) - printf("\n"); - } - - printf("};\n\n"); -} - -void -print_arrays_for(char *set) -{ - FILE *f; - - snprintf(buf, sizeof(buf), "%s.conf", set); - - if ((f = fopen(buf, "r")) == NULL) { - fprintf(stderr, "%s: can't read conf file for charset %s\n", prog, set); - exit(EXIT_FAILURE); - } - - printf("\ -/* The %s character set. Generated automatically by configure and\n\ - * the %s program\n\ - */\n\n", - set, prog); - - /* it would be nice if this used the code in mysys/charset.c, but... */ - print_array(f, set, "ctype", CTYPE_TABLE_SIZE); - print_array(f, set, "to_lower", TO_LOWER_TABLE_SIZE); - print_array(f, set, "to_upper", TO_UPPER_TABLE_SIZE); - print_array(f, set, "sort_order", SORT_ORDER_TABLE_SIZE); - printf("\n"); - - fclose(f); - - return; -} diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c deleted file mode 100644 index fc5a6a07e11..00000000000 --- a/libmysql/errmsg.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation. - - There are special exceptions to the terms and conditions of the GPL as it - is applied to this software. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -/* Error messages for MySQL clients */ -/* (Error messages for the daemon are in share/language/errmsg.sys) */ - -#include <my_global.h> -#include <my_sys.h> -#include "errmsg.h" - -const char *client_errors[]= -{ - "Unknown MySQL error", - "Can't create UNIX socket (%d)", - "Can't connect to local MySQL server through socket '%-.100s' (%M)", - "Can't connect to MySQL server on '%-.100s' (%M)", - "Can't create TCP/IP socket (%M)", - "Unknown MySQL server host '%-.100s' (%d)", - "MySQL server has gone away", - "Protocol mismatch; server version = %d, client version = %d", - "MySQL client ran out of memory", - "Wrong host info", - "Localhost via UNIX socket", - "%-.100s via TCP/IP", - "Error in server handshake", - "Lost connection to MySQL server during query", - "Commands out of sync; you can't run this command now", - "Named pipe: %-.32s", - "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", - "Can't initialize character set %-.32s (path: %-.100s)", - "Got packet bigger than 'max_allowed_packet' bytes", - "Embedded server", - "Error on SHOW SLAVE STATUS:", - "Error on SHOW SLAVE HOSTS:", - "Error connecting to slave:", - "Error connecting to master:", - "SSL connection error: %-.100s", - "Malformed packet", - "This client library is licensed only for use with MySQL servers having '%s' license", - "Invalid use of null pointer", - "Statement not prepared", - "No data supplied for parameters in prepared statement", - "Data truncated", - "No parameters exist in the statement", - "Invalid parameter number", - "Can't send long data for non-string/non-binary data types (parameter: %d)", - "Using unsupported buffer type: %d (parameter: %d)", - "Shared memory: %-.100s", - "Can't open shared memory; client could not create request event (%lu)", - "Can't open shared memory; no answer event received from server (%lu)", - "Can't open shared memory; server could not allocate file mapping (%lu)", - "Can't open shared memory; server could not get pointer to file mapping (%lu)", - "Can't open shared memory; client could not allocate file mapping (%lu)", - "Can't open shared memory; client could not get pointer to file mapping (%lu)", - "Can't open shared memory; client could not create %s event (%lu)", - "Can't open shared memory; no answer from server (%lu)", - "Can't open shared memory; cannot send request event to server (%lu)", - "Wrong or unknown protocol", - "Invalid connection handle", - "Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)", - "Row retrieval was canceled by mysql_stmt_close() call", - "Attempt to read column without prior row fetch", - "Prepared statement contains no metadata", - "Attempt to read a row while there is no result set associated with the statement", - "This feature is not implemented yet", - "Lost connection to MySQL server at '%s', system error: %M", - "Statement closed indirectly because of a preceding %s() call", - "The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again", - "This handle is already connected. Use a separate handle for each connection.", - "Authentication plugin '%s' cannot be loaded: %s", - "There is an attribute with the same name already", - "Authentication plugin '%s' reported error: %s", - "" -}; - -const char** get_client_errmsgs(int nr __attribute__((unused))) -{ - return client_errors; -} - -/* - Register client error messages for use with my_error(). - - SYNOPSIS - init_client_errs() - - RETURN - void -*/ - -void init_client_errs(void) -{ - compile_time_assert(array_elements(client_errors) == - (CR_ERROR_LAST - CR_ERROR_FIRST + 2)); - (void) my_error_register(get_client_errmsgs, CR_ERROR_FIRST, CR_ERROR_LAST); -} - - -/* - Unregister client error messages. - - SYNOPSIS - finish_client_errs() - - RETURN - void -*/ - -void finish_client_errs(void) -{ - (void) my_error_unregister(CR_ERROR_FIRST, CR_ERROR_LAST); -} diff --git a/libmysql/get_password.c b/libmysql/get_password.c deleted file mode 100644 index a113306ed57..00000000000 --- a/libmysql/get_password.c +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation. - - There are special exceptions to the terms and conditions of the GPL as it - is applied to this software. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -/* -** Ask for a password from tty -** This is an own file to avoid conflicts with curses -*/ -#include <my_global.h> -#include <my_sys.h> -#include "mysql.h" -#include <m_string.h> -#include <m_ctype.h> - -#ifdef HAVE_GETPASS -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif /* HAVE_PWD_H */ -#else /* ! HAVE_GETPASS */ -#if !defined(__WIN__) -#include <sys/ioctl.h> -#ifdef HAVE_TERMIOS_H /* For tty-password */ -#include <termios.h> -#define TERMIO struct termios -#else -#ifdef HAVE_TERMIO_H /* For tty-password */ -#include <termio.h> -#define TERMIO struct termio -#else -#include <sgtty.h> -#define TERMIO struct sgttyb -#endif -#endif -#ifdef alpha_linux_port -#include <asm/ioctls.h> -#include <asm/termiobits.h> -#endif -#else -#include <conio.h> -#endif /* __WIN__ */ -#endif /* HAVE_GETPASS */ - -#ifdef HAVE_GETPASSPHRASE /* For Solaris */ -#define getpass(A) getpassphrase(A) -#endif - -#if defined(__WIN__) -/* were just going to fake it here and get input from the keyboard */ -void get_tty_password_buff(const char *opt_message, char *to, size_t length) -{ - HANDLE consoleinput; - DWORD oldstate; - char *pos=to,*end=to+length-1; - int i=0; - - consoleinput= CreateFile("CONIN$", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ , - NULL, OPEN_EXISTING, 0, NULL); - if (consoleinput == NULL || consoleinput == INVALID_HANDLE_VALUE) - { - /* This is a GUI application or service without console input, bail out. */ - *to= 0; - return; - } - _cputs(opt_message ? opt_message : "Enter password: "); - - /* - Switch to raw mode (no line input, no echo input). - Allow Ctrl-C handler with ENABLE_PROCESSED_INPUT. - */ - GetConsoleMode(consoleinput, &oldstate); - SetConsoleMode(consoleinput, ENABLE_PROCESSED_INPUT); - for (;;) - { - char tmp; - DWORD chars_read; - if (!ReadConsole(consoleinput, &tmp, 1, &chars_read, NULL)) - break; - if (chars_read == 0) - break; - if (tmp == '\b' || tmp == 127) - { - if (pos != to) - { - _cputs("\b \b"); - pos--; - continue; - } - } - if (tmp == '\n' || tmp == '\r') - break; - if (iscntrl(tmp) || pos == end) - continue; - _cputs("*"); - *(pos++) = tmp; - } - /* Reset console mode after password input. */ - SetConsoleMode(consoleinput, oldstate); - CloseHandle(consoleinput); - *pos=0; - _cputs("\n"); -} - -#else - -#ifndef HAVE_GETPASS -/* - Can't use fgets, because readline will get confused - length is max number of chars in to, not counting \0 - to will not include the eol characters. -*/ - -static void get_password(char *to,uint length,int fd, my_bool echo) -{ - char *pos=to,*end=to+length; - - for (;;) - { - char tmp; - if (my_read(fd,&tmp,1,MYF(0)) != 1) - break; - if (tmp == '\b' || (int) tmp == 127) - { - if (pos != to) - { - if (echo) - { - fputs("\b \b",stdout); - fflush(stdout); - } - pos--; - continue; - } - } - if (tmp == '\n' || tmp == '\r' || tmp == 3) - break; - if (iscntrl(tmp) || pos == end) - continue; - if (echo) - { - fputc('*',stdout); - fflush(stdout); - } - *(pos++) = tmp; - } - *pos=0; - return; -} -#endif /* ! HAVE_GETPASS */ - - -void get_tty_password_buff(const char *opt_message, char *buff, size_t buflen) -{ -#ifdef HAVE_GETPASS - char *passbuff; -#else /* ! HAVE_GETPASS */ - TERMIO org,tmp; -#endif /* HAVE_GETPASS */ - -#ifdef HAVE_GETPASS - passbuff = getpass(opt_message ? opt_message : "Enter password: "); - - /* copy the password to buff and clear original (static) buffer */ - strncpy(buff, passbuff, buflen - 1); -#ifdef _PASSWORD_LEN - memset(passbuff, 0, _PASSWORD_LEN); -#endif -#else - if (isatty(fileno(stdout))) - { - fputs(opt_message ? opt_message : "Enter password: ",stdout); - fflush(stdout); - } -#if defined(HAVE_TERMIOS_H) - tcgetattr(fileno(stdin), &org); - tmp = org; - tmp.c_lflag &= ~(ECHO | ISIG | ICANON); - tmp.c_cc[VMIN] = 1; - tmp.c_cc[VTIME] = 0; - tcsetattr(fileno(stdin), TCSADRAIN, &tmp); - get_password(buff, buflen, fileno(stdin), isatty(fileno(stdout))); - tcsetattr(fileno(stdin), TCSADRAIN, &org); -#elif defined(HAVE_TERMIO_H) - ioctl(fileno(stdin), (int) TCGETA, &org); - tmp=org; - tmp.c_lflag &= ~(ECHO | ISIG | ICANON); - tmp.c_cc[VMIN] = 1; - tmp.c_cc[VTIME]= 0; - ioctl(fileno(stdin),(int) TCSETA, &tmp); - get_password(buff,buflen-1,fileno(stdin),isatty(fileno(stdout))); - ioctl(fileno(stdin),(int) TCSETA, &org); -#else - gtty(fileno(stdin), &org); - tmp=org; - tmp.sg_flags &= ~ECHO; - tmp.sg_flags |= RAW; - stty(fileno(stdin), &tmp); - get_password(buff,buflen-1,fileno(stdin),isatty(fileno(stdout))); - stty(fileno(stdin), &org); -#endif - if (isatty(fileno(stdout))) - fputc('\n',stdout); -#endif /* HAVE_GETPASS */ -} -#endif /*__WIN__*/ - -#ifndef MYSQL_DYNAMIC_PLUGIN -char *get_tty_password(const char *opt_message) -{ - char buff[80]; - get_tty_password_buff(opt_message, buff, sizeof(buff)); - return my_strdup(buff, MYF(MY_FAE)); -} -#endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c deleted file mode 100644 index de50acde2f4..00000000000 --- a/libmysql/libmysql.c +++ /dev/null @@ -1,4922 +0,0 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation. - - There are special exceptions to the terms and conditions of the GPL as it - is applied to this software. View the full text of the exception in file - EXCEPTIONS-CLIENT in the directory of this software distribution. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include <my_global.h> -#include <my_sys.h> -#include <my_time.h> -#include <mysys_err.h> -#include <m_string.h> -#include <m_ctype.h> -#include "mysql.h" -#include "mysql_version.h" -#include "mysqld_error.h" -#include "errmsg.h" -#include <violite.h> -#include <sys/stat.h> -#include <signal.h> -#include <time.h> -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#if !defined(__WIN__) -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#ifdef HAVE_SELECT_H -#include <select.h> -#endif -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#endif /* !defined(__WIN__) */ -#if defined(HAVE_POLL_H) -#include <poll.h> -#elif defined(HAVE_SYS_POLL_H) -#include <sys/poll.h> -#endif /* defined(HAVE_POLL_H) */ -#ifdef HAVE_SYS_UN_H -#include <sys/un.h> -#endif -#if !defined(__WIN__) -#include <my_pthread.h> /* because of signal() */ -#endif -#ifndef INADDR_NONE -#define INADDR_NONE -1 -#endif - -#include <sql_common.h> -#include "client_settings.h" - -#undef net_buffer_length -#undef max_allowed_packet - -ulong net_buffer_length=8192; -ulong max_allowed_packet= 1024L*1024L*1024L; - - -#ifdef EMBEDDED_LIBRARY -#undef net_flush -my_bool net_flush(NET *net); -#endif - -#if defined(__WIN__) -/* socket_errno is defined in my_global.h for all platforms */ -#define perror(A) -#else -#include <errno.h> -#define SOCKET_ERROR -1 -#endif /* __WIN__ */ - -/* - If allowed through some configuration, then this needs to - be changed -*/ -#define MAX_LONG_DATA_LENGTH 8192 -#define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG) - -static void append_wild(char *to,char *end,const char *wild); -sig_handler my_pipe_sig_handler(int sig); - -static my_bool mysql_client_init= 0; -static my_bool org_my_init_done= 0; - -typedef struct st_mysql_stmt_extension -{ - MEM_ROOT fields_mem_root; -} MYSQL_STMT_EXT; - - -/* - Initialize the MySQL client library - - SYNOPSIS - mysql_server_init() - - NOTES - Should be called before doing any other calls to the MySQL - client library to initialize thread specific variables etc. - It's called by mysql_init() to ensure that things will work for - old not threaded applications that doesn't call mysql_server_init() - directly. - - RETURN - 0 ok - 1 could not initialize environment (out of memory or thread keys) -*/ - -int STDCALL mysql_server_init(int argc __attribute__((unused)), - char **argv __attribute__((unused)), - char **groups __attribute__((unused))) -{ - int result= 0; - if (!mysql_client_init) - { - mysql_client_init=1; - org_my_init_done=my_init_done; - if (my_init()) /* Will init threads */ - return 1; - init_client_errs(); - if (mysql_client_plugin_init()) - return 1; - if (!mysql_port) - { - char *env; - struct servent *serv_ptr __attribute__((unused)); - - mysql_port = MYSQL_PORT; - - /* - if builder specifically requested a default port, use that - (even if it coincides with our factory default). - only if they didn't do we check /etc/services (and, failing - on that, fall back to the factory default of 3306). - either default can be overridden by the environment variable - MYSQL_TCP_PORT, which in turn can be overridden with command - line options. - */ - -#if MYSQL_PORT_DEFAULT == 0 - if ((serv_ptr= getservbyname("mysql", "tcp"))) - mysql_port= (uint) ntohs((ushort) serv_ptr->s_port); -#endif - if ((env= getenv("MYSQL_TCP_PORT"))) - mysql_port=(uint) atoi(env); - } - - if (!mysql_unix_port) - { - char *env; -#ifdef __WIN__ - mysql_unix_port = (char*) MYSQL_NAMEDPIPE; -#else - mysql_unix_port = (char*) MYSQL_UNIX_ADDR; -#endif - if ((env = getenv("MYSQL_UNIX_PORT"))) - mysql_unix_port = env; - } - mysql_debug(NullS); -#if defined(SIGPIPE) && !defined(__WIN__) - (void) signal(SIGPIPE, SIG_IGN); -#endif -#ifdef EMBEDDED_LIBRARY - if (argc > -1) - result= init_embedded_server(argc, argv, groups); -#endif - } - else - result= (int)my_thread_init(); /* Init if new thread */ - return result; -} - - -/* - Free all memory and resources used by the client library - - NOTES - When calling this there should not be any other threads using - the library. - - To make things simpler when used with windows dll's (which calls this - function automaticly), it's safe to call this function multiple times. -*/ - - -void STDCALL mysql_server_end() -{ - if (!mysql_client_init) - return; - - mysql_client_plugin_deinit(); - - finish_client_errs(); - if (mariadb_deinitialize_ssl) - vio_end(); -#ifdef EMBEDDED_LIBRARY - end_embedded_server(); -#endif - - /* If library called my_init(), free memory allocated by it */ - if (!org_my_init_done) - { - my_end(0); - } -#ifdef NOT_NEEDED - /* - The following is not needed as if the program explicitly called - my_init() then we can assume it will also call my_end(). - The reason to not also do it here is in that case we can't get - statistics from my_end() to debug log. - */ - else - { - free_charsets(); - mysql_thread_end(); - } -#endif - - mysql_client_init= org_my_init_done= 0; -} - -static MYSQL_PARAMETERS mysql_internal_parameters= -{&max_allowed_packet, &net_buffer_length, 0}; - -MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void) -{ - return &mysql_internal_parameters; -} - -my_bool STDCALL mysql_thread_init() -{ - return my_thread_init(); -} - -void STDCALL mysql_thread_end() -{ - my_thread_end(); -} - - -/* - Expand wildcard to a sql string -*/ - -static void -append_wild(char *to, char *end, const char *wild) -{ - end-=5; /* Some extra */ - if (wild && wild[0]) - { - to=strmov(to," like '"); - while (*wild && to < end) - { - if (*wild == '\\' || *wild == '\'') - *to++='\\'; - *to++= *wild++; - } - if (*wild) /* Too small buffer */ - *to++='%'; /* Nicer this way */ - to[0]='\''; - to[1]=0; - } -} - - -/************************************************************************** - Init debugging if MYSQL_DEBUG environment variable is found -**************************************************************************/ - -void STDCALL -mysql_debug(const char *debug __attribute__((unused))) -{ -#ifndef DBUG_OFF - char *env; - if (debug) - { - DBUG_PUSH(debug); - } - else if ((env = getenv("MYSQL_DEBUG"))) - { - DBUG_PUSH(env); -#if !defined(_WINVER) && !defined(WINVER) - puts("\n-------------------------------------------------------"); - puts("MYSQL_DEBUG found. libmysql started with the following:"); - puts(env); - puts("-------------------------------------------------------\n"); -#else - { - char buff[80]; - buff[sizeof(buff)-1]= 0; - strxnmov(buff,sizeof(buff)-1,"libmysql: ", env, NullS); - MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK); - } -#endif - } -#endif -} - - -/************************************************************************** - Ignore SIGPIPE handler - ARGSUSED -**************************************************************************/ - -sig_handler -my_pipe_sig_handler(int sig __attribute__((unused))) -{ - DBUG_PRINT("info",("Hit by signal %d",sig)); -#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY - (void) signal(SIGPIPE, my_pipe_sig_handler); -#endif -} - - -/************************************************************************** - Connect to sql server - If host == 0 then use localhost -**************************************************************************/ - -#ifdef USE_OLD_FUNCTIONS -MYSQL * STDCALL -mysql_connect(MYSQL *mysql,const char *host, - const char *user, const char *passwd) -{ - MYSQL *res; - mysql=mysql_init(mysql); /* Make it thread safe */ - { - DBUG_ENTER("mysql_connect"); - if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0))) - { - if (mysql->free_me) - my_free(mysql); - } - mysql->reconnect= 1; - DBUG_RETURN(res); - } -} -#endif - - -/************************************************************************** - Change user and database -**************************************************************************/ - -my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, - const char *passwd, const char *db) -{ - int rc; - CHARSET_INFO *saved_cs= mysql->charset; - char *saved_user= mysql->user; - char *saved_passwd= mysql->passwd; - char *saved_db= mysql->db; - - DBUG_ENTER("mysql_change_user"); - - /* Get the connection-default character set. */ - - if (mysql_init_character_set(mysql)) - { - mysql->charset= saved_cs; - DBUG_RETURN(TRUE); - } - - /* Use an empty string instead of NULL. */ - - mysql->user= (char*)(user ? user : ""); - mysql->passwd= (char*)(passwd ? passwd : ""); - mysql->db= 0; - - rc= run_plugin_auth(mysql, 0, 0, 0, db); - - /* - The server will close all statements no matter was the attempt - to change user successful or not. - */ - mysql_detach_stmt_list(&mysql->stmts, "mysql_change_user"); - if (rc == 0) - { - /* Free old connect information */ - my_free(saved_user); - my_free(saved_passwd); - my_free(saved_db); - - /* alloc new connect information */ - mysql->user= my_strdup(mysql->user, MYF(MY_WME)); - mysql->passwd= my_strdup(mysql->passwd, MYF(MY_WME)); - mysql->db= db ? my_strdup(db, MYF(MY_WME)) : 0; - } - else - { - mysql->charset= saved_cs; - mysql->user= saved_user; - mysql->passwd= saved_passwd; - mysql->db= saved_db; - } - - DBUG_RETURN(rc); -} - -#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL) -struct passwd *getpwuid(uid_t); -char* getlogin(void); -#endif - -#if !defined(__WIN__) - -void read_user_name(char *name) -{ - DBUG_ENTER("read_user_name"); - if (geteuid() == 0) - (void) strmov(name,"root"); /* allow use of surun */ - else - { -#ifdef HAVE_GETPWUID - struct passwd *skr; - const char *str; - if ((str=getlogin()) == NULL) - { - if ((skr=getpwuid(geteuid())) != NULL) - str=skr->pw_name; - else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) && - !(str=getenv("LOGIN"))) - str="UNKNOWN_USER"; - } - (void) strmake(name,str,USERNAME_LENGTH); -#elif HAVE_CUSERID - (void) cuserid(name); -#else - strmov(name,"UNKNOWN_USER"); -#endif - } - DBUG_VOID_RETURN; -} - -#else /* If Windows */ - -void read_user_name(char *name) -{ - char *str=getenv("USER"); /* ODBC will send user variable */ - strmake(name,str ? str : "ODBC", USERNAME_LENGTH); -} - -#endif - -my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) -{ - my_bool result= 1; - uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE); - NET *net= &mysql->net; - int readcount; - void *li_ptr; /* pass state to local_infile functions */ - char *buf; /* buffer to be filled by local_infile_read */ - struct st_mysql_options *options= &mysql->options; - DBUG_ENTER("handle_local_infile"); - - /* check that we've got valid callback functions */ - if (!(options->local_infile_init && - options->local_infile_read && - options->local_infile_end && - options->local_infile_error)) - { - /* if any of the functions is invalid, set the default */ - mysql_set_local_infile_default(mysql); - } - - /* copy filename into local memory and allocate read buffer */ - if (!(buf=my_malloc(packet_length, MYF(0)))) - { - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - DBUG_RETURN(1); - } - - /* initialize local infile (open file, usually) */ - if ((*options->local_infile_init)(&li_ptr, net_filename, - options->local_infile_userdata)) - { - (void) my_net_write(net,(const uchar*) "",0); /* Server needs one packet */ - net_flush(net); - strmov(net->sqlstate, unknown_sqlstate); - net->last_errno= - (*options->local_infile_error)(li_ptr, - net->last_error, - sizeof(net->last_error)-1); - goto err; - } - - /* read blocks of data from local infile callback */ - while ((readcount = - (*options->local_infile_read)(li_ptr, buf, - packet_length)) > 0) - { - if (my_net_write(net, (uchar*) buf, readcount)) - { - DBUG_PRINT("error", - ("Lost connection to MySQL server during LOAD DATA of local file")); - set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate); - goto err; - } - } - - /* Send empty packet to mark end of file */ - if (my_net_write(net, (const uchar*) "", 0) || net_flush(net)) - { - set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate); - goto err; - } - - if (readcount < 0) - { - net->last_errno= - (*options->local_infile_error)(li_ptr, - net->last_error, - sizeof(net->last_error)-1); - goto err; - } - - result=0; /* Ok */ - -err: - /* free up memory allocated with _init, usually */ - (*options->local_infile_end)(li_ptr); - my_free(buf); - DBUG_RETURN(result); -} - - -/**************************************************************************** - Default handlers for LOAD LOCAL INFILE -****************************************************************************/ - -typedef struct st_default_local_infile -{ - int fd; - int error_num; - const char *filename; - char error_msg[LOCAL_INFILE_ERROR_LEN]; -} default_local_infile_data; - - -/* - Open file for LOAD LOCAL INFILE - - SYNOPSIS - default_local_infile_init() - ptr Store pointer to internal data here - filename File name to open. This may be in unix format ! - - - NOTES - Even if this function returns an error, the load data interface - guarantees that default_local_infile_end() is called. - - RETURN - 0 ok - 1 error -*/ - -static int default_local_infile_init(void **ptr, const char *filename, - void *userdata __attribute__ ((unused))) -{ - default_local_infile_data *data; - char tmp_name[FN_REFLEN]; - - if (!(*ptr= data= ((default_local_infile_data *) - my_malloc(sizeof(default_local_infile_data), MYF(0))))) - return 1; /* out of memory */ - - data->error_msg[0]= 0; - data->error_num= 0; - data->filename= filename; - - fn_format(tmp_name, filename, "", "", MY_UNPACK_FILENAME); - if ((data->fd = my_open(tmp_name, O_RDONLY, MYF(0))) < 0) - { - data->error_num= my_errno; - my_snprintf(data->error_msg, sizeof(data->error_msg)-1, - EE(EE_FILENOTFOUND), tmp_name, data->error_num); - return 1; - } - return 0; /* ok */ -} - - -/* - Read data for LOAD LOCAL INFILE - - SYNOPSIS - default_local_infile_read() - ptr Points to handle allocated by _init - buf Read data here - buf_len Ammount of data to read - - RETURN - > 0 number of bytes read - == 0 End of data - < 0 Error -*/ - -static int default_local_infile_read(void *ptr, char *buf, uint buf_len) -{ - int count; - default_local_infile_data*data = (default_local_infile_data *) ptr; - - if ((count= (int) my_read(data->fd, (uchar *) buf, buf_len, MYF(0))) < 0) - { - data->error_num= EE_READ; /* the errmsg for not entire file read */ - my_snprintf(data->error_msg, sizeof(data->error_msg)-1, - EE(EE_READ), - data->filename, my_errno); - } - return count; -} - - -/* - Read data for LOAD LOCAL INFILE - - SYNOPSIS - default_local_infile_end() - ptr Points to handle allocated by _init - May be NULL if _init failed! - - RETURN -*/ - -static void default_local_infile_end(void *ptr) -{ - default_local_infile_data *data= (default_local_infile_data *) ptr; - if (data) /* If not error on open */ - { - if (data->fd >= 0) - my_close(data->fd, MYF(MY_WME)); - my_free(ptr); - } -} - - -/* - Return error from LOAD LOCAL INFILE - - SYNOPSIS - default_local_infile_end() - ptr Points to handle allocated by _init - May be NULL if _init failed! - error_msg Store error text here - error_msg_len Max lenght of error_msg - - RETURN - error message number -*/ - -static int -default_local_infile_error(void *ptr, char *error_msg, uint error_msg_len) -{ - default_local_infile_data *data = (default_local_infile_data *) ptr; - if (data) /* If not error on open */ - { - strmake(error_msg, data->error_msg, error_msg_len); - return data->error_num; - } - /* This can only happen if we got error on malloc of handle */ - strmov(error_msg, ER(CR_OUT_OF_MEMORY)); - return CR_OUT_OF_MEMORY; -} - - -void -mysql_set_local_infile_handler(MYSQL *mysql, - int (*local_infile_init)(void **, const char *, - void *), - int (*local_infile_read)(void *, char *, uint), - void (*local_infile_end)(void *), - int (*local_infile_error)(void *, char *, uint), - void *userdata) -{ - mysql->options.local_infile_init= local_infile_init; - mysql->options.local_infile_read= local_infile_read; - mysql->options.local_infile_end= local_infile_end; - mysql->options.local_infile_error= local_infile_error; - mysql->options.local_infile_userdata = userdata; -} - - -void mysql_set_local_infile_default(MYSQL *mysql) -{ - mysql->options.local_infile_init= default_local_infile_init; - mysql->options.local_infile_read= default_local_infile_read; - mysql->options.local_infile_end= default_local_infile_end; - mysql->options.local_infile_error= default_local_infile_error; -} - - -/************************************************************************** - Do a query. If query returned rows, free old rows. - Read data by mysql_store_result or by repeat call of mysql_fetch_row -**************************************************************************/ - -int STDCALL -mysql_query(MYSQL *mysql, const char *query) -{ - return mysql_real_query(mysql,query, (uint) strlen(query)); -} - - -/************************************************************************** - Return next field of the query results -**************************************************************************/ - -MYSQL_FIELD * STDCALL -mysql_fetch_field(MYSQL_RES *result) -{ - if (result->current_field >= result->field_count) - return(NULL); - return &result->fields[result->current_field++]; -} - - -/************************************************************************** - Move to a specific row and column -**************************************************************************/ - -void STDCALL -mysql_data_seek(MYSQL_RES *result, my_ulonglong row) -{ - MYSQL_ROWS *tmp=0; - DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row)); - if (result->data) - for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ; - result->current_row=0; - result->data_cursor = tmp; -} - - -/************************************************************************* - put the row or field cursor one a position one got from mysql_row_tell() - This doesn't restore any data. The next mysql_fetch_row or - mysql_fetch_field will return the next row or field after the last used -*************************************************************************/ - -MYSQL_ROW_OFFSET STDCALL -mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row) -{ - MYSQL_ROW_OFFSET return_value=result->data_cursor; - result->current_row= 0; - result->data_cursor= row; - return return_value; -} - - -MYSQL_FIELD_OFFSET STDCALL -mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset) -{ - MYSQL_FIELD_OFFSET return_value=result->current_field; - result->current_field=field_offset; - return return_value; -} - - -/***************************************************************************** - List all databases -*****************************************************************************/ - -MYSQL_RES * STDCALL -mysql_list_dbs(MYSQL *mysql, const char *wild) -{ - char buff[255]; - DBUG_ENTER("mysql_list_dbs"); - - append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild); - if (mysql_query(mysql,buff)) - DBUG_RETURN(0); - DBUG_RETURN (mysql_store_result(mysql)); -} - - -/***************************************************************************** - List all tables in a database - If wild is given then only the tables matching wild is returned -*****************************************************************************/ - -MYSQL_RES * STDCALL -mysql_list_tables(MYSQL *mysql, const char *wild) -{ - char buff[255]; - DBUG_ENTER("mysql_list_tables"); - - append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild); - if (mysql_query(mysql,buff)) - DBUG_RETURN(0); - DBUG_RETURN (mysql_store_result(mysql)); -} - - -MYSQL_FIELD *cli_list_fields(MYSQL *mysql) -{ - MYSQL_DATA *query; - if (!(query= cli_read_rows(mysql,(MYSQL_FIELD*) 0, - protocol_41(mysql) ? 8 : 6))) - return NULL; - - mysql->field_count= (uint) query->rows; - return unpack_fields(mysql, query,&mysql->field_alloc, - mysql->field_count, 1, mysql->server_capabilities); -} - - -/************************************************************************** - List all fields in a table - If wild is given then only the fields matching wild is returned - Instead of this use query: - show fields in 'table' like "wild" -**************************************************************************/ - -MYSQL_RES * STDCALL -mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) -{ - MYSQL_RES *result; - MYSQL_FIELD *fields; - char buff[258],*end; - DBUG_ENTER("mysql_list_fields"); - DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : "")); - - end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128); - free_old_query(mysql); - if (simple_command(mysql, COM_FIELD_LIST, (uchar*) buff, - (ulong) (end-buff), 1) || - !(fields= (*mysql->methods->list_fields)(mysql))) - DBUG_RETURN(NULL); - - if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES), - MYF(MY_WME | MY_ZEROFILL)))) - DBUG_RETURN(NULL); - - result->methods= mysql->methods; - result->field_alloc=mysql->field_alloc; - mysql->fields=0; - result->field_count = mysql->field_count; - result->fields= fields; - result->eof=1; - DBUG_RETURN(result); -} - -/* List all running processes (threads) in server */ - -MYSQL_RES * STDCALL -mysql_list_processes(MYSQL *mysql) -{ - MYSQL_DATA *UNINIT_VAR(fields); - uint field_count; - uchar *pos; - DBUG_ENTER("mysql_list_processes"); - - if (simple_command(mysql,COM_PROCESS_INFO,0,0,0)) - DBUG_RETURN(0); - free_old_query(mysql); - pos=(uchar*) mysql->net.read_pos; - field_count=(uint) net_field_length(&pos); - if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0, - protocol_41(mysql) ? 7 : 5))) - DBUG_RETURN(NULL); - if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0, - mysql->server_capabilities))) - DBUG_RETURN(0); - mysql->status=MYSQL_STATUS_GET_RESULT; - mysql->field_count=field_count; - DBUG_RETURN(mysql_store_result(mysql)); -} - - -#ifdef USE_OLD_FUNCTIONS -int STDCALL -mysql_create_db(MYSQL *mysql, const char *db) -{ - DBUG_ENTER("mysql_createdb"); - DBUG_PRINT("enter",("db: %s",db)); - DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0)); -} - - -int STDCALL -mysql_drop_db(MYSQL *mysql, const char *db) -{ - DBUG_ENTER("mysql_drop_db"); - DBUG_PRINT("enter",("db: %s",db)); - DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0)); -} -#endif - - -int STDCALL -mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level) -{ - uchar level[1]; - DBUG_ENTER("mysql_shutdown"); - level[0]= (uchar) shutdown_level; - DBUG_RETURN(simple_command(mysql, COM_SHUTDOWN, level, 1, 0)); -} - - -int STDCALL -mysql_refresh(MYSQL *mysql,uint options) -{ - uchar bits[1]; - DBUG_ENTER("mysql_refresh"); - bits[0]= (uchar) options; - DBUG_RETURN(simple_command(mysql, COM_REFRESH, bits, 1, 0)); -} - - -int STDCALL -mysql_kill(MYSQL *mysql,ulong pid) -{ - uchar buff[4]; - DBUG_ENTER("mysql_kill"); - int4store(buff,pid); - DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,sizeof(buff),0)); -} - - -int STDCALL -mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option) -{ - uchar buff[2]; - DBUG_ENTER("mysql_set_server_option"); - int2store(buff, (uint) option); - DBUG_RETURN(simple_command(mysql, COM_SET_OPTION, buff, sizeof(buff), 0)); -} - - -int STDCALL -mysql_dump_debug_info(MYSQL *mysql) -{ - DBUG_ENTER("mysql_dump_debug_info"); - DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0)); -} - - -const char *cli_read_statistics(MYSQL *mysql) -{ - mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */ - if (!mysql->net.read_pos[0]) - { - set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate); - return mysql->net.last_error; - } - return (char*) mysql->net.read_pos; -} - - -const char * STDCALL -mysql_stat(MYSQL *mysql) -{ - DBUG_ENTER("mysql_stat"); - if (simple_command(mysql,COM_STATISTICS,0,0,0)) - DBUG_RETURN(mysql->net.last_error); - DBUG_RETURN((*mysql->methods->read_statistics)(mysql)); -} - - -int STDCALL -mysql_ping(MYSQL *mysql) -{ - int res; - DBUG_ENTER("mysql_ping"); - res= simple_command(mysql,COM_PING,0,0,0); - if (res == CR_SERVER_LOST && mysql->reconnect) - res= simple_command(mysql,COM_PING,0,0,0); - DBUG_RETURN(res); -} - - -const char * STDCALL -mysql_get_server_info(MYSQL *mysql) -{ - return((char*) mysql->server_version); -} - - -my_bool STDCALL mariadb_connection(MYSQL *mysql) -{ - return (strstr(mysql->server_version, "MariaDB") || - strstr(mysql->server_version, "-maria-")); -} - -const char * STDCALL -mysql_get_server_name(MYSQL *mysql) -{ - return mariadb_connection(mysql) ? "MariaDB" : "MySQL"; -} - - -const char * STDCALL -mysql_get_host_info(MYSQL *mysql) -{ - return(mysql->host_info); -} - - -uint STDCALL -mysql_get_proto_info(MYSQL *mysql) -{ - return (mysql->protocol_version); -} - -const char * STDCALL -mysql_get_client_info(void) -{ - return (char*) MYSQL_SERVER_VERSION; -} - -ulong STDCALL mysql_get_client_version(void) -{ - return MYSQL_VERSION_ID; -} - -my_bool STDCALL mysql_eof(MYSQL_RES *res) -{ - return res->eof; -} - -MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr) -{ - return &(res)->fields[fieldnr]; -} - -MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res) -{ - return (res)->fields; -} - -MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res) -{ - return res->data_cursor; -} - -MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res) -{ - return (res)->current_field; -} - -/* MYSQL */ - -unsigned int STDCALL mysql_field_count(MYSQL *mysql) -{ - return mysql->field_count; -} - -my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) -{ - return mysql->affected_rows; -} - -my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql) -{ - return mysql->insert_id; -} - -const char *STDCALL mysql_sqlstate(MYSQL *mysql) -{ - return mysql ? mysql->net.sqlstate : cant_connect_sqlstate; -} - -uint STDCALL mysql_warning_count(MYSQL *mysql) -{ - return mysql->warning_count; -} - -const char *STDCALL mysql_info(MYSQL *mysql) -{ - return mysql->info; -} - -ulong STDCALL mysql_thread_id(MYSQL *mysql) -{ - return (mysql)->thread_id; -} - -const char * STDCALL mysql_character_set_name(MYSQL *mysql) -{ - return mysql->charset->csname; -} - -void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo) -{ - csinfo->number = mysql->charset->number; - csinfo->state = mysql->charset->state; - csinfo->csname = mysql->charset->csname; - csinfo->name = mysql->charset->name; - csinfo->comment = mysql->charset->comment; - csinfo->mbminlen = mysql->charset->mbminlen; - csinfo->mbmaxlen = mysql->charset->mbmaxlen; - - if (mysql->options.charset_dir) - csinfo->dir = mysql->options.charset_dir; - else - csinfo->dir = charsets_dir; -} - -uint STDCALL mysql_thread_safe(void) -{ - return 1; -} - - -my_bool STDCALL mysql_embedded(void) -{ -#ifdef EMBEDDED_LIBRARY - return 1; -#else - return 0; -#endif -} - -/**************************************************************************** - Some support functions -****************************************************************************/ - -/* - Functions called my my_net_init() to set some application specific variables -*/ - -void my_net_local_init(NET *net) -{ - net->max_packet= (uint) net_buffer_length; - my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT); - my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT); - net->retry_count= 1; - net->max_packet_size= MY_MAX(net_buffer_length, max_allowed_packet); -} - -/* - This function is used to create HEX string that you - can use in a SQL statement in of the either ways: - INSERT INTO blob_column VALUES (0xAABBCC); (any MySQL version) - INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher) - - The string in "from" is encoded to a HEX string. - The result is placed in "to" and a terminating null byte is appended. - - The string pointed to by "from" must be "length" bytes long. - You must allocate the "to" buffer to be at least length*2+1 bytes long. - Each character needs two bytes, and you need room for the terminating - null byte. When mysql_hex_string() returns, the contents of "to" will - be a null-terminated string. The return value is the length of the - encoded string, not including the terminating null character. - - The return value does not contain any leading 0x or a leading X' and - trailing '. The caller must supply whichever of those is desired. -*/ - -ulong STDCALL -mysql_hex_string(char *to, const char *from, ulong length) -{ - char *to0= to; - const char *end; - - for (end= from + length; from < end; from++) - { - *to++= _dig_vec_upper[((unsigned char) *from) >> 4]; - *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F]; - } - *to= '\0'; - return (ulong) (to-to0); -} - -/* - Add escape characters to a string (blob?) to make it suitable for a insert - to should at least have place for length*2+1 chars - Returns the length of the to string -*/ - -ulong STDCALL -mysql_escape_string(char *to,const char *from,ulong length) -{ - return (uint) escape_string_for_mysql(default_charset_info, to, 0, from, length); -} - -ulong STDCALL -mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, - ulong length) -{ - if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) - return (uint) escape_quotes_for_mysql(mysql->charset, to, 0, from, length); - return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length); -} - -void STDCALL -myodbc_remove_escape(MYSQL *mysql,char *name) -{ - char *to; -#ifdef USE_MB - my_bool use_mb_flag=use_mb(mysql->charset); - char *UNINIT_VAR(end); - if (use_mb_flag) - for (end=name; *end ; end++) ; -#endif - - for (to=name ; *name ; name++) - { -#ifdef USE_MB - int l; - if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) ) - { - while (l--) - *to++ = *name++; - name--; - continue; - } -#endif - if (*name == '\\' && name[1]) - name++; - *to++= *name; - } - *to=0; -} - -/******************************************************************** - Implementation of new client API for 4.1 version. - - mysql_stmt_* are real prototypes used by applications. - - To make API work in embedded library all functions performing - real I/O are prefixed with 'cli_' (abbreviated from 'Call Level - Interface'). This functions are invoked via pointers set in - MYSQL::methods structure. Embedded counterparts, prefixed with - 'emb_' reside in libmysqld/lib_sql.cc. -*********************************************************************/ - -/******************* Declarations ***********************************/ - -/* Default number of rows fetched per one COM_STMT_FETCH command. */ - -#define DEFAULT_PREFETCH_ROWS (ulong) 1 - -/* - These functions are called by function pointer MYSQL_STMT::read_row_func. - Each function corresponds to one of the read methods: - - mysql_stmt_fetch without prior mysql_stmt_store_result, - - mysql_stmt_fetch when result is stored, - - mysql_stmt_fetch when there are no rows (always returns MYSQL_NO_DATA) -*/ - -static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row); -static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row); -static int stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row); -static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); -static int stmt_read_row_no_result_set(MYSQL_STMT *stmt, unsigned char **row); - -/* - This function is used in mysql_stmt_store_result if - STMT_ATTR_UPDATE_MAX_LENGTH attribute is set. -*/ -static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data); -static my_bool setup_one_fetch_function(MYSQL_BIND *, MYSQL_FIELD *field); - -/* Auxilary function used to reset statement handle. */ - -#define RESET_SERVER_SIDE 1 -#define RESET_LONG_DATA 2 -#define RESET_STORE_RESULT 4 -#define RESET_CLEAR_ERROR 8 -#define RESET_ALL_BUFFERS 16 - -static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); - -/* - Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME - values stored in network buffer. -*/ - -/* 1 (length) + 2 (year) + 1 (month) + 1 (day) */ -#define MAX_DATE_REP_LENGTH 5 - -/* - 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) - + 1 (minute) + 1 (seconds) + 4 (microseconds) -*/ -#define MAX_TIME_REP_LENGTH 13 - -/* - 1 (length) + 2 (year) + 1 (month) + 1 (day) + - 1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds) -*/ -#define MAX_DATETIME_REP_LENGTH 12 - -#define MAX_DOUBLE_STRING_REP_LENGTH 331 - -/* A macro to check truncation errors */ - -#define IS_TRUNCATED(value, is_unsigned, min, max, umax) \ - ((is_unsigned) ? (((value) > (umax) || (value) < 0) ? 1 : 0) : \ - (((value) > (max) || (value) < (min)) ? 1 : 0)) - -#define BIND_RESULT_DONE 1 -/* - We report truncations only if at least one of MYSQL_BIND::error - pointers is set. In this case stmt->bind_result_done |-ed with - this flag. -*/ -#define REPORT_DATA_TRUNCATION 2 - -/**************** Misc utility functions ****************************/ - -/* - Reallocate the NET package to have at least length bytes available. - - SYNPOSIS - my_realloc_str() - net The NET structure to modify. - length Ensure that net->buff has space for at least - this number of bytes. - - RETURN VALUES - 0 Success. - 1 Error, i.e. out of memory or requested packet size is bigger - than max_allowed_packet. The error code is stored in net->last_errno. -*/ - -static my_bool my_realloc_str(NET *net, ulong length) -{ - ulong buf_length= (ulong) (net->write_pos - net->buff); - my_bool res=0; - DBUG_ENTER("my_realloc_str"); - if (buf_length + length > net->max_packet) - { - res= net_realloc(net, buf_length + length); - if (res) - { - if (net->last_errno == ER_OUT_OF_RESOURCES) - net->last_errno= CR_OUT_OF_MEMORY; - else if (net->last_errno == ER_NET_PACKET_TOO_LARGE) - net->last_errno= CR_NET_PACKET_TOO_LARGE; - strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error, ER(net->last_errno)); - } - net->write_pos= net->buff+ buf_length; - } - DBUG_RETURN(res); -} - - -static void stmt_clear_error(MYSQL_STMT *stmt) -{ - if (stmt->last_errno) - { - stmt->last_errno= 0; - stmt->last_error[0]= '\0'; - strmov(stmt->sqlstate, not_error_sqlstate); - } -} - -/** - Set statement error code, sqlstate, and error message - from given errcode and sqlstate. -*/ - -void set_stmt_error(MYSQL_STMT * stmt, int errcode, - const char *sqlstate, const char *err) -{ - DBUG_ENTER("set_stmt_error"); - DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode))); - DBUG_ASSERT(stmt != 0); - - if (err == 0) - err= ER(errcode); - - stmt->last_errno= errcode; - strmov(stmt->last_error, ER(errcode)); - strmov(stmt->sqlstate, sqlstate); - - DBUG_VOID_RETURN; -} - - -/** - Set statement error code, sqlstate, and error message from NET. - - @param stmt a statement handle. Copy the error here. - @param net mysql->net. Source of the error. -*/ - -void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net) -{ - DBUG_ENTER("set_stmt_errmsg"); - DBUG_PRINT("enter", ("error: %d/%s '%s'", - net->last_errno, - net->sqlstate, - net->last_error)); - DBUG_ASSERT(stmt != 0); - - stmt->last_errno= net->last_errno; - if (net->last_error && net->last_error[0]) - strmov(stmt->last_error, net->last_error); - strmov(stmt->sqlstate, net->sqlstate); - - DBUG_VOID_RETURN; -} - -/* - Read and unpack server reply to COM_STMT_PREPARE command (sent from - mysql_stmt_prepare). - - SYNOPSIS - cli_read_prepare_result() - mysql connection handle - stmt statement handle - - RETURN VALUES - 0 ok - 1 error -*/ - -my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) -{ - uchar *pos; - uint field_count, param_count; - ulong packet_length; - MYSQL_DATA *fields_data; - DBUG_ENTER("cli_read_prepare_result"); - - if ((packet_length= cli_safe_read(mysql)) == packet_error) - DBUG_RETURN(1); - mysql->warning_count= 0; - - pos= (uchar*) mysql->net.read_pos; - stmt->stmt_id= uint4korr(pos+1); pos+= 5; - /* Number of columns in result set */ - field_count= uint2korr(pos); pos+= 2; - /* Number of placeholders in the statement */ - param_count= uint2korr(pos); pos+= 2; - if (packet_length >= 12) - mysql->warning_count= uint2korr(pos+1); - - if (param_count != 0) - { - MYSQL_DATA *param_data; - - /* skip parameters data: we don't support it yet */ - if (!(param_data= (*mysql->methods->read_rows)(mysql, (MYSQL_FIELD*)0, 7))) - DBUG_RETURN(1); - free_rows(param_data); - } - - if (field_count != 0) - { - if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) - mysql->server_status|= SERVER_STATUS_IN_TRANS; - - if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7))) - DBUG_RETURN(1); - if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root, - field_count,0, - mysql->server_capabilities))) - DBUG_RETURN(1); - } - stmt->field_count= field_count; - stmt->param_count= (ulong) param_count; - DBUG_PRINT("exit",("field_count: %u param_count: %u warning_count: %u", - field_count, param_count, (uint) mysql->warning_count)); - - DBUG_RETURN(0); -} - - -/* - Allocate memory and init prepared statement structure. - - SYNOPSIS - mysql_stmt_init() - mysql connection handle - - DESCRIPTION - This is an entry point of the new API. Returned handle stands for - a server-side prepared statement. Memory for this structure (~700 - bytes) is allocated using 'malloc'. Once created, the handle can be - reused many times. Created statement handle is bound to connection - handle provided to this call: its lifetime is limited by lifetime - of connection. - 'mysql_stmt_init()' is a pure local call, server side structure is - created only in mysql_stmt_prepare. - Next steps you may want to make: - - set a statement attribute (mysql_stmt_attr_set()), - - prepare statement handle with a query (mysql_stmt_prepare()), - - close statement handle and free its memory (mysql_stmt_close()), - - reset statement with mysql_stmt_reset() (a no-op which will - just return). - Behaviour of the rest of API calls on this statement is not defined yet - (though we're working on making each wrong call sequence return - error). - - RETURN VALUE - statement structure upon success and NULL if out of - memory -*/ - -#ifdef EMBEDDED_LIBRARY -#undef MY_THREAD_SPECIFIC -#define MY_THREAD_SPECIFIC 0 -#endif /*EMBEDDED_LIBRARY*/ - -MYSQL_STMT * STDCALL -mysql_stmt_init(MYSQL *mysql) -{ - MYSQL_STMT *stmt; - DBUG_ENTER("mysql_stmt_init"); - - if (!(stmt= - (MYSQL_STMT *) my_malloc(sizeof (MYSQL_STMT), - MYF(MY_WME | MY_ZEROFILL))) || - !(stmt->extension= - (MYSQL_STMT_EXT *) my_malloc(sizeof (MYSQL_STMT_EXT), - MYF(MY_WME | MY_ZEROFILL)))) - { - set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - my_free(stmt); - DBUG_RETURN(NULL); - } - - init_alloc_root(&stmt->mem_root, 2048,2048, MYF(MY_THREAD_SPECIFIC)); - init_alloc_root(&stmt->result.alloc, 4096, 4096, MYF(MY_THREAD_SPECIFIC)); - stmt->result.alloc.min_malloc= sizeof(MYSQL_ROWS); - mysql->stmts= list_add(mysql->stmts, &stmt->list); - stmt->list.data= stmt; - stmt->state= MYSQL_STMT_INIT_DONE; - stmt->mysql= mysql; - stmt->read_row_func= stmt_read_row_no_result_set; - stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS; - strmov(stmt->sqlstate, not_error_sqlstate); - /* The rest of statement members was bzeroed inside malloc */ - - init_alloc_root(&stmt->extension->fields_mem_root, 2048, 0, - MYF(MY_THREAD_SPECIFIC)); - - DBUG_RETURN(stmt); -} - - -/* - Prepare server side statement with query. - - SYNOPSIS - mysql_stmt_prepare() - stmt statement handle - query statement to prepare - length statement length - - DESCRIPTION - Associate statement with statement handle. This is done both on - client and server sides. At this point the server parses given query - and creates an internal structure to represent it. - Next steps you may want to make: - - find out if this statement returns a result set by - calling mysql_stmt_field_count(), and get result set metadata - with mysql_stmt_result_metadata(), - - if query contains placeholders, bind input parameters to placeholders - using mysql_stmt_bind_param(), - - otherwise proceed directly to mysql_stmt_execute(). - - IMPLEMENTATION NOTES - - if this is a re-prepare of the statement, first close previous data - structure on the server and free old statement data - - then send the query to server and get back number of placeholders, - number of columns in result set (if any), and result set metadata. - At the same time allocate memory for input and output parameters - to have less checks in mysql_stmt_bind_{param, result}. - - RETURN VALUES - 0 success - !0 error -*/ - -int STDCALL -mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) -{ - MYSQL *mysql= stmt->mysql; - DBUG_ENTER("mysql_stmt_prepare"); - - if (!mysql) - { - /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - /* - Reset the last error in any case: that would clear the statement - if the previous prepare failed. - */ - stmt->last_errno= 0; - stmt->last_error[0]= '\0'; - - if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) - { - /* This is second prepare with another statement */ - uchar buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - - if (reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT)) - DBUG_RETURN(1); - /* - These members must be reset for API to - function in case of error or misuse. - */ - stmt->bind_param_done= stmt->bind_result_done= FALSE; - stmt->param_count= stmt->field_count= 0; - free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC)); - free_root(&stmt->extension->fields_mem_root, MYF(0)); - - int4store(buff, stmt->stmt_id); - - /* - Close statement in server - - If there was a 'use' result from another statement, or from - mysql_use_result it won't be freed in mysql_stmt_free_result and - we should get 'Commands out of sync' here. - */ - stmt->state= MYSQL_STMT_INIT_DONE; - if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)) - { - set_stmt_errmsg(stmt, &mysql->net); - DBUG_RETURN(1); - } - } - - if (stmt_command(mysql, COM_STMT_PREPARE, (const uchar*) query, length, stmt)) - { - set_stmt_errmsg(stmt, &mysql->net); - DBUG_RETURN(1); - } - - if ((*mysql->methods->read_prepare_result)(mysql, stmt)) - { - set_stmt_errmsg(stmt, &mysql->net); - DBUG_RETURN(1); - } - - /* - alloc_root will return valid address even in case when param_count - and field_count are zero. Thus we should never rely on stmt->bind - or stmt->params when checking for existence of placeholders or - result set. - */ - if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root, - sizeof(MYSQL_BIND)* - (stmt->param_count + - stmt->field_count)))) - { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - stmt->bind= stmt->params + stmt->param_count; - stmt->state= MYSQL_STMT_PREPARE_DONE; - DBUG_PRINT("info", ("Parameter count: %u", stmt->param_count)); - DBUG_RETURN(0); -} - -/* - Get result set metadata from reply to mysql_stmt_execute. - This is used mainly for SHOW commands, as metadata for these - commands is sent only with result set. - To be removed when all commands will fully support prepared mode. -*/ - -static void alloc_stmt_fields(MYSQL_STMT *stmt) -{ - MYSQL_FIELD *fields, *field, *end; - MEM_ROOT *fields_mem_root= &stmt->extension->fields_mem_root; - MYSQL *mysql= stmt->mysql; - - DBUG_ASSERT(stmt->field_count); - - free_root(fields_mem_root, MYF(0)); - - /* - Get the field information for non-select statements - like SHOW and DESCRIBE commands - */ - if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(fields_mem_root, - sizeof(MYSQL_FIELD) * - stmt->field_count)) || - !(stmt->bind= (MYSQL_BIND *) alloc_root(fields_mem_root, - sizeof(MYSQL_BIND) * - stmt->field_count))) - { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); - return; - } - - for (fields= mysql->fields, end= fields+stmt->field_count, - field= stmt->fields; - field && fields < end; fields++, field++) - { - *field= *fields; /* To copy all numeric parts. */ - field->catalog= strmake_root(fields_mem_root, - fields->catalog, - fields->catalog_length); - field->db= strmake_root(fields_mem_root, - fields->db, - fields->db_length); - field->table= strmake_root(fields_mem_root, - fields->table, - fields->table_length); - field->org_table= strmake_root(fields_mem_root, - fields->org_table, - fields->org_table_length); - field->name= strmake_root(fields_mem_root, - fields->name, - fields->name_length); - field->org_name= strmake_root(fields_mem_root, - fields->org_name, - fields->org_name_length); - if (fields->def) - { - field->def= strmake_root(fields_mem_root, - fields->def, - fields->def_length); - field->def_length= fields->def_length; - } - else - { - field->def= NULL; - field->def_length= 0; - } - field->extension= 0; /* Avoid dangling links. */ - field->max_length= 0; /* max_length is set in mysql_stmt_store_result() */ - } -} - - -/** - Update result set columns metadata if it was sent again in - reply to COM_STMT_EXECUTE. - - @note If the new field count is different from the original one, - an error is set and no update is performed. -*/ - -static void update_stmt_fields(MYSQL_STMT *stmt) -{ - MYSQL_FIELD *field= stmt->mysql->fields; - MYSQL_FIELD *field_end= field + stmt->field_count; - MYSQL_FIELD *stmt_field= stmt->fields; - MYSQL_BIND *my_bind= stmt->bind_result_done ? stmt->bind : 0; - - if (stmt->field_count != stmt->mysql->field_count) - { - /* - The tables used in the statement were altered, - and the query now returns a different number of columns. - There is no way to continue without reallocating the bind - array: - - if the number of columns increased, mysql_stmt_fetch() - will write beyond allocated memory - - if the number of columns decreased, some user-bound - buffers will be left unassigned without user knowing - that. - */ - set_stmt_error(stmt, CR_NEW_STMT_METADATA, unknown_sqlstate, NULL); - return; - } - - for (; field < field_end; ++field, ++stmt_field) - { - stmt_field->charsetnr= field->charsetnr; - stmt_field->length = field->length; - stmt_field->type = field->type; - stmt_field->flags = field->flags; - stmt_field->decimals = field->decimals; - if (my_bind) - { - /* Ignore return value: it should be 0 if bind_result succeeded. */ - (void) setup_one_fetch_function(my_bind++, stmt_field); - } - } -} - -/* - Returns prepared statement metadata in the form of a result set. - - SYNOPSIS - mysql_stmt_result_metadata() - stmt statement handle - - DESCRIPTION - This function should be used after mysql_stmt_execute(). - You can safely check that prepared statement has a result set by calling - mysql_stmt_field_count(): if number of fields is not zero, you can call - this function to get fields metadata. - Next steps you may want to make: - - find out number of columns in result set by calling - mysql_num_fields(res) (the same value is returned by - mysql_stmt_field_count()) - - fetch metadata for any column with mysql_fetch_field, - mysql_fetch_field_direct, mysql_fetch_fields, mysql_field_seek. - - free returned MYSQL_RES structure with mysql_free_result. - - proceed to binding of output parameters. - - RETURN - NULL statement contains no result set or out of memory. - In the latter case you can retreive error message - with mysql_stmt_error. - MYSQL_RES a result set with no rows -*/ - -MYSQL_RES * STDCALL -mysql_stmt_result_metadata(MYSQL_STMT *stmt) -{ - MYSQL_RES *result; - DBUG_ENTER("mysql_stmt_result_metadata"); - - /* - stmt->fields is only defined if stmt->field_count is not null; - stmt->field_count is initialized in prepare. - */ - if (!stmt->field_count) - DBUG_RETURN(0); - - if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result), - MYF(MY_WME | MY_ZEROFILL)))) - { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); - DBUG_RETURN(0); - } - - result->methods= stmt->mysql->methods; - result->eof= 1; /* Marker for buffered */ - result->fields= stmt->fields; - result->field_count= stmt->field_count; - /* The rest of members of 'result' was bzeroed inside malloc */ - DBUG_RETURN(result); -} - - -/* - Returns parameter columns meta information in the form of - result set. - - SYNOPSYS - mysql_stmt_param_metadata() - stmt statement handle - - DESCRIPTION - This function can be called after you prepared the statement handle - with mysql_stmt_prepare(). - XXX: not implemented yet. - - RETURN - MYSQL_RES on success, 0 if there is no metadata. - Currently this function always returns 0. -*/ - -MYSQL_RES * STDCALL -mysql_stmt_param_metadata(MYSQL_STMT *stmt) -{ - DBUG_ENTER("mysql_stmt_param_metadata"); - - if (!stmt->param_count) - DBUG_RETURN(0); - - /* - TODO: Fix this when server sends the information. - Till then keep a dummy prototype. - */ - DBUG_RETURN(0); -} - - -/* Store type of parameter in network buffer. */ - -static void store_param_type(unsigned char **pos, MYSQL_BIND *param) -{ - uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0); - int2store(*pos, typecode); - *pos+= 2; -} - - -/* - Functions to store parameter data in network packet. - - SYNOPSIS - store_param_xxx() - net MySQL NET connection - param MySQL bind param - - DESCRIPTION - These funtions are invoked from mysql_stmt_execute() by - MYSQL_BIND::store_param_func pointer. This pointer is set once per - many executions in mysql_stmt_bind_param(). The caller must ensure - that network buffer have enough capacity to store parameter - (MYSQL_BIND::buffer_length contains needed number of bytes). -*/ - -static void store_param_tinyint(NET *net, MYSQL_BIND *param) -{ - *(net->write_pos++)= *(uchar *) param->buffer; -} - -static void store_param_short(NET *net, MYSQL_BIND *param) -{ - short value= *(short*) param->buffer; - int2store(net->write_pos,value); - net->write_pos+=2; -} - -static void store_param_int32(NET *net, MYSQL_BIND *param) -{ - int32 value= *(int32*) param->buffer; - int4store(net->write_pos,value); - net->write_pos+=4; -} - -static void store_param_int64(NET *net, MYSQL_BIND *param) -{ - longlong value= *(longlong*) param->buffer; - int8store(net->write_pos,value); - net->write_pos+= 8; -} - -static void store_param_float(NET *net, MYSQL_BIND *param) -{ - float value= *(float*) param->buffer; - float4store(net->write_pos, value); - net->write_pos+= 4; -} - -static void store_param_double(NET *net, MYSQL_BIND *param) -{ - double value= *(double*) param->buffer; - float8store(net->write_pos, value); - net->write_pos+= 8; -} - -static void store_param_time(NET *net, MYSQL_BIND *param) -{ - MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; - char buff[MAX_TIME_REP_LENGTH], *pos; - uint length; - - pos= buff+1; - pos[0]= tm->neg ? 1: 0; - int4store(pos+1, tm->day); - pos[5]= (uchar) tm->hour; - pos[6]= (uchar) tm->minute; - pos[7]= (uchar) tm->second; - int4store(pos+8, tm->second_part); - if (tm->second_part) - length= 12; - else if (tm->hour || tm->minute || tm->second || tm->day) - length= 8; - else - length= 0; - buff[0]= (char) length++; - memcpy((char *)net->write_pos, buff, length); - net->write_pos+= length; -} - -static void net_store_datetime(NET *net, MYSQL_TIME *tm) -{ - char buff[MAX_DATETIME_REP_LENGTH], *pos; - uint length; - - pos= buff+1; - - int2store(pos, tm->year); - pos[2]= (uchar) tm->month; - pos[3]= (uchar) tm->day; - pos[4]= (uchar) tm->hour; - pos[5]= (uchar) tm->minute; - pos[6]= (uchar) tm->second; - int4store(pos+7, tm->second_part); - if (tm->second_part) - length= 11; - else if (tm->hour || tm->minute || tm->second) - length= 7; - else if (tm->year || tm->month || tm->day) - length= 4; - else - length= 0; - buff[0]= (char) length++; - memcpy((char *)net->write_pos, buff, length); - net->write_pos+= length; -} - -static void store_param_date(NET *net, MYSQL_BIND *param) -{ - MYSQL_TIME tm= *((MYSQL_TIME *) param->buffer); - tm.hour= tm.minute= tm.second= tm.second_part= 0; - net_store_datetime(net, &tm); -} - -static void store_param_datetime(NET *net, MYSQL_BIND *param) -{ - MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; - net_store_datetime(net, tm); -} - -static void store_param_str(NET *net, MYSQL_BIND *param) -{ - /* param->length is always set in mysql_stmt_bind_param */ - ulong length= *param->length; - uchar *to= net_store_length(net->write_pos, length); - memcpy(to, param->buffer, length); - net->write_pos= to+length; -} - - -/* - Mark if the parameter is NULL. - - SYNOPSIS - store_param_null() - net MySQL NET connection - param MySQL bind param - - DESCRIPTION - A data package starts with a string of bits where we set a bit - if a parameter is NULL. Unlike bit string in result set row, here - we don't have reserved bits for OK/error packet. -*/ - -static void store_param_null(NET *net, MYSQL_BIND *param) -{ - uint pos= param->param_number; - net->buff[pos/8]|= (uchar) (1 << (pos & 7)); -} - - -/* - Store one parameter in network packet: data is read from - client buffer and saved in network packet by means of one - of store_param_xxxx functions. -*/ - -static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) -{ - NET *net= &stmt->mysql->net; - DBUG_ENTER("store_param"); - DBUG_PRINT("enter",("type: %d buffer: 0x%lx length: %lu is_null: %d", - param->buffer_type, - (long) (param->buffer ? param->buffer : NullS), - *param->length, *param->is_null)); - - if (*param->is_null) - store_param_null(net, param); - else - { - /* - Param->length should ALWAYS point to the correct length for the type - Either to the length pointer given by the user or param->buffer_length - */ - if ((my_realloc_str(net, *param->length))) - { - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - (*param->store_param_func)(net, param); - } - DBUG_RETURN(0); -} - - -/* - Auxilary function to send COM_STMT_EXECUTE packet to server and read reply. - Used from cli_stmt_execute, which is in turn used by mysql_stmt_execute. -*/ - -static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) -{ - MYSQL *mysql= stmt->mysql; - NET *net= &mysql->net; - uchar buff[4 /* size of stmt id */ + - 5 /* execution flags */]; - my_bool res; - DBUG_ENTER("execute"); - DBUG_DUMP("packet", (uchar *) packet, length); - - int4store(buff, stmt->stmt_id); /* Send stmt id to server */ - buff[4]= (char) stmt->flags; - int4store(buff+5, 1); /* iteration count */ - - res= MY_TEST(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff), - (uchar*) packet, length, 1, stmt) || - (*mysql->methods->read_query_result)(mysql)); - stmt->affected_rows= mysql->affected_rows; - stmt->server_status= mysql->server_status; - stmt->insert_id= mysql->insert_id; - if (res) - { - /* - Don't set stmt error if stmt->mysql is NULL, as the error in this case - has already been set by mysql_prune_stmt_list(). - */ - if (stmt->mysql) - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - else if (mysql->status == MYSQL_STATUS_GET_RESULT) - stmt->mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT; - DBUG_RETURN(0); -} - - -int cli_stmt_execute(MYSQL_STMT *stmt) -{ - DBUG_ENTER("cli_stmt_execute"); - - if (stmt->param_count) - { - MYSQL *mysql= stmt->mysql; - NET *net= &mysql->net; - MYSQL_BIND *param, *param_end; - char *param_data; - ulong length; - uint null_count; - my_bool result; - - if (!stmt->bind_param_done) - { - set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - if (mysql->status != MYSQL_STATUS_READY || - mysql->server_status & SERVER_MORE_RESULTS_EXISTS) - { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - if (net->vio) - net_clear(net, 1); /* Sets net->write_pos */ - else - { - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - - /* Reserve place for null-marker bytes */ - null_count= (stmt->param_count+7) /8; - if (my_realloc_str(net, null_count + 1)) - { - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - bzero((char*) net->write_pos, null_count); - net->write_pos+= null_count; - param_end= stmt->params + stmt->param_count; - - /* In case if buffers (type) altered, indicate to server */ - *(net->write_pos)++= (uchar) stmt->send_types_to_server; - if (stmt->send_types_to_server) - { - if (my_realloc_str(net, 2 * stmt->param_count)) - { - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - /* - Store types of parameters in first in first package - that is sent to the server. - */ - for (param= stmt->params; param < param_end ; param++) - store_param_type(&net->write_pos, param); - } - - for (param= stmt->params; param < param_end; param++) - { - /* check if mysql_stmt_send_long_data() was used */ - if (param->long_data_used) - param->long_data_used= 0; /* Clear for next execute call */ - else if (store_param(stmt, param)) - DBUG_RETURN(1); - } - length= (ulong) (net->write_pos - net->buff); - /* TODO: Look into avoding the following memdup */ - if (!(param_data= my_memdup(net->buff, length, MYF(0)))) - { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - result= execute(stmt, param_data, length); - stmt->send_types_to_server=0; - my_free(param_data); - DBUG_RETURN(result); - } - DBUG_RETURN((int) execute(stmt,0,0)); -} - -/* - Read one row from buffered result set. Result set is created by prior - call to mysql_stmt_store_result(). - SYNOPSIS - stmt_read_row_buffered() - - RETURN VALUE - 0 - success; *row is set to valid row pointer (row data - is stored in result set buffer) - MYSQL_NO_DATA - end of result set. *row is set to NULL -*/ - -static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row) -{ - if (stmt->data_cursor) - { - *row= (uchar *) stmt->data_cursor->data; - stmt->data_cursor= stmt->data_cursor->next; - return 0; - } - *row= 0; - return MYSQL_NO_DATA; -} - -/* - Read one row from network: unbuffered non-cursor fetch. - If last row was read, or error occurred, erase this statement - from record pointing to object unbuffered fetch is performed from. - - SYNOPSIS - stmt_read_row_unbuffered() - stmt statement handle - row pointer to write pointer to row data; - - RETURN VALUE - 0 - success; *row contains valid address of a row; - row data is stored in network buffer - 1 - error; error code is written to - stmt->last_{errno,error}; *row is not changed - MYSQL_NO_DATA - end of file was read from network; - *row is set to NULL -*/ - -static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row) -{ - int rc= 1; - MYSQL *mysql= stmt->mysql; - /* - This function won't be called if stmt->field_count is zero - or execution wasn't done: this is ensured by mysql_stmt_execute. - */ - if (!mysql) - { - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); - return 1; - } - if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT) - { - set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ? - CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC, - unknown_sqlstate, NULL); - goto error; - } - if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row)) - { - set_stmt_errmsg(stmt, &mysql->net); - /* - If there was an error, there are no more pending rows: - reset statement status to not hang up in following - mysql_stmt_close (it will try to flush result set before - closing the statement). - */ - mysql->status= MYSQL_STATUS_READY; - goto error; - } - if (!*row) - { - mysql->status= MYSQL_STATUS_READY; - rc= MYSQL_NO_DATA; - goto error; - } - return 0; -error: - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - return rc; -} - - -/* - Fetch statement row using server side cursor. - - SYNOPSIS - stmt_read_row_from_cursor() - - RETURN VALUE - 0 success - 1 error - MYSQL_NO_DATA end of data -*/ - -static int -stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) -{ - if (stmt->data_cursor) - return stmt_read_row_buffered(stmt, row); - if (stmt->server_status & SERVER_STATUS_LAST_ROW_SENT) - stmt->server_status &= ~SERVER_STATUS_LAST_ROW_SENT; - else - { - MYSQL *mysql= stmt->mysql; - NET *net= &mysql->net; - MYSQL_DATA *result= &stmt->result; - uchar buff[4 /* statement id */ + - 4 /* number of rows to fetch */]; - - free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); - result->data= NULL; - result->rows= 0; - /* Send row request to the server */ - int4store(buff, stmt->stmt_id); - int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ - if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH, - buff, sizeof(buff), (uchar*) 0, 0, - 1, stmt)) - { - /* - Don't set stmt error if stmt->mysql is NULL, as the error in this case - has already been set by mysql_prune_stmt_list(). - */ - if (stmt->mysql) - set_stmt_errmsg(stmt, net); - return 1; - } - if ((*mysql->methods->read_rows_from_cursor)(stmt)) - return 1; - stmt->server_status= mysql->server_status; - - stmt->data_cursor= result->data; - return stmt_read_row_buffered(stmt, row); - } - *row= 0; - return MYSQL_NO_DATA; -} - - -/* - Default read row function to not SIGSEGV in client in - case of wrong sequence of API calls. -*/ - -static int -stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)), - unsigned char **row __attribute__((unused))) -{ - return MYSQL_NO_DATA; -} - -static int -stmt_read_row_no_result_set(MYSQL_STMT *stmt __attribute__((unused)), - unsigned char **row __attribute__((unused))) -{ - set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate, NULL); - return 1; -} - - -/* - Get/set statement attributes - - SYNOPSIS - mysql_stmt_attr_get() - mysql_stmt_attr_set() - - attr_type statement attribute - value casted to const void * pointer to value. - - RETURN VALUE - 0 success - !0 wrong attribute type -*/ - -my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, - enum enum_stmt_attr_type attr_type, - const void *value) -{ - switch (attr_type) { - case STMT_ATTR_UPDATE_MAX_LENGTH: - stmt->update_max_length= value ? *(const my_bool*) value : 0; - break; - case STMT_ATTR_CURSOR_TYPE: - { - ulong cursor_type; - cursor_type= value ? *(ulong*) value : 0UL; - if (cursor_type > (ulong) CURSOR_TYPE_READ_ONLY) - goto err_not_implemented; - stmt->flags= cursor_type; - break; - } - case STMT_ATTR_PREFETCH_ROWS: - { - ulong prefetch_rows= value ? *(ulong*) value : DEFAULT_PREFETCH_ROWS; - if (value == 0) - return TRUE; - stmt->prefetch_rows= prefetch_rows; - break; - } - default: - goto err_not_implemented; - } - return FALSE; -err_not_implemented: - set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate, NULL); - return TRUE; -} - - -my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, - enum enum_stmt_attr_type attr_type, - void *value) -{ - switch (attr_type) { - case STMT_ATTR_UPDATE_MAX_LENGTH: - *(my_bool*) value= stmt->update_max_length; - break; - case STMT_ATTR_CURSOR_TYPE: - *(ulong*) value= stmt->flags; - break; - case STMT_ATTR_PREFETCH_ROWS: - *(ulong*) value= stmt->prefetch_rows; - break; - default: - return TRUE; - } - return FALSE; -} - - -/** - Update statement result set metadata from with the new field - information sent during statement execute. - - @pre mysql->field_count is not zero - - @retval TRUE if error: out of memory or the new - result set has a different number of columns - @retval FALSE success -*/ - -static void reinit_result_set_metadata(MYSQL_STMT *stmt) -{ - /* Server has sent result set metadata */ - if (stmt->field_count == 0) - { - /* - This is 'SHOW'/'EXPLAIN'-like query. Current implementation of - prepared statements can't send result set metadata for these queries - on prepare stage. Read it now. - */ - - stmt->field_count= stmt->mysql->field_count; - - alloc_stmt_fields(stmt); - } - else - { - /* - Update result set metadata if it for some reason changed between - prepare and execute, i.e.: - - in case of 'SELECT ?' we don't know column type unless data was - supplied to mysql_stmt_execute, so updated column type is sent - now. - - if data dictionary changed between prepare and execute, for - example a table used in the query was altered. - Note, that now (4.1.3) we always send metadata in reply to - COM_STMT_EXECUTE (even if it is not necessary), so either this or - previous branch always works. - TODO: send metadata only when it's really necessary and add a warning - 'Metadata changed' when it's sent twice. - */ - update_stmt_fields(stmt); - } -} - - -static void prepare_to_fetch_result(MYSQL_STMT *stmt) -{ - if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS) - { - stmt->mysql->status= MYSQL_STATUS_READY; - stmt->read_row_func= stmt_read_row_from_cursor; - } - else if (stmt->flags & CURSOR_TYPE_READ_ONLY) - { - /* - This is a single-row result set, a result set with no rows, EXPLAIN, - SHOW VARIABLES, or some other command which either a) bypasses the - cursors framework in the server and writes rows directly to the - network or b) is more efficient if all (few) result set rows are - precached on client and server's resources are freed. - */ - mysql_stmt_store_result(stmt); - } - else - { - stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled; - stmt->unbuffered_fetch_cancelled= FALSE; - stmt->read_row_func= stmt_read_row_unbuffered; - } -} - - -/* - Send placeholders data to server (if there are placeholders) - and execute prepared statement. - - SYNOPSIS - mysql_stmt_execute() - stmt statement handle. The handle must be created - with mysql_stmt_init() and prepared with - mysql_stmt_prepare(). If there are placeholders - in the statement they must be bound to local - variables with mysql_stmt_bind_param(). - - DESCRIPTION - This function will automatically flush pending result - set (if there is one), send parameters data to the server - and read result of statement execution. - If previous result set was cached with mysql_stmt_store_result() - it will also be freed in the beginning of this call. - The server can return 3 types of responses to this command: - - error, can be retrieved with mysql_stmt_error() - - ok, no result set pending. In this case we just update - stmt->insert_id and stmt->affected_rows. - - the query returns a result set: there could be 0 .. N - rows in it. In this case the server can also send updated - result set metadata. - - Next steps you may want to make: - - find out if there is result set with mysql_stmt_field_count(). - If there is one: - - optionally, cache entire result set on client to unblock - connection with mysql_stmt_store_result() - - bind client variables to result set columns and start read rows - with mysql_stmt_fetch(). - - reset statement with mysql_stmt_reset() or close it with - mysql_stmt_close() - Otherwise: - - find out last insert id and number of affected rows with - mysql_stmt_insert_id(), mysql_stmt_affected_rows() - - RETURN - 0 success - 1 error, message can be retrieved with mysql_stmt_error(). -*/ - -int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) -{ - MYSQL *mysql= stmt->mysql; - DBUG_ENTER("mysql_stmt_execute"); - - if (!mysql) - { - /* Error is already set in mysql_detatch_stmt_list */ - DBUG_RETURN(1); - } - - if (reset_stmt_handle(stmt, RESET_STORE_RESULT | RESET_CLEAR_ERROR)) - DBUG_RETURN(1); - /* - No need to check for stmt->state: if the statement wasn't - prepared we'll get 'unknown statement handler' error from server. - */ - if (mysql->methods->stmt_execute(stmt)) - DBUG_RETURN(1); - stmt->state= MYSQL_STMT_EXECUTE_DONE; - if (mysql->field_count) - { - reinit_result_set_metadata(stmt); - prepare_to_fetch_result(stmt); - } - DBUG_RETURN(MY_TEST(stmt->last_errno)); -} - - -/* - Return total parameters count in the statement -*/ - -ulong STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt) -{ - DBUG_ENTER("mysql_stmt_param_count"); - DBUG_RETURN(stmt->param_count); -} - -/* - Return total affected rows from the last statement -*/ - -my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt) -{ - return stmt->affected_rows; -} - - -/* - Returns the number of result columns for the most recent query - run on this statement. -*/ - -unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt) -{ - return stmt->field_count; -} - -/* - Return last inserted id for auto_increment columns. - - SYNOPSIS - mysql_stmt_insert_id() - stmt statement handle - - DESCRIPTION - Current implementation of this call has a caveat: stmt->insert_id is - unconditionally updated from mysql->insert_id in the end of each - mysql_stmt_execute(). This works OK if mysql->insert_id contains new - value (sent in reply to mysql_stmt_execute()), otherwise stmt->insert_id - value gets undefined, as it's updated from some arbitrary value saved in - connection structure during some other call. -*/ - -my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt) -{ - return stmt->insert_id; -} - - -static my_bool int_is_null_true= 1; /* Used for MYSQL_TYPE_NULL */ -static my_bool int_is_null_false= 0; - - -/* - Set up input data buffers for a statement. - - SYNOPSIS - mysql_stmt_bind_param() - stmt statement handle - The statement must be prepared with mysql_stmt_prepare(). - my_bind Array of mysql_stmt_param_count() bind parameters. - This function doesn't check that size of this argument - is >= mysql_stmt_field_count(): it's user's responsibility. - - DESCRIPTION - Use this call after mysql_stmt_prepare() to bind user variables to - placeholders. - Each element of bind array stands for a placeholder. Placeholders - are counted from 0. For example statement - 'INSERT INTO t (a, b) VALUES (?, ?)' - contains two placeholders, and for such statement you should supply - bind array of two elements (MYSQL_BIND bind[2]). - - By properly initializing bind array you can bind virtually any - C language type to statement's placeholders: - First, it's strongly recommended to always zero-initialize entire - bind structure before setting its members. This will both shorten - your application code and make it robust to future extensions of - MYSQL_BIND structure. - Then you need to assign typecode of your application buffer to - MYSQL_BIND::buffer_type. The following typecodes with their - correspondence to C language types are supported: - MYSQL_TYPE_TINY for 8-bit integer variables. Normally it's - 'signed char' and 'unsigned char'; - MYSQL_TYPE_SHORT for 16-bit signed and unsigned variables. This - is usually 'short' and 'unsigned short'; - MYSQL_TYPE_LONG for 32-bit signed and unsigned variables. It - corresponds to 'int' and 'unsigned int' on - vast majority of platforms. On IA-32 and some - other 32-bit systems you can also use 'long' - here; - MYSQL_TYPE_LONGLONG 64-bit signed or unsigned integer. Stands for - '[unsigned] long long' on most platforms; - MYSQL_TYPE_FLOAT 32-bit floating point type, 'float' on most - systems; - MYSQL_TYPE_DOUBLE 64-bit floating point type, 'double' on most - systems; - MYSQL_TYPE_TIME broken-down time stored in MYSQL_TIME - structure - MYSQL_TYPE_DATE date stored in MYSQL_TIME structure - MYSQL_TYPE_DATETIME datetime stored in MYSQL_TIME structure See - more on how to use these types for sending - dates and times below; - MYSQL_TYPE_STRING character string, assumed to be in - character-set-client. If character set of - client is not equal to character set of - column, value for this placeholder will be - converted to destination character set before - insert. - MYSQL_TYPE_BLOB sequence of bytes. This sequence is assumed to - be in binary character set (which is the same - as no particular character set), and is never - converted to any other character set. See also - notes about supplying string/blob length - below. - MYSQL_TYPE_NULL special typecode for binding nulls. - These C/C++ types are not supported yet by the API: long double, - bool. - - As you can see from the list above, it's responsibility of - application programmer to ensure that chosen typecode properly - corresponds to host language type. For example on all platforms - where we build MySQL packages (as of MySQL 4.1.4) int is a 32-bit - type. So for int you can always assume that proper typecode is - MYSQL_TYPE_LONG (however queer it sounds, the name is legacy of the - old MySQL API). In contrary sizeof(long) can be 4 or 8 8-bit bytes, - depending on platform. - - TODO: provide client typedefs for each integer and floating point - typecode, i. e. int8, uint8, float32, etc. - - Once typecode was set, it's necessary to assign MYSQL_BIND::buffer - to point to the buffer of given type. Finally, additional actions - may be taken for some types or use cases: - - Binding integer types. - For integer types you might also need to set MYSQL_BIND::is_unsigned - member. Set it to TRUE when binding unsigned char, unsigned short, - unsigned int, unsigned long, unsigned long long. - - Binding floating point types. - For floating point types you just need to set - MYSQL_BIND::buffer_type and MYSQL_BIND::buffer. The rest of the - members should be zero-initialized. - - Binding NULLs. - You might have a column always NULL, never NULL, or sometimes - NULL. For an always NULL column set MYSQL_BIND::buffer_type to - MYSQL_TYPE_NULL. The rest of the members just need to be - zero-initialized. For never NULL columns set - MYSQL_BIND::is_null to 0, or this has already been done if you - zero-initialized the entire structure. If you set - MYSQL_TYPE::is_null to point to an application buffer of type - 'my_bool', then this buffer will be checked on each execution: - this way you can set the buffer to TRUE, or any non-0 value for - NULLs, and to FALSE or 0 for not NULL data. - - Binding text strings and sequences of bytes. - For strings, in addition to MYSQL_BIND::buffer_type and - MYSQL_BIND::buffer you need to set MYSQL_BIND::length or - MYSQL_BIND::buffer_length. If 'length' is set, 'buffer_length' - is ignored. 'buffer_length' member should be used when size of - string doesn't change between executions. If you want to vary - buffer length for each value, set 'length' to point to an - application buffer of type 'unsigned long' and set this long to - length of the string before each mysql_stmt_execute(). - - Binding dates and times. - For binding dates and times prepared statements API provides - clients with MYSQL_TIME structure. A pointer to instance of this - structure should be assigned to MYSQL_BIND::buffer whenever - MYSQL_TYPE_TIME, MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME typecodes - are used. When typecode is MYSQL_TYPE_TIME, only members - 'hour', 'minute', 'second' and 'neg' (is time offset negative) - are used. These members only will be sent to the server. - MYSQL_TYPE_DATE implies use of 'year', 'month', 'day', 'neg'. - MYSQL_TYPE_DATETIME utilizes both parts of MYSQL_TIME structure. - You don't have to set MYSQL_TIME::time_type member: it's not - used when sending data to the server, typecode information is - enough. 'second_part' member can hold microsecond precision of - time value, but now it's only supported on protocol level: you - can't store microsecond in a column, or use in temporal - calculations. However, if you send a time value with microsecond - part for 'SELECT ?', statement, you'll get it back unchanged - from the server. - - Data conversion. - If conversion from host language type to data representation, - corresponding to SQL type, is required it's done on the server. - Data truncation is possible when conversion is lossy. For - example, if you supply MYSQL_TYPE_DATETIME value out of valid - SQL type TIMESTAMP range, the same conversion will be applied as - if this value would have been sent as string in the old - protocol. TODO: document how the server will behave in case of - truncation/data loss. - - After variables were bound, you can repeatedly set/change their - values and mysql_stmt_execute() the statement. - - See also: mysql_stmt_send_long_data() for sending long text/blob - data in pieces, examples in tests/mysql_client_test.c. - Next steps you might want to make: - - execute statement with mysql_stmt_execute(), - - reset statement using mysql_stmt_reset() or reprepare it with - another query using mysql_stmt_prepare() - - close statement with mysql_stmt_close(). - - IMPLEMENTATION - The function copies given bind array to internal storage of the - statement, and sets up typecode-specific handlers to perform - serialization of bound data. This means that although you don't need - to call this routine after each assignment to bind buffers, you - need to call it each time you change parameter typecodes, or other - members of MYSQL_BIND array. - This is a pure local call. Data types of client buffers are sent - along with buffers' data at first execution of the statement. - - RETURN - 0 success - 1 error, can be retrieved with mysql_stmt_error. -*/ - -my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *my_bind) -{ - uint count=0; - MYSQL_BIND *param, *end; - DBUG_ENTER("mysql_stmt_bind_param"); - - if (!stmt->param_count) - { - if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) - { - set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - DBUG_RETURN(0); - } - - /* Allocated on prepare */ - memcpy((char*) stmt->params, (char*) my_bind, - sizeof(MYSQL_BIND) * stmt->param_count); - - for (param= stmt->params, end= param+stmt->param_count; - param < end ; - param++) - { - param->param_number= count++; - param->long_data_used= 0; - - /* If param->is_null is not set, then the value can never be NULL */ - if (!param->is_null) - param->is_null= &int_is_null_false; - - /* Setup data copy functions for the different supported types */ - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: - param->is_null= &int_is_null_true; - break; - case MYSQL_TYPE_TINY: - /* Force param->length as this is fixed for this type */ - param->length= ¶m->buffer_length; - param->buffer_length= 1; - param->store_param_func= store_param_tinyint; - break; - case MYSQL_TYPE_SHORT: - param->length= ¶m->buffer_length; - param->buffer_length= 2; - param->store_param_func= store_param_short; - break; - case MYSQL_TYPE_LONG: - param->length= ¶m->buffer_length; - param->buffer_length= 4; - param->store_param_func= store_param_int32; - break; - case MYSQL_TYPE_LONGLONG: - param->length= ¶m->buffer_length; - param->buffer_length= 8; - param->store_param_func= store_param_int64; - break; - case MYSQL_TYPE_FLOAT: - param->length= ¶m->buffer_length; - param->buffer_length= 4; - param->store_param_func= store_param_float; - break; - case MYSQL_TYPE_DOUBLE: - param->length= ¶m->buffer_length; - param->buffer_length= 8; - param->store_param_func= store_param_double; - break; - case MYSQL_TYPE_TIME: - param->store_param_func= store_param_time; - param->buffer_length= MAX_TIME_REP_LENGTH; - break; - case MYSQL_TYPE_DATE: - param->store_param_func= store_param_date; - param->buffer_length= MAX_DATE_REP_LENGTH; - break; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - param->store_param_func= store_param_datetime; - param->buffer_length= MAX_DATETIME_REP_LENGTH; - break; - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - param->store_param_func= store_param_str; - /* - For variable length types user must set either length or - buffer_length. - */ - break; - default: - strmov(stmt->sqlstate, unknown_sqlstate); - sprintf(stmt->last_error, - ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), - param->buffer_type, count); - DBUG_RETURN(1); - } - /* - If param->length is not given, change it to point to buffer_length. - This way we can always use *param->length to get the length of data - */ - if (!param->length) - param->length= ¶m->buffer_length; - } - /* We have to send/resend type information to MySQL */ - stmt->send_types_to_server= TRUE; - stmt->bind_param_done= TRUE; - DBUG_RETURN(0); -} - - -/******************************************************************** - Long data implementation -*********************************************************************/ - -/* - Send long data in pieces to the server - - SYNOPSIS - mysql_stmt_send_long_data() - stmt Statement handler - param_number Parameter number (0 - N-1) - data Data to send to server - length Length of data to send (may be 0) - - DESCRIPTION - This call can be used repeatedly to send long data in pieces - for any string/binary placeholder. Data supplied for - a placeholder is saved at server side till execute, and then - used instead of value from MYSQL_BIND object. More precisely, - if long data for a parameter was supplied, MYSQL_BIND object - corresponding to this parameter is not sent to server. In the - end of execution long data states of placeholders are reset, - so next time values of such placeholders will be taken again - from MYSQL_BIND array. - The server does not reply to this call: if there was an error - in data handling (which now only can happen if server run out - of memory) it would be returned in reply to - mysql_stmt_execute(). - You should choose type of long data carefully if you care - about character set conversions performed by server when the - statement is executed. No conversion is performed at all for - MYSQL_TYPE_BLOB and other binary typecodes. For - MYSQL_TYPE_STRING and the rest of text placeholders data is - converted from client character set to character set of - connection. If these character sets are different, this - conversion may require additional memory at server, equal to - total size of supplied pieces. - - RETURN VALUES - 0 ok - 1 error -*/ - -my_bool STDCALL -mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, - const char *data, ulong length) -{ - MYSQL_BIND *param; - DBUG_ENTER("mysql_stmt_send_long_data"); - DBUG_ASSERT(stmt != 0); - DBUG_PRINT("enter",("param no: %d data: 0x%lx, length : %ld", - param_number, (long) data, length)); - - /* - We only need to check for stmt->param_count, if it's not null - prepare was done. - */ - if (param_number >= stmt->param_count) - { - set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - param= stmt->params+param_number; - if (!IS_LONGDATA(param->buffer_type)) - { - /* Long data handling should be used only for string/binary types */ - strmov(stmt->sqlstate, unknown_sqlstate); - sprintf(stmt->last_error, ER(stmt->last_errno= CR_INVALID_BUFFER_USE), - param->param_number); - DBUG_RETURN(1); - } - - /* - Send long data packet if there is data or we're sending long data - for the first time. - */ - if (length || param->long_data_used == 0) - { - MYSQL *mysql= stmt->mysql; - /* Packet header: stmt id (4 bytes), param no (2 bytes) */ - uchar buff[MYSQL_LONG_DATA_HEADER]; - - int4store(buff, stmt->stmt_id); - int2store(buff + 4, param_number); - param->long_data_used= 1; - - /* - Note that we don't get any ok packet from the server in this case - This is intentional to save bandwidth. - */ - if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA, - buff, sizeof(buff), (uchar*) data, - length, 1, stmt)) - { - /* - Don't set stmt error if stmt->mysql is NULL, as the error in this case - has already been set by mysql_prune_stmt_list(). - */ - if (stmt->mysql) - set_stmt_errmsg(stmt, &mysql->net); - DBUG_RETURN(1); - } - } - DBUG_RETURN(0); -} - - -/******************************************************************** - Fetch and conversion of result set rows (binary protocol). -*********************************************************************/ - -/* - Read date, (time, datetime) value from network buffer and store it - in MYSQL_TIME structure. - - SYNOPSIS - read_binary_{date,time,datetime}() - tm MYSQL_TIME structure to fill - pos pointer to current position in network buffer. - These functions increase pos to point to the beginning of the - next column. - - Auxiliary functions to read time (date, datetime) values from network - buffer and store in MYSQL_TIME structure. Jointly used by conversion - and no-conversion fetching. -*/ - -static void read_binary_time(MYSQL_TIME *tm, uchar **pos) -{ - /* net_field_length will set pos to the first byte of data */ - uint length= net_field_length(pos); - - if (length) - { - uchar *to= *pos; - tm->neg= to[0]; - - tm->day= (ulong) sint4korr(to+1); - tm->hour= (uint) to[5]; - tm->minute= (uint) to[6]; - tm->second= (uint) to[7]; - tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0; - tm->year= tm->month= 0; - if (tm->day) - { - /* Convert days to hours at once */ - tm->hour+= tm->day*24; - tm->day= 0; - } - tm->time_type= MYSQL_TIMESTAMP_TIME; - - *pos+= length; - } - else - set_zero_time(tm, MYSQL_TIMESTAMP_TIME); -} - -static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) -{ - uint length= net_field_length(pos); - - if (length) - { - uchar *to= *pos; - - tm->neg= 0; - tm->year= (uint) sint2korr(to); - tm->month= (uint) to[2]; - tm->day= (uint) to[3]; - - if (length > 4) - { - tm->hour= (uint) to[4]; - tm->minute= (uint) to[5]; - tm->second= (uint) to[6]; - } - else - tm->hour= tm->minute= tm->second= 0; - tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0; - tm->time_type= MYSQL_TIMESTAMP_DATETIME; - - *pos+= length; - } - else - set_zero_time(tm, MYSQL_TIMESTAMP_DATETIME); -} - -static void read_binary_date(MYSQL_TIME *tm, uchar **pos) -{ - uint length= net_field_length(pos); - - if (length) - { - uchar *to= *pos; - tm->year = (uint) sint2korr(to); - tm->month= (uint) to[2]; - tm->day= (uint) to[3]; - - tm->hour= tm->minute= tm->second= 0; - tm->second_part= 0; - tm->neg= 0; - tm->time_type= MYSQL_TIMESTAMP_DATE; - - *pos+= length; - } - else - set_zero_time(tm, MYSQL_TIMESTAMP_DATE); -} - - -/* - Convert string to supplied buffer of any type. - - SYNOPSIS - fetch_string_with_conversion() - param output buffer descriptor - value column data - length data length -*/ - -static void fetch_string_with_conversion(MYSQL_BIND *param, char *value, - uint length) -{ - char *buffer= (char *)param->buffer; - int err= 0; - char *endptr= value + length; - - /* - This function should support all target buffer types: the rest - of conversion functions can delegate conversion to it. - */ - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: /* do nothing */ - break; - case MYSQL_TYPE_TINY: - { - longlong data= my_strtoll10(value, &endptr, &err); - *param->error= (IS_TRUNCATED(data, param->is_unsigned, - INT_MIN8, INT_MAX8, UINT_MAX8) || err > 0); - *buffer= (uchar) data; - break; - } - case MYSQL_TYPE_SHORT: - { - longlong data= my_strtoll10(value, &endptr, &err); - *param->error= (IS_TRUNCATED(data, param->is_unsigned, - INT_MIN16, INT_MAX16, UINT_MAX16) || err > 0); - shortstore(buffer, (short) data); - break; - } - case MYSQL_TYPE_LONG: - { - longlong data= my_strtoll10(value, &endptr, &err); - *param->error= (IS_TRUNCATED(data, param->is_unsigned, - INT_MIN32, INT_MAX32, UINT_MAX32) || err > 0); - longstore(buffer, (int32) data); - break; - } - case MYSQL_TYPE_LONGLONG: - { - longlong data= my_strtoll10(value, &endptr, &err); - *param->error= param->is_unsigned ? err != 0 : - (err > 0 || (err == 0 && data < 0)); - longlongstore(buffer, data); - break; - } - case MYSQL_TYPE_FLOAT: - { - double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err); - float fdata= (float) data; - *param->error= (fdata != data) | MY_TEST(err); - floatstore(buffer, fdata); - break; - } - case MYSQL_TYPE_DOUBLE: - { - double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err); - *param->error= MY_TEST(err); - doublestore(buffer, data); - break; - } - case MYSQL_TYPE_TIME: - { - MYSQL_TIME *tm= (MYSQL_TIME *)buffer; - MYSQL_TIME_STATUS status; - str_to_time(value, length, tm, 0, &status); - err= status.warnings; - *param->error= MY_TEST(err); - break; - } - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME *tm= (MYSQL_TIME *)buffer; - MYSQL_TIME_STATUS status; - (void) str_to_datetime(value, length, tm, 0, &status); - err= status.warnings; - *param->error= MY_TEST(err) && (param->buffer_type == MYSQL_TYPE_DATE && - tm->time_type != MYSQL_TIMESTAMP_DATE); - break; - } - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - default: - { - /* - Copy column data to the buffer taking into account offset, - data length and buffer length. - */ - char *start= value + param->offset; - char *end= value + length; - ulong copy_length; - if (start < end) - { - copy_length= end - start; - /* We've got some data beyond offset: copy up to buffer_length bytes */ - if (param->buffer_length) - memcpy(buffer, start, MY_MIN(copy_length, param->buffer_length)); - } - else - copy_length= 0; - if (copy_length < param->buffer_length) - buffer[copy_length]= '\0'; - *param->error= copy_length > param->buffer_length; - /* - param->length will always contain length of entire column; - number of copied bytes may be way different: - */ - *param->length= length; - break; - } - } -} - - -/* - Convert integer value to client buffer of any type. - - SYNOPSIS - fetch_long_with_conversion() - param output buffer descriptor - field column metadata - value column data -*/ - -static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, - longlong value, my_bool is_unsigned) -{ - char *buffer= (char *)param->buffer; - - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: /* do nothing */ - break; - case MYSQL_TYPE_TINY: - *param->error= IS_TRUNCATED(value, param->is_unsigned, - INT_MIN8, INT_MAX8, UINT_MAX8); - *(uchar *)param->buffer= (uchar) value; - break; - case MYSQL_TYPE_SHORT: - *param->error= IS_TRUNCATED(value, param->is_unsigned, - INT_MIN16, INT_MAX16, UINT_MAX16); - shortstore(buffer, (short) value); - break; - case MYSQL_TYPE_LONG: - *param->error= IS_TRUNCATED(value, param->is_unsigned, - INT_MIN32, INT_MAX32, UINT_MAX32); - longstore(buffer, (int32) value); - break; - case MYSQL_TYPE_LONGLONG: - longlongstore(buffer, value); - *param->error= param->is_unsigned != is_unsigned && value < 0; - break; - case MYSQL_TYPE_FLOAT: - { - /* - We need to mark the local variable volatile to - workaround Intel FPU executive precision feature. - (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details) - */ - volatile float data; - if (is_unsigned) - { - data= (float) ulonglong2double(value); - *param->error= ((ulonglong) value) != ((ulonglong) data); - } - else - { - data= (float)value; - *param->error= value != ((longlong) data); - } - floatstore(buffer, data); - break; - } - case MYSQL_TYPE_DOUBLE: - { - volatile double data; - if (is_unsigned) - { - data= ulonglong2double(value); - *param->error= ((ulonglong) value) != ((ulonglong) data); - } - else - { - data= (double)value; - *param->error= value != ((longlong) data); - } - doublestore(buffer, data); - break; - } - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - { - int error; - value= number_to_datetime(value, 0, (MYSQL_TIME *) buffer, 0, &error); - *param->error= MY_TEST(error); - break; - } - default: - { - uchar buff[22]; /* Enough for longlong */ - uchar *end= (uchar*) longlong10_to_str(value, (char*) buff, - is_unsigned ? 10: -10); - /* Resort to string conversion which supports all typecodes */ - uint length= (uint) (end-buff); - - if (field->flags & ZEROFILL_FLAG && length < field->length && - field->length < 21) - { - bmove_upp(buff+field->length,buff+length, length); - bfill(buff, field->length - length,'0'); - length= field->length; - } - fetch_string_with_conversion(param, (char*) buff, length); - break; - } - } -} - -/* - Convert double/float column to supplied buffer of any type. - - SYNOPSIS - fetch_float_with_conversion() - param output buffer descriptor - field column metadata - value column data - type either MY_GCVT_ARG_FLOAT or MY_GCVT_ARG_DOUBLE. - Affects the maximum number of significant digits - returned by my_gcvt(). -*/ - -static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, - double value, my_gcvt_arg_type type) -{ - char *buffer= (char *)param->buffer; - double val64 = (value < 0 ? -floor(-value) : floor(value)); - - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: /* do nothing */ - break; - case MYSQL_TYPE_TINY: - /* - We need to _store_ data in the buffer before the truncation check to - workaround Intel FPU executive precision feature. - (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details) - Sic: AFAIU it does not guarantee to work. - */ - if (param->is_unsigned) - *buffer= (uint8) value; - else - *buffer= (int8) value; - *param->error= val64 != (param->is_unsigned ? (double)((uint8) *buffer) : - (double)((int8) *buffer)); - break; - case MYSQL_TYPE_SHORT: - if (param->is_unsigned) - { - ushort data= (ushort) value; - shortstore(buffer, data); - } - else - { - short data= (short) value; - shortstore(buffer, data); - } - *param->error= val64 != (param->is_unsigned ? (double) (*(ushort*) buffer): - (double) (*(short*) buffer)); - break; - case MYSQL_TYPE_LONG: - if (param->is_unsigned) - { - uint32 data= (uint32) value; - longstore(buffer, data); - } - else - { - int32 data= (int32) value; - longstore(buffer, data); - } - *param->error= val64 != (param->is_unsigned ? (double) (*(uint32*) buffer): - (double) (*(int32*) buffer)); - break; - case MYSQL_TYPE_LONGLONG: - if (param->is_unsigned) - { - ulonglong data= (ulonglong) value; - longlongstore(buffer, data); - } - else - { - longlong data= (longlong) value; - longlongstore(buffer, data); - } - *param->error= val64 != (param->is_unsigned ? - ulonglong2double(*(ulonglong*) buffer) : - (double) (*(longlong*) buffer)); - break; - case MYSQL_TYPE_FLOAT: - { - float data= (float) value; - floatstore(buffer, data); - *param->error= (*(float*) buffer) != value; - break; - } - case MYSQL_TYPE_DOUBLE: - { - doublestore(buffer, value); - break; - } - default: - { - /* - Resort to fetch_string_with_conversion: this should handle - floating point -> string conversion nicely, honor all typecodes - and param->offset possibly set in mysql_stmt_fetch_column - */ - char buff[FLOATING_POINT_BUFFER]; - size_t len; - if (field->decimals >= FLOATING_POINT_DECIMALS) - len= my_gcvt(value, type, - (int) MY_MIN(sizeof(buff)-1, param->buffer_length), - buff, NULL); - else - len= my_fcvt(value, (int) field->decimals, buff, NULL); - - if (field->flags & ZEROFILL_FLAG && len < field->length && - field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1) - { - bmove_upp((uchar*) buff + field->length, (uchar*) buff + len, - len); - bfill((char*) buff, field->length - len, '0'); - len= field->length; - } - fetch_string_with_conversion(param, buff, len); - - break; - } - } -} - - -/* - Fetch time/date/datetime to supplied buffer of any type - - SYNOPSIS - param output buffer descriptor - time column data -*/ - -static void fetch_datetime_with_conversion(MYSQL_BIND *param, - MYSQL_FIELD *field, - MYSQL_TIME *my_time) -{ - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: /* do nothing */ - break; - case MYSQL_TYPE_DATE: - *(MYSQL_TIME *)(param->buffer)= *my_time; - *param->error= my_time->time_type != MYSQL_TIMESTAMP_DATE; - break; - case MYSQL_TYPE_TIME: - *(MYSQL_TIME *)(param->buffer)= *my_time; - *param->error= my_time->time_type != MYSQL_TIMESTAMP_TIME; - break; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - *(MYSQL_TIME *)(param->buffer)= *my_time; - /* No error: time and date are compatible with datetime */ - break; - case MYSQL_TYPE_YEAR: - shortstore(param->buffer, my_time->year); - *param->error= 1; - break; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - { - ulonglong value= TIME_to_ulonglong(my_time); - fetch_float_with_conversion(param, field, - ulonglong2double(value), MY_GCVT_ARG_DOUBLE); - break; - } - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - { - longlong value= (longlong) TIME_to_ulonglong(my_time); - fetch_long_with_conversion(param, field, value, TRUE); - break; - } - default: - { - /* - Convert time value to string and delegate the rest to - fetch_string_with_conversion: - */ - char buff[MAX_DATE_STRING_REP_LENGTH]; - uint length= my_TIME_to_str(my_time, buff, field->decimals); - /* Resort to string conversion */ - fetch_string_with_conversion(param, (char *)buff, length); - break; - } - } -} - - -/* - Fetch and convert result set column to output buffer. - - SYNOPSIS - fetch_result_with_conversion() - param output buffer descriptor - field column metadata - row points to a column of result set tuple in binary format - - DESCRIPTION - This is a fallback implementation of column fetch used - if column and output buffer types do not match. - Increases tuple pointer to point at the next column within the - tuple. -*/ - -static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, - uchar **row) -{ - enum enum_field_types field_type= field->type; - uint field_is_unsigned= field->flags & UNSIGNED_FLAG; - - switch (field_type) { - case MYSQL_TYPE_TINY: - { - uchar value= **row; - /* sic: we need to cast to 'signed char' as 'char' may be unsigned */ - longlong data= field_is_unsigned ? (longlong) value : - (longlong) (signed char) value; - fetch_long_with_conversion(param, field, data, 0); - *row+= 1; - break; - } - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_YEAR: - { - short value= sint2korr(*row); - longlong data= field_is_unsigned ? (longlong) (unsigned short) value : - (longlong) value; - fetch_long_with_conversion(param, field, data, 0); - *row+= 2; - break; - } - case MYSQL_TYPE_INT24: /* mediumint is sent as 4 bytes int */ - case MYSQL_TYPE_LONG: - { - int32 value= sint4korr(*row); - longlong data= field_is_unsigned ? (longlong) (uint32) value : - (longlong) value; - fetch_long_with_conversion(param, field, data, 0); - *row+= 4; - break; - } - case MYSQL_TYPE_LONGLONG: - { - longlong value= (longlong)sint8korr(*row); - fetch_long_with_conversion(param, field, value, - field->flags & UNSIGNED_FLAG); - *row+= 8; - break; - } - case MYSQL_TYPE_FLOAT: - { - float value; - float4get(value,*row); - fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_FLOAT); - *row+= 4; - break; - } - case MYSQL_TYPE_DOUBLE: - { - double value; - float8get(value,*row); - fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_DOUBLE); - *row+= 8; - break; - } - case MYSQL_TYPE_DATE: - { - MYSQL_TIME tm; - - read_binary_date(&tm, row); - fetch_datetime_with_conversion(param, field, &tm); - break; - } - case MYSQL_TYPE_TIME: - { - MYSQL_TIME tm; - - read_binary_time(&tm, row); - fetch_datetime_with_conversion(param, field, &tm); - break; - } - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME tm; - - read_binary_datetime(&tm, row); - fetch_datetime_with_conversion(param, field, &tm); - break; - } - default: - { - ulong length= net_field_length(row); - fetch_string_with_conversion(param, (char*) *row, length); - *row+= length; - break; - } - } -} - - -/* - Functions to fetch data to application buffers without conversion. - - All functions have the following characteristics: - - SYNOPSIS - fetch_result_xxx() - param MySQL bind param - pos Row value - - DESCRIPTION - These are no-conversion functions, used in binary protocol to store - rows in application buffers. A function used only if type of binary data - is compatible with type of application buffer. - - RETURN - none -*/ - -static void fetch_result_tinyint(MYSQL_BIND *param, MYSQL_FIELD *field, - uchar **row) -{ - my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG); - uchar data= **row; - *(uchar *)param->buffer= data; - *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX8; - (*row)++; -} - -static void fetch_result_short(MYSQL_BIND *param, MYSQL_FIELD *field, - uchar **row) -{ - my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG); - ushort data= (ushort) sint2korr(*row); - shortstore(param->buffer, data); - *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX16; - *row+= 2; -} - -static void fetch_result_int32(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG); - uint32 data= (uint32) sint4korr(*row); - longstore(param->buffer, data); - *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX32; - *row+= 4; -} - -static void fetch_result_int64(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG); - ulonglong data= (ulonglong) sint8korr(*row); - *param->error= param->is_unsigned != field_is_unsigned && data > LONGLONG_MAX; - longlongstore(param->buffer, data); - *row+= 8; -} - -static void fetch_result_float(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - float value; - float4get(value,*row); - floatstore(param->buffer, value); - *row+= 4; -} - -static void fetch_result_double(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - double value; - float8get(value,*row); - doublestore(param->buffer, value); - *row+= 8; -} - -static void fetch_result_time(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; - read_binary_time(tm, row); -} - -static void fetch_result_date(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; - read_binary_date(tm, row); -} - -static void fetch_result_datetime(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; - read_binary_datetime(tm, row); -} - -static void fetch_result_bin(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - ulong length= net_field_length(row); - ulong copy_length= MY_MIN(length, param->buffer_length); - memcpy(param->buffer, (char *)*row, copy_length); - *param->length= length; - *param->error= copy_length < length; - *row+= length; -} - -static void fetch_result_str(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) -{ - ulong length= net_field_length(row); - ulong copy_length= MY_MIN(length, param->buffer_length); - memcpy(param->buffer, (char *)*row, copy_length); - /* Add an end null if there is room in the buffer */ - if (copy_length != param->buffer_length) - ((uchar *)param->buffer)[copy_length]= '\0'; - *param->length= length; /* return total length */ - *param->error= copy_length < length; - *row+= length; -} - - -/* - functions to calculate max lengths for strings during - mysql_stmt_store_result() -*/ - -static void skip_result_fixed(MYSQL_BIND *param, - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) - -{ - (*row)+= param->pack_length; -} - - -static void skip_result_with_length(MYSQL_BIND *param __attribute__((unused)), - MYSQL_FIELD *field __attribute__((unused)), - uchar **row) - -{ - ulong length= net_field_length(row); - (*row)+= length; -} - - -static void skip_result_string(MYSQL_BIND *param __attribute__((unused)), - MYSQL_FIELD *field, - uchar **row) - -{ - ulong length= net_field_length(row); - (*row)+= length; - if (field->max_length < length) - field->max_length= length; -} - - -/* - Check that two field types are binary compatible i. e. - have equal representation in the binary protocol and - require client-side buffers of the same type. - - SYNOPSIS - is_binary_compatible() - type1 parameter type supplied by user - type2 field type, obtained from result set metadata - - RETURN - TRUE or FALSE -*/ - -static my_bool is_binary_compatible(enum enum_field_types type1, - enum enum_field_types type2) -{ - static const enum enum_field_types - range1[]= { MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR, MYSQL_TYPE_NULL }, - range2[]= { MYSQL_TYPE_INT24, MYSQL_TYPE_LONG, MYSQL_TYPE_NULL }, - range3[]= { MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_NULL }, - range4[]= { MYSQL_TYPE_ENUM, MYSQL_TYPE_SET, MYSQL_TYPE_TINY_BLOB, - MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB, - MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY, - MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NULL }; - static const enum enum_field_types - *range_list[]= { range1, range2, range3, range4 }, - **range_list_end= range_list + sizeof(range_list)/sizeof(*range_list); - const enum enum_field_types **range, *type; - - if (type1 == type2) - return TRUE; - for (range= range_list; range != range_list_end; ++range) - { - /* check that both type1 and type2 are in the same range */ - my_bool type1_found= FALSE, type2_found= FALSE; - for (type= *range; *type != MYSQL_TYPE_NULL; type++) - { - type1_found|= type1 == *type; - type2_found|= type2 == *type; - } - if (type1_found || type2_found) - return type1_found && type2_found; - } - return FALSE; -} - - -/* - Setup a fetch function for one column of a result set. - - SYNOPSIS - setup_one_fetch_function() - param output buffer descriptor - field column descriptor - - DESCRIPTION - When user binds result set buffers or when result set - metadata is changed, we need to setup fetch (and possibly - conversion) functions for all columns of the result set. - In addition to that here we set up skip_result function, used - to update result set metadata in case when - STMT_ATTR_UPDATE_MAX_LENGTH attribute is set. - Notice that while fetch_result is chosen depending on both - field->type and param->type, skip_result depends on field->type - only. - - RETURN - TRUE fetch function for this typecode was not found (typecode - is not supported by the client library) - FALSE success -*/ - -static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) -{ - DBUG_ENTER("setup_one_fetch_function"); - - /* Setup data copy functions for the different supported types */ - switch (param->buffer_type) { - case MYSQL_TYPE_NULL: /* for dummy binds */ - /* - It's not binary compatible with anything the server can return: - no need to setup fetch_result, as it'll be reset anyway - */ - *param->length= 0; - break; - case MYSQL_TYPE_TINY: - param->fetch_result= fetch_result_tinyint; - *param->length= 1; - break; - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_YEAR: - param->fetch_result= fetch_result_short; - *param->length= 2; - break; - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - param->fetch_result= fetch_result_int32; - *param->length= 4; - break; - case MYSQL_TYPE_LONGLONG: - param->fetch_result= fetch_result_int64; - *param->length= 8; - break; - case MYSQL_TYPE_FLOAT: - param->fetch_result= fetch_result_float; - *param->length= 4; - break; - case MYSQL_TYPE_DOUBLE: - param->fetch_result= fetch_result_double; - *param->length= 8; - break; - case MYSQL_TYPE_TIME: - param->fetch_result= fetch_result_time; - *param->length= sizeof(MYSQL_TIME); - break; - case MYSQL_TYPE_DATE: - param->fetch_result= fetch_result_date; - *param->length= sizeof(MYSQL_TIME); - break; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - param->fetch_result= fetch_result_datetime; - *param->length= sizeof(MYSQL_TIME); - break; - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_BIT: - DBUG_ASSERT(param->buffer_length != 0); - param->fetch_result= fetch_result_bin; - break; - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - case MYSQL_TYPE_NEWDATE: - DBUG_ASSERT(param->buffer_length != 0); - param->fetch_result= fetch_result_str; - break; - default: - DBUG_PRINT("error", ("Unknown param->buffer_type: %u", - (uint) param->buffer_type)); - DBUG_RETURN(TRUE); - } - if (! is_binary_compatible(param->buffer_type, field->type)) - param->fetch_result= fetch_result_with_conversion; - - /* Setup skip_result functions (to calculate max_length) */ - param->skip_result= skip_result_fixed; - switch (field->type) { - case MYSQL_TYPE_NULL: /* for dummy binds */ - param->pack_length= 0; - field->max_length= 0; - break; - case MYSQL_TYPE_TINY: - param->pack_length= 1; - field->max_length= 4; /* as in '-127' */ - break; - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_SHORT: - param->pack_length= 2; - field->max_length= 6; /* as in '-32767' */ - break; - case MYSQL_TYPE_INT24: - field->max_length= 9; /* as in '16777216' or in '-8388607' */ - param->pack_length= 4; - break; - case MYSQL_TYPE_LONG: - field->max_length= 11; /* '-2147483647' */ - param->pack_length= 4; - break; - case MYSQL_TYPE_LONGLONG: - field->max_length= 21; /* '18446744073709551616' */ - param->pack_length= 8; - break; - case MYSQL_TYPE_FLOAT: - param->pack_length= 4; - field->max_length= MAX_DOUBLE_STRING_REP_LENGTH; - break; - case MYSQL_TYPE_DOUBLE: - param->pack_length= 8; - field->max_length= MAX_DOUBLE_STRING_REP_LENGTH; - break; - case MYSQL_TYPE_TIME: - field->max_length= 17; /* -819:23:48.123456 */ - param->skip_result= skip_result_with_length; - break; - case MYSQL_TYPE_DATE: - field->max_length= 10; /* 2003-11-11 */ - param->skip_result= skip_result_with_length; - break; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - param->skip_result= skip_result_with_length; - field->max_length= MAX_DATE_STRING_REP_LENGTH; - break; - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_GEOMETRY: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_NEWDATE: - param->skip_result= skip_result_string; - break; - default: - DBUG_PRINT("error", ("Unknown field->type: %u", (uint) field->type)); - DBUG_RETURN(TRUE); - } - DBUG_RETURN(FALSE); -} - - -/* - Setup the bind buffers for resultset processing -*/ - -my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *my_bind) -{ - MYSQL_BIND *param, *end; - MYSQL_FIELD *field; - ulong bind_count= stmt->field_count; - uint param_count= 0; - DBUG_ENTER("mysql_stmt_bind_result"); - DBUG_PRINT("enter",("field_count: %lu", bind_count)); - - if (!bind_count) - { - int errorcode= (int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE ? - CR_NO_PREPARE_STMT : CR_NO_STMT_METADATA; - set_stmt_error(stmt, errorcode, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - /* - We only need to check that stmt->field_count - if it is not null - stmt->bind was initialized in mysql_stmt_prepare - stmt->bind overlaps with bind if mysql_stmt_bind_param - is called from mysql_stmt_store_result. - */ - - if (stmt->bind != my_bind) - memcpy((char*) stmt->bind, (char*) my_bind, - sizeof(MYSQL_BIND) * bind_count); - - for (param= stmt->bind, end= param + bind_count, field= stmt->fields ; - param < end ; - param++, field++) - { - DBUG_PRINT("info",("buffer_type: %u field_type: %u", - (uint) param->buffer_type, (uint) field->type)); - /* - Set param->is_null to point to a dummy variable if it's not set. - This is to make the execute code easier - */ - if (!param->is_null) - param->is_null= ¶m->is_null_value; - - if (!param->length) - param->length= ¶m->length_value; - - if (!param->error) - param->error= ¶m->error_value; - - param->param_number= param_count++; - param->offset= 0; - - if (setup_one_fetch_function(param, field)) - { - strmov(stmt->sqlstate, unknown_sqlstate); - sprintf(stmt->last_error, - ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), - field->type, param_count); - DBUG_RETURN(1); - } - } - stmt->bind_result_done= BIND_RESULT_DONE; - if (stmt->mysql->options.report_data_truncation) - stmt->bind_result_done|= REPORT_DATA_TRUNCATION; - - DBUG_RETURN(0); -} - - -/* - Fetch row data to bind buffers -*/ - -static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) -{ - MYSQL_BIND *my_bind, *end; - MYSQL_FIELD *field; - uchar *null_ptr, bit; - int truncation_count= 0; - /* - Precondition: if stmt->field_count is zero or row is NULL, read_row_* - function must return no data. - */ - DBUG_ASSERT(stmt->field_count); - DBUG_ASSERT(row); - - if (!stmt->bind_result_done) - { - /* If output parameters were not bound we should just return success */ - return 0; - } - - null_ptr= row; - row+= (stmt->field_count+9)/8; /* skip null bits */ - bit= 4; /* first 2 bits are reserved */ - - /* Copy complete row to application buffers */ - for (my_bind= stmt->bind, end= my_bind + stmt->field_count, - field= stmt->fields ; - my_bind < end ; - my_bind++, field++) - { - *my_bind->error= 0; - if (*null_ptr & bit) - { - /* - We should set both row_ptr and is_null to be able to see - nulls in mysql_stmt_fetch_column. This is because is_null may point - to user data which can be overwritten between mysql_stmt_fetch and - mysql_stmt_fetch_column, and in this case nullness of column will be - lost. See mysql_stmt_fetch_column for details. - */ - my_bind->row_ptr= NULL; - *my_bind->is_null= 1; - } - else - { - *my_bind->is_null= 0; - my_bind->row_ptr= row; - (*my_bind->fetch_result)(my_bind, field, &row); - truncation_count+= *my_bind->error; - } - if (!((bit<<=1) & 255)) - { - bit= 1; /* To next uchar */ - null_ptr++; - } - } - if (truncation_count && (stmt->bind_result_done & REPORT_DATA_TRUNCATION)) - return MYSQL_DATA_TRUNCATED; - return 0; -} - - -int cli_unbuffered_fetch(MYSQL *mysql, char **row) -{ - if (packet_error == cli_safe_read(mysql)) - return 1; - - *row= ((mysql->net.read_pos[0] == 254) ? NULL : - (char*) (mysql->net.read_pos+1)); - return 0; -} - - -/* - Fetch and return row data to bound buffers, if any -*/ - -int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt) -{ - int rc; - uchar *row; - DBUG_ENTER("mysql_stmt_fetch"); - - if ((rc= (*stmt->read_row_func)(stmt, &row)) || - ((rc= stmt_fetch_row(stmt, row)) && rc != MYSQL_DATA_TRUNCATED)) - { - stmt->state= MYSQL_STMT_PREPARE_DONE; /* XXX: this is buggy */ - stmt->read_row_func= (rc == MYSQL_NO_DATA) ? - stmt_read_row_no_data : stmt_read_row_no_result_set; - } - else - { - /* This is to know in mysql_stmt_fetch_column that data was fetched */ - stmt->state= MYSQL_STMT_FETCH_DONE; - } - DBUG_RETURN(rc); -} - - -/* - Fetch data for one specified column data - - SYNOPSIS - mysql_stmt_fetch_column() - stmt Prepared statement handler - my_bind Where data should be placed. Should be filled in as - when calling mysql_stmt_bind_result() - column Column to fetch (first column is 0) - ulong offset Offset in result data (to fetch blob in pieces) - This is normally 0 - RETURN - 0 ok - 1 error -*/ - -int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *my_bind, - uint column, ulong offset) -{ - MYSQL_BIND *param= stmt->bind+column; - DBUG_ENTER("mysql_stmt_fetch_column"); - - if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE) - { - set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - if (column >= stmt->field_count) - { - set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - if (!my_bind->error) - my_bind->error= &my_bind->error_value; - *my_bind->error= 0; - if (param->row_ptr) - { - MYSQL_FIELD *field= stmt->fields+column; - uchar *row= param->row_ptr; - my_bind->offset= offset; - if (my_bind->is_null) - *my_bind->is_null= 0; - if (my_bind->length) /* Set the length if non char/binary types */ - *my_bind->length= *param->length; - else - my_bind->length= ¶m->length_value; /* Needed for fetch_result() */ - fetch_result_with_conversion(my_bind, field, &row); - } - else - { - if (my_bind->is_null) - *my_bind->is_null= 1; - } - DBUG_RETURN(0); -} - - -/* - Read all rows of data from server (binary format) -*/ - -int cli_read_binary_rows(MYSQL_STMT *stmt) -{ - ulong pkt_len; - uchar *cp; - MYSQL *mysql= stmt->mysql; - MYSQL_DATA *result= &stmt->result; - MYSQL_ROWS *cur, **prev_ptr= &result->data; - NET *net; - - DBUG_ENTER("cli_read_binary_rows"); - - if (!mysql) - { - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - net = &mysql->net; - - while ((pkt_len= cli_safe_read(mysql)) != packet_error) - { - cp= net->read_pos; - if (cp[0] != 254 || pkt_len >= 8) - { - if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, - sizeof(MYSQL_ROWS) + pkt_len - 1))) - { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); - goto err; - } - cur->data= (MYSQL_ROW) (cur+1); - *prev_ptr= cur; - prev_ptr= &cur->next; - memcpy((char *) cur->data, (char *) cp+1, pkt_len-1); - cur->length= pkt_len; /* To allow us to do sanity checks */ - result->rows++; - } - else - { - /* end of data */ - *prev_ptr= 0; - mysql->warning_count= uint2korr(cp+1); - mysql->server_status= uint2korr(cp+3); - DBUG_PRINT("info",("status: %u warning_count: %u", - mysql->server_status, mysql->warning_count)); - DBUG_RETURN(0); - } - } - set_stmt_errmsg(stmt, net); - -err: - DBUG_RETURN(1); -} - - -/* - Update meta data for statement - - SYNOPSIS - stmt_update_metadata() - stmt Statement handler - row Binary data - - NOTES - Only updates MYSQL_FIELD->max_length for strings -*/ - -static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data) -{ - MYSQL_BIND *my_bind, *end; - MYSQL_FIELD *field; - uchar *null_ptr, bit; - uchar *row= (uchar*) data->data; -#ifndef DBUG_OFF - uchar *row_end= row + data->length; -#endif - - null_ptr= row; - row+= (stmt->field_count+9)/8; /* skip null bits */ - bit= 4; /* first 2 bits are reserved */ - - /* Go through all fields and calculate metadata */ - for (my_bind= stmt->bind, end= my_bind + stmt->field_count, field= stmt->fields ; - my_bind < end ; - my_bind++, field++) - { - if (!(*null_ptr & bit)) - (*my_bind->skip_result)(my_bind, field, &row); - DBUG_ASSERT(row <= row_end); - if (!((bit<<=1) & 255)) - { - bit= 1; /* To next uchar */ - null_ptr++; - } - } -} - - -/* - Store or buffer the binary results to stmt -*/ - -int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) -{ - MYSQL *mysql= stmt->mysql; - MYSQL_DATA *result= &stmt->result; - DBUG_ENTER("mysql_stmt_store_result"); - - if (!mysql) - { - /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - if (!stmt->field_count) - DBUG_RETURN(0); - - if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE) - { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - if (stmt->last_errno) - { - /* An attempt to use an invalid statement handle. */ - DBUG_RETURN(1); - } - - if (mysql->status == MYSQL_STATUS_READY && - stmt->server_status & SERVER_STATUS_CURSOR_EXISTS) - { - /* - Server side cursor exist, tell server to start sending the rows - */ - NET *net= &mysql->net; - uchar buff[4 /* statement id */ + - 4 /* number of rows to fetch */]; - - /* Send row request to the server */ - int4store(buff, stmt->stmt_id); - int4store(buff + 4, (int)~0); /* number of rows to fetch */ - if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff), - (uchar*) 0, 0, 1, stmt)) - { - /* - Don't set stmt error if stmt->mysql is NULL, as the error in this case - has already been set by mysql_prune_stmt_list(). - */ - if (stmt->mysql) - set_stmt_errmsg(stmt, net); - DBUG_RETURN(1); - } - } - else if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT) - { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - - if (stmt->update_max_length && !stmt->bind_result_done) - { - /* - We must initalize the bind structure to be able to calculate - max_length - */ - MYSQL_BIND *my_bind, *end; - MYSQL_FIELD *field; - bzero((char*) stmt->bind, sizeof(*stmt->bind)* stmt->field_count); - - for (my_bind= stmt->bind, end= my_bind + stmt->field_count, - field= stmt->fields; - my_bind < end ; - my_bind++, field++) - { - my_bind->buffer_type= MYSQL_TYPE_NULL; - my_bind->buffer_length=1; - } - - if (mysql_stmt_bind_result(stmt, stmt->bind)) - DBUG_RETURN(1); - stmt->bind_result_done= 0; /* No normal bind done */ - } - - if ((*mysql->methods->read_binary_rows)(stmt)) - { - free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); - result->data= NULL; - result->rows= 0; - mysql->status= MYSQL_STATUS_READY; - DBUG_RETURN(1); - } - - /* Assert that if there was a cursor, all rows have been fetched */ - DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY || - (mysql->server_status & SERVER_STATUS_LAST_ROW_SENT)); - - if (stmt->update_max_length) - { - MYSQL_ROWS *cur= result->data; - for(; cur; cur=cur->next) - stmt_update_metadata(stmt, cur); - } - - stmt->data_cursor= result->data; - mysql->affected_rows= stmt->affected_rows= result->rows; - stmt->read_row_func= stmt_read_row_buffered; - mysql->unbuffered_fetch_owner= 0; /* set in stmt_execute */ - mysql->status= MYSQL_STATUS_READY; /* server is ready */ - DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */ -} - - -/* - Seek to desired row in the statement result set -*/ - -MYSQL_ROW_OFFSET STDCALL -mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) -{ - MYSQL_ROW_OFFSET offset= stmt->data_cursor; - DBUG_ENTER("mysql_stmt_row_seek"); - - stmt->data_cursor= row; - DBUG_RETURN(offset); -} - - -/* - Return the current statement row cursor position -*/ - -MYSQL_ROW_OFFSET STDCALL -mysql_stmt_row_tell(MYSQL_STMT *stmt) -{ - DBUG_ENTER("mysql_stmt_row_tell"); - - DBUG_RETURN(stmt->data_cursor); -} - - -/* - Move the stmt result set data cursor to specified row -*/ - -void STDCALL -mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) -{ - MYSQL_ROWS *tmp= stmt->result.data; - DBUG_ENTER("mysql_stmt_data_seek"); - DBUG_PRINT("enter",("row id to seek: %ld",(long) row)); - - for (; tmp && row; --row, tmp= tmp->next) - ; - stmt->data_cursor= tmp; - if (!row && tmp) - { - /* Rewind the counter */ - stmt->read_row_func= stmt_read_row_buffered; - stmt->state= MYSQL_STMT_EXECUTE_DONE; - } - DBUG_VOID_RETURN; -} - - -/* - Return total rows the current statement result set -*/ - -my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt) -{ - DBUG_ENTER("mysql_stmt_num_rows"); - - DBUG_RETURN(stmt->result.rows); -} - - -/* - Free the client side memory buffers, reset long data state - on client if necessary, and reset the server side statement if - this has been requested. -*/ - -static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) -{ - /* If statement hasn't been prepared there is nothing to reset */ - if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) - { - MYSQL *mysql= stmt->mysql; - MYSQL_DATA *result= &stmt->result; - - /* - Reset stored result set if so was requested or it's a part - of cursor fetch. - */ - if (flags & RESET_STORE_RESULT) - { - /* Result buffered */ - free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); - result->data= NULL; - result->rows= 0; - stmt->data_cursor= NULL; - } - if (flags & RESET_LONG_DATA) - { - MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count; - /* Clear long_data_used flags */ - for (; param < param_end; param++) - param->long_data_used= 0; - } - stmt->read_row_func= stmt_read_row_no_result_set; - if (mysql) - { - if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) - { - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (stmt->field_count && mysql->status != MYSQL_STATUS_READY) - { - /* There is a result set and it belongs to this statement */ - (*mysql->methods->flush_use_result)(mysql, FALSE); - if (mysql->unbuffered_fetch_owner) - *mysql->unbuffered_fetch_owner= TRUE; - mysql->status= MYSQL_STATUS_READY; - } - if (flags & RESET_ALL_BUFFERS) - { - /* mysql_stmt_next_result will flush all pending - result sets - */ - while (mysql_more_results(mysql) && - mysql_stmt_next_result(stmt) == 0); - } - } - if (flags & RESET_SERVER_SIDE) - { - /* - Reset the server side statement and close the server side - cursor if it exists. - */ - uchar buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ - int4store(buff, stmt->stmt_id); - if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff, - sizeof(buff), 0, 0, 0, stmt)) - { - set_stmt_errmsg(stmt, &mysql->net); - stmt->state= MYSQL_STMT_INIT_DONE; - return 1; - } - } - } - if (flags & RESET_CLEAR_ERROR) - stmt_clear_error(stmt); - stmt->state= MYSQL_STMT_PREPARE_DONE; - } - return 0; -} - -my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) -{ - DBUG_ENTER("mysql_stmt_free_result"); - - /* Free the client side and close the server side cursor if there is one */ - DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT | - RESET_CLEAR_ERROR)); -} - -/******************************************************************** - statement error handling and close -*********************************************************************/ - -/* - Close the statement handle by freeing all alloced resources - - SYNOPSIS - mysql_stmt_close() - stmt Statement handle - - RETURN VALUES - 0 ok - 1 error -*/ - -my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) -{ - MYSQL *mysql= stmt->mysql; - int rc= 0; - DBUG_ENTER("mysql_stmt_close"); - - free_root(&stmt->result.alloc, MYF(0)); - free_root(&stmt->mem_root, MYF(0)); - free_root(&stmt->extension->fields_mem_root, MYF(0)); - - if (mysql) - { - mysql->stmts= list_delete(mysql->stmts, &stmt->list); - /* - Clear NET error state: if the following commands come through - successfully, connection will still be usable for other commands. - */ - net_clear_error(&mysql->net); - - if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) - { - uchar buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - - if ((rc= reset_stmt_handle(stmt, RESET_ALL_BUFFERS | RESET_CLEAR_ERROR))) - return rc; - - int4store(buff, stmt->stmt_id); - if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))) - { - set_stmt_errmsg(stmt, &mysql->net); - } - } - } - - my_free(stmt->extension); - my_free(stmt); - - DBUG_RETURN(MY_TEST(rc)); -} - -/* - Reset the statement buffers in server -*/ - -my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) -{ - DBUG_ENTER("mysql_stmt_reset"); - DBUG_ASSERT(stmt != 0); - if (!stmt->mysql) - { - /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); - DBUG_RETURN(1); - } - /* Reset the client and server sides of the prepared statement */ - DBUG_RETURN(reset_stmt_handle(stmt, - RESET_SERVER_SIDE | RESET_LONG_DATA | - RESET_ALL_BUFFERS | RESET_CLEAR_ERROR)); -} - -/* - Return statement error code -*/ - -uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt) -{ - DBUG_ENTER("mysql_stmt_errno"); - DBUG_RETURN(stmt->last_errno); -} - -const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt) -{ - DBUG_ENTER("mysql_stmt_sqlstate"); - DBUG_RETURN(stmt->sqlstate); -} - -/* - Return statement error message -*/ - -const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt) -{ - DBUG_ENTER("mysql_stmt_error"); - DBUG_RETURN(stmt->last_error); -} - - -/******************************************************************** - Transactional APIs -*********************************************************************/ - -/* - Commit the current transaction -*/ - -my_bool STDCALL mysql_commit(MYSQL * mysql) -{ - DBUG_ENTER("mysql_commit"); - DBUG_RETURN((my_bool) mysql_real_query(mysql, "commit", 6)); -} - -/* - Rollback the current transaction -*/ - -my_bool STDCALL mysql_rollback(MYSQL * mysql) -{ - DBUG_ENTER("mysql_rollback"); - DBUG_RETURN((my_bool) mysql_real_query(mysql, "rollback", 8)); -} - - -/* - Set autocommit to either true or false -*/ - -my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode) -{ - DBUG_ENTER("mysql_autocommit"); - DBUG_PRINT("enter", ("mode : %d", auto_mode)); - - DBUG_RETURN((my_bool) mysql_real_query(mysql, auto_mode ? - "set autocommit=1":"set autocommit=0", - 16)); -} - - -/******************************************************************** - Multi query execution + SPs APIs -*********************************************************************/ - -/* - Returns true/false to indicate whether any more query results exist - to be read using mysql_next_result() -*/ - -my_bool STDCALL mysql_more_results(MYSQL *mysql) -{ - my_bool res; - DBUG_ENTER("mysql_more_results"); - - res= ((mysql->server_status & SERVER_MORE_RESULTS_EXISTS) ? 1: 0); - DBUG_PRINT("exit",("More results exists ? %d", res)); - DBUG_RETURN(res); -} - - -/* - Reads and returns the next query results -*/ -int STDCALL mysql_next_result(MYSQL *mysql) -{ - DBUG_ENTER("mysql_next_result"); - - if (mysql->status != MYSQL_STATUS_READY) - { - set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); - DBUG_RETURN(1); - } - - net_clear_error(&mysql->net); - mysql->affected_rows= ~(my_ulonglong) 0; - - if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS) - DBUG_RETURN((*mysql->methods->next_result)(mysql)); - - DBUG_RETURN(-1); /* No more results */ -} - -int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) -{ - MYSQL *mysql= stmt->mysql; - int rc; - DBUG_ENTER("mysql_stmt_next_result"); - - if (!mysql) - DBUG_RETURN(1); - - if (stmt->last_errno) - DBUG_RETURN(stmt->last_errno); - - if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS) - { - if (reset_stmt_handle(stmt, RESET_STORE_RESULT)) - DBUG_RETURN(1); - } - - rc= mysql_next_result(mysql); - - if (rc) - { - set_stmt_errmsg(stmt, &mysql->net); - DBUG_RETURN(rc); - } - - if (mysql->status == MYSQL_STATUS_GET_RESULT) - mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT; - - stmt->state= MYSQL_STMT_EXECUTE_DONE; - stmt->bind_result_done= FALSE; - stmt->field_count= mysql->field_count; - - if (mysql->field_count) - { - alloc_stmt_fields(stmt); - prepare_to_fetch_result(stmt); - } - - DBUG_RETURN(0); -} - - -MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql) -{ - return (*mysql->methods->use_result)(mysql); -} - -my_bool STDCALL mysql_read_query_result(MYSQL *mysql) -{ - return (*mysql->methods->read_query_result)(mysql); -} - -/******************************************************************** - mysql_net_ functions - low-level API to MySQL protocol -*********************************************************************/ -ulong STDCALL mysql_net_read_packet(MYSQL *mysql) -{ - return cli_safe_read(mysql); -} - -ulong STDCALL mysql_net_field_length(uchar **packet) -{ - return net_field_length(packet); -} - diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def deleted file mode 100644 index 5a6bee4919f..00000000000 --- a/libmysql/libmysql.def +++ /dev/null @@ -1,107 +0,0 @@ -LIBRARY LIBMYSQL -VERSION 6.0 -EXPORTS - load_defaults - mysql_thread_end - mysql_thread_init - myodbc_remove_escape - mysql_affected_rows - mysql_autocommit - mysql_stmt_bind_param - mysql_stmt_bind_result - mysql_change_user - mysql_character_set_name - mysql_close - mysql_commit - mysql_data_seek - mysql_debug - mysql_dump_debug_info - mysql_eof - mysql_errno - mysql_error - mysql_escape_string - mysql_hex_string - mysql_stmt_execute - mysql_stmt_fetch - mysql_stmt_fetch_column - mysql_fetch_field - mysql_fetch_field_direct - mysql_fetch_fields - mysql_fetch_lengths - mysql_fetch_row - mysql_field_count - mysql_field_seek - mysql_field_tell - mysql_free_result - mysql_get_client_info - mysql_get_host_info - mysql_get_proto_info - mysql_get_server_info - mysql_get_client_version - mysql_get_ssl_cipher - mysql_info - mysql_init - mysql_insert_id - mysql_kill - mysql_set_server_option - mysql_list_dbs - mysql_list_fields - mysql_list_processes - mysql_list_tables - mysql_more_results - mysql_next_result - mysql_num_fields - mysql_num_rows - mysql_options - mysql_stmt_param_count - mysql_stmt_param_metadata - mysql_ping - mysql_stmt_result_metadata - mysql_query - mysql_read_query_result - mysql_real_connect - mysql_real_escape_string - mysql_real_query - mysql_refresh - mysql_rollback - mysql_row_seek - mysql_row_tell - mysql_select_db - mysql_stmt_send_long_data - mysql_send_query - mysql_shutdown - mysql_ssl_set - mysql_stat - mysql_stmt_affected_rows - mysql_stmt_close - mysql_stmt_reset - mysql_stmt_data_seek - mysql_stmt_errno - mysql_stmt_error - mysql_stmt_free_result - mysql_stmt_num_rows - mysql_stmt_row_seek - mysql_stmt_row_tell - mysql_stmt_store_result - mysql_store_result - mysql_thread_id - mysql_thread_safe - mysql_use_result - mysql_warning_count - mysql_stmt_sqlstate - mysql_sqlstate - mysql_get_server_version - mysql_stmt_prepare - mysql_stmt_init - mysql_stmt_insert_id - mysql_stmt_attr_get - mysql_stmt_attr_set - mysql_stmt_field_count - mysql_set_local_infile_default - mysql_set_local_infile_handler - mysql_embedded - mysql_server_init - mysql_server_end - mysql_set_character_set - mysql_get_character_set_info - mysql_get_server_name diff --git a/libmysql/libmysql_versions.ld.in b/libmysql/libmysql_versions.ld.in deleted file mode 100644 index 0cf5b45cc18..00000000000 --- a/libmysql/libmysql_versions.ld.in +++ /dev/null @@ -1,33 +0,0 @@ -/* - This version script is heavily inspired by Fedora's and Mageia's version - scripts for MySQL client shared library. - But it was modified to support Debian-compatible versioning too. - - In RedHat universe, symbols from old libmysqlclient.so.16 - keep their libmysqlclient_16 version. New symbols added in - libmysqlclient.so.18 get the new libmysqlclient_18 version. - - In Debian all symbols in libmysqlclient.so.18 have libmysqlclient_18 version, - including symbols that existed in libmysqlclient.so.16 - - We solve this by putting all symbols into libmysqlclient_18 version node, - but creating aliases for old symbols in the libmysqlclient_16 version node. -*/ - -@CLIENT_API_5_1_ALIASES@ - -/* - On Fedora the following symbols are exported, but renamed into a mysql_ - namespace. We export them as aliases, but keep original symbols too. See - MDEV-4127. -*/ -mysql_default_charset_info = default_charset_info; -mysql_get_charset = get_charset; -mysql_get_charset_by_csname = get_charset_by_csname; -mysql_net_realloc = net_realloc; -mysql_client_errors = client_errors; - -@VERSION_HEADER@ -@CLIENT_API_5_1_LIST@ -@CLIENT_API_5_5_LIST@ -@VERSION_FOOTER@ |