Date: Monday, December 12, 2005 @ 14:22:40
  Author: zsolt
    Path: /cvsroot/carob/libmysequoia

Modified: include/CarobMySQL.hpp (1.8 -> 1.9) include/Utils.hpp (1.6 ->
          1.7) src/CarobMySQL.cpp (1.14 -> 1.15) src/MySQLAPI.cpp (1.11 ->
          1.12) src/Utils.cpp (1.6 -> 1.7)

- changed alloc_row_data to allocate field_count+1 pointers and to return the 
length of each field
  the last pointer is used to calculate the length of the last field
- implemented
    - CarobMYSQL::get_query_fields - now retrieve field info from Carob
    - CarobMYSQL::delete_query_fields

    - convert_to_pchar
    - sql_to_mysql_type

    - mysql_data_seek
    - mysql_row_seek
    - mysql_row_tell
    - mysql_fetch_field
    - mysql_fetch_field_direct
    - mysql_fetch_fields
    - mysql_fetch_lengths
    - mysql_field_seek
    - mysql_field_count
    - mysql_field_tell

- better error handling (now use driver error messages)


------------------------+
 include/CarobMySQL.hpp |    9 ++++
 include/Utils.hpp      |   19 ++++++++++
 src/CarobMySQL.cpp     |   89 +++++++++++++++++++++++++++++++++++------------
 src/MySQLAPI.cpp       |   84 +++++++++++++++++++++++++++++++++++++++-----
 src/Utils.cpp          |   77 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 247 insertions(+), 31 deletions(-)


Index: libmysequoia/include/CarobMySQL.hpp
diff -u libmysequoia/include/CarobMySQL.hpp:1.8 
libmysequoia/include/CarobMySQL.hpp:1.9
--- libmysequoia/include/CarobMySQL.hpp:1.8     Mon Dec 12 08:58:57 2005
+++ libmysequoia/include/CarobMySQL.hpp Mon Dec 12 14:22:40 2005
@@ -239,13 +239,20 @@
    int get_query_fields(MYSQL_FIELD * &result, CarobNS::DriverResultSet 
*rsPtr);
    
   /**
+   * Release allocated field structure from the memory
+   * @param fields a pointer to the field structure
+   */
+  void delete_query_fields(MYSQL_FIELD * &fields, unsigned int field_count);
+  
+  /**
    * 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
+   * @param lengths pointer to an array which will hold the length of each 
field
    */
-   void alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned int 
field_count, unsigned long &length);
+   void alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned int 
field_count, unsigned long &length, unsigned long *lengths);
 
   /**
    * Release allocated row from the memory
Index: libmysequoia/include/Utils.hpp
diff -u libmysequoia/include/Utils.hpp:1.6 libmysequoia/include/Utils.hpp:1.7
--- libmysequoia/include/Utils.hpp:1.6  Fri Dec  9 15:29:00 2005
+++ libmysequoia/include/Utils.hpp      Mon Dec 12 14:22:40 2005
@@ -23,6 +23,10 @@
 #define _UTILS_HPP
 
 #include <string.h>
+#include <string>
+
+//MySQL includes
+#include <mysql.h>
 
 extern const char *error_sqlstate[];
 
@@ -69,6 +73,14 @@
 char *cstrdupcond(char * &dest, const char *src, int len);
 
 /**
+ * Converts a wstring to a char *.
+ * @param src the wide character string to be converted
+ * @param result reference to a pchar *, which will contain the result. The 
memory for it will be allocated
+ * @param length the length of the resulting string
+ */
+void convert_to_pchar(const std::wstring &src, char * &result, unsigned int 
&length);
+
+/**
  * Returns a client error message associated with the error code.
  * @param code MySQL client error code
  * @return a the detailed error message or null if the error code was not a 
client error
@@ -82,4 +94,11 @@
  */
 int convert_errcode(const int code);
 
+/**
+ * Converts sql field type to mysql type
+ * @param sqltype code of the sql field
+ * @return mapped MySQL field type
+ */
+enum enum_field_types sql_to_mysql_type(const int sqltype);
+
 #endif /* _UTILS_HPP */
