Date: Tuesday, January 17, 2006 @ 09:38:38
Author: zsolt
Path: /cvsroot/carob/libmysequoia
Modified: include/CarobStmt.hpp (1.5 -> 1.6) src/CarobStmt.cpp (1.10 ->
1.11) src/MySQLAPI.cpp (1.27 -> 1.28) src/Utils.cpp (1.18 ->
1.19) test/TestMySQLAPI.cpp (1.20 -> 1.21) test/TestMySQLAPI.hpp
(1.9 -> 1.10)
- prefetched rows now can be set and work correctly
- in the string conversion now is taking into account the offset
- long data emulation: the consecutive call to mysql_stmt_send_long_data will
build internally a buffer, and at the execute stage this buffer will be sent to
the server
- more structure filling at the CarobStmt::bind_result and CarobStmt::bind_param
- implemented max_length calculation if the option is set
- corrected misbehaviour in the CarobStmt::fetch, when the statement was not
yet executed
- introduced stage change after the fetch is successfully done, needed by
fetch_column
- modified mysql test data structure, introduced a new third varchar column
- new test: mysql_stmt_long_data_fetch_field_test() to test long data sending,
fetch field, offset, reprepare, ...
- implemented following functions:
mysql_stmt_data_seek
mysql_stmt_fetch_column
mysql_stmt_free_result
mysql_stmt_reset
mysql_stmt_result_metadata
mysql_stmt_row_seek
mysql_stmt_send_long_data
CarobStmt::send_long_data
CarobStmt::fetch_column
CarobStmt::reset
CarobStmt::result_metadata
CarobStmt::free_result
CarobStmt::link_bind
CarobStmt::free_long_data
-----------------------+
include/CarobStmt.hpp | 12 +
src/CarobStmt.cpp | 325 +++++++++++++++++++++++++++++++++++-------------
src/MySQLAPI.cpp | 63 ++++++++-
src/Utils.cpp | 14 +-
test/TestMySQLAPI.cpp | 68 +++++++++-
test/TestMySQLAPI.hpp | 2
6 files changed, 385 insertions(+), 99 deletions(-)
Index: libmysequoia/include/CarobStmt.hpp
diff -u libmysequoia/include/CarobStmt.hpp:1.5
libmysequoia/include/CarobStmt.hpp:1.6
--- libmysequoia/include/CarobStmt.hpp:1.5 Thu Jan 12 18:30:46 2006
+++ libmysequoia/include/CarobStmt.hpp Tue Jan 17 09:38:38 2006
@@ -39,12 +39,16 @@
int execute();
int fetch();
+ int fetch_column (MYSQL_BIND * bind, unsigned int column, unsigned long
offset);
int prepare(const char *query, unsigned long length);
bool bind_param(const MYSQL_BIND *bind);
+ bool send_long_data (unsigned int parameter_number, const char *data,
unsigned long length);
bool bind_result(const MYSQL_BIND *bind);
bool reset();
- MYSQL_RES *param_metadata();
+ void set_fetch_size(unsigned size) { if (c_stmt) c_stmt->setFetchSize(size);
}
+
+ MYSQL_RES *result_metadata();
int store_result();
static bool free_result(MYSQL_STMT *stmt);
@@ -59,11 +63,17 @@
void clear();
+ void link_bind(MYSQL_BIND *bind);
+
+ void fetch_field(MYSQL_FIELD *fPtr, MYSQL_BIND *bPtr, unsigned colNo);
+
void *alloc_fetch_field(MYSQL_FIELD *fPtr, unsigned colNo);
static void delete_fetch_field(MYSQL_FIELD *fPtr, void *buffer);
static void free_catched_result(MYSQL_STMT *stmt);
+
+ static void free_long_data(MYSQL_STMT *m_stmt);
/**
* Set the current mysql error to the specified one. The mysql error message
will be filled from the error list.
Index: libmysequoia/src/CarobStmt.cpp
diff -u libmysequoia/src/CarobStmt.cpp:1.10 libmysequoia/src/CarobStmt.cpp:1.11
--- libmysequoia/src/CarobStmt.cpp:1.10 Fri Jan 13 14:59:34 2006
+++ libmysequoia/src/CarobStmt.cpp Tue Jan 17 09:38:38 2006
@@ -127,6 +127,16 @@
MYSQL_BIND *p = m_stmt->params;
for (unsigned int no=1; no <= m_stmt->param_count && !result; no++, p++)
{
+ if (!p->is_null)
+ {
+ p->is_null= &p->is_null_value;
+ p->is_null_value = false;
+ }
+
+ p->long_data_used = 0;
+ p->row_ptr = 0;
+ p->param_number = no-1;
+
switch (p->buffer_type)
{
case MYSQL_TYPE_TINY:
@@ -164,6 +174,40 @@
return result;
}
+bool
+CarobStmt::send_long_data (unsigned int parameter_number, const char *data,
unsigned long length)
+{
+ LOG4CXX_DEBUG(logger, "Entering send_long_data.");
+ bool result = true;
+ //Because Carob doesn't support this feature it must be emulated. All data
is collected in a string type
+ //contained by the pointer row_ptr.
+ if (!m_stmt->bind_param_done)
+ set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+ else
+ if (parameter_number >= m_stmt->param_count)
+ set_error(CR_INVALID_PARAMETER_NO, SQLT_UNKNOWN);
+ else
+ {
+ MYSQL_BIND *bind = m_stmt->params + parameter_number;
+ if (bind->buffer_type >= MYSQL_TYPE_TINY_BLOB &&
+ bind->buffer_type <= MYSQL_TYPE_STRING)
+ {
+ //if we are at the first call, then allocate the string
+ if (!bind->long_data_used)
+ {
+ bind->long_data_used = 1;
+ bind->row_ptr = (unsigned char *)new string;
+ }
+ ((string *)(bind->row_ptr))->append(data, length);
+ }
+ else
+ set_error(CR_INVALID_BUFFER_USE, SQLT_UNKNOWN);
+ }
+
+ LOG4CXX_DEBUG(logger, "Leaving send_long_data.");
+ return result;
+}
+
int
CarobStmt::execute()
{
@@ -176,12 +220,14 @@
set_error(CR_PARAMS_NOT_BOUND, SQLT_UNKNOWN);
else
{
+ set_fetch_size(m_stmt->prefetch_rows);
+
try
{
MYSQL_BIND *p = m_stmt->params;
for (unsigned int no=1; no <= m_stmt->param_count; no++, p++)
{
- if (p->is_null)
+ if (*p->is_null)
c_stmt->setNull(no);
else
switch (p->buffer_type)
@@ -211,7 +257,10 @@
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
- c_stmt->setString(no, fromString(string((char *)p->buffer,
p->buffer_length)));
+ if (p->long_data_used && p->row_ptr)
+ c_stmt->setString(no, fromString(*(string *)(p->row_ptr)));
+ else
+ c_stmt->setString(no, fromString(string((char *)p->buffer,
p->buffer_length)));
break;
default:
LOG4CXX_DEBUG(logger, "This should never happen!!");
@@ -260,26 +309,35 @@
{
memcpy(m_stmt->bind, bind, sizeof(MYSQL_BIND) * m_stmt->field_count);
MYSQL_BIND *p = m_stmt->bind;
- for (unsigned int no=1; no <= m_stmt->field_count && !result; no++, p++)
+ MYSQL_FIELD *fPtr = m_stmt->fields;
+ for (unsigned int no=1; no <= m_stmt->field_count && !result; no++, p++,
fPtr++)
{
- /* set up the pointers if are not set up */
- if (!p->is_null)
- p->is_null= &p->is_null_value;
+ p->param_number = no-1;
+ p->offset = 0;
- if (!p->length)
- p->length= &p->length_value;
-
- if (!p->error)
- p->error= &p->error_value;
+ /* set up the pointers if are not set up */
+ link_bind(p);
switch (p->buffer_type)
{
case MYSQL_TYPE_TINY:
+ fPtr->max_length = 4;
+ break;
case MYSQL_TYPE_SHORT:
+ fPtr->max_length = 6;
+ break;
case MYSQL_TYPE_LONG:
+ fPtr->max_length = 11;
+ break;
case MYSQL_TYPE_LONGLONG:
+ fPtr->max_length = 21;
+ break;
case MYSQL_TYPE_FLOAT:
+ fPtr->max_length = 331;
+ break;
case MYSQL_TYPE_DOUBLE:
+ fPtr->max_length = 331;
+ break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
@@ -287,13 +345,14 @@
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ fPtr->max_length = 0;
break;
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_NULL:
default:
set_error(CR_UNSUPPORTED_PARAM_TYPE, SQLT_UNKNOWN);
@@ -315,7 +374,7 @@
LOG4CXX_DEBUG(logger, "Entering fetch.");
int result = 0;
- if (!m_stmt->bind_result_done)
+ if (!m_stmt->bind_result_done || (m_stmt->state < MYSQL_STMT_EXECUTE_DONE))
{
set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
result = 1;
@@ -327,74 +386,12 @@
{
MYSQL_FIELD *fPtr = m_stmt->fields;
MYSQL_BIND *bPtr = m_stmt->bind;
- for (unsigned colNo=1; colNo <= m_stmt->field_count; colNo++, fPtr++,
bPtr++)
+ for (unsigned colNo=0; colNo < m_stmt->field_count; colNo++, fPtr++,
bPtr++)
{
- void *buffer = 0;
- //if there are cached results ...
- if (m_stmt->result.data)
- buffer = m_stmt->data_cursor->data[colNo-1];
- else
- buffer = alloc_fetch_field(fPtr, colNo);
+ fetch_field(fPtr, bPtr, colNo);
- if (!buffer)
- {
- *bPtr->is_null = true;
- }
- else
- {
- switch (fPtr->type)
- {
- case MYSQL_TYPE_TINY:
- getFromTiny(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_SHORT:
- getFromShort(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_LONG:
- getFromLong(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_LONGLONG:
- getFromLonglong(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_FLOAT:
- getFromFloat(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_DOUBLE:
- getFromDouble(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- getFromString(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_TIME:
- getFromTime(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_DATE:
- getFromDate(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- getFromDateTime(bPtr, fPtr, buffer);
- break;
- case MYSQL_TYPE_NULL:
- break;
- default:
- LOG4CXX_DEBUG(logger, "This should never happen!!");
- }
-
- if (!m_stmt->result.data)
- delete_fetch_field(fPtr, buffer);
-
- if (*bPtr->error)
- result = MYSQL_DATA_TRUNCATED;
- }
+ if (*bPtr->error)
+ result = MYSQL_DATA_TRUNCATED;
}
if (m_stmt->result.data)
@@ -404,6 +401,8 @@
m_stmt->result.rows++;
m_stmt->affected_rows = m_stmt->result.rows;
}
+
+ m_stmt->state = MYSQL_STMT_FETCH_DONE;
}
else
result = MYSQL_NO_DATA;
@@ -413,16 +412,72 @@
return result;
}
+int
+CarobStmt::fetch_column (MYSQL_BIND * bind, unsigned int column, unsigned long
offset)
+{
+ LOG4CXX_DEBUG(logger, "Entering fetch_column.");
+ int result = 1;
+ if (m_stmt->state != MYSQL_STMT_FETCH_DONE)
+ set_error(CR_NO_DATA, SQLT_UNKNOWN);
+ else
+ if (column >= m_stmt->field_count)
+ set_error(CR_INVALID_PARAMETER_NO, SQLT_UNKNOWN);
+ else
+ if (!bind)
+ set_error(CR_NULL_POINTER, SQLT_UNKNOWN);
+ else
+ {
+ link_bind(bind);
+ bind->offset = offset;
+
+ fetch_field(m_stmt->fields+column, bind, column);
+
+ result = 0;
+ }
+
+ LOG4CXX_DEBUG(logger, "Leaving fetch_column.");
+ return result;
+}
+
bool
CarobStmt::reset()
{
- return 0;
+ LOG4CXX_DEBUG(logger, "Entering reset.");
+ if (m_stmt->state >= MYSQL_STMT_PREPARE_DONE)
+ {
+ free_catched_result(m_stmt);
+ free_long_data(m_stmt);
+ if (c_stmt)
+ {
+ //TODO maybe implement a reset in Carob?? It can use cleanUpResults, but
it's private...
+ c_stmt->close();
+ liveResultSet = 0;
+ }
+ m_stmt->state = MYSQL_STMT_PREPARE_DONE;
+ }
+ LOG4CXX_DEBUG(logger, "Leaving reset.");
+ return false;
}
MYSQL_RES *
-CarobStmt::param_metadata()
+CarobStmt::result_metadata()
{
- return 0;
+ LOG4CXX_DEBUG(logger, "Entering result_metadata.");
+ MYSQL_RES *result = 0;
+ if (m_stmt->field_count)
+ {
+ result = new MYSQL_RES;
+ memset(result, 0, sizeof(MYSQL_RES));
+ result->data = new MYSQL_DATA;
+ memset(result->data, 0, sizeof(MYSQL_DATA));
+ //duplicate fields to the dummy resultset
+ result->fields = new MYSQL_FIELD[m_stmt->field_count];
+ memcpy(result->fields, m_stmt->fields, m_stmt->field_count *
sizeof(MYSQL_FIELD));
+ result->data->fields = result->field_count = m_stmt->field_count;
+ result->eof = true;
+ }
+ LOG4CXX_DEBUG(logger, "Leaving result_metadata.");
+ return result;
}
int
@@ -482,7 +537,93 @@
bool
CarobStmt::free_result(MYSQL_STMT *stmt)
{
- return 0;
+ free_catched_result(stmt);
+ return false;
+}
+
+void
+CarobStmt::link_bind(MYSQL_BIND *bind)
+{
+ if (!bind->error)
+ bind->error = &bind->error_value;
+
+ if (!bind->is_null)
+ bind->is_null = &bind->is_null_value;
+
+ if (!bind->length)
+ bind->length = &bind->length_value;
+}
+
+void
+CarobStmt::fetch_field(MYSQL_FIELD *fPtr, MYSQL_BIND *bPtr, unsigned colNo)
+{
+ LOG4CXX_DEBUG(logger, "Entering fetch_field.");
+
+ void *buffer = 0;
+ //if there are cached results ...
+ if (m_stmt->result.data)
+ buffer = m_stmt->data_cursor->data[colNo];
+ else
+ buffer = alloc_fetch_field(fPtr, colNo+1);
+
+ if (!buffer)
+ {
+ *bPtr->is_null = true;
+ }
+ else
+ {
+ switch (fPtr->type)
+ {
+ case MYSQL_TYPE_TINY:
+ getFromTiny(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_SHORT:
+ getFromShort(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_LONG:
+ getFromLong(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ getFromLonglong(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_FLOAT:
+ getFromFloat(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ getFromDouble(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ if ((m_stmt->update_max_length) && (((string *)buffer)->length() >
fPtr->max_length))
+ fPtr->max_length = ((string *)buffer)->length();
+ getFromString(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_TIME:
+ getFromTime(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_DATE:
+ getFromDate(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ getFromDateTime(bPtr, fPtr, buffer);
+ break;
+ case MYSQL_TYPE_NULL:
+ break;
+ default:
+ LOG4CXX_DEBUG(logger, "This should never happen!!");
+ }
+ }
+ if (!m_stmt->result.data)
+ delete_fetch_field(fPtr, buffer);
+ LOG4CXX_DEBUG(logger, "Leaving fetch_field.");
}
void *
@@ -617,6 +758,21 @@
}
void
+CarobStmt::free_long_data(MYSQL_STMT *m_stmt)
+{
+ if (m_stmt)
+ {
+ MYSQL_BIND *bind=m_stmt->bind;
+ for (unsigned colNo=0; colNo < m_stmt->field_count && bind; colNo++,
bind++)
+ if (bind->long_data_used)
+ {
+ bind->long_data_used = 0;
+ delete (string *)(bind->row_ptr);
+ }
+ }
+}
+
+void
CarobStmt::set_error(int errcode, int sqlstate)
{
LOG4CXX_DEBUG(logger, "Entering set_error.");
@@ -652,6 +808,7 @@
liveResultSet = 0;
free_catched_result(m_stmt);
+ free_long_data(m_stmt);
FREE_AND_NULL_ARRAY(m_stmt->params);
FREE_AND_NULL_ARRAY(m_stmt->bind);
Index: libmysequoia/src/MySQLAPI.cpp
diff -u libmysequoia/src/MySQLAPI.cpp:1.27 libmysequoia/src/MySQLAPI.cpp:1.28
--- libmysequoia/src/MySQLAPI.cpp:1.27 Thu Jan 12 18:30:46 2006
+++ libmysequoia/src/MySQLAPI.cpp Tue Jan 17 09:38:38 2006
@@ -1104,7 +1104,10 @@
ulong prefetch_rows;
prefetch_rows = arg ? *(ulong *)arg : (ulong) 1;
if (prefetch_rows >= 1 && prefetch_rows <= ULONG_MAX)
+ {
stmt->prefetch_rows = prefetch_rows;
+ getCarobStmt(stmt)->set_fetch_size(stmt->prefetch_rows);
+ }
else
result = true;
break;
@@ -1249,6 +1252,12 @@
mysql_stmt_data_seek (MYSQL_STMT * stmt, my_ulonglong offset)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_data_seek.");
+ if (stmt && stmt->result.data)
+ {
+ MYSQL_ROWS *curRow;
+ for (curRow=stmt->result.data; offset && curRow; offset--, curRow =
curRow->next) ;
+ stmt->data_cursor = curRow;
+ }
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_data_seek.");
}
@@ -1275,8 +1284,19 @@
unsigned int column, unsigned long offset)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_fetch_column.");
+
+ int result = 1;
+
+ if (isCarobObject(stmt))
+ result = getCarobStmt(stmt)->fetch_column(bind, column, offset);
+ else
+ {
+ LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized
with mysql_stmt_init.");
+ //Todo maybe better errorhandling?
+ }
+
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_fetch_column.");
- return 0;
+ return result;
}
unsigned int
@@ -1292,8 +1312,14 @@
mysql_stmt_free_result (MYSQL_STMT * stmt)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_free_result.");
+ my_bool result = true;
+
+ if (isCarobObject(stmt))
+ result = CarobStmt::free_result(stmt);
+ else
+ LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized
with mysql_stmt_init.");
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_free_result.");
- return 0;
+ return result;
}
my_ulonglong
@@ -1336,24 +1362,43 @@
mysql_stmt_reset (MYSQL_STMT * stmt)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_reset.");
+ my_bool result = true;
+
+ if (isCarobObject(stmt))
+ result = getCarobStmt(stmt)->reset();
+ else
+ LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized
with mysql_stmt_init.");
+
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_reset.");
- return 0;
+ return result;
}
MYSQL_RES *
mysql_stmt_result_metadata (MYSQL_STMT * stmt)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_result_metadata.");
+ MYSQL_RES *result = stmt ? getCarobStmt(stmt)->result_metadata() : 0;
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_result_metadata.");
- return 0;
+ return result;
}
MYSQL_ROW_OFFSET
mysql_stmt_row_seek (MYSQL_STMT * stmt, MYSQL_ROW_OFFSET offset)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_row_seek.");
+
+ MYSQL_ROW_OFFSET result;
+
+ if (stmt && stmt->result.data)
+ {
+ result = stmt->data_cursor;
+ stmt->data_cursor = offset;
+ }
+ else
+ result = 0;
+
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_row_seek.");
- return 0;
+ return result;
}
MYSQL_ROW_OFFSET
@@ -1372,8 +1417,14 @@
const char *data, unsigned long length)
{
LOG4CXX_DEBUG(logger, "Entering mysql_stmt_send_long_data.");
+ my_bool result = true;
+
+ if (isCarobObject(stmt))
+ result = getCarobStmt(stmt)->send_long_data(parameter_number, data,
length);
+ else
+ LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized
with mysql_stmt_init.");
LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_send_long_data.");
- return 0;
+ return result;
}
int
Index: libmysequoia/src/Utils.cpp
diff -u libmysequoia/src/Utils.cpp:1.18 libmysequoia/src/Utils.cpp:1.19
--- libmysequoia/src/Utils.cpp:1.18 Mon Jan 16 13:51:20 2006
+++ libmysequoia/src/Utils.cpp Tue Jan 17 09:38:38 2006
@@ -581,7 +581,6 @@
{
string *s = (string *)data;
size_t s_length = s->length();
- size_t length = min(s_length, (size_t)bind->buffer_length);
long long int v;
float f;
double d;
@@ -642,12 +641,21 @@
*bind->error = true;
break;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
- memcpy(bind->buffer, s->data(), length);
+ size_t length = min((size_t)max((long long)s_length - bind->offset,
(long long)0), (size_t)bind->buffer_length);
+ if (length)
+ memcpy(bind->buffer, s->data()+bind->offset, length);
if (length < bind->buffer_length)
((char *)bind->buffer)[length] = '\0';
*bind->length = s_length;
- *bind->error = length < s_length;
+ *bind->error = s_length - bind->offset > bind->buffer_length;
break;
case MYSQL_TYPE_TIME:
Index: libmysequoia/test/TestMySQLAPI.cpp
diff -u libmysequoia/test/TestMySQLAPI.cpp:1.20
libmysequoia/test/TestMySQLAPI.cpp:1.21
--- libmysequoia/test/TestMySQLAPI.cpp:1.20 Fri Jan 13 15:01:10 2006
+++ libmysequoia/test/TestMySQLAPI.cpp Tue Jan 17 09:38:38 2006
@@ -197,7 +197,7 @@
void TestMySQLAPI::mysql_real_query_1_test(void)
{
- char *query = "create table t1 (a int(11) not null auto_increment, b int(11)
default null, primary key (a))";
+ char *query = "create table t1 (a int(11) not null auto_increment, b int(11)
default null, c varchar(200) default null, primary key (a))";
// connect to the database
CPPUNIT_ASSERT(mysql_real_connect(mysql, HOST, USER1, PASSWD1, DB1, 0, 0, 0)
!= 0);
@@ -370,7 +370,7 @@
MYSQL_BIND inbind[1];
MYSQL_BIND outbind[1];
int int_data;
- char *query = "select * from t1 where a <= ?";
+ char *query = "select a from t1 where a <= ?";
CPPUNIT_ASSERT(mysql_real_connect(mysql, HOST, USER1, PASSWD1, DB1, 0, 0, 0)
!= 0);
CPPUNIT_ASSERT((stmt = mysql_stmt_init(mysql)) != 0);
@@ -386,7 +386,7 @@
int_data = 3;
CPPUNIT_ASSERT(mysql_stmt_execute(stmt) == 0);
- CPPUNIT_ASSERT(mysql_stmt_field_count(stmt) == 2);
+ CPPUNIT_ASSERT(mysql_stmt_field_count(stmt) == 1);
int int_res;
my_bool isnull;
@@ -413,7 +413,7 @@
MYSQL_BIND inbind[1];
MYSQL_BIND outbind[1];
int int_data;
- char *query = "select * from t1 where a <= ?";
+ char *query = "select a from t1 where a <= ?";
CPPUNIT_ASSERT(mysql_real_connect(mysql, HOST, USER1, PASSWD1, DB1, 0, 0, 0)
!= 0);
CPPUNIT_ASSERT((stmt = mysql_stmt_init(mysql)) != 0);
@@ -429,7 +429,7 @@
int_data = 3;
CPPUNIT_ASSERT(mysql_stmt_execute(stmt) == 0);
- CPPUNIT_ASSERT(mysql_stmt_field_count(stmt) == 2);
+ CPPUNIT_ASSERT(mysql_stmt_field_count(stmt) == 1);
int int_res;
my_bool isnull;
@@ -451,3 +451,61 @@
CPPUNIT_ASSERT(mysql_stmt_close(stmt) == 0);
}
+
+void TestMySQLAPI::mysql_stmt_long_data_fetch_field_test(void)
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND inbind[2];
+ MYSQL_BIND outbind[1];
+ int int_data;
+ char *str1 = "test ";
+ char *str2 = "string";
+ char *query_ins = "insert into t1(a,c) values (?,?)";
+ char *query_sel = "select c from t1 where a = ?";
+ char result[200];
+
+ CPPUNIT_ASSERT(mysql_real_connect(mysql, HOST, USER1, PASSWD1, DB1, 0, 0, 0)
!= 0);
+ CPPUNIT_ASSERT((stmt = mysql_stmt_init(mysql)) != 0);
+ CPPUNIT_ASSERT(mysql_stmt_prepare(stmt, query_ins, strlen(query_ins)) == 0);
+ CPPUNIT_ASSERT(mysql_stmt_param_count(stmt) == 2);
+
+ memset(inbind, 0, sizeof(MYSQL_BIND)*2);
+ inbind[0].buffer_type= MYSQL_TYPE_LONG;
+ inbind[0].buffer= (char *)&int_data;
+ inbind[1].buffer_type= MYSQL_TYPE_STRING;
+ CPPUNIT_ASSERT(mysql_stmt_bind_param(stmt, inbind) == 0);
+
+ mysql_stmt_send_long_data(stmt,1,str1,strlen(str1));
+ mysql_stmt_send_long_data(stmt,1,str2,strlen(str2));
+ int_data = 99;
+ CPPUNIT_ASSERT(mysql_stmt_execute(stmt) == 0);
+ CPPUNIT_ASSERT(mysql_stmt_affected_rows(stmt) == 1);
+
+ CPPUNIT_ASSERT(mysql_stmt_prepare(stmt, query_sel, strlen(query_sel)) == 0);
+ CPPUNIT_ASSERT(mysql_stmt_param_count(stmt) == 1);
+
+ int int_res = 99;
+ unsigned long length;
+ my_bool isnull;
+
+ memset(inbind, 0, sizeof(MYSQL_BIND));
+ inbind[0].buffer_type= MYSQL_TYPE_LONG;
+ inbind[0].buffer= (char *)&int_res;
+
+ CPPUNIT_ASSERT(mysql_stmt_bind_param(stmt, inbind) == 0);
+ CPPUNIT_ASSERT(mysql_stmt_execute(stmt) == 0);
+
+ memset(outbind, 0, sizeof(MYSQL_BIND));
+ outbind[0].buffer_type = MYSQL_TYPE_STRING;
+ outbind[0].buffer = result;
+ outbind[0].buffer_length = sizeof(result);
+ outbind[0].is_null = &isnull;
+ outbind[0].length = &length;
+ CPPUNIT_ASSERT(mysql_stmt_bind_result(stmt, outbind) == 0);
+ CPPUNIT_ASSERT(mysql_stmt_fetch(stmt) == 0);
+ CPPUNIT_ASSERT(length == strlen(str1)+strlen(str2));
+ CPPUNIT_ASSERT(mysql_stmt_fetch_column(stmt,outbind,0,strlen(str1)) == 0);
+ CPPUNIT_ASSERT(strcmp(result,str2) == 0);
+
+ CPPUNIT_ASSERT(mysql_stmt_close(stmt) == 0);
+}
Index: libmysequoia/test/TestMySQLAPI.hpp
diff -u libmysequoia/test/TestMySQLAPI.hpp:1.9
libmysequoia/test/TestMySQLAPI.hpp:1.10
--- libmysequoia/test/TestMySQLAPI.hpp:1.9 Fri Jan 13 15:01:10 2006
+++ libmysequoia/test/TestMySQLAPI.hpp Tue Jan 17 09:38:38 2006
@@ -53,6 +53,7 @@
CPPUNIT_TEST (mysql_stmt_prepare_bind_exec_test);
CPPUNIT_TEST (mysql_stmt_select_fetch_test);
CPPUNIT_TEST (mysql_stmt_store_fetch_test);
+ CPPUNIT_TEST (mysql_stmt_long_data_fetch_field_test);
CPPUNIT_TEST_SUITE_END ();
public:
@@ -83,6 +84,7 @@
void mysql_stmt_prepare_bind_exec_test(void);
void mysql_stmt_select_fetch_test(void);
void mysql_stmt_store_fetch_test(void);
+ void mysql_stmt_long_data_fetch_field_test(void);
private:
MYSQL *mysql;
};
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits