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

Reply via email to