Index: libmysequoia/src/CarobMySQL.cpp
diff -u libmysequoia/src/CarobMySQL.cpp:1.14 
libmysequoia/src/CarobMySQL.cpp:1.15
--- libmysequoia/src/CarobMySQL.cpp:1.14        Mon Dec 12 08:58:57 2005
+++ libmysequoia/src/CarobMySQL.cpp     Mon Dec 12 14:22:40 2005
@@ -20,6 +20,7 @@
  */
 
 #include <CarobMySQL.hpp>
+#include <ResultSetMetaData.hpp>
 
 #include <Utils.hpp>
 
@@ -33,14 +34,6 @@
   mysqlPtr = mysql;
 
   connectionPool = &ConnectionPool::getInstance();
-  
-  /*
-   * initialize live results pointer. This will be used to store the result set
-   * when mysql_use_result() function is used
-   */
-
-//  liveResultPtr = new MYSQL_RES;
-//  memset(liveResultSet, 0, sizeof(MYSQL_RES));
 }
 
 CarobMYSQL::~CarobMYSQL ()
@@ -113,7 +106,7 @@
   } 
   catch (CarobException &e)
   {
-    //set_error(, toString(e.description).c_str(), 
toString(e.getSQLState).c_str());
+    set_error(e.getErrorCode(), toString(e.description()).c_str(), 
toString(e.getSQLState()).c_str());
     //TODO error handling
     return 0;
   }
@@ -166,7 +159,7 @@
   }
   catch (CarobException &e)
   {
-    //set_error(, toString(e.description).c_str(), 
toString(e.getSQLState).c_str());
+    set_error(e.getErrorCode(), toString(e.description()).c_str(), 
toString(e.getSQLState()).c_str());
     //TODO error handling
     return false;
   }
@@ -202,6 +195,7 @@
         //Fill the fields metadata        
         result->field_count = get_query_fields(result->fields, drsPtr);
         result->handle = mysqlPtr;
+        result->lengths = new unsigned long[result->field_count];
         
         //Fetch the rows if fetch_all was specified
         if (fetch_all)
@@ -215,7 +209,7 @@
           {
             MYSQL_ROWS *row = new MYSQL_ROWS;
             memset(row,0,sizeof(MYSQL_ROWS));
-            alloc_row_data(row->data, result->fields, result->field_count, 
row->length);
+            alloc_row_data(row->data, result->fields, result->field_count, 
row->length, result->lengths);
             if (prev)
               prev->next = row;
             else
@@ -250,7 +244,7 @@
   }
   catch (CarobException &e)
   {
-    //set_error(, toString(e.description).c_str(), 
toString(e.getSQLState).c_str());
+    set_error(e.getErrorCode(), toString(e.description()).c_str(), 
toString(e.getSQLState()).c_str());
     //TODO error handling
     return NULL;
   }
@@ -269,7 +263,7 @@
   {
     delete_row_data(liveResultPtr->row, liveResultPtr->field_count);
     unsigned long len;
-    alloc_row_data(liveResultPtr->row, liveResultPtr->fields, 
liveResultPtr->field_count, len);
+    alloc_row_data(liveResultPtr->row, liveResultPtr->fields, 
liveResultPtr->field_count, len, liveResultPtr->lengths);
     return (liveResultPtr->current_row = liveResultPtr->row);
   }
   else
@@ -327,8 +321,9 @@
       mysqlPtr->fields = 0;
       mysqlPtr->field_count = 0;
     }
-    delete [] res->fields;
-    
+    delete_query_fields(res->fields, res->field_count);
+
+    delete [] res->lengths;    
     delete res;
   }
   mysqlPtr->status = MYSQL_STATUS_READY;
