Date: Wednesday, June 21, 2006 @ 14:56:22
Author: gilles
Path: /cvsroot/carob/carob
Added: include/ResultAndWarnings.hpp (1.1)
Modified: include/CarobException.hpp (1.46 -> 1.47) include/Connection.hpp
(1.67 -> 1.68) include/DriverResultSet.hpp (1.40 -> 1.41)
include/Statement.hpp (1.41 -> 1.42) src/Connection.cpp (1.76 ->
1.77) src/DriverResultSet.cpp (1.54 -> 1.55) src/Statement.cpp
(1.28 -> 1.29)
Applied changes from sequoia = SQL Warnings on statements
-------------------------------+
include/CarobException.hpp | 17 ++++
include/Connection.hpp | 41 +++++++++--
include/DriverResultSet.hpp | 7 +-
include/ResultAndWarnings.hpp | 140 ++++++++++++++++++++++++++++++++++++++++
include/Statement.hpp | 8 ++
src/Connection.cpp | 92 ++++++++++++++++++++++----
src/DriverResultSet.cpp | 7 +-
src/Statement.cpp | 10 ++
8 files changed, 292 insertions(+), 30 deletions(-)
Index: carob/include/CarobException.hpp
diff -u carob/include/CarobException.hpp:1.46
carob/include/CarobException.hpp:1.47
--- carob/include/CarobException.hpp:1.46 Thu Mar 23 17:10:04 2006
+++ carob/include/CarobException.hpp Wed Jun 21 14:56:22 2006
@@ -316,6 +316,23 @@
};
/**
+ * Not a real exception but subclasses, as in java, an Exception
+ */
+class SQLWarning : public CarobException
+{
+public:
+ /**
+ * Constructs a SQLWarning with the given message
+ * @param s warning message
+ */
+ SQLWarning(const std::wstring& messagePrm,
+ const std::wstring& SQLStatePrm = DEFAULTSQLSTATE,
+ CarobException* causePrm = 0,
+ int vendorPrm = DEFAULTVENDORCODE) :
+ CarobException(messagePrm, SQLStatePrm, causePrm, vendorPrm) {};
+};
+
+/**
* Map of the Java stack trace element contained in an exception
* (actually a CarobException)
*/
Index: carob/include/Connection.hpp
diff -u carob/include/Connection.hpp:1.67 carob/include/Connection.hpp:1.68
--- carob/include/Connection.hpp:1.67 Mon Jun 5 20:25:36 2006
+++ carob/include/Connection.hpp Wed Jun 21 14:56:22 2006
@@ -22,6 +22,7 @@
#ifndef _CONNECTION_H_
#define _CONNECTION_H_
+#include "ResultAndWarnings.hpp"
#include "ConnectionParameters.hpp"
#include "DriverResultSet.hpp"
@@ -31,7 +32,7 @@
#include <list>
namespace {
-const int32_t ProtocolVersion = (static_cast<int32_t>(3) /* major */ << 16)
+const int32_t ProtocolVersion = (static_cast<int32_t>(4) /* major */ << 16)
+ 0 /* minor */;
}
@@ -257,12 +258,12 @@
* @return number of rows affected, -1 if an error occured
* @throws SocketIOException if an error occurs
*/
- int statementExecuteUpdate(Request& r)
+ ResultAndWarnings statementExecuteUpdate(Request& r)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
ConnectionException, UnexpectedException);
/**
- * Calls a request that returns a list of results.
+ * Calls a request that returns a list of results and the optionnal warnings.
* This list is returned as a copy (ie. not a pointer) because it contains
* only lightweight elements (pointers or ints), so there is no heavy
* ResultSet copy.
@@ -271,8 +272,7 @@
* @return a <code>list</code> of <code>ResultSetOrUpdateCount</code>
elements
* @throws SocketIOException if an error occurs
*/
- std::list<ResultSetOrUpdateCount> statementExecute(
- RequestWithResultSetParameters&
request)
+ ResultAndWarnings statementExecute(RequestWithResultSetParameters& request)
throw (SocketIOException,
BackendException, ControllerException,
ProtocolException, ConnectionException,
@@ -287,7 +287,7 @@
* DriverResultSet containing the autogenerated keys
* @throws SocketIOException if an error occurs
*/
- std::list<ResultSetOrUpdateCount> statementExecuteUpdateWithKeys(
+ ResultAndWarnings statementExecuteUpdateWithKeys(
Request &request)
throw (SocketIOException,
BackendException,ControllerException,
@@ -347,6 +347,14 @@
ProtocolException, ControllerException,
NotImplementedException, ConnectionException,
UnexpectedException);
+ /**
+ * Utility function to convert the given chain of backendException to a chain
+ * of SQLWarnings
+ *
+ * @param bde exception chain to convert
+ */
+ static SQLWarning* convertToSQLWarnings(BackendException* bde);
+
protected:
/**
@@ -523,6 +531,21 @@
ProtocolException,
UnexpectedException);
/**
+ * Deserialize SQL warnings from the stream: converts BackendDriverException
+ * to an SQLWarning chain
+ *
+ * @return the deserialized warning chain
+ * @throws IOException stream error
+ * @throws ProtocolException protocol error
+ * @throws SerializableException
+ */
+ SQLWarning* receiveSQLWarnings() throw (SocketIOException,
+ BackendException,
+ ControllerException,
+ ProtocolException,
+ UnexpectedException);
+
+ /**
* Deserialize an exception from the stream: converts explicit protocol
* typing into java types.
*
@@ -580,7 +603,7 @@
* @param request the request to check
* @return int the number of updated rows or -1 if not found
*/
- int retrieveExecuteUpdateResult(const Request &request)
+ int retrieveExecuteUpdateResult(const Request &request)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
UnexpectedException);
@@ -591,7 +614,7 @@
* @param request the request to check
* @return a <code>List</code> of ResultSetOrUpdateCount
*/
- std::list<ResultSetOrUpdateCount> retrieveExecuteResult(const Request
&request)
+ ResultAndWarnings retrieveExecuteResult(const Request &request)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
UnexpectedException);
@@ -603,7 +626,7 @@
* @return previous result of the given query,
* @throws DriverSQLException if an error occurs
*/
- std::list<ResultSetOrUpdateCount> retrieveExecuteUpdateWithKeysResult(
+ ResultAndWarnings retrieveExecuteUpdateWithKeysResult(
const Request &request) throw (SocketIOException,
BackendException, ControllerException,
ProtocolException, UnexpectedException);
Index: carob/include/DriverResultSet.hpp
diff -u carob/include/DriverResultSet.hpp:1.40
carob/include/DriverResultSet.hpp:1.41
--- carob/include/DriverResultSet.hpp:1.40 Mon Jun 5 20:25:36 2006
+++ carob/include/DriverResultSet.hpp Wed Jun 21 14:56:22 2006
@@ -64,6 +64,7 @@
class Field;
class TypeTag;
class BigDecimal;
+class SQLWarning;
/**
* Exception thrown when client tries to retrieve a value that is NULL,
@@ -436,9 +437,9 @@
throw (DriverException, UnexpectedException);
/**
* Gets the SQL warnings associated to this ResultSet
- * @return a warning chain as a BackendException
+ * @return a SQL warning chain
*/
- BackendException* getWarnings() {return warningsPtr;}
+ SQLWarning* getWarnings() {return warningsPtr;}
protected:
/**
* De-serialize only data rows, not any metadata.
@@ -501,7 +502,7 @@
int resultSetConcurrency;
/** Warning chain */
- BackendException* warningsPtr;
+ SQLWarning* warningsPtr;
/** Statement corresponding to this ResultSet, if any (not for metadata) */
Statement* owningStatementPtr;
/** The driver connection we were received from. Useful for streaming */
Index: carob/include/ResultAndWarnings.hpp
diff -u /dev/null carob/include/ResultAndWarnings.hpp:1.1
--- /dev/null Wed Jun 21 14:56:22 2006
+++ carob/include/ResultAndWarnings.hpp Wed Jun 21 14:56:22 2006
@@ -0,0 +1,140 @@
+/*
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005-2006 Continuent, Inc.
+ * Contact: [EMAIL PROTECTED]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Initial developer(s): Gilles Rayrat
+ * Contributor(s):
+ */
+
+#ifndef RESULTANDWARNINGS_H_
+#define RESULTANDWARNINGS_H_
+
+#include "DriverResultSet.hpp"
+#include "CarobException.hpp"
+
+#include <list>
+
+namespace CarobNS {
+
+class ResultAndWarnings
+{
+public:
+ /**
+ * Empty constructor
+ */
+ ResultAndWarnings() : warnings_ptr(NULL) {};
+ /**
+ * Constructs a <code>ResultAndWarning</code> that will hold an updateCount
+ * and the given SQLWarnings.<br>
+ * This constructor will typically be called by XXXexecuteUpdate() functions
+ *
+ * @param uc the update count
+ * @param warnsPtr pointer to the warnings to set, can be null
+ */
+ ResultAndWarnings(int uc, SQLWarning* warnsPtr)
+ {
+ warnings_ptr = warnsPtr;
+ update_count = uc;
+ is_update_count = true;
+ }
+
+ /**
+ * Constructs a <code>ResultAndWarning</code> that will hold a resultList
+ * and the given SQLWarnings.<br>
+ * This constructor will typically be called by XXXexecute() functions
+ *
+ * @param reslistPtr pointer to a list of results
+ * @param warnsPtr pointer to the warnings to set, can be null
+ */
+ ResultAndWarnings(std::list<ResultSetOrUpdateCount> reslist, SQLWarning*
warnsPtr)
+ {
+ warnings_ptr = warnsPtr;
+ result_list = reslist;
+ is_update_count = false;
+ }
+
+ /**
+ * Copy constructor
+ */
+ ResultAndWarnings(const ResultAndWarnings& cp) : warnings_ptr(NULL)
+ {
+ *this = cp;
+ }
+
+ /**
+ * Assignement operator. Deletes
+ */
+ ResultAndWarnings & operator =(const ResultAndWarnings& cp)
+ {
+ if (warnings_ptr != NULL)
+ delete warnings_ptr;
+ warnings_ptr = cp.getWarnings();
+ result_list = cp.getResultList();
+ update_count = cp.getUpdateCount();
+ is_update_count = cp.isUpdateCount();
+ return *this;
+ }
+ /**
+ * Tells whether this object holds an updateCount
+ *
+ * @return true if the result is an updateCount
+ */
+ bool isUpdateCount() const { return is_update_count; }
+
+ /**
+ * Tells whether this object holds a resultList
+ *
+ * @return true if the result is an resultList
+ */
+ bool isResultList() const { return !is_update_count; }
+
+ /**
+ * Gets the warning chain pointer associated to the result
+ *
+ * @return a <code>SQLWarning</code> pointer or null if no warnings
+ */
+ SQLWarning* getWarnings() const { return warnings_ptr; }
+
+ /**
+ * Gets the updateCount. <i>Note:</i> if the held value is a resultList (ie.
+ * if [EMAIL PROTECTED] #isUpdateCount()} returns false), then the returned
value is not
+ * specified
+ *
+ * @return the updateCount value
+ */
+ int getUpdateCount() const { return update_count; }
+
+ /**
+ * Gets the ResultList. <i>Note:</i> if the held value is an udpateCount
+ * (ie. if [EMAIL PROTECTED] #isResultList()} returns false), then the
returned value is
+ * not specified
+ *
+ * @return the updateCount value
+ */
+ std::list<ResultSetOrUpdateCount> getResultList() const { return
result_list; }
+
+private:
+ /** warning chain, null means no warning */
+ SQLWarning* warnings_ptr;
+ /** true if this object holds an update count, false if it holds a result
List */
+ bool is_update_count;
+
+ int update_count;
+ std::list<ResultSetOrUpdateCount> result_list;
+};
+
+} //namespace CarobNS
+#endif /*RESULTANDWARNINGS_H_*/
Index: carob/include/Statement.hpp
diff -u carob/include/Statement.hpp:1.41 carob/include/Statement.hpp:1.42
--- carob/include/Statement.hpp:1.41 Thu Mar 23 17:10:04 2006
+++ carob/include/Statement.hpp Wed Jun 21 14:56:22 2006
@@ -54,6 +54,7 @@
class Connection;
class ResultSetMetaData;
class RequestWithResultSetParameters;
+class SQLWarning;
/**
* A <code>Statement</code> object is used for executing a static SQL
@@ -299,6 +300,11 @@
*/
void setRequest(const std::wstring& sql)
{ sql_request = sql; }
+ /**
+ * Gets the SQL warnings associated to this statement
+ * @return a SQL warning chain
+ */
+ SQLWarning* getWarnings() {return warningsPtr;}
protected:
/** Original, untouched request (only trimmed) */
std::wstring sql_request;
@@ -385,6 +391,8 @@
ResultSetMetaData* rs_metadata_ptr;
/** Update count for a write request */
int lastUpdateCount;
+ /** Warning chain */
+ SQLWarning* warningsPtr;
/** Query timeout in seconds (0 means no timeout) */
int timeout;
/** Default ResultSet fetch size */
Index: carob/src/Connection.cpp
diff -u carob/src/Connection.cpp:1.76 carob/src/Connection.cpp:1.77
--- carob/src/Connection.cpp:1.76 Mon Jun 5 20:25:36 2006
+++ carob/src/Connection.cpp Wed Jun 21 14:56:22 2006
@@ -29,6 +29,7 @@
#include "TypeTag.hpp"
#include "Request.hpp"
#include "RequestWithResultSetParameters.hpp"
+#include "CarobException.hpp"
#include <string>
@@ -665,7 +666,7 @@
return retVal;
}
-int Connection::statementExecuteUpdate(Request& request)
+ResultAndWarnings Connection::statementExecuteUpdate(Request& request)
throw (SocketIOException, BackendException, ControllerException,
ProtocolException, ConnectionException, UnexpectedException)
{
@@ -677,6 +678,7 @@
beginTransactionIfNeeded();
setConnectionParametersOnRequest(request);
+ SQLWarning* sqlwPtr = NULL;
int controllerResponse = -1;
FO_TRY_NTIMES(RECONNECT_RETRIES)
@@ -691,19 +693,29 @@
// update count
try
{
+ sqlwPtr = receiveSQLWarnings();
controllerResponse = static_cast<int>(receiveIntOrException());
}
catch (SocketIOException sioe)
{
FO_TRY_NTIMES(RECONNECT_RETRIES)
controllerResponse = retrieveExecuteUpdateResult(request);
+ if (controllerResponse != -1)
+ {
+ if (sqlwPtr != NULL)
+ delete sqlwPtr;
+ sqlwPtr = new SQLWarning(L"Failover happened while executing request "
+ + static_cast<std::wstring>(request)
+ + L". SQLWarnings, if any, were lost");
+ return ResultAndWarnings(controllerResponse, sqlwPtr);
+ }
FO_CATCH_NTIMES
}
- return controllerResponse;
+ return ResultAndWarnings(controllerResponse, sqlwPtr);
}
-std::list<ResultSetOrUpdateCount> Connection::statementExecute(
+ResultAndWarnings Connection::statementExecute(
RequestWithResultSetParameters& request) throw (SocketIOException,
BackendException, ControllerException, ProtocolException,
ConnectionException, UnexpectedException)
@@ -715,6 +727,7 @@
beginTransactionIfNeeded();
setConnectionParametersOnRequest(request);
+ SQLWarning* sqlwPtr = NULL;
std::list<ResultSetOrUpdateCount> results;
FO_TRY_NTIMES(RECONNECT_RETRIES)
@@ -729,6 +742,7 @@
try
{
+ sqlwPtr = receiveSQLWarnings();
results = fetchMultipleResultsFromStream();
}
catch (SocketIOException sioe)
@@ -747,14 +761,20 @@
}
results.clear();
}
+ if (sqlwPtr != NULL)
+ {
+ delete sqlwPtr;
+ sqlwPtr = NULL;
+ }
// Then retrieve results on controller
- results = retrieveExecuteResult(request);
+ return (retrieveExecuteResult(request));
FO_CATCH_NTIMES
}
- return results;
+
+ return ResultAndWarnings(results, sqlwPtr);
}
-std::list<ResultSetOrUpdateCount> Connection::statementExecuteUpdateWithKeys(
+ResultAndWarnings Connection::statementExecuteUpdateWithKeys(
Request &request) throw (SocketIOException, BackendException,
ControllerException, ProtocolException, ConnectionException,
UnexpectedException)
@@ -767,10 +787,12 @@
beginTransactionIfNeeded();
setConnectionParametersOnRequest(request);
+ SQLWarning* sqlwPtr = NULL;
std::list<ResultSetOrUpdateCount> result;
for (int failuresCnt=0; failuresCnt<RECONNECT_RETRIES; failuresCnt++)
{ // this for is in the case we were disconnected and the controller did not
// get the update request
+ ResultAndWarnings ret;
FO_TRY_NTIMES(RECONNECT_RETRIES)
if (isDebugEnabled())
logDebug(fctName, L"Executing write request with keys: "
@@ -781,6 +803,7 @@
FO_CATCH_NTIMES
try
{
+ sqlwPtr = receiveSQLWarnings();
// Receive first the update count or an exception
ResultSetOrUpdateCount uc;
uc.isResultSet = false;
@@ -808,17 +831,23 @@
}
result.clear();
}
+ if (sqlwPtr != NULL)
+ {
+ delete sqlwPtr;
+ sqlwPtr = NULL;
+ }
// Then retrieve result on controller
- result = retrieveExecuteUpdateWithKeysResult(request);
+ ret = retrieveExecuteUpdateWithKeysResult(request);
FO_CATCH_NTIMES
- if (result.size() > 1)
- return result;
+ if (ret.getResultList().size() > 1)
+ return ret;
// otherwise, the update was not done on the controller, we go back at
// the beginning of the function, cleaning up results
- result.clear();
+ ret.getResultList().clear();
+ delete ret.getWarnings();
}
}
- return result;
+ return ResultAndWarnings(result, sqlwPtr);
}
void Connection::writeRequestOnStream(const Request& request)
@@ -955,6 +984,33 @@
return L"";
}
+SQLWarning* Connection::receiveSQLWarnings() throw (SocketIOException,
+ BackendException, ControllerException, ProtocolException,
+ UnexpectedException)
+{
+ if (!receiveBoolOrException())
+ // no warning
+ return NULL;
+ TypeTag exceptionType(*driverSocketPtr);
+ if (exceptionType != TT_BACKEND_EXCEPTION)
+ throw ProtocolException(
+ L"Unknown exception received instead of SQLWarning");
+ // Receive the warning as a BackendDriverException
+ BackendException* e = new BackendException(*driverSocketPtr);
+ return convertToSQLWarnings(e);
+}
+
+SQLWarning* Connection::convertToSQLWarnings(BackendException* bde)
+{
+ if (bde == NULL)
+ return NULL;
+ // recursion here:
+ SQLWarning* sqlw = new SQLWarning(bde->description(), bde->getSQLState(),
+ convertToSQLWarnings((BackendException*) bde->getNext()),
+ bde->getErrorCode());
+ return sqlw;
+}
+
void Connection::receiveException() throw (SocketIOException,
BackendException,
ControllerException,
@@ -1027,16 +1083,18 @@
return static_cast<int>(receiveIntOrException());
}
-std::list<ResultSetOrUpdateCount> Connection::retrieveExecuteResult(
+ResultAndWarnings Connection::retrieveExecuteResult(
const Request &request) throw (SocketIOException, BackendException,
ControllerException, ProtocolException, UnexpectedException)
{
sendCommand(*driverSocketPtr, RetrieveExecuteResult);
*driverSocketPtr << request.getId();
- return fetchMultipleResultsFromStream();
+ SQLWarning* sqlwPtr = receiveSQLWarnings();
+ std::list<ResultSetOrUpdateCount> result = fetchMultipleResultsFromStream();
+ return ResultAndWarnings(result, sqlwPtr);
}
-std::list<ResultSetOrUpdateCount>
Connection::retrieveExecuteUpdateWithKeysResult(
+ResultAndWarnings Connection::retrieveExecuteUpdateWithKeysResult(
const Request &request) throw (SocketIOException,
BackendException, ControllerException,
ProtocolException, UnexpectedException)
@@ -1044,6 +1102,7 @@
sendCommand(*driverSocketPtr, RetrieveExecuteUpdateWithKeysResult);
*driverSocketPtr << request.getId();
+ SQLWarning* sqlwPtr = receiveSQLWarnings();
std::list<ResultSetOrUpdateCount> result;
// Receive first the update count or an exception
ResultSetOrUpdateCount uc;
@@ -1059,7 +1118,7 @@
result.push_back(rs);
}
//else return an empty list
- return result;
+ return ResultAndWarnings(result, sqlwPtr);
}
std::list<ResultSetOrUpdateCount> Connection::fetchMultipleResultsFromStream()
@@ -1202,6 +1261,9 @@
if (persistent_connection)
*driverSocketPtr<<persistent_connection_id;
*driverSocketPtr<<retrieve_sql_warnings;
+ // read ack
+ bool ack = false;
+ *driverSocketPtr>>ack;
if (isInfoEnabled())
logInfo(fctName, L"Transparent reconnection succeeded");
}
Index: carob/src/DriverResultSet.cpp
diff -u carob/src/DriverResultSet.cpp:1.54 carob/src/DriverResultSet.cpp:1.55
--- carob/src/DriverResultSet.cpp:1.54 Mon Jun 5 20:25:36 2006
+++ carob/src/DriverResultSet.cpp Wed Jun 21 14:56:22 2006
@@ -147,7 +147,12 @@
bool hasWarnings = false;
socket>>hasWarnings;
if (hasWarnings)
- warningsPtr = new BackendException(socket);
+ {
+ if (warningsPtr != NULL)
+ delete warningsPtr;
+ BackendException* e = new BackendException(socket);
+ warningsPtr = Connection::convertToSQLWarnings(e);
+ }
// Get the ResultSet metadata, deserialize columns information
socket>>nbOfColumns;
for (int i=0; i<nbOfColumns; i++)
Index: carob/src/Statement.cpp
diff -u carob/src/Statement.cpp:1.28 carob/src/Statement.cpp:1.29
--- carob/src/Statement.cpp:1.28 Fri Feb 17 10:32:41 2006
+++ carob/src/Statement.cpp Wed Jun 21 14:56:22 2006
@@ -43,6 +43,7 @@
metadata_holder_ptr(NULL),
rs_metadata_ptr(NULL),
lastUpdateCount(-1),
+warningsPtr(NULL),
timeout(0),
fetchSize(0),
cursorName(L""),
@@ -71,6 +72,7 @@
resultList.clear();
lastResultPtr = NULL;
lastUpdateCount = -1;
+ delete (warningsPtr); warningsPtr = NULL;
delete rs_metadata_ptr; rs_metadata_ptr = NULL;
delete metadata_holder_ptr; metadata_holder_ptr = NULL;
}
@@ -112,7 +114,9 @@
if (!parameters.empty())
request.setParameters(parameters);
setReadRequestParameters(request);
- resultList = connectionPtr->statementExecute(request);
+ ResultAndWarnings rw = connectionPtr->statementExecute(request);
+ warningsPtr = rw.getWarnings();
+ resultList = rw.getResultList();
resultListIterator = resultList.begin();
return getMoreResults();
}
@@ -165,7 +169,9 @@
request.setParameters(parameters);
ResultSetOrUpdateCount uniqueUC;
uniqueUC.isResultSet = false;
- uniqueUC.updateCount = connectionPtr->statementExecuteUpdate(request);
+ ResultAndWarnings rw = connectionPtr->statementExecuteUpdate(request);
+ warningsPtr = rw.getWarnings();
+ uniqueUC.updateCount = rw.getUpdateCount();
resultList.push_back(uniqueUC);
resultList.push_back(endOfResultList);
resultListIterator = resultList.begin();
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits