Date: Friday, December 9, 2005 @ 15:29:00
  Author: zsolt
    Path: /cvsroot/carob/libmysequoia

Modified: include/CarobMySQL.hpp (1.6 -> 1.7) include/Utils.hpp (1.5 ->
          1.6) src/CarobMySQL.cpp (1.12 -> 1.13) src/MySQLAPI.cpp (1.9 ->
          1.10) src/Utils.cpp (1.5 -> 1.6)

- implemented the following functions:
CarobMYSQL::get_query_fields
CarobMYSQL::alloc_row_data
CarobMYSQL::delete_row_data
CarobMYSQL::real_query
CarobMYSQL::fetch_row
CarobMYSQL::free_results
mysql_query
mysql_real_query
mysql_use_result
mysql_store_result
mysql_free_result
mysql_fetch_row
- implemented the FREE_AND_NULL_ARRAY macro
- implemented that when a live query is running and another query is tried to 
executed on the server to result in a CR_COMMANDS_OUT_OF_SYNC


------------------------+
 include/CarobMySQL.hpp |   33 +++++
 include/Utils.hpp      |    3 
 src/CarobMySQL.cpp     |  274 ++++++++++++++++++++++++++++++++++++++++++++---
 src/MySQLAPI.cpp       |   73 ++++++++----
 src/Utils.cpp          |   17 ++
 5 files changed, 359 insertions(+), 41 deletions(-)


Index: libmysequoia/include/CarobMySQL.hpp
diff -u libmysequoia/include/CarobMySQL.hpp:1.6 
libmysequoia/include/CarobMySQL.hpp:1.7
--- libmysequoia/include/CarobMySQL.hpp:1.6     Thu Dec  8 09:04:57 2005
+++ libmysequoia/include/CarobMySQL.hpp Fri Dec  9 15:29:00 2005
@@ -111,7 +111,13 @@
      *         if fetch_all was false will return liveResultPtr
      */ 
     MYSQL_RES * get_results(my_bool fetch_all);
-       
+
+  /**
+   * If a live query is ongoing return the next row from the result set.
+   * there are more results on the server
+   */
+    MYSQL_ROW fetch_row();
+
        /**
         * In the case of multiple statement execution, returns true if
         * there are more results on the server
@@ -190,6 +196,7 @@
        CarobNS::Connection *connectionPtr;
        CarobNS::ConnectionPool *connectionPool;
        CarobNS::Statement *stmtPtr;
+  CarobNS::DriverResultSet *drsPtr;
        //holds the result set for 'live' type of results
        MYSQL_RES *liveResultPtr;
   
@@ -224,6 +231,30 @@
    * @param sqlstate ansi sql specific error message
    */
   void set_error(int errcode, const char *errmsg, const char *sqlstate);
+
+  /**
+   * Allocates the field info for a query
+   * @param result the resulting MYSQL_FIELD structure
+   * @param drsPtr a pointer containing the driver resultset from sequoia
+   * @return numer of fields in the query
+   */
+   int get_query_fields(MYSQL_FIELD * &result, CarobNS::DriverResultSet 
*rsPtr);
+   
+  /**
+   * Allocates a row from the freshly fetched results
+   * @param row the resulting row
+   * @param fields pointer to the field structure to update the max column 
length or null
+   * @param field_count number of fields in the result
+   * @param length total length of the result
+   */
+   void alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned int 
field_count, unsigned long &length);
+
+  /**
+   * Release allocated row from the memory
+   * @param row a pointer containing the row with data
+   * @param field_count number of fields in the row
+   */
+   void delete_row_data(MYSQL_ROW &row, const unsigned int field_count);
 };
 
 #endif /* _CAROBMYSQL_HPP */
Index: libmysequoia/include/Utils.hpp
diff -u libmysequoia/include/Utils.hpp:1.5 libmysequoia/include/Utils.hpp:1.6
--- libmysequoia/include/Utils.hpp:1.5  Thu Dec  8 09:04:57 2005
+++ libmysequoia/include/Utils.hpp      Fri Dec  9 15:29:00 2005
@@ -31,7 +31,8 @@
 
 extern const char *error_messages[];
 