@@ -400,6 +395,8 @@
 void
 CarobMYSQL::delete_connection()
 {
+  if (liveResultPtr)
+    free_results(liveResultPtr);
   FREE_AND_NULL(connectionPtr);
   FREE_AND_NULL(stmtPtr);
   FREE_AND_NULL(liveResultPtr);
@@ -428,27 +425,75 @@
 int
 CarobMYSQL::get_query_fields(MYSQL_FIELD * &result, DriverResultSet *rsPtr)
 {
-  int colNum = (int)rsPtr->getNumberOfColumns();
+  ResultSetMetaData rsmd(rsPtr);
+  int colNum = (int)rsmd.getColumnCount(), colNo;
   
   result = new MYSQL_FIELD[colNum];
   memset(result, 0, sizeof(MYSQL_FIELD)*colNum);
+
+  MYSQL_FIELD *colPtr;
+  for (colNo=1, colPtr=result; colNo <= colNum; colNo++, colPtr++)
+  {
+    convert_to_pchar(rsmd.getColumnLabel(colNo), colPtr->name, 
colPtr->name_length);
+    convert_to_pchar(rsmd.getColumnName(colNo), colPtr->org_name, 
colPtr->org_name_length);
+    convert_to_pchar(rsmd.getTableName(colNo), colPtr->table, 
colPtr->table_length);
+    colPtr->org_table = colPtr->table;
+    colPtr->org_table_length = colPtr->table_length;
+    //TODO if possible colPtr->db;
+    convert_to_pchar(rsmd.getCatalogName(colNo), colPtr->catalog, 
colPtr->catalog_length);
+    //TODO if possible colPtr->def;
+
+    colPtr->length = rsmd.getPrecision(colNo);
+    colPtr->decimals = rsmd.getScale(colNo);
+
+    //TODO more compatible flags...
+    colPtr->type = sql_to_mysql_type(rsmd.getColumnType(colNo));
+
+    colPtr->flags = (rsmd.isNullable(colNo) ? 0 : NOT_NULL_FLAG) |
+                    (rsmd.isAutoIncrement(colNo) ? AUTO_INCREMENT_FLAG : 0) |
+                    (rsmd.isSigned(colNo) ? 0 : UNSIGNED_FLAG) |
+                    (colPtr->type == MYSQL_TYPE_BLOB ? BLOB_FLAG : 0) |
+                    (IS_NUM(colPtr->type) && colPtr->type != 
MYSQL_TYPE_TIMESTAMP && 
+                      colPtr->type != MYSQL_TYPE_NULL ? NUM_FLAG : 0) | 
+                    (colPtr->type == MYSQL_TYPE_TIMESTAMP ? TIMESTAMP_FLAG : 
0) | 
+                    NO_DEFAULT_VALUE_FLAG;
+  }
   
   return colNum;
 }
 
+void
+CarobMYSQL::delete_query_fields(MYSQL_FIELD * &fields, unsigned int 
field_count)
+{
+  if (fields)
+  {
+    for (MYSQL_FIELD *colPtr=fields; field_count; colPtr++, field_count--)
+    {
+      delete colPtr->name;
+      delete colPtr->org_name;
+      delete colPtr->table;
+      delete colPtr->db;
+      delete colPtr->catalog;
+    }
+    
+    FREE_AND_NULL_ARRAY(fields);
+  }
+}
+
 typedef char *PCHAR;
 
 void
-CarobMYSQL::alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned 
int field_count, unsigned long &length)
+CarobMYSQL::alloc_row_data(MYSQL_ROW &row, MYSQL_FIELD *fields, const unsigned 
int field_count, unsigned long &length, unsigned long *lengths)
 {
   /* 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
+   * separated by \0, and allocate an array of field_count+1 pointers, which
    * will point to this allocated row. The length of the data can be calculated
-   * by substracting the pointer addresses. */
+   * by substracting the pointer addresses. The last pointer is needed to
+   * calculate the length of the last field */
   delete_row_data(row, field_count);
   
-  row = new PCHAR[field_count];
+  row = new PCHAR[field_count+1];
   memset(row, 0, sizeof(PCHAR)*field_count);
   
   std::string result;
@@ -467,7 +512,8 @@
       result.push_back(0);
 
       length += field_len;
-      
+
+      lengths[i] = field_len - 1;      
       if (fields && fields[i].max_length < field_len)
         fields[i].max_length = field_len;
     }
