1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Support for character set conversion in binary protocol: another go

after Monty's review.
- Item_param was rewritten.
- it turns out that we can't convert string data to character set of
  connection on the fly, because they first should be written to the binary
  log.
  To support efficient conversion we need to rewrite prepared statements
  binlogging code first.


include/my_global.h:
  Macro swap(a, b, c) was renamed to resolve name conflict with
  String::swap() method.
include/my_sys.h:
  Added declaration of escape_string_for_mysql()
include/mysql_com.h:
  Removed and moved back: a macro which is visible to libmysql user but
  has sence only in prepared statement protocol implementation.
isam/_search.c:
  swap -> swap_variables
isam/test2.c:
  swap -> swap_variables
libmysql/libmysql.c:
  - sub_escape_string moved to mysys/charset.c to be visible in sql/
  - few cleanups
myisam/mi_test2.c:
  swap -> swap_variables
mysys/charset.c:
  sub_escape_string was moved from libmysql.c to be able to use it in sql/
  code.
mysys/my_chsize.c:
  rename: swap -> swap_variables
mysys/my_compress.c:
  swap -> swap_variables
mysys/my_handler.c:
  swap -> swap_variables
sql/field.cc:
  Field::store_time refactored to use TIME_to_string function from time.cc
sql/item.cc:
  New implementation of Item_param class:
  added support for character sets conversion.
sql/item.h:
  Item_param:
  - 'state' member introduced instead of many boolean variables.
  - put ltime, int_value and real_value into union to save space.
  - remove unimplemented members
  - set_value renamed to set_str
sql/item_timefunc.cc:
  Refactored to use functions from time.cc
sql/lock.cc:
  rename: swap -> swap_variables
sql/mysql_priv.h:
  - added declarations for TIME_to_ulonglong_*, TIME_to_string functions
  - const specifiers for make_date, make_time, make_datetime arguments
sql/opt_range.cc:
  rename: swap -> swap_variables
sql/protocol.cc:
  - added character set conversion support to binary protocol.
  - Protocol::convert changed to point at shared buffer in THD.
    This lets us use one convert buffer for binary and simple protocol.
    The same buffer is used for client->server conversions in prepared
    statements code.
  - string conversion code refactored to Protocol::store_string_aux function.
  - few more comments
sql/protocol.h:
  - Protocol::convert now points at THD::convert_buffer: we want to share one
    buffer between all protocol implementations.
sql/sql_class.cc:
  - implementation of THD::convert_string using THD::convert_buffer
    (conversion of strings allocated in the system heap).
sql/sql_class.h:
  - THD::convert_buffer is shared between THD and network Protocols and
    used for character set conversion of strings.
  - new function to convert String object from one charset to another using
    THD::convert_buffer
sql/sql_insert.cc:
  A little fix in a comment.
sql/sql_parse.cc:
  Shrink convert buffer in the end of each statement.
sql/sql_prepare.cc:
    Many changes:
  - static specifier for set_param_* family of functions.
  - FIELD_TYPE -> MYSQL_TYPE
  - added set_param_binary as handler for BLOB types.
  - added character set support
  - added support for param typecode in mysql_stmt_get_longdata
    (mysql_stmt_send_long_data handler)
  - changes in Item_param deployed
  - few cleanups
sql/sql_select.cc:
  rename: swap -> swap_variables
sql/sql_string.cc:
  - String::append rewritten to support character set conversion for
  single-byte encodings.
  - added String::swap method to efficiently exchange two string objects.
sql/sql_string.h:
  Declraration for String::swap().
sql/time.cc:
  - function TIME_to_string to convert TIME to String in default MySQL format
  - family of functions TIME_to_ulonglong_*
tests/client_test.c:
  Test for support for character set conversions in prepared statements
  (binary and text data).
This commit is contained in:
unknown
2004-05-25 02:03:49 +04:00
parent 88da3ae5f9
commit 093d62922b
30 changed files with 1067 additions and 536 deletions

View File

