diff options
author | monty@mashka.mysql.fi <> | 2002-10-02 13:33:08 +0300 |
---|---|---|
committer | monty@mashka.mysql.fi <> | 2002-10-02 13:33:08 +0300 |
commit | d69250a969449da43891ef5b2859df77917183a8 (patch) | |
tree | 5a27bda6d3f628af7dcb922ad022e84cf8cb351c | |
parent | 7134ffec210edde21860a2b2c2654be481de49b4 (diff) | |
download | mariadb-git-d69250a969449da43891ef5b2859df77917183a8.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
108 files changed, 3026 insertions, 2916 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi index 5d4394a7d66..e8bd1ac53e3 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -28684,6 +28684,7 @@ and if you can use @code{GLOBAL} or @code{SESSION} with them. @item delayed_insert_limit @tab num @tab GLOBAL @item delayed_insert_timeout @tab num @tab GLOBAL @item delayed_queue_size @tab num @tab GLOBAL +@item error_count @tab num @tab LOCAL @item flush @tab bool @tab GLOBAL @item flush_time @tab num @tab GLOBAL @item foreign_key_checks @tab bool @tab SESSION @@ -28702,6 +28703,7 @@ and if you can use @code{GLOBAL} or @code{SESSION} with them. @item max_binlog_size @tab num @tab GLOBAL @item max_connect_errors @tab num @tab GLOBAL @item max_connections @tab num @tab GLOBAL +@item max_error_count @tab num @tab GLOBAL | SESSION @item max_delayed_threads @tab num @tab GLOBAL @item max_heap_table_size @tab num @tab GLOBAL | SESSION @item max_join_size @tab num @tab GLOBAL | SESSION @@ -28750,6 +28752,7 @@ and if you can use @code{GLOBAL} or @code{SESSION} with them. @item tx_isolation @tab enum @tab GLOBAL | SESSION @item version @tab string @tab GLOBAL @item wait_timeout @tab num @tab GLOBAL | SESSION +@item warning_count @tab num @tab LOCAL @item unique_checks @tab bool @tab SESSION @end multitable diff --git a/client/mysql.cc b/client/mysql.cc index 7fd221f479c..223d4b794d2 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -40,7 +40,7 @@ #include <signal.h> #include <violite.h> -const char *VER= "12.12"; +const char *VER= "12.13"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -1362,9 +1362,9 @@ com_clear(String *buffer,char *line __attribute__((unused))) static int com_go(String *buffer,char *line __attribute__((unused))) { - char buff[160],time_buff[32]; + char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer; + ulong timer, warnings; uint error=0; if (!status.batch) @@ -1447,7 +1447,7 @@ com_go(String *buffer,char *line __attribute__((unused))) { if (!mysql_num_rows(result) && ! quick) { - sprintf(buff,"Empty set%s",time_buff); + strmov(buff, "Empty set"); } else { @@ -1462,20 +1462,30 @@ com_go(String *buffer,char *line __attribute__((unused))) print_tab_data(result); else print_table_data(result); - sprintf(buff,"%ld %s in set%s", + sprintf(buff,"%ld %s in set", (long) mysql_num_rows(result), - (long) mysql_num_rows(result) == 1 ? "row" : "rows", - time_buff); + (long) mysql_num_rows(result) == 1 ? "row" : "rows"); end_pager(); } } else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0) - sprintf(buff,"Query OK%s",time_buff); + strmov(buff,"Query OK"); else - sprintf(buff,"Query OK, %ld %s affected%s", + sprintf(buff,"Query OK, %ld %s affected", (long) mysql_affected_rows(&mysql), - (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows", - time_buff); + (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows"); + + pos=strend(buff); + if ((warnings= mysql_warning_count(&mysql))) + { + *pos++= ','; + *pos++= ' '; + pos=int2str(warnings, pos, 10); + pos=strmov(pos, " warning"); + if (warnings != 1) + *pos++= 's'; + } + strmov(pos, time_buff); put_info(buff,INFO_RESULT); if (mysql_info(&mysql)) put_info(mysql_info(&mysql),INFO_RESULT); diff --git a/client/mysqltest.c b/client/mysqltest.c index f469a33f063..181a7fb2b8f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -311,7 +311,7 @@ static int eval_result = 0; void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; } -int mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } +my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif #define MAX_SERVER_ARGS 20 @@ -1073,7 +1073,7 @@ int do_disable_rpl_parse(struct st_query* q __attribute__((unused))) } -int do_sleep(struct st_query* q) +int do_sleep(struct st_query* q, my_bool real_sleep) { char *p=q->first_argument; struct timeval t; @@ -2055,6 +2055,36 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, dynstr_append_mem(ds, val, len); } +/* + Append all results to the dynamic string separated with '\t' +*/ + +static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) +{ + MYSQL_ROW row; + int num_fields= mysql_num_fields(res); + unsigned long *lengths; + while ((row = mysql_fetch_row(res))) + { + int i; + lengths = mysql_fetch_lengths(res); + for (i = 0; i < num_fields; i++) + { + const char *val= row[i]; + ulonglong len= lengths[i]; + if (!val) + { + val = "NULL"; + len = 4; + } + if (i) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + } + dynstr_append_mem(ds, "\n", 1); + } +} + /* * flags control the phased/stages of query execution to be performed @@ -2065,12 +2095,7 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int run_query(MYSQL* mysql, struct st_query* q, int flags) { MYSQL_RES* res = 0; - MYSQL_FIELD* fields; - MYSQL_ROW row; - int num_fields,i, error = 0; - unsigned long* lengths; - char* val; - int len; + int i, error = 0; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; DYNAMIC_STRING eval_query; @@ -2178,45 +2203,37 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) goto end; } - if (!res) - goto end; - - if (!disable_result_log) + if (!disable_result_log && res) { - fields = mysql_fetch_fields(res); - num_fields = mysql_num_fields(res); + int num_fields= mysql_num_fields(res); + MYSQL_FIELD *fields= mysql_fetch_fields(res); for (i = 0; i < num_fields; i++) { if (i) dynstr_append_mem(ds, "\t", 1); dynstr_append(ds, fields[i].name); } - dynstr_append_mem(ds, "\n", 1); + append_result(ds, res); + } - while ((row = mysql_fetch_row(res))) + /* Add all warnings to the result */ + if (!disable_result_log && mysql_warning_count(mysql)) + { + MYSQL_RES *warn_res= mysql_warnings(mysql); + if (!warn_res) + verbose_msg("Warning count is %d but didn't get any warnings\n", + mysql_warning_count(mysql)); + else { - lengths = mysql_fetch_lengths(res); - for (i = 0; i < num_fields; i++) - { - val = (char*)row[i]; - len = lengths[i]; - - if (!val) - { - val = (char*)"NULL"; - len = 4; - } - - if (i) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); - } - dynstr_append_mem(ds, "\n", 1); + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); } - if (glob_replace) - free_replace(); } + if (glob_replace) + free_replace(); + if (record) { if (!q->record_file[0] && !result_file) diff --git a/configure.in b/configure.in index 5cd299a8ba0..8ca1a0befed 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 DOT_FRM_VERSION=6 # See the libtool docs for information on how to do shared lib versions. -SHARED_LIB_VERSION=11:0:0 +SHARED_LIB_VERSION=12:0:0 # Set all version vars based on $VERSION. How do we do this more elegant ? # Remember that regexps needs to quote [ and ] since this is run through m4 diff --git a/include/errmsg.h b/include/errmsg.h index 175089ba371..d97522f0972 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -63,15 +63,12 @@ extern const char *client_errors[]; /* Error messages */ #define CR_PROBE_MASTER_CONNECT 2025 /* new 4.1 error codes */ -#define CR_INVALID_CONN_HANDLE 2026 -#define CR_NULL_POINTER 2027 -#define CR_MEMORY_ERROR 2028 -#define CR_NO_PREPARE_STMT 2029 -#define CR_NOT_ALL_PARAMS_BOUND 2030 -#define CR_DATA_TRUNCATED 2031 -#define CR_NOT_ALL_BUFFERS_BOUND 2032 -#define CR_FAILED_TO_SET_PARAM_DATA 2033 -#define CR_NO_PARAMETERS_EXISTS 2033 -#define CR_INVALID_PARAMETER_NO 2035 -#define CR_INVALID_BUFFER_USE 2036 - +#define CR_INVALID_CONN_HANDLE 2026 +#define CR_NULL_POINTER 2027 +#define CR_NO_PREPARE_STMT 2028 +#define CR_NOT_ALL_PARAMS_BOUND 2029 +#define CR_DATA_TRUNCATED 2030 +#define CR_NO_PARAMETERS_EXISTS 2031 +#define CR_INVALID_PARAMETER_NO 2032 +#define CR_INVALID_BUFFER_USE 2033 +#define CR_UNSUPPORTED_PARAM_TYPE 2034 diff --git a/include/mysql.h b/include/mysql.h index 50543c51f6b..376de1a0e08 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -157,7 +157,8 @@ enum mysql_rpl_type { MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN }; -typedef struct st_mysql { +typedef struct st_mysql +{ NET net; /* Communication parameters */ gptr connector_fd; /* ConnectorFd for SSL */ char *host,*user,*passwd,*unix_socket,*server_version,*host_info, @@ -175,6 +176,7 @@ typedef struct st_mysql { unsigned int field_count; unsigned int server_status; unsigned int server_language; + unsigned int warning_count; struct st_mysql_options options; enum mysql_status status; my_bool free_me; /* If free in mysql_close */ @@ -273,12 +275,13 @@ my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); unsigned int STDCALL mysql_errno(MYSQL *mysql); const char * STDCALL mysql_error(MYSQL *mysql); +uint STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_info(MYSQL *mysql); unsigned long STDCALL mysql_thread_id(MYSQL *mysql); const char * STDCALL mysql_character_set_name(MYSQL *mysql); MYSQL * STDCALL mysql_init(MYSQL *mysql); -int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, +my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, @@ -295,19 +298,19 @@ int STDCALL mysql_select_db(MYSQL *mysql, const char *db); int STDCALL mysql_query(MYSQL *mysql, const char *q); int STDCALL mysql_send_query(MYSQL *mysql, const char *q, unsigned long length); -int STDCALL mysql_read_query_result(MYSQL *mysql); +my_bool STDCALL mysql_read_query_result(MYSQL *mysql); int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned long length); /* perform query on master */ -int STDCALL mysql_master_query(MYSQL *mysql, const char *q, - unsigned long length); -int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, - unsigned long length); +my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned long length); /* perform query on slave */ -int STDCALL mysql_slave_query(MYSQL *mysql, const char *q, - unsigned long length); -int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, - unsigned long length); +my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, + unsigned long length); /* enable/disable parsing of all queries to decide if they go on master or @@ -322,12 +325,12 @@ int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql); void STDCALL mysql_enable_reads_from_master(MYSQL* mysql); 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); enum mysql_rpl_type STDCALL mysql_rpl_query_type(const char* q, int len); /* discover the master and its slaves */ -int STDCALL mysql_rpl_probe(MYSQL* mysql); +my_bool STDCALL mysql_rpl_probe(MYSQL* mysql); /* set the master, close/free the old one, if it is not a pivot */ int STDCALL mysql_set_master(MYSQL* mysql, const char* host, @@ -357,6 +360,7 @@ MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_warnings(MYSQL *mysql); int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg); void STDCALL mysql_free_result(MYSQL_RES *result); @@ -401,7 +405,6 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, int res_buf_size); - /* The following definitions are added for the enhanced client-server protocol @@ -411,67 +414,76 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, enum MY_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE }; /* bind structure */ -typedef struct st_mysql_bind { - - enum enum_field_types buffer_type; /* buffer type */ - enum enum_field_types field_type; /* field type */ - gptr buffer; /* buffer */ - long *length; /* output length pointer */ - unsigned long buffer_length; /* buffer length */ - unsigned long bind_length; /* internal use */ - my_bool is_null; /* NULL indicator */ - my_bool is_long_data; /* long data indicator */ - my_bool long_ended; /* internal use */ - +typedef struct st_mysql_bind +{ + long *length; /* output length pointer */ + gptr buffer; /* buffer */ + unsigned long buffer_length; /* buffer length */ + enum enum_field_types buffer_type; /* buffer type */ + enum enum_field_types field_type; /* field type */ + my_bool is_null; /* NULL indicator */ + my_bool is_long_data; /* long data indicator */ + + /* The following are for internal use. Set by mysql_bind_param */ + long bind_length; /* Default length of data */ + my_bool long_ended; /* All data supplied for long */ + uint param_number; /* For null count and error messages */ + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + char *(*fetch_result)(struct st_mysql_bind *, const char *row); } MYSQL_BIND; -/* statement handler */ -typedef struct st_mysql_stmt { - - MYSQL *mysql; /* connection handle */ - MYSQL_BIND *params; /* input parameters */ - MYSQL_RES *result; /* resultset */ - MYSQL_BIND *bind; /* row binding */ - MYSQL_FIELD *fields; /* prepare meta info */ - MEM_ROOT mem_root; /* root allocations */ - unsigned long param_count; /* parameters count */ - unsigned long field_count; /* fields count */ - unsigned long long_length; /* long buffer alloced length */ - uint err_no; /* error code */ - char error[MYSQL_ERRMSG_SIZE]; /* error message */ - char *query; /* query buffer */ - char *long_data; /* long buffer */ - enum MY_STMT_STATE state; /* statement state */ - my_bool long_alloced; /* flag to indicate long alloced */ - my_bool types_supplied; /* to indicate types supply */ +/* statement handler */ +typedef struct st_mysql_stmt +{ + MYSQL *mysql; /* connection handle */ + MYSQL_BIND *params; /* input parameters */ + MYSQL_RES *result; /* resultset */ + MYSQL_BIND *bind; /* row binding */ + MYSQL_FIELD *fields; /* prepare meta info */ + char *query; /* query buffer */ + MEM_ROOT mem_root; /* root allocations */ + MYSQL_RES tmp_result; /* Used by mysql_prepare_result */ + unsigned long param_count; /* parameters count */ + unsigned long field_count; /* fields count */ + unsigned long long_length; /* long buffer alloced length */ + ulong stmt_id; /* Id for prepared statement */ + uint last_errno; /* error code */ + enum MY_STMT_STATE state; /* statement state */ + char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ + my_bool long_alloced; /* flag to indicate long alloced */ + my_bool types_supplied; /* to indicate types supply */ } MYSQL_STMT; -MYSQL_STMT * STDCALL mysql_prepare(MYSQL * mysql, const char *query); +MYSQL_STMT * STDCALL mysql_prepare(MYSQL * mysql, const char *query, + unsigned long length); int STDCALL mysql_execute(MYSQL_STMT * stmt); unsigned long STDCALL mysql_param_count(MYSQL_STMT * stmt); -int STDCALL mysql_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bind); -int STDCALL mysql_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bind); -int STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bind); +my_bool STDCALL mysql_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bind); +my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); -int STDCALL mysql_commit(MYSQL * mysql); -int STDCALL mysql_rollback(MYSQL * mysql); -int STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); -int STDCALL mysql_fetch(MYSQL_STMT *stmt); +my_bool STDCALL mysql_commit(MYSQL * mysql); +my_bool STDCALL mysql_rollback(MYSQL * mysql); +my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); +int STDCALL mysql_fetch(MYSQL_STMT *stmt); my_bool STDCALL mysql_send_long_data(MYSQL_STMT *stmt, - uint param_number,gptr data, - unsigned long length); -int STDCALL mysql_multi_query(MYSQL *mysql,const char *query,unsigned long len); + uint param_number, + const char *data, + unsigned long length, + my_bool last_data); +int STDCALL mysql_multi_query(MYSQL *mysql,const char *query, + unsigned long len); MYSQL_RES *STDCALL mysql_next_result(MYSQL *mysql); -MYSQL_RES * STDCALL mysql_prepare_result(MYSQL_STMT *stmt); +MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt); /* new status messages */ #define MYSQL_SUCCESS 0 #define MYSQL_WARNING 1 -#define MYSQL_ERROR -1 +#define MYSQL_STATUS_ERROR 2 #define MYSQL_NO_DATA 100 #define MYSQL_NEED_DATA 99 #define MYSQL_LONG_DATA_END 0xFF @@ -492,8 +504,9 @@ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); They are not for general usage */ -int simple_command(MYSQL *mysql,enum enum_server_command command, - const char *arg, unsigned long length, my_bool skipp_check); +my_bool +simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + ulong length, my_bool skip_check); unsigned long net_safe_read(MYSQL* mysql); #ifdef __cplusplus diff --git a/include/mysql_com.h b/include/mysql_com.h index 9743fc4c3f5..1edaa99db28 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -34,15 +34,15 @@ #define MYSQL_SERVICENAME "MySql" #endif /* __WIN__ */ -enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, - COM_FIELD_LIST,COM_CREATE_DB,COM_DROP_DB,COM_REFRESH, - COM_SHUTDOWN,COM_STATISTICS, - COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL, - COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT, - COM_CHANGE_USER, COM_BINLOG_DUMP, - COM_TABLE_DUMP, COM_CONNECT_OUT, - COM_REGISTER_SLAVE, - COM_PREPARE,COM_EXECUTE,COM_LONG_DATA }; +enum enum_server_command +{ + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, + COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, + COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, + COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, + COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, + COM_PREPARE, COM_EXECUTE, COM_LONG_DATA, COM_CLOSE_STMT +}; #define NOT_NULL_FLAG 1 /* Field can't be NULL */ #define PRI_KEY_FLAG 2 /* Field is part of a primary key */ @@ -98,8 +98,9 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ #define CLIENT_PROTOCOL_41 16384 /* New 4.1 protocol */ -#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ -#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ +#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_STATUS_MORE_RESULTS 4 /* More results on server */ #define MYSQL_ERRMSG_SIZE 200 #define NET_READ_TIMEOUT 30 /* Timeout on read */ @@ -203,21 +204,26 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, extern "C" { #endif -int my_net_init(NET *net, Vio* vio); +my_bool my_net_init(NET *net, Vio* vio); void my_net_local_init(NET *net); void net_end(NET *net); void net_clear(NET *net); -int net_flush(NET *net); -int my_net_write(NET *net,const char *packet,unsigned long len); -int net_write_command(NET *net,unsigned char command,const char *packet, - unsigned long len); +my_bool net_realloc(NET *net, unsigned long length); +my_bool net_flush(NET *net); +my_bool my_net_write(NET *net,const char *packet,unsigned long len); +my_bool net_write_command(NET *net,unsigned char command, + const char *header, unsigned long head_len, + const char *packet, unsigned long len); int net_real_write(NET *net,const char *packet,unsigned long len); unsigned long my_net_read(NET *net); -/* The following function is not meant for normal usage */ +/* + The following function is not meant for normal usage + Currently it's used internally by manager.c +*/ struct sockaddr; -int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, - unsigned int timeout); +my_bool my_connect(my_socket s, const struct sockaddr *name, + unsigned int namelen, unsigned int timeout); struct rand_struct { unsigned long seed1,seed2,max_value; @@ -291,6 +297,6 @@ void my_thread_end(void); #endif #define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ -#define MYSQL_LONG_DATA_END 0xFF /* For indication of long data ending */ +#define MYSQL_LONG_DATA_HEADER 8 #endif diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 635d8390c2c..fc5df43f309 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -257,4 +257,5 @@ #define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1238 #define ER_SUBSELECT_NO_1_COL 1239 #define ER_SUBSELECT_NO_1_ROW 1240 -#define ER_ERROR_MESSAGES 241 +#define ER_UNKNOWN_STMT_HANDLER 1241 +#define ER_ERROR_MESSAGES 242 diff --git a/isam/pack_isam.c b/isam/pack_isam.c index 8a00b4c962a..ebe616714f5 100644 --- a/isam/pack_isam.c +++ b/isam/pack_isam.c @@ -687,7 +687,8 @@ static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIP_ZERO)) count[i].max_zero_fill= count[i].field_length; - init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL); + init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, + NULL, NULL); if (records) count[i].tree_pos=count[i].tree_buff = my_malloc(count[i].field_length > 1 ? tree_buff_length : 2, 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); diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index f5934fc93fa..a3e5bfb4fff 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -154,14 +154,12 @@ check_connections1(THD *thd) end+=SCRAMBLE_LENGTH +1; int2store(end,client_flags); end[2]=MY_CHARSET_CURRENT; - -#define MIN_HANDSHAKE_SIZE 6 - int2store(end+3,thd->server_status); bzero(end+5,13); end+=18; - if (net_write_command(net,protocol_version, buff, - (uint) (end-buff))) + if (net_write_command(net,protocol_version, + NullS, 0, + buff, (uint) (end-buff))) { inc_host_errors(&thd->remote.sin_addr); return(ER_HANDSHAKE_ERROR); @@ -169,6 +167,8 @@ check_connections1(THD *thd) return 0; } +#define MIN_HANDSHAKE_SIZE 6 + static int check_connections2(THD * thd) { @@ -214,13 +214,12 @@ check_connections2(THD * thd) static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { - NET *net= &thd->net; USER_RESOURCES ur; thd->db=0; if (!(thd->user = my_strdup(user, MYF(0)))) { - send_error(net,ER_OUT_OF_RESOURCES); + send_error(thd,ER_OUT_OF_RESOURCES); return 1; } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, @@ -236,7 +235,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, thd->master_access, thd->db ? thd->db : "*none*")); if (thd->master_access & NO_ACCESS) { - net_printf(net, ER_ACCESS_DENIED_ERROR, + net_printf(thd, ER_ACCESS_DENIED_ERROR, thd->user, thd->host_or_ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); @@ -254,7 +253,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (tmp) { // Too many connections - send_error(net, ER_CON_COUNT_ERROR); + send_error(thd, ER_CON_COUNT_ERROR); return(1); } } @@ -269,7 +268,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, if (db && db[0]) return test(mysql_change_db(thd,db)); else - send_ok(net); // Ready to handle questions + send_ok(thd); // Ready to handle questions return 0; // ok } @@ -370,7 +369,6 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); @@ -388,6 +386,7 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); @@ -499,7 +498,7 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) After this we can't quit by a simple unireg_abort */ error_handler_hook = my_message_sql; - if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) || + if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_MALLOC,NULL)) { sql_print_error("Can't create thread-keys"); diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 3fba238a8bf..453376092d7 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -212,12 +212,12 @@ static void free_rows(MYSQL_DATA *cur) } -int +my_bool simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, ulong length, my_bool skipp_check) { NET *net= &mysql->net; - int result= -1; + my_bool result= 1; /* Check that we are calling the client functions in right order */ if (mysql->status != MYSQL_STATUS_READY) @@ -239,7 +239,7 @@ simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, result = lib_dispatch_command(command, net, arg,length); if (!skipp_check) result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ? - -1 : 0); + 1 : 0); end: return result; } @@ -1124,7 +1124,7 @@ mysql_send_query(MYSQL* mysql, const char* query, ulong length) } -int STDCALL +my_bool STDCALL mysql_read_query_result(MYSQL *mysql) { uchar *pos; @@ -1134,7 +1134,7 @@ mysql_read_query_result(MYSQL *mysql) DBUG_ENTER("mysql_read_query_result"); 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; @@ -1154,7 +1154,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)) @@ -1162,19 +1162,19 @@ get_info: mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,5))) - DBUG_RETURN(-1); + DBUG_RETURN(1); if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, (uint) field_count,0, (my_bool) test(mysql->server_capabilities & CLIENT_LONG_FLAG)))) - DBUG_RETURN(-1); + DBUG_RETURN(1); mysql->status=MYSQL_STATUS_GET_RESULT; mysql->field_count=field_count; DBUG_RETURN(0); } /**************************************************************************** -* 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(). @@ -1182,11 +1182,11 @@ get_info: * 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); @@ -1199,7 +1199,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 @@ -1212,7 +1212,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); @@ -1252,7 +1252,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 @@ -1262,12 +1262,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 diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 1a70113f0ad..9a2a29f9a08 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -241,8 +241,8 @@ static void _ftb_init_index_search(FT_INFO *ftb) { if (!is_tree_inited(& ftb->no_dupes)) { - init_tree(& ftb->no_dupes,0,0,sizeof(my_off_t), - _ftb_no_dupes_cmp,0,0,0); + init_tree(&ftb->no_dupes,0,0,sizeof(my_off_t), + _ftb_no_dupes_cmp, 0, NULL, NULL); } } } diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index 170442c71de..5415a08e5e3 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -41,8 +41,8 @@ int ft_init_stopwords(const char **sws) if(!stopwords3) { if(!(stopwords3=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return -1; - init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp,0, - NULL, NULL); + init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp, + 0, NULL, NULL); } if(!sws) return 0; diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 49f6f31f96e..10d7052fb0f 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1771,7 +1771,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, File new_file; MI_SORT_PARAM sort_param; MYISAM_SHARE *share=info->s; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; ulong *rec_per_key_part; char llbuff[22]; SORT_INFO sort_info; @@ -2136,7 +2136,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, MI_SORT_PARAM *sort_param=0; MYISAM_SHARE *share=info->s; ulong *rec_per_key_part; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; char llbuff[22]; IO_CACHE_SHARE io_share; SORT_INFO sort_info; @@ -3080,7 +3080,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) { sort_info->dupp++; sort_info->info->lastpos=get_record_for_key(sort_info->info, - sort_parm->keyinfo, + sort_param->keyinfo, (uchar*) a); mi_check_print_warning(param, "Duplicate key for record at %10s against record at %10s", diff --git a/myisam/myisampack.c b/myisam/myisampack.c index a299e4eb00d..3fbc371be3f 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -665,7 +665,8 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIP_ZERO)) count[i].max_zero_fill= count[i].field_length; - init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL); + init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, NULL, + NULL); if (records && type != FIELD_BLOB && type != FIELD_VARCHAR) count[i].tree_pos=count[i].tree_buff = my_malloc(count[i].field_length > 1 ? tree_buff_length : 2, diff --git a/myisam/rt_key.c b/myisam/rt_key.c index c08e918c6db..a48aec53c97 100644 --- a/myisam/rt_key.c +++ b/myisam/rt_key.c @@ -1,5 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & MySQL Finland AB - & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin 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 @@ -22,14 +21,16 @@ #include "rt_mbr.h" /* -Add key to the page -Result values: --1 - error - 0 - not split - 1 - split + Add key to the page + + RESULT VALUES + -1 Error + 0 Not split + 1 Split */ + int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, - uint key_length, uchar *page_buf, my_off_t *new_page) + uint key_length, uchar *page_buf, my_off_t *new_page) { uint page_size = mi_getint(page_buf); uint nod_flag = mi_test_if_nod(page_buf); @@ -53,47 +54,39 @@ int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, mi_putint(page_buf, page_size, nod_flag); return 0; } - else - { - if (rtree_split_page(info, keyinfo, page_buf, key, key_length, new_page)) - return -1; - else - return 1; - } + + return (rtree_split_page(info, keyinfo, page_buf, key, key_length, + new_page) ? -1 : 0); } /* -Delete key from the page + Delete key from the page */ int rtree_delete_key(MI_INFO *info, uchar *page_buf, uchar *key, - uint key_length, uint nod_flag) + uint key_length, uint nod_flag) { uint16 page_size = mi_getint(page_buf); uchar *key_start; + key_start= key - nod_flag; if (nod_flag) - { - key_start = key - nod_flag; - } - else - { - key_start = key; key_length += info->s->base.rec_reflength; - } - memmove(key_start, key + key_length, page_size - key_length - - (key - page_buf)); - page_size -= key_length + nod_flag; - mi_putint(page_buf, page_size, nod_flag); + memmove(key_start, key + key_length, page_size - key_length - + (key - page_buf)); + page_size-= key_length + nod_flag; + mi_putint(page_buf, page_size, nod_flag); return 0; } + /* -Calculate and store key MBR + Calculate and store key MBR */ + int rtree_set_key_mbr(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, - uint key_length, my_off_t child_page) + uint key_length, my_off_t child_page) { uchar *k; uchar *last; @@ -114,21 +107,25 @@ err1: return -1; } + /* -Choose non-leaf better key for insertion + Choose non-leaf better key for insertion */ + uchar *rtree_choose_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, - uint key_length, uchar *page_buf, uint nod_flag) + uint key_length, uchar *page_buf, uint nod_flag) { double increase; double best_incr = DBL_MAX; double area; double best_area; uchar *best_key; - uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); uchar *last = rt_PAGE_END(page_buf); + LINT_INIT(best_area); + LINT_INIT(best_key); + for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) { if ((increase = rtree_area_increase(keyinfo->seg, key, k, key_length, diff --git a/myisam/rt_test.c b/myisam/rt_test.c index 4cc60d63031..5cf4262e804 100644 --- a/myisam/rt_test.c +++ b/myisam/rt_test.c @@ -32,7 +32,7 @@ static void print_record(char * record,my_off_t offs,const char * tail); static int run_test(const char *filename); -int main(int argc,char *argv[]) +int main(int argc __attribute__((unused)),char *argv[]) { MY_INIT(argv[0]); exit(run_test("rt_test")); @@ -63,7 +63,6 @@ int run_test(const char *filename) int row_count=0; char record[MAX_REC_LENGTH]; char read_record[MAX_REC_LENGTH]; - int upd=10; ha_rows hrows; @@ -343,7 +342,10 @@ static int read_with_pos (MI_INFO * file,int silent) } -static void bprint_record(char * record, my_off_t offs,const char * tail) +#ifdef NOT_USED +static void bprint_record(char * record, + my_off_t offs __attribute__((unused)), + const char * tail) { int i; char * pos; @@ -356,8 +358,12 @@ static void bprint_record(char * record, my_off_t offs,const char * tail) } printf("%s",tail); } +#endif -static void print_record(char * record, my_off_t offs,const char * tail) + +static void print_record(char * record, + my_off_t offs __attribute__((unused)), + const char * tail) { int i; char * pos; diff --git a/myisam/sp_key.c b/myisam/sp_key.c index 2ab11f993c3..82c2b1f8510 100644 --- a/myisam/sp_key.c +++ b/myisam/sp_key.c @@ -1,5 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin & MySQL Finland AB - & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB & Ramil Kalimullin 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 @@ -30,8 +29,9 @@ static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims, double *mbr, int top); static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr); + uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, - const byte *record, my_off_t filepos) + const byte *record, my_off_t filepos) { HA_KEYSEG *keyseg; MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr]; @@ -91,10 +91,12 @@ static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr) } /* -Add one point stored in wkb to mbr + Add one point stored in wkb to mbr */ + static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims, - uchar byte_order, double *mbr) + uchar byte_order __attribute__((unused)), + double *mbr) { double ord; double *mbr_end = mbr + n_dims * 2; @@ -115,12 +117,14 @@ static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims, return 0; } + static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims, uchar byte_order, double *mbr) { return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr); } + static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims, uchar byte_order, double *mbr) { @@ -137,6 +141,7 @@ static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims, return 0; } + static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims, uchar byte_order, double *mbr) { diff --git a/myisam/sp_test.c b/myisam/sp_test.c index 9d32b3e623d..b8b5880cf67 100644 --- a/myisam/sp_test.c +++ b/myisam/sp_test.c @@ -41,7 +41,7 @@ static void rtree_PrintWKB(uchar *wkb, uint n_dims); static char blob_key[MAX_REC_LENGTH]; -int main(int argc,char *argv[]) +int main(int argc __attribute__((unused)),char *argv[]) { MY_INIT(argv[0]); exit(run_test("sp_test")); @@ -320,7 +320,10 @@ static int read_with_pos (MI_INFO * file,int silent) } -static void bprint_record(char * record, my_off_t offs,const char * tail) +#ifdef NOT_USED +static void bprint_record(char * record, + my_off_t offs __attribute__((unused)), + const char * tail) { int i; char * pos; @@ -333,6 +336,8 @@ static void bprint_record(char * record, my_off_t offs,const char * tail) } printf("%s",tail); } +#endif + static void print_record(char * record, my_off_t offs,const char * tail) { @@ -356,6 +361,7 @@ static void print_record(char * record, my_off_t offs,const char * tail) +#ifndef NOT_USED static void create_point(char *record,uint rownr) { uint tmp; @@ -380,6 +386,7 @@ static void create_point(char *record,uint rownr) ptr=blob_key; memcpy_fixed(pos,&ptr,sizeof(char*)); } +#endif static void create_linestring(char *record,uint rownr) diff --git a/mysql-test/README b/mysql-test/README index c5dc3e219de..7c6efe7940e 100644 --- a/mysql-test/README +++ b/mysql-test/README @@ -1,6 +1,10 @@ This directory contains a test suite for mysql daemon. To run the currently existing test cases, simply execute ./mysql-test-run in this directory. It will fire up the newly built mysqld and test it. + +If you want to run the test with a running MySQL server use the --external +option to mysql-test-run. + Note that you do not have to have to do make install, and you could actually have a co-existing MySQL installation - the tests will not conflict with it. @@ -13,8 +17,7 @@ http://www.mysql.com/doc/M/y/MySQL_test_suite.html You can create your own test cases. To create a test case: - cd t - vi test_case_name.test + xeamacs t/test_case_name.test in the file, put a set of SQL commands that will create some tables, load test data, run some queries to manipulate it. diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index a26b597f8db..57b6ef056f2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -171,7 +171,7 @@ USER_TEST= EXTRA_MASTER_OPT="" EXTRA_MYSQL_TEST_OPT="" -USE_RUNNING_SERVER=1 +USE_RUNNING_SERVER="" DO_GCOV="" DO_GDB="" MANUAL_GDB="" @@ -199,6 +199,7 @@ while test $# -gt 0; do --slave-binary=*) SLAVE_MYSQLD=`$ECHO "$1" | $SED -e "s;--slave-binary=;;"` ;; --local) USE_RUNNING_SERVER="" ;; + --extern) USE_RUNNING_SERVER="1" ;; --tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;; --local-master) MASTER_MYPORT=3306; diff --git a/mysql-test/r/rollback.result b/mysql-test/r/rollback.result index a5eb6f8729f..d87aa68dce4 100644 --- a/mysql-test/r/rollback.result +++ b/mysql-test/r/rollback.result @@ -4,9 +4,26 @@ begin work; insert into t1 values (4); insert into t1 values (5); rollback; -Warning: Some non-transactional changed tables couldn't be rolled back +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select @@warning_count; +@@warning_count +1 +select @@error_count; +@@error_count +0 +show warnings; +Level Code Message +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show errors; +Level Code Message select * from t1; n 4 5 +select @@warning_count; +@@warning_count +0 +show warnings; +Level Code Message drop table t1; diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 8948460e1bd..b5719c920e6 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -18,24 +18,24 @@ drop table t1; show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 -master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) master-bin.001 172 Intvar 1 172 INSERT_ID=1 -master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) -master-bin.001 263 Query 1 263 use test; drop table t1 -master-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null) +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +master-bin.001 263 Query 1 263 use `test`; drop table t1 +master-bin.001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=81 master-bin.001 556 Exec_load 1 556 ;file_id=1 -master-bin.001 579 Query 1 579 use test; drop table t1 +master-bin.001 579 Query 1 579 use `test`; drop table t1 show binlog events from 79 limit 1; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) show binlog events from 79 limit 2; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) master-bin.001 172 Intvar 1 172 INSERT_ID=1 show binlog events from 79 limit 2,1; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) flush logs; create table t1 (n int); insert into t1 values (1); @@ -43,21 +43,21 @@ drop table t1; show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 -master-bin.001 79 Query 1 79 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) master-bin.001 172 Intvar 1 172 INSERT_ID=1 -master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) -master-bin.001 263 Query 1 263 use test; drop table t1 -master-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null) +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +master-bin.001 263 Query 1 263 use `test`; drop table t1 +master-bin.001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=81 master-bin.001 556 Exec_load 1 556 ;file_id=1 -master-bin.001 579 Query 1 579 use test; drop table t1 +master-bin.001 579 Query 1 579 use `test`; drop table t1 master-bin.001 627 Rotate 1 627 master-bin.002;pos=4 master-bin.001 668 Stop 1 668 show binlog events in 'master-bin.002'; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.002 4 Query 1 4 use test; create table t1 (n int) -master-bin.002 62 Query 1 62 use test; insert into t1 values (1) -master-bin.002 122 Query 1 122 use test; drop table t1 +master-bin.002 4 Query 1 4 use `test`; create table t1 (n int) +master-bin.002 62 Query 1 62 use `test`; insert into t1 values (1) +master-bin.002 122 Query 1 122 use `test`; drop table t1 show master logs; Log_name master-bin.001 @@ -71,9 +71,9 @@ show binlog events in 'slave-bin.001' from 4; show binlog events in 'slave-bin.002' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info slave-bin.002 4 Slave 2 627 host=127.0.0.1,port=MASTER_PORT,log=master-bin.002,pos=4 -slave-bin.002 57 Query 1 4 use test; create table t1 (n int) -slave-bin.002 115 Query 1 62 use test; insert into t1 values (1) -slave-bin.002 175 Query 1 122 use test; drop table t1 +slave-bin.002 57 Query 1 4 use `test`; create table t1 (n int) +slave-bin.002 115 Query 1 62 use `test`; insert into t1 values (1) +slave-bin.002 175 Query 1 122 use `test`; drop table t1 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space 127.0.0.1 root MASTER_PORT 1 master-bin.002 170 slave-relay-bin.002 916 master-bin.002 Yes Yes 0 0 170 920 diff --git a/mysql-test/t/README b/mysql-test/t/README deleted file mode 100644 index e69de29bb2d..00000000000 --- a/mysql-test/t/README +++ /dev/null diff --git a/mysql-test/t/rollback.test b/mysql-test/t/rollback.test index 6ea2cca887f..bd37e69ae23 100644 --- a/mysql-test/t/rollback.test +++ b/mysql-test/t/rollback.test @@ -8,7 +8,12 @@ create table t1 (n int not null primary key) type=myisam; begin work; insert into t1 values (4); insert into t1 values (5); -# Should give an error -!$1196 rollback; +rollback; +select @@warning_count; +select @@error_count; +show warnings; +show errors; select * from t1; +select @@warning_count; +show warnings; drop table t1; diff --git a/mysql-test/t/rpl_log_pos.test b/mysql-test/t/rpl_log_pos.test index f585fa233c5..b96d32c7fca 100644 --- a/mysql-test/t/rpl_log_pos.test +++ b/mysql-test/t/rpl_log_pos.test @@ -23,6 +23,7 @@ change master to master_log_pos=173; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT slave start; sleep 2; +--replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT show slave status; connection master; show master status; diff --git a/mysys/hash.c b/mysys/hash.c index 7fb634a05b9..43e6981f79d 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -35,11 +35,12 @@ static uint calc_hashnr(CHARSET_INFO *cs,const byte *key,uint length); static uint calc_hashnr_caseup(CHARSET_INFO *cs, const byte *key,uint length); static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length); + my_bool _hash_init(HASH *hash,CHARSET_INFO *charset, - uint size,uint key_offset,uint key_length, - hash_get_key get_key, - void (*free_element)(void*),uint flags CALLER_INFO_PROTO) + uint size,uint key_offset,uint key_length, + hash_get_key get_key, + void (*free_element)(void*),uint flags CALLER_INFO_PROTO) { DBUG_ENTER("hash_init"); DBUG_PRINT("enter",("hash: %lx size: %d",hash,size)); diff --git a/mysys/my_error.c b/mysys/my_error.c index eaa126a31c1..cd41589f366 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -120,7 +120,7 @@ int my_error(int nr,myf MyFlags, ...) ... variable list */ -int my_printf_error (uint error, const char *format, myf MyFlags, ...) +int my_printf_error(uint error, const char *format, myf MyFlags, ...) { va_list args; char ebuff[ERRMSGSIZE+20]; diff --git a/mysys/tree.c b/mysys/tree.c index 489262fcdc7..f72a4961312 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -17,26 +17,33 @@ /* Code for handling red-black (balanced) binary trees. key in tree is allocated accrding to following: - 1) If free_element function is given to init_tree or size < 0 then tree - will not allocate keys and only a pointer to each key is saved in tree. - key_sizes must be 0 to init and search. + + 1) If size < 0 then tree will not allocate keys and only a pointer to + each key is saved in tree. + compare and search functions uses and returns key-pointer + + 2) If size == 0 then there are two options: + - key_size != 0 to tree_insert: The key will be stored in the tree. + - key_size == 0 to tree_insert: A pointer to the key is stored. compare and search functions uses and returns key-pointer. - 2) if key_size is given to init_tree then each node will continue the + + 3) if key_size is given to init_tree then each node will continue the key and calls to insert_key may increase length of key. if key_size > sizeof(pointer) and key_size is a multiple of 8 (double allign) then key will be put on a 8 alligned adress. Else the key will be on adress (element+1). This is transparent for user compare and search functions uses a pointer to given key-argument. - 3) If init_tree - keysize is 0 then key_size must be given to tree_insert - and tree_insert will alloc space for key. - compare and search functions uses a pointer to given key-argument. + + - If you use a free function for tree-elements and you are freeing + the element itself, you should use key_size = 0 to init_tree and + tree_search The actual key in TREE_ELEMENT is saved as a pointer or after the TREE_ELEMENT struct. If one uses only pointers in tree one can use tree_set_pointer() to change address of data. - Copyright Monty Program KB. - By monty. + + Implemented by monty. */ #include "mysys_priv.h" diff --git a/sql/field.cc b/sql/field.cc index c9669c93c04..336bc9d7cc2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -314,6 +314,7 @@ void Field::store_time(TIME *ltime,timestamp_type type) store(buff,(uint) length, default_charset_info); break; } + } } @@ -476,7 +477,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) from++; frac_digits_from= from; /* Read digits at the right of '.' */ - for (;from!=end && my_isdigit(system_charset_info, (*from); from++) ; + for (;from!=end && my_isdigit(system_charset_info, *from); from++) ; frac_digits_end=from; // Some exponentiation symbol ? if (from != end && (*from == 'e' || *from == 'E')) @@ -505,7 +506,8 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) if (current_thd->count_cuted_fields) { - for (;from != end && isspace(*from); from++) ; // Read end spaces + // Skip end spaces + for (;from != end && my_isspace(system_charset_info, *from); from++) ; if (from != end) // If still something left, warn { current_thd->cuted_fields++; @@ -736,10 +738,10 @@ int Field_decimal::store(double nr) #ifdef HAVE_SNPRINTF_ buff[sizeof(buff)-1]=0; // Safety snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr); + length=(uint) strlen(buff); #else - sprintf(buff,"%.*f",dec,nr); + length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr)); #endif - length=(uint) strlen(buff); if (length > field_length) { @@ -2207,10 +2209,10 @@ String *Field_float::val_str(String *val_buffer, #ifdef HAVE_SNPRINTF to[to_length-1]=0; // Safety snprintf(to,to_length-1,"%.*f",dec,nr); + to=strend(to); #else - sprintf(to,"%.*f",dec,nr); + to+= my_sprintf(to,(to,"%.*f",dec,nr)); #endif - to=strend(to); #endif } #ifdef HAVE_FCONVERT @@ -2468,10 +2470,10 @@ String *Field_double::val_str(String *val_buffer, #ifdef HAVE_SNPRINTF to[to_length-1]=0; // Safety snprintf(to,to_length-1,"%.*f",dec,nr); + to=strend(to); #else - sprintf(to,"%.*f",dec,nr); + to+= my_sprintf(to,(to,"%.*f",dec,nr)); #endif - to=strend(to); #endif } #ifdef HAVE_FCONVERT @@ -2886,8 +2888,10 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - sprintf((char*) res.ptr(),"timestamp(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"timestamp(%d)", + (int) field_length)); + res.length(length); } @@ -3026,10 +3030,11 @@ String *Field_time::val_str(String *val_buffer, tmp= -tmp; sign= "-"; } - sprintf((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", - sign,(int) (tmp/10000), (int) (tmp/100 % 100), - (int) (tmp % 100)); - val_buffer->length((uint) strlen(val_buffer->ptr())); + long length= my_sprintf((char*) val_buffer->ptr(), + ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", + sign,(int) (tmp/10000), (int) (tmp/100 % 100), + (int) (tmp % 100))); + val_buffer->length(length); return val_buffer; } @@ -3158,8 +3163,9 @@ String *Field_year::val_str(String *val_buffer, void Field_year::sql_type(String &res) const { - sprintf((char*) res.ptr(),"year(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length=my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"year(%d)",(int) field_length)); + res.length(length); } @@ -3852,12 +3858,14 @@ void Field_string::sort_string(char *to,uint length) void Field_string::sql_type(String &res) const { - sprintf((char*) res.ptr(),"%s(%d)", - field_length > 3 && - (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - "varchar" : "char", - (int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(), "%s(%d)", + (field_length > 3 && + (table->db_options_in_use & + HA_OPTION_PACK_RECORD) ? + "varchar" : "char"), + (int) field_length)); + res.length((uint) length); if (binary_flag) res.append(" binary"); else @@ -4060,8 +4068,10 @@ void Field_varstring::sort_string(char *to,uint length) void Field_varstring::sql_type(String &res) const { - sprintf((char*) res.ptr(),"varchar(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"varchar(%u)", + field_length)); + res.length((uint) length); if (binary_flag) res.append(" binary"); else diff --git a/sql/field.h b/sql/field.h index 551619abc6f..d8cfba14e02 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1036,6 +1036,7 @@ public: uint decimals,flags,pack_length; Field::utype unireg_check; TYPELIB *interval; // Which interval to use + CHARSET_INFO *charset; Field *field; // For alter table uint8 row,col,sc_length,interval_id; // For rea_create_table diff --git a/sql/gstream.h b/sql/gstream.h index f8df6e337b0..f26ef8899f8 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -1,11 +1,19 @@ -#ifndef GSTREAM_H -#define GSTREAM_H +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef WITHOUT_MYSQL - #include ".\rtree\myisamdef.h" -#else - #include "mysql_priv.h" -#endif class GTextReadStream { @@ -20,9 +28,13 @@ public: r_bra, comma, }; - GTextReadStream(const char *buffer, int size) : - m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), m_err_msg(NULL) {} - GTextReadStream() : m_cur(NULL), m_limit(NULL), m_err_msg(NULL) {} + + GTextReadStream(const char *buffer, int size) + :m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), + m_err_msg(NULL) + {} + GTextReadStream(): m_cur(NULL), m_limit(NULL), m_err_msg(NULL) + {} ~GTextReadStream() { @@ -41,21 +53,17 @@ public: void set_error_msg(const char *msg); -// caller should free this pointer + // caller should free this pointer char *get_error_msg() { char *err_msg = m_err_msg; m_err_msg = NULL; return err_msg; } + protected: const char *m_cur; const char *m_limit; const char *m_last_text_position; char *m_err_msg; }; - -#endif - - - diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d42311b43b6..65aaa63f7db 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3557,7 +3557,7 @@ innodb_show_status( ut_free(buf); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/item.cc b/sql/item.cc index 7693ef428c6..946c0f24fe1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -44,10 +44,10 @@ Item::Item() current_thd->free_list=this; } -void Item::set_name(char *str,uint length) +void Item::set_name(const char *str,uint length) { if (!length) - name=str; // Used by AS + name= (char*) str; // Used by AS else { while (length && !my_isgraph(system_charset_info,*str)) @@ -303,21 +303,13 @@ void Item_param::set_int(longlong i) item_type = INT_ITEM; } -void Item_param::set_double(double i) +void Item_param::set_double(double value) { - double value = (double)i; real_value=value; item_result_type = REAL_RESULT; item_type = REAL_ITEM; } -void Item_param::set_double(float i) -{ - float value = (float)i; - real_value=(double)value; - item_result_type = REAL_RESULT; - item_type = REAL_ITEM; -} void Item_param::set_value(const char *str, uint length) { @@ -326,6 +318,7 @@ void Item_param::set_value(const char *str, uint length) item_type = STRING_ITEM; } + void Item_param::set_longdata(const char *str, ulong length) { /* TODO: Fix this for binary handling by making use of @@ -334,16 +327,11 @@ void Item_param::set_longdata(const char *str, ulong length) str_value.append(str,length); } -void Item_param::set_long_end() -{ - long_data_supplied = true; - item_result_type = STRING_RESULT; -}; -int Item_param::save_in_field(Field *field) +int Item_param::save_in_field(Field *field) { if (null_value) - return set_field_to_null(field); + return (int) set_field_to_null(field); field->set_notnull(); if (item_result_type == INT_RESULT) @@ -357,24 +345,21 @@ int Item_param::save_in_field(Field *field) return (field->store(nr)) ? -1 : 0; } String *result; - CHARSET_INFO *cs=default_charset_info;//fix this + CHARSET_INFO *cs=default_charset_info; //fix this result=val_str(&str_value); return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0; } + void Item_param::make_field(Send_field *tmp_field) { init_make_field(tmp_field,FIELD_TYPE_STRING); } + double Item_param::val() { - /* Cross check whether we need need this conversions ? or direct - return(real_value) is enough ? - */ - - switch(item_result_type) { - + switch (item_result_type) { case STRING_RESULT: return (double)atof(str_value.ptr()); case INT_RESULT: @@ -384,16 +369,12 @@ double Item_param::val() } } + longlong Item_param::val_int() { - /* Cross check whether we need need this conversions ? or direct - return(int_value) is enough ? - */ - - switch(item_result_type) { - + switch (item_result_type) { case STRING_RESULT: - return (longlong)strtoll(str_value.ptr(),(char**) 0,10); + return strtoll(str_value.ptr(),(char**) 0,10); case REAL_RESULT: return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5)); default: @@ -401,14 +382,10 @@ longlong Item_param::val_int() } } + String *Item_param::val_str(String* str) { - /* Cross check whether we need need this conversions ? or direct - return(&str_value) is enough ? - */ - - switch(item_result_type) { - + switch (item_result_type) { case INT_RESULT: str->set(int_value); return str; @@ -421,6 +398,7 @@ String *Item_param::val_str(String* str) } /* End of Item_param related */ + void Item_copy_string::copy() { String *res=item->val_str(&str_value); @@ -438,7 +416,7 @@ String *Item_copy_string::val_str(String *str) } /* -** Functions to convert item to field (for send_fields) + Functions to convert item to field (for send_fields) */ /* ARGSUSED */ @@ -614,7 +592,7 @@ void Item_field::save_org_in_field(Field *to) } } -int Item_field::save_in_field(Field *to) +int Item_field::save_in_field(Field *to) { if (result_field->is_null()) { @@ -631,13 +609,13 @@ int Item_field::save_in_field(Field *to) } -int Item_null::save_in_field(Field *field) +int Item_null::save_in_field(Field *field) { return set_field_to_null(field); } -int Item::save_in_field(Field *field) +int Item::save_in_field(Field *field) { int error; if (result_type() == STRING_RESULT || @@ -674,7 +652,7 @@ int Item::save_in_field(Field *field) return (error) ? -1 : 0; } -int Item_string::save_in_field(Field *field) +int Item_string::save_in_field(Field *field) { String *result; CHARSET_INFO *cs=field->binary()?default_charset_info:((Field_str*)field)->charset(); @@ -685,7 +663,7 @@ int Item_string::save_in_field(Field *field) return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0; } -int Item_int::save_in_field(Field *field) +int Item_int::save_in_field(Field *field) { longlong nr=val_int(); if (null_value) @@ -694,7 +672,7 @@ int Item_int::save_in_field(Field *field) return (field->store(nr)) ? -1 : 0; } -int Item_real::save_in_field(Field *field) +int Item_real::save_in_field(Field *field) { double nr=val(); if (null_value) @@ -716,7 +694,8 @@ inline uint char_val(char X) X-'a'+10); } -Item_varbinary::Item_varbinary(const char *str, uint str_length, CHARSET_INFO *cs) +Item_varbinary::Item_varbinary(const char *str, uint str_length, + CHARSET_INFO *cs) { name=(char*) str-2; // Lex makes this start with 0x max_length=(str_length+1)/2; @@ -748,7 +727,7 @@ longlong Item_varbinary::val_int() } -int Item_varbinary::save_in_field(Field *field) +int Item_varbinary::save_in_field(Field *field) { int error; CHARSET_INFO *cs=field->binary()?default_charset_info:((Field_str*)field)->charset(); diff --git a/sql/item.h b/sql/item.h index 206d7b5bd78..84182203d4c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -50,7 +50,7 @@ public: // alloc & destruct is done as start of select using sql_alloc Item(); virtual ~Item() { name=0; } /*lint -e1509 */ - void set_name(char* str,uint length=0); + void set_name(const char *str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual bool fix_fields(THD *, struct st_table_list *, Item **); virtual int save_in_field(Field *field); @@ -82,7 +82,6 @@ public: virtual bool get_date(TIME *ltime,bool fuzzydate); virtual bool get_time(TIME *ltime); virtual bool is_null() { return 0; } - virtual unsigned int size_of()= 0; }; @@ -100,7 +99,6 @@ public: field_name(field_name_par), depended_from(0) { name = (char*) field_name_par; } const char *full_name() const; - unsigned int size_of() { return sizeof(*this);} }; @@ -141,7 +139,6 @@ public: bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } - unsigned int size_of() { return sizeof(*this);} }; @@ -163,7 +160,6 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } - unsigned int size_of() { return sizeof(*this);} }; class Item_param :public Item @@ -176,10 +172,12 @@ public: enum enum_field_types buffer_type; my_bool long_data_supplied; - Item_param(char *name_par=0){ + Item_param(char *name_par=0) + { name= name_par ? name_par : (char*) "?"; long_data_supplied = false; - item_type = STRING_ITEM; item_result_type = STRING_RESULT; + item_type = STRING_ITEM; + item_result_type = STRING_RESULT; } enum Type type() const { return item_type; } double val(); @@ -189,13 +187,13 @@ public: int save_in_field(Field *field); void set_null(); void set_int(longlong i); - void set_double(float i); void set_double(double i); void set_value(const char *str, uint length); void set_long_str(const char *str, ulong length); void set_long_binary(const char *str, ulong length); void set_longdata(const char *str, ulong length); void set_long_end(); + void reset() {} enum Item_result result_type () const { return item_result_type; } Item *new_item() { return new Item_param(name); } @@ -227,7 +225,6 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_int(name,value,max_length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -242,7 +239,6 @@ public: void make_field(Send_field *field); Item *new_item() { return new Item_uint(name,max_length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -273,7 +269,6 @@ public: void make_field(Send_field *field); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_real(name,value,decimals,max_length); } - unsigned int size_of() { return sizeof(*this);} }; @@ -285,7 +280,6 @@ public: decimals=NOT_FIXED_DEC; max_length=DBL_DIG+8; } - unsigned int size_of() { return sizeof(*this);} }; class Item_string :public Item @@ -319,7 +313,6 @@ public: String *const_string() { return &str_value; } inline void append(char *str,uint length) { str_value.append(str,length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -331,7 +324,7 @@ public: Item_default() { name= (char*) "DEFAULT"; } enum Type type() const { return DEFAULT_ITEM; } void make_field(Send_field *field) {} - bool save_in_field(Field *field) + int save_in_field(Field *field) { field->set_default(); return 0; @@ -340,7 +333,6 @@ public: virtual longlong val_int() { return 0; } virtual String *val_str(String *str) { return 0; } bool basic_const_item() const { return 1; } - unsigned int size_of() { return sizeof(*this);} }; @@ -352,7 +344,6 @@ public: Item_datetime(const char *item_name): Item_string(item_name,"",0,default_charset_info) { max_length=19;} void make_field(Send_field *field); - unsigned int size_of() { return sizeof(*this);} }; class Item_empty_string :public Item_string @@ -360,7 +351,6 @@ class Item_empty_string :public Item_string public: Item_empty_string(const char *header,uint length) :Item_string("",0,default_charset_info) { name=(char*) header; max_length=length;} - unsigned int size_of() { return sizeof(*this);} }; class Item_varbinary :public Item @@ -375,7 +365,6 @@ public: int save_in_field(Field *field); void make_field(Send_field *field); enum Item_result result_type () const { return INT_RESULT; } - unsigned int size_of() { return sizeof(*this);} }; @@ -388,7 +377,6 @@ public: Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } table_map used_tables() const { return 1; } virtual void fix_length_and_dec()=0; - unsigned int size_of() { return sizeof(*this);} }; @@ -438,7 +426,6 @@ public: void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } table_map used_tables() const { return (*ref)->used_tables(); } - unsigned int size_of() { return sizeof(*this);} }; @@ -458,10 +445,10 @@ public: { return ref->save_in_field(field); } - unsigned int size_of() { return sizeof(*this);} }; +#include "gstream.h" #include "spatial.h" #include "item_sum.h" #include "item_func.h" @@ -495,7 +482,6 @@ public: table_map used_tables() const { return (table_map) 1L; } bool const_item() const { return 0; } bool is_null() { return null_value; } - unsigned int size_of() { return sizeof(*this);} }; @@ -506,7 +492,6 @@ public: Item_buff() :null_value(0) {} virtual bool cmp(void)=0; virtual ~Item_buff(); /*line -e1509 */ - unsigned int size_of() { return sizeof(*this);} }; class Item_str_buff :public Item_buff @@ -517,7 +502,6 @@ public: Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {} bool cmp(void); ~Item_str_buff(); // Deallocate String:s - unsigned int size_of() { return sizeof(*this);} }; @@ -528,7 +512,6 @@ class Item_real_buff :public Item_buff public: Item_real_buff(Item *item_par) :item(item_par),value(0.0) {} bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; class Item_int_buff :public Item_buff @@ -538,7 +521,6 @@ class Item_int_buff :public Item_buff public: Item_int_buff(Item *item_par) :item(item_par),value(0) {} bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; @@ -555,7 +537,6 @@ public: buff= (char*) sql_calloc(length=field->pack_length()); } bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; extern Item_buff *new_Item_buff(Item *item); diff --git a/sql/item_func.cc b/sql/item_func.cc index bd811726b47..ed7398b4f94 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -22,14 +22,13 @@ #endif #include "mysql_priv.h" +#include "slave.h" // for wait_for_master_pos #include <m_ctype.h> #include <hash.h> #include <time.h> #include <ft_global.h> #include <zlib.h> -#include "slave.h" // for wait_for_master_pos -#include "gstream.h" - +#include <assert.h> /* return TRUE if item is a constant */ @@ -231,9 +230,11 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) break; case STRING_RESULT: if (max_length > 255) - res= new Field_blob(max_length, maybe_null, name, t_arg, binary); + res= new Field_blob(max_length, maybe_null, name, t_arg, binary, + str_value.charset()); else - res= new Field_string(max_length, maybe_null, name, t_arg, binary); + res= new Field_string(max_length, maybe_null, name, t_arg, binary, + str_value.charset()); break; } return res; @@ -2390,18 +2391,19 @@ longlong Item_func_bit_xor::val_int() Item *get_system_var(enum_var_type var_type, LEX_STRING name) { - if (!my_strcasecmp(name.str,"VERSION")) - return new Item_string("@@VERSION",server_version, - (uint) strlen(server_version)); + if (!my_strcasecmp(system_charset_info, name.str, "VERSION")) + return new Item_string("@@VERSION", server_version, + (uint) strlen(server_version), + system_charset_info); THD *thd=current_thd; Item *item; sys_var *var; char buff[MAX_SYS_VAR_LENGTH+3]; - if (!(var= find_sys_var(name.str))) + if (!(var= find_sys_var(name.str, name.length))) { - net_printf(&thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); + net_printf(thd, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); return 0; } if (!(item=var->item(thd, var_type))) @@ -2415,6 +2417,23 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name) } +Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, + const char *item_name) +{ + THD *thd=current_thd; + Item *item; + sys_var *var; + + var= find_sys_var(var_name, length); + DBUG_ASSERT(var != 0); + if (!(item=var->item(thd, var_type))) + return 0; // Impossible + thd->safe_to_cache_query=0; + item->set_name(item_name); // Will use original name + return item; +} + + /* Check a user level lock. diff --git a/sql/item_func.h b/sql/item_func.h index 45427bec017..3ef25a1fae2 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -39,7 +39,7 @@ public: enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, - COND_AND_FUNC, COND_OR_FUNC, CONX_XOR_FUNC, BETWEEN, IN_FUNC, + COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC, INTERVAL_FUNC, SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC, SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 2bc9b170fc1..1b091f29a6b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2394,8 +2394,6 @@ null: General functions for spatial objects ********************************************************/ -#include "gstream.h" - String *Item_func_geometry_from_text::val_str(String *str) { Geometry geom; @@ -2715,7 +2713,7 @@ String *Item_func_spatial_collection::val_str(String *str) } } - if (str->length() > max_allowed_packet) + if (str->length() > current_thd->variables.max_allowed_packet) goto ret; null_value = 0; diff --git a/sql/item_sum.h b/sql/item_sum.h index 3c86370c189..3e67f1e3624 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -70,7 +70,6 @@ public: void print(String *str); void fix_num_length_and_dec(); virtual bool setup(THD *thd) {return 0;} - unsigned int size_of() { return sizeof(*this);} }; @@ -85,7 +84,6 @@ public: longlong val_int() { return (longlong) val(); } /* Real as default */ String *val_str(String*str); void reset_field(); - unsigned int size_of() { return sizeof(*this);} }; @@ -100,7 +98,6 @@ public: double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } - unsigned int size_of() { return sizeof(*this);} }; @@ -118,7 +115,6 @@ class Item_sum_sum :public Item_sum_num void reset_field(); void update_field(int offset); const char *func_name() const { return "sum"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -141,7 +137,6 @@ class Item_sum_count :public Item_sum_int void reset_field(); void update_field(int offset); const char *func_name() const { return "count"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -193,7 +188,6 @@ class Item_sum_count_distinct :public Item_sum_int void update_field(int offset) { return ; } // Never called const char *func_name() const { return "count_distinct"; } bool setup(THD *thd); - unsigned int size_of() { return sizeof(*this);} }; @@ -213,7 +207,6 @@ public: String *val_str(String*); void make_field(Send_field *field); void fix_length_and_dec() {} - unsigned int size_of() { return sizeof(*this);} }; @@ -235,7 +228,6 @@ class Item_sum_avg :public Item_sum_num Item *result_item(Field *field) { return new Item_avg_field(this); } const char *func_name() const { return "avg"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_sum_std; @@ -252,7 +244,6 @@ public: bool is_null() { (void) val_int(); return null_value; } void make_field(Send_field *field); void fix_length_and_dec() {} - unsigned int size_of() { return sizeof(*this);} }; class Item_sum_std :public Item_sum_num @@ -273,7 +264,6 @@ class Item_sum_std :public Item_sum_num Item *result_item(Field *field) { return new Item_std_field(this); } const char *func_name() const { return "std"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -316,7 +306,6 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(int offset); void min_max_update_real_field(int offset); void min_max_update_int_field(int offset); - unsigned int size_of() { return sizeof(*this);} }; @@ -328,7 +317,6 @@ public: bool add(); const char *func_name() const { return "min"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -340,7 +328,6 @@ public: bool add(); const char *func_name() const { return "max"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -356,7 +343,6 @@ class Item_sum_bit :public Item_sum_int void reset(); longlong val_int(); void reset_field(); - unsigned int size_of() { return sizeof(*this);} }; @@ -367,7 +353,6 @@ class Item_sum_or :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_or"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -378,7 +363,6 @@ class Item_sum_and :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_and"; } - unsigned int size_of() { return sizeof(*this);} }; /* @@ -409,7 +393,6 @@ public: bool add(); void reset_field() {}; void update_field(int offset_arg) {}; - unsigned int size_of() { return sizeof(*this);} }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 566097893a8..b42b78c9c91 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -477,11 +477,10 @@ void Item_func_curtime::fix_length_and_dec() value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+ (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec)); - sprintf(buff,"%02d:%02d:%02d", - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - buff_length=(uint) strlen(buff); + buff_length= my_sprintf(buff, (buff,"%02d:%02d:%02d", + (int) start->tm_hour, + (int) start->tm_min, + (int) start->tm_sec)); } void Item_func_now::fix_length_and_dec() @@ -497,14 +496,13 @@ void Item_func_now::fix_length_and_dec() (longlong) ((ulong) ((uint) start->tm_hour)*10000L+ (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec))); - sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", - ((int) (start->tm_year+1900)) % 10000, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - buff_length=(uint) strlen(buff); + buff_length= (uint) my_sprintf(buff, (buff,"%04d-%02d-%02d %02d:%02d:%02d", + ((int) (start->tm_year+1900)) % 10000, + (int) start->tm_mon+1, + (int) start->tm_mday, + (int) start->tm_hour, + (int) start->tm_min, + (int) start->tm_sec)); /* For getdate */ ltime.year= start->tm_year+1900; ltime.month= start->tm_mon+1; @@ -538,6 +536,7 @@ String *Item_func_sec_to_time::val_str(String *str) char buff[23]; const char *sign=""; longlong seconds=(longlong) args[0]->val_int(); + ulong length; if ((null_value=args[0]->null_value)) return (String*) 0; if (seconds < 0) @@ -546,9 +545,9 @@ String *Item_func_sec_to_time::val_str(String *str) sign= "-"; } uint sec= (uint) ((ulonglong) seconds % 3600); - sprintf(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), - sec/60, sec % 60); - str->copy(buff,(uint) strlen(buff)); + length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), + sec/60, sec % 60)); + str->copy(buff, length); return str; } @@ -658,6 +657,7 @@ String *Item_func_date_format::val_str(String *str) TIME l_time; char intbuff[15]; uint size,weekday; + ulong length; if (!date_or_time) { @@ -750,40 +750,39 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - sprintf(intbuff,"%d",l_time.day); - str->append(intbuff); + length= my_sprintf(intbuff, (intbuff,"%d",l_time.day)); + str->append(intbuff, length); if (l_time.day >= 10 && l_time.day <= 19) str->append("th"); else { - switch (l_time.day %10) - { + switch (l_time.day %10) { case 1: - str->append("st"); + str->append("st",2); break; case 2: - str->append("nd"); + str->append("nd",2); break; case 3: - str->append("rd"); + str->append("rd",2); break; default: - str->append("th"); + str->append("th",2); break; } } break; case 'Y': sprintf(intbuff,"%04d",l_time.year); - str->append(intbuff); + str->append(intbuff,4); break; case 'y': sprintf(intbuff,"%02d",l_time.year%100); - str->append(intbuff); + str->append(intbuff,2); break; case 'm': sprintf(intbuff,"%02d",l_time.month); - str->append(intbuff); + str->append(intbuff,2); break; case 'c': sprintf(intbuff,"%d",l_time.month); @@ -791,7 +790,7 @@ String *Item_func_date_format::val_str(String *str) break; case 'd': sprintf(intbuff,"%02d",l_time.day); - str->append(intbuff); + str->append(intbuff,2); break; case 'e': sprintf(intbuff,"%d",l_time.day); @@ -799,16 +798,16 @@ String *Item_func_date_format::val_str(String *str) break; case 'H': sprintf(intbuff,"%02d",l_time.hour); - str->append(intbuff); + str->append(intbuff,2); break; case 'h': case 'I': sprintf(intbuff,"%02d", (l_time.hour+11)%12+1); - str->append(intbuff); + str->append(intbuff,2); break; case 'i': /* minutes */ sprintf(intbuff,"%02d",l_time.minute); - str->append(intbuff); + str->append(intbuff,2); break; case 'j': if (date_or_time) @@ -819,7 +818,7 @@ String *Item_func_date_format::val_str(String *str) sprintf(intbuff,"%03d", (int) (calc_daynr(l_time.year,l_time.month,l_time.day) - calc_daynr(l_time.year,1,1)) + 1); - str->append(intbuff); + str->append(intbuff,3); break; case 'k': sprintf(intbuff,"%d",l_time.hour); @@ -830,7 +829,7 @@ String *Item_func_date_format::val_str(String *str) str->append(intbuff); break; case 'p': - str->append(l_time.hour < 12 ? "AM" : "PM"); + str->append(l_time.hour < 12 ? "AM" : "PM",2); break; case 'r': sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" : @@ -844,7 +843,8 @@ String *Item_func_date_format::val_str(String *str) str->append(intbuff); break; case 'T': - sprintf(intbuff,"%02d:%02d:%02d",l_time.hour,l_time.minute,l_time.second); + sprintf(intbuff,"%02d:%02d:%02d", l_time.hour, l_time.minute, + l_time.second); str->append(intbuff); break; case 'U': @@ -852,7 +852,7 @@ String *Item_func_date_format::val_str(String *str) { uint year; sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year)); - str->append(intbuff); + str->append(intbuff,2); } break; case 'v': @@ -860,7 +860,7 @@ String *Item_func_date_format::val_str(String *str) { uint year; sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year)); - str->append(intbuff); + str->append(intbuff,2); } break; case 'x': @@ -869,13 +869,13 @@ String *Item_func_date_format::val_str(String *str) uint year; (void) calc_week(&l_time, 1, (*ptr) == 'X', &year); sprintf(intbuff,"%04d",year); - str->append(intbuff); + str->append(intbuff,4); } break; case 'w': weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1); - sprintf(intbuff,"%01d",weekday); - str->append(intbuff); + sprintf(intbuff,"%d",weekday); + str->append(intbuff,1); break; default: str->append(*ptr); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a45ea159014..94e8e6eba43 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -176,7 +176,6 @@ public: const char *func_name() const { return "weekday"; } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_dayname :public Item_func_weekday @@ -202,7 +201,6 @@ public: { decimals=0; max_length=10; } - unsigned int size_of() { return sizeof(*this);} }; @@ -240,7 +238,6 @@ public: { return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg); } - unsigned int size_of() { return sizeof(*this);} }; @@ -259,7 +256,6 @@ public: return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, t_arg); } - unsigned int size_of() { return sizeof(*this);} }; @@ -286,7 +282,6 @@ public: { return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); } - unsigned int size_of() { return sizeof(*this);} }; @@ -300,7 +295,6 @@ public: const char *func_name() const { return "curdate"; } void fix_length_and_dec(); /* Retrieves curtime */ bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; @@ -322,7 +316,6 @@ public: const char *func_name() const { return "now"; } void fix_length_and_dec(); bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; @@ -347,7 +340,6 @@ public: const char *func_name() const { return "date_format"; } void fix_length_and_dec(); uint format_length(const String *format); - unsigned int size_of() { return sizeof(*this);} }; @@ -407,7 +399,6 @@ public: double val() { return (double) val_int(); } longlong val_int(); bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; class Item_extract :public Item_int_func @@ -421,7 +412,6 @@ class Item_extract :public Item_int_func longlong val_int(); const char *func_name() const { return "extract"; } void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; class Item_typecast :public Item_str_func diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 6ab01d55e2f..f0d1d353cfb 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,9 +29,9 @@ public: :Item_real_func(list) {} double val() { return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } - unsigned int size_of() { return sizeof(*this);} }; + class Item_sum_unique_users :public Item_sum_num { public: diff --git a/sql/lex.h b/sql/lex.h index 83890e75c20..b9e993c54c7 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -327,7 +327,6 @@ static SYMBOL symbols[] = { { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0}, { "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0}, - { "SQL_ERROR_COUNT", SYM(SQL_ERROR_COUNT),0,0}, { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0}, { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0}, { "SQL_THREAD", SYM(SQL_THREAD),0,0}, diff --git a/sql/log.cc b/sql/log.cc index b3ce1226210..213f5102507 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -215,15 +215,18 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, time_t skr=time(NULL); struct tm tm_tmp; localtime_r(&skr,&tm_tmp); - sprintf(buff,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n", - my_progname,server_version, - tm_tmp.tm_year % 100, - tm_tmp.tm_mon+1, - tm_tmp.tm_mday, - tm_tmp.tm_hour, - tm_tmp.tm_min, - tm_tmp.tm_sec); - if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) || + ulong length; + length= my_sprintf(buff, + (buff, + "# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n", + my_progname,server_version, + tm_tmp.tm_year % 100, + tm_tmp.tm_mon+1, + tm_tmp.tm_mday, + tm_tmp.tm_hour, + tm_tmp.tm_min, + tm_tmp.tm_sec)); + if (my_b_write(&log_file, (byte*) buff, length) || flush_io_cache(&log_file)) goto err; break; @@ -931,7 +934,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, { if (is_open() && (what_to_log & (1L << (uint) command))) { - int error=0; + uint length; + int error= 0; VOID(pthread_mutex_lock(&LOCK_log)); /* Test if someone closed after the is_open test */ @@ -965,6 +969,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, last_time=skr; struct tm tm_tmp; struct tm *start; + ulong length; localtime_r(&skr,&tm_tmp); start=&tm_tmp; /* Note that my_b_write() assumes it knows the length for this */ @@ -980,8 +985,10 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, } else if (my_b_write(&log_file, (byte*) "\t\t",2) < 0) error=errno; - sprintf(buff,"%7ld %-11.11s", id,command_name[(uint) command]); - if (my_b_write(&log_file, (byte*) buff,strlen(buff))) + length=my_sprintf(buff, + (buff, "%7ld %-11.11s", id, + command_name[(uint) command])); + if (my_b_write(&log_file, (byte*) buff,length)) error=errno; if (format) { @@ -1218,11 +1225,7 @@ err: /* Write update log in a format suitable for incremental backup - - NOTE - - This code should be deleted in MySQL 5,0 as the binary log - is a full replacement for the update log. - + This is also used by the slow query log. */ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, diff --git a/sql/log_event.cc b/sql/log_event.cc index 23622bc0141..df5ef4eb7fe 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1516,9 +1516,12 @@ void Append_block_log_event::print(FILE* file, bool short_form, #ifndef MYSQL_CLIENT void Append_block_log_event::pack_info(String* packet) { - char buf1[256]; - sprintf(buf1, ";file_id=%u;block_len=%u", file_id, block_len); - net_store_data(packet, buf1); + char buf[256]; + uint length; + length= (uint) my_sprintf(buf, + (buf, ";file_id=%u;block_len=%u", file_id, + block_len)); + net_store_data(packet, buf, length); } @@ -1560,9 +1563,10 @@ void Delete_file_log_event::print(FILE* file, bool short_form, #ifndef MYSQL_CLIENT void Delete_file_log_event::pack_info(String* packet) { - char buf1[64]; - sprintf(buf1, ";file_id=%u", (uint) file_id); - net_store_data(packet, buf1); + char buf[64]; + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, length); } #endif @@ -1607,8 +1611,9 @@ void Execute_load_log_event::print(FILE* file, bool short_form, void Execute_load_log_event::pack_info(String* packet) { char buf[64]; - sprintf(buf, ";file_id=%u", (uint) file_id); - net_store_data(packet, buf); + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, length); } #endif diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 5bd88e9b09a..d678e76c5ed 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -40,6 +40,7 @@ #include "mysql_version.h" #include "mysqld_error.h" #include "errmsg.h" +#include <assert.h> #if defined( OS2) && defined(MYSQL_SERVER) #undef ER @@ -124,7 +125,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, if (!host || !strcmp(host,LOCAL_HOST)) host=LOCAL_HOST_NAMEDPIPE; - sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket); + sprintf(szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket); DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", host, unix_socket)); @@ -456,15 +457,14 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command, if (!arg) arg=""; - if (net_write_command(net,(uchar) command,arg, - length ? length :(uint) strlen(arg))) + if (net_write_command(net, (uchar) command, NullS, 0, 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)); mc_end_server(mysql); if (mc_mysql_reconnect(mysql)) goto end; - if (net_write_command(net,(uchar) command,arg, - length ? length :(uint) strlen(arg))) + if (net_write_command(net,(uchar) command, NullS, 0, arg, length)) { net->last_errno=CR_SERVER_GONE_ERROR; strmov(net->last_error,ER(net->last_errno)); @@ -1027,18 +1027,19 @@ get_info: DBUG_RETURN(0); } -int mc_mysql_query(MYSQL *mysql, const char *query, uint length) + +int mc_mysql_query(MYSQL *mysql, const char *query, uint length) { - DBUG_ENTER("mysql_real_query"); + DBUG_ENTER("mc_mysql_query"); DBUG_PRINT("enter",("handle: %lx",mysql)); DBUG_PRINT("query",("Query = \"%s\"",query)); - if (!length) - length = strlen(query); + DBUG_ASSERT(length == strlen(query)); if (mc_simple_command(mysql,COM_QUERY,query,length,1)) DBUG_RETURN(-1); DBUG_RETURN(mc_mysql_read_query_result(mysql)); } + static int mc_send_file_to_server(MYSQL *mysql, const char *filename) { int fd, readcount, result= -1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 61973c5af91..4532646b1c2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -294,7 +294,7 @@ inline THD *_current_thd(void) #define prepare_execute(A) ((A)->command == COM_EXECUTE) int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); -int mysql_alter_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); +int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists); @@ -308,8 +308,13 @@ int quick_rm_table(enum db_type base,const char *db, bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); +void free_items(Item *item); +bool alloc_query(THD *thd, char *packet, ulong packet_length); void mysql_init_select(LEX *lex); +void mysql_init_query(THD *thd); +void mysql_reset_errors(THD *thd); bool mysql_new_select(LEX *lex, bool move_down); +void create_select_for_variable(const char *var_name); void mysql_init_multi_delete(LEX *lex); void init_max_user_conn(void); void free_max_user_conn(void); @@ -318,7 +323,7 @@ pthread_handler_decl(handle_bootstrap,arg); sig_handler end_thread_signal(int sig); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); -void mysql_execute_command(void); +void mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); @@ -349,11 +354,12 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, bool check_simple_select(); /* net_pkg.c */ -void send_warning(NET *net, uint sql_errno, const char *err=0); -void net_printf(NET *net,uint sql_errno, ...); -void send_ok(NET *net,ha_rows affected_rows=0L,ulonglong id=0L, +void send_warning(THD *thd, uint sql_errno, const char *err=0); +void net_printf(THD *thd,uint sql_errno, ...); +void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); -void send_eof(NET *net,bool no_flush=0); +void send_eof(THD *thd, bool no_flush=0); +void net_send_error(NET *net, uint sql_errno, const char *err); char *net_store_length(char *packet,ulonglong length); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from); @@ -391,7 +397,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List<create_field> &fields, List<Key> &keys, - bool tmp_table, bool no_log); + bool tmp_table, bool no_log, uint select_field_count); TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, const char *db, const char *name, List<create_field> *extra_fields, @@ -491,20 +497,19 @@ int mysqld_show_privileges(THD *thd); int mysqld_show_column_types(THD *thd); /* sql_prepare.cc */ -void mysql_com_prepare(THD *thd,char*packet,uint packet_length); -void mysql_init_query(THD *thd);/* sql_parse. cc */ -void mysql_com_execute(THD *thd); -void mysql_com_longdata(THD *thd); +int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used); +void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used); +bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); +void mysql_stmt_execute(THD *thd, char *packet); +void mysql_stm_close(THD *thd, char *packet); +void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, List<Item> &values, ulong counter); /* sql_error.cc */ -void push_error(uint code, const char *msg); -void push_warning(uint code, const char *msg); -int mysqld_show_warnings(THD *thd); -int mysqld_show_errors(THD *thd); -int mysqld_show_warnings_count(THD *thd); -int mysqld_show_errors_count(THD *); +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, + const char *msg); +my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show); /* sql_handler.cc */ int mysql_ha_open(THD *thd, TABLE_LIST *tables); @@ -682,13 +687,13 @@ extern char f_fyllchar; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; extern FILE *bootstrap_file; extern pthread_key(MEM_ROOT*,THR_MALLOC); -extern pthread_key(NET*, THR_NET); extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status, - LOCK_grant, LOCK_error_log, LOCK_delayed_insert, + LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables; +extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; @@ -737,7 +742,7 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list); void unireg_init(ulong options); void unireg_end(int signal); -int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info, +int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info, List<create_field> &create_field, uint key_count,KEY *key_info); int format_number(uint inputflag,uint max_length,my_string pos,uint length, @@ -818,6 +823,8 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length); /* item.cc */ Item *get_system_var(enum_var_type var_type, LEX_STRING name); +Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, + const char *item_name); /* Some inline functions for more speed */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 89f1c07b2fe..8c3db86e44f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -240,6 +240,8 @@ SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES; SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO; #endif +const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; + bool opt_large_files= sizeof(my_off_t) > 4; /* @@ -413,15 +415,14 @@ my_bool use_temp_pool=0; pthread_key(MEM_ROOT*,THR_MALLOC); pthread_key(THD*, THR_THD); -pthread_key(NET*, THR_NET); pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, - LOCK_mapped_file, LOCK_status, LOCK_grant, + LOCK_mapped_file, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; - +rw_lock_t LOCK_grant; pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped, COND_slave_start; pthread_cond_t COND_thread_cache,COND_flush_thread_cache; @@ -1042,7 +1043,7 @@ static void server_init(void) if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe) { - sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port ); + sprintf(szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port ); ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) ); ZeroMemory( &sdPipeDescriptor, sizeof(sdPipeDescriptor) ); if ( !InitializeSecurityDescriptor(&sdPipeDescriptor, @@ -1127,12 +1128,12 @@ static void server_init(void) void yyerror(const char *s) { - NET *net=my_pthread_getspecific_ptr(NET*,THR_NET); - char *yytext=(char*) current_lex->tok_start; + THD *thd=current_thd; + char *yytext=(char*) thd->lex.tok_start; if (!strcmp(s,"parse error")) s=ER(ER_SYNTAX_ERROR); - net_printf(net,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "", - current_lex->yylineno); + net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "", + thd->lex.yylineno); } @@ -1148,7 +1149,7 @@ void close_connection(NET *net,uint errcode,bool lock) if ((vio=net->vio) != 0) { if (errcode) - send_error(net,errcode,ER(errcode)); /* purecov: inspected */ + net_send_error(net,errcode,ER(errcode)); /* purecov: inspected */ vio_close(vio); /* vio is freed in delete thd */ } if (lock) @@ -1541,8 +1542,8 @@ static void *signal_hand(void *arg __attribute__((unused))) if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0) { char buff[21]; - sprintf(buff,"%lu",(ulong) getpid()); - (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME)); + ulong length= my_sprintf(buff, (buff,"%lu",(ulong) getpid())); + (void) my_write(pidFile, buff, length, MYF(MY_WME)); (void) my_close(pidFile,MYF(0)); } } @@ -1640,11 +1641,12 @@ static void *signal_hand(void *arg __attribute__((unused))) static int my_message_sql(uint error, const char *str, myf MyFlags __attribute__((unused))) { - NET *net; + THD *thd; DBUG_ENTER("my_message_sql"); DBUG_PRINT("error",("Message: '%s'",str)); - if ((net=my_pthread_getspecific_ptr(NET*,THR_NET))) + if ((thd=current_thd)) { + NET *net= &thd->net; if (!net->last_error[0]) // Return only first message { strmake(net->last_error,str,sizeof(net->last_error)-1); @@ -1853,7 +1855,6 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); @@ -1871,6 +1872,7 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); @@ -2027,7 +2029,7 @@ int main(int argc, char **argv) After this we can't quit by a simple unireg_abort */ error_handler_hook = my_message_sql; - if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) || + if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_MALLOC,NULL)) { sql_print_error("Can't create thread-keys"); @@ -2481,7 +2483,7 @@ static void create_new_thread(THD *thd) thread_count--; thd->killed=1; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); - net_printf(net,ER_CANT_CREATE_THREAD,error); + net_printf(thd,ER_CANT_CREATE_THREAD,error); (void) pthread_mutex_lock(&LOCK_thread_count); close_connection(net,0,0); delete thd; @@ -2886,6 +2888,7 @@ enum options { OPT_MAX_JOIN_SIZE, OPT_MAX_SORT_LENGTH, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, + OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, @@ -3506,6 +3509,11 @@ struct my_option my_long_options[] = "Don't start more than this number of threads to handle INSERT DELAYED statements.", (gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads, 0, GET_ULONG, REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, + {"max_error_count", OPT_MAX_ERROR_COUNT, + "Max number of errors/warnings to store for a statement", + (gptr*) &global_system_variables.max_error_count, + (gptr*) &max_system_variables.max_error_count, + 0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 1, 65535, 0, 1, 0}, {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE, "Don't allow creation of heap tables bigger than this.", (gptr*) &global_system_variables.max_heap_table_size, @@ -3516,6 +3524,11 @@ struct my_option my_long_options[] = (gptr*) &global_system_variables.max_join_size, (gptr*) &max_system_variables.max_join_size, 0, GET_ULONG, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, + {"max_prepared_statements", OPT_MAX_PREP_STMT, + "Max number of prepared_statements for a thread", + (gptr*) &global_system_variables.max_prep_stmt_count, + (gptr*) &max_system_variables.max_prep_stmt_count, 0, GET_ULONG, + REQUIRED_ARG, DEFAULT_PREP_STMT_COUNT, 0, ~0L, 0, 1, 0}, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).", (gptr*) &global_system_variables.max_sort_length, diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index 1e7536e3007..19234181839 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -20,19 +20,17 @@ /* Send a error string to client */ -void send_error(NET *net, uint sql_errno, const char *err) +void send_error(THD *thd, uint sql_errno, const char *err) { uint length; char buff[MYSQL_ERRMSG_SIZE+2]; - THD *thd=current_thd; + NET *net= &thd->net; DBUG_ENTER("send_error"); DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err ? err : net->last_error[0] ? - net->last_error : "NULL")); + net->last_error : "NULL")); query_cache_abort(net); - if (thd) - thd->query_error = 1; // needed to catch query errors during replication if (!err) { if (sql_errno) @@ -48,10 +46,9 @@ void send_error(NET *net, uint sql_errno, const char *err) } } } - push_error(sql_errno, err); if (net->vio == 0) { - if (thd && thd->bootstrap) + if (thd->bootstrap) { /* In bootstrap it's ok to print on stderr */ fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); @@ -68,53 +65,73 @@ void send_error(NET *net, uint sql_errno, const char *err) else { length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); } - VOID(net_write_command(net,(uchar) 255,(char*) err,length)); - if (thd) - thd->fatal_error=0; // Error message is given + VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); + thd->fatal_error=0; // Error message is given DBUG_VOID_RETURN; } /* - At some point we need to be able to distinguish between warnings and - errors; The following function will help make this easier. + Send an error to the client when a connection is forced close + This is used by mysqld.cc, which doesn't have a THD */ -void send_warning(NET *net, uint sql_errno, const char *err) +void net_send_error(NET *net, uint sql_errno, const char *err) { - DBUG_ENTER("send_warning"); - push_warning(sql_errno, err ? err : ER(sql_errno)); + char buff[2]; + uint length; + DBUG_ENTER("send_net_error"); - /* - TODO : - Try to return ok with warning status to client, instead - of returning error .. - */ - send_error(net,sql_errno,err); + int2store(buff,sql_errno); + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + net_write_command(net,(uchar) 255, buff, 2, err, length); + DBUG_VOID_RETURN; +} + + +/* + Send a warning to the end user + + SYNOPSIS + send_warning() + thd Thread handler + sql_errno Warning number (error message) + err Error string. If not set, use ER(sql_errno) + + DESCRIPTION + Register the warning so that the user can get it with mysql_warnings() + Send an ok (+ warning count) to the end user. +*/ + +void send_warning(THD *thd, uint sql_errno, const char *err) +{ + DBUG_ENTER("send_warning"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, + err ? err : ER(sql_errno)); + send_ok(thd); DBUG_VOID_RETURN; } /* Write error package and flush to client - It's a little too low level, but I don't want to allow another buffer + It's a little too low level, but I don't want to use another buffer for + this */ -/* VARARGS3 */ void -net_printf(NET *net, uint errcode, ...) +net_printf(THD *thd, uint errcode, ...) { va_list args; uint length,offset; const char *format,*text_pos; int head_length= NET_HEADER_SIZE; - THD *thd=current_thd; + NET *net= &thd->net; DBUG_ENTER("net_printf"); DBUG_PRINT("enter",("message: %u",errcode)); - if (thd) - thd->query_error = 1; // if we are here, something is wrong :-) query_cache_abort(net); // Safety va_start(args,errcode); /* @@ -132,10 +149,9 @@ net_printf(NET *net, uint errcode, ...) length=sizeof(net->last_error)-1; /* purecov: inspected */ va_end(args); - push_error(errcode, text_pos); if (net->vio == 0) { - if (thd && thd->bootstrap) + if (thd->bootstrap) { /* In bootstrap it's ok to print on stderr */ fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); @@ -150,16 +166,42 @@ net_printf(NET *net, uint errcode, ...) if (offset) int2store(text_pos-2, errcode); VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); - if (thd) - thd->fatal_error=0; // Error message is given + thd->fatal_error=0; // Error message is given DBUG_VOID_RETURN; } +/* + Return ok to the client. + + SYNOPSIS + send_ok() + thd Thread handler + affected_rows Number of rows changed by statement + id Auto_increment id for first row (if used) + message Message to send to the client (Used by mysql_status) + + DESCRIPTION + The ok packet has the following structure + + 0 Marker (1 byte) + affected_rows Stored in 1-9 bytes + id Stored in 1-9 bytes + server_status Copy of thd->server_status; Can be used by client + to check if we are inside an transaction + New in 4.0 protocol + warning_count Stored in 2 bytes; New in 4.1 protocol + message Stored as packed length (1-9 bytes) + message + Is not stored if no message + + If net->no_send_ok return without sending packet +*/ + void -send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message) +send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) { - if (net->no_send_ok) // hack for re-parsing queries + NET *net= &thd->net; + if (net->no_send_ok || !net->vio) // hack for re-parsing queries return; char buff[MYSQL_ERRMSG_SIZE+10],*pos; @@ -167,31 +209,75 @@ send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message) buff[0]=0; // No fields pos=net_store_length(buff+1,(ulonglong) affected_rows); pos=net_store_length(pos, (ulonglong) id); - if (net->return_status) + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + int2store(pos,thd->server_status); + pos+=2; + + /* We can only return up to 65535 warnings in two bytes */ + uint tmp= min(thd->total_warn_count, 65535); + int2store(pos, tmp); + pos+= 2; + } + else if (net->return_status) // For 4.0 protocol { - int2store(pos,*net->return_status); + int2store(pos,thd->server_status); pos+=2; } if (message) pos=net_store_data((char*) pos,message); - if (net->vio != 0) - { - VOID(my_net_write(net,buff,(uint) (pos-buff))); - VOID(net_flush(net)); - } + VOID(my_net_write(net,buff,(uint) (pos-buff))); + VOID(net_flush(net)); DBUG_VOID_RETURN; } + +/* + Send eof (= end of result set) to the client + + SYNOPSIS + send_eof() + thd Thread handler + no_flush Set to 1 if there will be more data to the client, + like in send_fields(). + + DESCRIPTION + The eof packet has the following structure + + 254 Marker (1 byte) + warning_count Stored in 2 bytes; New in 4.1 protocol + status_flag Stored in 2 bytes; + For flags like SERVER_STATUS_MORE_RESULTS + + Note that the warning count will not be sent if 'no_flush' is set as + we don't want to report the warning count until all data is sent to the + client. +*/ + void -send_eof(NET *net,bool no_flush) +send_eof(THD *thd, bool no_flush) { static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ + NET *net= &thd->net; DBUG_ENTER("send_eof"); if (net->vio != 0) { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) + if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) + { + char buff[5]; + uint tmp= min(thd->total_warn_count, 65535); + buff[0]=254; + int2store(buff+1, tmp); + int2store(buff+3, 0); // No flags yet + VOID(my_net_write(net,buff,5)); VOID(net_flush(net)); + } + else + { + VOID(my_net_write(net,eof_buff,1)); + if (!no_flush) + VOID(net_flush(net)); + } } DBUG_VOID_RETURN; } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index bb7100f31be..538ff5babe6 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -75,12 +75,12 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #define TEST_BLOCKING 8 #define MAX_THREE_BYTES 255L*255L*255L -static int net_write_buff(NET *net,const char *packet,ulong len); +static my_bool net_write_buff(NET *net,const char *packet,ulong len); /* Init with packet info */ -int my_net_init(NET *net, Vio* vio) +my_bool my_net_init(NET *net, Vio* vio) { DBUG_ENTER("my_net_init"); my_net_local_init(net); /* Set some limits */ @@ -127,7 +127,7 @@ void net_end(NET *net) /* Realloc the packet buffer */ -static my_bool net_realloc(NET *net, ulong length) +my_bool net_realloc(NET *net, ulong length) { uchar *buff; ulong pkt_length; @@ -184,14 +184,14 @@ void net_clear(NET *net) /* Flush write_buffer if not empty. */ -int net_flush(NET *net) +my_bool net_flush(NET *net) { - int error=0; + my_bool error= 0; DBUG_ENTER("net_flush"); if (net->buff != net->write_pos) { - error=net_real_write(net,(char*) net->buff, - (ulong) (net->write_pos - net->buff)); + error=test(net_real_write(net,(char*) net->buff, + (ulong) (net->write_pos - net->buff))); net->write_pos=net->buff; } /* Sync packet number if using compression */ @@ -212,7 +212,7 @@ int net_flush(NET *net) ** NOTE: If compression is used the original package is modified! */ -int +my_bool my_net_write(NET *net,const char *packet,ulong len) { uchar buff[NET_HEADER_SIZE]; @@ -242,17 +242,38 @@ my_net_write(NET *net,const char *packet,ulong len) /* Send a command to the server. - As the command is part of the first data packet, we have to do some data - juggling to put the command in there, without having to create a new - packet. - This function will split big packets into sub-packets if needed. - (Each sub packet can only be 2^24 bytes) + + SYNOPSIS + net_write_command() + net NET handler + command Command in MySQL server (enum enum_server_command) + header Header to write after command + head_len Length of header + packet Query or parameter to query + len Length of packet + + DESCRIPTION + The reason for having both header and packet is so that libmysql + can easy add a header to a special command (like prepared statements) + without having to re-alloc the string. + + As the command is part of the first data packet, we have to do some data + juggling to put the command in there, without having to create a new + packet. + This function will split big packets into sub-packets if needed. + (Each sub packet can only be 2^24 bytes) + + RETURN VALUES + 0 ok + 1 error */ -int -net_write_command(NET *net,uchar command,const char *packet,ulong len) +my_bool +net_write_command(NET *net,uchar command, + const char *header, ulong head_len, + const char *packet, ulong len) { - ulong length=len+1; /* 1 extra byte for command */ + ulong length=len+1+head_len; /* 1 extra byte for command */ uchar buff[NET_HEADER_SIZE+1]; uint header_size=NET_HEADER_SIZE+1; buff[4]=command; /* For first packet */ @@ -260,25 +281,28 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len) if (length >= MAX_THREE_BYTES) { /* Take into account that we have the command in the first header */ - len= MAX_THREE_BYTES -1; + len= MAX_THREE_BYTES - 1 - head_len; do { int3store(buff, MAX_THREE_BYTES); buff[3]= (uchar) net->pkt_nr++; if (net_write_buff(net,(char*) buff, header_size) || - net_write_buff(net,packet,len)) + net_write_buff(net, header, head_len) || + net_write_buff(net, packet, len)) return 1; packet+= len; length-= MAX_THREE_BYTES; len=MAX_THREE_BYTES; + head_len=0; header_size=NET_HEADER_SIZE; } while (length >= MAX_THREE_BYTES); len=length; /* Data left to be written */ } int3store(buff,length); buff[3]= (uchar) net->pkt_nr++; - return test(net_write_buff(net,(char*) buff,header_size) || - net_write_buff(net,packet,len) || net_flush(net)); + return test(net_write_buff(net, (char*) buff, header_size) || + (head_len && net_write_buff(net, (char*) header, head_len)) || + net_write_buff(net, packet, len) || net_flush(net)); } /* @@ -286,7 +310,7 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len) One can force the buffer to be flushed with 'net_flush'. */ -static int +static my_bool net_write_buff(NET *net,const char *packet,ulong len) { ulong left_length=(ulong) (net->buff_end - net->write_pos); @@ -815,13 +839,3 @@ my_net_read(NET *net) #endif /* HAVE_COMPRESS */ return len; } - -bool net_request_file(NET* net, const char* fname) -{ - char tmp [FN_REFLEN+1],*end; - DBUG_ENTER("net_request_file"); - tmp[0] = (char) 251; /* NULL_LENGTH */ - end=strnmov(tmp+1,fname,sizeof(tmp)-2); - DBUG_RETURN(my_net_write(net,tmp,(uint) (end-tmp)) || - net_flush(net)); -} diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 04f1ffce00e..3d4a7893790 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -186,7 +186,7 @@ err: my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave", MYF(0)); err2: - send_error(&thd->net); + send_error(thd); return 1; } @@ -425,10 +425,10 @@ int show_new_master(THD* thd) if (translate_master(thd, lex_mi, errmsg)) { if (errmsg[0]) - net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND, + net_printf(thd, ER_ERROR_WHEN_EXECUTING_COMMAND, "SHOW NEW MASTER", errmsg); else - send_error(&thd->net, 0); + send_error(thd, 0); DBUG_RETURN(1); } @@ -444,7 +444,7 @@ int show_new_master(THD* thd) net_store_data(packet, (longlong)lex_mi->pos); if (my_net_write(&thd->net, packet->ptr(), packet->length())) DBUG_RETURN(-1); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } } @@ -459,7 +459,7 @@ int update_slave_list(MYSQL* mysql) int port_ind; DBUG_ENTER("update_slave_list"); - if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",0) || + if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",16) || !(res = mc_mysql_store_result(mysql))) { error = "Query error"; @@ -623,7 +623,7 @@ int show_slave_hosts(THD* thd) } } pthread_mutex_unlock(&LOCK_slave_list); - send_eof(net); + send_eof(thd); DBUG_RETURN(0); } @@ -709,7 +709,7 @@ int load_master_data(THD* thd) (error=terminate_slave_threads(active_mi,restart_thread_mask, 1 /*skip lock*/))) { - send_error(&thd->net,error); + send_error(thd,error); unlock_slave_threads(active_mi); UNLOCK_ACTIVE_MI; return 1; @@ -717,7 +717,7 @@ int load_master_data(THD* thd) if (connect_to_master(thd, &mysql, active_mi)) { - net_printf(&thd->net, error= ER_CONNECT_TO_MASTER, + net_printf(thd, error= ER_CONNECT_TO_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -727,10 +727,10 @@ int load_master_data(THD* thd) MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; uint num_dbs; - if (mc_mysql_query(&mysql, "show databases", 0) || + if (mc_mysql_query(&mysql, "SHOW DATABASES", 14) || !(db_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -744,7 +744,7 @@ int load_master_data(THD* thd) if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*)))) { - net_printf(&thd->net, error = ER_OUTOFMEMORY); + net_printf(thd, error = ER_OUTOFMEMORY); goto err; } @@ -754,11 +754,11 @@ int load_master_data(THD* thd) we wait to issue FLUSH TABLES WITH READ LOCK for as long as we can to minimize the lock time. */ - if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) || - mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) || + if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || + mc_mysql_query(&mysql, "SHOW MASTER STATUS",18) || !(master_status_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -798,16 +798,16 @@ int load_master_data(THD* thd) if (mysql_rm_db(thd, db, 1,1) || mysql_create_db(thd, db, 0, 1)) { - send_error(&thd->net, 0, 0); + send_error(thd, 0, 0); cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; } if (mc_mysql_select_db(&mysql, db) || - mc_mysql_query(&mysql, "show tables", 0) || + mc_mysql_query(&mysql, "SHOW TABLES", 11) || !(*cur_table_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; @@ -848,9 +848,9 @@ int load_master_data(THD* thd) mc_mysql_free_result(master_status_res); } - if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0)) + if (mc_mysql_query(&mysql, "UNLOCK TABLES", 13)) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -860,7 +860,7 @@ int load_master_data(THD* thd) 0 /* not only reset, but also reinit */, &errmsg)) { - send_error(&thd->net, 0, "Failed purging old relay logs"); + send_error(thd, 0, "Failed purging old relay logs"); unlock_slave_threads(active_mi); UNLOCK_ACTIVE_MI; return 1; @@ -888,7 +888,7 @@ err: mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init() if (!error) - send_ok(&thd->net); + send_ok(thd); return error; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 3c71d1d32e3..29c9ac09131 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -24,8 +24,9 @@ - Use one of the 'sys_var... classes from set_var.h or write a specific one for the variable type. - Define it in the 'variable definition list' in this file. - - If the variable should be changeable, it should be added to the - 'list of all variables' list in this file. + - If the variable should be changeable or one should be able to access it + with @@variable_name, it should be added to the 'list of all variables' + list in this file. - If the variable should be changed from the command line, add a definition of it in the my_option structure list in mysqld.dcc - If the variable should show up in 'show variables' add it to the @@ -82,6 +83,8 @@ static void fix_net_retry_count(THD *thd, enum_var_type type); static void fix_max_join_size(THD *thd, enum_var_type type); static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_key_buffer_size(THD *thd, enum_var_type type); +static byte *get_error_count(THD *thd); +static byte *get_warning_count(THD *thd); /* Variable definition list @@ -147,6 +150,8 @@ sys_var_long_ptr sys_max_connect_errors("max_connect_errors", &max_connect_errors); sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads", &max_insert_delayed_threads); +sys_var_thd_ulong sys_max_error_count("max_error_count", + &SV::max_error_count); sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", &SV::max_heap_table_size); sys_var_thd_ulong sys_max_join_size("max_join_size", @@ -157,6 +162,8 @@ sys_var_thd_ulong sys_sql_max_join_size("sql_max_join_size", &SV::max_join_size, fix_max_join_size); #endif +sys_var_thd_ulong sys_max_prep_stmt_count("max_prepared_statements", + &SV::max_prep_stmt_count); sys_var_thd_ulong sys_max_sort_length("max_sort_length", &SV::max_sort_length); sys_var_long_ptr sys_max_user_connections("max_user_connections", @@ -220,8 +227,6 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size", &SV::tmp_table_size); sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", &SV::net_wait_timeout); - - /* Variables that are bits in THD */ @@ -283,6 +288,15 @@ static sys_var_timestamp sys_timestamp("timestamp"); static sys_var_last_insert_id sys_last_insert_id("last_insert_id"); static sys_var_last_insert_id sys_identity("identity"); static sys_var_insert_id sys_insert_id("insert_id"); +static sys_var_readonly sys_error_count("error_count", + OPT_SESSION, + SHOW_LONG, + get_error_count); +static sys_var_readonly sys_warning_count("warning_count", + OPT_SESSION, + SHOW_LONG, + get_warning_count); + /* alias for last_insert_id() to be compatible with Sybase */ static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter"); @@ -311,6 +325,7 @@ sys_var *sys_variables[]= &sys_delayed_insert_limit, &sys_delayed_insert_timeout, &sys_delayed_queue_size, + &sys_error_count, &sys_flush, &sys_flush_time, &sys_foreign_key_checks, @@ -333,8 +348,10 @@ sys_var *sys_variables[]= &sys_max_connect_errors, &sys_max_connections, &sys_max_delayed_threads, + &sys_max_error_count, &sys_max_heap_table_size, &sys_max_join_size, + &sys_max_prep_stmt_count, &sys_max_sort_length, &sys_max_tmp_tables, &sys_max_user_connections, @@ -375,7 +392,8 @@ sys_var *sys_variables[]= &sys_timestamp, &sys_tmp_table_size, &sys_tx_isolation, - &sys_unique_checks + &sys_unique_checks, + &sys_warning_count }; @@ -465,9 +483,11 @@ struct show_var_st init_vars[]= { {sys_max_binlog_size.name, (char*) &sys_max_binlog_size, SHOW_SYS}, {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS}, {sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS}, + {sys_max_error_count.name, (char*) &sys_max_error_count, SHOW_SYS}, {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS}, {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS}, + {sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, @@ -793,7 +813,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type) bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { char buff[80], *value; - String str(buff,sizeof(buff)), *res; + String str(buff, sizeof(buff), system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) { @@ -831,6 +851,10 @@ err: We have to use netprintf() instead of my_error() here as this is called on the parsing stage. + + TODO: + With prepared statements/stored procedures this has to be fixed + to create an item that gets the current value at fix_fields() stage. */ Item *sys_var::item(THD *thd, enum_var_type var_type) @@ -839,7 +863,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) { if (var_type != OPT_DEFAULT) { - net_printf(&thd->net, + net_printf(thd, var_type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE, name); return 0; @@ -857,10 +881,10 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) case SHOW_CHAR: { char *str= (char*) value_ptr(thd, var_type); - return new Item_string(str,strlen(str)); + return new Item_string(str, strlen(str), system_charset_info); } default: - net_printf(&thd->net, ER_VAR_CANT_BE_READ, name); + net_printf(thd, ER_VAR_CANT_BE_READ, name); } return 0; } @@ -918,7 +942,7 @@ bool sys_var_thd_conv_charset::check(THD *thd, set_var *var) { CONVERT *tmp; char buff[80]; - String str(buff,sizeof(buff)), *res; + String str(buff,sizeof(buff), system_charset_info), *res; if (!var->value) // Default value { @@ -1100,6 +1124,21 @@ static bool set_log_update(THD *thd, set_var *var) return 0; } +static byte *get_warning_count(THD *thd) +{ + thd->sys_var_tmp.long_value= + (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] + + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]); + return (byte*) &thd->sys_var_tmp.long_value; +} + +static byte *get_error_count(THD *thd) +{ + thd->sys_var_tmp.long_value= + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR]; + return (byte*) &thd->sys_var_tmp.long_value; +} + /**************************************************************************** Main handling of variables: @@ -1161,7 +1200,8 @@ void set_var_init() { extern struct my_option my_long_options[]; // From mysqld - hash_init(&system_variable_hash,array_elements(sys_variables),0,0, + hash_init(&system_variable_hash, system_charset_info, + array_elements(sys_variables),0,0, (hash_get_key) get_sys_var_length,0, HASH_CASE_INSENSITIVE); sys_var **var, **end; for (var= sys_variables, end= sys_variables+array_elements(sys_variables) ; @@ -1212,7 +1252,7 @@ sys_var *find_sys_var(const char *str, uint length) length ? length : strlen(str)); if (!var) - net_printf(¤t_thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str); + net_printf(current_thd, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str); return var; } @@ -1286,7 +1326,7 @@ bool set_var::check(THD *thd) return 0; } - if (value->fix_fields(thd,0)) + if (value->fix_fields(thd, 0, &value)) return 1; if (var->check_update_type(value->result_type())) { @@ -1315,7 +1355,7 @@ bool set_var::update(THD *thd) bool set_var_user::check(THD *thd) { - return user_var_item->fix_fields(thd,0); + return user_var_item->fix_fields(thd,0, (Item**) 0); } @@ -1324,7 +1364,7 @@ bool set_var_user::update(THD *thd) if (user_var_item->update()) { /* Give an error if it's not given already */ - send_error(&thd->net, ER_SET_CONSTANTS_ONLY); + send_error(thd, ER_SET_CONSTANTS_ONLY); return 1; } return 0; diff --git a/sql/set_var.h b/sql/set_var.h index cbe479b7902..2c40414f591 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -39,6 +39,7 @@ typedef bool (*sys_check_func)(THD *, set_var *); typedef bool (*sys_update_func)(THD *, set_var *); typedef void (*sys_after_update_func)(THD *,enum_var_type); typedef void (*sys_set_default_func)(THD *, enum_var_type); +typedef byte *(*sys_value_ptr_func)(THD *thd); class sys_var { @@ -350,6 +351,31 @@ public: }; +/* Variable that you can only read from */ + +class sys_var_readonly: public sys_var +{ +public: + enum_var_type var_type; + SHOW_TYPE show_type; + sys_value_ptr_func value_ptr_func; + sys_var_readonly(const char *name_arg, enum_var_type type, + SHOW_TYPE show_type_arg, + sys_value_ptr_func value_ptr_func_arg) + :sys_var(name_arg), var_type(type), + show_type(show_type_arg), value_ptr_func(value_ptr_func_arg) + {} + bool update(THD *thd, set_var *var) { return 1; } + bool check_default(enum_var_type type) { return 1; } + bool check_type(enum_var_type type) { return type != var_type; } + bool check_update_type(Item_result type) { return 1; } + byte *value_ptr(THD *thd, enum_var_type type) + { + return (*value_ptr_func)(thd); + } + SHOW_TYPE type() { return show_type; } +}; + /**************************************************************************** Classes for parsing of the SET command ****************************************************************************/ @@ -388,7 +414,8 @@ public: if (value_arg && value_arg->type() == Item::FIELD_ITEM) { Item_field *item= (Item_field*) value_arg; - if (!(value=new Item_string(item->field_name, strlen(item->field_name)))) + if (!(value=new Item_string(item->field_name, strlen(item->field_name), + system_charset_info))) value=value_arg; /* Give error message later */ } else diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index e9f3b997a96..17651303714 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -206,7 +206,7 @@ "Nezn-Bámá systémová promìnná '%-.64s'", "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena", "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 88ab604fbcf..ccb452f0cca 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -242,3 +242,4 @@ "Key reference and table reference doesn't match", "Subselect return more than 1 field", "Subselect return more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index a344ed2df9e..f9117bdd44e 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 9e88f2c3e2c..9bf7121d309 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 07bdcd6bee5..215a30c5062 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 57f990fdc04..0560442ddb8 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 37f7f2fac01..bc9f9829945 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 93f4090d697..2af2e7809b0 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 3b43ce539c7..93578e6119d 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -201,7 +201,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index ce237d755d4..cde6ab9a4f4 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -201,7 +201,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 9912e4c9191..4c5cf834262 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -205,7 +205,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index f6553f247b6..587c9cab406 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -197,7 +197,7 @@ "Okänd system variabel '%-.64s'", "Tabell '%-.64s' är crashad och bör repareras med REPAIR TABLE", "Tabell '%-.64s' är crashad och senast (automatiska?) reparation misslyckades", -"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK", +"Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK", "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Utöka denna mysqld variabel och försök på nytt", "Denna operation kan inte göras under replikering; Gör SLAVE STOP först", "Denna operation kan endast göras under replikering; Konfigurera slaven och gör SLAVE START", diff --git a/sql/slave.cc b/sql/slave.cc index 01f6233a2e0..71dbb1fc1a2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -56,7 +56,6 @@ static int events_till_disconnect = -1; typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE; -void skip_load_data_infile(NET* net); static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev); static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev); static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli); @@ -723,13 +722,22 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) rli->last_slave_errno = err_code; } +/* + This is used to tell a 3.23 master to break send_file() +*/ + +void skip_load_data_infile(NET *net) +{ + (void)net_request_file(net, "/dev/null"); + (void)my_net_read(net); // discard response + (void)net_write_command(net, 0, "", 0, "", 0); // Send ok +} + -void skip_load_data_infile(NET* net) +bool net_request_file(NET* net, const char* fname) { - (void)my_net_write(net, "\xfb/dev/null", 10); - (void)net_flush(net); - (void)my_net_read(net); // discard response - send_ok(net); // the master expects it + DBUG_ENTER("net_request_file"); + DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0)); } @@ -875,13 +883,13 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, if (packet_len == packet_error) { - send_error(&thd->net, ER_MASTER_NET_READ); + send_error(thd, ER_MASTER_NET_READ); return 1; } if (net->read_pos[0] == 255) // error from master { net->read_pos[packet_len] = 0; - net_printf(&thd->net, ER_MASTER, net->read_pos + 3); + net_printf(thd, ER_MASTER, net->read_pos + 3); return 1; } thd->command = COM_TABLE_DUMP; @@ -889,7 +897,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, if (!thd->query) { sql_print_error("create_table_from_dump: out of memory"); - net_printf(&thd->net, ER_GET_ERRNO, "Out of memory"); + net_printf(thd, ER_GET_ERRNO, "Out of memory"); return 1; } memcpy(thd->query, net->read_pos, packet_len); @@ -919,7 +927,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Opening master dump table"; if (!open_ltable(thd, &tables, TL_WRITE)) { - send_error(&thd->net,0,0); // Send error from open_ltable + send_error(thd,0,0); // Send error from open_ltable sql_print_error("create_table_from_dump: could not open created table"); goto err; } @@ -928,7 +936,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Reading master dump table data"; if (file->net_read_dump(net)) { - net_printf(&thd->net, ER_MASTER_NET_READ); + net_printf(thd, ER_MASTER_NET_READ); sql_print_error("create_table_from_dump::failed in\ handler::net_read_dump()"); goto err; @@ -947,7 +955,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, error=file->repair(thd,&check_opt) != 0; thd->net.vio = save_vio; if (error) - net_printf(&thd->net, ER_INDEX_REBUILD,tables.table->real_name); + net_printf(thd, ER_INDEX_REBUILD,tables.table->real_name); err: close_thread_tables(thd); @@ -969,12 +977,12 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, { if (!(mysql = mc_mysql_init(NULL))) { - send_error(&thd->net); // EOM + send_error(thd); // EOM DBUG_RETURN(1); } if (connect_to_master(thd, mysql, mi)) { - net_printf(&thd->net, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); + net_printf(thd, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); mc_mysql_close(mysql); DBUG_RETURN(1); } @@ -998,7 +1006,7 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, if (!called_connected) mc_mysql_close(mysql); if (errmsg && thd->net.vio) - send_error(&thd->net, error, errmsg); + send_error(thd, error, errmsg); DBUG_RETURN(test(error)); // Return 1 on error } @@ -1440,7 +1448,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi) if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -2222,8 +2230,8 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) int error = 1; ulong num_bytes; bool cev_not_written; - THD* thd; - NET* net = &mi->mysql->net; + THD *thd = mi->io_thd; + NET *net = &mi->mysql->net; DBUG_ENTER("process_io_create_file"); if (unlikely(!cev->is_valid())) @@ -2237,7 +2245,6 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) DBUG_RETURN(0); } DBUG_ASSERT(cev->inited_from_old); - thd = mi->io_thd; thd->file_id = cev->file_id = mi->file_id++; thd->server_id = cev->server_id; cev_not_written = 1; @@ -2266,7 +2273,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) } if (unlikely(!num_bytes)) /* eof */ { - send_ok(net); /* 3.23 master wants it */ + net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */ Execute_load_log_event xev(thd); xev.log_pos = mi->master_log_pos; if (unlikely(mi->rli.relay_log.append(&xev))) diff --git a/sql/spatial.h b/sql/spatial.h index c6e30a44fbf..3f09e86e823 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -1,8 +1,22 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef _spatial_h #define _spatial_h -#include "gstream.h" - const uint POINT_DATA_SIZE = 8+8; const uint WKB_HEADER_SIZE = 1+4; @@ -30,7 +44,8 @@ struct MBR ymax=-DBL_MAX; } - MBR(const double &_xmin, const double &_ymin, const double &_xmax, const double &_ymax) + MBR(const double &_xmin, const double &_ymin, + const double &_xmax, const double &_ymax) { xmin=_xmin; ymin=_ymin; @@ -52,7 +67,8 @@ struct MBR double ymax; void add_xy(double x, double y) - { /* Not using "else" for proper one point MBR calculation */ + { + /* Not using "else" for proper one point MBR calculation */ if (x<xmin) { xmin=x; @@ -72,10 +88,11 @@ struct MBR } void add_xy(const char *px, const char *py) - { /* Not using "else" for proper one point MBR calculation */ + { double x, y; float8get(x, px); float8get(y, py); + /* Not using "else" for proper one point MBR calculation */ if (x<xmin) { xmin=x; @@ -116,12 +133,14 @@ struct MBR int equals(const MBR *mbr) { - return (mbr->xmin==xmin)&&(mbr->ymin==ymin)&&(mbr->xmax==xmax)&&(mbr->ymax==ymax); + return ((mbr->xmin == xmin) && (mbr->ymin == ymin) && + (mbr->xmax == xmax) && (mbr->ymax == ymax)); } int disjoint(const MBR *mbr) { - return (mbr->xmin>xmax)||(mbr->ymin>ymax)||(mbr->xmax<xmin)||(mbr->ymax<ymin); + return ((mbr->xmin > xmax) || (mbr->ymin > ymax) || + (mbr->xmax < xmin) || (mbr->ymax < ymin)); } int intersects(const MBR *mbr) @@ -131,24 +150,24 @@ struct MBR int touches(const MBR *mbr) { - return (((mbr->xmin==xmax) || (mbr->xmax==xmin)) && - ((mbr->ymin>=ymin) && (mbr->ymin<=ymax) || - (mbr->ymax>=ymin) && (mbr->ymax<=ymax))) || - (((mbr->ymin==ymax) || (mbr->ymax==ymin)) && - ((mbr->xmin>=xmin) && (mbr->xmin<=xmax) || - (mbr->xmax>=xmin)&&(mbr->xmax<=xmax))); + return ((((mbr->xmin == xmax) || (mbr->xmax == xmin)) && + ((mbr->ymin >= ymin) && (mbr->ymin <= ymax) || + (mbr->ymax >= ymin) && (mbr->ymax <= ymax))) || + (((mbr->ymin == ymax) || (mbr->ymax == ymin)) && + ((mbr->xmin >= xmin) && (mbr->xmin <= xmax) || + (mbr->xmax >= xmin) && (mbr->xmax <= xmax)))); } int within(const MBR *mbr) { - return (mbr->xmin<=xmin) && (mbr->ymin<=ymin) && - (mbr->xmax>=xmax) && (mbr->ymax>=ymax); + return ((mbr->xmin <= xmin) && (mbr->ymin <= ymin) && + (mbr->xmax >= xmax) && (mbr->ymax >= ymax)); } int contains(const MBR *mbr) { - return (mbr->xmin>=xmin) && (mbr->ymin>=ymin) && - (mbr->xmax<=xmax) && (mbr->ymax<=ymax); + return ((mbr->xmin >= xmin) && (mbr->ymin >= ymin) && + (mbr->xmax <= xmax) && (mbr->ymax <= ymax)); } bool inner_point(double x, double y) const @@ -245,45 +264,46 @@ public: size_t get_data_size() const { return (this->*m_vmt->get_data_size)(); } int init_from_text(GTextReadStream *trs, String *wkb) - { return (this->*m_vmt->init_from_text)(trs, wkb); } + { return (this->*m_vmt->init_from_text)(trs, wkb); } int get_data_as_text(String *txt) const - { return (this->*m_vmt->get_data_as_text)(txt); } + { return (this->*m_vmt->get_data_as_text)(txt); } int get_mbr(MBR *mbr) const { return (this->*m_vmt->get_mbr)(mbr); } int dimension(uint32 *dim) const - { return (this->*m_vmt->dimension)(dim); } + { return (this->*m_vmt->dimension)(dim); } int get_x(double *x) const { return (this->*m_vmt->get_x)(x); } int get_y(double *y) const { return (this->*m_vmt->get_y)(y); } int length(double *len) const { return (this->*m_vmt->length)(len); } int area(double *ar) const { return (this->*m_vmt->area)(ar); } - int is_closed(int *closed) const { return (this->*m_vmt->is_closed)(closed); } + int is_closed(int *closed) const + { return (this->*m_vmt->is_closed)(closed); } int num_interior_ring(uint32 *n_int_rings) const - { return (this->*m_vmt->num_interior_ring)(n_int_rings); } + { return (this->*m_vmt->num_interior_ring)(n_int_rings); } int num_points(uint32 *n_points) const - { return (this->*m_vmt->num_points)(n_points); } + { return (this->*m_vmt->num_points)(n_points); } int num_geometries(uint32 *num) const - { return (this->*m_vmt->num_geometries)(num); } + { return (this->*m_vmt->num_geometries)(num); } int start_point(String *point) const - { return (this->*m_vmt->start_point)(point); } + { return (this->*m_vmt->start_point)(point); } int end_point(String *point) const - { return (this->*m_vmt->end_point)(point); } + { return (this->*m_vmt->end_point)(point); } int exterior_ring(String *ring) const - { return (this->*m_vmt->exterior_ring)(ring); } + { return (this->*m_vmt->exterior_ring)(ring); } int centroid(String *point) const - { return (this->*m_vmt->centroid)(point); } + { return (this->*m_vmt->centroid)(point); } int point_n(uint32 num, String *result) const - { return (this->*m_vmt->point_n)(num, result); } + { return (this->*m_vmt->point_n)(num, result); } int interior_ring_n(uint32 num, String *result) const - { return (this->*m_vmt->interior_ring_n)(num, result); } + { return (this->*m_vmt->interior_ring_n)(num, result); } int geometry_n(uint32 num, String *result) const - { return (this->*m_vmt->geometry_n)(num, result); } + { return (this->*m_vmt->geometry_n)(num, result); } public: int create_from_wkb(const char *data, uint32 data_len); @@ -301,11 +321,11 @@ public: int as_wkt(String *wkt) const { - if(wkt->reserve(strlen(get_class_info()->m_name) + 2, 512)) + if (wkt->reserve(strlen(get_class_info()->m_name) + 2, 512)) return 1; wkt->qs_append(get_class_info()->m_name); wkt->qs_append('('); - if(get_data_as_text(wkt)) + if (get_data_as_text(wkt)) return 1; wkt->qs_append(')'); return 0; @@ -330,35 +350,37 @@ protected: bool no_data(const char *cur_data, uint32 data_amount) const { - return cur_data + data_amount > m_data_end; + return (cur_data + data_amount > m_data_end); } const char *m_data; const char *m_data_end; }; +#define SIZEOF_STORED_DOUBLE 8 + /***************************** Point *******************************/ class GPoint: public Geometry { public: - size_t get_data_size() const; - int init_from_text(GTextReadStream *trs, String *wkb); - int get_data_as_text(String *txt) const; - int get_mbr(MBR *mbr) const; + size_t get_data_size() const; + int init_from_text(GTextReadStream *trs, String *wkb); + int get_data_as_text(String *txt) const; + int get_mbr(MBR *mbr) const; int get_xy(double *x, double *y) const { const char *data = m_data; - if(no_data(data, sizeof(double)) * 2) return 1; + if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; float8get(*x, data); - float8get(*y, data + sizeof(double)); + float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } int get_x(double *x) const { - if(no_data(m_data, sizeof(double))) return 1; + if (no_data(m_data, SIZEOF_STORED_DOUBLE)) return 1; float8get(*x, m_data); return 0; } @@ -366,8 +388,8 @@ public: int get_y(double *y) const { const char *data = m_data; - if(no_data(data, sizeof(double)) * 2) return 1; - float8get(*y, data + sizeof(double)); + if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; + float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } @@ -399,11 +421,11 @@ public: class GPolygon: public Geometry { public: - size_t get_data_size() const; - int init_from_text(GTextReadStream *trs, String *wkb); - int get_data_as_text(String *txt) const; - int get_mbr(MBR *mbr) const; - + size_t get_data_size() const; + int init_from_text(GTextReadStream *trs, String *wkb); + int get_data_as_text(String *txt) const; + int get_mbr(MBR *mbr) const; + int area(double *ar) const; int exterior_ring(String *result) const; int num_interior_ring(uint32 *n_int_rings) const; @@ -431,11 +453,11 @@ public: class GMultiLineString: public Geometry { public: - size_t get_data_size() const; - int init_from_text(GTextReadStream *trs, String *wkb); - int get_data_as_text(String *txt) const; - int get_mbr(MBR *mbr) const; - + size_t get_data_size() const; + int init_from_text(GTextReadStream *trs, String *wkb); + int get_data_as_text(String *txt) const; + int get_mbr(MBR *mbr) const; + int length(double *len) const; int is_closed(int *closed) const; int dimension(uint32 *dim) const { *dim = 1; return 0; } @@ -446,10 +468,10 @@ public: class GMultiPolygon: public Geometry { public: - size_t get_data_size() const; - int init_from_text(GTextReadStream *trs, String *wkb); - int get_data_as_text(String *txt) const; - int get_mbr(MBR *mbr) const; + size_t get_data_size() const; + int init_from_text(GTextReadStream *trs, String *wkb); + int get_data_as_text(String *txt) const; + int get_mbr(MBR *mbr) const; int area(double *ar) const; int centroid(String *result) const; @@ -462,14 +484,13 @@ public: class GGeometryCollection: public Geometry { public: - size_t get_data_size() const; - int init_from_text(GTextReadStream *trs, String *wkb); - int get_data_as_text(String *txt) const; - int get_mbr(MBR *mbr) const; + size_t get_data_size() const; + int init_from_text(GTextReadStream *trs, String *wkb); + int get_data_as_text(String *txt) const; + int get_mbr(MBR *mbr) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; - int dimension(uint32 *dim) const; }; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1069e779e86..e6b9a1f532b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -997,7 +997,7 @@ bool check_change_password(THD *thd, const char *host, const char *user) { if (!initialized) { - send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */ + send_error(thd, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */ return(1); /* purecov: inspected */ } if (!thd->slave_thread && @@ -1009,7 +1009,7 @@ bool check_change_password(THD *thd, const char *host, const char *user) } if (!thd->slave_thread && !thd->user[0]) { - send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER); + send_error(thd, ER_PASSWORD_ANONYMOUS_USER); return(1); } return(0); @@ -1036,7 +1036,7 @@ bool change_password(THD *thd, const char *host, const char *user, ACL_USER *acl_user; if (!(acl_user= find_acl_user(host,user))) { - send_error(&thd->net, ER_PASSWORD_NO_MATCH); + send_error(thd, ER_PASSWORD_NO_MATCH); VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(1); } @@ -1046,7 +1046,7 @@ bool change_password(THD *thd, const char *host, const char *user, new_password)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ - send_error(&thd->net,0); /* purecov: deadcode */ + send_error(thd,0); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */ } get_salt_from_password(acl_user->salt,new_password); @@ -1960,7 +1960,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: inspected */ + send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: inspected */ return 1; /* purecov: inspected */ } if (rights & ~TABLE_ACLS) @@ -2026,7 +2026,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); int result=0; - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&memex); @@ -2135,9 +2135,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, } grant_option=TRUE; my_pthread_setspecific_ptr(THR_MALLOC,old_root); - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!result) - send_ok(&thd->net); + send_ok(thd); /* Tables are automatically closed */ DBUG_RETURN(result); } @@ -2155,8 +2155,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: tested */ - return 1; /* purecov: tested */ + send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: tested */ + return 1; /* purecov: tested */ } if (lower_case_table_names && db) @@ -2185,7 +2185,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, create_new_users= test_if_create_new_users(thd); // go through users in user_list - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); grant_version++; @@ -2218,11 +2218,11 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, } } VOID(pthread_mutex_unlock(&acl_cache->lock)); - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (!result) - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(result); } @@ -2341,7 +2341,7 @@ void grant_reload(void) // Locked tables are checked by acl_init and doesn't have to be checked here - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); grant_version++; old_hash_tables=hash_tables; old_grant_option = grant_option; @@ -2359,7 +2359,7 @@ void grant_reload(void) hash_free(&old_hash_tables); free_root(&old_mem,MYF(0)); } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); DBUG_VOID_RETURN; } @@ -2379,7 +2379,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, if (!want_access) return 0; // ok - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); for (table=tables; table ;table=table->next) { if (!(~table->grant.privilege & want_access)) @@ -2413,11 +2413,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, goto err; // impossible } } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { const char *command=""; @@ -2439,7 +2439,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, command = "index"; else if (want_access & GRANT_ACL) command = "grant"; - net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR, + net_printf(thd,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, thd->host_or_ip, @@ -2459,7 +2459,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, if (!want_access) return 0; // Already checked - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants @@ -2477,20 +2477,20 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, grant_column=column_hash_search(grant_table, name, length); if (grant_column && !(~grant_column->rights & want_access)) { - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; } #ifdef NOT_USED if (show_tables && (grant_column || table->grant.privilege & COL_ACLS)) { - pthread_mutex_unlock(&LOCK_grant); /* purecov: deadcode */ + rw_unlock(&LOCK_grant); /* purecov: deadcode */ return 0; /* purecov: deadcode */ } #endif /* We must use my_printf_error() here! */ err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!show_tables) { char command[128]; @@ -2518,7 +2518,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) if (!want_access) return 0; // Already checked - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants @@ -2541,12 +2541,12 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) if (!grant_column || (~grant_column->rights & want_access)) goto err; } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; /* We must use my_printf_error() here! */ err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); const char *command=""; if (want_access & SELECT_ACL) @@ -2578,7 +2578,7 @@ bool check_grant_db(THD *thd,const char *db) bool error=1; len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); for (uint idx=0 ; idx < hash_tables.records ; idx++) { @@ -2594,7 +2594,7 @@ bool check_grant_db(THD *thd,const char *db) break; } } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return error; } @@ -2608,14 +2608,14 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); grant_table = table_hash_search(thd->host,thd->ip,db,user, table->real_name,0); table->grant.grant_table=grant_table; // Remember for column test table->grant.version=grant_version; if (grant_table) table->grant.privilege|= grant_table->privs; - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return table->grant.privilege; } @@ -2626,7 +2626,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) GRANT_COLUMN *grant_column; ulong priv; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants if (table->grant.version != grant_version) { @@ -2648,7 +2648,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) else priv=table->grant.privilege | grant_column->rights; } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return priv; } @@ -2683,7 +2683,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) LINT_INIT(acl_user); if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); DBUG_RETURN(-1); } if (!lex_user->host.str) @@ -2990,7 +2990,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } end: VOID(pthread_mutex_unlock(&acl_cache->lock)); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(error); } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 91d6b967929..363a194276b 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -89,21 +89,21 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } pc->max_tree_elements = (uint) (*param->item)->val_int(); param = param->next; if (param->next) // no third parameter possible { - net_printf(&thd->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } // second parameter if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } pc->max_treemem = (uint) (*param->item)->val_int(); @@ -111,7 +111,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } // if only one parameter was given, it will be the value of max_tree_elements @@ -387,8 +387,7 @@ void field_real::add() if ((decs = decimals()) == NOT_FIXED_DEC) { - sprintf(buff, "%g", num); - length = (uint) strlen(buff); + length= my_sprintf(buff, (buff, "%g", num)); if (rint(num) != num) max_notzero_dec_len = 1; } @@ -397,11 +396,11 @@ void field_real::add() #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num); + length = (uint) strlen(buff); #else - sprintf(buff, "%-.*f", (int) decs, num); + length= my_sprintf(buff, (buff, "%-.*f", (int) decs, num)); #endif - length = (uint) strlen(buff); // We never need to check further than this end = buff + length - 1 - decs + max_notzero_dec_len; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a8115c15412..3175193e8ce 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -224,7 +224,7 @@ send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag) char buff[80]; String tmp((char*) buff,sizeof(buff),default_charset_info); String *res,*packet= &thd->packet; - DBUG_ENTER("send_fields"); + DBUG_ENTER("send_convert_fields"); while ((item=it++)) { @@ -286,10 +286,10 @@ send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag) if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) break; /* purecov: inspected */ } - return 0; + DBUG_RETURN(0); err: - return 1; + DBUG_RETURN(1); } @@ -406,7 +406,8 @@ send_non_convert_fields(THD *thd,List<Item> &list,uint flag) bool send_fields(THD *thd, List<Item> &list, uint flag) { - CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set; + char buff[9]; // Big enough for store_length + CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set; DBUG_ENTER("send_fields"); if (thd->fatal_error) // We have got an error @@ -414,7 +415,7 @@ send_fields(THD *thd, List<Item> &list, uint flag) if (flag & 1) { // Packet with number of elements - char *pos=net_store_length(buff,(uint) list.elements); + char *pos=net_store_length(buff, (uint) list.elements); (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); } @@ -430,11 +431,11 @@ send_fields(THD *thd, List<Item> &list, uint flag) else if (send_non_convert_fields(thd, list, flag)) goto err; - send_eof(&thd->net); - return 0; + send_eof(thd); + DBUG_RETURN(0); err: - send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */ + send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 41def4aa1b5..277492bcea6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -77,14 +77,15 @@ static void free_var(user_var_entry *entry) ** Thread specific functions ****************************************************************************/ -THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), +THD::THD():user_time(0), fatal_error(0), + last_insert_id_used(0), insert_id_used(0), in_lock_tables(0), global_read_lock(0), bootstrap(0) { host=user=priv_user=db=query=ip=0; host_or_ip="unknown ip"; locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password= - query_start_used=safe_to_cache_query=0; + query_start_used=safe_to_cache_query=prepare_command=0; pthread_mutex_lock(&LOCK_global_system_variables); variables= global_system_variables; pthread_mutex_unlock(&LOCK_global_system_variables); @@ -96,7 +97,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), tmp_table=0; lock=locked_tables=0; used_tables=0; - cuted_fields=sent_row_count=0L; + cuted_fields= sent_row_count= current_stmt_id= 0L; start_time=(time_t) 0; current_linfo = 0; slave_thread = 0; @@ -142,10 +143,21 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), bzero((char*) &mem_root,sizeof(mem_root)); bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root)); bzero((char*) &con_root,sizeof(con_root)); + bzero((char*) &warn_root,sizeof(warn_root)); + init_alloc_root(&warn_root, 1024, 0); + bzero((char*) warn_count, sizeof(warn_count)); + warn_list.empty(); user_connect=(USER_CONN *)0; hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, (void (*)(void*)) free_var,0); + + /* Prepared statements */ + last_prepared_stmt= 0; + init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT), + (qsort_cmp2) compare_prep_stmt, 1, + (tree_element_free) free_prep_stmt, 0); + #ifdef USING_TRANSACTIONS bzero((char*) &transaction,sizeof(transaction)); if (opt_using_transactions) @@ -222,7 +234,9 @@ THD::~THD() safeFree(ip); free_root(&mem_root,MYF(0)); free_root(&con_root,MYF(0)); + free_root(&warn_root,MYF(0)); free_root(&transaction.mem_root,MYF(0)); + delete_tree(&prepared_statements); mysys_var=0; // Safety (shouldn't be needed) pthread_mutex_destroy(&LOCK_delete); #ifndef DBUG_OFF @@ -272,8 +286,7 @@ void THD::awake(bool prepare_to_die) bool THD::store_globals() { return (my_pthread_setspecific_ptr(THR_THD, this) || - my_pthread_setspecific_ptr(THR_MALLOC, &mem_root) || - my_pthread_setspecific_ptr(THR_NET, &net)); + my_pthread_setspecific_ptr(THR_MALLOC, &mem_root)); } @@ -424,7 +437,7 @@ bool select_send::send_eof() { mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - ::send_eof(&thd->net); + ::send_eof(thd); return 0; } @@ -649,7 +662,7 @@ err: void select_export::send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); file= -1; @@ -662,9 +675,9 @@ bool select_export::send_eof() if (my_close(file,MYF(MY_WME))) error=1; if (error) - ::send_error(&thd->net); + ::send_error(thd); else - ::send_ok(&thd->net,row_count); + ::send_ok(thd,row_count); file= -1; return error; } @@ -761,7 +774,7 @@ err: void select_dump::send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); (void) my_delete(path,MYF(0)); // Delete file on error @@ -774,9 +787,9 @@ bool select_dump::send_eof() if (my_close(file,MYF(MY_WME))) error=1; if (error) - ::send_error(&thd->net); + ::send_error(thd); else - ::send_ok(&thd->net,row_count); + ::send_ok(thd,row_count); file= -1; return error; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 8b2e9400613..f1eb4febf0f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -292,31 +292,43 @@ public: i_string_pair():key(0),val(0) { } i_string_pair(char* key_arg, char* val_arg) : key(key_arg),val(val_arg) {} }; -#define MYSQL_DEFAULT_ERROR_COUNT 500 -class mysql_st_error + +class MYSQL_ERROR: public Sql_alloc { public: + enum enum_warning_level + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + uint code; - char msg[MYSQL_ERRMSG_SIZE+1]; - char query[NAME_LEN+1]; + enum_warning_level level; + char *msg; - static void *operator new(size_t size) - { - return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE)); - } - static void operator delete(void* ptr_arg, size_t size) - { - my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); - } - mysql_st_error(uint ecode, const char *emsg, const char *equery) + MYSQL_ERROR(uint code_arg, enum_warning_level level_arg, + const char *msg_arg) + :code(code_arg), level(level_arg) { - code = ecode; - strmov(msg, emsg); - strnmov(query, equery ? equery : "", NAME_LEN); + msg=sql_strdup(msg_arg); } }; + +/* This is a struct as it's allocated in tree_insert */ + +typedef struct st_prep_stmt +{ + THD *thd; + Item_param *param; + Item *free_list; + MEM_ROOT mem_root; + ulong stmt_id; + uint param_count; + uint last_errno; + char last_error[MYSQL_ERRMSG_SIZE]; + bool error_in_prepare, long_data_used; +} PREP_STMT; + + class delayed_insert; #define THD_SENTRY_MAGIC 0xfeedd1ff @@ -332,27 +344,27 @@ struct system_variables ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; + ulong max_error_count; ulong max_heap_table_size; - ulong max_sort_length; ulong max_join_size; + ulong max_prep_stmt_count; + ulong max_sort_length; ulong max_tmp_tables; - ulong max_error_count; - ulong max_warning_count; ulong myisam_sort_buff_size; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; + ulong net_retry_count; ulong net_wait_timeout; ulong net_write_timeout; - ulong net_retry_count; ulong query_cache_type; ulong read_buff_size; ulong read_rnd_buff_size; ulong select_limit; ulong sortbuff_size; + ulong table_type; ulong tmp_table_size; ulong tx_isolation; - ulong table_type; my_bool log_warnings; my_bool low_priority_updates; @@ -372,7 +384,9 @@ public: LEX lex; // parse tree descriptor MEM_ROOT mem_root; // 1 command-life memory pool MEM_ROOT con_root; // connection-life memory + MEM_ROOT warn_root; // For warnings and errors HASH user_vars; // hash for user variables + TREE prepared_statements; String packet; // dynamic buffer for network I/O struct sockaddr_in remote; // client socket address struct rand_struct rand; // used for authentication @@ -408,7 +422,6 @@ public: ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ - /* open_tables - list of regular tables in use by this thread temporary_tables - list of temp tables in use by this thread @@ -417,9 +430,10 @@ public: */ TABLE *open_tables,*temporary_tables, *handler_tables; // TODO: document the variables below - MYSQL_LOCK *lock; /* Current locks */ - MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */ - ULL *ull; + MYSQL_LOCK *lock; /* Current locks */ + MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */ + ULL *ull; + PREP_STMT *last_prepared_stmt; #ifndef DBUG_OFF uint dbug_sentry; // watch out for memory corruption #endif @@ -466,8 +480,11 @@ public: table_map used_tables; USER_CONN *user_connect; CHARSET_INFO *db_charset; + List <MYSQL_ERROR> warn_list; + uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; + uint total_warn_count, old_total_warn_count; ulong query_id, version, options, thread_id, col_access; - ulong param_count,current_param_number; + ulong current_stmt_id; long dbug_thread_id; pthread_t real_id; uint current_tablenr,tmp_table,cond_count; @@ -480,16 +497,15 @@ public: uint8 query_cache_type; // type of query cache processing bool slave_thread; bool set_query_id,locked,count_cuted_fields,some_tables_deleted; - bool no_errors, allow_sum_func, password, fatal_error; + bool no_errors, allow_sum_func, password; + bool fatal_error; bool query_start_used,last_insert_id_used,insert_id_used; bool system_thread,in_lock_tables,global_read_lock; bool query_error, bootstrap, cleanup_done; bool safe_to_cache_query; bool volatile killed; bool prepare_command; - Error<mysql_st_error> err_list; - Error<mysql_st_error> warn_list; - Item_param *current_param; + Item_param *params; // Pointer to array of params /* If we do a purge of binary logs, log index info of the threads @@ -638,7 +654,7 @@ public: class JOIN; -void send_error(NET *net,uint sql_errno=0, const char *err=0); +void send_error(THD *thd, uint sql_errno=0, const char *err=0); class select_result :public Sql_alloc { protected: @@ -657,7 +673,7 @@ public: virtual void initialize_tables (JOIN *join=0) {} virtual void send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); } virtual bool send_eof()=0; virtual void abort() {} diff --git a/sql/sql_db.cc b/sql/sql_db.cc index dee26aae4be..708a016f727 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -25,112 +25,138 @@ #include <direct.h> #endif -#define MY_DB_OPT_FILE ".db.opt" +#define MY_DB_OPT_FILE "db.opt" + +const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; +static TYPELIB deletable_extentions= +{array_elements(del_exts)-1,"del_exts", del_exts}; + +const char *known_exts[]= +{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS}; +static TYPELIB known_extentions= +{array_elements(known_exts)-1,"known_exts", known_exts}; static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, const char *path, uint level); /* - Create database options file: - Currently databse default charset is only stored there. + Create database options file: + + DESCRIPTION + Currently database default charset is only stored there. + + RETURN VALUES + 0 ok + 1 Could not create file or write to it. Error sent through my_error() */ -static int write_db_opt(THD *thd,const char *db,HA_CREATE_INFO *create,char *fn) +static bool write_db_opt(const char *path, HA_CREATE_INFO *create) { register File file; - char buf[256]; // Should be enough - int error=0; + char buf[256]; // Should be enough for one option + bool error=1; - if ((file=my_create(fn,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) + if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) { - sprintf(buf,"default-character-set=%s\n", - (create && create->table_charset) ? - create->table_charset->name : "DEFAULT"); - - if (my_write(file,(byte*)buf,strlen(buf),MYF(MY_NABP+MY_WME))) - { - // QQ : should we send more suitable error message? - my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno); - error = -1; - goto exit; - } + ulong length; + length= my_sprintf(buf,(buf, "default-character-set=%s\n", + (create && create->table_charset) ? + create->table_charset->name : "DEFAULT")); + + /* Error is written by my_write */ + if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME))) + error=0; my_close(file,MYF(0)); } - else - { - // QQ : should we send more suitable error message? - my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno); - error = -1; - goto exit; - } exit: return error; } - /* - Load database options file: - */ -static int load_db_opt(THD *thd,const char *db,HA_CREATE_INFO *create,char *fn) -{ - register File file; - char buf[256]=""; +/* + Load database options file - if ((file=my_open(fn,O_RDWR|O_BINARY,MYF(MY_WME))) >= 0) - { - int nbytes=my_read(file,(byte*)buf,sizeof(buf)-1,MYF(0)); - if ( nbytes >= 0 ) - { - char *ln=buf; - char *pe=buf+nbytes; + load_db_opt() + path Path for option file + create Where to store the read options + + DESCRIPTION + For now, only default-character-set is read. - buf[nbytes]='\0'; + RETURN VALUES + 0 File found + 1 No database file or could not open it - for ( ln=buf; ln<pe; ) +*/ + +static bool load_db_opt(const char *path, HA_CREATE_INFO *create) +{ + File file; + char buf[256]; + DBUG_ENTER("load_db_opt"); + bool error=1; + uint nbytes; + + bzero((char*) create,sizeof(*create)); + if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) + { + IO_CACHE cache; + init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)); + + while ((int) (nbytes= my_b_gets(&cache, (byte*) buf, sizeof(buf))) > 0) + { + char *pos= buf+nbytes-1; + /* Remove end space and control characters */ + while (pos > buf && !my_isgraph(system_charset_info, pos[-1])) + pos--; + *pos=0; + if ((pos= strchr(buf, '='))) { - char *le,*val; - for ( le=ln, val=0 ; le<pe ; le++ ) + if (!strncmp(buf,"default-character-set", (pos-buf))) { - switch(le[0]) + if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0)))) { - case '=': - le[0]='\0'; - val=le+1; - le++; - break; - case '\r': - case '\n': - le[0]='\0'; - le++; - for( ; (le[0]=='\r' || le[0]=='\n') ; le++); - if (!strcmp(ln,"default-character-set") && val && val[0]) - { - create->table_charset=get_charset_by_name(val, MYF(0)); - } - goto cnt; - break; + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET), + pos+1); } } -cnt: - ln=le; } } + error=0; + end_io_cache(&cache); my_close(file,MYF(0)); } - return 0; + DBUG_RETURN(error); } -/* db-name is already validated when we come here */ -int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) +/* + Create a database + + SYNOPSIS + mysql_create_db() + thd Thread handler + db Name of database to create + Function assumes that this is already validated. + create_info Database create options (like character set) + silent Used by replication when internally creating a database. + In this case the entry should not be logged. + + RETURN VALUES + 0 ok + -1 Error + +*/ + +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, + bool silent) { char path[FN_REFLEN+16]; MY_DIR *dirp; long result=1; int error = 0; uint create_options = create_info ? create_info->options : 0; - DBUG_ENTER("mysql_create_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -167,34 +193,49 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent } } - strcat(path,"/"); - unpack_dirname(path,path); + unpack_dirname(path, path); strcat(path,MY_DB_OPT_FILE); - if ((error=write_db_opt(thd,db,create_info,path))) - goto exit; + if (write_db_opt(path, create_info)) + { + /* + Could not create options file. + Restore things to beginning. + */ + if (rmdir(path) >= 0) + { + error= -1; + goto exit; + } + /* + We come here when we managed to create the database, but not the option + file. In this case it's best to just continue as if nothing has + happened. (This is a very unlikely senario) + */ + } if (!silent) { - if (!thd->query) + char *query; + uint query_length; + + if (!thd->query) // Only in replication { - thd->query = path; - thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)- - path); + query= path; + query_length= (uint) (strxmov(path,"create database ", db, NullS) - + path); } + else { - mysql_update_log.write(thd,thd->query, thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query); - mysql_bin_log.write(&qinfo); - } + query= thd->query; + query_length= thd->query_length; } - if (thd->query == path) + mysql_update_log.write(thd, query, query_length); + if (mysql_bin_log.is_open()) { - thd->query = 0; // just in case - thd->query_length = 0; + Query_log_event qinfo(thd, query, query_length); + mysql_bin_log.write(&qinfo); } - send_ok(&thd->net, result); + send_ok(thd, result); } exit: @@ -207,15 +248,15 @@ exit2: /* db-name is already validated when we come here */ -int mysql_alter_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) +int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { - char path[FN_REFLEN+16]; + char path[FN_REFLEN+16]; MY_DIR *dirp; long result=1; int error = 0; - DBUG_ENTER("mysql_create_db"); register File file; uint create_options = create_info ? create_info->options : 0; + DBUG_ENTER("mysql_alter_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -227,45 +268,27 @@ int mysql_alter_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) } /* Check directory */ - (void)sprintf(path,"%s/%s", mysql_data_home, db); - strcat(path,"/"); - unpack_dirname(path,path); // Convert if not unix - strcat(path,MY_DB_OPT_FILE); - if ((error=write_db_opt(thd,db,create_info,path))) + (void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE); + fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME)); + if ((error=write_db_opt(path, create_info))) goto exit; /* - Change options if current - database is being altered + Change options if current database is being altered + TODO: Delete this code */ if (thd->db && !strcmp(thd->db,db)) { thd->db_charset= create_info ? create_info->table_charset : NULL; } - if (!silent) + mysql_update_log.write(thd,thd->query, thd->query_length); + if (mysql_bin_log.is_open()) { - if (!thd->query) - { - thd->query = path; - thd->query_length = (uint) (strxmov(path,"alter database ", db, NullS)- - path); - } - { - mysql_update_log.write(thd,thd->query, thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query, thd->query_length); - mysql_bin_log.write(&qinfo); - } - } - if (thd->query == path) - { - thd->query = 0; // just in case - thd->query_length = 0; - } - send_ok(&thd->net, result); + Query_log_event qinfo(thd, thd->query, thd->query_length); + mysql_bin_log.write(&qinfo); } + send_ok(thd, result); exit: start_waiting_global_read_lock(thd); @@ -275,18 +298,6 @@ exit2: } - - - -const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; -static TYPELIB deletable_extentions= -{array_elements(del_exts)-1,"del_exts", del_exts}; - -const char *known_exts[]= -{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS}; -static TYPELIB known_extentions= -{array_elements(known_exts)-1,"known_exts", known_exts}; - /* Drop all tables in a database. @@ -324,7 +335,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) my_error(ER_DB_DROP_EXISTS,MYF(0),db); } else if (!silent) - send_ok(&thd->net,0); + send_ok(thd,0); goto exit; } pthread_mutex_lock(&LOCK_open); @@ -355,7 +366,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) thd->query = 0; // just in case thd->query_length = 0; } - send_ok(&thd->net,(ulong) deleted); + send_ok(thd,(ulong) deleted); } error = 0; } @@ -503,30 +514,47 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } -bool mysql_change_db(THD *thd,const char *name) +/* + Change default database. + + SYNOPSIS + mysql_change_db() + thd Thread handler + name Databasename + + DESCRIPTION + Becasue the database name may have been given directly from the + communication packet (in case of 'connect' or 'COM_INIT_DB') + we have to do end space removal in this function. + + RETURN VALUES + 0 ok + 1 error +*/ + +bool mysql_change_db(THD *thd, const char *name) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); char path[FN_REFLEN]; uint db_access; HA_CREATE_INFO create; - DBUG_ENTER("mysql_change_db"); if (!dbname || !(db_length=strip_sp(dbname))) { x_free(dbname); /* purecov: inspected */ - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } if ((db_length > NAME_LEN) || check_db_name(dbname)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, dbname); + net_printf(thd,ER_WRONG_DB_NAME, dbname); x_free(dbname); DBUG_RETURN(1); } if (lower_case_table_names) - casedn_str(dbname); + my_casedn_str(system_charset_info, dbname); DBUG_PRINT("info",("Use database: %s", dbname)); if (test_all_bits(thd->master_access,DB_ACLS)) db_access=DB_ACLS; @@ -536,7 +564,7 @@ bool mysql_change_db(THD *thd,const char *name) thd->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, dbname); @@ -554,49 +582,37 @@ bool mysql_change_db(THD *thd,const char *name) path[length-1]=0; // remove ending '\' if (access(path,F_OK)) { - net_printf(&thd->net,ER_BAD_DB_ERROR,dbname); + net_printf(thd,ER_BAD_DB_ERROR,dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); } - send_ok(&thd->net); + send_ok(thd); x_free(thd->db); - thd->db=dbname; + thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; thd->db_access=db_access; - strcat(path,"/"); - unpack_dirname(path,path); - strcat(path,MY_DB_OPT_FILE); - bzero(&create,sizeof(create)); - load_db_opt(thd,name,&create,path); + strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); + load_db_opt(path, &create); thd->db_charset=create.table_charset; DBUG_RETURN(0); } -int mysqld_show_create_db(THD *thd,const char *name) +int mysqld_show_create_db(THD *thd, const char *dbname) { int length, db_length; - char *dbname=my_strdup((char*) name,MYF(MY_WME)); - char path[FN_REFLEN]; + char path[FN_REFLEN], *to; uint db_access; + bool found_libchar; HA_CREATE_INFO create; - CONVERT *convert=thd->convert_set; - + CONVERT *convert=thd->variables.convert_set; DBUG_ENTER("mysql_show_create_db"); - if (!dbname || !(db_length=strip_sp(dbname))) + if (check_db_name(dbname)) { - x_free(dbname); /* purecov: inspected */ - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ - DBUG_RETURN(1); /* purecov: inspected */ - } - - if ((db_length > NAME_LEN) || check_db_name(dbname)) - { - net_printf(&thd->net,ER_WRONG_DB_NAME, dbname); - x_free(dbname); + net_printf(thd,ER_WRONG_DB_NAME, dbname); DBUG_RETURN(1); } @@ -608,7 +624,7 @@ int mysqld_show_create_db(THD *thd,const char *name) thd->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, dbname); @@ -616,26 +632,26 @@ int mysqld_show_create_db(THD *thd,const char *name) thd->priv_user, thd->host_or_ip, dbname); - my_free(dbname,MYF(0)); DBUG_RETURN(1); } - (void) sprintf(path,"%s/%s",mysql_data_home,dbname); + (void) sprintf(path,"%s/%s",mysql_data_home, dbname); length=unpack_dirname(path,path); // Convert if not unix + found_libchar= 0; if (length && path[length-1] == FN_LIBCHAR) + { + found_libchar= 1; path[length-1]=0; // remove ending '\' + } if (access(path,F_OK)) { - net_printf(&thd->net,ER_BAD_DB_ERROR,dbname); - my_free(dbname,MYF(0)); + net_printf(thd,ER_BAD_DB_ERROR,dbname); DBUG_RETURN(1); } - - strcat(path,"/"); - unpack_dirname(path,path); - strcat(path,MY_DB_OPT_FILE); - bzero(&create,sizeof(create)); - load_db_opt(thd,name,&create,path); + if (found_libchar) + path[length-1]= FN_LIBCHAR; + strmov(path+length, MY_DB_OPT_FILE); + load_db_opt(path, &create); List<Item> field_list; field_list.push_back(new Item_empty_string("Database",NAME_LEN)); @@ -646,19 +662,16 @@ int mysqld_show_create_db(THD *thd,const char *name) String *packet = &thd->packet; packet->length(0); - net_store_data(packet, convert, name); - sprintf(path, "CREATE DATABASE %s", name); + net_store_data(packet, convert, dbname); + to= strxmov(path, "CREATE DATABASE `", dbname, "`", NullS); if (create.table_charset) - { - strcat(path," DEFAULT CHARACTER SET "); - strcat(path,create.table_charset->name); - } - net_store_data(packet, convert, path); - - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + to= strxmov(to," DEFAULT CHARACTER SET ", create.table_charset->name, + NullS); + net_store_data(packet, convert, path, (uint) (to-path)); + + if (my_net_write(&thd->net,(char*) packet->ptr(), packet->length())) DBUG_RETURN(1); - send_eof(&thd->net); - + send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index fc98cfb90c5..0581e0b5a3b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -43,7 +43,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, table_list->db=thd->db; if ((thd->options & OPTION_SAFE_UPDATES) && !conds) { - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } @@ -83,7 +83,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, !limit) { delete select; - send_ok(&thd->net,0L); + send_ok(thd,0L); DBUG_RETURN(0); // Nothing to delete } @@ -94,7 +94,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR) { delete select; - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } } @@ -188,10 +188,10 @@ cleanup: } delete select; if (error >= 0) // Fatal error - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0); + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0); else { - send_ok(&thd->net,deleted); + send_ok(thd,deleted); DBUG_PRINT("info",("%d records deleted",deleted)); } DBUG_RETURN(0); @@ -354,7 +354,7 @@ void multi_delete::send_error(uint errcode,const char *err) DBUG_ENTER("multi_delete::send_error"); /* First send error what ever it is ... */ - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); /* If nothing deleted return */ if (!deleted) @@ -456,7 +456,7 @@ bool multi_delete::send_eof() thd->proc_info="end"; if (error) { - ::send_error(&thd->net); + ::send_error(thd); return 1; } @@ -483,7 +483,7 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - ::send_ok(&thd->net,deleted); + ::send_ok(thd,deleted); return 0; } @@ -580,7 +580,7 @@ end: Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); // This should return record count + send_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); unlock_table_name(thd, table_list); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index fb40a85fd91..6b144d36f53 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -120,7 +120,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) exit: close_thread_tables(thd); if (res > 0) - send_error(&thd->net, ER_UNKNOWN_COM_ERROR); // temporary only ... + send_error(thd, ER_UNKNOWN_COM_ERROR); // temporary only ... } DBUG_RETURN(res); } diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 70124c2d796..2eef088da5b 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -29,6 +29,6 @@ int mysql_do(THD *thd, List<Item> &values) DBUG_RETURN(-1); while ((value = li++)) value->val_int(); - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 13466f454c5..3d6a0fa24aa 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -18,202 +18,136 @@ /********************************************************************** This file contains the implementation of error and warnings related - - Whenever an error or warning occured, it pushes the same to - the respective list along with sending it to client. + - Whenever an error or warning occurred, it pushes it to a warning list + that the user can retrieve with SHOW WARNINGS or SHOW ERRORS. + + - For each statement, we return the number of warnings generated from this + command. Note that this can be different from @@warning_count as + we reset the warning list only for questions that uses a table. + This is done to allow on to do: + INSERT ...; + SELECT @@warning_count; + SHOW WARNINGS; + (If we would reset after each command, we could not retrieve the number + of warnings) - When client requests the information using SHOW command, then server processes from this list and returns back in the form of resultset. - syntax : SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows] - SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows] + Supported syntaxes: + + SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows] + SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows] + SELECT @@warning_count, @@error_count; ***********************************************************************/ -/* Handles errors and warnings .. */ #include "mysql_priv.h" -/* - Push the error to error list -*/ +/* + Reset all warnings for the thread -void push_error(uint code, const char *msg) -{ - THD *thd=current_thd; + SYNOPSIS + mysql_reset_errors() + thd Thread handle +*/ - mysql_st_error *err = new mysql_st_error(code,msg,(const char*)thd->query); - - if (thd->err_list.elements >= thd->max_error_count) - { - /* Remove the old elements and always maintain the max size - equal to sql_error_count. - - If one max_error_count using sets sql_error_count less than - the current list size, then make sure it always grows upto - sql_error_count size only - - ** BUG ** : Doesn't work in removing the old one - from the list, and thus SET SQL_ERROR_COUNT=x doesn't work - */ - for (uint count=thd->err_list.elements-1; - count <= thd->max_error_count-1; count++) - { - thd->err_list.remove_last(); - } - } - thd->err_list.push_front(err); +void mysql_reset_errors(THD *thd) +{ + free_root(&thd->warn_root,MYF(0)); + bzero((char*) thd->warn_count, sizeof(thd->warn_count)); + thd->warn_list.empty(); } + /* - Push the warning to warning list + Push the warning/error to error list if there is still room in the list + + SYNOPSIS + push_warning() + thd Thread handle + level Severity of warning (note, warning, error ...) + code Error number + msg Clear error message */ -void push_warning(uint code, const char *msg) -{ - THD *thd=current_thd; - - mysql_st_error *warn = new mysql_st_error(code,msg,(const char *)thd->query); - - if (thd->warn_list.elements >= thd->max_warning_count) +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, + const char *msg) +{ + if (thd->warn_list.elements < thd->variables.max_error_count) { - /* Remove the old elements and always maintian the max size - equal to sql_error_count + /* + The following code is here to change the allocation to not + use the thd->mem_root, which is freed after each query */ - for (uint count=thd->warn_list.elements; - count <= thd->max_warning_count-1; count++) - { - thd->warn_list.remove_last(); - } - } - thd->warn_list.push_front(warn); -} - -/* - List all errors -*/ - -int mysqld_show_errors(THD *thd) -{ - List<Item> field_list; - DBUG_ENTER("mysqld_show_errors"); - - field_list.push_back(new Item_int("CODE",0,4)); - field_list.push_back(new Item_empty_string("MESSAGE",MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_empty_string("QUERY",NAME_LEN)); - - if (send_fields(thd,field_list,1)) - DBUG_RETURN(1); - - mysql_st_error *err; - SELECT_LEX *sel=&thd->lex.select_lex; - ha_rows offset = sel->offset_limit,limit = sel->select_limit; - uint num_rows = 0; - - Error_iterator<mysql_st_error> it(thd->err_list); - - while(offset-- && (err = it++));/* Should be fixed with overloaded - operator '+' or with new funtion - goto() in list ? - */ - - while((num_rows++ < limit) && (err = it++)) - { - thd->packet.length(0); - net_store_data(&thd->packet,(uint32)err->code); - net_store_data(&thd->packet,err->msg); - net_store_data(&thd->packet,err->query); - - if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) - DBUG_RETURN(-1); + MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); + my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root); + MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg); + if (err) + thd->warn_list.push_back(err); + my_pthread_setspecific_ptr(THR_MALLOC, old_root); } - send_eof(&thd->net); - DBUG_RETURN(0); + thd->warn_count[(uint) level]++; + thd->total_warn_count++; } -/* - Return errors count -*/ -int mysqld_show_errors_count(THD *thd) -{ - List<Item> field_list; - DBUG_ENTER("mysqld_show_errors_count"); +/* + Send all notes, errors or warnings to the client in a result set - field_list.push_back(new Item_int("COUNT(*)",0,4)); + SYNOPSIS + mysqld_show_warnings() + thd Thread handler + levels_to_show Bitmap for which levels to show - if (send_fields(thd,field_list,1)) - DBUG_RETURN(1); + DESCRIPTION + Takes into account the current LIMIT - thd->packet.length(0); - net_store_data(&thd->packet,(uint32)thd->err_list.elements); + RETURN VALUES + 0 ok + 1 Error sending data to client +*/ - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) - DBUG_RETURN(-1); +static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"}; - send_eof(&thd->net); - DBUG_RETURN(0); -} -/* - List all warnings -*/ - -int mysqld_show_warnings(THD *thd) -{ +my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) +{ List<Item> field_list; - DBUG_ENTER("mysqld_show_warnings"); + DBUG_ENTER("mysqld_show_errors"); - field_list.push_back(new Item_int("CODE",0,21)); - field_list.push_back(new Item_empty_string("MESSAGE",MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_empty_string("QUERY",NAME_LEN)); + field_list.push_back(new Item_empty_string("Level", 7)); + field_list.push_back(new Item_int("Code",0,4)); + field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE)); if (send_fields(thd,field_list,1)) DBUG_RETURN(1); - mysql_st_error *warn; - + MYSQL_ERROR *err; + SELECT_LEX *sel= &thd->lex.select_lex; + ha_rows offset= sel->offset_limit, limit= sel->select_limit; - SELECT_LEX *sel=&thd->lex.select_lex; - ha_rows offset = sel->offset_limit,limit = sel->select_limit; - uint num_rows = 0; - - Error_iterator<mysql_st_error> it(thd->warn_list); - while(offset-- && (warn = it++)); - while((num_rows++ < limit) && (warn = it++)) + List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); + while ((err= it++)) { + /* Skip levels that the user is not interested in */ + if (!(levels_to_show & ((ulong) 1 << err->level))) + continue; + if (offset) + { + offset--; + continue; + } thd->packet.length(0); - net_store_data(&thd->packet,(uint32)warn->code); - net_store_data(&thd->packet,warn->msg); - net_store_data(&thd->packet,warn->query); - - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) - DBUG_RETURN(-1); + net_store_data(&thd->packet,warning_level_names[err->level]); + net_store_data(&thd->packet,(uint32) err->code); + net_store_data(&thd->packet,err->msg); + if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) + DBUG_RETURN(1); + if (!--limit) + break; } - send_eof(&thd->net); - DBUG_RETURN(0); -} - -/* - Return warnings count -*/ - -int mysqld_show_warnings_count(THD *thd) -{ - List<Item> field_list; - DBUG_ENTER("mysqld_show_warnings_count"); - - field_list.push_back(new Item_int("COUNT(*)",0,21)); - - if (send_fields(thd,field_list,1)) - DBUG_RETURN(1); - - thd->packet.length(0); - net_store_data(&thd->packet,(uint32)thd->warn_list.elements); - - if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) - DBUG_RETURN(-1); - - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } - diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 7fa24faf6c4..4191973b325 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -62,7 +62,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables) return -1; } - send_ok(&thd->net); + send_ok(thd); return 0; } @@ -83,7 +83,7 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) return -1; } if (!dont_send_ok) - send_ok(&thd->net); + send_ok(thd); return 0; } @@ -185,7 +185,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len)))) { - send_error(&thd->net,ER_OUTOFMEMORY); + send_error(thd,ER_OUTOFMEMORY); goto err; } key_copy(key, table, keyno, key_len); @@ -195,7 +195,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, break; } default: - send_error(&thd->net,ER_ILLEGAL_HA); + send_error(thd,ER_ILLEGAL_HA); goto err; } @@ -240,7 +240,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } ok: mysql_unlock_tables(thd,lock); - send_eof(&thd->net); + send_eof(thd); return 0; err: mysql_unlock_tables(thd,lock); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b02fd99e358..2852ac8b45d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -333,7 +333,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) || !thd->cuted_fields)) - send_ok(&thd->net,info.copied+info.deleted,id); + send_ok(thd,info.copied+info.deleted,id); else { char buff[160]; @@ -345,7 +345,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, else sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, thd->cuted_fields); - ::send_ok(&thd->net,info.copied+info.deleted,(ulonglong)id,buff); + ::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff); } DBUG_RETURN(0); @@ -667,7 +667,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) delete tmp; thd->fatal_error=1; pthread_mutex_unlock(&LOCK_delayed_create); - net_printf(&thd->net,ER_CANT_CREATE_THREAD,error); + net_printf(thd,ER_CANT_CREATE_THREAD,error); DBUG_RETURN(0); } @@ -1334,7 +1334,7 @@ bool select_insert::send_data(List<Item> &values) void select_insert::send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); ha_rollback_stmt(thd); @@ -1360,7 +1360,7 @@ bool select_insert::send_eof() if (error) { table->file->print_error(error,MYF(0)); - ::send_error(&thd->net); + ::send_error(thd); return 1; } else @@ -1374,7 +1374,7 @@ bool select_insert::send_eof() thd->cuted_fields); if (last_insert_id) thd->insert_id(last_insert_id); // For update log - ::send_ok(&thd->net,info.copied,last_insert_id,buff); + ::send_ok(thd,info.copied,last_insert_id,buff); mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index dc9019de2c8..1af8d363fda 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1064,7 +1064,7 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, // check usage of ORDER BY in union if (sl->order_list.first && sl->next_select() && !sl->braces) { - net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY"); + net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY"); return 1; } for (SELECT_LEX_UNIT *inner= sl->first_inner_unit(); @@ -1092,7 +1092,7 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux, sizeof(*aux)))) { - send_error(&thd->net,0); + send_error(thd,0); return 1; } *new_table_list= cursor; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6aef99886e9..dba8216e94c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -238,7 +238,8 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; SELECT_LEX - store information of parsed SELECT_LEX statment */ class JOIN; -class st_select_lex: public st_select_lex_node { +class st_select_lex: public st_select_lex_node +{ public: char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ @@ -342,6 +343,7 @@ typedef struct st_lex enum enum_var_type option_type; uint grant, grant_tot_col, which_columns, union_option; uint fk_delete_opt, fk_update_opt, fk_match_option; + uint param_count; bool drop_primary, drop_if_exists, local_file, olap; bool in_comment, ignore_space, verbose, simple_alter; bool derived_tables; diff --git a/sql/sql_list.h b/sql/sql_list.h index ef8a0c41a1b..56e6528f214 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -362,120 +362,3 @@ public: I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {} inline T* operator++(int) { return (T*) base_ilist_iterator::next(); } }; - -/* - New error list without mem_root from THD, to have the life of the - allocation becomes connection level . by ovveriding new from Sql_alloc. -*/ -class Error_alloc -{ -public: - static void *operator new(size_t size) - { - return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE)); - } -#if 0 - static void operator delete(void* ptr_arg, size_t size) - { - my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); - } -#endif - friend class error_node; - friend class error_list; -}; - -class error_node :public Error_alloc, public list_node -{ -public: - static void *operator new(size_t size) - { - return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE)); - } -#if 0 - static void operator delete(void* ptr_arg, size_t size) - { - my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); - } -#endif - error_node(void *info_par,list_node *next_par):list_node(info_par,next_par){}; - error_node() : list_node() {}; - friend class error_list; - friend class error_list_iterator; -}; - -class error_list: public Error_alloc, public base_list -{ -public: - inline error_list() : base_list() { }; - inline error_list(const error_list &tmp) : base_list(tmp) - { - elements=tmp.elements; - first=tmp.first; - last=tmp.last; - } - inline bool push_front(void *info) - { - error_node *node=new error_node(info,first); - if (node) - { - if (last == &first) - last= &node->next; - first=node; - elements++; - return 0; - } - return 1; - } - inline void remove_last(void) - { - remove(last); - } -protected: - void after(void *info,list_node *node) - { - error_node *new_node=new error_node(info,node->next); - node->next=new_node; - elements++; - if (last == &(node->next)) - last= &new_node->next; - } -}; - -class error_list_iterator : public base_list_iterator -{ - inline error_list_iterator(base_list &base_ptr): base_list_iterator(base_ptr) {}; -}; - -template <class T> class Error :public error_list -{ -public: - inline Error() :error_list() {} - inline Error(const Error<T> &tmp) :error_list(tmp) {} - inline bool push_back(T *a) { return error_list::push_back(a); } - inline bool push_front(T *a) { return error_list::push_front(a); } - inline T* head() {return (T*) error_list::head(); } - inline T** head_ref() {return (T**) error_list::head_ref(); } - inline T* pop() {return (T*) error_list::pop(); } - void delete_elements(void) - { - error_node *element,*next; - for (element=first; element != &error_end_of_list; element=next) - { - next=element->next; - delete (T*) element->info; - } - empty(); - } -}; - -template <class T> class Error_iterator :public base_list_iterator -{ -public: - Error_iterator(Error<T> &a) : base_list_iterator(a) {} - inline T* operator++(int) { return (T*) base_list_iterator::next(); } - inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } - inline T *replace(Error<T> &a) { return (T*) base_list_iterator::replace(a); } - inline void after(T *a) { base_list_iterator::after(a); } - inline T** ref(void) { return (T**) base_list_iterator::ref(); } -}; - diff --git a/sql/sql_load.cc b/sql/sql_load.cc index ad25ef85e75..fe556be98f5 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -293,7 +293,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted, info.records-info.copied,thd->cuted_fields); - send_ok(&thd->net,info.copied+info.deleted,0L,name); + send_ok(thd,info.copied+info.deleted,0L,name); // on the slave thd->query is never initialized if (!thd->slave_thread) mysql_update_log.write(thd,thd->query,thd->query_length); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b889b9ee29f..461276900a5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -57,7 +57,7 @@ extern "C" pthread_mutex_t THR_LOCK_keycache; extern "C" int gethostname(char *name, int namelen); #endif -static int check_for_max_user_connections(USER_CONN *uc); +static int check_for_max_user_connections(THD *thd, USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); @@ -77,7 +77,7 @@ const char *command_name[]={ "Prepare", "Prepare Execute", "Long Data" }; -bool volatile abort_slave = 0; +static char empty_c_string[1]= {0}; // Used for not defined 'db' #ifdef HAVE_OPENSSL extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; @@ -144,7 +144,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, my_malloc(sizeof(struct user_conn) + temp_len+1, MYF(MY_WME))))) { - send_error(¤t_thd->net, 0, NullS); // Out of memory + send_error(thd, 0, NullS); // Out of memory return_val=1; goto end; } @@ -162,7 +162,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, if (hash_insert(&hash_user_connections, (byte*) uc)) { my_free((char*) uc,0); - send_error(¤t_thd->net, 0, NullS); // Out of memory + send_error(thd, 0, NullS); // Out of memory return_val=1; goto end; } @@ -184,14 +184,13 @@ end: static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { - NET *net= &thd->net; thd->db=0; thd->db_length=0; USER_RESOURCES ur; if (!(thd->user = my_strdup(user, MYF(0)))) { - send_error(net,ER_OUT_OF_RESOURCES); + send_error(thd,ER_OUT_OF_RESOURCES); return 1; } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, @@ -207,7 +206,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, thd->master_access, thd->db ? thd->db : "*none*")); if (thd->master_access & NO_ACCESS) { - net_printf(net, ER_ACCESS_DENIED_ERROR, + net_printf(thd, ER_ACCESS_DENIED_ERROR, thd->user, thd->host_or_ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); @@ -225,7 +224,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (tmp) { // Too many connections - send_error(net, ER_CON_COUNT_ERROR); + send_error(thd, ER_CON_COUNT_ERROR); return(1); } } @@ -242,7 +241,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) return -1; if (thd->user_connect && thd->user_connect->user_resources.connections && - check_for_max_user_connections(thd->user_connect)) + check_for_max_user_connections(thd, thd->user_connect)) return -1; if (db && db[0]) { @@ -252,7 +251,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, return error; } else - send_ok(net); // Ready to handle questions + send_ok(thd); // Ready to handle questions return 0; // ok } @@ -283,7 +282,7 @@ void init_max_user_conn(void) } -static int check_for_max_user_connections(USER_CONN *uc) +static int check_for_max_user_connections(THD *thd, USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); @@ -291,7 +290,7 @@ static int check_for_max_user_connections(USER_CONN *uc) if (max_user_connections && (max_user_connections <= (uint) uc->connections)) { - net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user); + net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; goto end; } @@ -299,11 +298,10 @@ static int check_for_max_user_connections(USER_CONN *uc) if (uc->user_resources.connections && uc->conn_per_hour++ >= uc->user_resources.connections) { - net_printf(¤t_thd->net, ER_USER_LIMIT_REACHED, uc->user, + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_connections", (long) uc->user_resources.connections); error=1; - goto end; } end: DBUG_RETURN(error); @@ -363,7 +361,7 @@ static bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.questions && uc->questions++ >= uc->user_resources.questions) { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions", + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", (long) uc->user_resources.questions); error=1; goto end; @@ -374,7 +372,7 @@ static bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.updates && uc_update_queries[check_command] && uc->updates++ >= uc->user_resources.updates) { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", (long) uc->user_resources.updates); error=1; goto end; @@ -501,7 +499,7 @@ check_connections(THD *thd) int2store(end+3,thd->server_status); bzero(end+5,13); end+=18; - if (net_write_command(net,(uchar) protocol_version, buff, + if (net_write_command(net,(uchar) protocol_version, "", 0, buff, (uint) (end-buff)) || (pkt_len= my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) @@ -629,7 +627,7 @@ pthread_handler_decl(handle_one_connection,arg) if ((error=check_connections(thd))) { // Wrong permissions if (error > 0) - net_printf(net,error,thd->host_or_ip); + net_printf(thd,error,thd->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) sleep(1); /* must wait after eof() */ @@ -667,7 +665,7 @@ pthread_handler_decl(handle_one_connection,arg) thd->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); - send_error(net,net->last_errno,NullS); + send_error(thd,net->last_errno,NullS); thread_safe_increment(aborted_threads,&LOCK_status); } @@ -765,11 +763,11 @@ end: DBUG_RETURN(0); // Never reached } + /* This works because items are allocated with sql_alloc() */ -inline void free_items(THD *thd) +void free_items(Item *item) { - /* This works because items are allocated with sql_alloc() */ - for (Item *item=thd->free_list ; item ; item=item->next) + for (; item ; item=item->next) delete item; } @@ -793,7 +791,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!db || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); goto err; } if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege)) @@ -891,7 +889,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_REGISTER_SLAVE: { if (!register_slave(thd, (uchar*)packet, packet_length)) - send_ok(&thd->net); + send_ok(thd); break; } case COM_TABLE_DUMP: @@ -907,7 +905,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, memcpy(tbl_name, packet + db_len + 2, tbl_len); tbl_name[tbl_len] = 0; if (mysql_table_dump(thd, db, tbl_name, -1)) - send_error(&thd->net); // dump to NET + send_error(thd); // dump to NET break; } @@ -929,7 +927,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if ((uint) ((uchar*) db - net->read_pos) > packet_length) { // Check if protocol is ok - send_error(net, ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); break; } if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0)) @@ -953,48 +951,26 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_EXECUTE: { - mysql_com_execute(thd); + mysql_stmt_execute(thd, packet); break; } case COM_LONG_DATA: { - mysql_com_longdata(thd); + mysql_stmt_get_longdata(thd, packet, packet_length); break; } case COM_PREPARE: { - mysql_com_prepare(thd,packet,packet_length); + mysql_stmt_prepare(thd, packet, packet_length); break; } case COM_QUERY: { - packet_length--; // Remove end null - /* Remove garage at start and end of query */ - while (my_isspace(system_charset_info,packet[0]) && packet_length > 0) - { - packet++; - packet_length--; - } - char *pos=packet+packet_length; // Point at end null - while (packet_length > 0 && - (pos[-1] == ';' || my_isspace(system_charset_info,pos[-1]))) - { - pos--; - packet_length--; - } - /* We must allocate some extra memory for query cache */ - if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), - packet_length, - thd->db_length+2))) - break; - thd->query[packet_length]=0; - thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); + if (alloc_query(thd, packet, packet_length)) + break; // fatal error is set mysql_log.write(thd,command,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); - /* thd->query_length is set by mysql_parse() */ - mysql_parse(thd,thd->query,packet_length); + mysql_parse(thd,thd->query, thd->query_length); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); DBUG_PRINT("info",("query ready")); @@ -1002,7 +978,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_FIELD_LIST: // This isn't actually needed #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ break; #else { @@ -1012,7 +988,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, bzero((char*) &table_list,sizeof(table_list)); if (!(table_list.db=thd->db)) { - send_error(net,ER_NO_DB_ERROR); + send_error(thd,ER_NO_DB_ERROR); break; } thd->free_list=0; @@ -1030,7 +1006,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2)) break; mysqld_list_fields(thd,&table_list,fields); - free_items(thd); + free_items(thd->free_list); break; } #endif @@ -1048,11 +1024,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; } if (lower_case_table_names) - casedn_str(db); + my_casedn_str(system_charset_info, db); if (check_access(thd,CREATE_ACL,db,0,1)) break; mysql_log.write(thd,command,packet); @@ -1066,14 +1042,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; } if (lower_case_table_names) - casedn_str(db); + my_casedn_str(system_charset_info, db); if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); break; } mysql_log.write(thd,command,db); @@ -1112,9 +1088,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; mysql_log.write(thd,command,NullS); if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0)) - send_error(net,0); + send_error(thd,0); else - send_eof(net); + send_eof(thd); break; } case COM_SHUTDOWN: @@ -1123,12 +1099,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* purecov: inspected */ DBUG_PRINT("quit",("Got shutdown command")); mysql_log.write(thd,command,NullS); - send_eof(net); + send_eof(thd); #ifdef __WIN__ sleep(1); // must wait after eof() #endif #ifndef OS2 - send_eof(net); // This is for 'quit request' + send_eof(thd); // This is for 'quit request' #endif close_connection(net); close_thread_tables(thd); // Free before kill @@ -1161,7 +1137,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_PING: thread_safe_increment(com_other,&LOCK_status); - send_ok(net); // Tell client we are alive + send_ok(thd); // Tell client we are alive break; case COM_PROCESS_INFO: thread_safe_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status); @@ -1184,14 +1160,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* purecov: inspected */ mysql_print_status(thd); mysql_log.write(thd,command,NullS); - send_eof(net); + send_eof(thd); break; case COM_SLEEP: case COM_CONNECT: // Impossible here case COM_TIME: // Impossible from client case COM_DELAYED_INSERT: default: - send_error(net, ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); break; } if (thd->lock || thd->open_tables) @@ -1201,7 +1177,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } if (thd->fatal_error) - send_error(net,0); // End of memory ? + send_error(thd,0); // End of memory ? time_t start_of_query=thd->start_time; thd->end_time(); // Set start time @@ -1233,22 +1209,80 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_RETURN(error); } + +/* + Read query from packet and store in thd->query + Used in COM_QUERY and COM_PREPARE + + DESCRIPTION + Sets the following THD variables: + query + query_length + + RETURN VALUES + 0 ok + 1 error; In this case thd->fatal_error is set +*/ + +bool alloc_query(THD *thd, char *packet, ulong packet_length) +{ + packet_length--; // Remove end null + /* Remove garage at start and end of query */ + while (my_isspace(system_charset_info,packet[0]) && packet_length > 0) + { + packet++; + packet_length--; + } + char *pos=packet+packet_length; // Point at end null + while (packet_length > 0 && + (pos[-1] == ';' || my_isspace(system_charset_info,pos[-1]))) + { + pos--; + packet_length--; + } + /* We must allocate some extra memory for query cache */ + if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), + packet_length, + thd->db_length+2))) + return 1; + thd->query[packet_length]=0; + thd->query_length= packet_length; + thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + return 0; +} + /**************************************************************************** ** mysql_execute_command ** Execute command saved in thd and current_lex->sql_command ****************************************************************************/ void -mysql_execute_command(void) +mysql_execute_command(THD *thd) { int res= 0; - THD *thd= current_thd; LEX *lex= &thd->lex; TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first; SELECT_LEX *select_lex= lex->select; SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_execute_command"); + /* + Reset warning count for each query that uses tables + A better approach would be to reset this for any commands + that is not a SHOW command or a select that only access local + variables, but for now this is probably good enough. + */ + if (tables) + mysql_reset_errors(thd); + /* + Save old warning count to be able to send to client how many warnings we + got + */ + thd->old_total_warn_count= thd->total_warn_count; + if (thd->slave_thread) { /* @@ -1376,7 +1410,7 @@ mysql_execute_command(void) break; case SQLCOM_EMPTY_QUERY: - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_PURGE: @@ -1388,12 +1422,15 @@ mysql_execute_command(void) } case SQLCOM_SHOW_WARNS: { - res = mysqld_show_warnings(thd); + res= mysqld_show_warnings(thd, (ulong) + ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) | + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN))); break; } case SQLCOM_SHOW_ERRORS: { - res = mysqld_show_errors(thd); + res= mysqld_show_warnings(thd, (ulong) + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)); break; } case SQLCOM_SHOW_NEW_MASTER: @@ -1499,7 +1536,7 @@ mysql_execute_command(void) } if (strlen(tables->name) > NAME_LEN) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name); + net_printf(thd,ER_WRONG_TABLE_NAME,tables->name); break; } LOCK_ACTIVE_MI; @@ -1507,7 +1544,7 @@ mysql_execute_command(void) if (!fetch_master_table(thd, tables->db, tables->real_name, active_mi, 0)) { - send_ok(&thd->net); + send_ok(thd); } UNLOCK_ACTIVE_MI; break; @@ -1535,7 +1572,7 @@ mysql_execute_command(void) } if (strlen(tables->name) > NAME_LEN) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name); + net_printf(thd,ER_WRONG_TABLE_NAME,tables->name); res=0; break; } @@ -1559,7 +1596,7 @@ mysql_execute_command(void) if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && check_dup(tables->db, tables->real_name, tables->next)) { - net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); + net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } if (tables->next) @@ -1598,7 +1635,7 @@ mysql_execute_command(void) lex->create_list, lex->key_list,0,0,0); // do logging if (!res) - send_ok(&thd->net); + send_ok(thd); } break; } @@ -1631,14 +1668,14 @@ mysql_execute_command(void) } case SQLCOM_ALTER_TABLE: #if defined(DONT_ALLOW_SHOW_COMMANDS) - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ break; #else { ulong priv=0; if (lex->name && strlen(lex->name) > NAME_LEN) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name); + net_printf(thd,ER_WRONG_TABLE_NAME,lex->name); res=0; break; } @@ -1721,7 +1758,7 @@ mysql_execute_command(void) } case SQLCOM_SHOW_BINLOGS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { @@ -1733,7 +1770,7 @@ mysql_execute_command(void) #endif case SQLCOM_SHOW_CREATE: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { @@ -1805,7 +1842,7 @@ mysql_execute_command(void) goto error; if (select_lex->item_list.elements != lex->value_list.elements) { - send_error(&thd->net,ER_WRONG_VALUE_COUNT); + send_error(thd,ER_WRONG_VALUE_COUNT); DBUG_VOID_RETURN; } if (select_lex->table_list.elements == 1) @@ -1844,7 +1881,7 @@ mysql_execute_command(void) msg="LIMIT"; if (msg) { - net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg); + net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg); res= 1; break; } @@ -1934,7 +1971,7 @@ mysql_execute_command(void) if (check_dup(tables->db, tables->real_name, tables->next)) { - net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); + net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } tables->lock_type=TL_WRITE; // update first table @@ -1966,7 +2003,7 @@ mysql_execute_command(void) */ if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS); goto error; } res=mysql_truncate(thd,tables); @@ -2003,7 +2040,7 @@ mysql_execute_command(void) goto error; if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) { - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); goto error; } for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) @@ -2019,7 +2056,7 @@ mysql_execute_command(void) } if (!walk) { - net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name); + net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name); goto error; } auxi->lock_type=walk->lock_type=TL_WRITE; @@ -2078,7 +2115,7 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_DATABASES: #if defined(DONT_ALLOW_SHOW_COMMANDS) - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else if ((specialflag & SPECIAL_SKIP_SHOW_DB) && @@ -2112,7 +2149,7 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_LOGS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { @@ -2125,20 +2162,20 @@ mysql_execute_command(void) case SQLCOM_SHOW_TABLES: /* FALL THROUGH */ #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=select_lex->db ? select_lex->db : thd->db; if (!db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' if (check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db); + net_printf(thd,ER_WRONG_DB_NAME, db); goto error; } if (check_access(thd,SELECT_ACL,db,&thd->col_access)) @@ -2161,14 +2198,14 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_FIELDS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=tables->db; if (!*db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' @@ -2186,14 +2223,14 @@ mysql_execute_command(void) #endif case SQLCOM_SHOW_KEYS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=tables->db; if (!db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' @@ -2227,7 +2264,7 @@ mysql_execute_command(void) if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || ! opt_local_infile) { - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); + send_error(thd,ER_NOT_ALLOWED_COMMAND); goto error; } if (check_access(thd,privilege,tables->db,&tables->grant.privilege) || @@ -2242,7 +2279,7 @@ mysql_execute_command(void) if (sql_set_variables(thd, &lex->var_list)) res= -1; else - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_UNLOCK_TABLES: if (thd->locked_tables) @@ -2257,7 +2294,7 @@ mysql_execute_command(void) } if (thd->global_read_lock) unlock_global_read_lock(thd); - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_LOCK_TABLES: if (thd->locked_tables) @@ -2276,7 +2313,7 @@ mysql_execute_command(void) { thd->locked_tables=thd->lock; thd->lock=0; - send_ok(&thd->net); + send_ok(thd); } else thd->options&= ~(ulong) (OPTION_TABLE_LOCK); @@ -2286,11 +2323,11 @@ mysql_execute_command(void) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (lower_case_table_names) - casedn_str(lex->name); + my_casedn_str(system_charset_info, lex->name); if (check_access(thd,CREATE_ACL,lex->name,0,1)) break; res=mysql_create_db(thd,lex->name,&lex->create_info,0); @@ -2300,16 +2337,16 @@ mysql_execute_command(void) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (lower_case_table_names) - casedn_str(lex->name); + my_casedn_str(system_charset_info, lex->name); if (check_access(thd,DROP_ACL,lex->name,0,1)) break; if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); goto error; } res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0); @@ -2319,31 +2356,31 @@ mysql_execute_command(void) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (check_access(thd,ALTER_ACL,lex->name,0,1)) break; if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); goto error; } - res=mysql_alter_db(thd,lex->name,&lex->create_info,0); + res=mysql_alter_db(thd,lex->name,&lex->create_info); break; } case SQLCOM_SHOW_CREATE_DB: { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (check_access(thd,DROP_ACL,lex->name,0,1)) break; if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); goto error; } res=mysqld_show_create_db(thd,lex->name); @@ -2354,7 +2391,7 @@ mysql_execute_command(void) break; #ifdef HAVE_DLOPEN if (!(res = mysql_create_function(thd,&lex->udf))) - send_ok(&thd->net); + send_ok(thd); #else res= -1; #endif @@ -2364,7 +2401,7 @@ mysql_execute_command(void) break; #ifdef HAVE_DLOPEN if (!(res = mysql_drop_function(thd,lex->udf.name))) - send_ok(&thd->net); + send_ok(thd); #else res= -1; #endif @@ -2424,7 +2461,7 @@ mysql_execute_command(void) { if (lex->columns.elements) { - send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE); res=1; } else @@ -2454,9 +2491,9 @@ mysql_execute_command(void) if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables)) goto error; if (reload_acl_and_cache(thd, lex->type, tables)) - send_error(&thd->net,0); + send_error(thd,0); else - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_KILL: kill_one_thread(thd,lex->thread_id); @@ -2506,7 +2543,7 @@ mysql_execute_command(void) thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; - send_ok(&thd->net); + send_ok(thd); } break; case SQLCOM_COMMIT: @@ -2520,7 +2557,7 @@ mysql_execute_command(void) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (!ha_commit(thd)) { - send_ok(&thd->net); + send_ok(thd); } else res= -1; @@ -2531,21 +2568,21 @@ mysql_execute_command(void) if (!ha_rollback(thd)) { if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) - send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); + send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); else - send_ok(&thd->net); + send_ok(thd); } else res= -1; thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; default: /* Impossible */ - send_ok(&thd->net); + send_ok(thd); break; } thd->proc_info="query end"; // QQ if (res < 0) - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); error: DBUG_VOID_RETURN; @@ -2578,7 +2615,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { if (!no_errors) - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } @@ -2591,7 +2628,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, ! db && dont_check_global_grants) { // We can never grant this if (!no_errors) - net_printf(&thd->net,ER_ACCESS_DENIED_ERROR, + net_printf(thd,ER_ACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ @@ -2616,7 +2653,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, !(want_access & ~TABLE_ACLS))) DBUG_RETURN(FALSE); /* Ok */ if (!no_errors) - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ @@ -2632,7 +2669,7 @@ bool check_global_access(THD *thd, ulong want_access) if ((thd->master_access & want_access) == want_access) return 0; get_privilege_desc(command, sizeof(command), want_access); - net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR, + net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR, command); return 1; } @@ -2687,7 +2724,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables) { if (!(tables->db=thd->db)) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ return TRUE; /* purecov: tested */ } } @@ -2710,7 +2747,7 @@ static bool check_merge_table_access(THD *thd, char *db, tmp->db=db; else if (strcmp(tmp->db,db)) { - send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR); + send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR); return 1; } } @@ -2799,11 +2836,10 @@ mysql_init_query(THD *thd) thd->lex.olap=0; thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE; thd->fatal_error= 0; // Safety + thd->total_warn_count=0; // Warnings for this query thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; thd->sent_row_count= thd->examined_row_count= 0; thd->safe_to_cache_query= 1; - thd->param_count=0; - thd->prepare_command=false; thd->lex.param_list.empty(); DBUG_VOID_RETURN; } @@ -2850,6 +2886,33 @@ mysql_new_select(LEX *lex, bool move_down) return 0; } +/* + Create a select to return the same output as 'SELECT @@var_name'. + + SYNOPSIS + create_select_for_variable() + var_name Variable name + + DESCRIPTION + Used for SHOW COUNT(*) [ WARNINGS | ERROR] + + This will crash with a core dump if the variable doesn't exists +*/ + +void create_select_for_variable(const char *var_name) +{ + LEX *lex; + LEX_STRING tmp; + DBUG_ENTER("create_select_for_variable"); + lex= current_lex; + mysql_init_select(lex); + lex->sql_command= SQLCOM_SELECT; + tmp.str= (char*) var_name; + tmp.length=strlen(var_name); + add_item_to_list(get_system_var(OPT_SESSION, tmp)); + DBUG_VOID_RETURN; +} + void mysql_init_multi_delete(LEX *lex) { @@ -2881,7 +2944,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) } else { - mysql_execute_command(); + mysql_execute_command(thd); query_cache_end_of_result(&thd->net); } } @@ -2892,7 +2955,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) query_cache_abort(&thd->net); } thd->proc_info="freeing items"; - free_items(thd); /* Free strings used by items */ + free_items(thd->free_list); /* Free strings used by items */ lex_end(lex); } DBUG_VOID_RETURN; @@ -2928,7 +2991,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, if (strlen(field_name) > NAME_LEN) { - net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */ + net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } if (type_modifier & PRI_KEY_FLAG) @@ -2951,7 +3014,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } default_value=0; @@ -3037,7 +3100,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, res=default_value->val_str(&str); if (res->length()) { - net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */ + net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } new_field->def=0; @@ -3057,7 +3120,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, uint tmp_length=new_field->length; if (tmp_length > PRECISION_FOR_DOUBLE) { - net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name); + net_printf(thd,ER_WRONG_FIELD_SPEC,field_name); DBUG_RETURN(1); } else if (tmp_length > PRECISION_FOR_FLOAT) @@ -3111,7 +3174,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, { if (interval->count > sizeof(longlong)*8) { - net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */ + net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } new_field->pack_length=(interval->count+7)/8; @@ -3133,7 +3196,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, (void) find_set(interval,res->ptr(),res->length()); if (thd->cuted_fields) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } } @@ -3156,7 +3219,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, res=default_value->val_str(&str); if (!find_enum(interval,res->ptr(),res->length())) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } } @@ -3168,14 +3231,14 @@ bool add_field_to_list(char *field_name, enum_field_types type, (!new_field->length && !(new_field->flags & BLOB_FLAG) && type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING)) { - net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name, + net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name, MAX_FIELD_WIDTH-1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } type_modifier&= AUTO_INCREMENT_FLAG; if ((~allowed_type_modifier) & type_modifier) { - net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name); + net_printf(thd,ER_WRONG_FIELD_SPEC,field_name); DBUG_RETURN(1); } if (!new_field->pack_length) @@ -3286,7 +3349,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, (table->table.length && check_table_name(table->table.str,table->table.length)) || table->db.str && check_db_name(table->db.str)) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str); + net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str); DBUG_RETURN(0); } @@ -3308,7 +3371,8 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, } else { - ptr->db= (char*) ""; + /* The following can't be "" as we may do 'casedn_str()' on it */ + ptr->db= empty_c_string; ptr->db_length= 0; } @@ -3339,7 +3403,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, { if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db)) { - net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ + net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ } } @@ -3487,9 +3551,9 @@ void kill_one_thread(THD *thd, ulong id) } if (!error) - send_ok(&thd->net); + send_ok(thd); else - net_printf(&thd->net,error,id); + net_printf(thd,error,id); } /* Clear most status variables */ @@ -3552,7 +3616,7 @@ bool check_simple_select() char command[80]; strmake(command, thd->lex.yylval->symbol.str, min(thd->lex.yylval->symbol.length, sizeof(command)-1)); - net_printf(&thd->net, ER_CANT_USE_OPTION_HERE, command); + net_printf(thd, ER_CANT_USE_OPTION_HERE, command); return 1; } return 0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d41aca21fb8..05b3f360caa 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -25,7 +25,7 @@ Prepare: store its information list lex->param_list - Without executing the query, return back to client the total number of parameters along with result-set metadata information - (if any ) + (if any) Prepare-execute: @@ -38,46 +38,132 @@ Prepare-execute: to client Long data handling: - - Server gets the long data in pieces with command type 'COM_LONG_DATA'. - The packet recieved will have the format as: - [type_spec_exists][type][length][data] + [COM_LONG_DATA:1][parameter_number:2][type:2][data] - Checks if the type is specified by client, and if yes reads the type, and stores the data in that format. - - If length == MYSQL_END_OF_DATA, then server sets up the data read ended. + - It's up to the client to check for read data ended. The server doesn't + care. + ***********************************************************************/ #include "mysql_priv.h" #include "sql_acl.h" #include <assert.h> // for DEBUG_ASSERT() -#include <ctype.h> // for isspace() +#include <m_ctype.h> // for isspace() -/**************************************************************************/ extern int yyparse(void); static ulong get_param_length(uchar **packet); static uint get_buffer_type(uchar **packet); static bool param_is_null(uchar **packet); static bool setup_param_fields(THD *thd,List<Item> ¶ms); -static uchar* setup_param_field(Item_param *item_param, uchar *pos, uint buffer_type); +static uchar* setup_param_field(Item_param *item_param, uchar *pos, + uint buffer_type); static void setup_longdata_field(Item_param *item_param, uchar *pos); static bool setup_longdata(THD *thd,List<Item> ¶ms); -static void send_prepare_results(THD *thd); -static void mysql_parse_prepare_query(THD *thd,char *packet,uint length); -static bool mysql_send_insert_fields(THD *thd,TABLE_LIST *table_list, +static bool send_prepare_results(PREP_STMT *stmt); +static bool parse_prepare_query(PREP_STMT *stmt, char *packet, uint length); +static bool mysql_send_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, - List<List_item> &values_list,thr_lock_type lock_type); -static bool mysql_test_insert_fields(THD *thd,TABLE_LIST *table_list, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, - List<List_item> &values_list,thr_lock_type lock_type); -static bool mysql_test_upd_fields(THD *thd,TABLE_LIST *table_list, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, COND *conds,thr_lock_type lock_type); -static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, - List<Item> &fields, List<Item> &values, - COND *conds, ORDER *order, ORDER *group, - Item *having,thr_lock_type lock_type); -extern const char *any_db; -/**************************************************************************/ +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, + List<Item> &fields, List<Item> &values, + COND *conds, ORDER *order, ORDER *group, + Item *having,thr_lock_type lock_type); + + +/* + Find prepared statement in thd + + SYNOPSIS + find_prepared_statement() + thd Thread handler + stmt_id Statement id server specified to the client on prepare + + RETURN VALUES + 0 error. In this case the error is sent with my_error() + ptr Pointer to statement +*/ + +static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id, + const char *when) +{ + PREP_STMT *stmt; + DBUG_ENTER("find_prepared_statement"); + DBUG_PRINT("enter",("stmt_id: %d", stmt_id)); + + if (thd->last_prepared_stmt && thd->last_prepared_stmt->stmt_id == stmt_id) + DBUG_RETURN(thd->last_prepared_stmt); + if ((stmt= (PREP_STMT*) tree_search(&thd->prepared_statements, &stmt_id, + (void*) 0))) + DBUG_RETURN (thd->last_prepared_stmt= stmt); + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, when); + DBUG_RETURN(0); +} + +/* + Compare two prepared statements; Used to find a prepared statement +*/ + +int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used) +{ + return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1; +} + + +/* + Free prepared statement. + + SYNOPSIS + standard tree_element_free function. + + DESCRIPTION + We don't have to free the stmt itself as this was stored in the tree + and will be freed when the node is deleted +*/ + +void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used) +{ + free_root(&stmt->mem_root, MYF(0)); + free_items(stmt->free_list); +} + +/* + Send prepared stmt info to client after prepare +*/ + +bool send_prep_stmt(PREP_STMT *stmt, uint columns) +{ + char buff[8]; + int4store(buff, stmt->stmt_id); + int2store(buff+4, columns); + int2store(buff+6, stmt->param_count); + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + +/* + Send information about all item parameters + + TODO: Not yet ready +*/ + +bool send_item_params(PREP_STMT *stmt) +{ + char buff[1]; + buff[0]=0; + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + + /* Read the buffer type, this happens only first time @@ -90,8 +176,13 @@ static uint get_buffer_type(uchar **packet) return (uint) uint2korr(pos); } + /* Check for NULL param data + + RETURN VALUES + 0 Value was not NULL + 1 Value was NULL */ static bool param_is_null(uchar **packet) @@ -144,8 +235,7 @@ static uchar* setup_param_field(Item_param *item_param, item_param->set_null(); return(pos); } - switch (buffer_type) - { + switch (buffer_type) { case FIELD_TYPE_TINY: item_param->set_int((longlong)(*pos)); pos += 1; @@ -169,7 +259,7 @@ static uchar* setup_param_field(Item_param *item_param, case FIELD_TYPE_FLOAT: float data; float4get(data,pos); - item_param->set_double(data); + item_param->set_double((double) data); pos += 4; break; case FIELD_TYPE_DOUBLE: @@ -193,20 +283,19 @@ static uchar* setup_param_field(Item_param *item_param, from client .. */ -static bool setup_param_fields(THD *thd, List<Item> ¶ms) +static bool setup_param_fields(THD *thd, PREP_STMT *stmt) { - reg2 Item_param *item_param; - List_iterator<Item> it(params); - NET *net = &thd->net; DBUG_ENTER("setup_param_fields"); - +#ifdef READY_TO_BE_USED + Item_param *item_param; ulong param_count=0; - uchar *pos=(uchar*)net->read_pos+1;// skip command type - - if(*pos++) // No types supplied, read only param data + uchar *pos=(uchar*) thd->net.read_pos+1;// skip command type + + + if (*pos++) // No types supplied, read only param data { while ((item_param=(Item_param *)it++) && - (param_count++ < thd->param_count)) + (param_count++ < stmt->param_count)) { if (item_param->long_data_supplied) continue; @@ -224,68 +313,15 @@ static bool setup_param_fields(THD *thd, List<Item> ¶ms) continue; if (!(pos=setup_param_field(item_param,pos, - item_param->buffer_type=(enum_field_types)get_buffer_type(&pos)))) + item_param->buffer_type= + (enum_field_types) get_buffer_type(&pos)))) DBUG_RETURN(1); } } +#endif DBUG_RETURN(0); } -/* - Buffer the long data and update the flags -*/ - -static void setup_longdata_field(Item_param *item_param, uchar *pos) -{ - ulong len; - - if (!*pos++) - item_param->buffer_type=(enum_field_types)get_buffer_type(&pos); - - if (*pos == MYSQL_LONG_DATA_END) - item_param->set_long_end(); - - else - { - len = get_param_length(&pos); - item_param->set_longdata((const char *)pos, len); - } -} - -/* - Store the long data from client in pieces -*/ - -static bool setup_longdata(THD *thd, List<Item> ¶ms) -{ - NET *net=&thd->net; - List_iterator<Item> it(params); - DBUG_ENTER("setup_longdata"); - - uchar *pos=(uchar*)net->read_pos+1;// skip command type at first position - ulong param_number = get_param_length(&pos); - Item_param *item_param = thd->current_param; - - if (thd->current_param_number != param_number) - { - thd->current_param_number = param_number; - while (param_number--) /* TODO: - Change this loop by either having operator '+' - overloaded to point to desired 'item' or - add another memeber in list as 'goto' with - location count as parameter number, but what - is the best way to traverse ? - */ - { - it++; - } - thd->current_param = item_param = (Item_param *)it++; - } - setup_longdata_field(item_param,pos); - DBUG_RETURN(0); -} - - /* Validates insert fields @@ -337,16 +373,15 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields, Validate the following information for INSERT statement: - field existance - fields count - - If there is no column list spec exists, then update the field_list - with all columns from the table, and send fields info back to client */ -static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, +static bool mysql_test_insert_fields(PREP_STMT *stmt, + TABLE_LIST *table_list, List<Item> &fields, List<List_item> &values_list, thr_lock_type lock_type) { + THD *thd= stmt->thd; TABLE *table; List_iterator_fast<List_item> its(values_list); List_item *values; @@ -358,7 +393,7 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, if ((values= its++)) { uint value_count; - ulong counter=0; + ulong counter= 0; if (check_insert_fields(thd,table,fields,*values,1)) DBUG_RETURN(1); @@ -366,35 +401,20 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, value_count= values->elements; its.rewind(); - while ((values = its++)) + while ((values= its++)) { counter++; if (values->elements != value_count) { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0),counter); + MYF(0), counter); DBUG_RETURN(1); } } - if (fields.elements == 0) - { - /* No field listing, so setup all fields */ - List<Item> all_fields; - Field **ptr,*field; - for (ptr=table->field; (field= *ptr) ; ptr++) - { - all_fields.push_back(new Item_field(table->table_cache_key, - table->real_name, - field->field_name)); - } - if ((setup_fields(thd,table_list,all_fields,1,0,0) || - send_fields(thd,all_fields,1))) - DBUG_RETURN(1); - } - else if (send_fields(thd,fields,1)) - DBUG_RETURN(1); } + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) + DBUG_RETURN(1); DBUG_RETURN(0); } @@ -403,15 +423,16 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, Validate the following information UPDATE - set and where clause DELETE - where clause - And send update-set cluase column list fields info - back to client. For DELETE, just validate where cluase + And send update-set clause column list fields info + back to client. For DELETE, just validate where clause and return no fields information back to client. */ -static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, COND *conds, thr_lock_type lock_type) { + THD *thd= stmt->thd; TABLE *table; DBUG_ENTER("mysql_test_upd_fields"); @@ -426,9 +447,8 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, Currently return only column list info only, and we are not sending any info on where clause. */ - if (fields.elements && send_fields(thd,fields,1)) + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) DBUG_RETURN(1); - DBUG_RETURN(0); } @@ -437,7 +457,7 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, SELECT - column list - where clause - - orderr clause + - order clause - having clause - group by clause - if no column spec i.e. '*', then setup all fields @@ -445,13 +465,14 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, And send column list fields info back to client. */ -static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, List<Item> &fields, List<Item> &values, COND *conds, ORDER *order, ORDER *group, Item *having, thr_lock_type lock_type) { TABLE *table; bool hidden_group_fields; + THD *thd= stmt->thd; List<Item> all_fields(fields); DBUG_ENTER("mysql_test_select_fields"); @@ -482,13 +503,15 @@ static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, Currently return only column list info only, and we are not sending any info on where clause. */ - if (fields.elements && send_fields(thd,fields,1)) + if (send_prep_stmt(stmt, fields.elements) || + send_fields(thd,fields,0) || send_item_params(stmt)) DBUG_RETURN(1); DBUG_RETURN(0); } + /* - Check the access privileges + Check the access privileges */ static bool check_prepare_access(THD *thd, TABLE_LIST *tables, @@ -505,42 +528,47 @@ static bool check_prepare_access(THD *thd, TABLE_LIST *tables, Send the prepare query results back to client */ -static void send_prepare_results(THD *thd) +static bool send_prepare_results(PREP_STMT *stmt) { - DBUG_ENTER("send_prepare_results"); + THD *thd= stmt->thd; + LEX *lex= &thd->lex; enum enum_sql_command sql_command = thd->lex.sql_command; - - DBUG_PRINT("enter",("command :%d, param_count :%ld", - sql_command,thd->param_count)); + DBUG_ENTER("send_prepare_results"); + DBUG_PRINT("enter",("command: %d, param_count: %ld", + sql_command, lex->param_count)); - LEX *lex=&thd->lex; + /* Setup prepared stmt */ + stmt->param_count= lex->param_count; + stmt->free_list= thd->free_list; // Save items used in stmt + thd->free_list= 0; + SELECT_LEX *select_lex = lex->select; TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; - switch(sql_command) { + switch (sql_command) { case SQLCOM_INSERT: - if (mysql_test_insert_fields(thd,tables, lex->field_list, + if (mysql_test_insert_fields(stmt, tables, lex->field_list, lex->many_values, lex->lock_option)) goto abort; break; case SQLCOM_UPDATE: - if (mysql_test_upd_fields(thd,tables, select_lex->item_list, + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, lex->lock_option)) goto abort; break; case SQLCOM_DELETE: - if (mysql_test_upd_fields(thd,tables, select_lex->item_list, + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, lex->lock_option)) goto abort; break; case SQLCOM_SELECT: - if (mysql_test_select_fields(thd,tables, select_lex->item_list, + if (mysql_test_select_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, (ORDER*) select_lex->order_list.first, (ORDER*) select_lex->group_list.first, @@ -556,42 +584,37 @@ static void send_prepare_results(THD *thd) */ } } - send_ok(&thd->net,thd->param_count,0); - DBUG_VOID_RETURN; + DBUG_RETURN(0); abort: - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); - DBUG_VOID_RETURN; + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); + DBUG_RETURN(1); } /* Parse the prepare query */ -static void mysql_parse_prepare_query(THD *thd, char *packet, uint length) +static bool parse_prepare_query(PREP_STMT *stmt, + char *packet, uint length) { - DBUG_ENTER("mysql_parse_prepare_query"); + bool error= 1; + THD *thd= stmt->thd; + DBUG_ENTER("parse_prepare_query"); mysql_log.write(thd,COM_PREPARE,"%s",packet); mysql_init_query(thd); thd->prepare_command=true; + thd->safe_to_cache_query= 0; - if (query_cache.send_result_to_client(thd, packet, length) <= 0) - { - LEX *lex=lex_start(thd, (uchar*)packet, length); - - if (!yyparse() && !thd->fatal_error) - { - send_prepare_results(thd); - query_cache_end_of_result(&thd->net); - } - else - query_cache_abort(&thd->net); - lex_end(lex); - } - DBUG_VOID_RETURN; + LEX *lex=lex_start(thd, (uchar*) packet, length); + if (!yyparse() && !thd->fatal_error) + error= send_prepare_results(stmt); + lex_end(lex); + DBUG_RETURN(error); } + /* Parse the query and send the total number of parameters and resultset metadata information back to client (if any), @@ -606,52 +629,36 @@ static void mysql_parse_prepare_query(THD *thd, char *packet, uint length) items. */ -void mysql_com_prepare(THD *thd, char *packet, uint packet_length) +bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { MEM_ROOT thd_root = thd->mem_root; - DBUG_ENTER("mysql_com_prepare"); - - packet_length--; - - while (isspace(packet[0]) && packet_length > 0) - { - packet++; - packet_length--; - } - char *pos=packet+packet_length; - while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1]))) - { - pos--; - packet_length--; - } - /* - Have the prepare items to have a connection level scope or - till next prepare statement by doing all allocations using - connection level memory allocator 'con_root' from THD. - */ - free_root(&thd->con_root,MYF(0)); - init_sql_alloc(&thd->con_root,8192,8192); - thd->mem_root = thd->con_root; - - if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), - packet_length, - thd->db_length+2))) - DBUG_VOID_RETURN; - thd->query[packet_length]=0; - thd->packet.shrink(net_buffer_length); - thd->query_length = packet_length; + PREP_STMT stmt; + bool error; + DBUG_ENTER("mysql_stmt_prepare"); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); - - mysql_parse_prepare_query(thd,thd->query,packet_length); + bzero((char*) &stmt, sizeof(stmt)); + stmt.thd= thd; + stmt.stmt_id= ++thd->current_stmt_id; + init_sql_alloc(&stmt.mem_root, 8192, 8192); + + thd->mem_root= stmt.mem_root; + if (alloc_query(thd, packet, packet_length)) + goto err; + if (parse_prepare_query(&stmt, thd->query, thd->query_length)) + goto err; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); - thd->mem_root = thd_root; // restore main mem_root - DBUG_PRINT("exit",("prepare query ready")); - DBUG_VOID_RETURN; + stmt.mem_root= thd->mem_root; + thd->mem_root= thd_root; // restore main mem_root + DBUG_RETURN(0); + +err: + stmt.mem_root= thd->mem_root; + free_prep_stmt(&stmt, free_free, (void*) 0); + thd->mem_root = thd_root; // restore main mem_root + DBUG_RETURN(1); } @@ -663,47 +670,166 @@ void mysql_com_prepare(THD *thd, char *packet, uint packet_length) execute the query */ -void mysql_com_execute(THD *thd) +void mysql_stmt_execute(THD *thd, char *packet) { - MEM_ROOT thd_root=thd->mem_root; - DBUG_ENTER("mysql_com_execute"); - DBUG_PRINT("enter", ("parameters : %ld", thd->param_count)); + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_execute"); - thd->mem_root = thd->con_root; - if (thd->param_count && setup_param_fields(thd, thd->lex.param_list)) + if (!(stmt=find_prepared_statement(thd, stmt_id, "execute"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + /* Check if we got an error when sending long data */ + if (stmt->error_in_prepare) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + if (stmt->param_count && setup_param_fields(thd, stmt)) DBUG_VOID_RETURN; - + + MEM_ROOT thd_root= thd->mem_root; + thd->mem_root = thd->con_root; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - /* TODO: + /* + TODO: Also, have checks on basic executions such as mysql_insert(), mysql_delete(), mysql_update() and mysql_select() to not to have re-check on setup_* and other things .. */ - mysql_execute_command(); + mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),WAIT_PRIOR); + my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->mem_root = (MEM_ROOT )thd_root; - DBUG_PRINT("exit",("prepare-execute done!")); + thd->mem_root= thd_root; DBUG_VOID_RETURN; } + /* - Long data in pieces from client + Reset a prepared statement + + SYNOPSIS + mysql_stmt_reset() + thd Thread handle + packet Packet with stmt handle + + DESCRIPTION + This function is useful when one gets an error after calling + mysql_stmt_getlongdata() and one wants to reset the handle + so that one can call execute again. */ -void mysql_com_longdata(THD *thd) +void mysql_stmt_reset(THD *thd, char *packet) { - DBUG_ENTER("mysql_com_execute"); + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_reset"); - if(thd->param_count && setup_longdata(thd,thd->lex.param_list)) - DBUG_VOID_RETURN; - - send_ok(&thd->net,0,0);// ok status to client - DBUG_PRINT("exit",("longdata-buffering done!")); + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + stmt->error_in_prepare=0; + Item_param *item= stmt->param, *end= item + stmt->param_count; + + /* Free long data if used */ + if (stmt->long_data_used) + { + stmt->long_data_used= 0; + for (; item < end ; item++) + item->reset(); + } + DBUG_VOID_RETURN; +} + + +/* + Delete a prepared statement from memory +*/ + +void mysql_stmt_close(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_close"); + + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + /* Will call free_prep_stmt() */ + tree_delete(&thd->prepared_statements, (void*) stmt, NULL); + thd->last_prepared_stmt=0; DBUG_VOID_RETURN; } + +/* + Long data in pieces from client + + SYNOPSIS + mysql_stmt_get_longdata() + thd Thread handle + pos String to append + packet_length Length of string + + DESCRIPTION + Get a part of a long data. + To make the protocol efficient, we are not sending any return packages + here. + If something goes wrong, then we will send the error on 'execute' + + We assume that the client takes care of checking that all parts are sent + to the server. (No checking that we get a 'end of column' in the server) +*/ + +void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) +{ + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_get_longdata"); + + /* The following should never happen */ + if (packet_length < 9) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata"); + DBUG_VOID_RETURN; + } + + pos++; // skip command type at first position + ulong stmt_id= uint4korr(pos); + uint param_number= uint2korr(pos+4); + uint param_type= uint2korr(pos+6); + pos+=8; // Point to data + + if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata"))) + { + /* + There is a chance that the client will never see this as + it doesn't expect an answer from this call... + */ + send_error(thd); + DBUG_VOID_RETURN; + } + + if (param_number >= stmt->param_count) + { + stmt->error_in_prepare=1; + stmt->last_errno=ER_WRONG_ARGUMENTS; + sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata"); + DBUG_VOID_RETURN; + } + stmt->param[param_number].set_longdata(pos, packet_length-9); + stmt->long_data_used= 1; + DBUG_VOID_RETURN; +} diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 049690eb318..a9ab1776e19 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -97,7 +97,7 @@ end: Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); + send_ok(thd); } for (TABLE_LIST *table=table_list ; table != lock_table ; table=table->next) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 628b1775778..03b840aebf9 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -283,11 +283,11 @@ binlog purge"; break; if (errmsg) { - send_error(&thd->net, 0, errmsg); + send_error(thd, 0, errmsg); return 1; } else - send_ok(&thd->net); + send_ok(thd); return 0; } @@ -372,7 +372,7 @@ impossible position"; We need to start a packet with something other than 255 to distiquish it from error */ - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); // if we are at the start of the log if (pos == BIN_LOG_HEADER_SIZE) @@ -383,7 +383,7 @@ impossible position"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); } while (!net->error && net->vio != 0 && !thd->killed) @@ -418,7 +418,7 @@ impossible position"; goto err; } } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); } /* TODO: now that we are logging the offset, check to make sure @@ -538,7 +538,7 @@ Increase max_allowed_packet on master"; goto err; } } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); /* No need to net_flush because we will get to flush later when we hit EOF pretty quick @@ -593,7 +593,7 @@ Increase max_allowed_packet on master"; end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - send_eof(&thd->net); + send_eof(thd); thd->proc_info = "waiting to finalize termination"; pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; @@ -615,15 +615,15 @@ Increase max_allowed_packet on master"; pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); - send_error(&thd->net, my_errno, errmsg); + send_error(thd, my_errno, errmsg); DBUG_VOID_RETURN; } int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) { int slave_errno = 0; - if (!thd) thd = current_thd; - NET* net = &thd->net; + if (!thd) + thd = current_thd; int thread_mask; DBUG_ENTER("start_slave"); @@ -654,20 +654,21 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) if (slave_errno) { if (net_report) - send_error(net, slave_errno); + send_error(thd, slave_errno); DBUG_RETURN(1); } else if (net_report) - send_ok(net); + send_ok(thd); DBUG_RETURN(0); } + int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) { int slave_errno = 0; - if (!thd) thd = current_thd; - NET* net = &thd->net; + if (!thd) + thd = current_thd; if (check_access(thd, SUPER_ACL, any_db)) return 1; @@ -686,11 +687,11 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (slave_errno) { if (net_report) - send_error(net, slave_errno); + send_error(thd, slave_errno); return 1; } else if (net_report) - send_ok(net); + send_ok(thd); return 0; } @@ -779,7 +780,7 @@ int change_master(THD* thd, MASTER_INFO* mi) restart_thread_mask, 1 /*skip lock*/))) { - send_error(&thd->net,error); + send_error(thd,error); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -788,7 +789,7 @@ int change_master(THD* thd, MASTER_INFO* mi) // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) { - send_error(&thd->net, 0, "Could not initialize master info"); + send_error(thd, 0, "Could not initialize master info"); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -850,7 +851,7 @@ int change_master(THD* thd, MASTER_INFO* mi) 0 /* not only reset, but also reinit */, &errmsg)) { - net_printf(&thd->net, 0, "Failed purging old relay logs: %s",errmsg); + net_printf(thd, 0, "Failed purging old relay logs: %s",errmsg); DBUG_RETURN(1); } } @@ -864,7 +865,7 @@ int change_master(THD* thd, MASTER_INFO* mi) 0 /*no data lock*/, &msg)) { - net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg); + net_printf(thd,0,"Failed initializing relay log position: %s",msg); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -890,9 +891,9 @@ int change_master(THD* thd, MASTER_INFO* mi) unlock_slave_threads(mi); thd->proc_info = 0; if (error) - send_error(&thd->net,error); + send_error(thd,error); else - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } @@ -1010,12 +1011,12 @@ err: if (errmsg) { - net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND, + net_printf(thd, ER_ERROR_WHEN_EXECUTING_COMMAND, "SHOW BINLOG EVENTS", errmsg); DBUG_RETURN(1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -1045,7 +1046,7 @@ int show_binlog_info(THD* thd) if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -1098,11 +1099,11 @@ int show_binlogs(THD* thd) goto err; } mysql_bin_log.unlock_index(); - send_eof(net); + send_eof(thd); return 0; err_with_msg: - send_error(net, 0, errmsg); + send_error(thd, ER_UNKNOWN_ERROR, errmsg); err: mysql_bin_log.unlock_index(); return 1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8a64fbf968c..2b737ab65d7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -164,13 +164,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; cursor; cursor=cursor->next) - { - if (cursor->do_redirect) // False if CUBE/ROLLUP - { - cursor->do_redirect=false; - cursor->table= ((TABLE_LIST*) cursor->table)->table; - } - } + cursor->table= ((TABLE_LIST*) cursor->table)->table; } } @@ -226,7 +220,7 @@ int JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, ORDER *order_init, ORDER *group_init, Item *having_init, - ORDER *proc_param_init, SELECT_LEX *select_lex, + ORDER *proc_param_init, SELECT_LEX *select, SELECT_LEX_UNIT *unit) { DBUG_ENTER("JOIN::prepare"); @@ -237,7 +231,8 @@ JOIN::prepare(TABLE_LIST *tables_init, having= having_init; proc_param= proc_param_init; tables_list= tables_init; - select->join= this; + select_lex= select; + select_lex->join= this; union_part= (unit->first_select()->next_select() != 0); /* Check that all tables, fields, conds and order are ok */ @@ -679,16 +674,16 @@ JOIN::exec() result->send_fields(fields_list,1); if (!having || having->val_int()) { - if (do_send_rows && result->send_data(fields_list)) - { - result->send_error(0,NullS); /* purecov: inspected */ - error=1; - } - else - error=(int) result->send_eof(); + if (do_send_rows && result->send_data(fields_list)) + { + result->send_error(0,NullS); /* purecov: inspected */ + error=1; + } + else + error=(int) result->send_eof(); } else - error=(int) result->send_eof(); + error=(int) result->send_eof(); } delete procedure; DBUG_VOID_RETURN; @@ -696,6 +691,7 @@ JOIN::exec() if (zero_result_cause) { + error=0; (void) return_zero_rows(this, result, tables_list, fields_list, tmp_table_param.sum_func_count != 0 && !group_list, @@ -739,7 +735,7 @@ JOIN::exec() thd->proc_info="Creating tmp table"; tmp_table_param.hidden_field_count= (all_fields.elements- - fields.elements); + fields_list.elements); if (!(exec_tmp_table = create_tmp_table(thd, &tmp_table_param, all_fields, ((!simple_group && !procedure && @@ -996,6 +992,8 @@ JOIN::exec() int JOIN::cleanup(THD *thd) { + DBUG_ENTER("JOIN::cleanup"); + lock=0; // It's faster to unlock later join_free(this); if (exec_tmp_table) @@ -1006,6 +1004,7 @@ JOIN::cleanup(THD *thd) for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); unit != 0; unit= unit->next_unit()) + { for (SELECT_LEX *sl= unit->first_select(); sl != 0; sl= sl->next_select()) @@ -1018,7 +1017,8 @@ JOIN::cleanup(THD *thd) sl->join= 0; } } - return error; + } + DBUG_RETURN(error); } int @@ -1044,7 +1044,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, goto err; } - if(join->global_optimize()) + if (join->global_optimize()) goto err; join->exec(); @@ -7276,7 +7276,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, { KEY *key_info=table->key_info+ tab->ref.key; item_list.push_back(new Item_string(key_info->name, - strlen(key_info->name))); + strlen(key_info->name), + system_charset_info)); item_list.push_back(new Item_int((int32) tab->ref.key_length)); for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) { @@ -7416,5 +7417,5 @@ static void describe_info(JOIN *join, const char *info) packet->length(0); net_store_data(packet,info); if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) - send_eof(&thd->net); + send_eof(thd); } diff --git a/sql/sql_select.h b/sql/sql_select.h index f651f069c13..89dee2a4019 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -149,7 +149,8 @@ class TMP_TABLE_PARAM { } }; -class JOIN :public Sql_alloc{ +class JOIN :public Sql_alloc +{ public: JOIN_TAB *join_tab,**best_ref,**map2table; TABLE **table,**all_tables,*sort_by_table; @@ -222,6 +223,7 @@ class JOIN :public Sql_alloc{ !test(select_options & OPTION_FOUND_ROWS)), all_fields(fields), fields_list(fields), + error(0), select(0), exec_tmp_table(0), test_function_query(0), diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5899fe86024..fb9db707c16 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -76,6 +76,8 @@ mysqld_show_dbs(THD *thd,const char *wild) if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1)) DBUG_RETURN(1); List_iterator_fast<char> it(files); + + String *packet= &thd->packet; while ((file_name=it++)) { if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || @@ -83,19 +85,20 @@ mysqld_show_dbs(THD *thd,const char *wild) thd->priv_user, file_name) || (grant_option && !check_grant_db(thd, file_name))) { - thd->packet.length(0); - net_store_data(&thd->packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - thd->packet.length())) + packet->length(0); + net_store_data(packet, thd->variables.convert_set, file_name); + if (my_net_write(&thd->net, (char*) packet->ptr(), + packet->length())) DBUG_RETURN(-1); } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + /*************************************************************************** -** List all open tables in a database + List all open tables in a database ***************************************************************************/ int mysqld_show_open_tables(THD *thd,const char *wild) @@ -116,19 +119,20 @@ int mysqld_show_open_tables(THD *thd,const char *wild) if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error) DBUG_RETURN(-1); + String *packet= &thd->packet; for (; open_list ; open_list=open_list->next) { - thd->packet.length(0); - net_store_data(&thd->packet,convert, open_list->db); - net_store_data(&thd->packet,convert, open_list->table); - net_store_data(&thd->packet,open_list->in_use); - net_store_data(&thd->packet,open_list->locked); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet,convert, open_list->db); + net_store_data(packet,convert, open_list->table); + net_store_data(packet,open_list->in_use); + net_store_data(packet,open_list->locked); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) { DBUG_RETURN(-1); } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -160,14 +164,15 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); List_iterator_fast<char> it(files); + String *packet= &thd->packet; while ((file_name=it++)) { - thd->packet.length(0); - net_store_data(&thd->packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet, thd->variables.convert_set, file_name); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -175,15 +180,33 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) ** List all table types supported ***************************************************************************/ -static struct show_table_type_st sys_table_types[]= { - {"MyISAM", (char *)"YES", "Default type from 3.23 with great performance"}, - {"HEAP" , (char *)"YES", "Hash based, stored in memory, useful for temporary tables"}, - {"MERGE", (char *)"YES", "Collection of identical MyISAM tables"}, - {"ISAM", (char*) &have_isam,"Obsolete table type"}, - {"InnoDB", (char*) &have_innodb,"Supports transactions, row-level locking and foreign keys"}, - {"BDB", (char*) &have_berkeley_db, "Supports transactions and page-level locking"}, +struct show_table_type_st { + const char *type; + SHOW_COMP_OPTION *value; + const char *comment; +}; + + +SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; + +static struct show_table_type_st sys_table_types[]= +{ + {"MyISAM", &have_yes, + "Default type from 3.23 with great performance"}, + {"HEAP" , &have_yes, + "Hash based, stored in memory, useful for temporary tables"}, + {"MERGE", &have_yes, + "Collection of identical MyISAM tables"}, + {"ISAM", &have_isam, + "Obsolete table type; Is replaced by MyISAM"}, + {"InnoDB", &have_innodb, + "Supports transactions, row-level locking and foreign keys"}, + {"BDB", &have_berkeley_db, + "Supports transactions and page-level locking"}, + {NullS, NULL, NullS} }; + int mysqld_show_table_types(THD *thd) { List<Item> field_list; @@ -191,76 +214,68 @@ int mysqld_show_table_types(THD *thd) field_list.push_back(new Item_empty_string("Type",10)); field_list.push_back(new Item_empty_string("Support",10)); - field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); + field_list.push_back(new Item_empty_string("Comment",80)); if (send_fields(thd,field_list,1)) DBUG_RETURN(1); - const char *default_type_name=ha_table_typelib.type_names[default_table_type-1]; - show_table_type_st *types = sys_table_types; - - uint i; - for (i = 0; i < 3; i++) - { - thd->packet.length(0); - net_store_data(&thd->packet,types[i].type); - if (!strcasecmp(default_type_name,types[i].type)) - net_store_data(&thd->packet,"DEFAULT"); - else - net_store_data(&thd->packet,types[i].value); - net_store_data(&thd->packet,types[i].comment); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) - DBUG_RETURN(-1); - } + const char *default_type_name= ha_table_typelib.type_names[thd->variables.table_type]; - for (; i < sizeof(sys_table_types)/sizeof(sys_table_types[0]); i++) + show_table_type_st *types; + String *packet= &thd->packet; + for (types= sys_table_types; types->type; types++) { - thd->packet.length(0); - net_store_data(&thd->packet,types[i].type); - SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) types[i].value; - - if (tmp == SHOW_OPTION_NO) - net_store_data(&thd->packet,"NO"); - else - { - if (tmp == SHOW_OPTION_YES) - { - if (!strcasecmp(default_type_name,types[i].type)) - net_store_data(&thd->packet,"DEFAULT"); - else - net_store_data(&thd->packet,"YES"); - } - else net_store_data(&thd->packet,"DISABLED"); - } - net_store_data(&thd->packet,types[i].comment); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet, types->type); + const char *option_name= show_comp_option_name[(int) *types->value]; + + if (*types->value == SHOW_OPTION_YES && + !strcasecmp(default_type_name, types->type)) + option_name= "DEFAULT"; + net_store_data(packet, option_name); + net_store_data(packet, types->comment); + if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + /*************************************************************************** -** List all privileges supported + List all privileges supported ***************************************************************************/ -static struct show_table_type_st sys_privileges[]= { - {"Select", (char *)"Tables", "To retrieve rows from table"}, - {"Insert", (char *)"Tables", "To insert data into tables"}, - {"Update", (char *)"Tables", "To update existing rows "}, - {"Delete", (char *)"Tables", "To delete existing rows"}, - {"Index", (char *)"Tables", "To create or drop indexes"}, - {"Alter", (char *)"Tables", "To alter the table"}, - {"Create", (char *)"Databases,Tables,Indexes", "To create new databases and tables"}, - {"Drop", (char *)"Databases,Tables", "To drop databases and tables"}, - {"Grant", (char *)"Databases,Tables", "To give to other users those privileges you possesed"}, - {"References", (char *)"Databases,Tables", "To have references on tables"}, - {"Reload", (char *)"Server Admin", "To reload or refresh tables, logs and privileges"}, - {"Shutdown",(char *)"Server Admin", "To shutdown the server"}, - {"Process", (char *)"Server Admin", "To view the plain text of currently executing queries"}, - {"File", (char *)"File access on server", "To read and write files on the server"}, +struct show_privileges_st { + const char *privilege; + const char *context; + const char *comment; }; + +/* + TODO: Update with new privileges +*/ +static struct show_privileges_st sys_privileges[]= +{ + {"Select", "Tables", "To retrieve rows from table"}, + {"Insert", "Tables", "To insert data into tables"}, + {"Update", "Tables", "To update existing rows "}, + {"Delete", "Tables", "To delete existing rows"}, + {"Index", "Tables", "To create or drop indexes"}, + {"Alter", "Tables", "To alter the table"}, + {"Create", "Databases,Tables,Indexes", "To create new databases and tables"}, + {"Drop", "Databases,Tables", "To drop databases and tables"}, + {"Grant", "Databases,Tables", "To give to other users those privileges you possess"}, + {"References", "Databases,Tables", "To have references on tables"}, + {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"}, + {"Shutdown","Server Admin", "To shutdown the server"}, + {"Process", "Server Admin", "To view the plain text of currently executing queries"}, + {"File", "File access on server", "To read and write files on the server"}, + {NullS, NullS, NullS} +}; + + int mysqld_show_privileges(THD *thd) { List<Item> field_list; @@ -273,43 +288,48 @@ int mysqld_show_privileges(THD *thd) if (send_fields(thd,field_list,1)) DBUG_RETURN(1); - for (uint i=0; i < sizeof(sys_privileges)/sizeof(sys_privileges[0]); i++) + show_privileges_st *privilege= sys_privileges; + String *packet= &thd->packet; + for (privilege= sys_privileges; privilege->privilege ; privilege++) { - thd->packet.length(0); - net_store_data(&thd->packet,sys_privileges[i].type); - net_store_data(&thd->packet,sys_privileges[i].value); - net_store_data(&thd->packet,sys_privileges[i].comment); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet,privilege->privilege); + net_store_data(packet,privilege->context); + net_store_data(packet,privilege->comment); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } /*************************************************************************** -** List all column types + List all column types ***************************************************************************/ -#if 0 -struct show_column_type_st { +struct show_column_type_st +{ const char *type; uint size; - char *min_value; - char *max_value; - uint precision, - uint scale, - char *nullable; - char *auto_increment; - char *unsigned_attr; - char *zerofill; - char *searchable; - char *case_sensitivity; - char *default_value; - char *comment; + const char *min_value; + const char *max_value; + uint precision; + uint scale; + const char *nullable; + const char *auto_increment; + const char *unsigned_attr; + const char *zerofill; + const char *searchable; + const char *case_sensitivity; + const char *default_value; + const char *comment; }; -#endif -static struct show_column_type_st sys_column_types[]= { + +/* TODO: Add remaning types */ + +static struct show_column_type_st sys_column_types[]= +{ {"tinyint", 1, "-128", "127", 0, 0, "YES", "YES", "NO", "YES", "YES", "NO", "NULL,0", @@ -343,30 +363,33 @@ int mysqld_show_column_types(THD *thd) if (send_fields(thd,field_list,1)) DBUG_RETURN(1); + /* TODO: Change the loop to not use 'i' */ + String *packet= &thd->packet; for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) { - thd->packet.length(0); - net_store_data(&thd->packet,sys_column_types[i].type); - net_store_data(&thd->packet,(longlong)sys_column_types[i].size); - net_store_data(&thd->packet,sys_column_types[i].min_value); - net_store_data(&thd->packet,sys_column_types[i].max_value); - net_store_data(&thd->packet,(uint32)sys_column_types[i].precision); - net_store_data(&thd->packet,(uint32)sys_column_types[i].scale); - net_store_data(&thd->packet,sys_column_types[i].nullable); - net_store_data(&thd->packet,sys_column_types[i].auto_increment); - net_store_data(&thd->packet,sys_column_types[i].unsigned_attr); - net_store_data(&thd->packet,sys_column_types[i].zerofill); - net_store_data(&thd->packet,sys_column_types[i].searchable); - net_store_data(&thd->packet,sys_column_types[i].case_sensitivity); - net_store_data(&thd->packet,sys_column_types[i].default_value); - net_store_data(&thd->packet,sys_column_types[i].comment); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet,sys_column_types[i].type); + net_store_data(packet,(longlong)sys_column_types[i].size); + net_store_data(packet,sys_column_types[i].min_value); + net_store_data(packet,sys_column_types[i].max_value); + net_store_data(packet,(uint32)sys_column_types[i].precision); + net_store_data(packet,(uint32)sys_column_types[i].scale); + net_store_data(packet,sys_column_types[i].nullable); + net_store_data(packet,sys_column_types[i].auto_increment); + net_store_data(packet,sys_column_types[i].unsigned_attr); + net_store_data(packet,sys_column_types[i].zerofill); + net_store_data(packet,sys_column_types[i].searchable); + net_store_data(packet,sys_column_types[i].case_sensitivity); + net_store_data(packet,sys_column_types[i].default_value); + net_store_data(packet,sys_column_types[i].comment); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + static int mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, const char *wild, bool dir) @@ -441,8 +464,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, DBUG_RETURN(0); } + /*************************************************************************** -** Extended version of mysqld_show_tables + Extended version of mysqld_show_tables ***************************************************************************/ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) @@ -459,7 +483,6 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) (void) sprintf(path,"%s/%s",mysql_data_home,db); (void) unpack_dirname(path,path); -//,default_charset_info field_list.push_back(item=new Item_empty_string("Name",NAME_LEN)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Type",10)); @@ -612,14 +635,13 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } - /*************************************************************************** -** List all columns in a table + List all columns in a table ***************************************************************************/ int @@ -637,7 +659,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } file=table->file; @@ -742,10 +764,11 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, } } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + int mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -758,7 +781,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Only one table for now */ if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } @@ -809,7 +832,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) DBUG_RETURN(1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -832,7 +855,7 @@ mysqld_show_logs(THD *thd) DBUG_RETURN(-1); #endif - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -849,7 +872,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } @@ -933,14 +956,14 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(1); /* purecov: inspected */ } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } /**************************************************************************** -** Return only fields for API mysql_list_fields -** Use "show table wildcard" in mysql instead of this + Return only fields for API mysql_list_fields + Use "show table wildcard" in mysql instead of this ****************************************************************************/ void @@ -952,7 +975,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_VOID_RETURN; } List<Item> field_list; @@ -971,6 +994,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) DBUG_VOID_RETURN; } + int mysqld_dump_create_info(THD *thd, TABLE *table, int fd) { @@ -978,7 +1002,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) DBUG_ENTER("mysqld_dump_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); - String* packet = &thd->packet; + String *packet = &thd->packet; packet->length(0); if (store_create_info(thd,table,packet)) DBUG_RETURN(-1); @@ -1000,6 +1024,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) DBUG_RETURN(0); } + static void append_identifier(THD *thd, String *packet, const char *name) { @@ -1015,6 +1040,7 @@ append_identifier(THD *thd, String *packet, const char *name) } } + static int store_create_info(THD *thd, TABLE *table, String *packet) { @@ -1215,8 +1241,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) /**************************************************************************** -** Return info about all processes -** returns for each thread: thread id, user, host, db, command, info + Return info about all processes + returns for each thread: thread id, user, host, db, command, info ****************************************************************************/ class thread_info :public ilink { @@ -1357,7 +1383,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) break; /* purecov: inspected */ } - send_eof(&thd->net); + send_eof(thd); DBUG_VOID_RETURN; } @@ -1372,7 +1398,7 @@ int mysqld_show_charsets(THD *thd, const char *wild) char buff[8192]; String packet2(buff,sizeof(buff),default_charset_info); List<Item> field_list; - CONVERT *convert=thd->convert_set; + CONVERT *convert=thd->variables.convert_set; CHARSET_INFO *cs; DBUG_ENTER("mysqld_show_charsets"); @@ -1401,7 +1427,7 @@ int mysqld_show_charsets(THD *thd, const char *wild) goto err; } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); err: DBUG_RETURN(1); @@ -1428,7 +1454,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, for (; variables->name; variables++) { if (!(wild && wild[0] && wild_case_compare(system_charset_info, - variables[i].name,wild))) + variables->name,wild))) { packet2.length(0); net_store_data(&packet2,convert,variables->name); @@ -1461,9 +1487,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_HAVE: { SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value; - net_store_data(&packet2, (tmp == SHOW_OPTION_NO ? "NO" : - tmp == SHOW_OPTION_YES ? "YES" : - "DISABLED")); + net_store_data(&packet2, show_comp_option_name[(int) tmp]); break; } case SHOW_CHAR: @@ -1663,7 +1687,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, } pthread_mutex_unlock(&LOCK_status); /* pthread_mutex_unlock(&THR_LOCK_keycache); */ - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); err: diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6b24999763b..fb0815a1a26 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -82,7 +82,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) if (error) DBUG_RETURN(-1); - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } @@ -305,8 +305,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_RETURN(-1); } - - for(field_no=0; (sql_field=it++) ; field_no++) + for (field_no=0; (sql_field=it++) ; field_no++) { /* Don't pack keys in old tables if the user has requested this */ if ((sql_field->flags & BLOB_FLAG) || @@ -317,28 +316,35 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields++; - for(dup_no=0; (dup_field=it2++) != sql_field; dup_no++) + + /* Check if we have used the same field name before */ + for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) { if (my_strcasecmp(system_charset_info, sql_field->field_name, dup_field->field_name) == 0) { - if (field_no<select_field_pos || dup_no>=select_field_pos) + /* + If this was a CREATE ... SELECT statement, accept a field + redefinition if we are changing a field in the SELECT part + */ + if (field_no < select_field_pos || dup_no >= select_field_pos) { my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name); DBUG_RETURN(-1); } else { - sql_field->length=dup_field->length; - sql_field->decimals=dup_field->decimals; - sql_field->flags=dup_field->flags; - sql_field->pack_length=dup_field->pack_length; - sql_field->unireg_check=dup_field->unireg_check; - sql_field->sql_type=dup_field->sql_type; - it2.remove(); - select_field_pos--; - break; + /* Field redefined */ + sql_field->length= dup_field->length; + sql_field->decimals= dup_field->decimals; + sql_field->flags= dup_field->flags; + sql_field->pack_length= dup_field->pack_length; + sql_field->unireg_check= dup_field->unireg_check; + sql_field->sql_type= dup_field->sql_type; + it2.remove(); // Remove first (create) definition + select_field_pos--; + break; } } } @@ -749,7 +755,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, create_info->create_statement = thd->query; create_info->table_options=db_options; - if (rea_create_table(path, create_info, fields, key_count, + if (rea_create_table(thd, path, create_info, fields, key_count, key_info_buffer)) { /* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */ @@ -825,7 +831,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, TABLE tmp_table; // Used during 'create_field()' TABLE *table; tmp_table.table_name=0; - uint select_field_count=0; + uint select_field_count= items->elements; DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ @@ -859,7 +865,6 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, (Field*) 0)))) DBUG_RETURN(0); extra_fields->push_back(cr_field); - select_field_count++; } /* create and lock table */ /* QQ: This should be done atomic ! */ @@ -1271,7 +1276,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, goto err; } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); err: close_thread_tables(thd); // Shouldn't be needed @@ -1476,7 +1481,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); + send_ok(thd); } DBUG_RETURN(error); } @@ -1994,7 +1999,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, end_temporary: sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted), (ulong) deleted, thd->cuted_fields); - send_ok(&thd->net,copied+deleted,0L,tmp_name); + send_ok(thd,copied+deleted,0L,tmp_name); thd->some_tables_deleted=0; DBUG_RETURN(0); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 225c0ea26a4..893f0838a7f 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -342,7 +342,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!initialized) { - send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); + send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); DBUG_RETURN(1); } @@ -353,19 +353,19 @@ int mysql_create_function(THD *thd,udf_func *udf) */ if (strchr(udf->dl, '/')) { - send_error(&thd->net, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS)); + send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS)); DBUG_RETURN(1); } if (udf->name_length > NAME_LEN) { - net_printf(&thd->net, ER_TOO_LONG_IDENT,udf->name); + net_printf(thd, ER_TOO_LONG_IDENT,udf->name); DBUG_RETURN(1); } pthread_mutex_lock(&THR_LOCK_udf); if (hash_search(&udf_hash,(byte*) udf->name, udf->name_length)) { - net_printf(&thd->net, ER_UDF_EXISTS, udf->name); + net_printf(thd, ER_UDF_EXISTS, udf->name); goto err; } if (!(dl = find_udf_dl(udf->dl))) @@ -374,7 +374,7 @@ int mysql_create_function(THD *thd,udf_func *udf) { DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)", udf->dl,errno,dlerror())); - net_printf(&thd->net, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror()); + net_printf(thd, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror()); goto err; } new_dl=1; @@ -384,7 +384,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (udf->func == NULL) { - net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, udf->name); + net_printf(thd, ER_CANT_FIND_DL_ENTRY, udf->name); goto err; } udf->name=strdup_root(&mem,udf->name); @@ -392,7 +392,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!udf->name || !udf->dl || !(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type))) { - send_error(&thd->net,0); // End of memory + send_error(thd,0); // End of memory goto err; } u_d->dlhandle = dl; @@ -422,7 +422,7 @@ int mysql_create_function(THD *thd,udf_func *udf) close_thread_tables(thd); if (error) { - net_printf(&thd->net, ER_ERROR_ON_WRITE, "func@mysql",error); + net_printf(thd, ER_ERROR_ON_WRITE, "func@mysql",error); del_udf(u_d); goto err; } @@ -445,13 +445,13 @@ int mysql_drop_function(THD *thd,const char *udf_name) DBUG_ENTER("mysql_drop_function"); if (!initialized) { - send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); + send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); DBUG_RETURN(1); } pthread_mutex_lock(&THR_LOCK_udf); if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name, (uint) strlen(udf_name)))) { - net_printf(&thd->net, ER_FUNCTION_NOT_DEFINED, udf_name); + net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name); goto err; } del_udf(udf); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 51f278536de..8244384cc94 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -242,7 +242,7 @@ bool select_union::flush() if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { table->file->print_error(error,MYF(0)); - ::send_error(&thd->net); + ::send_error(thd); return 1; } return 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f0ca5ad6c7b..ccd4439a9d2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -127,7 +127,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(-1); // Error in where } - send_ok(&thd->net); // No matching records + send_ok(thd); // No matching records DBUG_RETURN(0); } /* If running in safe sql mode, don't allow updates without keys */ @@ -138,7 +138,7 @@ int mysql_update(THD *thd, { delete select; table->time_stamp=save_time_stamp; - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } } @@ -329,13 +329,13 @@ int mysql_update(THD *thd, delete select; if (error >= 0) - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */ + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */ else { char buff[80]; sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, (long) thd->cuted_fields); - send_ok(&thd->net, + send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); DBUG_PRINT("info",("%d records updated",updated)); @@ -439,7 +439,7 @@ multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u) } if (!table_ref) { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES"); + net_printf(thd, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES"); DBUG_RETURN(1); } else @@ -447,7 +447,7 @@ multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u) } if (!num_updated) { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE"); + net_printf(thd, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE"); DBUG_RETURN(1); } @@ -662,7 +662,7 @@ bool multi_update::send_data(List<Item> &values) void multi_update::send_error(uint errcode,const char *err) { /* First send error what ever it is ... */ - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); /* reset used flags */ // update_tables->table->no_keyread=0; @@ -821,7 +821,7 @@ bool multi_update::send_eof() { query_cache_invalidate3(thd, update_tables, 1); } - ::send_ok(&thd->net, + ::send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8571cb9af6d..d9662f25c1b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -26,6 +26,7 @@ #include "slave.h" #include "sql_acl.h" #include "lex_symbol.h" +#include "item_create.h" #include <myisam.h> #include <myisammrg.h> @@ -356,9 +357,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token COMPRESSED_SYM %token ERRORS -%token SQL_ERROR_COUNT %token WARNINGS -%token SQL_WARNING_COUNT %token BIGINT %token BLOB_SYM @@ -642,7 +641,7 @@ query: if (!thd->bootstrap && (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT))) { - send_error(¤t_thd->net,ER_EMPTY_QUERY); + send_error(current_thd,ER_EMPTY_QUERY); YYABORT; } else @@ -1128,7 +1127,7 @@ charset: { if (!(Lex->charset=get_charset_by_name($1.str,MYF(0)))) { - net_printf(¤t_thd->net,ER_UNKNOWN_CHARACTER_SET,$1.str); + net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str); YYABORT; } }; @@ -1690,7 +1689,7 @@ expr_expr: { if (!(Lex->charset=get_charset_by_name($3.str,MYF(0)))) { - net_printf(¤t_thd->net,ER_UNKNOWN_CHARACTER_SET,$3.str); + net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$3.str); YYABORT; } $$= new Item_func_set_collation($1,Lex->charset); @@ -1921,9 +1920,8 @@ simple_expr: { $$= new Item_func_interval($3,* $5); } | LAST_INSERT_ID '(' ')' { - $$= new Item_int((char*) "last_insert_id()", - current_thd->insert_id(),21); - current_thd->safe_to_cache_query=0; + $$= get_system_var(OPT_SESSION, "last_insert_id", 14, + "last_insert_id()"); } | LAST_INSERT_ID '(' expr ')' { @@ -2409,7 +2407,7 @@ olap_opt: LEX *lex=Lex; lex->olap = true; lex->select->olap= CUBE_TYPE; - net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "CUBE"); + net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE"); YYABORT; /* To be deleted in 4.1 */ } | WITH ROLLUP_SYM @@ -2417,7 +2415,7 @@ olap_opt: LEX *lex=Lex; lex->olap = true; lex->select->olap= ROLLUP_TYPE; - net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "ROLLUP"); + net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP"); YYABORT; /* To be deleted in 4.1 */ } ; @@ -2436,12 +2434,12 @@ order_clause: LEX *lex=Lex; if (lex->sql_command == SQLCOM_MULTI_UPDATE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, "UPDATE", "ORDER BY"); + net_printf(lex->thd, ER_WRONG_USAGE, "UPDATE", "ORDER BY"); YYABORT; } if (lex->select->olap != UNSPECIFIED_OLAP_TYPE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, + net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "ORDER BY"); YYABORT; @@ -2467,7 +2465,7 @@ limit_clause: LEX *lex=Lex; if (lex->select->olap != UNSPECIFIED_OLAP_TYPE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, "CUBE/ROLLUP", + net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "LIMIT"); YYABORT; } @@ -2480,7 +2478,7 @@ limit_clause: LEX *lex=Lex; if (lex->select->olap != UNSPECIFIED_OLAP_TYPE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, "CUBE/ROLLUP", + net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "LIMIT"); YYABORT; } @@ -2495,7 +2493,7 @@ delete_limit_clause: LEX *lex=Lex; if (lex->sql_command == SQLCOM_MULTI_UPDATE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, "DELETE", "LIMIT"); + net_printf(lex->thd, ER_WRONG_USAGE, "DELETE", "LIMIT"); YYABORT; } lex->select->select_limit= HA_POS_ERROR; @@ -2935,9 +2933,9 @@ show_param: lex->sql_command= SQLCOM_SHOW_PRIVILEGES; } | COUNT_SYM '(' '*' ')' WARNINGS - { Lex->sql_command = SQLCOM_SHOW_WARNS_COUNT;} + { (void) create_select_for_variable("warning_count"); } | COUNT_SYM '(' '*' ')' ERRORS - { Lex->sql_command = SQLCOM_SHOW_ERRORS_COUNT;} + { (void) create_select_for_variable("error_count"); } | WARNINGS {Select->offset_limit=0L;} limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} | ERRORS {Select->offset_limit=0L;} limit_clause @@ -3103,7 +3101,7 @@ kill: LEX *lex=Lex; if ($2->fix_fields(lex->thd, 0, &$2)) { - send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY); + send_error(lex->thd, ER_SET_CONSTANTS_ONLY); YYABORT; } lex->sql_command=SQLCOM_KILL; @@ -3218,10 +3216,11 @@ text_string: param_marker: '?' { - if(current_thd->prepare_command) + LEX *lex=Lex; + if (current_thd->prepare_command) { - Lex->param_list.push_back($$=new Item_param()); - current_thd->param_count++; + lex->param_list.push_back($$=new Item_param()); + lex->param_count++; } else { @@ -3602,8 +3601,8 @@ text_or_password: set_expr_or_default: expr { $$=$1; } | DEFAULT { $$=0; } - | ON { $$=new Item_string("ON",2); } - | ALL { $$=new Item_string("ALL",3); } + | ON { $$=new Item_string("ON", 2, system_charset_info); } + | ALL { $$=new Item_string("ALL", 3, system_charset_info); } ; @@ -3769,7 +3768,7 @@ require_list_element: SUBJECT_SYM TEXT_STRING LEX *lex=Lex; if (lex->x509_subject) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "SUBJECT"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "SUBJECT"); YYABORT; } lex->x509_subject=$2.str; @@ -3779,7 +3778,7 @@ require_list_element: SUBJECT_SYM TEXT_STRING LEX *lex=Lex; if (lex->x509_issuer) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "ISSUER"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "ISSUER"); YYABORT; } lex->x509_issuer=$2.str; @@ -3789,7 +3788,7 @@ require_list_element: SUBJECT_SYM TEXT_STRING LEX *lex=Lex; if (lex->ssl_cipher) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "CIPHER"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "CIPHER"); YYABORT; } lex->ssl_cipher=$2.str; @@ -3805,7 +3804,7 @@ opt_table: lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } @@ -3817,7 +3816,7 @@ opt_table: lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } @@ -3829,7 +3828,7 @@ opt_table: lex->grant= GLOBAL_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } @@ -3977,15 +3976,15 @@ union_list: if (lex->exchange) { /* Only the last SELECT can have INTO...... */ - net_printf(&lex->thd->net, ER_WRONG_USAGE, "UNION", "INTO"); + net_printf(lex->thd, ER_WRONG_USAGE, "UNION", "INTO"); YYABORT; } if (lex->select->linkage == GLOBAL_OPTIONS_TYPE) { - send_error(&lex->thd->net, ER_SYNTAX_ERROR); + send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } - if (mysql_new_select(lex)) + if (mysql_new_select(lex, 0)) YYABORT; lex->select->linkage=UNION_TYPE; } @@ -4003,7 +4002,7 @@ optional_order_or_limit: LEX *lex=Lex; if (!lex->select->braces) { - send_error(&lex->thd->net, ER_SYNTAX_ERROR); + send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } lex->select->master_unit()->global_parameters= @@ -4013,7 +4012,7 @@ optional_order_or_limit: SELECT_LEX fields always check linkage type. */ lex->select= (SELECT_LEX*)lex->select->master_unit(); - lex->select->select_limit=lex->thd->default_select_limit; + lex->select->select_limit=lex->thd->variables.select_limit; } opt_order_clause limit_clause ; diff --git a/sql/structs.h b/sql/structs.h index c2ad4ef527e..7873de4db63 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -148,36 +148,18 @@ enum SHOW_TYPE }; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; + +extern const char *show_comp_option_name[]; + typedef int *(*update_var)(THD *, struct show_var_st *); + typedef struct show_var_st { const char *name; char *value; SHOW_TYPE type; } SHOW_VAR; -struct show_table_type_st { - const char *type; - char *value; - const char *comment; -}; - -struct show_column_type_st { - const char *type; - uint size; - const char *min_value; - const char *max_value; - uint precision; - uint scale; - const char *nullable; - const char *auto_increment; - const char *unsigned_attr; - const char *zerofill; - const char *searchable; - const char *case_sensitivity; - const char *default_value; - const char *comment; -}; typedef struct lex_string { char *str; diff --git a/sql/table.cc b/sql/table.cc index 3e41da73109..2cdd62001f1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -493,7 +493,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (field->key_length() == key_part->length && field->type() != FIELD_TYPE_BLOB) { - if ((index_flags & HA_HAVE_KEY_READ_ONLY) && + if ((index_flags & HA_KEY_READ_ONLY) && (field->key_type() != HA_KEYTYPE_TEXT || (!(ha_option & HA_KEY_READ_WRONG_STR) && !(keyinfo->flags & HA_FULLTEXT)))) @@ -1141,7 +1141,7 @@ bool check_db_name(const char *name) return 1; name++; } - return (uint) (name - start) > NAME_LEN; + return (uint) (name - start) > NAME_LEN || name == start; } diff --git a/sql/uniques.cc b/sql/uniques.cc index 60905567ba0..ed256a4b791 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, :max_in_memory_size(max_in_memory_size_arg),elements(0) { my_b_clear(&file); - init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg); + init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, + comp_func_fixed_arg); /* If the following fail's the next add will also fail */ my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); diff --git a/sql/unireg.cc b/sql/unireg.cc index 8db9b871a39..344583b56f1 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -46,7 +46,7 @@ static bool make_empty_rec(int file, enum db_type table_type, uint reclength,uint null_fields); -int rea_create_table(my_string file_name, +int rea_create_table(THD *thd, my_string file_name, HA_CREATE_INFO *create_info, List<create_field> &create_fields, uint keys, KEY *key_info) @@ -67,13 +67,12 @@ int rea_create_table(my_string file_name, if (pack_header(forminfo, create_info->db_type,create_fields,info_length, screens, create_info->table_options, db_file)) { - NET *net=my_pthread_getspecific_ptr(NET*,THR_NET); my_free((gptr) screen_buff,MYF(0)); - if (net->last_errno != ER_TOO_MANY_FIELDS) + if (thd->net.last_errno != ER_TOO_MANY_FIELDS) DBUG_RETURN(1); // Try again without UNIREG screens (to get more columns) - net->last_error[0]=0; + thd->net.last_error[0]=0; if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1))) DBUG_RETURN(1); if (pack_header(forminfo, create_info->db_type, create_fields,info_length, diff --git a/sql/unireg.h b/sql/unireg.h index 2cfa709bbdc..fd1117a4708 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -63,6 +63,8 @@ #define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD) #define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD) +#define DEFAULT_ERROR_COUNT 64 +#define DEFAULT_PREP_STMT_COUNT 64 #define EXTRA_RECORDS 10 /* Extra records in sort */ #define SCROLL_EXTRA 5 /* Extra scroll-rows. */ #define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */ diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 19989afea60..f6c92edf1b8 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2002 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,22 +23,24 @@ int my_strnxfrm_simple(CHARSET_INFO * cs, char *dest, uint len, const char *src, uint srclen) { + uchar *map= cs->sort_order; DBUG_ASSERT(len >= srclen); for ( ; len > 0 ; len-- ) - *dest++= (char) cs->sort_order[(uchar) *src++]; + *dest++= (char) map[(uchar) *src++]; return srclen; } -int my_strnncoll_simple(CHARSET_INFO * cs,const char *s, uint slen, - const char *t, uint tlen) +int my_strnncoll_simple(CHARSET_INFO * cs, const char *s, uint slen, + const char *t, uint tlen) { int len = ( slen > tlen ) ? tlen : slen; + uchar *map= cs->sort_order; while (len--) { - if (cs->sort_order[(uchar) *s++] != cs->sort_order[(uchar) *t++]) - return ((int) cs->sort_order[(uchar) s[-1]] - - (int) cs->sort_order[(uchar) t[-1]]); + if (map[(uchar) *s++] != map[(uchar) *t++]) + return ((int) map[(uchar) s[-1]] - + (int) map[(uchar) t[-1]]); } return (int) (slen-tlen); } diff --git a/tests/client_test.c b/tests/client_test.c index f988b7dec9a..a00c475129d 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -268,7 +268,7 @@ void my_print_result_metadata(MYSQL_RES *result) for(i=0; i< field_count; i++) { field = mysql_fetch_field(result); - fprintf(stdout, " %-*s |",field->max_length, field->name); + fprintf(stdout, " %-*s |",(int) field->max_length, field->name); } fputc('\n', stdout); my_print_dashes(result); @@ -296,11 +296,11 @@ int my_process_result_set(MYSQL *mysql, MYSQL_RES *result) { field = mysql_fetch_field(result); if(row[i] == NULL) - fprintf(stdout, " %-*s |", field->max_length, "NULL"); + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", field->max_length, row[i]); + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); else - fprintf(stdout, " %-*s |", field->max_length, row[i]); + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); } fputc('\t',stdout); fputc('\n',stdout); @@ -548,13 +548,15 @@ void test_tran_innodb(MYSQL *mysql) mysql_autocommit(mysql,true); } + /******************************************************** -* to test simple prepares of all DML statements * + To test simple prepares of all DML statements *********************************************************/ + void test_prepare_simple(MYSQL *mysql) { MYSQL_STMT *stmt; - int rc,param_count,length; + int rc,param_count; const char *query; myheader("test_prepare_simple"); @@ -570,8 +572,7 @@ void test_prepare_simple(MYSQL *mysql) /* alter table */ query = "ALTER TABLE test_prepare_simple ADD new char(20)"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -581,8 +582,7 @@ void test_prepare_simple(MYSQL *mysql) /* insert */ query = "INSERT INTO test_prepare_simple VALUES(?,?)"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -592,8 +592,7 @@ void test_prepare_simple(MYSQL *mysql) /* update */ query = "UPDATE test_prepare_simple SET id=? WHERE id=? AND name= ?"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -603,8 +602,7 @@ void test_prepare_simple(MYSQL *mysql) /* delete */ query = "DELETE FROM test_prepare_simple WHERE id=10"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -617,8 +615,7 @@ void test_prepare_simple(MYSQL *mysql) /* delete */ query = "DELETE FROM test_prepare_simple WHERE id=?"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -631,8 +628,7 @@ void test_prepare_simple(MYSQL *mysql) /* select */ query = "SELECT * FROM test_prepare_simple WHERE id=? AND name= ?"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -653,7 +649,7 @@ void test_prepare_simple(MYSQL *mysql) void test_prepare_field_result(MYSQL *mysql) { MYSQL_STMT *stmt; - int rc,param_count,length; + int rc,param_count; const char *query; myheader("test_prepare_field_result"); @@ -670,8 +666,7 @@ void test_prepare_field_result(MYSQL *mysql) /* insert */ query = "SELECT id,name FROM test_prepare_field_result WHERE id=?"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -691,7 +686,7 @@ void test_prepare_field_result(MYSQL *mysql) void test_prepare_syntax(MYSQL *mysql) { MYSQL_STMT *stmt; - int rc,length; + int rc; const char *query; myheader("test_prepare_syntax"); @@ -706,13 +701,11 @@ void test_prepare_syntax(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_prepare_syntax VALUES(?"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery_r(mysql,stmt); query = "SELECT id,name FROM test_prepare_syntax WHERE id=? AND WHERE"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery_r(mysql,stmt); /* now fetch the results ..*/ @@ -759,7 +752,7 @@ void test_prepare(MYSQL *mysql) /* insert by prepare */ strcpy(query,"INSERT INTO my_prepare VALUES(?,?,?,?,?,?,?)"); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -861,7 +854,7 @@ void test_double_compare(MYSQL *mysql) myquery(mysql,rc); strcpy(query, "UPDATE test_double_compare SET col1=100 WHERE col1 = ? AND col2 = ? AND COL3 = ?"); - stmt = mysql_prepare(mysql,query); + stmt = mysql_prepare(mysql,query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -937,13 +930,11 @@ void test_null(MYSQL *mysql) /* insert by prepare, wrong column name */ query = "INSERT INTO test_null(col3,col2) VALUES(?,?)"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery_r(mysql,stmt); query = "INSERT INTO test_null(col1,col2) VALUES(?,?)"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -998,8 +989,7 @@ void test_select_simple(MYSQL *mysql) /* insert by prepare */ strcpy((char *)query, "SHOW TABLES FROM mysql"); - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); length = mysql_param_count(stmt); @@ -1079,8 +1069,7 @@ void test_select(MYSQL *mysql) myquery(mysql,rc); query = "SELECT * FROM test_select WHERE id=? AND name=?"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1159,8 +1148,7 @@ void test_simple_update(MYSQL *mysql) /* insert by prepare */ query = "UPDATE test_update SET col2=? WHERE col1=?"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1208,7 +1196,6 @@ void test_long_data(MYSQL *mysql) int rc,param_count; const char *query; char *data=NullS; - int length; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1233,8 +1220,7 @@ void test_long_data(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_long_data(col2) VALUES(?)"; - length=strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1261,7 +1247,7 @@ void test_long_data(MYSQL *mysql) data = (char *)"Micheal"; /* supply data in pieces */ - rc = mysql_send_long_data(stmt,0,data,7); + rc = mysql_send_long_data(stmt,0,data,7,1); mystmt(stmt, rc); /* try to execute mysql_execute() now, it should return @@ -1275,11 +1261,11 @@ void test_long_data(MYSQL *mysql) /* supply data in pieces */ data = (char *)" 'monty' widenius"; - rc = mysql_send_long_data(stmt,0,data,17); + rc = mysql_send_long_data(stmt,0,data,17,0); mystmt(stmt, rc); /* Indiate end of data supply */ - rc = mysql_send_long_data(stmt,0,0,MYSQL_LONG_DATA_END); + rc = mysql_send_long_data(stmt,0,0,0,1); mystmt(stmt, rc); /* execute */ @@ -1311,7 +1297,7 @@ void test_long_data_str(MYSQL *mysql) int rc,param_count; const char *query; char data[255]; - int length; + long length; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1335,8 +1321,7 @@ void test_long_data_str(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_long_data_str VALUES(?,?)"; - length=strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1365,7 +1350,7 @@ void test_long_data_str(MYSQL *mysql) int i; for(i=0; i < 4; i++) { - rc = mysql_send_long_data(stmt,1,(char *)data,5); + rc = mysql_send_long_data(stmt,1,(char *)data,5,0); mystmt(stmt, rc); } @@ -1378,7 +1363,7 @@ void test_long_data_str(MYSQL *mysql) } /* Indiate end of data supply */ - rc = mysql_send_long_data(stmt,1,0,MYSQL_LONG_DATA_END); + rc = mysql_send_long_data(stmt,1,0,0,1); mystmt(stmt, rc); /* execute */ @@ -1437,8 +1422,7 @@ void test_long_data_str1(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_long_data_str VALUES(?,?)"; - length=strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1467,10 +1451,10 @@ void test_long_data_str1(MYSQL *mysql) int i; for(i=0; i < 2; i++) { - rc = mysql_send_long_data(stmt,0,data,length); + rc = mysql_send_long_data(stmt,0,data,length,0); mystmt(stmt, rc); - rc = mysql_send_long_data(stmt,1,data,2); + rc = mysql_send_long_data(stmt,1,data,2,0); mystmt(stmt, rc); } /* try to execute mysql_execute() now, it should return @@ -1482,14 +1466,14 @@ void test_long_data_str1(MYSQL *mysql) } /* Indiate end of data supply */ - rc = mysql_send_long_data(stmt,1,0,MYSQL_LONG_DATA_END); + rc = mysql_send_long_data(stmt,1,0,0,1); mystmt(stmt, rc); rc = mysql_execute(stmt); fprintf(stdout,"mysql_execute() returned %d\n",rc); assert(rc == MYSQL_NEED_DATA); - rc = mysql_send_long_data(stmt,0,0,MYSQL_LONG_DATA_END); + rc = mysql_send_long_data(stmt,0,0,0,1); mystmt(stmt, rc); /* execute */ @@ -1548,8 +1532,7 @@ void test_long_data_bin(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_long_data_bin VALUES(?,?)"; - length=strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1577,7 +1560,7 @@ void test_long_data_bin(MYSQL *mysql) int i; for(i=0; i < 100; i++) { - rc = mysql_send_long_data(stmt,1,(char *)data,4); + rc = mysql_send_long_data(stmt,1,(char *)data,4,0); mystmt(stmt, rc); } @@ -1590,7 +1573,7 @@ void test_long_data_bin(MYSQL *mysql) } /* Indiate end of data supply */ - rc = mysql_send_long_data(stmt,1,0,MYSQL_LONG_DATA_END); + rc = mysql_send_long_data(stmt,1,0,0,1); mystmt(stmt, rc); /* execute */ @@ -1659,8 +1642,7 @@ void test_simple_delete(MYSQL *mysql) /* insert by prepare */ query = "DELETE FROM test_simple_delete WHERE col1=? AND col2=? AND col3=100"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1737,8 +1719,7 @@ void test_update(MYSQL *mysql) myquery(mysql,rc); query = "INSERT INTO test_update(col2,col3) VALUES(?,?)"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1764,8 +1745,7 @@ void test_update(MYSQL *mysql) /* insert by prepare */ query = "UPDATE test_update SET col2=? WHERE col3=?"; - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1812,7 +1792,7 @@ void test_update(MYSQL *mysql) void test_init_prepare(MYSQL *mysql) { MYSQL_STMT *stmt; - int length, param_count, rc; + int param_count, rc; const char *query; MYSQL_RES *result; @@ -1830,8 +1810,7 @@ void test_init_prepare(MYSQL *mysql) /* insert by prepare */ query = "INSERT INTO my_prepare VALUES(10,'venu')"; - length = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -1904,8 +1883,7 @@ void test_bind_result(MYSQL *mysql) bind[1].buffer=szData; /* string data */ strcpy((char *)query , "SELECT * FROM test_bind_result"); - nData = strlen(query); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); rc = mysql_bind_result(stmt,bind); @@ -2000,7 +1978,7 @@ void test_prepare_ext(MYSQL *mysql) /* insert by prepare - all integers */ query = (char *)"INSERT INTO test_prepare_ext(c1,c2,c3,c4,c5,c6) VALUES(?,?,?,?,?,?)"; - stmt = mysql_prepare(mysql,query); + stmt = mysql_prepare(mysql,query, strlen(query)); myquery(mysql,rc); param_count = mysql_param_count(stmt); @@ -2189,7 +2167,7 @@ void test_insert(MYSQL *mysql) /* insert by prepare */ bzero(bind, sizeof(bind)); strcpy(query,"INSERT INTO test_prep_insert VALUES(?,?)"); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); @@ -2260,7 +2238,7 @@ void test_prepare_resultset(MYSQL *mysql) /* insert by prepare */ strcpy(query,"INSERT INTO test_prepare_resultset(id,name) VALUES(?,?)"); - stmt = mysql_prepare(mysql, query); + stmt = mysql_prepare(mysql, query, strlen(query)); myxquery(mysql,stmt); param_count = mysql_param_count(stmt); |