Date: Thursday, January 12, 2006 @ 18:30:46
  Author: zsolt
    Path: /cvsroot/carob/libmysequoia

Modified: include/CarobStmt.hpp (1.4 -> 1.5) src/CarobMySQL.cpp (1.30 ->
          1.31) src/CarobStmt.cpp (1.7 -> 1.8) src/MySQLAPI.cpp (1.26 ->
          1.27)

- moved PCHAR definition in Utils.hpp
- Implemented the following functions. With this function now is possible to 
handle the results from a select in a prepared statement.
CarobStmt::bind_result()
CarobStmt::fetch()
CarobStmt::store_result()
CarobStmt::alloc_fetch_field()
CarobStmt::delete_fetch_field()
CarobStmt::free_catched_result()
mysql_stmt_bind_result()
mysql_stmt_fetch()
mysql_stmt_field_count()
mysql_stmt_store_result()
- modified clear() to remove a statement only if the statement is not null


-----------------------+
 include/CarobStmt.hpp |    9 +
 src/CarobMySQL.cpp    |    2 
 src/CarobStmt.cpp     |  349 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/MySQLAPI.cpp      |   54 +++++--
 4 files changed, 396 insertions(+), 18 deletions(-)


Index: libmysequoia/include/CarobStmt.hpp
diff -u libmysequoia/include/CarobStmt.hpp:1.4 
libmysequoia/include/CarobStmt.hpp:1.5
--- libmysequoia/include/CarobStmt.hpp:1.4      Wed Jan 11 11:25:37 2006
+++ libmysequoia/include/CarobStmt.hpp  Thu Jan 12 18:30:46 2006
@@ -29,6 +29,7 @@
 
 //Carob includes
 #include <ParameterStatement.hpp>