@@ -76,8 +76,6 @@ Long data handling:
#include <mysql.h>
#endif
const String my_null_string("NULL", 4, default_charset_info);
/******************************************************************************
Prepared_statement: statement which can contain placeholders
******************************************************************************/
@@ -91,7 +89,6 @@ public:
uint last_errno;
char last_error[MYSQL_ERRMSG_SIZE];
bool get_longdata_error;
bool log_full_query;
#ifndef EMBEDDED_LIBRARY
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
uchar *read_pos);
@@ -239,7 +236,7 @@ static ulong get_param_length(uchar **packet, ulong len)
none
*/
void set_param_tiny(Item_param *param, uchar **pos, ulong len)
static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
{
#ifndef EMBEDDED_LIBRARY
if (len < 1)
@@ -247,55 +244,55 @@ void set_param_tiny(Item_param *param, uchar **pos, ulong len)
#endif
int8 value= (int8) **pos;
param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
(longlong) value);
(longlong) value, 4);
*pos+= 1;
}
void set_param_short(Item_param *param, uchar **pos, ulong len)
static void set_param_short(Item_param *param, uchar **pos, ulong len)
{
int16 value;
#ifndef EMBEDDED_LIBRARY
if (len < 2)
return;
int16 value= sint2korr(*pos);
value= sint2korr(*pos);
#else
int16 value;
shortget(value, *pos);
#endif
param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
(longlong) value);
(longlong) value, 6);
*pos+= 2;
}
void set_param_int32(Item_param *param, uchar **pos, ulong len)
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
{
int32 value;
#ifndef EMBEDDED_LIBRARY
if (len < 4)
return;
int32 value= sint4korr(*pos);
value= sint4korr(*pos);
#else
int32 value;
longget(value, *pos);
#endif
param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
(longlong) value);
(longlong) value, 11);
*pos+= 4;
}
void set_param_int64(Item_param *param, uchar **pos, ulong len)
static void set_param_int64(Item_param *param, uchar **pos, ulong len)
{
longlong value;
#ifndef EMBEDDED_LIBRARY
if (len < 8)
return;
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
value= (longlong) sint8korr(*pos);
#else
longlong value;
longlongget(value, *pos);
param->set_int(value);
#endif
param->set_int(value, 21);
*pos+= 8;
}
void set_param_float(Item_param *param, uchar **pos, ulong len)
static void set_param_float(Item_param *param, uchar **pos, ulong len)
{
#ifndef EMBEDDED_LIBRARY
if (len < 4)
@@ -307,7 +304,7 @@ void set_param_float(Item_param *param, uchar **pos, ulong len)
*pos+= 4;
}
void set_param_double(Item_param *param, uchar **pos, ulong len)
static void set_param_double(Item_param *param, uchar **pos, ulong len)
{
#ifndef EMBEDDED_LIBRARY
if (len < 8)
@@ -320,9 +317,10 @@ void set_param_double(Item_param *param, uchar **pos, ulong len)
}
#ifndef EMBEDDED_LIBRARY
void set_param_time(Item_param *param, uchar **pos, ulong len)
static void set_param_time(Item_param *param, uchar **pos, ulong len)
{
ulong length;
uint day;
if ((length= get_param_length(pos, len)) >= 8)
{
@@ -332,20 +330,33 @@ void set_param_time(Item_param *param, uchar **pos, ulong len)
/* TODO: why length is compared with 8 here? */
tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
tm.day= (ulong) sint4korr(to+1);
tm.hour= (uint) to[5];
/*
Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise
we'll get buffer overflow in make_{date,time} functions,
which are called when time value is converted to string.
*/
day= (uint) sint4korr(to+1);
tm.hour= (uint) to[5] + day * 24;
tm.minute= (uint) to[6];
tm.second= (uint) to[7];
tm.year= tm.month= 0;
if (tm.hour > 838)
{
/* TODO: add warning 'Data truncated' here */
tm.hour= 838;
tm.minute= 59;
tm.second= 59;
}
tm.day= tm.year= tm.month= 0;
tm.neg= (bool)to[0];
param->set_time(&tm, TIMESTAMP_TIME);
param->set_time(&tm, TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
}
void set_param_datetime(Item_param *param, uchar **pos, ulong len)
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
uint length;
@@ -356,6 +367,11 @@ void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0;
/*
Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise
we'll get buffer overflow in make_{date,time} functions.
*/
if (length > 4)
{
tm.hour= (uint) to[4];
@@ -370,12 +386,13 @@ void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.day= (uint) to[3];
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATETIME);
param->set_time(&tm, TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
}
void set_param_date(Item_param *param, uchar **pos, ulong len)
static void set_param_date(Item_param *param, uchar **pos, ulong len)
{
ulong length;
@@ -383,7 +400,11 @@ void set_param_date(Item_param *param, uchar **pos, ulong len)
{
uchar *to= *pos;
TIME tm;
/*
Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise
we'll get buffer overflow in make_{date,time} functions.
*/
tm.year= (uint) sint2korr(to);
tm.month= (uint) to[2];
tm.day= (uint) to[3];
@@ -392,7 +413,8 @@ void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.second_part= 0;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATE);
param->set_time(&tm, TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
}
@@ -412,8 +434,9 @@ void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.year= tm.month= 0;
tm.neg= to->neg;
param->set_time(&tm, TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
param->set_time(&tm, TIMESTAMP_TIME);
}
void set_param_datetime(Item_param *param, uchar **pos, ulong len)
@@ -431,7 +454,8 @@ void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.month= to->month;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATETIME);
param->set_time(&tm, TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
void set_param_date(Item_param *param, uchar **pos, ulong len)
@@ -449,60 +473,111 @@ void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.second_part= 0;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATE);
param->set_time(&tm, TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
#endif /*!EMBEDDED_LIBRARY*/
void set_param_str(Item_param *param, uchar **pos, ulong len)
static void set_param_str(Item_param *param, uchar **pos, ulong len)
{
ulong length= get_param_length(pos, len);
param->set_value((const char *)*pos, length);
param->set_str((const char *)*pos, length);
*pos+= length;
}
static void setup_one_conversion_function(Item_param *param, uchar param_type)
#undef get_param_length
static void setup_one_conversion_function(THD *thd, Item_param *param,
uchar param_type)
{
switch (param_type) {
case FIELD_TYPE_TINY:
case MYSQL_TYPE_TINY:
param->set_param_func= set_param_tiny;
param->item_type= Item::INT_ITEM;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_SHORT:
case MYSQL_TYPE_SHORT:
param->set_param_func= set_param_short;
param->item_type= Item::INT_ITEM;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_LONG:
case MYSQL_TYPE_LONG:
param->set_param_func= set_param_int32;
param->item_type= Item::INT_ITEM;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_LONGLONG:
case MYSQL_TYPE_LONGLONG:
param->set_param_func= set_param_int64;
param->item_type= Item::INT_ITEM;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_FLOAT:
case MYSQL_TYPE_FLOAT:
param->set_param_func= set_param_float;
param->item_type= Item::REAL_ITEM;
param->item_result_type= REAL_RESULT;
break;
case FIELD_TYPE_DOUBLE:
case MYSQL_TYPE_DOUBLE:
param->set_param_func= set_param_double;
param->item_type= Item::REAL_ITEM;
param->item_result_type= REAL_RESULT;
break;
case FIELD_TYPE_TIME:
case MYSQL_TYPE_TIME:
param->set_param_func= set_param_time;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
break;
case FIELD_TYPE_DATE:
case MYSQL_TYPE_DATE:
param->set_param_func= set_param_date;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
param->set_param_func= set_param_datetime;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
param->set_param_func= set_param_str;
param->value.cs_info.character_set_client= &my_charset_bin;
param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
break;
default:
param->set_param_func= set_param_str;
param->item_result_type= STRING_RESULT;
/*
The client library ensures that we won't get any other typecodes
except typecodes above and typecodes for string types. Marking
label as 'default' lets us to handle malformed packets as well.
*/
{
CHARSET_INFO *fromcs= thd->variables.character_set_client;
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
param->value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
make later checks easier.
*/
param->value.cs_info.final_character_set_of_str_value=
String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
tocs : fromcs;
param->set_param_func= set_param_str;
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
}
}
}
@@ -531,23 +606,21 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
for (Item_param **it= begin; it < end; ++it)
{
Item_param *param= *it;
if (param->long_data_supplied)
res= param->query_val_str(&str);
else
if (param->state != Item_param::LONG_DATA_VALUE)
{
if (is_param_null(null_array, it - begin))
{
param->set_null();
res= &my_null_string;
}
else
{
if (read_pos >= data_end)
DBUG_RETURN(1);
param->set_param_func(param, &read_pos, data_end - read_pos);
res= param->query_val_str(&str);
}
}
res= param->query_val_str(&str);
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
if (query.replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1);
@@ -571,7 +644,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
for (Item_param **it= begin; it < end; ++it)
{
Item_param *param= *it;
if (!param->long_data_supplied)
if (param->state != Item_param::LONG_DATA_VALUE)
{
if (is_param_null(null_array, it - begin))
param->set_null();
@@ -582,6 +655,8 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
param->set_param_func(param, &read_pos, data_end - read_pos);
}
}
if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */
}
DBUG_RETURN(0);
}
@@ -603,6 +678,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
*/
Item_param **it= stmt->param_array;
Item_param **end= it + stmt->param_count;
THD *thd= stmt->thd;
for (; it < end; ++it)
{
ushort typecode;
@@ -614,7 +690,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
typecode= sint2korr(read_pos);
read_pos+= 2;
(**it).unsigned_flag= test(typecode & signed_bit);
setup_one_conversion_function(*it, (uchar) (typecode & ~signed_bit));
setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
}
}
*data= read_pos;
@@ -625,6 +701,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
static bool emb_insert_params(Prepared_statement *stmt)
{
THD *thd= stmt->thd;
Item_param **it= stmt->param_array;
Item_param **end= it + stmt->param_count;
MYSQL_BIND *client_param= stmt->thd->client_params;
@@ -634,21 +711,22 @@ static bool emb_insert_params(Prepared_statement *stmt)
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
setup_one_conversion_function(param, client_param->buffer_type);
param->unsigned_flag= client_param->is_unsigned;
if (!param->long_data_supplied)
setup_one_conversion_function(thd, param, client_param->buffer_type);
if (param->state != Item_param::LONG_DATA_VALUE)
{
if (*client_param->is_null)
param->set_null();
else
{
uchar *buff= (uchar*)client_param->buffer;
uchar *buff= (uchar*) client_param->buffer;
param->set_param_func(param, &buff,
client_param->length ?
*client_param->length :
client_param->buffer_length);
}
}
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
}
DBUG_RETURN(0);
}
@@ -673,25 +751,22 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
setup_one_conversion_function(param, client_param->buffer_type);
if (param->long_data_supplied)
res= param->query_val_str(&str);
else
setup_one_conversion_function(thd, param, client_param->buffer_type);
if (param->state != Item_param::LONG_DATA_VALUE)
{
if (*client_param->is_null)
{
param->set_null();
res= &my_null_string;
}
else
{
uchar *buff= (uchar*)client_param->buffer;
uchar *buff= (uchar*)client_param->buffer;
param->set_param_func(param, &buff,
client_param->length ?
*client_param->length :
client_param->buffer_length);
res= param->query_val_str(&str);
}
res= param->query_val_str(&str);
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
}
if (query.replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1);
@@ -736,7 +811,7 @@ static int mysql_test_insert(Prepared_statement *stmt,
TABLE_LIST *insert_table_list=
(TABLE_LIST*) lex->select_lex.table_list.first;
my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0);
DBUG_ENTER("mysql_test_insert_fields");
DBUG_ENTER("mysql_test_insert");
if ((res= insert_precheck(thd, table_list, update)))
DBUG_RETURN(res);
@@ -792,7 +867,7 @@ error:
Validate UPDATE statement
SYNOPSIS
mysql_test_delete()
mysql_test_update()
stmt prepared statemen handler
tables list of tables queries
@@ -1105,7 +1180,7 @@ end:
/*
Validate and prepare for execution CRETE TABLE statement
Validate and prepare for execution CREATE TABLE statement
SYNOPSIS
mysql_test_create_table()
@@ -1142,7 +1217,7 @@ static int mysql_test_create_table(Prepared_statement *stmt,
/*
Validate and prepare for execution multy update statement
Validate and prepare for execution multi update statement
SYNOPSIS
mysql_test_multiupdate()
@@ -1165,7 +1240,7 @@ static int mysql_test_multiupdate(Prepared_statement *stmt,
/*
Validate and prepare for execution multy delete statement
Validate and prepare for execution multi delete statement
SYNOPSIS
mysql_test_multidelete()
@@ -1337,8 +1412,8 @@ error:
}
/*
Initialize array of parametes in statement from LEX.
(We need to have quick access to items by number in mysql_send_longdata).
Initialize array of parameters in statement from LEX.
(We need to have quick access to items by number in mysql_stmt_get_longdata).
This is to avoid using malloc/realloc in the parser.
*/
@@ -1540,7 +1615,6 @@ static void reset_stmt_params(Prepared_statement *stmt)
mysql_stmt_execute()
*/
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
@@ -1552,7 +1626,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
packet+= 9; /* stmt_id + 5 bytes of flags */
if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR)))
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute",
SEND_ERROR)))
DBUG_VOID_RETURN;
DBUG_PRINT("exec_query:", ("%s", stmt->query));
@@ -1606,7 +1681,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
/*
/*
Free Items that were created during this execution of the PS by query
optimizer.
*/
@@ -1616,7 +1691,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
set_params_data_err:
reset_stmt_params(stmt);
thd->set_statement(&thd->stmt_backup);
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
send_error(thd);
DBUG_VOID_RETURN;
}
@@ -1647,7 +1722,8 @@ void mysql_stmt_reset(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_reset");
if (!(stmt= find_prepared_statement(thd, stmt_id, "reset", SEND_ERROR)))
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset",
SEND_ERROR)))
DBUG_VOID_RETURN;
stmt->get_longdata_error= 0;
@@ -1677,7 +1753,8 @@ void mysql_stmt_free(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_free");
if (!(stmt= find_prepared_statement(thd, stmt_id, "close", DONT_SEND_ERROR)))
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close",
DONT_SEND_ERROR)))
DBUG_VOID_RETURN;
/* Statement map deletes statement on erase */
@@ -1705,43 +1782,50 @@ void mysql_stmt_free(THD *thd, char *packet)
to the server. (No checking that we get a 'end of column' in the server)
*/
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
{
ulong stmt_id;
uint param_number;
Prepared_statement *stmt;
Item_param *param;
char *packet_end= packet + packet_length - 1;
DBUG_ENTER("mysql_stmt_get_longdata");
#ifndef EMBEDDED_LIBRARY
/* The following should never happen */
if (packet_length < MYSQL_LONG_DATA_HEADER+1)
/* Minimal size of long data packet is 6 bytes */
if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
DBUG_VOID_RETURN;
}
#endif
ulong stmt_id= uint4korr(pos);
uint param_number= uint2korr(pos+4);
stmt_id= uint4korr(packet);
packet+= 4;
if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata",
if (!(stmt=find_prepared_statement(thd, stmt_id, "mysql_stmt_send_long_data",
DONT_SEND_ERROR)))
DBUG_VOID_RETURN;
param_number= uint2korr(packet);
packet+= 2;
#ifndef EMBEDDED_LIBRARY
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
stmt->get_longdata_error= 1;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysql_stmt_send_long_data");
DBUG_VOID_RETURN;
}
pos+= MYSQL_LONG_DATA_HEADER; // Point to data
#endif
Item_param *param= stmt->param_array[param_number];
param= stmt->param_array[param_number];
#ifndef EMBEDDED_LIBRARY
param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
param->set_longdata(packet, (ulong) (packet_end - packet));
#else
param->set_longdata(thd->extra_data, thd->extra_length);
#endif
@@ -1755,13 +1839,11 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
param_array(0),
param_count(0),
last_errno(0),
get_longdata_error(0),
log_full_query(0)
get_longdata_error(0)
{
*last_error= '\0';
if (mysql_bin_log.is_open())
{
log_full_query= 1;
#ifndef EMBEDDED_LIBRARY
set_params= insert_params_withlog;
#else