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