+#include <DriverResultSet.hpp>
 
 class CarobStmt : public CarobCommon
 {
@@ -40,6 +41,7 @@
   int fetch();
   int prepare(const char *query, unsigned long length);
   bool bind_param(const MYSQL_BIND *bind);
+  bool bind_result(const MYSQL_BIND *bind);
   bool reset();
   
   MYSQL_RES *param_metadata();
@@ -53,9 +55,16 @@
   MYSQL_STMT *m_stmt;
   CarobNS::ParameterStatement *c_stmt;
   CarobMYSQL *cmysql;
+  CarobNS::DriverResultSet *liveResultSet;
 
   void clear();
 
+  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);
+  
   /**
    * Set the current mysql error to the specified one. The mysql error message 
will be filled from the error list.
    * @param errcode mysql error code
Index: libmysequoia/src/CarobMySQL.cpp
diff -u libmysequoia/src/CarobMySQL.cpp:1.30 
libmysequoia/src/CarobMySQL.cpp:1.31
--- libmysequoia/src/CarobMySQL.cpp:1.30        Thu Jan 12 17:35:44 2006
+++ libmysequoia/src/CarobMySQL.cpp     Thu Jan 12 18:30:46 2006
@@ -660,8 +660,6 @@
   LOG4CXX_DEBUG(logger, "Leaving set_error.");
 }
 
-typedef char *PCHAR;
-
 void
 CarobMYSQL::alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned 
int field_count, unsigned long &length, unsigned long *lengths)
 {
Index: libmysequoia/src/CarobStmt.cpp
diff -u libmysequoia/src/CarobStmt.cpp:1.7 libmysequoia/src/CarobStmt.cpp:1.8
--- libmysequoia/src/CarobStmt.cpp:1.7  Thu Jan 12 17:35:44 2006
+++ libmysequoia/src/CarobStmt.cpp      Thu Jan 12 18:30:46 2006
@@ -36,7 +36,7 @@
 using namespace CarobNS;
 using namespace std;
 
-CarobStmt::CarobStmt(MYSQL *mysql): c_stmt(0)
+CarobStmt::CarobStmt(MYSQL *mysql): c_stmt(0), liveResultSet(0)
 {
   LOG4CXX_DEBUG(logger, "Entering constructor.");
 
@@ -228,7 +228,10 @@
         }
         if (!c_stmt->execute())
           m_stmt->affected_rows = c_stmt->getUpdateCount();
+        else
+          liveResultSet = c_stmt->getResultSet();
 
+        m_stmt->state = MYSQL_STMT_EXECUTE_DONE;
         result = 0;
       }
       catch (CarobException &e)
@@ -241,10 +244,159 @@
   return result;
 }
 
+bool
+CarobStmt::bind_result(const MYSQL_BIND *bind)
+{
+  LOG4CXX_DEBUG(logger, "Entering bind_result.");
+ 
+  bool result = false;
+
+  if (!m_stmt->field_count)
+  {
+    set_error(m_stmt->state < MYSQL_STMT_PREPARE_DONE ? CR_NO_PREPARE_STMT : 
CR_NO_STMT_METADATA, SQLT_UNKNOWN);
+    result = true;
+  }
+  else
+  {
+    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++)
+    {
+      switch (p->buffer_type)
+      {
+        case MYSQL_TYPE_TINY:
+        case MYSQL_TYPE_SHORT:
+        case MYSQL_TYPE_LONG:
+        case MYSQL_TYPE_LONGLONG:
+        case MYSQL_TYPE_FLOAT:
+        case MYSQL_TYPE_DOUBLE:
+        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:
+          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);
+          result = true;
+      }
+    }
+
+    if (!result)
+      m_stmt->bind_result_done= true;
+  }
+  
+  LOG4CXX_DEBUG(logger, "Leaving bind_result.");
+  return result;
+}
+
 int
 CarobStmt::fetch()
 {
-  return 0;
+  LOG4CXX_DEBUG(logger, "Entering fetch.");
+  int result = 0;
+  
+  if (!m_stmt->bind_result_done)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    result = 1;
+  }
+  else
+  {
+    //check if there are more results to fetch
+    if (m_stmt->result.data ? m_stmt->data_cursor != 0 : liveResultSet->next())
+    {
+      MYSQL_FIELD *fPtr = m_stmt->fields;
+      MYSQL_BIND *bPtr = m_stmt->bind;
+      for (unsigned colNo=1; 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);
+
+        if (!buffer)
+        {
+          *bPtr->is_null = true;
+        }
+        else
+        {
+          bool error = false;
+          switch (fPtr->type)
+          {
+            case MYSQL_TYPE_TINY:
+              error = getFromTiny(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_SHORT:
+              error = getFromShort(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_LONG:
+              error = getFromLong(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_LONGLONG:
+              error = getFromLonglong(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_FLOAT:
+              error = getFromFloat(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_DOUBLE:
+              error = 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:
+              error = getFromString(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_TIME:
+              error = getFromTime(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_DATE:
+              error = getFromDate(bPtr, fPtr, buffer);
+              break;
+            case MYSQL_TYPE_DATETIME:
+            case MYSQL_TYPE_TIMESTAMP:
+              error = 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 (error)
+            result = MYSQL_DATA_TRUNCATED;
+        }
+      }
+      
+      if (m_stmt->result.data)
+        m_stmt->data_cursor = m_stmt->data_cursor->next;
+    }
+    else
+      result = MYSQL_NO_DATA;
+  }
+  
+  LOG4CXX_DEBUG(logger, "Leaving fetch.");
+  return result;
 }
 
 bool
@@ -262,7 +414,55 @@
 int
 CarobStmt::store_result()
 {
-  return 0;
+  LOG4CXX_DEBUG(logger, "Entering store_result.");
+
+  int result = 0;
+  
+  if (m_stmt->state < MYSQL_STMT_EXECUTE_DONE)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    result = 1;
+  }
+  else
+    if (m_stmt->field_count && liveResultSet)
+    {    
+      if (m_stmt->result.data)
+        free_catched_result(m_stmt);
+  
+      memset(&m_stmt->result, 0, sizeof(MYSQL_DATA));
+      m_stmt->result.fields = m_stmt->field_count;
+      
+      MYSQL_ROWS *prev = 0;
+      //Fetch row by row and allocate memory for each row
+      while (liveResultSet->next())
+      {
+        MYSQL_ROWS *row = new MYSQL_ROWS;
+        memset(row,0,sizeof(MYSQL_ROWS));
+        row->data = new PCHAR[m_stmt->field_count];
+
+        MYSQL_FIELD *fPtr = m_stmt->fields;
+        MYSQL_ROW dataPtr = row->data;
+
+        for (unsigned colNo=1; colNo <= m_stmt->field_count; colNo++, fPtr++, 
dataPtr++)
+          *dataPtr = (char *)alloc_fetch_field(fPtr, colNo);
+        if (prev)
+          prev->next = row;
+        else
+          m_stmt->result.data = row;
+        prev = row;
+        m_stmt->result.rows++;
+      }
+      m_stmt->data_cursor = m_stmt->result.data;
+      m_stmt->affected_rows = m_stmt->result.rows;
+  
+      //Release the Carob dataset      
+      c_stmt->close();
+      liveResultSet = 0;
+    }
+
+  LOG4CXX_DEBUG(logger, "Leaving store_result.");
+
+  return result;
 }
 
 bool
@@ -271,6 +471,137 @@
   return 0;
 }
 
+void *
+CarobStmt::alloc_fetch_field(MYSQL_FIELD *fPtr, unsigned colNo)
+{
+  LOG4CXX_DEBUG(logger, "Entering alloc_fetch_field.");
+  
+  void *result = 0;
+  
+  try
+  {
+    switch (fPtr->type)
+    {
+      case MYSQL_TYPE_TINY:
+        result = new unsigned char(liveResultSet->getInt32(colNo));
+        break;
+      case MYSQL_TYPE_SHORT:
+        result = new short(liveResultSet->getInt32(colNo));
+        break;
+      case MYSQL_TYPE_LONG:
+        result = new int(liveResultSet->getInt32(colNo));
+        break;
+      case MYSQL_TYPE_LONGLONG:
+//        result = new(long long(liveResultSet->getInt64(colNo)));
+        break;
+      case MYSQL_TYPE_FLOAT:
+//        result = new(float(liveResultSet->getFloat(colNo)));
+        break;
+      case MYSQL_TYPE_DOUBLE:
+//        result = new(double(liveResultSet->getDouble(colNo)));
+        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:
+        result = new string(toString(liveResultSet->getAsString(colNo)));
+        break;
+      case MYSQL_TYPE_TIME:
+        break;
+      case MYSQL_TYPE_DATE:
+        break;
+      case MYSQL_TYPE_DATETIME:
+      case MYSQL_TYPE_TIMESTAMP:
+        break;
+      case MYSQL_TYPE_NULL:
+        break;
+      default:
+        LOG4CXX_DEBUG(logger, "This should never happen!!");
+    }
+  }
+  catch (NullValueException)
+  {
+  }
+  
+  LOG4CXX_DEBUG(logger, "Leaving alloc_fetch_field.");
+  
+  return result;
+}
+
+void
+CarobStmt::delete_fetch_field(MYSQL_FIELD *fPtr, void *buffer)
+{
+  switch (fPtr->type)
+  {
+    case MYSQL_TYPE_TINY:
+      delete (unsigned char *)buffer;
+      break;
+    case MYSQL_TYPE_SHORT:
+      delete (short *)buffer;
+      break;
+    case MYSQL_TYPE_LONG:
+      delete (int *)buffer;
+      break;
+    case MYSQL_TYPE_LONGLONG:
+      delete (long long *)buffer;
+      break;
+    case MYSQL_TYPE_FLOAT:
+      delete (float *)buffer;
+      break;
+    case MYSQL_TYPE_DOUBLE:
+      delete (double *)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:
+      delete (string *)buffer;
+      break;
+    case MYSQL_TYPE_TIME:
+      break;
+    case MYSQL_TYPE_DATE:
+      break;
+    case MYSQL_TYPE_DATETIME:
+    case MYSQL_TYPE_TIMESTAMP:
+      break;
+    case MYSQL_TYPE_NULL:
+      break;
+    default:
+      LOG4CXX_DEBUG(logger, "This should never happen!!");
+  }
+}
+
+void
+CarobStmt::free_catched_result(MYSQL_STMT *stmt)
+{
+  if (stmt->result.data)
+  {
+    MYSQL_ROWS *tmp;
+    while ((tmp = stmt->result.data))
+    {
+      stmt->result.data = stmt->result.data->next;
+      MYSQL_FIELD *fPtr = stmt->fields;
+      MYSQL_ROW dataPtr = tmp->data;
+      for (unsigned colNo=0; colNo < stmt->field_count; colNo++, fPtr++, 
dataPtr++)
+        delete_fetch_field(fPtr, *dataPtr);
+      delete []tmp->data;
+      delete tmp;
+    }
+    stmt->result.rows= 0;
+    stmt->data_cursor= NULL;
+  }
+}
+
 void
 CarobStmt::set_error(int errcode, int sqlstate)
 {
@@ -298,8 +629,16 @@
 void
 CarobStmt::clear()
 {
-  cmysql->connectionPtr->deleteStatement(c_stmt);
-  c_stmt = NULL;
+  if (c_stmt)
+  {
+    cmysql->connectionPtr->deleteStatement(c_stmt);
+    c_stmt = NULL;
+  }
+
+  liveResultSet = 0;
+
+  free_catched_result(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.26 libmysequoia/src/MySQLAPI.cpp:1.27
--- libmysequoia/src/MySQLAPI.cpp:1.26  Wed Jan 11 12:51:42 2006
+++ libmysequoia/src/MySQLAPI.cpp       Thu Jan 12 18:30:46 2006
@@ -1184,6 +1184,25 @@
   return result;
 }
 
+my_bool
+mysql_stmt_bind_result (MYSQL_STMT * stmt, MYSQL_BIND * bind)
+{
+  LOG4CXX_DEBUG(logger, "Entering mysql_stmt_bind_result.");
+  my_bool result = false;
+
+  if (isCarobObject(stmt))
+    result = getCarobStmt(stmt)->bind_result(bind);
+  else
+  {
+    LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized 
with mysql_stmt_init.");
+    //Todo maybe better errorhandling?
+    result = true;
+  }
+
+  LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_bind_result.");
+  return result;
+}
+
 unsigned int
 mysql_stmt_errno (MYSQL_STMT * stmt)
 {
@@ -1226,14 +1245,6 @@
   return result;
 }
 
-my_bool
-mysql_stmt_bind_result (MYSQL_STMT * stmt, MYSQL_BIND * bind)
-{
-  LOG4CXX_DEBUG(logger, "Entering mysql_stmt_bind_result.");
-  LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_bind_result.");
-  return 0;
-}
-
 void
 mysql_stmt_data_seek (MYSQL_STMT * stmt, my_ulonglong offset)
 {
@@ -1245,8 +1256,18 @@
 mysql_stmt_fetch (MYSQL_STMT * stmt)
 {
   LOG4CXX_DEBUG(logger, "Entering mysql_stmt_fetch.");
+  int result = 0;
+
+  if (isCarobObject(stmt))
+    result = getCarobStmt(stmt)->fetch();
+  else
+  {
+    LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized 
with mysql_stmt_init.");
+    //Todo maybe better errorhandling?
+    result = 1;
+  }
   LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_fetch.");
-  return 0;
+  return result;
 }
 
 int
@@ -1262,8 +1283,9 @@
 mysql_stmt_field_count (MYSQL_STMT * stmt)
 {
   LOG4CXX_DEBUG(logger, "Entering mysql_stmt_field_count.");
+  unsigned result = stmt ? stmt->field_count : 0;
   LOG4CXX_DEBUG(logger, "Leaving mysql_stmt_field_count.");
-  return 0;
+  return result;
 }
 
 my_bool
@@ -1358,6 +1380,16 @@
 mysql_stmt_store_result (MYSQL_STMT * stmt)
 {
   LOG4CXX_DEBUG(logger, "Entering mysql_stmt_store_result.");
+  int result = 0;
+
+  if (isCarobObject(stmt))
+    result = getCarobStmt(stmt)->store_result();
+  else
+  {
+    LOG4CXX_ERROR(logger, "The given mysql stmt pointer was not initialized 
with mysql_stmt_init.");
+    //Todo maybe better errorhandling?
+    result = 1;
+  }
   LOG4CXX_DEBUG(logger, "Leave mysql_stmt_store_result.");
-  return 0;
+  return result;
 }

_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits

Reply via email to