Big patch to make embedded-server working in 5.x

Now it supports queries returning several results
(particularly important with the SP)
This commit is contained in:
holyfoot@deer.(none) 2006-01-04 14:20:28 +04:00
parent 795f744c5f
commit e8697cf428
46 changed files with 1031 additions and 465 deletions

View File

@ -130,14 +130,14 @@ typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
#include "my_alloc.h" #include "my_alloc.h"
typedef struct embedded_query_result EMBEDDED_QUERY_RESULT;
typedef struct st_mysql_data { typedef struct st_mysql_data {
my_ulonglong rows; my_ulonglong rows;
unsigned int fields; unsigned int fields;
MYSQL_ROWS *data; MYSQL_ROWS *data;
MEM_ROOT alloc; MEM_ROOT alloc;
#if !defined(CHECK_EMBEDDED_DIFFERENCES) || defined(EMBEDDED_LIBRARY) /* extra info for embedded library */
MYSQL_ROWS **prev_ptr; struct embedded_query_result *embedded_info;
#endif
} MYSQL_DATA; } MYSQL_DATA;
enum mysql_option 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. from mysql_stmt_close if close had to cancel result set of this object.
*/ */
my_bool *unbuffered_fetch_owner; my_bool *unbuffered_fetch_owner;
/* needed for embedded server - no net buffer to store the 'info' */
char *info_buffer;
} MYSQL; } MYSQL;
typedef struct st_mysql_res { typedef struct st_mysql_res {
@ -755,6 +757,7 @@ typedef struct st_mysql_methods
const char *(*read_statistics)(MYSQL *mysql); const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql); my_bool (*next_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd); int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
#endif #endif
} MYSQL_METHODS; } MYSQL_METHODS;

View File

@ -2722,13 +2722,13 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
/* Send row request to the server */ /* Send row request to the server */
int4store(buff, stmt->stmt_id); int4store(buff, stmt->stmt_id);
int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */
if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff), if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
NullS, 0, 1)) buff, sizeof(buff), NullS, 0, 1))
{ {
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
return 1; return 1;
} }
if (cli_read_binary_rows(stmt)) if ((*mysql->methods->read_rows_from_cursor)(stmt))
return 1; return 1;
stmt->server_status= mysql->server_status; 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_ENTER("mysql_autocommit");
DBUG_PRINT("enter", ("mode : %d", auto_mode)); DBUG_PRINT("enter", ("mode : %d", auto_mode));
if (auto_mode) /* set to true */ DBUG_RETURN((my_bool) mysql_real_query(mysql, auto_mode ?
DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=1", 16)); "set autocommit=1":"set autocommit=0",
DBUG_RETURN((my_bool) mysql_real_query(mysql, "set autocommit=0", 16)); 16));
} }

View File

@ -18,6 +18,7 @@
#ifdef HAVE_QUERY_CACHE #ifdef HAVE_QUERY_CACHE
#include <mysql.h> #include <mysql.h>
#include "emb_qcache.h" #include "emb_qcache.h"
#include "embedded_priv.h"
void Querycache_stream::store_char(char c) 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 emb_count_querycache_size(THD *thd)
{ {
uint result; uint result= 0;
MYSQL *mysql= thd->mysql; MYSQL_FIELD *field;
MYSQL_FIELD *field= mysql->fields; MYSQL_FIELD *field_end;
MYSQL_FIELD *field_end= field + mysql->field_count; MYSQL_ROWS *cur_row;
MYSQL_ROWS *cur_row=NULL; my_ulonglong n_rows;
my_ulonglong n_rows=0; 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) if (!field)
return 0; return result;
if (thd->data) *data->embedded_info->prev_ptr= NULL; // this marks the last record
{ cur_row= data->data;
*thd->data->prev_ptr= NULL; // this marks the last record n_rows= data->rows;
cur_row= thd->data->data; /* n_fields + n_rows + (field_info + strlen * n_rows) * n_fields */
n_rows= thd->data->rows; result+= (uint) (4+8 + (42 + 4*n_rows)*data->fields);
}
result= (uint) (4+8 + (42 + 4*n_rows)*mysql->field_count);
for(; field < field_end; field++) for(; field < field_end; field++)
{ {
@ -313,34 +317,38 @@ uint emb_count_querycache_size(THD *thd)
for (; cur_row; cur_row=cur_row->next) for (; cur_row; cur_row=cur_row->next)
{ {
MYSQL_ROW col= cur_row->data; 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++) for (; col < col_end; col++)
if (*col) if (*col)
result+= *(uint *)((*col) - sizeof(uint)); result+= *(uint *)((*col) - sizeof(uint));
} }
return result; return result;
} }
void emb_store_querycache_result(Querycache_stream *dst, THD *thd) void emb_store_querycache_result(Querycache_stream *dst, THD *thd)
{ {
MYSQL *mysql= thd->mysql; MYSQL_FIELD *field;
MYSQL_FIELD *field= mysql->fields; MYSQL_FIELD *field_end;
MYSQL_FIELD *field_end= field + mysql->field_count; MYSQL_ROWS *cur_row;
MYSQL_ROWS *cur_row= NULL; my_ulonglong n_rows;
my_ulonglong n_rows= 0; 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) if (!field)
return; DBUG_VOID_RETURN;
if (thd->data) *data->embedded_info->prev_ptr= NULL; // this marks the last record
{ cur_row= data->data;
*thd->data->prev_ptr= NULL; // this marks the last record n_rows= data->rows;
cur_row= thd->data->data;
n_rows= thd->data->rows;
}
dst->store_int((uint)mysql->field_count); dst->store_int((uint)data->fields);
dst->store_ll((uint)n_rows); dst->store_ll((ulonglong)n_rows);
for(; field < field_end; field++) 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->org_table, field->org_table_length);
dst->store_str(field->db, field->db_length); dst->store_str(field->db, field->db_length);
dst->store_str(field->catalog, field->catalog_length); dst->store_str(field->catalog, field->catalog_length);
dst->store_safe_str(field->def, field->def_length); dst->store_safe_str(field->def, field->def_length);
} }
for (; cur_row; cur_row=cur_row->next) for (; cur_row; cur_row=cur_row->next)
{ {
MYSQL_ROW col= cur_row->data; 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++) for (; col < col_end; col++)
{ {
uint len= *col ? *(uint *)((*col) - sizeof(uint)) : 0; 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_ASSERT(emb_count_querycache_size(thd) == dst->stored_size);
DBUG_VOID_RETURN;
} }
int emb_load_querycache_result(THD *thd, Querycache_stream *src) int emb_load_querycache_result(THD *thd, Querycache_stream *src)
{ {
MYSQL *mysql= thd->mysql; MYSQL_DATA *data= thd->alloc_new_dataset();
MYSQL_DATA *data;
MYSQL_FIELD *field; MYSQL_FIELD *field;
MYSQL_FIELD *field_end; MYSQL_FIELD *field_end;
MEM_ROOT *f_alloc= &mysql->field_alloc; MEM_ROOT *f_alloc;
MYSQL_ROWS *row, *end_row; MYSQL_ROWS *row, *end_row;
MYSQL_ROWS **prev_row; MYSQL_ROWS **prev_row;
ulonglong rows; ulonglong rows;
MYSQL_ROW columns; MYSQL_ROW columns;
DBUG_ENTER("emb_load_querycache_result");
mysql->field_count= src->load_int(); if (!data)
goto err;
init_alloc_root(&data->alloc, 8192,0);
f_alloc= &data->alloc;
data->fields= src->load_int();
rows= src->load_ll(); rows= src->load_ll();
if (!(field= (MYSQL_FIELD *) 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; goto err;
mysql->fields= field; data->embedded_info->fields_list= field;
for(field_end= field+mysql->field_count; field < field_end; field++) for(field_end= field+data->fields; field < field_end; field++)
{ {
field->length= src->load_int(); field->length= src->load_int();
field->max_length= (unsigned int)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(); field->decimals= (unsigned int)src->load_char();
if (!(field->name= src->load_str(f_alloc, &field->name_length)) || if (!(field->name= src->load_str(f_alloc, &field->name_length)) ||
!(field->table= src->load_str(f_alloc,&field->table_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_name= src->load_str(f_alloc, &field->org_name_length)) ||
!(field->org_table= src->load_str(f_alloc, &field->org_table_length))|| !(field->org_table= src->load_str(f_alloc, &field->org_table_length))||
!(field->db= src->load_str(f_alloc, &field->db_length)) || !(field->db= src->load_str(f_alloc, &field->db_length)) ||
!(field->catalog= src->load_str(f_alloc, &field->catalog_length)) || !(field->catalog= src->load_str(f_alloc, &field->catalog_length)) ||
src->load_safe_str(f_alloc, &field->def, &field->def_length)) src->load_safe_str(f_alloc, &field->def, &field->def_length))
goto err; goto err;
} }
if (!rows) row= (MYSQL_ROWS *)alloc_root(&data->alloc,
return 0; (uint) (rows * sizeof(MYSQL_ROWS) +
if (!(data= (MYSQL_DATA*)my_malloc(sizeof(MYSQL_DATA), rows*(data->fields+1)*sizeof(char*)));
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*)));
end_row= row + rows; end_row= row + rows;
columns= (MYSQL_ROW)end_row; columns= (MYSQL_ROW)end_row;
data->rows= rows; data->rows= rows;
data->fields= mysql->field_count;
data->data= row; data->data= row;
if (!rows)
goto return_ok;
for (prev_row= &row->next; row < end_row; prev_row= &row->next, row++) for (prev_row= &row->next; row < end_row; prev_row= &row->next, row++)
{ {
*prev_row= row; *prev_row= row;
row->data= columns; row->data= columns;
MYSQL_ROW col_end= columns + mysql->field_count; MYSQL_ROW col_end= columns + data->fields;
for (; columns < col_end; columns++) for (; columns < col_end; columns++)
src->load_column(&data->alloc, columns); src->load_column(&data->alloc, columns);
*(columns++)= NULL; *(columns++)= NULL;
} }
*prev_row= NULL; *prev_row= NULL;
data->prev_ptr= prev_row; data->embedded_info->prev_ptr= prev_row;
return_ok:
return 0; send_eof(thd);
DBUG_RETURN(0);
err: err:
return 1; DBUG_RETURN(1);
} }
#endif /*HAVE_QUERY_CACHE*/ #endif /*HAVE_QUERY_CACHE*/

View File

@ -16,18 +16,25 @@
/* Prototypes for the embedded version of MySQL */ /* 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 C_MODE_START
void lib_connection_phase(NET *net, int phase); void lib_connection_phase(NET *net, int phase);
void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db); void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db);
void *create_embedded_thd(int client_flag, char *db); void *create_embedded_thd(int client_flag, char *db);
int check_embedded_connection(MYSQL *mysql); int check_embedded_connection(MYSQL *mysql);
void free_old_query(MYSQL *mysql); void free_old_query(MYSQL *mysql);
void embedded_get_error(MYSQL *mysql);
extern MYSQL_METHODS embedded_methods; 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 C_MODE_END

View File

@ -42,21 +42,48 @@ C_MODE_START
#undef ER #undef ER
#include "errmsg.h" #include "errmsg.h"
#include <sql_common.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()
{
while (first_data)
{
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)
{ {
THD *thd=(THD *) mysql->thd;
NET *net= &mysql->net; NET *net= &mysql->net;
if ((net->last_errno= thd->net.last_errno)) struct embedded_query_result *ei= data->embedded_info;
{ net->last_errno= ei->last_errno;
memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error)); strmake(net->last_error, ei->info, sizeof(net->last_error));
memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate)); memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
} my_free((gptr) data, MYF(0));
else
{
net->last_error[0]= 0;
strmov(net->sqlstate, not_error_sqlstate);
}
} }
static my_bool static my_bool
@ -68,11 +95,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
THD *thd=(THD *) mysql->thd; THD *thd=(THD *) mysql->thd;
NET *net= &mysql->net; NET *net= &mysql->net;
if (thd->data) thd->clear_data_list();
{
free_rows(thd->data);
thd->data= 0;
}
/* Check that we are calling the client functions in right order */ /* Check that we are calling the client functions in right order */
if (mysql->status != MYSQL_STATUS_READY) if (mysql->status != MYSQL_STATUS_READY)
{ {
@ -104,83 +127,101 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
arg_length= header_length; arg_length= header_length;
} }
thd->net.no_send_error= 0;
result= dispatch_command(command, thd, (char *) arg, arg_length + 1); result= dispatch_command(command, thd, (char *) arg, arg_length + 1);
thd->cur_data= 0;
if (!skip_check) if (!skip_check)
result= thd->net.last_errno ? -1 : 0; 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; return result;
} }
static void emb_flush_use_result(MYSQL *mysql) static void emb_flush_use_result(MYSQL *mysql)
{ {
MYSQL_DATA *data= ((THD*)(mysql->thd))->data; THD *thd= (THD*) mysql->thd;
if (thd->cur_data)
if (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); 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 * static MYSQL_DATA *
emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)), emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
unsigned int fields __attribute__((unused))) unsigned int fields __attribute__((unused)))
{ {
MYSQL_DATA *result= ((THD*)mysql->thd)->data; MYSQL_DATA *result= ((THD*)mysql->thd)->cur_data;
embedded_get_error(mysql); ((THD*)mysql->thd)->cur_data= 0;
if (mysql->net.last_errno) if (result->embedded_info->last_errno)
return NULL;
if (!result)
{ {
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), embedded_get_error(mysql, result);
MYF(MY_WME | MY_ZEROFILL)))) return NULL;
{
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; *result->embedded_info->prev_ptr= NULL;
((THD*)mysql->thd)->data= NULL;
return result; return result;
} }
static MYSQL_FIELD *emb_list_fields(MYSQL *mysql) 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; return mysql->fields;
} }
static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
{ {
THD *thd= (THD*)mysql->thd; THD *thd= (THD*) mysql->thd;
if (mysql->net.last_errno) MYSQL_DATA *res;
return 1;
stmt->stmt_id= thd->client_stmt_id; stmt->stmt_id= thd->client_stmt_id;
stmt->param_count= thd->client_param_count; 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)) if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->server_status|= SERVER_STATUS_IN_TRANS;
stmt->fields= mysql->fields; stmt->fields= mysql->fields;
stmt->mem_root= mysql->field_alloc; stmt->mem_root= res->alloc;
mysql->fields= NULL; mysql->fields= NULL;
my_free((gptr) res,MYF(0));
} }
return 0; return 0;
@ -201,13 +242,42 @@ static void emb_fetch_lengths(ulong *to, MYSQL_ROW column,
*to= *column ? *(uint *)((*column) - sizeof(uint)) : 0; *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) THD *thd= (THD*) mysql->thd;
return -1; 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;
}
if (mysql->field_count) 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 (res->embedded_info->fields_list)
{
mysql->status=MYSQL_STATUS_GET_RESULT; mysql->status=MYSQL_STATUS_GET_RESULT;
thd->cur_data= res;
}
else
my_free((gptr) res, MYF(0));
return 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) static int emb_stmt_execute(MYSQL_STMT *stmt)
{ {
DBUG_ENTER("emb_stmt_execute"); DBUG_ENTER("emb_stmt_execute");
char header[4]; char header[5];
MYSQL_DATA *res;
THD *thd;
int4store(header, stmt->stmt_id); 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_param_count= stmt->param_count;
thd->client_params= stmt->params; thd->client_params= stmt->params;
if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0, if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
header, sizeof(header), 1) || header, sizeof(header), 1) ||
emb_mysql_read_query_result(stmt->mysql)) emb_read_query_result(stmt->mysql))
{ {
NET *net= &stmt->mysql->net; NET *net= &stmt->mysql->net;
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); 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->affected_rows= stmt->mysql->affected_rows;
stmt->insert_id= stmt->mysql->insert_id; stmt->insert_id= stmt->mysql->insert_id;
stmt->server_status= stmt->mysql->server_status;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -240,22 +316,53 @@ int emb_read_binary_rows(MYSQL_STMT *stmt)
return 1; return 1;
stmt->result= *data; stmt->result= *data;
my_free((char *) data, MYF(0)); 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; 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) int emb_unbuffered_fetch(MYSQL *mysql, char **row)
{ {
MYSQL_DATA *data= ((THD*)mysql->thd)->data; THD *thd= (THD*) mysql->thd;
embedded_get_error(mysql); MYSQL_DATA *data= thd->cur_data;
if (mysql->net.last_errno) if (data && data->embedded_info->last_errno)
return mysql->net.last_errno; {
embedded_get_error(mysql, data);
thd->cur_data= 0;
return 1;
}
if (!data || !data->data) if (!data || !data->data)
{ {
*row= NULL; *row= NULL;
if (data) if (data)
{ {
thd->cur_data= thd->first_data;
thd->first_data= data->embedded_info->next;
free_rows(data); free_rows(data);
((THD*)mysql->thd)->data= NULL;
} }
} }
else else
@ -269,9 +376,9 @@ int emb_unbuffered_fetch(MYSQL *mysql, char **row)
static void emb_free_embedded_thd(MYSQL *mysql) static void emb_free_embedded_thd(MYSQL *mysql)
{ {
THD *thd= (THD*)mysql->thd; THD *thd= (THD*)mysql->thd;
if (thd->data) thd->clear_data_list();
free_rows(thd->data);
thread_count--; thread_count--;
thd->store_globals();
delete thd; delete thd;
mysql->thd=0; 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); 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, int emb_read_change_user_result(MYSQL *mysql,
char *buff __attribute__((unused)), char *buff __attribute__((unused)),
@ -310,10 +405,10 @@ int emb_read_change_user_result(MYSQL *mysql,
MYSQL_METHODS embedded_methods= MYSQL_METHODS embedded_methods=
{ {
emb_mysql_read_query_result, emb_read_query_result,
emb_advanced_command, emb_advanced_command,
emb_read_rows, emb_read_rows,
emb_mysql_store_result, emb_store_result,
emb_fetch_lengths, emb_fetch_lengths,
emb_flush_use_result, emb_flush_use_result,
emb_list_fields, emb_list_fields,
@ -323,8 +418,9 @@ MYSQL_METHODS embedded_methods=
emb_unbuffered_fetch, emb_unbuffered_fetch,
emb_free_embedded_thd, emb_free_embedded_thd,
emb_read_statistics, emb_read_statistics,
emb_next_result, emb_read_query_result,
emb_read_change_user_result emb_read_change_user_result,
emb_read_rows_from_cursor
}; };
C_MODE_END C_MODE_END
@ -483,6 +579,7 @@ void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db)
THD *thd = (THD *)mysql->thd; THD *thd = (THD *)mysql->thd;
thd->mysql= mysql; thd->mysql= mysql;
mysql->server_version= server_version; mysql->server_version= server_version;
init_alloc_root(&mysql->field_alloc, 8192, 0);
} }
void *create_embedded_thd(int client_flag, char *db) 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 * thd= new THD;
thd->thread_id= thread_id++; thd->thread_id= thread_id++;
thd->thread_stack= (char*) &thd;
if (thd->store_globals()) if (thd->store_globals())
{ {
fprintf(stderr,"store_globals failed.\n"); 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->mysys_var= my_thread_var;
thd->dbug_thread_id= my_thread_id(); thd->dbug_thread_id= my_thread_id();
thd->thread_stack= (char*) &thd;
/* TODO - add init_connect command execution */ /* 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->db_access= DB_ACLS;
thd->security_ctx->master_access= ~NO_ACCESS; thd->security_ctx->master_access= ~NO_ACCESS;
#endif #endif
thd->net.query_cache_query= 0; thd->cur_data= 0;
thd->first_data= 0;
thd->data= 0; thd->data_tail= &thd->first_data;
bzero((char*) &thd->net, sizeof(thd->net));
thread_count++; thread_count++;
return thd; return thd;
@ -531,11 +629,15 @@ err:
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
int check_embedded_connection(MYSQL *mysql) int check_embedded_connection(MYSQL *mysql)
{ {
int result;
THD *thd= (THD*)mysql->thd; THD *thd= (THD*)mysql->thd;
Security_context *sctx= thd->security_ctx; 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)); 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 #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) bool Protocol::send_fields(List<Item> *list, uint flags)
{ {
List_iterator_fast<Item> it(*list); List_iterator_fast<Item> it(*list);
Item *item; Item *item;
MYSQL_FIELD *client_field; MYSQL_FIELD *client_field;
MYSQL *mysql= thd->mysql;
MEM_ROOT *field_alloc; MEM_ROOT *field_alloc;
CHARSET_INFO *thd_cs= thd->variables.character_set_results; CHARSET_INFO *thd_cs= thd->variables.character_set_results;
CHARSET_INFO *cs= system_charset_info; CHARSET_INFO *cs= system_charset_info;
MYSQL_DATA *data;
DBUG_ENTER("send_fields"); DBUG_ENTER("send_fields");
if (!mysql) // bootstrap file handling if (!thd->mysql) // bootstrap file handling
DBUG_RETURN(0); DBUG_RETURN(0);
field_count= list->elements; if (begin_dataset())
field_alloc= &mysql->field_alloc; goto err;
if (!(client_field= thd->mysql->fields=
(MYSQL_FIELD *)alloc_root(field_alloc, data= thd->cur_data;
sizeof(MYSQL_FIELD) * field_count))) 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; goto err;
while ((item= it++)) while ((item= it++))
@ -643,6 +866,10 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
Send_field server_field; Send_field server_field;
item->make_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, client_field->db= dup_str_aux(field_alloc, server_field.db_name,
strlen(server_field.db_name), cs, thd_cs); strlen(server_field.db_name), cs, thd_cs);
client_field->table= dup_str_aux(field_alloc, server_field.table_name, 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->max_length= 0;
++client_field; ++client_field;
} }
thd->mysql->field_count= field_count;
if (flags & SEND_EOF)
write_eof_packet(thd);
DBUG_RETURN(prepare_for_send(list)); DBUG_RETURN(prepare_for_send(list));
err: err:
@ -723,25 +952,11 @@ bool Protocol::write()
bool Protocol_prep::write() bool Protocol_prep::write()
{ {
MYSQL_ROWS *cur; MYSQL_ROWS *cur;
MYSQL_DATA *data= thd->data; MYSQL_DATA *data= thd->cur_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;
}
data->rows++; 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)); my_error(ER_OUT_OF_RESOURCES,MYF(0));
return true; return true;
@ -750,8 +965,8 @@ bool Protocol_prep::write()
memcpy(cur->data, packet->ptr()+1, packet->length()-1); memcpy(cur->data, packet->ptr()+1, packet->length()-1);
cur->length= packet->length(); /* To allow us to do sanity checks */ cur->length= packet->length(); /* To allow us to do sanity checks */
*data->prev_ptr= cur; *data->embedded_info->prev_ptr= cur;
data->prev_ptr= &cur->next; data->embedded_info->prev_ptr= &cur->next;
cur->next= 0; cur->next= 0;
return false; return false;
@ -761,46 +976,52 @@ void
send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
{ {
DBUG_ENTER("send_ok"); DBUG_ENTER("send_ok");
MYSQL *mysql= current_thd->mysql; MYSQL_DATA *data;
MYSQL *mysql= thd->mysql;
if (!mysql) // bootstrap file handling if (!mysql) // bootstrap file handling
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
mysql->affected_rows= affected_rows; if (thd->net.no_send_ok) // hack for re-parsing queries
mysql->insert_id= id; 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) if (message)
{ strmake(data->embedded_info->info, message,
strmake(thd->net.last_error, message, sizeof(thd->net.last_error)-1); sizeof(data->embedded_info->info)-1);
mysql->info= thd->net.last_error;
} write_eof_packet(thd);
thd->cur_data= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
void void
send_eof(THD *thd) 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() void Protocol_simple::prepare_for_resend()
{ {
MYSQL_ROWS *cur; MYSQL_ROWS *cur;
MYSQL_DATA *data= thd->data; MYSQL_DATA *data= thd->cur_data;
DBUG_ENTER("send_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++; data->rows++;
if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+(field_count + 1) * sizeof(char *)))) 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)); cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS));
*data->prev_ptr= cur; *data->embedded_info->prev_ptr= cur;
data->prev_ptr= &cur->next; data->embedded_info->prev_ptr= &cur->next;
next_field=cur->data; next_field=cur->data;
next_mysql_field= thd->mysql->fields; next_mysql_field= data->embedded_info->fields_list;
err: err:
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -14,6 +14,11 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 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 "embedded_priv.h"
#include <my_sys.h> #include <my_sys.h>
#include <mysys_err.h> #include <mysys_err.h>
@ -193,7 +198,12 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
if (!user) if (!user)
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; port=0;
unix_socket=0; unix_socket=0;
@ -207,6 +217,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
if (db) if (db)
client_flag|=CLIENT_CONNECT_WITH_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); mysql->thd= create_embedded_thd(client_flag, db_name);
init_embedded_mysql(mysql, 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); DBUG_RETURN(mysql);
error: error:
embedded_get_error(mysql);
DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno, DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno,
mysql->net.last_error)); mysql->net.last_error));
{ {

View File

@ -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 # This test is a bit tricky as we can't use backup table to overwrite an old
# table # table

View File

@ -1,5 +1,6 @@
# This is a wrapper for binlog.test so that the same test case can be used # 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] # 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 include/have_binlog_format_statement.inc
-- source extra/binlog_tests/binlog.test -- source extra/binlog_tests/binlog.test

View File

@ -1,5 +1,6 @@
# This is a wrapper for binlog.test so that the same test case can be used # 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] # 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 include/have_binlog_format_statement.inc
-- source extra/binlog_tests/blackhole.test -- source extra/binlog_tests/blackhole.test

View File

@ -1,5 +1,6 @@
# This is a wrapper for binlog.test so that the same test case can be used # 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] # 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 include/have_binlog_format_statement.inc
-- source extra/binlog_tests/ctype_cp932.test -- source extra/binlog_tests/ctype_cp932.test

View File

@ -1,6 +1,9 @@
# Turn on compression between the client and server # Turn on compression between the client and server
# and run a number of tests # and run a number of tests
# Can't test with embedded server
-- source include/not_embedded.inc
-- source include/have_compress.inc -- source include/have_compress.inc
connect (comp_con,localhost,root,,,,,COMPRESS); connect (comp_con,localhost,root,,,,,COMPRESS);

View File

@ -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

View File

@ -3,6 +3,9 @@
# (Can't be tested with purify :( ) # (Can't be tested with purify :( )
# #
# This tests not performed with embedded server
-- source include/not_embedded.inc
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1;
--enable_warnings --enable_warnings

View File

@ -1,3 +1,5 @@
# should work with embedded server after mysqltest is fixed
-- source include/not_embedded.inc
source include/federated.inc; source include/federated.inc;
connection slave; connection slave;

View File

@ -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/have_archive.inc;
source include/federated.inc; source include/federated.inc;

View File

@ -1,3 +1,5 @@
# should work with embedded server after mysqltest is fixed
-- source include/not_embedded.inc
source include/federated.inc; source include/federated.inc;

View File

@ -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/have_bdb.inc;
source include/federated.inc; source include/federated.inc;

View File

@ -4,6 +4,8 @@
# Test of flush table # Test of flush table
# #
# Should work in embedded server after mysqltest is fixed
-- source include/not_embedded.inc
--disable_warnings --disable_warnings
drop table if exists t1,t2; drop table if exists t1,t2;
--enable_warnings --enable_warnings

View File

@ -2,6 +2,9 @@
# test of HANDLER ... # test of HANDLER ...
# #
# should work in embedded server after mysqltest is fixed
-- source include/not_embedded.inc
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1;
--enable_warnings --enable_warnings

View File

@ -2,6 +2,8 @@
# Test of init_connect variable # Test of init_connect variable
# #
# should work with embedded server after mysqltest is fixed
-- source include/not_embedded.inc
connect (con0,localhost,root,,); connect (con0,localhost,root,,);
connection con0; connection con0;
select hex(@a); select hex(@a);

View File

@ -1576,33 +1576,7 @@ connection a;
checksum table t1; checksum table t1;
drop 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; connection default;
select * from t1;
connection a;
rollback;
connection b;
reap;
rollback;
connection default;
drop table t1;
drop function f1;
disconnect a; disconnect a;
disconnect b; disconnect b;

View File

@ -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;

View File

@ -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) # Testing the MySQL command line client(mysql)
# #

View File

@ -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 # We run with different binaries for normal and --embedded-server
# #
# If this test fails with "command "$MYSQL_CLIENT_TEST" failed", # If this test fails with "command "$MYSQL_CLIENT_TEST" failed",

View File

@ -1,3 +1,5 @@
# This test should work in embedded server after mysqltest is fixed
-- source include/not_embedded.inc
# ============================================================================ # ============================================================================
# #

View File

@ -822,29 +822,14 @@ select sql_cache * from t1 where s1=1;
end;// end;//
delimiter ;// delimiter ;//
call f1(); call f1();
show status like "Qcache_queries_in_cache";
show status like "Qcache_inserts";
show status like "Qcache_hits";
call f1(); call f1();
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; 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); insert into t1 values (1);
select sql_cache * from t1; 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();
call f1(); call f1();
select sql_cache * from t1; 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; flush query cache;
reset query cache; reset query cache;
flush status; flush status;