-#define FREE_AND_NULL(p) if (p) {delete p; p=0;}
+#define FREE_AND_NULL(p) {delete p; p=0;}
+#define FREE_AND_NULL_ARRAY(p) {delete[] p; p=0;}
 
 /**
  * Creates a duplicate of a null terminated string and return the pointer to 
it.
Index: libmysequoia/src/CarobMySQL.cpp
diff -u libmysequoia/src/CarobMySQL.cpp:1.12 
libmysequoia/src/CarobMySQL.cpp:1.13
--- libmysequoia/src/CarobMySQL.cpp:1.12        Thu Dec  8 14:37:56 2005
+++ libmysequoia/src/CarobMySQL.cpp     Fri Dec  9 15:29:00 2005
@@ -28,7 +28,7 @@
 
 using namespace CarobNS;
 
-CarobMYSQL::CarobMYSQL (): connectionPtr(NULL), stmtPtr(NULL), 
liveResultPtr(NULL)
+CarobMYSQL::CarobMYSQL (): connectionPtr(0), stmtPtr(0), drsPtr(0), 
liveResultPtr(0)
 {
   //TODO handle special case when not enough memory
   mysqlPtr = new CMYSQL();
@@ -60,8 +60,12 @@
                     const char *passwd, const char *db, unsigned int port,
                     const char *unix_socket, unsigned long clientflag)
 {
-  //TODO handle special case when a live query is ongoing, in that case return 
CR_COMMANDS_OUT_OF_SYNC
-  
+  if (mysqlPtr->my.status != MYSQL_STATUS_READY)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    return 0;
+  }
+
   if (unix_socket)
   {
     set_error(CR_NOT_IMPLEMENTED, SQLT_UNKNOWN);
@@ -78,6 +82,9 @@
   if (!host || !*host)
     host = "localhost";
 
+  if (!passwd)
+    passwd = "";
+    
   if (!port)
     port = 25322;
   
@@ -105,6 +112,8 @@
 
       connectionPtr = newConnectionPtr;
       stmtPtr = connectionPtr->createStatement();
+// Commented out because of bug in Carob when setting fetchsize 1
+//      stmtPtr->setFetchSize(1);
     }
     
     return true;
@@ -140,13 +149,142 @@
 bool
 CarobMYSQL::real_query (const char *query, ulong length)
 {
-  return 0;
+  if (mysqlPtr->my.status != MYSQL_STATUS_READY)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    return 0;
+  }
+
+  try {
+    drsPtr = NULL;
+
+    if (stmtPtr->execute(fromString(std::string(query,length))))
+    {
+      mysqlPtr->my.affected_rows = 0;
+      mysqlPtr->my.status = MYSQL_STATUS_GET_RESULT;
+    }
+    else
+    {
+      mysqlPtr->my.affected_rows = stmtPtr->getUpdateCount();
+      mysqlPtr->my.status = MYSQL_STATUS_READY;
+    }
+    
+    return true;
+  }
+  catch (CarobException &e)
+  {
+    //set_error(, toString(e.description).c_str(), 
toString(e.getSQLState).c_str());
+    //TODO error handling
+    return false;
+  }
 }
 
 MYSQL_RES *
 CarobMYSQL::get_results (my_bool fetch_all)
 {
-  return 0;
+  if (mysqlPtr->my.status != MYSQL_STATUS_GET_RESULT)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    return 0;
+  }
+
+  //If we already stored or used the results, we are not allowed to use it 
again
+  if (drsPtr)
+  {
+    set_error(CR_FETCH_CANCELED, SQLT_UNKNOWN);
+    return 0;
+  }
+  try {
+    if (stmtPtr)
+    {
+      MYSQL_RES *result = 0;
+      
+      drsPtr = stmtPtr->getResultSet();
+      if (drsPtr)
+      {
+        //TODO handle not enough memory (std::nothrow)
+        result = new MYSQL_RES;
+        memset(result, 0, sizeof(MYSQL_RES));
+
+        //Fill the fields metadata        
+        result->field_count = get_query_fields(result->fields, drsPtr);
+        result->handle = (MYSQL *)mysqlPtr;
+        
+        //Fetch the rows if fetch_all was specified
+        if (fetch_all)
+        {
+          result->data = new MYSQL_DATA;
+          memset(result->data, 0, sizeof(MYSQL_DATA));
+          result->data->fields = result->field_count;
+          MYSQL_ROWS *prev = 0;
+          //Fetch row by row and allocate memory for each row
+          while (drsPtr->next())
+          {
+            MYSQL_ROWS *row = new MYSQL_ROWS;
+            memset(row,0,sizeof(MYSQL_ROWS));
+            alloc_row_data(row->data, result->fields, result->field_count, 
row->length);
+            if (prev)
+              prev->next = row;
+            else
+              result->data->data = row;
+            prev = row;
+            result->data->rows++;
+          }
+          result->row_count=result->data->rows;
+          result->data_cursor = result->data->data;
+          mysqlPtr->my.status = MYSQL_STATUS_READY;
+          
+          //TODO release carob resultset
+          drsPtr = 0;
+        }
+        else
+        {
+          //TODO check when to free the main internal liveResultPtr
+          liveResultPtr = result;
+          mysqlPtr->my.status = MYSQL_STATUS_USE_RESULT;
+        }
+
+        mysqlPtr->my.field_count = result->field_count;
+        mysqlPtr->my.affected_rows = result->row_count;
+        mysqlPtr->my.fields = result->fields;
+      }
+      else
+        set_error(CR_NO_RESULT_SET, SQLT_UNKNOWN);
+
+      return result;
+    }
+    return NULL;
+  }
+  catch (CarobException &e)
+  {
+    //set_error(, toString(e.description).c_str(), 
toString(e.getSQLState).c_str());
+    //TODO error handling
+    return NULL;
+  }
+}
+
+MYSQL_ROW
+CarobMYSQL::fetch_row()
+{
+  if (mysqlPtr->my.status != MYSQL_STATUS_USE_RESULT || !drsPtr)
+  {
+    set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
+    return 0;
+  }
+  
+  if (drsPtr->next())
+  {
+    delete_row_data(liveResultPtr->row, liveResultPtr->field_count);
+    unsigned long len;
+    alloc_row_data(liveResultPtr->row, liveResultPtr->fields, 
liveResultPtr->field_count, len);
+    return (liveResultPtr->current_row = liveResultPtr->row);
+  }
+  else
+  {
+    liveResultPtr->eof = 1;
+    liveResultPtr->current_row = 0;
+    return 0;
+  }
 }
 
 bool
@@ -164,6 +302,43 @@
 void
 CarobMYSQL::free_results (MYSQL_RES * res)
 {
+  if (res)
+  {
+    if (res == liveResultPtr)
+    {
+      liveResultPtr = 0;
+      drsPtr = 0;
+      //TODO free the carob result too
+    }
+    
+    if (res->data)
+    {
+      MYSQL_ROWS *row = res->data->data;
+      while (row)
+      {
+        MYSQL_ROWS *tempRow = row;
+        row = row->next;
+        delete_row_data(tempRow->data, res->field_count);
+        delete tempRow;
+      }
+
+      delete res->data;
+    }
+    else
+    {
+      delete_row_data(res->current_row,res->field_count);
+    }
+    
+    if (mysqlPtr->my.fields == res->fields)
+    {
+      mysqlPtr->my.fields = 0;
+      mysqlPtr->my.field_count = 0;
+    }
+    delete [] res->fields;
+    
+    delete res;
+  }
+  mysqlPtr->my.status = MYSQL_STATUS_READY;
 }
 
 bool
@@ -224,9 +399,8 @@
   cstrdupcond(mysqlPtr->my.db, db);
   mysqlPtr->my.port = port;
 
-  //Warning buffer overflow error ...
-  char buf[101];
-  snprintf(buf, 101, "%s via TCP/IP", host); buf[100]='\0';
+  char buf[100];
+  snprintf(buf, sizeof(buf), "%s via TCP/IP", host); buf[sizeof(buf)-1]='\0';
   cstrdupcond(mysqlPtr->my.host_info, buf);
 }
 
@@ -235,11 +409,11 @@
 {
   if (free_mysql)
   {
-    FREE_AND_NULL(mysqlPtr->my.host);
-    FREE_AND_NULL(mysqlPtr->my.user);
-    FREE_AND_NULL(mysqlPtr->my.passwd);
-    FREE_AND_NULL(mysqlPtr->my.db);
-    FREE_AND_NULL(mysqlPtr->my.host_info);
+    FREE_AND_NULL_ARRAY(mysqlPtr->my.host);
+    FREE_AND_NULL_ARRAY(mysqlPtr->my.user);
+    FREE_AND_NULL_ARRAY(mysqlPtr->my.passwd);
+    FREE_AND_NULL_ARRAY(mysqlPtr->my.db);
+    FREE_AND_NULL_ARRAY(mysqlPtr->my.host_info);
   }
   
   FREE_AND_NULL(connectionPtr);
@@ -266,3 +440,77 @@
   else
     *mysqlPtr->my.net.sqlstate = 0;
 }
+
+int
+CarobMYSQL::get_query_fields(MYSQL_FIELD * &result, DriverResultSet *rsPtr)
+{
+  int colNum = (int)rsPtr->getNumberOfColumns();
+  
+  result = new MYSQL_FIELD[colNum];
+  memset(result, 0, sizeof(MYSQL_FIELD)*colNum);
+  
+  return colNum;
+}
+
+typedef char *PCHAR;
+
+void
+CarobMYSQL::alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned 
int field_count, unsigned long &length)
+{
+  /* TODO implement better
+   * The main idea is to allocate a big enough row to hold all data as strings
+   * separated by \0, and allocate an array of field_count pointers, which
+   * will point to this allocated row. The length of the data can be calculated
+   * by substracting the pointer addresses. */
+  delete_row_data(row, field_count);
+  
+  row = new PCHAR[field_count];
+  memset(row, 0, sizeof(PCHAR)*field_count);
+  
+  std::string result;
+  length = 0;
+
+  for (unsigned i=0; i<field_count; i++)
+  {
+    if (!drsPtr->isNull(i+1))
+    {
+      std::wstring s = drsPtr->getString(i+1);
+      unsigned long field_len = s.length() + 1;
+
+      row[i] = (char *)(unsigned long)(result.size()+1);
+
+      result += toString(s);
+      result.push_back(0);
+
+      length += field_len;
+      
+      if (fields && fields[i].max_length < field_len)
+        fields[i].max_length = field_len;
+    }
+  }
+
+  if (result.size())
+  {
+    char * presult = cstrdup(result.data(), result.size());
+    for (unsigned i=0; i<field_count; i++)
+      if (row[i])
+        row[i] = presult + ((unsigned long) row[i] - 1);
+  }
+}
+
+void
+CarobMYSQL::delete_row_data(MYSQL_ROW &row, const unsigned int field_count)
+{
+  if (row)
+  {
+    for (unsigned int i=0; i<field_count; i++)
+      if (row[i])
+      {
+        delete [] row[i];
+        break;
+      }
+
+    delete [] row;
+    row = 0;
+  }
+}
Index: libmysequoia/src/MySQLAPI.cpp
diff -u libmysequoia/src/MySQLAPI.cpp:1.9 libmysequoia/src/MySQLAPI.cpp:1.10
--- libmysequoia/src/MySQLAPI.cpp:1.9   Fri Dec  9 11:59:26 2005
+++ libmysequoia/src/MySQLAPI.cpp       Fri Dec  9 15:29:00 2005
@@ -121,7 +121,7 @@
 {
   if (mysql)
   {
-    return ((CMYSQL *)mysql)->carob->select_db(db) ? 1 : 0;
+    return ((CMYSQL *)mysql)->carob->select_db(db) ? 0 : 1;
   }
   else
     return 0;
@@ -155,39 +155,76 @@
 
 /* Query functions */
 
+/* Executes an SQL query specified as a null-terminated string. */
 int STDCALL
 mysql_query (MYSQL * mysql, const char *q)
 {
-       return 0;
+  return mysql_real_query(mysql, q, strlen(q));
 }
 
+/* Executes an SQL query specified as a null-terminated string. */
 int STDCALL
 mysql_real_query (MYSQL * mysql, const char *q, unsigned long length)
 {
-       return 0;
+  if (mysql)
+    return ((CMYSQL *)mysql)->carob->real_query(q, length) ? 0 : 1;
+  else    
+    return 1;
 }
 
+/* Initiates a row-by-row result set retrieval. */
 MYSQL_RES *STDCALL
 mysql_use_result (MYSQL * mysql)
 {
-       return 0;
+  if (mysql)
+    return ((CMYSQL *)mysql)->carob->get_results(false);
+  else
+    return 0;
 }
 
+/* Retrieves a complete result set to the client. */
 MYSQL_RES *STDCALL
 mysql_store_result (MYSQL * mysql)
 {
-       return 0;
+  if (mysql)
+    return ((CMYSQL *)mysql)->carob->get_results(true);
+  else
+    return 0;
 }
 
+/* Frees memory used by a result set. */
 void STDCALL
 mysql_free_result (MYSQL_RES * result)
 {
+  if (result && result->handle)
+    return ((CMYSQL *)result->handle)->carob->free_results(result);
 }
 
+/* Fetches the next row from the result set. */
 MYSQL_ROW STDCALL
 mysql_fetch_row (MYSQL_RES * result)
 {
-       return 0;
+  if (result)
+  {
+    if (result->data)
+    {
+      MYSQL_ROW curRow = 0;
+
+      if (!result->data_cursor)
+        result->eof = 1;
+      else
+      {
+        curRow = result->data_cursor->data;
+        result->data_cursor = result->data_cursor->next;
+      }
+        
+      return (result->current_row = curRow);
+    }
+    else
+      return ((CMYSQL *)result->handle)->carob->fetch_row();
+  }
+  else
+    return 0;
 }
 
 my_bool STDCALL
@@ -267,22 +304,25 @@
        return 0;
 }
 
