diff options
-rw-r--r-- | client/insert_test.c | 1 | ||||
-rw-r--r-- | client/select_test.c | 1 | ||||
-rw-r--r-- | include/mysql.h | 9 | ||||
-rw-r--r-- | libmysql/libmysql.c | 43 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 45 |
7 files changed, 79 insertions, 29 deletions
diff --git a/client/insert_test.c b/client/insert_test.c index 42691df6875..fb4890faf73 100644 --- a/client/insert_test.c +++ b/client/insert_test.c @@ -16,6 +16,7 @@ #include <stdio.h> #include <stdlib.h> +#include <my_global.h> #include "mysql.h" #define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)" diff --git a/client/select_test.c b/client/select_test.c index ee2a9192865..d7f18c0f1f0 100644 --- a/client/select_test.c +++ b/client/select_test.c @@ -19,6 +19,7 @@ #endif #include <stdio.h> #include <stdlib.h> +#include "my_global.h" #include "mysql.h" #define SELECT_QUERY "select name from test where num = %d" diff --git a/include/mysql.h b/include/mysql.h index 230c0aad9df..67558e39cdb 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -61,6 +61,8 @@ typedef int my_socket; #define CHECK_EXTRA_ARGUMENTS #endif +#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + extern unsigned int mysql_port; extern char *mysql_unix_port; @@ -213,6 +215,8 @@ typedef struct st_mysql struct st_mysql* last_used_slave; /* needed for round-robin slave pick */ /* needed for send/read/store/use result to work correctly with replication */ struct st_mysql* last_used_con; + + LIST *stmts; /* list of all statements */ } MYSQL; @@ -457,6 +461,7 @@ typedef struct st_mysql_stmt MYSQL_RES *result; /* resultset */ MYSQL_BIND *bind; /* row binding */ MYSQL_FIELD *fields; /* prepare meta info */ + LIST list; /* list to keep track of all stmts */ char *query; /* query buffer */ MEM_ROOT mem_root; /* root allocations */ MYSQL_RES tmp_result; /* Used by mysql_prepare_result */ @@ -469,8 +474,8 @@ typedef struct st_mysql_stmt char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ my_bool long_alloced; /* flag to indicate long alloced */ my_bool send_types_to_server; /* to indicate types supply to server */ - my_bool param_buffers; /* to indicate the param bound buffers */ - my_bool res_buffers; /* to indicate the result bound buffers */ + my_bool param_buffers; /* to indicate the param bound buffers */ + my_bool res_buffers; /* to indicate the output bound buffers */ } MYSQL_STMT; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 410be65660f..352ac520fed 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -114,6 +114,7 @@ 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); +static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list); static my_bool org_my_init_done=0; @@ -2436,6 +2437,16 @@ mysql_close(MYSQL *mysql) } mysql->rpl_pivot=0; } + if (mysql->stmts) + { + /* Free any open prepared statements */ + LIST *element, *next_element; + for (element= mysql->stmts; element; element= next_element) + { + next_element= element->next; + stmt_close((MYSQL_STMT *)element->data, 0); + } + } if (mysql != mysql->master) mysql_close(mysql->master); if (mysql->free_me) @@ -3675,18 +3686,20 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) } if (simple_command(mysql, COM_PREPARE, query, length, 1)) { - mysql_stmt_close(stmt); + stmt_close(stmt, 1); DBUG_RETURN(0); } init_alloc_root(&stmt->mem_root,8192,0); if (read_prepare_result(mysql, stmt)) { - mysql_stmt_close(stmt); + stmt_close(stmt, 1); DBUG_RETURN(0); } stmt->state= MY_ST_PREPARE; stmt->mysql= mysql; + mysql->stmts= list_add(mysql->stmts, &stmt->list); + stmt->list.data= stmt; DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count)); DBUG_RETURN(stmt); } @@ -4304,7 +4317,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) DBUG_RETURN(0); } - /* Fetch row data to bind buffers */ @@ -4387,27 +4399,42 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt) *********************************************************************/ /* - Close the statement handle by freeing all resources -*/ + Close the statement handle by freeing all alloced resources -my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) + SYNOPSIS + mysql_stmt_close() + stmt Statement handle + skip_list Flag to indicate delete from list or not + RETURN VALUES + 0 ok + 1 error +*/ +static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list) { my_bool error=0; DBUG_ENTER("mysql_stmt_close"); - if (stmt->state != MY_ST_UNKNOWN) + DBUG_ASSERT(stmt != 0); + if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE) { char buff[4]; int4store(buff, stmt->stmt_id); - error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 0); + error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1); } mysql_free_result(stmt->result); free_root(&stmt->mem_root, MYF(0)); my_free((gptr) stmt->query, MYF(MY_WME | MY_ALLOW_ZERO_PTR)); + if (!skip_list) + stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list); my_free((gptr) stmt, MYF(MY_WME)); DBUG_RETURN(error); } +my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) +{ + return stmt_close(stmt, 0); +} + /* Return statement error code */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0b6c2872925..0a1b02ada40 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -516,7 +516,7 @@ int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key); 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_free(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); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 86333552837..669cea7303b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -74,7 +74,7 @@ const char *command_name[]={ "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "Binlog Dump","Table Dump", "Connect Out", "Register Slave", - "Prepare", "Prepare Execute", "Long Data" + "Prepare", "Prepare Execute", "Long Data", "Close stmt" }; static char empty_c_string[1]= {0}; // Used for not defined 'db' @@ -1004,6 +1004,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_stmt_prepare(thd, packet, packet_length); break; } + case COM_CLOSE_STMT: + { + mysql_stmt_free(thd, packet); + break; + } case COM_QUERY: { if (alloc_query(thd, packet, packet_length)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a3a1f93a829..b631a30fed9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -20,32 +20,47 @@ This file contains the implementation of prepare and executes. Prepare: - - Server gets the query from client with command 'COM_PREPARE' + - Server gets the query from client with command 'COM_PREPARE'; + in the following format: + [COM_PREPARE:1] [query] - Parse the query and recognize any parameter markers '?' and - store its information list lex->param_list + store its information list in lex->param_list + - Allocate a new statement for this prepare; and keep this in + 'thd->prepared_statements' pool. - Without executing the query, return back to client the total number of parameters along with result-set metadata information - (if any) + (if any) in the following format: + [STMT_ID:4][Columns:2][Param_count:2][Columns meta info][Params meta info] Prepare-execute: - Server gets the command 'COM_EXECUTE' to execute the previously prepared query. If there is any param markers; then client will send the data in the following format: - [null_bits][types_specified(0/1)][[length][data]][[length][data] .. [length][data]. + [COM_EXECUTE:1] + [STMT_ID:4] + [NULL_BITS:(param_count+7)/8)] + [TYPES_SUPPLIED_BY_CLIENT(0/1):1] + [[length]data] + [[length]data] .. [[length]data]. + (Note: Except for string/binary types; all other types will not be + supplied with length field) - Replace the param items with this new data. If it is a first execute or types altered by client; then setup the conversion routines. - Execute the query without re-parsing and send back the results 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: - [COM_LONG_DATA:1][parameter_number:2][type:2][data] + [COM_LONG_DATA:1][STMT_ID:4][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. - It's up to the client to check for read data ended. The server doesn't - care. + care; and also server doesn't notify to the client that it got the + data or not; if there is any error; then during execute; the error + will be returned ***********************************************************************/ @@ -238,9 +253,9 @@ static void setup_param_str(Item_param *param, uchar **pos) *pos+=len; } -static void setup_param_functions(Item_param *param, uchar read_pos) +static void setup_param_functions(Item_param *param, uchar param_type) { - switch (read_pos) { + switch (param_type) { case FIELD_TYPE_TINY: param->setup_param_func= setup_param_tiny; param->item_result_type = INT_RESULT; @@ -286,7 +301,6 @@ static bool setup_params_data(PREP_STMT *stmt) uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits - ulong param_no; if (*read_pos++) //types supplied / first execute { @@ -304,7 +318,7 @@ static bool setup_params_data(PREP_STMT *stmt) } param_iterator.rewind(); } - param_no= 0; + ulong param_no= 0; while ((param= (Item_param *)param_iterator++)) { if (!param->long_data_supplied) @@ -319,7 +333,6 @@ static bool setup_params_data(PREP_STMT *stmt) DBUG_RETURN(0); } - /* Validates insert fields */ @@ -473,7 +486,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, List<Item> all_fields(fields); DBUG_ENTER("mysql_test_select_fields"); - if (!(table = open_ltable(thd,tables,tables->lock_type))) + if (!(table = open_ltable(thd,tables,TL_READ))) DBUG_RETURN(1); thd->used_tables=0; // Updated by setup_fields @@ -627,8 +640,8 @@ static bool init_param_items(THD *thd, PREP_STMT *stmt) { DBUG_PRINT("info",("param: %lx", to)); } - return 0; #endif + return 0; } /* @@ -671,7 +684,6 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) stmt.mem_root= thd->mem_root; tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0); thd->mem_root= thd_root; // restore main mem_root - thd->last_prepared_stmt= &stmt; DBUG_RETURN(0); err: @@ -722,7 +734,6 @@ void mysql_stmt_execute(THD *thd, char *packet) have re-check on setup_* and other things .. */ mysql_execute_command(stmt->thd); - thd->last_prepared_stmt= stmt; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); @@ -775,11 +786,11 @@ void mysql_stmt_reset(THD *thd, char *packet) Delete a prepared statement from memory */ -void mysql_stmt_close(THD *thd, char *packet) +void mysql_stmt_free(THD *thd, char *packet) { ulong stmt_id= uint4korr(packet); PREP_STMT *stmt; - DBUG_ENTER("mysql_stmt_close"); + DBUG_ENTER("mysql_stmt_free"); if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) { |