View File

@ -97,4 +97,88 @@ connection root;
SELECT * FROM t1; SELECT * FROM t1;
drop table 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; set GLOBAL query_cache_size=0;

View File

@ -1,6 +1,9 @@
# Test of the READ_ONLY global variable: # Test of the READ_ONLY global variable:
# check that it blocks updates unless they are only on temporary tables. # 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 --disable_warnings
DROP TABLE IF EXISTS t1,t2,t3; DROP TABLE IF EXISTS t1,t2,t3;
--enable_warnings --enable_warnings

View File

@ -1,3 +1,6 @@
# This tests not performed with embedded server
-- source include/not_embedded.inc
--disable_warnings --disable_warnings
drop table if exists t1,v1; drop table if exists t1,v1;
drop view if exists t1,v1; drop view if exists t1,v1;

View File

@ -35,10 +35,13 @@ create trigger t1_ai after insert on t1 for each row call bug14233();
# Unsupported tampering with the mysql.proc definition # Unsupported tampering with the mysql.proc definition
alter table mysql.proc drop type; alter table mysql.proc drop type;
--replace_result $MYSQL_TEST_DIR .
--error ER_SP_PROC_TABLE_CORRUPT --error ER_SP_PROC_TABLE_CORRUPT
call bug14233(); call bug14233();
--replace_result $MYSQL_TEST_DIR .
--error ER_SP_PROC_TABLE_CORRUPT --error ER_SP_PROC_TABLE_CORRUPT
create view v1 as select bug14233_f(); create view v1 as select bug14233_f();
--replace_result $MYSQL_TEST_DIR .
--error ER_SP_PROC_TABLE_CORRUPT --error ER_SP_PROC_TABLE_CORRUPT
insert into t1 values (0); insert into t1 values (0);

