diff options
46 files changed, 1031 insertions, 465 deletions
diff --git a/include/mysql.h b/include/mysql.h index f3244d4ba36..303cb2af4f5 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -130,14 +130,14 @@ typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ #include "my_alloc.h" +typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; typedef struct st_mysql_data { my_ulonglong rows; unsigned int fields; MYSQL_ROWS *data; MEM_ROOT alloc; -#if !defined(CHECK_EMBEDDED_DIFFERENCES) || defined(EMBEDDED_LIBRARY) - MYSQL_ROWS **prev_ptr; -#endif + /* extra info for embedded library */ + struct embedded_query_result *embedded_info; } MYSQL_DATA; enum mysql_option @@ -287,6 +287,8 @@ typedef struct st_mysql from mysql_stmt_close if close had to cancel result set of this object. */ my_bool *unbuffered_fetch_owner; + /* needed for embedded server - no net buffer to store the 'info' */ + char *info_buffer; } MYSQL; typedef struct st_mysql_res { @@ -755,6 +757,7 @@ typedef struct st_mysql_methods const char *(*read_statistics)(MYSQL *mysql); my_bool (*next_result)(MYSQL *mysql); int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd); + int (*read_rows_from_cursor)(MYSQL_STMT *stmt); #endif } MYSQL_METHODS; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 11ee7284cbf..e2ee44efffb 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2722,13 +2722,13 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) /* Send row request to the server */ int4store(buff, stmt->stmt_id); int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ - if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff), - NullS, 0, 1)) + if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH, + buff, sizeof(buff), NullS, 0, 1)) { set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); return 1; } - if (cli_read_binary_rows(stmt)) + if ((*mysql->methods->read_rows_from_cursor)(stmt)) return 1; stmt->server_status= mysql->server_status; @@ -5101,9 +5101,9 @@ my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode) DBUG_ENTER("mysql_autocommit"); DBUG_PRINT("enter", ("mode : %d", auto_mode)); - if (auto_mode) /* set to true */ - DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=1", 16)); - DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=0", 16)); + DBUG_RETURN((my_bool) mysql_real_query(mysql, auto_mode ? + "set autocommit=1":"set autocommit=0", + 16)); } diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index ecc45096165..078243a6d5e 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -18,6 +18,7 @@ #ifdef HAVE_QUERY_CACHE #include <mysql.h> #include "emb_qcache.h" +#include "embedded_priv.h" void Querycache_stream::store_char(char c) { @@ -284,22 +285,25 @@ int Querycache_stream::load_column(MEM_ROOT *alloc, char** column) uint emb_count_querycache_size(THD *thd) { - uint result; - MYSQL *mysql= thd->mysql; - MYSQL_FIELD *field= mysql->fields; - MYSQL_FIELD *field_end= field + mysql->field_count; - MYSQL_ROWS *cur_row=NULL; - my_ulonglong n_rows=0; + uint result= 0; + MYSQL_FIELD *field; + MYSQL_FIELD *field_end; + MYSQL_ROWS *cur_row; + my_ulonglong n_rows; + MYSQL_DATA *data= thd->first_data; + + while (data->embedded_info->next) + data= data->embedded_info->next; + field= data->embedded_info->fields_list; + field_end= field + data->fields; if (!field) - return 0; - if (thd->data) - { - *thd->data->prev_ptr= NULL; // this marks the last record - cur_row= thd->data->data; - n_rows= thd->data->rows; - } - result= (uint) (4+8 + (42 + 4*n_rows)*mysql->field_count); + return result; + *data->embedded_info->prev_ptr= NULL; // this marks the last record + cur_row= data->data; + n_rows= data->rows; + /* n_fields + n_rows + (field_info + strlen * n_rows) * n_fields */ + result+= (uint) (4+8 + (42 + 4*n_rows)*data->fields); for(; field < field_end; field++) { @@ -313,34 +317,38 @@ uint emb_count_querycache_size(THD *thd) for (; cur_row; cur_row=cur_row->next) { MYSQL_ROW col= cur_row->data; - MYSQL_ROW col_end= col + mysql->field_count; + MYSQL_ROW col_end= col + data->fields; for (; col < col_end; col++) if (*col) - result+= *(uint *)((*col) - sizeof(uint)); + result+= *(uint *)((*col) - sizeof(uint)); } return result; } void emb_store_querycache_result(Querycache_stream *dst, THD *thd) { - MYSQL *mysql= thd->mysql; - MYSQL_FIELD *field= mysql->fields; - MYSQL_FIELD *field_end= field + mysql->field_count; - MYSQL_ROWS *cur_row= NULL; - my_ulonglong n_rows= 0; + MYSQL_FIELD *field; + MYSQL_FIELD *field_end; + MYSQL_ROWS *cur_row; + my_ulonglong n_rows; + MYSQL_DATA *data= thd->first_data; + + DBUG_ENTER("emb_store_querycache_result"); + + while (data->embedded_info->next) + data= data->embedded_info->next; + field= data->embedded_info->fields_list; + field_end= field + data->fields; if (!field) - return; + DBUG_VOID_RETURN; - if (thd->data) - { - *thd->data->prev_ptr= NULL; // this marks the last record - cur_row= thd->data->data; - n_rows= thd->data->rows; - } + *data->embedded_info->prev_ptr= NULL; // this marks the last record + cur_row= data->data; + n_rows= data->rows; - dst->store_int((uint)mysql->field_count); - dst->store_ll((uint)n_rows); + dst->store_int((uint)data->fields); + dst->store_ll((ulonglong)n_rows); for(; field < field_end; field++) { @@ -356,14 +364,13 @@ void emb_store_querycache_result(Querycache_stream *dst, THD *thd) dst->store_str(field->org_table, field->org_table_length); dst->store_str(field->db, field->db_length); dst->store_str(field->catalog, field->catalog_length); - dst->store_safe_str(field->def, field->def_length); } for (; cur_row; cur_row=cur_row->next) { MYSQL_ROW col= cur_row->data; - MYSQL_ROW col_end= col + mysql->field_count; + MYSQL_ROW col_end= col + data->fields; for (; col < col_end; col++) { uint len= *col ? *(uint *)((*col) - sizeof(uint)) : 0; @@ -371,28 +378,34 @@ void emb_store_querycache_result(Querycache_stream *dst, THD *thd) } } DBUG_ASSERT(emb_count_querycache_size(thd) == dst->stored_size); + DBUG_VOID_RETURN; } int emb_load_querycache_result(THD *thd, Querycache_stream *src) { - MYSQL *mysql= thd->mysql; - MYSQL_DATA *data; + MYSQL_DATA *data= thd->alloc_new_dataset(); MYSQL_FIELD *field; MYSQL_FIELD *field_end; - MEM_ROOT *f_alloc= &mysql->field_alloc; + MEM_ROOT *f_alloc; MYSQL_ROWS *row, *end_row; MYSQL_ROWS **prev_row; ulonglong rows; MYSQL_ROW columns; + DBUG_ENTER("emb_load_querycache_result"); + + if (!data) + goto err; + init_alloc_root(&data->alloc, 8192,0); + f_alloc= &data->alloc; - mysql->field_count= src->load_int(); + data->fields= src->load_int(); rows= src->load_ll(); if (!(field= (MYSQL_FIELD *) - alloc_root(&mysql->field_alloc,mysql->field_count*sizeof(MYSQL_FIELD)))) + alloc_root(f_alloc,data->fields*sizeof(MYSQL_FIELD)))) goto err; - mysql->fields= field; - for(field_end= field+mysql->field_count; field < field_end; field++) + data->embedded_info->fields_list= field; + for(field_end= field+data->fields; field < field_end; field++) { field->length= src->load_int(); field->max_length= (unsigned int)src->load_int(); @@ -402,47 +415,43 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src) field->decimals= (unsigned int)src->load_char(); if (!(field->name= src->load_str(f_alloc, &field->name_length)) || - !(field->table= src->load_str(f_alloc,&field->table_length)) || - !(field->org_name= src->load_str(f_alloc, &field->org_name_length)) || - !(field->org_table= src->load_str(f_alloc, &field->org_table_length))|| - !(field->db= src->load_str(f_alloc, &field->db_length)) || - !(field->catalog= src->load_str(f_alloc, &field->catalog_length)) || - src->load_safe_str(f_alloc, &field->def, &field->def_length)) + !(field->table= src->load_str(f_alloc,&field->table_length)) || + !(field->org_name= src->load_str(f_alloc, &field->org_name_length)) || + !(field->org_table= src->load_str(f_alloc, &field->org_table_length))|| + !(field->db= src->load_str(f_alloc, &field->db_length)) || + !(field->catalog= src->load_str(f_alloc, &field->catalog_length)) || + src->load_safe_str(f_alloc, &field->def, &field->def_length)) goto err; } - if (!rows) - return 0; - if (!(data= (MYSQL_DATA*)my_malloc(sizeof(MYSQL_DATA), - MYF(MY_WME | MY_ZEROFILL)))) - goto err; - thd->data= data; - init_alloc_root(&data->alloc, 8192,0); - row= (MYSQL_ROWS *)alloc_root(&data->alloc, (uint) (rows * sizeof(MYSQL_ROWS) + - rows * (mysql->field_count+1)*sizeof(char*))); + row= (MYSQL_ROWS *)alloc_root(&data->alloc, + (uint) (rows * sizeof(MYSQL_ROWS) + + rows*(data->fields+1)*sizeof(char*))); end_row= row + rows; columns= (MYSQL_ROW)end_row; data->rows= rows; - data->fields= mysql->field_count; data->data= row; + if (!rows) + goto return_ok; for (prev_row= &row->next; row < end_row; prev_row= &row->next, row++) { *prev_row= row; row->data= columns; - MYSQL_ROW col_end= columns + mysql->field_count; + MYSQL_ROW col_end= columns + data->fields; for (; columns < col_end; columns++) src->load_column(&data->alloc, columns); *(columns++)= NULL; } *prev_row= NULL; - data->prev_ptr= prev_row; - - return 0; + data->embedded_info->prev_ptr= prev_row; +return_ok: + send_eof(thd); + DBUG_RETURN(0); err: - return 1; + DBUG_RETURN(1); } #endif /*HAVE_QUERY_CACHE*/ diff --git a/libmysqld/embedded_priv.h b/libmysqld/embedded_priv.h index d4316dff63f..88015340e8c 100644 --- a/libmysqld/embedded_priv.h +++ b/libmysqld/embedded_priv.h @@ -16,18 +16,25 @@ /* Prototypes for the embedded version of MySQL */ -#include <my_global.h> -#include <mysql.h> -#include <mysql_embed.h> -#include <mysqld_error.h> -#include <my_pthread.h> - C_MODE_START void lib_connection_phase(NET *net, int phase); void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db); void *create_embedded_thd(int client_flag, char *db); int check_embedded_connection(MYSQL *mysql); void free_old_query(MYSQL *mysql); -void embedded_get_error(MYSQL *mysql); extern MYSQL_METHODS embedded_methods; + +/* This one is used by embedded library to gather returning data */ +typedef struct embedded_query_result +{ + MYSQL_ROWS **prev_ptr; + unsigned int warning_count, server_status; + struct st_mysql_data *next; + my_ulonglong affected_rows, insert_id; + char info[MYSQL_ERRMSG_SIZE]; + MYSQL_FIELD *fields_list; + unsigned int last_errno; + char sqlstate[SQLSTATE_LENGTH+1]; +} EQR; + C_MODE_END diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 8552b1c2b8a..fe60b4fd19c 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -42,21 +42,48 @@ C_MODE_START #undef ER #include "errmsg.h" #include <sql_common.h> +#include "embedded_priv.h" -void embedded_get_error(MYSQL *mysql) +static my_bool emb_read_query_result(MYSQL *mysql); + +void THD::clear_data_list() { - THD *thd=(THD *) mysql->thd; - NET *net= &mysql->net; - if ((net->last_errno= thd->net.last_errno)) - { - memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error)); - memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate)); - } - else + while (first_data) { - net->last_error[0]= 0; - strmov(net->sqlstate, not_error_sqlstate); + MYSQL_DATA *data= first_data; + first_data= data->embedded_info->next; + free_rows(data); } + data_tail= &first_data; + free_rows(cur_data); + cur_data= 0; +} + + +/* + Reads error information from the MYSQL_DATA and puts + it into proper MYSQL members + + SYNOPSIS + embedded_get_error() + mysql connection handler + data query result + + NOTES + after that function error information will be accessible + with usual functions like mysql_error() + data is my_free-d in this function + most of the data is stored in data->embedded_info structure +*/ + +void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data) +{ + NET *net= &mysql->net; + struct embedded_query_result *ei= data->embedded_info; + net->last_errno= ei->last_errno; + strmake(net->last_error, ei->info, sizeof(net->last_error)); + memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate)); + my_free((gptr) data, MYF(0)); } static my_bool @@ -68,11 +95,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, THD *thd=(THD *) mysql->thd; NET *net= &mysql->net; - if (thd->data) - { - free_rows(thd->data); - thd->data= 0; - } + thd->clear_data_list(); /* Check that we are calling the client functions in right order */ if (mysql->status != MYSQL_STATUS_READY) { @@ -104,83 +127,101 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, arg_length= header_length; } + thd->net.no_send_error= 0; result= dispatch_command(command, thd, (char *) arg, arg_length + 1); + thd->cur_data= 0; if (!skip_check) result= thd->net.last_errno ? -1 : 0; - /* - If mysql->field_count is set it means the parsing of the query was OK - and metadata was returned (see Protocol::send_fields). - In this case we postpone the error to be returned in mysql_stmt_store_result - (see emb_read_rows) to behave just as standalone server. - */ - if (!mysql->field_count) - embedded_get_error(mysql); - mysql->server_status= thd->server_status; - mysql->warning_count= ((THD*)mysql->thd)->total_warn_count; return result; } static void emb_flush_use_result(MYSQL *mysql) { - MYSQL_DATA *data= ((THD*)(mysql->thd))->data; - - if (data) + THD *thd= (THD*) mysql->thd; + if (thd->cur_data) { + free_rows(thd->cur_data); + thd->cur_data= 0; + } + else if (thd->first_data) + { + MYSQL_DATA *data= thd->first_data; + thd->first_data= data->embedded_info->next; free_rows(data); - ((THD*)(mysql->thd))->data= NULL; } } + +/* + reads dataset from the next query result + + SYNOPSIS + emb_read_rows() + mysql connection handle + other parameters are not used + + NOTES + It just gets next MYSQL_DATA from the result's queue + + RETURN + pointer to MYSQL_DATA with the coming recordset +*/ + static MYSQL_DATA * emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)), unsigned int fields __attribute__((unused))) { - MYSQL_DATA *result= ((THD*)mysql->thd)->data; - embedded_get_error(mysql); - if (mysql->net.last_errno) - return NULL; - if (!result) + MYSQL_DATA *result= ((THD*)mysql->thd)->cur_data; + ((THD*)mysql->thd)->cur_data= 0; + if (result->embedded_info->last_errno) { - if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), - MYF(MY_WME | MY_ZEROFILL)))) - { - NET *net = &mysql->net; - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error,ER(net->last_errno)); - return NULL; - } - return result; - } - *result->prev_ptr= NULL; - ((THD*)mysql->thd)->data= NULL; + embedded_get_error(mysql, result); + return NULL; + } + *result->embedded_info->prev_ptr= NULL; return result; } + static MYSQL_FIELD *emb_list_fields(MYSQL *mysql) { + MYSQL_DATA *res; + if (emb_read_query_result(mysql)) + return 0; + res= ((THD*) mysql->thd)->cur_data; + ((THD*) mysql->thd)->cur_data= 0; + mysql->field_alloc= res->alloc; + my_free((gptr) res,MYF(0)); + mysql->status= MYSQL_STATUS_READY; return mysql->fields; } static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) { - THD *thd= (THD*)mysql->thd; - if (mysql->net.last_errno) - return 1; + THD *thd= (THD*) mysql->thd; + MYSQL_DATA *res; + stmt->stmt_id= thd->client_stmt_id; stmt->param_count= thd->client_param_count; - stmt->field_count= mysql->field_count; + stmt->field_count= 0; - if (stmt->field_count != 0) + if (thd->first_data) { + if (emb_read_query_result(mysql)) + return 1; + stmt->field_count= mysql->field_count; + mysql->status= MYSQL_STATUS_READY; + res= thd->cur_data; + thd->cur_data= NULL; if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) mysql->server_status|= SERVER_STATUS_IN_TRANS; stmt->fields= mysql->fields; - stmt->mem_root= mysql->field_alloc; + stmt->mem_root= res->alloc; mysql->fields= NULL; + my_free((gptr) res,MYF(0)); } return 0; @@ -201,13 +242,42 @@ static void emb_fetch_lengths(ulong *to, MYSQL_ROW column, *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0; } -static my_bool emb_mysql_read_query_result(MYSQL *mysql) +static my_bool emb_read_query_result(MYSQL *mysql) { - if (mysql->net.last_errno) - return -1; + THD *thd= (THD*) mysql->thd; + MYSQL_DATA *res= thd->first_data; + DBUG_ASSERT(!thd->cur_data); + thd->first_data= res->embedded_info->next; + if (res->embedded_info->last_errno && + !res->embedded_info->fields_list) + { + embedded_get_error(mysql, res); + return 1; + } + + mysql->warning_count= res->embedded_info->warning_count; + mysql->server_status= res->embedded_info->server_status; + mysql->field_count= res->fields; + mysql->fields= res->embedded_info->fields_list; + mysql->affected_rows= res->embedded_info->affected_rows; + mysql->insert_id= res->embedded_info->insert_id; + mysql->net.last_errno= 0; + mysql->net.last_error[0]= 0; + mysql->info= 0; + + if (res->embedded_info->info[0]) + { + strmake(mysql->info_buffer, res->embedded_info->info, MYSQL_ERRMSG_SIZE-1); + mysql->info= mysql->info_buffer; + } - if (mysql->field_count) + if (res->embedded_info->fields_list) + { mysql->status=MYSQL_STATUS_GET_RESULT; + thd->cur_data= res; + } + else + my_free((gptr) res, MYF(0)); return 0; } @@ -215,14 +285,18 @@ static my_bool emb_mysql_read_query_result(MYSQL *mysql) static int emb_stmt_execute(MYSQL_STMT *stmt) { DBUG_ENTER("emb_stmt_execute"); - char header[4]; + char header[5]; + MYSQL_DATA *res; + THD *thd; + int4store(header, stmt->stmt_id); - THD *thd= (THD*)stmt->mysql->thd; + header[4]= stmt->flags; + thd= (THD*)stmt->mysql->thd; thd->client_param_count= stmt->param_count; thd->client_params= stmt->params; if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0, header, sizeof(header), 1) || - emb_mysql_read_query_result(stmt->mysql)) + emb_read_query_result(stmt->mysql)) { NET *net= &stmt->mysql->net; set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); @@ -230,6 +304,8 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) } stmt->affected_rows= stmt->mysql->affected_rows; stmt->insert_id= stmt->mysql->insert_id; + stmt->server_status= stmt->mysql->server_status; + DBUG_RETURN(0); } @@ -240,22 +316,53 @@ int emb_read_binary_rows(MYSQL_STMT *stmt) return 1; stmt->result= *data; my_free((char *) data, MYF(0)); + set_stmt_errmsg(stmt, stmt->mysql->net.last_error, + stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate); return 0; } +int emb_read_rows_from_cursor(MYSQL_STMT *stmt) +{ + MYSQL *mysql= stmt->mysql; + THD *thd= (THD*) mysql->thd; + MYSQL_DATA *res= thd->first_data; + DBUG_ASSERT(!thd->first_data->embedded_info->next); + thd->first_data= 0; + if (res->embedded_info->last_errno) + { + embedded_get_error(mysql, res); + set_stmt_errmsg(stmt, mysql->net.last_error, + mysql->net.last_errno, mysql->net.sqlstate); + return 1; + } + + thd->cur_data= res; + mysql->warning_count= res->embedded_info->warning_count; + mysql->server_status= res->embedded_info->server_status; + mysql->net.last_errno= 0; + mysql->net.last_error[0]= 0; + + return emb_read_binary_rows(stmt); +} + int emb_unbuffered_fetch(MYSQL *mysql, char **row) { - MYSQL_DATA *data= ((THD*)mysql->thd)->data; - embedded_get_error(mysql); - if (mysql->net.last_errno) - return mysql->net.last_errno; + THD *thd= (THD*) mysql->thd; + MYSQL_DATA *data= thd->cur_data; + if (data && data->embedded_info->last_errno) + { + embedded_get_error(mysql, data); + thd->cur_data= 0; + return 1; + } if (!data || !data->data) { *row= NULL; if (data) { + thd->cur_data= thd->first_data; + thd->first_data= data->embedded_info->next; free_rows(data); - ((THD*)mysql->thd)->data= NULL; } } else @@ -269,9 +376,9 @@ int emb_unbuffered_fetch(MYSQL *mysql, char **row) static void emb_free_embedded_thd(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - if (thd->data) - free_rows(thd->data); + thd->clear_data_list(); thread_count--; + thd->store_globals(); delete thd; mysql->thd=0; } @@ -283,23 +390,11 @@ static const char * emb_read_statistics(MYSQL *mysql) } -static MYSQL_RES * emb_mysql_store_result(MYSQL *mysql) +static MYSQL_RES * emb_store_result(MYSQL *mysql) { return mysql_store_result(mysql); } -my_bool emb_next_result(MYSQL *mysql) -{ - THD *thd= (THD*)mysql->thd; - DBUG_ENTER("emb_next_result"); - - if (emb_advanced_command(mysql, COM_QUERY,0,0, - thd->query_rest.ptr(),thd->query_rest.length(),1) || - emb_mysql_read_query_result(mysql)) - DBUG_RETURN(1); - - DBUG_RETURN(0); /* No more results */ -} int emb_read_change_user_result(MYSQL *mysql, char *buff __attribute__((unused)), @@ -310,10 +405,10 @@ int emb_read_change_user_result(MYSQL *mysql, MYSQL_METHODS embedded_methods= { - emb_mysql_read_query_result, + emb_read_query_result, emb_advanced_command, emb_read_rows, - emb_mysql_store_result, + emb_store_result, emb_fetch_lengths, emb_flush_use_result, emb_list_fields, @@ -323,8 +418,9 @@ MYSQL_METHODS embedded_methods= emb_unbuffered_fetch, emb_free_embedded_thd, emb_read_statistics, - emb_next_result, - emb_read_change_user_result + emb_read_query_result, + emb_read_change_user_result, + emb_read_rows_from_cursor }; C_MODE_END @@ -483,6 +579,7 @@ void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db) THD *thd = (THD *)mysql->thd; thd->mysql= mysql; mysql->server_version= server_version; + init_alloc_root(&mysql->field_alloc, 8192, 0); } void *create_embedded_thd(int client_flag, char *db) @@ -490,6 +587,7 @@ void *create_embedded_thd(int client_flag, char *db) THD * thd= new THD; thd->thread_id= thread_id++; + thd->thread_stack= (char*) &thd; if (thd->store_globals()) { fprintf(stderr,"store_globals failed.\n"); @@ -498,7 +596,6 @@ void *create_embedded_thd(int client_flag, char *db) thd->mysys_var= my_thread_var; thd->dbug_thread_id= my_thread_id(); - thd->thread_stack= (char*) &thd; /* TODO - add init_connect command execution */ @@ -517,9 +614,10 @@ void *create_embedded_thd(int client_flag, char *db) thd->security_ctx->db_access= DB_ACLS; thd->security_ctx->master_access= ~NO_ACCESS; #endif - thd->net.query_cache_query= 0; - - thd->data= 0; + thd->cur_data= 0; + thd->first_data= 0; + thd->data_tail= &thd->first_data; + bzero((char*) &thd->net, sizeof(thd->net)); thread_count++; return thd; @@ -531,11 +629,15 @@ err: #ifdef NO_EMBEDDED_ACCESS_CHECKS int check_embedded_connection(MYSQL *mysql) { + int result; THD *thd= (THD*)mysql->thd; Security_context *sctx= thd->security_ctx; - sctx->host_or_ip= sctx->host= (char*)my_localhost; + sctx->host_or_ip= sctx->host= (char*) my_localhost; + strmake(sctx->priv_host, (char*) my_localhost, MAX_HOSTNAME-1); sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0)); - return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); + result= check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); + emb_read_query_result(mysql); + return result; } #else @@ -616,26 +718,147 @@ static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, } +/* + creates new result and hooks it to the list + + SYNOPSIS + alloc_new_dataset() + + NOTES + allocs the MYSQL_DATA + embedded_query_result couple + to store the next query result, + links these two and attach it to the THD::data_tail + + RETURN + pointer to the newly created query result +*/ + +MYSQL_DATA *THD::alloc_new_dataset() +{ + MYSQL_DATA *data; + struct embedded_query_result *emb_data; + if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &data, sizeof(*data), + &emb_data, sizeof(*emb_data), + NULL)) + return NULL; + + emb_data->prev_ptr= &data->data; + cur_data= data; + *data_tail= data; + data_tail= &emb_data->next; + data->embedded_info= emb_data; + return data; +} + + +/* + stores server_status and warning_count in the current + query result structures + + SYNOPSIS + write_eof_packet() + thd current thread + + NOTES + should be called to after we get the recordset-result + +*/ + +static void write_eof_packet(THD *thd) +{ + /* + The following test should never be true, but it's better to do it + because if 'is_fatal_error' is set the server is not going to execute + other queries (see the if test in dispatch_command / COM_QUERY) + */ + if (thd->is_fatal_error) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; + thd->cur_data->embedded_info->server_status= thd->server_status; + /* + Don't send warn count during SP execution, as the warn_list + is cleared between substatements, and mysqltest gets confused + */ + thd->cur_data->embedded_info->warning_count= + (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); +} + + +/* + allocs new query result and initialises Protocol::alloc + + SYNOPSIS + Protocol::begin_dataset() + + RETURN + 0 if success + 1 if memory allocation failed +*/ + +int Protocol::begin_dataset() +{ + MYSQL_DATA *data= thd->alloc_new_dataset(); + if (!data) + return 1; + alloc= &data->alloc; + init_alloc_root(alloc,8192,0); /* Assume rowlength < 8192 */ + alloc->min_malloc=sizeof(MYSQL_ROWS); + return 0; +} + + +/* + remove last row of current recordset + + SYNOPSIS + Protocol_simple::remove_last_row() + + NOTES + does the loop from the beginning of the current recordset to + the last record and cuts it off. + Not supposed to be frequently called. +*/ + +void Protocol_simple::remove_last_row() +{ + MYSQL_DATA *data= thd->cur_data; + MYSQL_ROWS **last_row_hook= &data->data; + uint count= data->rows; + DBUG_ENTER("Protocol_simple::remove_last_row"); + while (--count) + last_row_hook= &(*last_row_hook)->next; + + *last_row_hook= 0; + data->embedded_info->prev_ptr= last_row_hook; + data->rows--; + + DBUG_VOID_RETURN; +} + + bool Protocol::send_fields(List<Item> *list, uint flags) { List_iterator_fast<Item> it(*list); Item *item; MYSQL_FIELD *client_field; - MYSQL *mysql= thd->mysql; MEM_ROOT *field_alloc; CHARSET_INFO *thd_cs= thd->variables.character_set_results; CHARSET_INFO *cs= system_charset_info; - + MYSQL_DATA *data; DBUG_ENTER("send_fields"); - if (!mysql) // bootstrap file handling + if (!thd->mysql) // bootstrap file handling DBUG_RETURN(0); - field_count= list->elements; - field_alloc= &mysql->field_alloc; - if (!(client_field= thd->mysql->fields= - (MYSQL_FIELD *)alloc_root(field_alloc, - sizeof(MYSQL_FIELD) * field_count))) + if (begin_dataset()) + goto err; + + data= thd->cur_data; + data->fields= field_count= list->elements; + field_alloc= &data->alloc; + + if (!(client_field= data->embedded_info->fields_list= + (MYSQL_FIELD*)alloc_root(field_alloc, sizeof(MYSQL_FIELD)*field_count))) goto err; while ((item= it++)) @@ -643,6 +866,10 @@ bool Protocol::send_fields(List<Item> *list, uint flags) Send_field server_field; item->make_field(&server_field); + /* Keep things compatible for old clients */ + if (server_field.type == MYSQL_TYPE_VARCHAR) + server_field.type= MYSQL_TYPE_VAR_STRING; + client_field->db= dup_str_aux(field_alloc, server_field.db_name, strlen(server_field.db_name), cs, thd_cs); client_field->table= dup_str_aux(field_alloc, server_field.table_name, @@ -703,7 +930,9 @@ bool Protocol::send_fields(List<Item> *list, uint flags) client_field->max_length= 0; ++client_field; } - thd->mysql->field_count= field_count; + + if (flags & SEND_EOF) + write_eof_packet(thd); DBUG_RETURN(prepare_for_send(list)); err: @@ -723,25 +952,11 @@ bool Protocol::write() bool Protocol_prep::write() { MYSQL_ROWS *cur; - MYSQL_DATA *data= thd->data; - - if (!data) - { - if (!(data= (MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), - MYF(MY_WME | MY_ZEROFILL)))) - return true; - - alloc= &data->alloc; - init_alloc_root(alloc,8192,0); /* Assume rowlength < 8192 */ - alloc->min_malloc=sizeof(MYSQL_ROWS); - data->rows=0; - data->fields=field_count; - data->prev_ptr= &data->data; - thd->data= data; - } + MYSQL_DATA *data= thd->cur_data; data->rows++; - if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+packet->length()))) + if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, + sizeof(MYSQL_ROWS)+packet->length()))) { my_error(ER_OUT_OF_RESOURCES,MYF(0)); return true; @@ -750,8 +965,8 @@ bool Protocol_prep::write() memcpy(cur->data, packet->ptr()+1, packet->length()-1); cur->length= packet->length(); /* To allow us to do sanity checks */ - *data->prev_ptr= cur; - data->prev_ptr= &cur->next; + *data->embedded_info->prev_ptr= cur; + data->embedded_info->prev_ptr= &cur->next; cur->next= 0; return false; @@ -761,46 +976,52 @@ void send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) { DBUG_ENTER("send_ok"); - MYSQL *mysql= current_thd->mysql; + MYSQL_DATA *data; + MYSQL *mysql= thd->mysql; + if (!mysql) // bootstrap file handling DBUG_VOID_RETURN; - mysql->affected_rows= affected_rows; - mysql->insert_id= id; + if (thd->net.no_send_ok) // hack for re-parsing queries + DBUG_VOID_RETURN; + if (!(data= thd->alloc_new_dataset())) + return; + data->embedded_info->affected_rows= affected_rows; + data->embedded_info->insert_id= id; if (message) - { - strmake(thd->net.last_error, message, sizeof(thd->net.last_error)-1); - mysql->info= thd->net.last_error; - } + strmake(data->embedded_info->info, message, + sizeof(data->embedded_info->info)-1); + + write_eof_packet(thd); + thd->cur_data= 0; DBUG_VOID_RETURN; } void send_eof(THD *thd) { + write_eof_packet(thd); + thd->cur_data= 0; } + +void net_send_error_packet(THD *thd, uint sql_errno, const char *err) +{ + MYSQL_DATA *data= thd->cur_data ? thd->cur_data : thd->alloc_new_dataset(); + struct embedded_query_result *ei= data->embedded_info; + + ei->last_errno= sql_errno; + strmake(ei->info, err, sizeof(ei->info)-1); + strmov(ei->sqlstate, mysql_errno_to_sqlstate(sql_errno)); + thd->cur_data= 0; +} + + void Protocol_simple::prepare_for_resend() { MYSQL_ROWS *cur; - MYSQL_DATA *data= thd->data; - + MYSQL_DATA *data= thd->cur_data; DBUG_ENTER("send_data"); - if (!data) - { - if (!(data= (MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), - MYF(MY_WME | MY_ZEROFILL)))) - goto err; - - alloc= &data->alloc; - init_alloc_root(alloc,8192,0); /* Assume rowlength < 8192 */ - alloc->min_malloc=sizeof(MYSQL_ROWS); - data->rows=0; - data->fields=field_count; - data->prev_ptr= &data->data; - thd->data= data; - } - data->rows++; if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+(field_count + 1) * sizeof(char *)))) { @@ -809,10 +1030,10 @@ void Protocol_simple::prepare_for_resend() } cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS)); - *data->prev_ptr= cur; - data->prev_ptr= &cur->next; + *data->embedded_info->prev_ptr= cur; + data->embedded_info->prev_ptr= &cur->next; next_field=cur->data; - next_mysql_field= thd->mysql->fields; + next_mysql_field= data->embedded_info->fields_list; err: DBUG_VOID_RETURN; } diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 70074e44c6f..cad1bd4c47b 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -14,6 +14,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <my_global.h> +#include <mysql.h> +#include <mysql_embed.h> +#include <mysqld_error.h> +#include <my_pthread.h> #include "embedded_priv.h" #include <my_sys.h> #include <mysys_err.h> @@ -193,7 +198,12 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (!user) user= ""; - mysql->user=my_strdup(user,MYF(0)); + /* + We need to alloc some space for mysql->info but don't want to + put extra 'my_free's in mysql_close. + So we alloc it with the 'user' string to be freed at once + */ + mysql->user= my_strdup(user, MYF(0)); port=0; unix_socket=0; @@ -207,6 +217,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (db) client_flag|=CLIENT_CONNECT_WITH_DB; + mysql->info_buffer= my_malloc(MYSQL_ERRMSG_SIZE, MYF(0)); mysql->thd= create_embedded_thd(client_flag, db_name); init_embedded_mysql(mysql, client_flag, db_name); @@ -243,7 +254,6 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, DBUG_RETURN(mysql); error: - embedded_get_error(mysql); DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno, mysql->net.last_error)); { diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test index 40a9fa73b60..a75837c1d2d 100644 --- a/mysql-test/t/backup.test +++ b/mysql-test/t/backup.test @@ -1,3 +1,6 @@ +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc + # # This test is a bit tricky as we can't use backup table to overwrite an old # table diff --git a/mysql-test/t/binlog_stm_binlog.test b/mysql-test/t/binlog_stm_binlog.test index da93d86c7ce..6d3dce9a323 100644 --- a/mysql-test/t/binlog_stm_binlog.test +++ b/mysql-test/t/binlog_stm_binlog.test @@ -1,5 +1,6 @@ # This is a wrapper for binlog.test so that the same test case can be used # For both statement and row based bin logs 9/19/2005 [jbm] +-- source include/not_embedded.inc -- source include/have_binlog_format_statement.inc -- source extra/binlog_tests/binlog.test diff --git a/mysql-test/t/binlog_stm_blackhole.test b/mysql-test/t/binlog_stm_blackhole.test index 3c0096fa3f6..6047d8ca2fc 100644 --- a/mysql-test/t/binlog_stm_blackhole.test +++ b/mysql-test/t/binlog_stm_blackhole.test @@ -1,5 +1,6 @@ # This is a wrapper for binlog.test so that the same test case can be used # For both statement and row based bin logs 9/19/2005 [jbm] +-- source include/not_embedded.inc -- source include/have_binlog_format_statement.inc -- source extra/binlog_tests/blackhole.test diff --git a/mysql-test/t/binlog_stm_ctype_cp932.test b/mysql-test/t/binlog_stm_ctype_cp932.test index cef179e0028..436f95a2453 100644 --- a/mysql-test/t/binlog_stm_ctype_cp932.test +++ b/mysql-test/t/binlog_stm_ctype_cp932.test @@ -1,5 +1,6 @@ # This is a wrapper for binlog.test so that the same test case can be used # For both statement and row based bin logs 9/19/2005 [jbm] +-- source include/not_embedded.inc -- source include/have_binlog_format_statement.inc -- source extra/binlog_tests/ctype_cp932.test diff --git a/mysql-test/t/compress.test b/mysql-test/t/compress.test index 46244edd2a8..3f1892b5dec 100644 --- a/mysql-test/t/compress.test +++ b/mysql-test/t/compress.test @@ -1,6 +1,9 @@ # Turn on compression between the client and server # and run a number of tests +# Can't test with embedded server +-- source include/not_embedded.inc + -- source include/have_compress.inc connect (comp_con,localhost,root,,,,,COMPRESS); diff --git a/mysql-test/t/ctype_cp932_notembedded.test b/mysql-test/t/ctype_cp932_notembedded.test new file mode 100644 index 00000000000..52e7acc3f01 --- /dev/null +++ b/mysql-test/t/ctype_cp932_notembedded.test @@ -0,0 +1,32 @@ +-- source include/not_embedded.inc +-- source include/have_cp932.inc + +--character_set cp932 +--disable_warnings +drop table if exists t1; +--enable_warnings + +set names cp932; +set character_set_database = cp932; + +# Test prepared statement with 0x8300 sequence in parameter while +# running with cp932 client character set. +RESET MASTER; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +# TODO: Note that this doesn't actually test the code which was added for +# bug#11338 because this syntax for prepared statements causes the PS to +# be replicated differently than if we executed the PS from C or Java. +# Using this syntax, variable names are inserted into the binlog instead +# of values. The real goal of this test is to check the code that was +# added to Item_param::query_val_str() in order to do hex encoding of +# PS parameters when the client character set is cp932; +# Bug#11338 has an example java program which can be used to verify this +# code (and I have used it to test the fix) until there is some way to +# exercise this code from mysql-test-run. +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS FROM 98; +SELECT HEX(f1) FROM t1; +DROP table t1; +# end test for bug#11338 diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index ca34cc020f3..5ae757b1fde 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -3,6 +3,9 @@ # (Can't be tested with purify :( ) # +# This tests not performed with embedded server +-- source include/not_embedded.inc + --disable_warnings drop table if exists t1; --enable_warnings diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index b6b3b90c083..a31fcf59074 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1,3 +1,5 @@ +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc source include/federated.inc; connection slave; diff --git a/mysql-test/t/federated_archive.test b/mysql-test/t/federated_archive.test index 6d80664fef7..f8df5f1c51a 100644 --- a/mysql-test/t/federated_archive.test +++ b/mysql-test/t/federated_archive.test @@ -1,3 +1,5 @@ +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc source include/have_archive.inc; source include/federated.inc; diff --git a/mysql-test/t/federated_bug_13118.test b/mysql-test/t/federated_bug_13118.test index deec79becd2..e429a660489 100644 --- a/mysql-test/t/federated_bug_13118.test +++ b/mysql-test/t/federated_bug_13118.test @@ -1,3 +1,5 @@ +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc source include/federated.inc; diff --git a/mysql-test/t/federated_transactions.test b/mysql-test/t/federated_transactions.test index 1a5b14ca8b4..5095c8ce9c3 100644 --- a/mysql-test/t/federated_transactions.test +++ b/mysql-test/t/federated_transactions.test @@ -1,3 +1,5 @@ +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc source include/have_bdb.inc; source include/federated.inc; diff --git a/mysql-test/t/flush_table.test b/mysql-test/t/flush_table.test index 0ea0ac0840a..50e7e91419a 100644 --- a/mysql-test/t/flush_table.test +++ b/mysql-test/t/flush_table.test @@ -4,6 +4,8 @@ # Test of flush table # +# Should work in embedded server after mysqltest is fixed +-- source include/not_embedded.inc --disable_warnings drop table if exists t1,t2; --enable_warnings diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index f3e14c3cd2b..cce1c5de725 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -2,6 +2,9 @@ # test of HANDLER ... # +# should work in embedded server after mysqltest is fixed +-- source include/not_embedded.inc + --disable_warnings drop table if exists t1; --enable_warnings diff --git a/mysql-test/t/init_connect.test b/mysql-test/t/init_connect.test index 2e3c67a7d38..0ee6387d985 100644 --- a/mysql-test/t/init_connect.test +++ b/mysql-test/t/init_connect.test @@ -2,6 +2,8 @@ # Test of init_connect variable # +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc connect (con0,localhost,root,,); connection con0; select hex(@a); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 71b92c419ca..10cb1dcf08b 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1576,33 +1576,7 @@ connection a; checksum table t1; drop table t1; -# -# BUG#11238 - in prelocking mode SELECT .. FOR UPDATE is changed to -# non-blocking SELECT -# -create table t1 (col1 integer primary key, col2 integer) engine=innodb; -insert t1 values (1,100); -delimiter |; -create function f1 () returns integer begin -declare var1 int; -select col2 into var1 from t1 where col1=1 for update; -return var1; -end| -delimiter ;| -start transaction; -select f1(); -connection b; -send update t1 set col2=0 where col1=1; -connection default; -select * from t1; -connection a; -rollback; -connection b; -reap; -rollback; connection default; -drop table t1; -drop function f1; disconnect a; disconnect b; diff --git a/mysql-test/t/innodb_notembedded.test b/mysql-test/t/innodb_notembedded.test new file mode 100644 index 00000000000..1d8a590be78 --- /dev/null +++ b/mysql-test/t/innodb_notembedded.test @@ -0,0 +1,36 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +connect (a,localhost,root,,); +connect (b,localhost,root,,); + + +# +# BUG#11238 - in prelocking mode SELECT .. FOR UPDATE is changed to +# non-blocking SELECT +# +create table t1 (col1 integer primary key, col2 integer) engine=innodb; +insert t1 values (1,100); +delimiter |; +create function f1 () returns integer begin +declare var1 int; +select col2 into var1 from t1 where col1=1 for update; +return var1; +end| +delimiter ;| +start transaction; +select f1(); +connection b; +send update t1 set col2=0 where col1=1; +connection default; +select * from t1; +connection a; +rollback; +connection b; +reap; +rollback; +connection default; +drop table t1; +drop function f1; +disconnect a; +disconnect b; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 0783c043ef6..7871ec3690e 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -1,3 +1,5 @@ +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc # # Testing the MySQL command line client(mysql) # diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 66b57dd5fb7..1225bf73009 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -1,3 +1,6 @@ +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc + # We run with different binaries for normal and --embedded-server # # If this test fails with "command "$MYSQL_CLIENT_TEST" failed", diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 440a7787985..1f5c798e6fe 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1,3 +1,5 @@ +# This test should work in embedded server after mysqltest is fixed +-- source include/not_embedded.inc # ============================================================================ # diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 9b4a64872d9..a99d802e5a5 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -822,29 +822,14 @@ select sql_cache * from t1 where s1=1; end;// delimiter ;// call f1(); -show status like "Qcache_queries_in_cache"; -show status like "Qcache_inserts"; -show status like "Qcache_hits"; call f1(); -show status like "Qcache_queries_in_cache"; -show status like "Qcache_inserts"; -show status like "Qcache_hits"; call f1(); select sql_cache * from t1; -show status like "Qcache_queries_in_cache"; -show status like "Qcache_inserts"; -show status like "Qcache_hits"; insert into t1 values (1); select sql_cache * from t1; -show status like "Qcache_queries_in_cache"; -show status like "Qcache_inserts"; -show status like "Qcache_hits"; call f1(); call f1(); select sql_cache * from t1; -show status like "Qcache_queries_in_cache"; -show status like "Qcache_inserts"; -show status like "Qcache_hits"; flush query cache; reset query cache; flush status; diff --git a/mysql-test/t/query_cache_notembedded.test b/mysql-test/t/query_cache_notembedded.test index fd4785ffe95..5e1ab7051e5 100644 --- a/mysql-test/t/query_cache_notembedded.test +++ b/mysql-test/t/query_cache_notembedded.test @@ -97,4 +97,88 @@ connection root; SELECT * FROM t1; drop table t1; +# +# query in QC from normal execution and SP (BUG#6897) +# improved to also test BUG#3583 and BUG#12990 +# +flush query cache; +reset query cache; +flush status; +delimiter //; +create table t1 (s1 int)// +create procedure f1 () begin +select sql_cache * from t1; +select sql_cache * from t1; +select sql_cache * from t1; +end;// +create procedure f2 () begin +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +end;// +create procedure f3 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +end;// +create procedure f4 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1 where s1=1; +end;// +delimiter ;// +call f1(); +--replace_result 1 3 +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +insert into t1 values (1); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +call f1(); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +flush query cache; +reset query cache; +flush status; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +call f1(); +call f2(); +call f3(); +call f4(); +call f4(); +call f3(); +call f2(); +select sql_cache * from t1 where s1=1; +insert into t1 values (2); +call f1(); +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +call f1(); +call f3(); +call f3(); +call f1(); + +drop procedure f1; +drop procedure f2; +drop procedure f3; +drop procedure f4; +drop table t1; + + set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/read_only.test b/mysql-test/t/read_only.test index 0861951a6a1..1e92e438122 100644 --- a/mysql-test/t/read_only.test +++ b/mysql-test/t/read_only.test @@ -1,6 +1,9 @@ # Test of the READ_ONLY global variable: # check that it blocks updates unless they are only on temporary tables. +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc + --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 16b0fbc4d25..a0164cb0759 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -1,3 +1,6 @@ +# This tests not performed with embedded server +-- source include/not_embedded.inc + --disable_warnings drop table if exists t1,v1; drop view if exists t1,v1; diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test index a2a66090866..4f812453f45 100644 --- a/mysql-test/t/sp-destruct.test +++ b/mysql-test/t/sp-destruct.test @@ -35,10 +35,13 @@ create trigger t1_ai after insert on t1 for each row call bug14233(); # Unsupported tampering with the mysql.proc definition alter table mysql.proc drop type; +--replace_result $MYSQL_TEST_DIR . --error ER_SP_PROC_TABLE_CORRUPT call bug14233(); +--replace_result $MYSQL_TEST_DIR . --error ER_SP_PROC_TABLE_CORRUPT create view v1 as select bug14233_f(); +--replace_result $MYSQL_TEST_DIR . --error ER_SP_PROC_TABLE_CORRUPT insert into t1 values (0); diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index cf8f8dfc79c..cabd00fe5f9 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -648,28 +648,6 @@ call bug3294()| drop procedure bug3294| # -# BUG#6807: Stored procedure crash if CREATE PROCEDURE ... KILL QUERY -# ---disable_warnings -drop procedure if exists bug6807| ---enable_warnings -create procedure bug6807() -begin - declare id int; - - set id = connection_id(); - kill query id; - select 'Not reached'; -end| - ---error 1317 -call bug6807()| ---error 1317 -call bug6807()| - -drop procedure bug6807| - -# # BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in # a DECLARE ? HANDLER FOR stmt. # diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 70c1efb1f0b..d8a8ce5dae7 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -1,3 +1,5 @@ +# This test should work in embedded server after mysqltest is fixed +-- source include/not_embedded.inc # # Testing stored procedures with multiple connections, # except security/privilege tests, they go to sp-security.test diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 91973da6c22..54444a91fbb 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1368,11 +1368,11 @@ end| call ifac(20)| select * from fac| drop table fac| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show function status like '%f%'| drop procedure ifac| drop function fac| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show function status like '%f%'| @@ -1455,7 +1455,7 @@ begin end while; end| show create procedure opp| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like '%p%'| # This isn't the fastest way in the world to compute prime numbers, so @@ -1473,7 +1473,7 @@ select * from primes where i=45 or i=100 or i=199| drop table primes| drop procedure opp| drop procedure ip| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like '%p%'| @@ -1541,13 +1541,13 @@ drop procedure if exists bar| create procedure bar(x char(16), y int) comment "111111111111" sql security invoker insert into test.t1 values (x, y)| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'bar'| alter procedure bar comment "2222222222" sql security definer| alter procedure bar comment "3333333333"| alter procedure bar| show create procedure bar| ---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'bar'| drop procedure bar| @@ -2497,7 +2497,6 @@ begin show databases like 'foo'; show errors; show columns from t1; - show grants for 'root'@'localhost'; show keys from t1; show open tables like 'foo'; show privileges; @@ -2519,20 +2518,6 @@ call bug4902()| drop procedure bug4902| -# We need separate SP for SHOW PROCESSLIST since we want use replace_column ---disable_warnings -drop procedure if exists bug4902_2| ---enable_warnings -create procedure bug4902_2() -begin - show processlist; -end| ---replace_column 1 # 6 # 3 localhost -call bug4902_2()| ---replace_column 1 # 6 # 3 localhost -call bug4902_2()| -drop procedure bug4902_2| - # # BUG#4904 # @@ -2747,44 +2732,6 @@ select @x| delete from t1| drop procedure bug4941| - -# -# BUG#3583: query cache doesn't work for stored procedures -# ---disable_warnings -drop procedure if exists bug3583| ---enable_warnings ---disable_warnings -drop procedure if exists bug3583| ---enable_warnings -create procedure bug3583() -begin - declare c int; - - select * from t1; - select count(*) into c from t1; - select c; -end| - -insert into t1 values ("x", 3), ("y", 5)| -set @x = @@query_cache_size| -set global query_cache_size = 10*1024*1024| - -flush status| -flush query cache| -show status like 'Qcache_hits'| -call bug3583()| -show status like 'Qcache_hits'| -call bug3583()| -call bug3583()| -show status like 'Qcache_hits'| - -set global query_cache_size = @x| -flush status| -flush query cache| -delete from t1| -drop procedure bug3583| - # # BUG#4905: Stored procedure doesn't clear for "Rows affected" # @@ -3094,24 +3041,6 @@ select id, bug5240() from t1| drop function bug5240| # -# BUG#5278: Stored procedure packets out of order if SET PASSWORD. -# ---disable_warnings -drop function if exists bug5278| ---enable_warnings -create function bug5278 () returns char -begin - SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass'); - return 'okay'; -end| - ---error 1133 -select bug5278()| ---error 1133 -select bug5278()| -drop function bug5278| - -# # BUG#7992: rolling back temporary Item tree changes in SP # --disable_warnings @@ -4733,24 +4662,6 @@ select bug10100f(5)| call bug10100t(5)| #end of the stack checking -set @@max_sp_recursion_depth=255| -set @var=1| -#disable log because error about stack overrun contains numbers which -#depend on a system --- disable_result_log --- error ER_STACK_OVERRUN_NEED_MORE -call bug10100p(255, @var)| --- error ER_STACK_OVERRUN_NEED_MORE -call bug10100pt(1,255)| --- error ER_STACK_OVERRUN_NEED_MORE -call bug10100pv(1,255)| --- error ER_STACK_OVERRUN_NEED_MORE -call bug10100pd(1,255)| --- error ER_STACK_OVERRUN_NEED_MORE -call bug10100pc(1,255)| --- enable_result_log -set @@max_sp_recursion_depth=0| - deallocate prepare stmt2| drop function bug10100f| diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test new file mode 100644 index 00000000000..964b5d313c8 --- /dev/null +++ b/mysql-test/t/sp_notembedded.test @@ -0,0 +1,261 @@ +# Can't test with embedded server +-- source include/not_embedded.inc + +delimiter |; + +# +# BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error +# +# Added tests for show grants command +--disable_warnings +drop procedure if exists bug4902| +--enable_warnings +create procedure bug4902() +begin + show grants for 'root'@'localhost'; +end| +--disable_parsing +show binlog events; +show storage engines; +show master status; +show slave hosts; +show slave status; +--enable_parsing + +call bug4902()| +call bug4902()| + +drop procedure bug4902| + +# We need separate SP for SHOW PROCESSLIST since we want use replace_column +--disable_warnings +drop procedure if exists bug4902_2| +--enable_warnings +create procedure bug4902_2() +begin + show processlist; +end| +--replace_column 1 # 6 # 3 localhost +call bug4902_2()| +--replace_column 1 # 6 # 3 localhost +call bug4902_2()| +drop procedure bug4902_2| + + +# +# BUG#5278: Stored procedure packets out of order if SET PASSWORD. +# +--disable_warnings +drop function if exists bug5278| +--enable_warnings +create function bug5278 () returns char +begin + SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass'); + return 'okay'; +end| + +--error 1133 +select bug5278()| +--error 1133 +select bug5278()| +drop function bug5278| + + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 ( + id char(16) not null default '', + data int not null +); +# +# BUG#3583: query cache doesn't work for stored procedures +# +--disable_warnings +drop procedure if exists bug3583| +--enable_warnings +--disable_warnings +drop procedure if exists bug3583| +--enable_warnings +create procedure bug3583() +begin + declare c int; + + select * from t1; + select count(*) into c from t1; + select c; +end| + +insert into t1 values ("x", 3), ("y", 5)| +set @x = @@query_cache_size| +set global query_cache_size = 10*1024*1024| + +flush status| +flush query cache| +show status like 'Qcache_hits'| +call bug3583()| +show status like 'Qcache_hits'| +call bug3583()| +call bug3583()| +show status like 'Qcache_hits'| + +set global query_cache_size = @x| +flush status| +flush query cache| +delete from t1| +drop procedure bug3583| +drop table t1; + +# +# BUG#6807: Stored procedure crash if CREATE PROCEDURE ... KILL QUERY +# +--disable_warnings +drop procedure if exists bug6807| +--enable_warnings +create procedure bug6807() +begin + declare id int; + + set id = connection_id(); + kill query id; + select 'Not reached'; +end| + +--error 1317 +call bug6807()| +--error 1317 +call bug6807()| + +drop procedure bug6807| + +# +# BUG#10100: function (and stored procedure?) recursivity problem +# +--disable_warnings +drop function if exists bug10100f| +drop procedure if exists bug10100p| +drop procedure if exists bug10100t| +drop procedure if exists bug10100pt| +drop procedure if exists bug10100pv| +drop procedure if exists bug10100pd| +drop procedure if exists bug10100pc| +--enable_warnings +# routines with simple recursion +create function bug10100f(prm int) returns int +begin + if prm > 1 then + return prm * bug10100f(prm - 1); + end if; + return 1; +end| +create procedure bug10100p(prm int, inout res int) +begin + set res = res * prm; + if prm > 1 then + call bug10100p(prm - 1, res); + end if; +end| +create procedure bug10100t(prm int) +begin + declare res int; + set res = 1; + call bug10100p(prm, res); + select res; +end| + +# a procedure which use tables and recursion +create table t3 (a int)| +insert into t3 values (0)| +create view v1 as select a from t3; +create procedure bug10100pt(level int, lim int) +begin + if level < lim then + update t3 set a=level; + FLUSH TABLES; + call bug10100pt(level+1, lim); + else + select * from t3; + end if; +end| +# view & recursion +create procedure bug10100pv(level int, lim int) +begin + if level < lim then + update v1 set a=level; + FLUSH TABLES; + call bug10100pv(level+1, lim); + else + select * from v1; + end if; +end| +# dynamic sql & recursion +prepare stmt2 from "select * from t3;"; +create procedure bug10100pd(level int, lim int) +begin + if level < lim then + select level; + prepare stmt1 from "update t3 set a=a+2"; + execute stmt1; + FLUSH TABLES; + execute stmt1; + FLUSH TABLES; + execute stmt1; + FLUSH TABLES; + deallocate prepare stmt1; + execute stmt2; + select * from t3; + call bug10100pd(level+1, lim); + else + execute stmt2; + end if; +end| +# cursor & recursion +create procedure bug10100pc(level int, lim int) +begin + declare lv int; + declare c cursor for select a from t3; + open c; + if level < lim then + select level; + fetch c into lv; + select lv; + update t3 set a=level+lv; + FLUSH TABLES; + call bug10100pc(level+1, lim); + else + select * from t3; + end if; + close c; +end| + +#end of the stack checking +set @@max_sp_recursion_depth=255| +set @var=1| +#disable log because error about stack overrun contains numbers which +#depend on a system +-- disable_result_log +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100p(255, @var)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pt(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pv(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pd(1,255)| +-- error ER_STACK_OVERRUN_NEED_MORE +call bug10100pc(1,255)| +-- enable_result_log +set @@max_sp_recursion_depth=0| + +deallocate prepare stmt2| + +drop function bug10100f| +drop procedure bug10100p| +drop procedure bug10100t| +drop procedure bug10100pt| +drop procedure bug10100pv| +drop procedure bug10100pd| +drop procedure bug10100pc| +drop view v1| + +delimiter ;| diff --git a/mysql-test/t/subselect_notembedded.test b/mysql-test/t/subselect_notembedded.test new file mode 100644 index 00000000000..c5b23f6dac8 --- /dev/null +++ b/mysql-test/t/subselect_notembedded.test @@ -0,0 +1,8 @@ +-- source include/not_embedded.inc + +# +# BUG #10308: purge log with subselect +# + +purge master logs before (select adddate(current_timestamp(), interval -4 day)); + diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 3a0e33f6aae..957b74b9c8c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2084,7 +2084,9 @@ drop table t1, t2; # -- error ER_MALFORMED_DEFINER create definer=some_user@`` sql security invoker view v1 as select 1; +--disable_warnings create definer=some_user@localhost sql security invoker view v1 as select 1; +--enable_warnings show create view v1; drop view v1; diff --git a/mysql-test/t/wait_timeout.test b/mysql-test/t/wait_timeout.test index 26f91569868..4c1aeee5c04 100644 --- a/mysql-test/t/wait_timeout.test +++ b/mysql-test/t/wait_timeout.test @@ -1,3 +1,6 @@ +# This tests not performed with embedded server +-- source include/not_embedded.inc + # # Bug #8731: wait_timeout does not work on Mac OS X # diff --git a/sql-common/client.c b/sql-common/client.c index 4c2debd41ff..8e55cf7c2b7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1545,7 +1545,8 @@ static MYSQL_METHODS client_methods= NULL, cli_read_statistics, cli_read_query_result, - cli_read_change_user_result + cli_read_change_user_result, + cli_read_binary_rows #endif }; @@ -2339,8 +2340,9 @@ static void mysql_close_free(MYSQL *mysql) my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->info_buffer,MYF(MY_ALLOW_ZERO_PTR)); /* Clear pointers for better safety */ - mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; + mysql->info_buffer=mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; } @@ -2476,8 +2478,7 @@ get_info: if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) mysql->server_status|= SERVER_STATUS_IN_TRANS; - if (!(fields=(*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0, - protocol_41(mysql) ? 7 : 5))) + if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) DBUG_RETURN(1); if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, (uint) field_count,0, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2a51afbee8d..3682f16613f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2449,9 +2449,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) { NET *net= &thd->net; net->report_error= 1; -#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/ query_cache_abort(net); -#endif if (!net->last_error[0]) // Return only first message { strmake(net->last_error, str, sizeof(net->last_error)-1); diff --git a/sql/protocol.cc b/sql/protocol.cc index 0a1b42f5236..98cded56871 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -29,6 +29,7 @@ static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; static void write_eof_packet(THD *thd, NET *net); +void net_send_error_packet(THD *thd, uint sql_errno, const char *err); #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const char *from, uint length) @@ -56,10 +57,6 @@ bool Protocol_prep::net_store_data(const char *from, uint length) void net_send_error(THD *thd, uint sql_errno, const char *err) { -#ifndef EMBEDDED_LIBRARY - uint length; - char buff[MYSQL_ERRMSG_SIZE+2], *pos; -#endif NET *net= &thd->net; bool generate_warning= thd->killed != THD::KILL_CONNECTION; DBUG_ENTER("net_send_error"); @@ -106,42 +103,8 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err); } -#ifdef EMBEDDED_LIBRARY - net->last_errno= sql_errno; - strmake(net->last_error, err, sizeof(net->last_error)-1); - strmov(net->sqlstate, mysql_errno_to_sqlstate(sql_errno)); -#else - - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* In bootstrap it's ok to print on stderr */ - fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); - } - DBUG_VOID_RETURN; - } + net_send_error_packet(thd, sql_errno, err); - if (net->return_errno) - { // new client code; Add errno before message - int2store(buff,sql_errno); - pos= buff+2; - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - /* The first # is to make the protocol backward compatible */ - buff[2]= '#'; - pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno)); - } - length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff); - err=buff; - } - else - { - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - } - VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); -#endif /* EMBEDDED_LIBRARY*/ thd->is_fatal_error=0; // Error message is given thd->net.report_error= 0; @@ -430,6 +393,47 @@ bool send_old_password_request(THD *thd) return my_net_write(net, eof_buff, 1) || net_flush(net); } + +void net_send_error_packet(THD *thd, uint sql_errno, const char *err) +{ + NET *net= &thd->net; + uint length; + char buff[MYSQL_ERRMSG_SIZE+2], *pos; + + DBUG_ENTER("send_error_packet"); + + if (net->vio == 0) + { + if (thd->bootstrap) + { + /* In bootstrap it's ok to print on stderr */ + fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); + } + DBUG_VOID_RETURN; + } + + if (net->return_errno) + { // new client code; Add errno before message + int2store(buff,sql_errno); + pos= buff+2; + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + /* The first # is to make the protocol backward compatible */ + buff[2]= '#'; + pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno)); + } + length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff); + err=buff; + } + else + { + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + } + VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); + DBUG_VOID_RETURN; +} + #endif /* EMBEDDED_LIBRARY */ /* diff --git a/sql/protocol.h b/sql/protocol.h index 8d9da5774b2..85c22724b74 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -91,6 +91,12 @@ public: virtual bool store_date(TIME *time)=0; virtual bool store_time(TIME *time)=0; virtual bool store(Field *field)=0; +#ifdef EMBEDDED_LIBRARY + int begin_dataset(); + virtual void remove_last_row() {} +#else + void remove_last_row() {} +#endif }; @@ -117,6 +123,9 @@ public: virtual bool store(float nr, uint32 decimals, String *buffer); virtual bool store(double from, uint32 decimals, String *buffer); virtual bool store(Field *field); +#ifdef EMBEDDED_LIBRARY + void remove_last_row(); +#endif }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 08d89228a72..4644145c856 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -951,7 +951,9 @@ bool select_send::send_data(List<Item> &items) thd->sent_row_count++; if (!thd->vio_ok()) DBUG_RETURN(0); - if (!thd->net.report_error) + if (thd->net.report_error) + protocol->remove_last_row(); + else DBUG_RETURN(protocol->write()); DBUG_RETURN(1); } @@ -1983,10 +1985,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, cuted_fields= 0; transaction.savepoints= 0; -#ifndef EMBEDDED_LIBRARY /* Surpress OK packets in case if we will execute statements */ net.no_send_ok= TRUE; -#endif } diff --git a/sql/sql_class.h b/sql/sql_class.h index 1ef3322bc8f..fc31742240b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -801,13 +801,16 @@ public: #ifdef EMBEDDED_LIBRARY struct st_mysql *mysql; - struct st_mysql_data *data; unsigned long client_stmt_id; unsigned long client_param_count; struct st_mysql_bind *client_params; char *extra_data; ulong extra_length; - String query_rest; + struct st_mysql_data *cur_data; + struct st_mysql_data *first_data; + struct st_mysql_data **data_tail; + void clear_data_list(); + struct st_mysql_data *alloc_new_dataset(); #endif NET net; // client connection descriptor MEM_ROOT warn_root; // For warnings and errors @@ -1441,6 +1444,11 @@ public: */ virtual void cleanup(); void set_thd(THD *thd_arg) { thd= thd_arg; } +#ifdef EMBEDDED_LIBRARY + virtual void begin_dataset() {} +#else + void begin_dataset() {} +#endif }; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 89c160cd70a..33ad27b9d14 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -603,6 +603,7 @@ void Materialized_cursor::fetch(ulong num_rows) THD *thd= table->in_use; int res= 0; + result->begin_dataset(); for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++) { if ((res= table->file->rnd_next(table->record[0]))) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4def568635d..5a3d25f9de7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1713,13 +1713,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, net->no_send_error= 0; /* Multiple queries exits, execute them individually - in embedded server - just store them to be executed later */ -#ifndef EMBEDDED_LIBRARY if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) close_thread_tables(thd); -#endif ulong length= (ulong)(packet_end-packet); log_slow_statement(thd); @@ -1737,25 +1734,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ VOID(pthread_mutex_unlock(&LOCK_thread_count)); -#ifndef EMBEDDED_LIBRARY mysql_parse(thd, packet, length); -#else - /* - 'packet' can point inside the query_rest's buffer - so we have to do memmove here - */ - if (thd->query_rest.length() > length) - { - memmove(thd->query_rest.c_ptr(), packet, length); - thd->query_rest.length(length); - } - else - thd->query_rest.copy(packet, length, thd->query_rest.charset()); - - thd->server_status&= ~ (SERVER_QUERY_NO_INDEX_USED | - SERVER_QUERY_NO_GOOD_INDEX_USED); - break; -#endif /*EMBEDDED_LIBRARY*/ } if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -4242,10 +4221,8 @@ end_with_restore_list: goto error; } -#ifndef EMBEDDED_LIBRARY my_bool nsok= thd->net.no_send_ok; thd->net.no_send_ok= TRUE; -#endif if (sp->m_flags & sp_head::MULTI_RESULTS) { if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS)) @@ -4255,9 +4232,7 @@ end_with_restore_list: back */ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); -#ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; -#endif goto error; } /* @@ -4274,18 +4249,14 @@ end_with_restore_list: sp->m_db.str, sp->m_name.str, TRUE, 0) || sp_change_security_context(thd, sp, &save_ctx)) { -#ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; -#endif goto error; } if (save_ctx && check_routine_access(thd, EXECUTE_ACL, sp->m_db.str, sp->m_name.str, TRUE, 0)) { -#ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; -#endif sp_restore_security_context(thd, save_ctx); goto error; } @@ -4317,9 +4288,7 @@ end_with_restore_list: sp_restore_security_context(thd, save_ctx); #endif -#ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; -#endif thd->server_status&= ~bits_to_be_cleared; if (!res) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 7b35f057217..78487dd965d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -92,6 +92,12 @@ public: virtual bool send_fields(List<Item> &list, uint flags); virtual bool send_data(List<Item> &items); virtual bool send_eof(); +#ifdef EMBEDDED_LIBRARY + void begin_dataset() + { + protocol.begin_dataset(); + } +#endif }; /****************************************************************************** @@ -524,9 +530,10 @@ void set_param_time(Item_param *param, uchar **pos, ulong len) void set_param_datetime(Item_param *param, uchar **pos, ulong len) { - MYSQL_TIME *to= (MYSQL_TIME*)*pos; + MYSQL_TIME tm= *((MYSQL_TIME*)*pos); + tm.neg= 0; - param->set_time(to, MYSQL_TIMESTAMP_DATETIME, + param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME, MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); } |