+/* Returns the number of columns in a result set. */
 unsigned int STDCALL
 mysql_num_fields (MYSQL_RES * res)
 {
-       return 0;
+  return res ? res->field_count : 0;
 }
 
+/* Returns the number of rows changed/deleted/inserted by the last UPDATE, 
DELETE, or INSERT query. */
 my_ulonglong
 mysql_affected_rows (MYSQL * mysql)
 {
-       return 0;
+  return mysql ? mysql->affected_rows : 0;
 }
 
+/* Returns the number of rows in a result set. */
 my_ulonglong STDCALL
 mysql_num_rows (MYSQL_RES * res)
 {
-       return 0;
+  return res ? res->row_count : 0;
 }
 
 my_ulonglong STDCALL
@@ -297,30 +337,21 @@
 unsigned int STDCALL
 mysql_errno (MYSQL * mysql)
 {
-       if (mysql)
-    return mysql->net.last_errno;
-  else
-    return CR_NULL_POINTER;
+  return mysql ? mysql->net.last_errno : CR_NULL_POINTER;
 }
 
 /* Returns the error message for the most recently invoked MySQL function. */
 const char *STDCALL
 mysql_error (MYSQL * mysql)
 {
-  if (mysql)
-    return mysql->net.last_error;
-  else
-    return error_messages[CR_NULL_POINTER-CR_MIN_ERROR];
+  return mysql ? mysql->net.last_error : 
error_messages[CR_NULL_POINTER-CR_MIN_ERROR];
 }
 
 /* Returns the SQLSTATE error code for the last error. */
 const char *STDCALL
 mysql_sqlstate (MYSQL * mysql)
 {
-  if (mysql)
-    return mysql->net.sqlstate;
-  else
-    return error_sqlstate[SQLT_UNKNOWN];
+  return mysql ? mysql->net.sqlstate : error_sqlstate[SQLT_UNKNOWN];
 }
 
 unsigned int STDCALL
Index: libmysequoia/src/Utils.cpp
diff -u libmysequoia/src/Utils.cpp:1.5 libmysequoia/src/Utils.cpp:1.6
--- libmysequoia/src/Utils.cpp:1.5      Thu Dec  8 09:04:57 2005
+++ libmysequoia/src/Utils.cpp  Fri Dec  9 15:29:00 2005
@@ -99,10 +99,17 @@
 {
   if (src)
   {
-    char *result = new char[len+1];
-    memcpy(result, src, len);
-    result[len] = 0;
-    return result;
+    try 
+    {
+      char *result = new char[len+1];
+      memcpy(result, src, len);
+      result[len] = 0;
+      return result;
+    }
+    catch (...)
+    {
+      return 0;
+    }
   }
   else
     return 0;
@@ -117,7 +124,7 @@
 {
   if (dest != src)
   {
-    delete dest;
+    delete []dest;
     dest = cstrdup(src, len);
   }
   return dest;

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

Reply via email to