View File

@ -647,28 +647,6 @@ create table t5 (x int)|
call bug3294()| call bug3294()|
drop procedure 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 # BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in
# a DECLARE ? HANDLER FOR stmt. # a DECLARE ? HANDLER FOR stmt.

View File

@ -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, # Testing stored procedures with multiple connections,
# except security/privilege tests, they go to sp-security.test # except security/privilege tests, they go to sp-security.test

View File

@ -1368,11 +1368,11 @@ end|
call ifac(20)| call ifac(20)|
select * from fac| select * from fac|
drop table 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%'| show function status like '%f%'|
drop procedure ifac| drop procedure ifac|
drop function fac| 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%'| show function status like '%f%'|
@ -1455,7 +1455,7 @@ begin
end while; end while;
end| end|
show create procedure opp| 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%'| show procedure status like '%p%'|
# This isn't the fastest way in the world to compute prime numbers, so # 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 table primes|
drop procedure opp| drop procedure opp|
drop procedure ip| 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%'| show procedure status like '%p%'|
@ -1541,13 +1541,13 @@ drop procedure if exists bar|
create procedure bar(x char(16), y int) create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker comment "111111111111" sql security invoker
insert into test.t1 values (x, y)| 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'| show procedure status like 'bar'|
alter procedure bar comment "2222222222" sql security definer| alter procedure bar comment "2222222222" sql security definer|
alter procedure bar comment "3333333333"| alter procedure bar comment "3333333333"|
alter procedure bar| alter procedure bar|
show create 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'| show procedure status like 'bar'|
drop procedure bar| drop procedure bar|
@ -2497,7 +2497,6 @@ begin
show databases like 'foo'; show databases like 'foo';
show errors; show errors;
show columns from t1; show columns from t1;
show grants for 'root'@'localhost';
show keys from t1; show keys from t1;
show open tables like 'foo'; show open tables like 'foo';
show privileges; show privileges;
@ -2519,20 +2518,6 @@ call bug4902()|
drop procedure 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 # BUG#4904
# #
@ -2747,44 +2732,6 @@ select @x|
delete from t1| delete from t1|
drop procedure bug4941| 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" # BUG#4905: Stored procedure doesn't clear for "Rows affected"
# #
@ -3093,24 +3040,6 @@ insert into t1 values ("answer", 42)|
select id, bug5240() from t1| select id, bug5240() from t1|
drop function bug5240| 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 # BUG#7992: rolling back temporary Item tree changes in SP
# #
@ -4733,24 +4662,6 @@ select bug10100f(5)|
call bug10100t(5)| call bug10100t(5)|
#end of the stack checking #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| deallocate prepare stmt2|
drop function bug10100f| drop function bug10100f|

