diff options
author | unknown <monty@mysql.com> | 2006-02-24 18:34:15 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2006-02-24 18:34:15 +0200 |
commit | 0afb6ff66082f64c7c0aea62662e4c03e7c987c5 (patch) | |
tree | 603ae9081a58d9f7bb204327f65d4a8af4425b28 /libmysqld | |
parent | ef1316fadda7b7d8c1b00de6d82576ebc21607cc (diff) | |
download | mariadb-git-0afb6ff66082f64c7c0aea62662e4c03e7c987c5.tar.gz |
Fixes to embedded server to be able to run tests with it
(Needed for "list of pushes" web page and autopush)
include/mysql.h:
Fix to embedded server to be able to run tests on it
libmysql/libmysql.c:
Fix to embedded server to be able to run tests on it
libmysqld/emb_qcache.cc:
Fix to embedded server to be able to run tests on it
libmysqld/embedded_priv.h:
Fix to embedded server to be able to run tests on it
libmysqld/lib_sql.cc:
Fix to embedded server to be able to run tests on it
libmysqld/libmysqld.c:
Fix to embedded server to be able to run tests on it
mysql-test/mysql-test-run.sh:
Fix to embedded server to be able to run tests on it
mysql-test/r/binlog.result:
Updated test for embedded server
mysql-test/r/ctype_cp932.result:
Updated test for embedded server
mysql-test/r/innodb.result:
Updated test for embedded server
mysql-test/r/mysqltest.result:
Updated test for embedded server
mysql-test/r/query_cache.result:
Updated test for embedded server
mysql-test/r/query_cache_notembedded.result:
Updated test for embedded server
mysql-test/r/sp-error.result:
Updated test for embedded server
mysql-test/r/sp.result:
Updated test for embedded server
mysql-test/r/subselect.result:
Updated test for embedded server
mysql-test/r/view.result:
Updated test for embedded server
mysql-test/r/view_grant.result:
Updated test for embedded server
mysql-test/t/backup.test:
Updated test for embedded server
mysql-test/t/binlog.test:
Updated test for embedded server
mysql-test/t/blackhole.test:
Updated test for embedded server
mysql-test/t/compress.test:
Updated test for embedded server
mysql-test/t/ctype_cp932.test:
Updated test for embedded server
mysql-test/t/delayed.test:
Updated test for embedded server
mysql-test/t/handler.test:
Updated test for embedded server
mysql-test/t/innodb.test:
Updated test for embedded server
mysql-test/t/mysql.test:
Updated test for embedded server
mysql-test/t/mysql_client_test.test:
Updated test for embedded server
mysql-test/t/mysqltest.test:
Updated test for embedded server
mysql-test/t/query_cache.test:
Updated test for embedded server
mysql-test/t/query_cache_notembedded.test:
Updated test for embedded server
mysql-test/t/read_only.test:
Updated test for embedded server
mysql-test/t/skip_grants.test:
Updated test for embedded server
mysql-test/t/sp-destruct.test:
Updated test for embedded server
mysql-test/t/sp-error.test:
Updated test for embedded server
mysql-test/t/sp-threads.test:
Updated test for embedded server
mysql-test/t/sp.test:
Updated test for embedded server
mysql-test/t/subselect.test:
Updated test for embedded server
mysql-test/t/temp_table.test:
Updated test for embedded server
mysql-test/t/view.test:
Updated test for embedded server
mysql-test/t/view_grant.test:
Updated test for embedded server
mysql-test/t/wait_timeout.test:
Updated test for embedded server
mysys/mf_dirname.c:
Review fix: Don't access data outside of array
mysys/my_bitmap.c:
Remove compiler warnings
scripts/mysql_fix_privilege_tables.sql:
Add flush privileges to .sql script so that one doesn't have to reboot mysqld when one runs the mysql_fix_privilege_script
sql-common/client.c:
Updated test for embedded server
sql/item.cc:
Remove DBUG_PRINT statement that can cause crashes when running with --debug
sql/mysqld.cc:
Fix to embedded server to be able to run tests on it
sql/protocol.cc:
Fix to embedded server to be able to run tests on it
(Trivial reconstruction of code)
sql/protocol.h:
Fix to embedded server to be able to run tests on it
sql/sql_base.cc:
Better comment
sql/sql_class.cc:
Fix to embedded server to be able to run tests on it
sql/sql_class.h:
Fix to embedded server to be able to run tests on it
sql/sql_cursor.cc:
Fix to embedded server to be able to run tests on it
sql/sql_parse.cc:
Fix to embedded server to be able to run tests on it
Don't crash for disabled commands when using embedded server
sql/sql_prepare.cc:
Fix to embedded server to be able to run tests on it
mysql-test/r/ctype_cp932_notembedded.result:
New BitKeeper file ``mysql-test/r/ctype_cp932_notembedded.result''
mysql-test/r/innodb_notembedded.result:
New BitKeeper file ``mysql-test/r/innodb_notembedded.result''
mysql-test/r/sp.result.orig:
New BitKeeper file ``mysql-test/r/sp.result.orig''
mysql-test/r/sp_notembedded.result:
New BitKeeper file ``mysql-test/r/sp_notembedded.result''
mysql-test/r/subselect_notembedded.result:
New BitKeeper file ``mysql-test/r/subselect_notembedded.result''
mysql-test/t/ctype_cp932_notembedded.test:
New BitKeeper file ``mysql-test/t/ctype_cp932_notembedded.test''
mysql-test/t/innodb_notembedded.test:
New BitKeeper file ``mysql-test/t/innodb_notembedded.test''
mysql-test/t/sp.test.orig:
New BitKeeper file ``mysql-test/t/sp.test.orig''
mysql-test/t/sp_notembedded.test:
New BitKeeper file ``mysql-test/t/sp_notembedded.test''
mysql-test/t/subselect_notembedded.test:
New BitKeeper file ``mysql-test/t/subselect_notembedded.test''
Diffstat (limited to 'libmysqld')
-rw-r--r-- | libmysqld/emb_qcache.cc | 129 | ||||
-rw-r--r-- | libmysqld/embedded_priv.h | 21 | ||||
-rw-r--r-- | libmysqld/lib_sql.cc | 512 | ||||
-rw-r--r-- | libmysqld/libmysqld.c | 14 |
4 files changed, 462 insertions, 214 deletions
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..e4c9d8cb4e9 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"); @@ -517,9 +615,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 +630,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 +719,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 +867,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 +931,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 +953,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 +966,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 +977,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 +1031,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)); { |