@@ -479,6 +525,7 @@
     for (unsigned i=0; i<field_count; i++)
       if (row[i])
         row[i] = presult + ((unsigned long) row[i] - 1);
+    row[field_count] = presult + result.size();
   }
 }
 
Index: libmysequoia/src/MySQLAPI.cpp
diff -u libmysequoia/src/MySQLAPI.cpp:1.11 libmysequoia/src/MySQLAPI.cpp:1.12
--- libmysequoia/src/MySQLAPI.cpp:1.11  Mon Dec 12 08:58:57 2005
+++ libmysequoia/src/MySQLAPI.cpp       Mon Dec 12 14:22:40 2005
@@ -271,63 +271,129 @@
        return 0;
 }
 
+/* Seeks to an arbitrary row number in a query result set. */
 void STDCALL
 mysql_data_seek (MYSQL_RES * result, my_ulonglong offset)
 {
+  if (result && result->data)
+  {
+    MYSQL_ROWS *curRow;
+    for (curRow=result->data->data; offset && curRow; offset--, curRow = 
curRow->next) ;
+    result->current_row = 0;
+    result->data_cursor = curRow;
+  }
 }
 
+/* Seeks to a row offset in a result set, using value returned from 
mysql_row_tell(). */
 MYSQL_ROW_OFFSET STDCALL
 mysql_row_seek (MYSQL_RES * result, MYSQL_ROW_OFFSET offset)
 {
-       return 0;
+  if (result && result->data)
+  {
+    MYSQL_ROW_OFFSET oldRow = result->data_cursor;
+    result->current_row = 0;
+    result->data_cursor = offset;
+    return oldRow;
+  }    
+  else
+    return 0;
 }
 
+/* Seeks to a row offset in a result set, using value returned from 
mysql_row_tell(). */
 MYSQL_ROW_OFFSET STDCALL
 mysql_row_tell (MYSQL_RES * res)
 {
-       return 0;
+  return res ? res->data_cursor : 0;
 }
 
+/* Returns the type of the next table field. */
 MYSQL_FIELD *STDCALL
 mysql_fetch_field (MYSQL_RES * result)
 {
-       return 0;
+  if (result && (result->current_field < result->field_count))
+    return &result->fields[result->current_field++];
+  else
+    return 0;
 }
 
+/* Returns the type of a table field, given a field number. */
 MYSQL_FIELD *STDCALL
 mysql_fetch_field_direct (MYSQL_RES * res, unsigned int fieldnr)
 {
-       return 0;
+  if (res && (fieldnr < res->field_count))
+    return &res->fields[fieldnr];
+  else
+    return 0;
 }
 
+/* Returns an array of all field structures. */
 MYSQL_FIELD *STDCALL
 mysql_fetch_fields (MYSQL_RES * res)
 {
-       return 0;
+       return res ? res->fields : 0;
 }
 
+/* Returns the lengths of all columns in the current row. */
 unsigned long *STDCALL
 mysql_fetch_lengths (MYSQL_RES * result)
 {
-       return 0;
+  if (result && result->current_row)
+  {
+    //Calculate the field length from pointer offsets
+    if (result->data)
+    {
+      unsigned long *curLength, *lastLength = 0;
+      MYSQL_ROW curField;
+      char *lastField = 0;
+      int colNo;
+      
+      for (colNo = result->field_count+1, curField = result->current_row, 
curLength = result->lengths; 
+           colNo; curField++, colNo--, curLength++)
+      {
+        if (!*curField)
+          *curLength = 0;
+        else
+        {
+          if (lastField)
+            *lastLength = *curField-lastField-1;
+          lastField = *curField;
+          lastLength = curLength;
+        }
+      }
+    }
+    
+    return result->lengths;
+  }
+  else
+    return 0;
 }
 
+/* Returns the type of the next table field. */
 MYSQL_FIELD_OFFSET STDCALL
 mysql_field_seek (MYSQL_RES * result, MYSQL_FIELD_OFFSET offset)
 {
-       return 0;
+  if (result)
+  {
+    MYSQL_FIELD_OFFSET old = result->current_field;
+    result->current_field = offset < result->field_count ? offset : 
result->field_count;
+    return old;
+  }
+  else
+    return 0;
 }
 