View File

@ -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 ;|

View File

@ -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));

View File

@ -2084,7 +2084,9 @@ drop table t1, t2;
# #
-- error ER_MALFORMED_DEFINER -- error ER_MALFORMED_DEFINER
create definer=some_user@`` sql security invoker view v1 as select 1; 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; create definer=some_user@localhost sql security invoker view v1 as select 1;
--enable_warnings
show create view v1; show create view v1;
drop view v1; drop view v1;

View File

@ -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 # Bug #8731: wait_timeout does not work on Mac OS X
# #

View File

@ -1545,7 +1545,8 @@ static MYSQL_METHODS client_methods=
NULL, NULL,
cli_read_statistics, cli_read_statistics,
cli_read_query_result, cli_read_query_result,
cli_read_change_user_result cli_read_change_user_result,
cli_read_binary_rows
#endif #endif
}; };
@ -2339,8 +2340,9 @@ static void mysql_close_free(MYSQL *mysql)
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->passwd,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->db,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->info_buffer,MYF(MY_ALLOW_ZERO_PTR));
/* Clear pointers for better safety */ /* 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)) if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->server_status|= SERVER_STATUS_IN_TRANS;
if (!(fields=(*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0, if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
protocol_41(mysql) ? 7 : 5)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
(uint) field_count,0, (uint) field_count,0,

View File

@ -2449,9 +2449,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
{ {
NET *net= &thd->net; NET *net= &thd->net;
net->report_error= 1; net->report_error= 1;
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_abort(net); query_cache_abort(net);
#endif
if (!net->last_error[0]) // Return only first message if (!net->last_error[0]) // Return only first message
{ {
strmake(net->last_error, str, sizeof(net->last_error)-1); strmake(net->last_error, str, sizeof(net->last_error)-1);

View File

@ -29,6 +29,7 @@
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
static void write_eof_packet(THD *thd, NET *net); 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 #ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length) 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) 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; NET *net= &thd->net;
bool generate_warning= thd->killed != THD::KILL_CONNECTION; bool generate_warning= thd->killed != THD::KILL_CONNECTION;
DBUG_ENTER("net_send_error"); 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); push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err);
} }
#ifdef EMBEDDED_LIBRARY net_send_error_packet(thd, sql_errno, err);
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;
}
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->is_fatal_error=0; // Error message is given
thd->net.report_error= 0; 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); 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 */ #endif /* EMBEDDED_LIBRARY */
/* /*

View File

@ -91,6 +91,12 @@ public:
virtual bool store_date(TIME *time)=0; virtual bool store_date(TIME *time)=0;
virtual bool store_time(TIME *time)=0; virtual bool store_time(TIME *time)=0;
virtual bool store(Field *field)=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(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer); virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field); virtual bool store(Field *field);
#ifdef EMBEDDED_LIBRARY
void remove_last_row();
#endif
}; };

View File

@ -951,7 +951,9 @@ bool select_send::send_data(List<Item> &items)
thd->sent_row_count++; thd->sent_row_count++;
if (!thd->vio_ok()) if (!thd->vio_ok())
DBUG_RETURN(0); DBUG_RETURN(0);
if (!thd->net.report_error) if (thd->net.report_error)
protocol->remove_last_row();
else
DBUG_RETURN(protocol->write()); DBUG_RETURN(protocol->write());
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -1983,10 +1985,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
cuted_fields= 0; cuted_fields= 0;
transaction.savepoints= 0; transaction.savepoints= 0;
#ifndef EMBEDDED_LIBRARY
/* Surpress OK packets in case if we will execute statements */ /* Surpress OK packets in case if we will execute statements */
net.no_send_ok= TRUE; net.no_send_ok= TRUE;
#endif
} }

