diff options
author | unknown <monty@mashka.mysql.fi> | 2002-10-02 13:33:08 +0300 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2002-10-02 13:33:08 +0300 |
commit | 5a28c2caca888be932140d12f87c496398ad4220 (patch) | |
tree | 5a27bda6d3f628af7dcb922ad022e84cf8cb351c /libmysql | |
parent | 9421f1dae99e0f2d6100b31a3641b2cd0ad68e58 (diff) | |
download | mariadb-git-5a28c2caca888be932140d12f87c496398ad4220.tar.gz |
Fixes and code cleanups after merge with 4.0.3
Warning handling and initial prepared statement handling (last not complete yet)
Changed a lot of functions that returned 0/1 to my_bool type.
GRANT handling now uses read/write locks instead of mutex
Change basic net functions to use THD instead of NET
(needed for 4.1 protocol)
Use my_sprintf instead of sprintf() + strlen()
Added alloc_query() to be able to chare query initialization code with
prepared statements.
Cleanup handling of SHOW COUNT(*) WARNINGS and SELECT LAST_INSERT_ID()
Note that the following test fails (will be fixed ASAP):
sub_select, union, rpl_rotate_logs and rpl_mystery22
BitKeeper/deleted/.del-README~3449730baf983117:
Delete: mysql-test/t/README
BitKeeper/deleted/.del-sql_error.cc~2f1caca8d2485dbe:
Delete: libmysqld/sql_error.cc
BitKeeper/deleted/.del-sql_prepare.cc~f703729793935ed6:
Delete: libmysqld/sql_prepare.cc
Docs/manual.texi:
Updated variable list
client/mysql.cc:
Show warning count to user.
client/mysqltest.c:
Add warnings to test results
configure.in:
New shared library version number
include/errmsg.h:
Indentation cleanup
include/mysql.h:
Removed MYSQL_ERROR
Indentaion cleanups
include/mysql_com.h:
Changed functions to returns true/false to my_bool.
include/mysqld_error.h:
New error messages
isam/pack_isam.c:
Indentation change
libmysql/Makefile.am:
Fix of wrong merge
libmysql/Makefile.shared:
Indentation cleanup
libmysql/errmsg.c:
Removed not used errors
libmysql/libmysql.c:
Change functions to return 1 on error (not -1)
Change type of functions that returns 0/1 to my_bool
Lot of code optimizations.
Lot of changes for prepared statements. This now handles sending of binary data to server.
Receving of binary data is not yet done (will have to wait until server code for this is ready)
mysql_warning_count and mysql_warnings() implemented.
libmysql/libmysql.def:
Added mysql_warnings and mysql_warning_count
libmysql/manager.c:
Fixed wrong testing of result from my_connect()
libmysqld/lib_sql.cc:
Removed global variable THR_NET
Change basic net functions to use THD instead of NET
GRANT handling now uses read/write locks instead of mutex
libmysqld/libmysqld.c:
Changed functions to be my_bool
myisam/ft_boolean_search.c:
Trivial code cleanup
myisam/ft_stopwords.c:
Trivial code cleanup
myisam/mi_check.c:
Update to 4.1 structures
myisam/myisampack.c:
Trivial code cleanup
myisam/rt_key.c:
Code cleanup
myisam/rt_test.c:
Code cleanup
Removed compiler warnings
myisam/sp_key.c:
Indentation changes
myisam/sp_test.c:
Removed compiler warnings
mysql-test/README:
Updated to reflect the new --external flag.
mysql-test/mysql-test-run.sh:
--local (start new server) is now default.
Use --external to test against external server.
mysql-test/r/rollback.result:
Updated for 4.1 warnings
mysql-test/r/rpl_log.result:
Update for 4.1
mysql-test/t/rollback.test:
Updated for 4.1 warnings
mysql-test/t/rpl_log_pos.test:
Portability fix
mysys/hash.c:
Indentation change
mysys/my_error.c:
Indentation change
mysys/tree.c:
Updated file description
sql/field.cc:
Fixed bugs introduced by merge
Use my_sprintf instead of sprintf() + strlen()
sql/field.h:
Add CHARSET_INFO to field structure
sql/gstream.h:
Indentation changes.
Added GPL copyright header
sql/ha_innodb.cc:
Updated parameters for net functions.
sql/item.cc:
Updates of Item_param
Indentation changes
sql/item.h:
Removed size_of() function from item.
sql/item_func.cc:
Update function usage for 4.1
Added get_system_var()
sql/item_func.h:
Indentation change
sql/item_strfunc.cc:
Removed not needed inclusion of gstream.h
Update to use system variables (from 4.0)
sql/item_sum.h:
Removed size_of() functions from item.
sql/item_timefunc.cc:
Change sprintf() + strlen() -> my_sprintf()
Added length parameter to ->append()
sql/item_timefunc.h:
Removed size_of() functions from item.
sql/item_uniq.h:
Removed size_of() functions from item.
sql/lex.h:
Removed SQL_ERROR_COUNT variable
sql/log.cc:
Change sprintf() + strlen() -> my_sprintf()
sql/log_event.cc:
Change sprintf() + strlen() -> my_sprintf()
sql/mini_client.cc:
Added check that one always specifies a length to mc_mysql_query()
sql/mysql_priv.h:
New prototypes
Change of NET -> THD parameter for net functions.
sql/mysqld.cc:
New startup options: 'max_prepared_statements', 'max_error_count'
Updated usage of net functions.
sql/net_pkg.cc:
Change basic net functions to use THD instead of NET
(needed to be able to handle 4.0 and 4.1 protocols)
Lots of function comments
sql/net_serv.cc:
Change int return values -> my_bool
Updated net_write_command() to take an extra header block to be added to the packet.
(This made the prepared statement code much nicer and more efficient)
sql/repl_failsafe.cc:
Update net functions to use THD instead of NET
sql/set_var.cc:
Added @@error_count and @@warning_count variables.
Updated to 4.1 function usage
sql/set_var.h:
Added @@error_count and @@warning_count variables.
sql/share/czech/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/english/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/greek/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/hungarian/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/japanese/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/korean/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/norwegian-ny/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/norwegian/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/polish/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/romanian/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/slovak/errmsg.txt:
Removed Warning: from warning error messages.
sql/share/swedish/errmsg.txt:
Removed Warning: from warning error messages.
sql/slave.cc:
Change basic net functions to use THD instead of NET
skip_load_data_file recoded to fit new client/server protocol
sql/spatial.h:
Added copyright header
Indentation cleanups
sql/sql_acl.cc:
Change basic net functions to use THD instead of NET
GRANT handling now uses read/write locks instead of mutex
sql/sql_analyse.cc:
Change basic net functions to use THD instead of NET
sprintf() + strlen() -> my_sprintf()
sql/sql_base.cc:
More DBUG statements
sql/sql_class.cc:
Change basic net functions to use THD instead of NET
warning and prepared statement handling
sql/sql_class.h:
Change basic net functions to use THD instead of NET
warning and prepared statement handling
sql/sql_db.cc:
Code cleanup & optimization.
sql/sql_delete.cc:
Change basic net functions to use THD instead of NET
sql/sql_derived.cc:
Change basic net functions to use THD instead of NET
sql/sql_do.cc:
Change basic net functions to use THD instead of NET
sql/sql_error.cc:
Big rewrite of error handling.
sql/sql_handler.cc:
Change basic net functions to use THD instead of NET
sql/sql_insert.cc:
Change basic net functions to use THD instead of NET
sql/sql_lex.cc:
Change basic net functions to use THD instead of NET
sql/sql_lex.h:
Added param_count to st_select_lex_node
sql/sql_list.h:
Removed not needed error list.
sql/sql_load.cc:
Change basic net functions to use THD instead of NET
sql/sql_parse.cc:
Change basic net functions to use THD instead of NET
Added alloc_query() to be able to chare query initialization code with
prepared statements.
Update of warning handling.
Added create_select_for_variable() (for SHOW COUNT(*) WARNINGS)
sql/sql_prepare.cc:
Initial prepared statement handling
sql/sql_rename.cc:
Change basic net functions to use THD instead of NET
sql/sql_repl.cc:
Change basic net functions to use THD instead of NET
sql/sql_select.cc:
Small code cleanups
Added missing initialization of error that caused some queries that returned an empty result set to fail
sql/sql_select.h:
Ensure that JOIN.error is properly initialized
sql/sql_show.cc:
Change basic net functions to use THD instead of NET
A lot of optimization
sql/sql_table.cc:
Change basic net functions to use THD instead of NET
Indentaion cleanup
sql/sql_udf.cc:
Change basic net functions to use THD instead of NET
sql/sql_union.cc:
Change basic net functions to use THD instead of NET
sql/sql_update.cc:
Change basic net functions to use THD instead of NET
sql/sql_yacc.yy:
Change basic net functions to use THD instead of NET
Cleanup handling of SHOW COUNT(*) WARNINGS and SELECT LAST_INSERT_ID()
sql/structs.h:
Moved structures to files where they was used
sql/table.cc:
Don't accept empty database names
sql/uniques.cc:
Indentation cleanup
sql/unireg.cc:
Change basic net functions to use THD instead of NET
sql/unireg.h:
Added defaults for warnings and prepared statements
strings/ctype-simple.c:
optimization
tests/client_test.c:
Fixed wrong paramaters to printf()
Diffstat (limited to 'libmysql')
-rw-r--r-- | libmysql/Makefile.am | 4 | ||||
-rw-r--r-- | libmysql/Makefile.shared | 5 | ||||
-rw-r--r-- | libmysql/errmsg.c | 18 | ||||
-rw-r--r-- | libmysql/libmysql.c | 1475 | ||||
-rw-r--r-- | libmysql/libmysql.def | 4 | ||||
-rw-r--r-- | libmysql/manager.c | 2 |
6 files changed, 640 insertions, 868 deletions
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index fac544ba44d..3d380c14076 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -49,10 +49,6 @@ link_sources: rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ done; \ - for f in $(mystringsgen); do \ - rm -f $(srcdir)/$$f; \ - @LN_CP_F@ ../strings/$$f $(srcdir)/$$f; \ - done; \ for f in $$qs; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index a1020709d22..0f7cb713d54 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -39,9 +39,10 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \ strtoull.lo strtoll.lo llstr.lo \ ctype.lo ctype-simple.lo ctype-mb.lo \ - ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo ctype-win1250ch.lo\ + ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \ + ctype-win1250ch.lo ctype-utf8.lo \ ctype-gb2312.lo ctype-gbk.lo ctype-latin1_de.lo \ - ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo ctype-utf8.lo + ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo mystringsextra= strto.c dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index f1cf667f774..581bb184ff3 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -52,15 +52,13 @@ const char *client_errors[]= "Error connecting to master:", "Invalid connection handle", "Invalid use of null pointer", - "Memory allocation error", "Statement not prepared", "Not all parameters data supplied", "Data truncated", - "Not all parameters bound for the row fetch", - "Failed to send the parameter data", "No parameters exists in the statement", "Invalid parameter number", - "Can't send long data for non string or binary data types" + "Can't send long data for non string or binary data types (parameter: %d)", + "Using not supported parameter type: %d (parameter: %d)" }; /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ @@ -96,15 +94,13 @@ const char *client_errors[]= "Error connecting to master:", "Invalid connection handle", "Invalid use of null pointer", - "Memory allocation error", "Statement not prepared", "Not all parameters data supplied", "Data truncated", - "Not all parameters bound for the row fetch", - "Failed to send the parameter data", "No parameters exists in the statement", "Invalid parameter number", - "Can't send long data for non string or binary data types" + "Can't send long data for non string or binary data types (parameter: %d)", + "Using not supported parameter type: %d (parameter: %d)" }; #else /* ENGLISH */ @@ -138,15 +134,13 @@ const char *client_errors[]= "Error connecting to master:", "Invalid connection handle", "Invalid use of null pointer", - "Memory allocation error", "Statement not prepared", "Not all parameters data supplied", "Data truncated", - "Not all parameters bound for the row fetch", - "Failed to send the parameter data", "No parameters exists in the statement", "Invalid parameter number", - "Can't send long data for non string or binary data types" + "Can't send long data for non string or binary data types (parameter: %d)", + "Using not supported parameter type: %d (parameter: %d)" }; #endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 052907d8c28..16fecc8038f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -31,6 +31,7 @@ #include <sys/stat.h> #include <signal.h> #include <time.h> +#include <assert.h> /* for DBUG_ASSERT() */ #ifdef HAVE_PWD_H #include <pwd.h> #endif @@ -56,8 +57,6 @@ #define INADDR_NONE -1 #endif -#include <assert.h> /* for DBUG_ASSERT() */ - static my_bool mysql_client_init=0; uint mysql_port=0; my_string mysql_unix_port=0; @@ -66,9 +65,9 @@ ulong max_allowed_packet=16*1024*1024L; ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; -#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG\ - | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS\ - | CLIENT_PROTOCOL_41) +#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \ + | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \ + | CLIENT_PROTOCOL_41) #ifdef __WIN__ @@ -85,10 +84,11 @@ ulong net_write_timeout= NET_WRITE_TIMEOUT; #define SOCKET_ERROR -1 #endif /* __WIN__ */ -#define MAX_LONG_DATA_LENGTH 8192 /* if allowed through some - configuration, then this needs to - be changed - */ +/* + If allowed through some configuration, then this needs to + be changed +*/ +#define MAX_LONG_DATA_LENGTH 8192 #define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) #define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG) @@ -101,7 +101,7 @@ static void end_server(MYSQL *mysql); static void read_user_name(char *name); static void append_wild(char *to,char *end,const char *wild); static my_bool mysql_reconnect(MYSQL *mysql); -static int send_file_to_server(MYSQL *mysql,const char *filename); +static my_bool send_file_to_server(MYSQL *mysql,const char *filename); static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); @@ -160,7 +160,7 @@ static MYSQL* spawn_init(MYSQL* parent, const char* host, /**************************************************************************** - A modified version of connect(). connect2() allows you to specify + A modified version of connect(). my_connect() allows you to specify a timeout value, in seconds, that we should wait until we derermine we can't connect to a particular host. If timeout is 0, my_connect() will behave exactly like connect(). @@ -168,11 +168,11 @@ static MYSQL* spawn_init(MYSQL* parent, const char* host, Base version coded by Steve Bernacki, Jr. <steve@navinet.net> *****************************************************************************/ -int my_connect(my_socket s, const struct sockaddr *name, uint namelen, - uint timeout) +my_bool my_connect(my_socket s, const struct sockaddr *name, + uint namelen, uint timeout) { #if defined(__WIN__) || defined(OS2) - return connect(s, (struct sockaddr*) name, namelen); + return connect(s, (struct sockaddr*) name, namelen) != 0; #else int flags, res, s_err; SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint); @@ -185,7 +185,7 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, */ if (timeout == 0) - return connect(s, (struct sockaddr*) name, namelen); + return connect(s, (struct sockaddr*) name, namelen) != 0; flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */ #ifdef O_NONBLOCK @@ -198,7 +198,7 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, if ((res != 0) && (s_err != EINPROGRESS)) { errno = s_err; /* Restore it */ - return(-1); + return(1); } if (res == 0) /* Connected quickly! */ return(0); @@ -243,7 +243,7 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, now_time=time(NULL); timeout-= (uint) (now_time - start_time); if (errno != EINTR || (int) timeout <= 0) - return -1; + return 1; } /* select() returned something more interesting than zero, let's @@ -253,12 +253,12 @@ int my_connect(my_socket s, const struct sockaddr *name, uint namelen, s_err=0; if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) - return(-1); + return(1); if (s_err) { /* getsockopt could succeed */ errno = s_err; - return(-1); /* but return an error... */ + return(1); /* but return an error... */ } return(0); /* It's all good! */ #endif @@ -464,44 +464,45 @@ static void free_rows(MYSQL_DATA *cur) } -int -simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, - ulong length, my_bool skipp_check) +static my_bool +advanced_command(MYSQL *mysql, enum enum_server_command command, + const char *header, ulong header_length, + const char *arg, ulong arg_length, my_bool skip_check) { NET *net= &mysql->net; - int result= -1; + my_bool result= 1; init_sigpipe_variables /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); + if (mysql->net.vio == 0) { /* Do reconnect if possible */ if (mysql_reconnect(mysql)) - goto end; + return 1; } if (mysql->status != MYSQL_STATUS_READY) { strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); - goto end; + return 1; } mysql->net.last_error[0]=0; mysql->net.last_errno=0; mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; - net_clear(net); /* Clear receive buffer */ - if (!arg) - arg=""; + net_clear(&mysql->net); /* Clear receive buffer */ - if (net_write_command(net,(uchar) command,arg, - length ? length : (ulong) strlen(arg))) + if (net_write_command(net,(uchar) command, header, header_length, + arg, arg_length)) { - DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno)); + DBUG_PRINT("error",("Can't send command to server. Error: %d", + socket_errno)); end_server(mysql); if (mysql_reconnect(mysql)) goto end; - if (net_write_command(net,(uchar) command,arg, - length ? length : (ulong) strlen(arg))) + if (net_write_command(net,(uchar) command, header, header_length, + arg, arg_length)) { net->last_errno=CR_SERVER_GONE_ERROR; strmov(net->last_error,ER(net->last_errno)); @@ -509,15 +510,23 @@ simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, } } result=0; - if (!skipp_check) + if (!skip_check) result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ? - -1 : 0); + 1 : 0); end: reset_sigpipe(mysql); return result; } +my_bool +simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + ulong length, my_bool skip_check) +{ + return advanced_command(mysql, command, NullS, 0, arg, length, skip_check); +} + + static void free_old_query(MYSQL *mysql) { DBUG_ENTER("free_old_query"); @@ -529,6 +538,7 @@ static void free_old_query(MYSQL *mysql) DBUG_VOID_RETURN; } + #if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL) struct passwd *getpwuid(uid_t); char* getlogin(void); @@ -606,7 +616,6 @@ append_wild(char *to, char *end, const char *wild) } - /************************************************************************** Init debugging if MYSQL_DEBUG environment variable is found **************************************************************************/ @@ -691,13 +700,13 @@ mysql_free_result(MYSQL_RES *result) { if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) { - DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows")); + DBUG_PRINT("warning",("Not all rows in set where read; Ignoring rows")); for (;;) { ulong pkt_len; if ((pkt_len=net_safe_read(result->handle)) == packet_error) break; - if (pkt_len == 1 && result->handle->net.read_pos[0] == 254) + if (pkt_len <= 8 && result->handle->net.read_pos[0] == 254) break; /* End of data */ } result->handle->status=MYSQL_STATUS_READY; @@ -906,9 +915,11 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field=result=(MYSQL_FIELD*) alloc_root(alloc, (uint) sizeof(MYSQL_FIELD)*fields); if (!result) + { + free_rows(data); /* Free old data */ DBUG_RETURN(0); - - if(server_capabilities & CLIENT_PROTOCOL_41) + } + if (server_capabilities & CLIENT_PROTOCOL_41) { /* server is 4.1, and returns the new field result format */ for (row=data->data; row ; row = row->next,field++) @@ -933,8 +944,10 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->max_length= 0; } } - else /* old ones, for backward compatibility */ +#ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL + else { + /* old protocol, for backward compatibility */ for (row=data->data; row ; row = row->next,field++) { field->org_table= field->table= strdup_root(alloc,(char*) row->data[0]); @@ -961,6 +974,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->max_length= 0; } } +#endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */ free_rows(data); /* Free old data */ DBUG_RETURN(result); } @@ -996,14 +1010,22 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, result->rows=0; result->fields=fields; - while (*(cp=net->read_pos) != 254 || pkt_len != 1) + /* + The last EOF packet is either a single 254 character or (in MySQL 4.1) + 254 followed by 1-7 status bytes. + + This doesn't conflict with normal usage of 254 which stands for a + string where the length of the string is 8 bytes. (see net_field_length()) + */ + + while (*(cp=net->read_pos) != 254 || pkt_len >= 8) { result->rows++; if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, - sizeof(MYSQL_ROWS))) || + sizeof(MYSQL_ROWS))) || !(cur->data= ((MYSQL_ROW) alloc_root(&result->alloc, - (fields+1)*sizeof(char *)+pkt_len)))) + (fields+1)*sizeof(char *)+pkt_len)))) { free_rows(result); net->last_errno=CR_OUT_OF_MEMORY; @@ -1040,6 +1062,11 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, } } *prev_ptr=0; /* last pointer is null */ + if (pkt_len > 1) /* MySQL 4.1 protocol */ + { + mysql->warning_count= uint2korr(cp+1); + DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count)); + } DBUG_PRINT("exit",("Got %d rows",result->rows)); DBUG_RETURN(result); } @@ -1060,8 +1087,12 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) if ((pkt_len=net_safe_read(mysql)) == packet_error) return -1; - if (pkt_len == 1 && mysql->net.read_pos[0] == 254) + if (pkt_len <= 8 && mysql->net.read_pos[0] == 254) + { + if (pkt_len > 1) /* MySQL 4.1 protocol */ + mysql->warning_count= uint2korr(mysql->net.read_pos+1); return 1; /* End of data */ + } prev_pos= 0; /* allowed to write at packet[-1] */ pos=mysql->net.read_pos; for (field=0 ; field < fields ; field++) @@ -1087,7 +1118,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) } /* perform query on master */ -int STDCALL mysql_master_query(MYSQL *mysql, const char *q, +my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q, unsigned long length) { if (mysql_master_send_query(mysql, q, length)) @@ -1095,8 +1126,8 @@ int STDCALL mysql_master_query(MYSQL *mysql, const char *q, return mysql_read_query_result(mysql); } -int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, - unsigned long length) +my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned long length) { MYSQL*master = mysql->master; if (!length) @@ -1109,15 +1140,16 @@ int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, /* perform query on slave */ -int STDCALL mysql_slave_query(MYSQL *mysql, const char *q, - unsigned long length) +my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q, + unsigned long length) { if (mysql_slave_send_query(mysql, q, length)) return 1; return mysql_read_query_result(mysql); } -int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, + +my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, unsigned long length) { MYSQL* last_used_slave, *slave_to_use = 0; @@ -1169,7 +1201,7 @@ void STDCALL mysql_disable_reads_from_master(MYSQL* mysql) } /* get the value of the master read flag */ -int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql) +my_bool STDCALL mysql_reads_from_master_enabled(MYSQL* mysql) { return !(mysql->options.no_master_reads); } @@ -1198,7 +1230,7 @@ static void expand_error(MYSQL* mysql, int error) read the given result and row */ -static int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row) +static my_bool get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row) { MYSQL* master; DBUG_ENTER("get_master"); @@ -1218,11 +1250,11 @@ static int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row) retrieve all the slaves */ -static int get_slaves_from_master(MYSQL* mysql) +static my_bool get_slaves_from_master(MYSQL* mysql) { MYSQL_RES* res = 0; MYSQL_ROW row; - int error = 1; + my_bool error = 1; int has_auth_info; int port_ind; DBUG_ENTER("get_slaves_from_master"); @@ -1285,11 +1317,11 @@ err: } -int STDCALL mysql_rpl_probe(MYSQL* mysql) +my_bool STDCALL mysql_rpl_probe(MYSQL* mysql) { MYSQL_RES *res= 0; MYSQL_ROW row; - int error = 1; + my_bool error= 1; DBUG_ENTER("mysql_rpl_probe"); /* @@ -1473,7 +1505,7 @@ static void mysql_once_init() #define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME)) -int STDCALL +my_bool STDCALL mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , const char *key __attribute__((unused)), const char *cert __attribute__((unused)), @@ -1497,7 +1529,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , NB! Errors are not reported until you do mysql_real_connect. **************************************************************************/ -static int +static void mysql_ssl_free(MYSQL *mysql __attribute__((unused))) { #ifdef HAVE_OPENSSL @@ -1515,7 +1547,6 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused))) mysql->options.use_ssl = FALSE; mysql->connector_fd = 0; #endif /* HAVE_OPENSSL */ - return 0; } /************************************************************************** @@ -1635,7 +1666,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, UNIXaddr.sun_family = AF_UNIX; strmov(UNIXaddr.sun_path, unix_socket); if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), - mysql->options.connect_timeout) <0) + mysql->options.connect_timeout)) { DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno)); net->last_errno=CR_CONNECTION_ERROR; @@ -2264,7 +2295,7 @@ mysql_send_query(MYSQL* mysql, const char* query, ulong length) } -int STDCALL mysql_read_query_result(MYSQL *mysql) +my_bool STDCALL mysql_read_query_result(MYSQL *mysql) { uchar *pos; ulong field_count; @@ -2272,13 +2303,14 @@ int STDCALL mysql_read_query_result(MYSQL *mysql) ulong length; DBUG_ENTER("mysql_read_query_result"); - /* read from the connection which we actually used, which - could differ from the original connection if we have slaves - */ + /* + Read from the connection which we actually used, which + could differ from the original connection if we have slaves + */ mysql = mysql->last_used_con; if ((length = net_safe_read(mysql)) == packet_error) - DBUG_RETURN(-1); + DBUG_RETURN(1); free_old_query(mysql); /* Free old result */ get_info: pos=(uchar*) mysql->net.read_pos; @@ -2286,10 +2318,18 @@ get_info: { mysql->affected_rows= net_field_length_ll(&pos); mysql->insert_id= net_field_length_ll(&pos); - if (mysql->server_capabilities & CLIENT_TRANSACTIONS) + if (mysql->server_capabilities & CLIENT_PROTOCOL_41) { mysql->server_status=uint2korr(pos); pos+=2; + mysql->warning_count=uint2korr(pos); pos+=2; } + else if (mysql->server_capabilities & CLIENT_TRANSACTIONS) + { + mysql->server_status=uint2korr(pos); pos+=2; + mysql->warning_count= 0; + } + DBUG_PRINT("info",("status: %ld warning_count: %ld", + mysql->server_status, mysql->warning_count)); if (pos < mysql->net.read_pos+length && net_field_length(&pos)) mysql->info=(char*) pos; DBUG_RETURN(0); @@ -2298,7 +2338,7 @@ get_info: { int error=send_file_to_server(mysql,(char*) pos); if ((length=net_safe_read(mysql)) == packet_error || error) - DBUG_RETURN(-1); + DBUG_RETURN(1); goto get_info; /* Get info packet */ } if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) @@ -2306,14 +2346,15 @@ get_info: mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ - if (!(fields=read_rows(mysql,(MYSQL_FIELD*)0,protocol_41(mysql) ? 8:5))) - DBUG_RETURN(-1); + if (!(fields=read_rows(mysql,(MYSQL_FIELD*)0, (protocol_41(mysql) ? 8 : 5)))) + DBUG_RETURN(1); if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, (uint) field_count,0, mysql->server_capabilities))) - DBUG_RETURN(-1); - mysql->status=MYSQL_STATUS_GET_RESULT; + DBUG_RETURN(1); + mysql->status= MYSQL_STATUS_GET_RESULT; mysql->field_count= (uint) field_count; + mysql->warning_count= 0; DBUG_RETURN(0); } @@ -2326,15 +2367,16 @@ mysql_real_query(MYSQL *mysql, const char *query, ulong length) DBUG_PRINT("query",("Query = \"%s\"",query)); if (mysql_send_query(mysql,query,length)) - DBUG_RETURN(-1); - DBUG_RETURN(mysql_read_query_result(mysql)); + DBUG_RETURN(1); + DBUG_RETURN((int) mysql_read_query_result(mysql)); } -static int +static my_bool send_file_to_server(MYSQL *mysql, const char *filename) { - int fd, readcount, result= -1; + int fd, readcount; + my_bool result= 1; uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE); char *buf, tmp_name[FN_REFLEN]; DBUG_ENTER("send_file_to_server"); @@ -2342,7 +2384,7 @@ send_file_to_server(MYSQL *mysql, const char *filename) if (!(buf=my_malloc(packet_length,MYF(0)))) { strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY)); - DBUG_RETURN(-1); + DBUG_RETURN(1); } fn_format(tmp_name,filename,"","",4); /* Convert to client format */ @@ -2675,7 +2717,8 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128); if (simple_command(mysql,COM_FIELD_LIST,buff,(ulong) (end-buff),1) || - !(query = read_rows(mysql,(MYSQL_FIELD*)0,protocol_41(mysql) ? 9:6))) + !(query = read_rows(mysql,(MYSQL_FIELD*) 0, + (protocol_41(mysql) ? 9 : 6)))) DBUG_RETURN(NULL); free_old_query(mysql); @@ -2689,11 +2732,13 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) mysql->fields=0; result->field_count = (uint) query->rows; result->fields= unpack_fields(query,&result->field_alloc, - result->field_count,1,mysql->server_capabilities); + result->field_count, 1, + mysql->server_capabilities); result->eof=1; DBUG_RETURN(result); } + /* List all running processes (threads) in server */ MYSQL_RES * STDCALL @@ -2869,7 +2914,7 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg) mysql->options.charset_name=my_strdup(arg,MYF(MY_WME)); break; default: - DBUG_RETURN(-1); + DBUG_RETURN(1); } DBUG_RETURN(0); } @@ -2942,6 +2987,11 @@ const char * STDCALL mysql_error(MYSQL *mysql) return mysql->net.last_error; } +uint STDCALL mysql_warning_count(MYSQL *mysql) +{ + return mysql->warning_count; +} + const char *STDCALL mysql_info(MYSQL *mysql) { return mysql->info; @@ -2967,6 +3017,18 @@ uint STDCALL mysql_thread_safe(void) #endif } +MYSQL_RES *STDCALL mysql_warnings(MYSQL *mysql) +{ + uint warning_count; + DBUG_ENTER("mysql_warnings"); + /* Save warning count as mysql_real_query may change this */ + warning_count= mysql->warning_count; + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) + DBUG_RETURN(0); + mysql->warning_count= warning_count; + DBUG_RETURN(mysql_store_result(mysql)); +} + /**************************************************************************** Some support functions ****************************************************************************/ @@ -3170,7 +3232,6 @@ myodbc_remove_escape(MYSQL *mysql,char *name) Implementation of new client-server prototypes for 4.1 version starts from here .. - my_* and genaral function names are internal implementations mysql_* are real prototypes used by applications *********************************************************************/ @@ -3180,212 +3241,169 @@ myodbc_remove_escape(MYSQL *mysql,char *name) ********************************************************************/ /* - Set the internal stmt error messages + Set the internal stmt error messages */ static void set_stmt_error(MYSQL_STMT * stmt, int errcode) { DBUG_ENTER("set_stmt_error"); - DBUG_PRINT("enter", ("error :[%d][%s]", errcode, ER(errcode))); + DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode))); DBUG_ASSERT(stmt != 0); - stmt->err_no = errcode; - strmov(stmt->error, ER(errcode)); + stmt->last_errno= errcode; + strmov(stmt->last_error, ER(errcode)); DBUG_VOID_RETURN; } + /* - Copy error message to statement handler + Copy error message to statement handler */ static void set_stmt_errmsg(MYSQL_STMT * stmt, char *err, int errcode) { DBUG_ENTER("set_stmt_error_msg"); - DBUG_PRINT("enter", ("error :[%d][%s]", errcode, err)); + DBUG_PRINT("enter", ("error: %d '%s'", errcode, err)); DBUG_ASSERT(stmt != 0); - stmt->err_no = errcode; - + stmt->last_errno= errcode; if (err && err[0]) - strmov(stmt->error, err); + strmov(stmt->last_error, err); DBUG_VOID_RETURN; } + /* - Set the internal error message to mysql handler + Set the internal error message to mysql handler */ static void set_mysql_error(MYSQL * mysql, int errcode) { DBUG_ENTER("set_mysql_error"); - DBUG_PRINT("enter", ("error :[%d][%s]", errcode, ER(errcode))); + DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode))); DBUG_ASSERT(mysql != 0); - mysql->net.last_errno = errcode; + mysql->net.last_errno= errcode; strmov(mysql->net.last_error, ER(errcode)); } -/* - Return the duplicate string by allocating the memory -*/ - -static char *my_dupp_str(const char *from, int length) -{ - char *str; - - if ((str = my_malloc(length + 1, MYF(MY_WME)))) - { - memcpy(str, from, length); - str[length] = 0; - } - return str; -} - /* - Return the reallocted string -*/ + Reallocate the NET package to be at least of 'length' bytes -static char *my_realloc_str(NET *net, int length) -{ - char *from = net->buff; - ulong nead = net->buf_length + length; - DBUG_ENTER("my_realloc_str"); + SYNPOSIS + my_realloc_str() + net The NET structure to modify + int length Ensure that net->buff is at least this big - if ( nead > net->max_packet ) - { - char *new_buff; - ulong pkt_length = nead + 8192; - - if (pkt_length > max_allowed_packet) - { - DBUG_PRINT("error",("Needed %ld but max_allowed_packet is %ld", - pkt_length,max_allowed_packet)); - DBUG_RETURN(0); - } - if (!(new_buff = (char *)my_realloc(from, pkt_length, MYF(MY_WME)))) - DBUG_RETURN(0); + RETURN VALUES + 0 ok + 1 Error - net->max_packet = pkt_length; - DBUG_RETURN(new_buff); - } - DBUG_RETURN(from); -} - -/* - Return the type length */ -static ulong return_result_length(uint field_type, ulong length) +static my_bool my_realloc_str(NET *net, ulong length) { - switch (field_type) { - case MYSQL_TYPE_TINY: - return 1; - case MYSQL_TYPE_SHORT: - return 2; - case MYSQL_TYPE_INT24: - return 3; - case MYSQL_TYPE_LONG: - return 4; - case MYSQL_TYPE_LONGLONG: - return 8; - case MYSQL_TYPE_FLOAT: - return 4; - case MYSQL_TYPE_DOUBLE: - return 8; - default: - return length; - } -} - -/* - Get the parameter count value -*/ - -static ulong my_get_param_count(MYSQL *mysql) -{ - uchar *pos; - - mysql = mysql->last_used_con; - - if (net_safe_read(mysql) == packet_error) - return 0; - - pos=(uchar*) mysql->net.read_pos; - if (!net_field_length(&pos)) + 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) { - return (ulong)net_field_length(&pos); + res= net_realloc(net, buf_length + length); + net->write_pos= net->buff+ buf_length; } - return 0; + DBUG_RETURN(res); } /******************************************************************** - Prepare related implementations + Prepare related implementations ********************************************************************/ /* Read the prepare statement results .. + + NOTE + This is only called for connection to servers that supports + prepared statements (and thus the 4.1 protocol) + + RETURN VALUES + 0 ok + 1 error */ -int my_read_prepare_result(MYSQL *mysql,MYSQL_STMT *stmt) +static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) { uchar *pos; - ulong field_count; + uint field_count; MYSQL_DATA *fields_data; ulong length; + DBUG_ENTER("read_prepare_result"); - DBUG_ENTER("my_read_prepare_result"); + mysql= mysql->last_used_con; + if ((length= net_safe_read(mysql)) == packet_error) + DBUG_RETURN(1); - mysql = mysql->last_used_con; + pos=(uchar*) mysql->net.read_pos; + stmt->stmt_id= uint4korr(pos); pos+=4; + field_count= uint2korr(pos); pos+=2; + stmt->param_count=uint2korr(pos); pos+=2; - if ((length = net_safe_read(mysql)) == packet_error) - DBUG_RETURN(-1); - - if (stmt->fields) - free_root(&stmt->mem_root,MYF(0)); - init_alloc_root(&stmt->mem_root,8192,0); - stmt->fields=0; - stmt->field_count=0; + if (field_count != 0) + { + if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) + mysql->server_status|= SERVER_STATUS_IN_TRANS; - pos=(uchar*) mysql->net.read_pos; - if ((field_count= net_field_length(&pos)) == 0) + mysql->extra_info= net_field_length_ll(&pos); + if (!(fields_data= read_rows(mysql, (MYSQL_FIELD*) 0, 8))) + DBUG_RETURN(1); + if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, + field_count,0, + mysql->server_capabilities))) + DBUG_RETURN(1); + } + if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root, + sizeof(MYSQL_BIND)* + (stmt->param_count + + field_count)))) { - stmt->param_count= (ulong)net_field_length_ll(&pos); + set_stmt_error(stmt, CR_OUT_OF_MEMORY); DBUG_RETURN(0); } - if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) - mysql->server_status|= SERVER_STATUS_IN_TRANS; - - mysql->extra_info= net_field_length_ll(&pos); - - if (!(fields_data=read_rows(mysql,(MYSQL_FIELD*)0,protocol_41(mysql) ? 8:5))) - DBUG_RETURN(-1); - - if (!(stmt->fields=unpack_fields(fields_data,&stmt->mem_root, - (uint) field_count,0, - mysql->server_capabilities))) - DBUG_RETURN(-1); - mysql->status = MYSQL_STATUS_READY; - stmt->field_count= (uint) field_count; + stmt->bind= (stmt->params + stmt->param_count); + stmt->field_count= (uint) field_count; + mysql->status= MYSQL_STATUS_READY; DBUG_RETURN(0); } /* - Prepare the query and return the new statement handle to - caller. - - Also update the total parameter count along with resultset - metadata information by reading from server + Prepare the query and return the new statement handle to + caller. + + Also update the total parameter count along with resultset + metadata information by reading from server */ -MYSQL_STMT *STDCALL -mysql_real_prepare(MYSQL *mysql, const char *query, ulong length) +/* QQ The follwing function will be removed after next merge */ + +static char *my_strdup_with_length(const byte *from, uint length, myf MyFlags) +{ + gptr ptr; + if ((ptr=my_malloc(length+1,MyFlags)) != 0) + { + memcpy((byte*) ptr, (byte*) from,(size_t) length); + ((char*) ptr)[length]=0; + } + return((char*) ptr); +} + + +MYSQL_STMT *STDCALL +mysql_prepare(MYSQL *mysql, const char *query, ulong length) { MYSQL_STMT *stmt; - DBUG_ENTER("mysql_real_prepare"); DBUG_ASSERT(mysql != 0); @@ -3397,59 +3415,39 @@ mysql_real_prepare(MYSQL *mysql, const char *query, ulong length) } #endif - if (simple_command(mysql, COM_PREPARE, query, length, 1)) + if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT), + MYF(MY_WME | MY_ZEROFILL))) || + !(stmt->query= my_strdup_with_length((byte *) query, length, MYF(0)))) + { + my_free((gptr) stmt, MYF(MY_ALLOW_ZERO_PTR)); + set_mysql_error(mysql, CR_OUT_OF_MEMORY); DBUG_RETURN(0); - - if (!(stmt = (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT), - MYF(MY_WME | MY_ZEROFILL))) || - !(stmt->query = my_dupp_str((char *)query, length))) - { - my_free((gptr)stmt, MY_ALLOW_ZERO_PTR); - set_mysql_error(mysql, CR_MEMORY_ERROR); + } + if (simple_command(mysql, COM_PREPARE, query, length, 1)) + { + mysql_stmt_close(stmt); DBUG_RETURN(0); } + stmt->state= MY_ST_PREPARE; - DBUG_ASSERT(stmt != 0); - - if (my_read_prepare_result(mysql,stmt)) + init_alloc_root(&stmt->mem_root,8192,0); + if (read_prepare_result(mysql, stmt)) { - my_free((gptr)stmt, MYF(MY_WME)); + mysql_stmt_close(stmt); DBUG_RETURN(0); } - - if (stmt->fields) - stmt->param_count = my_get_param_count(mysql); - - stmt->mysql = mysql; - stmt->state = MY_ST_PREPARE; - stmt->err_no = 0; - stmt->types_supplied = 0; - + + stmt->mysql= mysql; DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count)); DBUG_RETURN(stmt); } -/* - Prepare the query and return the new statement handle to - caller. - - Also update the total parameter count along with resultset - metadata information by reading from server -*/ - -MYSQL_STMT *STDCALL mysql_prepare(MYSQL *mysql, const char *query) -{ - DBUG_ENTER("mysql_prepare"); - DBUG_ASSERT(query != 0); - DBUG_RETURN(mysql_real_prepare(mysql,query,strlen(query))); -} /* Returns prepared meta information in the form of resultset - to client.. + to client. */ - MYSQL_RES * STDCALL mysql_prepare_result(MYSQL_STMT *stmt) { @@ -3458,349 +3456,279 @@ mysql_prepare_result(MYSQL_STMT *stmt) if (!stmt->fields) DBUG_RETURN(0); - - /* Will be freed during mysql_stmt_close as the prepare - meta info should live till the stmt life - */ - if (!(result=(MYSQL_RES*) alloc_root(&stmt->mem_root, - (uint) (sizeof(MYSQL_RES)+ sizeof(ulong) * - stmt->field_count)))) - { - set_stmt_error(stmt, CR_MEMORY_ERROR); - DBUG_RETURN(0); - } + result= &stmt->tmp_result; bzero((char*) result, sizeof(MYSQL_RES)); - result->eof=1; /* Marker for buffered */ - result->lengths=(ulong*) (result+1); - result->row_count= 0; - result->fields= stmt->fields; - result->field_count= stmt->field_count; - DBUG_RETURN(result); + result->eof=1; /* Marker for buffered */ + result->fields= stmt->fields; + result->field_count= stmt->field_count; + DBUG_RETURN(result); } + /******************************************************************** Prepare-execute, and param handling *********************************************************************/ - -/* - Store the buffer type +/* + Store the buffer type */ -static void my_store_param_type(NET *net, uint type) +static void store_param_type(NET *net, uint type) { - int2store(net->buff+net->buf_length, type); - net->buf_length+=2; + int2store(net->write_pos, type); + net->write_pos+=2; } -/* +/* Store the length of parameter data + (Same function as in sql/net_pkg.cc) */ -static char * my_store_param_length(char *pkg, ulong length) + +char * +net_store_length(char *pkg, ulong length) { uchar *packet=(uchar*) pkg; - if (length < 251) { *packet=(uchar) length; return (char*) packet+1; } - *packet++ = 252; - int2store(packet,(uint) length); - return (char*) packet+2; + /* 251 is reserved for NULL */ + if (length < 65536L) + { + *packet++=252; + int2store(packet,(uint) length); + return (char*) packet+2; + } + if (length < 16777216L) + { + *packet++=253; + int3store(packet,(ulong) length); + return (char*) packet+3; + } + *packet++=254; + int8store(packet, (ulonglong) length); + return (char*) packet+9; } -/* - Store the integer data -*/ -static bool my_store_param_long(NET *net, longlong *data, uint length) -{ - char *packet; +/**************************************************************************** + Functions to store parameter data from a prepared statement. - if (!(net->buff = my_realloc_str(net, net->buf_length + length + 1))) - return 1; + All functions has the following characteristics: - packet = (char *)net->buff+net->buf_length; - - switch(length) { - case 1: - { - char value = (char)*data; - *packet = value; - } - break; - case 2: - { - short value = (short)*data; - int2store(packet,value); - } - break; - case 3: - { - int value = (int)*data; - int3store(packet,value); - } - break; - case 4: - { - long value = (long)*data; - int4store(packet, value); - } - break; - default: - { - longlong value = (longlong)*data; - int8store(packet, value); - } - } - net->buf_length += length; - return 0; + SYNOPSIS + store_param_xxx() + net MySQL NET connection + param MySQL bind param + + RETURN VALUES + 0 ok + 1 Error (Can't alloc net->buffer) +****************************************************************************/ + + +static void store_param_tinyint(NET *net, MYSQL_BIND *param) +{ + *(net->write_pos++)= (uchar) *param->buffer; } -/* - Store the float data -*/ +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 bool my_store_param_double(NET *net, double *data, uint length) +static void store_param_int32(NET *net, MYSQL_BIND *param) { - char *packet; + int32 value= *(int32*) param->buffer; + int4store(net->write_pos,value); + net->write_pos+=4; +} - if (!(net->buff = my_realloc_str(net, net->buf_length + length + 1))) - return 1; +static void store_param_int64(NET *net, MYSQL_BIND *param) +{ + longlong value= *(longlong*) param->buffer; + int8store(net->write_pos,value); + net->write_pos+= 8; +} - packet = (char *)net->buff+net->buf_length; - if (length == 4) - { - float value = (float)*data; - float4store(packet, value); - } - else - { - double value = (double)*data; - float8store(packet, value); - } - net->buf_length += length; - return 0; +static void store_param_float(NET *net, MYSQL_BIND *param) +{ + float value= *(float*) param->buffer; + float4store(net->write_pos, value); + net->write_pos+= 4; } -/* - Store NULL data -*/ +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 my_bool my_store_param_null(NET * net) +static void store_param_str(NET *net, MYSQL_BIND *param) { - if (!(net->buff = my_realloc_str(net, net->buf_length + 1))) - return 1; /* Signal error */ - - net->buff[net->buf_length++] = (char)251; - return 0; + ulong length= *param->length; + char *to= (char *) net_store_length((char *) net->write_pos, length); + memcpy(to, param->buffer, length); + net->write_pos+= length; } + /* - Store string and binary data + 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 */ -static my_bool my_store_param_str(NET * net, const char *from, uint length) +static void store_param_null(NET *net, MYSQL_BIND *param) { - char *to; + uint pos= param->param_number; + (uchar) net->buff[pos/8]|= (1 << pos & 7); +} - if (!(net->buff = my_realloc_str(net, net->buf_length + 5 + length))) - return 1; - to = (char *)my_store_param_length((char *)net->buff + net->buf_length, - (ulong) length); - memcpy(to, from, length); - net->buf_length = (ulong) ((char *)(to + length) - (char *)(net->buff)); - return 0; -} - - /* Set parameter data by reading from input buffers from the - client application + client application */ -static my_bool my_store_param(MYSQL_STMT * stmt, MYSQL_BIND * param) +static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) { - MYSQL *mysql = stmt->mysql; - NET *net = &mysql->net; - - DBUG_ENTER("my_store_param"); + MYSQL *mysql= stmt->mysql; + NET *net = &mysql->net; + DBUG_ENTER("store_param"); DBUG_PRINT("enter",("type : %d, buffer :%lx", param->buffer_type, param->buffer)); - if (!stmt->types_supplied) - my_store_param_type(net, (uint)param->buffer_type); - - if (!param->buffer) - { - if (my_store_param_null(net)) - goto err; - - DBUG_RETURN(0); - } - switch (param->buffer_type) - { - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - if (my_store_param_long(net,(longlong *)param->buffer,param->bind_length)) - goto err; - break; - - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - if (my_store_param_double(net,(double *)param->buffer,param->bind_length)) - goto err; - break; - - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - { - /* - Binary handling, application should supply valid length else - will lead into problems - */ - ulong length = param->buffer_length; - if(param->length) /* ovverite, if length pointer exists */ - length = *param->length; - if (my_store_param_str(net, (char *)param->buffer, length)) - goto err; - } - break; - - default: - { - /* All other conversions should fall through to string type .. */ - char *data = param->buffer; - ulong length; - - if (!param->length) - { - /* - This case is not supose to happen, application should - supply the length for strings and binary data - */ - if (data) - length = param->buffer_length ? strnlen(data,param->buffer_length) : - strlen(data); - else - { - DBUG_PRINT("warning",("data is a null pointer")); - length=0; - } - } - else - length= *param->length; - - if (my_store_param_str(net,data,length)) - goto err; - } - } - DBUG_RETURN(0); - -err: - set_stmt_error(stmt, CR_MEMORY_ERROR); + /* Allocate for worst case (long string) */ + if ((my_realloc_str(net, 9 + *param->length))) + return 1; + if (!param->buffer) + store_param_null(net, param); + else + (*param->store_param_func)(net, param); DBUG_RETURN(1); } + /* Send the prepare query to server for execution */ -static int my_execute(MYSQL_STMT * stmt, char *packet, ulong length) +static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) { - MYSQL *mysql = stmt->mysql; - NET *net = &mysql->net; - - DBUG_ENTER("my_execute"); + MYSQL *mysql= stmt->mysql; + NET *net= &mysql->net; + char buff[4]; + DBUG_ENTER("execute"); DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); - - mysql->last_used_con = mysql; - if (simple_command(mysql, COM_EXECUTE, packet, length, 1) || + mysql->last_used_con= mysql; + int4store(buff, stmt->stmt_id); /* Send stmt id to server */ + if (advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff), packet, + length, 1) || mysql_read_query_result(mysql)) { set_stmt_errmsg(stmt, net->last_error, net->last_errno); - DBUG_RETURN(-1); + DBUG_RETURN(1); } - stmt->state = MY_ST_EXECUTE; + stmt->state= MY_ST_EXECUTE; if (stmt->bind) { mysql_free_result(stmt->result); - stmt->result = mysql_store_result(mysql); + stmt->result= mysql_store_result(mysql); } DBUG_RETURN(0); } -/* - Execute the prepare query + +/* + Execute the prepare query */ -int STDCALL mysql_execute(MYSQL_STMT * stmt) +int STDCALL mysql_execute(MYSQL_STMT *stmt) { + ulong length; + uint null_count; DBUG_ENTER("mysql_execute"); - DBUG_ASSERT(stmt != 0); if (stmt->state == MY_ST_UNKNOWN) { set_stmt_error(stmt, CR_NO_PREPARE_STMT); - DBUG_RETURN(-1); + DBUG_RETURN(1); } - stmt->mysql->fields = stmt->fields; + stmt->mysql->fields= stmt->fields; if (stmt->param_count) { - NET *net = &stmt->mysql->net; - MYSQL_BIND *param; - ulong param_count; + NET *net= &stmt->mysql->net; + MYSQL_BIND *param, *param_end; char *param_data; + my_bool result; if (!stmt->params) { /* Parameters exists, but no bound buffers */ set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND); - DBUG_RETURN(-1); + DBUG_RETURN(1); } - net_clear(net); - net->buf_length = 0; /* clear net */ - - /* In case if buffers (type) alterned, indicate to server */ - net->buff[net->buf_length++] = (char)stmt->types_supplied; - - for (param=stmt->params, param_count = 0; - param_count < stmt->param_count; param_count++, param++) + net_clear(net); /* Sets net->write_pos */ + /* Reserve place for null-marker bytes */ + null_count= (stmt->param_count+7) /8; + 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->types_supplied; + if (!stmt->types_supplied) { - /* Check if any long data, run-time supply exists */ - if (param->is_long_data && !param->long_ended) - DBUG_RETURN(MYSQL_NEED_DATA); - - if (my_store_param(stmt, param)) - DBUG_RETURN(-1); - } - if (!(param_data = my_memdup((byte *) net->buff, - net->buf_length, MYF(MY_WME)))) + stmt->types_supplied=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, (uint) param->buffer_type); + } + + for (param= stmt->params; param < param_end; param++) { - set_stmt_error(stmt, CR_MEMORY_ERROR); - DBUG_RETURN(-1); + /* Check for long data which has not been propery given/terminated */ + if (param->is_long_data) + { + if (!param->long_ended) + DBUG_RETURN(MYSQL_NEED_DATA); + } + else if (store_param(stmt, param)) + DBUG_RETURN(1); } - if (my_execute(stmt,param_data,net->buf_length)) - { - my_free(param_data, MYF(MY_WME)); - DBUG_RETURN(-1); + length= (ulong) (net->write_pos - net->buff); + /* TODO: Look into avoding the following memdup */ + if (!(param_data= my_memdup((byte *) net->buff, length, MYF(0)))) + { + set_stmt_error(stmt, CR_OUT_OF_MEMORY); + DBUG_RETURN(1); } + net->write_pos= net->buff; /* Reset for net_write() */ + result= execute(stmt, param_data, length); my_free(param_data, MYF(MY_WME)); - stmt->types_supplied = 1; - DBUG_RETURN(0); - } - DBUG_RETURN(my_execute(stmt,0,0)); + DBUG_RETURN(result); + } + DBUG_RETURN((int) execute(stmt,0,0)); } + /* Return total parameters count in the statement */ @@ -3808,452 +3736,308 @@ int STDCALL mysql_execute(MYSQL_STMT * stmt) ulong STDCALL mysql_param_count(MYSQL_STMT * stmt) { DBUG_ENTER("mysql_param_count"); - DBUG_ASSERT(stmt != 0); - DBUG_RETURN(stmt->param_count); } /* - Setup the parameter data buffers from application + Setup the parameter data buffers from application */ -int STDCALL mysql_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bind) +my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) { - MYSQL_BIND *param; - ulong count; - + uint count=0; + MYSQL_BIND *param, *end; DBUG_ENTER("mysql_bind_param"); - DBUG_ASSERT(stmt != 0); #ifdef CHECK_EXTRA_ARGUMENTS - if (!bind) - { - set_stmt_error(stmt, CR_NULL_POINTER); - DBUG_RETURN(-1); - } if (stmt->state == MY_ST_UNKNOWN) { set_stmt_error(stmt, CR_NO_PREPARE_STMT); - DBUG_RETURN(-1); + DBUG_RETURN(1); } if (!stmt->param_count) { set_stmt_error(stmt, CR_NO_PARAMETERS_EXISTS); - DBUG_RETURN(-1); + DBUG_RETURN(1); } #endif - - /* In case if buffers bounded previously, free it */ - my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR); - if (!(stmt->params=(MYSQL_BIND *)my_memdup((byte *) bind, - sizeof(MYSQL_BIND) * stmt->param_count, MYF(MY_WME)))) - { - set_stmt_error(stmt, CR_MEMORY_ERROR); - DBUG_RETURN(0); - } - for (param=stmt->params, count=0; - count < stmt->param_count; count++, param++) + /* Allocated on prepare */ + memcpy((char*) stmt->params, (char*) bind, + sizeof(MYSQL_BIND) * stmt->param_count); + + for (param= stmt->params, end= param+stmt->param_count; + param < end ; + param++) { - if (!param) + param->param_number= count++; + if (param->is_long_data && + (param->buffer_type < MYSQL_TYPE_TINY_BLOB || + param->buffer_type > MYSQL_TYPE_STRING)) { - /* Not all parameters bound by the application */ - my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR); - set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND); - DBUG_RETURN(-1); - } - if (param->is_long_data && - (param->buffer_type < MYSQL_TYPE_TINY_BLOB || - param->buffer_type > MYSQL_TYPE_STRING)) - { - /* - Long data handling should be used only for string/binary - types only + /* + Long data handling should be used only for string/binary + types only */ - my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR); - set_stmt_error(stmt, CR_INVALID_BUFFER_USE); - DBUG_RETURN(-1); + sprintf(stmt->last_error, ER(stmt->last_errno= CR_INVALID_BUFFER_USE), + param->param_number); + DBUG_RETURN(1); + } + /* + If param->length is not given, change it to point to bind_length. + This way we can always use *param->length to get the length of data + */ + if (!param->length) + param->length= ¶m->bind_length; + + /* Setup data copy functions for the different supported types */ + switch (param->buffer_type) { + case MYSQL_TYPE_TINY: + param->bind_length= 1; + param->store_param_func= store_param_tinyint; + break; + case MYSQL_TYPE_SHORT: + param->bind_length= 2; + param->store_param_func= store_param_short; + break; + case MYSQL_TYPE_LONG: + param->bind_length= 4; + param->store_param_func= store_param_int32; + break; + case MYSQL_TYPE_LONGLONG: + param->bind_length= 8; + param->store_param_func= store_param_int64; + break; + case MYSQL_TYPE_FLOAT: + param->bind_length= 4; + param->store_param_func= store_param_float; + break; + case MYSQL_TYPE_DOUBLE: + param->bind_length= 4; + param->store_param_func= store_param_double; + break; + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + param->bind_length= param->buffer_length; + param->store_param_func= store_param_str; + break; + default: + sprintf(stmt->last_error, ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), + param->buffer_type, param->param_number); + DBUG_RETURN(1); } - /* setup default buffer_length for int and double types */ - param->bind_length = return_result_length(param->buffer_type, - param->buffer_length); } - stmt->types_supplied = 0; + /* We have to send/resendtype information to MySQL */ + stmt->types_supplied= 0; DBUG_RETURN(0); } + /******************************************************************** Long data implementation *********************************************************************/ /* - Store long data buffer type, to distinguish string and binary + Send long data in pieces to the server + + SYNOPSIS + mysql_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) + last_data If != 0 then this is the last data to the + server. + RETURN VALUES + 0 ok + 1 error */ -static char* my_store_long_type(MYSQL_STMT *stmt, char *packet, uint type) -{ - *packet++ = (char)stmt->types_supplied; - if (!stmt->types_supplied) - { - int2store(packet, type); - packet += 2; - } - return(packet); -} - -/* - Long data in pieces, if buffured successfully send '0' as - status else send '1' - - if length == MYSQL_END_OF_DATA, then thats the last data - piece for the parameter -*/ -my_bool STDCALL -mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, - gptr data, ulong length) +my_bool STDCALL +mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, + const char *data, ulong length, + my_bool last_data) { MYSQL_BIND *param; - MYSQL *mysql; - char *packet; - ulong packet_length, long_length; - DBUG_ENTER("mysql_send_long_data"); - DBUG_ASSERT( stmt != 0 ); - + DBUG_ASSERT(stmt != 0); DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld", - param_number, data, length)); + param_number, data, length)); - if (!(param = (stmt->params+param_number))) + if (param_number >= stmt->param_count) { set_stmt_error(stmt, CR_INVALID_PARAMETER_NO); DBUG_RETURN(1); } - - mysql = stmt->mysql; - if (length == MYSQL_LONG_DATA_END || param->long_ended) - { - if (!stmt->long_alloced) - { - stmt->long_length = MAX_LONG_DATA_LENGTH; - my_free(stmt->long_data, MY_ALLOW_ZERO_PTR); - - if (!(stmt->long_data = (char*) my_malloc(stmt->long_length,MYF(0)))) - { - set_stmt_error(stmt, CR_MEMORY_ERROR); - DBUG_RETURN(1); - } - stmt->long_alloced = 1; - } - packet = stmt->long_data; - packet = my_store_param_length(packet, param_number);/* number */ - packet = my_store_long_type(stmt, packet, param->buffer_type);/* type */ - packet_length = (ulong) ((char *)packet - (char *)(stmt->long_data)); - *packet = (char )MYSQL_LONG_DATA_END; /* data end indicator */ - packet_length++; - - if (simple_command(mysql,COM_LONG_DATA,stmt->long_data,packet_length,0)) - goto err; - - stmt->types_supplied = 1; - param->long_ended = 1; - DBUG_RETURN(0); - } - if (!stmt->long_alloced || stmt->long_length < length+7) + param= stmt->params+param_number; + if (length) { - stmt->long_length = ( MAX_LONG_DATA_LENGTH > (length + 7)) ? - MAX_LONG_DATA_LENGTH : length + 7; + MYSQL *mysql= stmt->mysql; + char *packet, extra_data[MYSQL_LONG_DATA_HEADER]; + + packet= extra_data; + int4store(packet, stmt->stmt_id); packet+=4; + int2store(packet, param_number); packet+=2; + int2store(packet, param->buffer_type); packet+=2; - my_free(stmt->long_data, MY_ALLOW_ZERO_PTR); - if (!(stmt->long_data = (char*) my_malloc(stmt->long_length ,MYF(0)))) + /* + Note that we don't get any ok packet from the server in this case + This is intentional to save bandwidth. + */ + if (advanced_command(mysql, COM_LONG_DATA, extra_data, + MYSQL_LONG_DATA_HEADER, data, length, 1)) { - set_stmt_error(stmt, CR_MEMORY_ERROR); + set_stmt_errmsg(stmt,(char *) mysql->net.last_error, + mysql->net.last_errno); DBUG_RETURN(1); } - stmt->long_alloced = 1; - } - packet = stmt->long_data; - long_length = stmt->long_length; - packet = my_store_param_length(packet, param_number);/* number */ - packet = my_store_long_type(stmt, packet, param->buffer_type);/* type */ - { - char *to = my_store_param_length(packet, length); /* data length */ - memcpy(to, data, length); /* data */ - packet_length = (ulong)((char *)(to + length) - (char *)(stmt->long_data)); } - /* - Send the data to server directly for buffering .. - - TO_BE_DELETED : cross check this with Monty, becuase over the phone - Monty said not to have check for max_packet_length for long data to - have a local storage, instead send it to server directlty, but in - one of his e-mail says to store upto max_packet_size locally.. - */ - if (simple_command(mysql, COM_LONG_DATA, stmt->long_data, packet_length, 0)) - goto err; - - stmt->types_supplied = 1; + param->long_ended= last_data; DBUG_RETURN(0); - -err: - set_stmt_errmsg(stmt,(char *)mysql->net.last_error, mysql->net.last_errno); - DBUG_RETURN(-1); } + /******************************************************************** - Fetch-bind related implementations + Fetch-bind related implementations *********************************************************************/ /* - Setup the bind buffers for resultset processing + Setup the bind buffers for resultset processing */ -int STDCALL mysql_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bind) +my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) { - MYSQL_BIND *param; - ulong count,bind_count, *length; - + MYSQL_BIND *param, *end; + ulong bind_count; DBUG_ENTER("mysql_bind_result"); DBUG_ASSERT(stmt != 0); +#ifdef EXTRA_CHECK_ARGUMENTS if (!bind) { set_stmt_error(stmt, CR_NULL_POINTER); - DBUG_RETURN(-1); + DBUG_RETURN(1); } - count = sizeof(*bind) / sizeof(MYSQL_BIND) + 1; - bind_count = stmt->result ? stmt->result->field_count : count; +#endif + bind_count= stmt->result->field_count; + memcpy((char*) stmt->bind, (char*) bind, + sizeof(MYSQL_BIND)*bind_count); - /* bind_count now will have total fields, if no resultset - exists, then this points to sizeof(bind) - */ - if (bind_count < count) + for (param= stmt->bind, end= param+bind_count; param < end ; param++) { - set_stmt_error(stmt, CR_NOT_ALL_BUFFERS_BOUND); - DBUG_RETURN(-1); - } - /* In case previously bound, free it */ - my_free((gptr)stmt->bind, MY_ALLOW_ZERO_PTR); - if (!(stmt->bind=(MYSQL_BIND *)my_memdup((byte *) bind, - sizeof(MYSQL_BIND) * bind_count, MYF(MY_WME)))) - { - set_stmt_error(stmt, CR_MEMORY_ERROR); - DBUG_RETURN(0); - } - /* set the lengths */ - for (param=stmt->bind,count=0; count<bind_count; count++,param++) - { - if((length=bind->length)) - *length = return_result_length(bind->buffer_type, bind->buffer_length); + /* TODO: Set up convert functions like in mysql_bind_param */ } DBUG_RETURN(0); } + /* - Copy a row of data to bound buffers, used in myql_fetch + Fetch row data to bind buffers */ -static int -my_fetch_record(MYSQL_BIND *bind, MYSQL_FIELD *field, - char *value) +static my_bool +my_fetch_row(MYSQL_STMT *stmt, MYSQL_RES *result, const byte *row) { - gptr buff = bind->buffer; - ulong buff_length = bind->buffer_length; - long *length = bind->length , tmp_length; - enum enum_field_types buff_type = bind->buffer_type; - - DBUG_ENTER("my_fetch_record"); - - if (!value) - { - buff = NullS; - DBUG_RETURN(0); - } - if (!length) - length= &tmp_length; - - /* Copy the data which is in string format to application buffers - based on its type .. no cross conversion needed as everything - is in string buffers in result->row. + MYSQL_BIND *bind, *end; + uchar *null_ptr= (uchar*) row, bit; - When the server supports the sending of data in its own format, - then this needs to be cleaned to have all cross combinations - */ - switch (buff_type) + result->row_count++; + row+= (result->field_count+7)/8; + /* Copy complete row to application buffers */ + bit=1; + for (bind= stmt->bind, end= (MYSQL_BIND *) bind + result->field_count; + bind < end; + bind++) { - case MYSQL_TYPE_TINY: - if (unsigned_field(field)) - *((uchar *) buff) = ((uchar) (uint) atoi(value)); + if (*null_ptr & bit) + bind->is_null= 1; else - *((char *) buff) = ((char)atoi(value)); - break; - - case MYSQL_TYPE_SHORT: - if (unsigned_field(field)) - *((ushort *) buff) = (ushort) (uint) atol(value); - else - *((short *) buff) = (short)atoi(value); - break; - - case MYSQL_TYPE_LONG: - if (unsigned_field(field)) { - char *end_ptr; - *((ulong *) buff) = strtoul(value, &end_ptr, 10); + bind->is_null= 0; + row= (byte*) (*bind->fetch_result)(bind, (char*) row); } - else + if (! (bit<<=1) & 255) { - uint actual_length = strlen(value); - if (actual_length >= 10 && value[4] == '-' && value[7] == '-' && - (!value[10] || value[10] == ' ')) - { - *((long *) buff) = ((long)atol(value) * 10000L + - (long)atol(value + 5) * 100L + - (long)atol(value + 8)); - } - else - *((long *) buff) = (long)atol(value); + bit=1; /* To next byte */ + null_ptr++; } - break; - - case MYSQL_TYPE_LONGLONG: - if (unsigned_field(field)) - *((ulonglong *) buff) = (ulonglong) strtoull(value, NULL, 10); - else - *((longlong *) buff) = (longlong) strtoll(value, NULL, 10); - break; - - case MYSQL_TYPE_FLOAT: - *((float *) buff) = (float)atof(value); - break; - - case MYSQL_TYPE_DOUBLE: - *((double *) buff) = (double)atof(value); - break; - - /* TODO : for strings and blobs, Monty comments - - For strings: We should also support letting the user specify - a pointer to a char * which we would update to where the - date is in the memory. In this case we would only update the - pointer to where we have the string in memory. This would make - things twice as fast for us as we would not have to move things - around and would also require much less memoryfrom the application. - - so, just return the address with the length pointer updated ? - - confirm with Monty and enble the following lines of code by - disbling the existing code which follows next to this. - - If this is enabled, then there is no need of buffer_length in - MYSQL_BIND structure, and clean the code related to that - */ -#if TO_BE_IMPLEMENTED - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - *length = sizeof(value);/* will contain size */ - (char *)bind->buffer = value; /* send the data address to application */ - break; - - default: - *length = strlen(value);/* will contain string length */ - (char *)bind->buffer = value; /* send the data address to application */ - break; -#endif - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - *length = sizeof(value); - memcpy((char *)buff, value, buff_length); - break; - - default: - buff_length--; - *length = strlen(value); - strmake((char *)buff, value, buff_length); } - DBUG_RETURN(0); + return 0; } -/* - Fetch row data to bind buffers -*/ -static int my_fetch_row(MYSQL_STMT *stmt, MYSQL_RES *result, MYSQL_ROW values) +static int +read_binary_data(MYSQL *mysql) { - MYSQL_BIND *bind, *end; - MYSQL_FIELD *field; - ulong record=0; - - result->current_row = values; - result->row_count++; - - /* Copy complete row to application buffers */ - for (bind = stmt->bind, end = (MYSQL_BIND *) bind + result->field_count; - bind < end; - bind++, values++) - { - field = &result->fields[record++]; - - if (my_fetch_record(bind, field, *values)) - return -1; - } + ulong pkt_len; + if ((pkt_len= net_safe_read(mysql)) == packet_error) + return -1; + if (mysql->net.read_pos[0]) + return 1; /* End of data */ return 0; } + /* - Fetch and return row data to bound buffers, if any + Fetch and return row data to bound buffers, if any */ -int STDCALL mysql_fetch(MYSQL_STMT * stmt) +int STDCALL mysql_fetch(MYSQL_STMT *stmt) { MYSQL_RES *result; - DBUG_ENTER("mysql_fetch"); - DBUG_ASSERT(stmt != 0); - - result = stmt->result; + result= stmt->result; if (!result) DBUG_RETURN(MYSQL_NO_DATA); if (!result->data) { + MYSQL *mysql= stmt->mysql; if (!result->eof) { - if (!(read_one_row(result->handle, result->field_count, - result->row, result->lengths))) - { - DBUG_RETURN(my_fetch_row(stmt, result, result->row)); - } - else + int res; + if (!(res= read_binary_data(result->handle))) + DBUG_RETURN((int) my_fetch_row(stmt, result, + (byte*) mysql->net.read_pos+1)); + DBUG_PRINT("info", ("end of data")); + result->eof= 1; + result->handle->status= MYSQL_STATUS_READY; + + /* Don't clear handle in mysql_free_results */ + result->handle= 0; + if (res < 0) /* Network error */ { - DBUG_PRINT("info", ("end of data")); - result->eof = 1; - result->handle->status = MYSQL_STATUS_READY; - /* Don't clear handle in mysql_free_results */ - result->handle = 0; + set_stmt_errmsg(stmt,(char *)mysql->net.last_error, + mysql->net.last_errno); + DBUG_RETURN(MYSQL_STATUS_ERROR); } } DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ } { + /* + For prepared statements, the row data is a string of binary bytes, + not a set of string pointers as for normal statements + It's however convenient to use the data pointer also for prepared + statements. + */ MYSQL_ROW values; - if (!result->data_cursor) { DBUG_PRINT("info", ("end of data")); - result->current_row = (MYSQL_ROW) NULL; + result->current_row= (MYSQL_ROW) NULL; DBUG_RETURN(MYSQL_NO_DATA); } - values = result->data_cursor->data; - result->data_cursor = result->data_cursor->next; + values= result->data_cursor->data; + result->data_cursor= result->data_cursor->next; - DBUG_RETURN(my_fetch_row(stmt,result,values)); + DBUG_RETURN((int) my_fetch_row(stmt,result, (byte*) values)); } DBUG_RETURN(0); } @@ -4262,22 +4046,29 @@ int STDCALL mysql_fetch(MYSQL_STMT * stmt) /******************************************************************** Misc function implementations *********************************************************************/ + /* - Close the statement handle by freeing all resources + Close the statement handle by freeing all resources */ -int STDCALL mysql_stmt_close(MYSQL_STMT * stmt) +my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { + my_bool error=0; DBUG_ENTER("mysql_stmt_close"); - DBUG_ASSERT(stmt != 0); - free_root(&stmt->mem_root,MY_ALLOW_ZERO_PTR); - my_free((gptr) stmt->query, MYF(MY_WME)); + if (stmt->state) + { + char buff[4]; + int4store(buff, stmt->stmt_id); + error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 0); + } + + free_root(&stmt->mem_root, MYF(0)); + my_free((gptr) stmt->query, MYF(MY_WME | MY_ALLOW_ZERO_PTR)); my_free((gptr) stmt->bind, MY_ALLOW_ZERO_PTR); - my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR); - my_free((gptr) stmt->long_data, MY_ALLOW_ZERO_PTR); + my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR); my_free((gptr) stmt, MYF(MY_WME)); - DBUG_RETURN(0); + DBUG_RETURN(error); } /* @@ -4287,9 +4078,7 @@ int STDCALL mysql_stmt_close(MYSQL_STMT * stmt) uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt) { DBUG_ENTER("mysql_stmt_errno"); - DBUG_ASSERT(stmt != 0); - - DBUG_RETURN(stmt->err_no); + DBUG_RETURN(stmt->last_errno); } /* @@ -4299,33 +4088,27 @@ uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt) const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt) { DBUG_ENTER("mysql_stmt_error"); - DBUG_ASSERT(stmt != 0); - - DBUG_RETURN(stmt->error); + DBUG_RETURN(stmt->last_error); } /* Commit the current transaction */ -int STDCALL mysql_commit(MYSQL * mysql) +my_bool STDCALL mysql_commit(MYSQL * mysql) { DBUG_ENTER("mysql_commit"); - DBUG_ASSERT(mysql != 0); - - DBUG_RETURN(mysql_real_query(mysql, "commit", 6)); + DBUG_RETURN((my_bool) mysql_real_query(mysql, "commit", 6)); } /* - Rollback the current transaction + Rollback the current transaction */ -int STDCALL mysql_rollback(MYSQL * mysql) +my_bool STDCALL mysql_rollback(MYSQL * mysql) { DBUG_ENTER("mysql_rollback"); - DBUG_ASSERT(mysql != 0); - - DBUG_RETURN(mysql_real_query(mysql, "rollback", 8)); + DBUG_RETURN((my_bool) mysql_real_query(mysql, "rollback", 8)); } @@ -4333,14 +4116,12 @@ int STDCALL mysql_rollback(MYSQL * mysql) Set autocommit to either true or false */ -int STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode) +my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode) { DBUG_ENTER("mysql_autocommit"); - DBUG_ASSERT(mysql != 0); - DBUG_PRINT("enter", ("mode : %d", auto_mode)); if (auto_mode) /* set to true */ - DBUG_RETURN(mysql_real_query(mysql, "set autocommit=1", 16)); - DBUG_RETURN(mysql_real_query(mysql, "set autocommit=0", 16)); + DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=1", 16)); + DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=0", 16)); } diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 46ca5acafcc..f72f045c96c 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -104,8 +104,8 @@ EXPORTS mysql_rpl_probe mysql_set_master mysql_add_slave - - + mysql_warning_count + mysql_warnings diff --git a/libmysql/manager.c b/libmysql/manager.c index 22b109caea8..6d977e7eef2 100644 --- a/libmysql/manager.c +++ b/libmysql/manager.c @@ -138,7 +138,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, } sock_addr.sin_port = (ushort) htons((ushort) port); if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr), - 0) <0) + 0)) { con->last_errno=errno; sprintf(con->last_error ,"Could not connect to %-.64s", host); |