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