View File

@ -801,13 +801,16 @@ public:
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
struct st_mysql *mysql; struct st_mysql *mysql;
struct st_mysql_data *data;
unsigned long client_stmt_id; unsigned long client_stmt_id;
unsigned long client_param_count; unsigned long client_param_count;
struct st_mysql_bind *client_params; struct st_mysql_bind *client_params;
char *extra_data; char *extra_data;
ulong extra_length; 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 #endif
NET net; // client connection descriptor NET net; // client connection descriptor
MEM_ROOT warn_root; // For warnings and errors MEM_ROOT warn_root; // For warnings and errors
@ -1441,6 +1444,11 @@ public:
*/ */
virtual void cleanup(); virtual void cleanup();
void set_thd(THD *thd_arg) { thd= thd_arg; } void set_thd(THD *thd_arg) { thd= thd_arg; }
#ifdef EMBEDDED_LIBRARY
virtual void begin_dataset() {}
#else
void begin_dataset() {}
#endif
}; };

View File

@ -603,6 +603,7 @@ void Materialized_cursor::fetch(ulong num_rows)
THD *thd= table->in_use; THD *thd= table->in_use;
int res= 0; int res= 0;
result->begin_dataset();
for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++) for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++)
{ {
if ((res= table->file->rnd_next(table->record[0]))) if ((res= table->file->rnd_next(table->record[0])))

View File

@ -1713,13 +1713,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
net->no_send_error= 0; net->no_send_error= 0;
/* /*
Multiple queries exits, execute them individually 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 || if (thd->lock || thd->open_tables || thd->derived_tables ||
thd->prelocked_mode) thd->prelocked_mode)
close_thread_tables(thd); close_thread_tables(thd);
#endif
ulong length= (ulong)(packet_end-packet); ulong length= (ulong)(packet_end-packet);
log_slow_statement(thd); 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. */ thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
#ifndef EMBEDDED_LIBRARY
mysql_parse(thd, packet, length); 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)) if (!(specialflag & SPECIAL_NO_PRIOR))
@ -4242,10 +4221,8 @@ end_with_restore_list:
goto error; goto error;
} }
#ifndef EMBEDDED_LIBRARY
my_bool nsok= thd->net.no_send_ok; my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE; thd->net.no_send_ok= TRUE;
#endif
if (sp->m_flags & sp_head::MULTI_RESULTS) if (sp->m_flags & sp_head::MULTI_RESULTS)
{ {
if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS)) if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
@ -4255,9 +4232,7 @@ end_with_restore_list:
back back
*/ */
my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif
goto error; goto error;
} }
/* /*
@ -4274,18 +4249,14 @@ end_with_restore_list:
sp->m_db.str, sp->m_name.str, TRUE, 0) || sp->m_db.str, sp->m_name.str, TRUE, 0) ||
sp_change_security_context(thd, sp, &save_ctx)) sp_change_security_context(thd, sp, &save_ctx))
{ {
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif
goto error; goto error;
} }
if (save_ctx && if (save_ctx &&
check_routine_access(thd, EXECUTE_ACL, check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, 0)) sp->m_db.str, sp->m_name.str, TRUE, 0))
{ {
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif
sp_restore_security_context(thd, save_ctx); sp_restore_security_context(thd, save_ctx);
goto error; goto error;
} }
@ -4317,9 +4288,7 @@ end_with_restore_list:
sp_restore_security_context(thd, save_ctx); sp_restore_security_context(thd, save_ctx);
#endif #endif
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif
thd->server_status&= ~bits_to_be_cleared; thd->server_status&= ~bits_to_be_cleared;
if (!res) if (!res)

View File

@ -92,6 +92,12 @@ public:
virtual bool send_fields(List<Item> &list, uint flags); virtual bool send_fields(List<Item> &list, uint flags);
virtual bool send_data(List<Item> &items); virtual bool send_data(List<Item> &items);
virtual bool send_eof(); 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) 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); MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
} }