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