+/* Returns the number of result columns for the most recent statement. */
 unsigned int STDCALL
 mysql_field_count (MYSQL * mysql)
 {
-       return 0;
+       return mysql ? mysql->field_count : 0;
 }
 
+/* Returns the position of the field cursor used for the last 
mysql_fetch_field(). */
 MYSQL_FIELD_OFFSET STDCALL
 mysql_field_tell (MYSQL_RES * res)
 {
-       return 0;
+       return res ? res->current_field : 0;
 }
 
 /* Returns the number of columns in a result set. */
Index: libmysequoia/src/Utils.cpp
diff -u libmysequoia/src/Utils.cpp:1.6 libmysequoia/src/Utils.cpp:1.7
--- libmysequoia/src/Utils.cpp:1.6      Fri Dec  9 15:29:00 2005
+++ libmysequoia/src/Utils.cpp  Mon Dec 12 14:22:40 2005
@@ -19,11 +19,17 @@
  * Contributor(s): 
  */
 
+//Carob includes
+#include <Common.hpp>
+#include <TypeConstants.hpp>
+
 #include <Utils.hpp>
 
 /* MySQL include */
 #include <errmsg.h>
 
+using namespace CarobNS;
+
 const char *error_sqlstate[]=
 {
   "00000",
@@ -130,6 +136,12 @@
   return dest;
 }
 
+void convert_to_pchar(const std::wstring &src, char * &result, unsigned int 
&length)
+{
+  length = src.length();
+  result = cstrdup(toString(src).data(), length);
+}
+
 const char *get_error_msg(const int code)
 {
   if (code >= CR_MIN_ERROR && code <= CR_MAX_ERROR)
@@ -145,3 +157,68 @@
   //TODO do more error conversion !!
   return CR_MIN_ERROR;
 }
+
+enum enum_field_types sql_to_mysql_type(const int sqltype)
+{
+  switch (sqltype)
+  {
+    case SQLT_BIT:
+      return MYSQL_TYPE_BIT;
+      break;
+    case SQLT_BOOLEAN:
+    case SQLT_TINYINT:
+      return MYSQL_TYPE_TINY;
+      break;
+    case SQLT_SMALLINT:
+      return MYSQL_TYPE_SHORT;
+      break;
+    case SQLT_INTEGER:
+      return MYSQL_TYPE_LONG;
+      break;
+    case SQLT_BIGINT:
+      return MYSQL_TYPE_LONGLONG;
+      break;
+    case SQLT_FLOAT:
+      return MYSQL_TYPE_FLOAT;
+      break;
+    case SQLT_REAL:
+    case SQLT_DOUBLE:
+      return MYSQL_TYPE_DOUBLE;
+      break;
+    case SQLT_NUMERIC:
+    case SQLT_DECIMAL:
+      return MYSQL_TYPE_NEWDECIMAL;
+      break;
+    case SQLT_BINARY:
+    case SQLT_CHAR:
+      return MYSQL_TYPE_STRING;
+      break;
+    case SQLT_VARBINARY:
+    case SQLT_VARCHAR:
+      return MYSQL_TYPE_VAR_STRING;
+      break;
+    case SQLT_LONGVARCHAR:
+      return MYSQL_TYPE_BLOB;
+      break;
+    case SQLT_DATE:
+      return MYSQL_TYPE_DATE;
+      break;
+    case SQLT_TIME:
+      return MYSQL_TYPE_TIME;
+      break;
+    case SQLT_TIMESTAMP:
+      return MYSQL_TYPE_TIMESTAMP;
+      break;
+    case SQLT_BLOB:
+    case SQLT_CLOB:
+    case SQLT_LONGVARBINARY:
+      return MYSQL_TYPE_BLOB;
+      break;
+//    case SQLT_NULL:
+//      return MYSQL_TYPE_NULL;
+//      break;
+    default:
+      //TODO what to return ?? raise an error ??
+      return MYSQL_TYPE_NULL;
+  }
+}

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

Reply via email to