Date: Thursday, November 10, 2005 @ 12:03:34
Author: gilles
Path: /cvsroot/carob/carob
Added: include/Statement.hpp (1.1) src/Statement.cpp (1.1)
test/TestStatement.cpp (1.1) test/TestStatement.hpp (1.1)
Modified: Makefile (1.9 -> 1.10) include/Connection.hpp (1.16 -> 1.17)
include/DriverResultSet.hpp (1.5 -> 1.6) src/Connection.cpp
(1.18 -> 1.19) src/DriverResultSet.cpp (1.5 -> 1.6)
test/CarobTestLauncher.cpp (1.2 -> 1.3)
Added Statement class and tests
-----------------------------+
Makefile | 1
include/Connection.hpp | 32 +++++
include/DriverResultSet.hpp | 47 ++++++++
include/Statement.hpp | 189 ++++++++++++++++++++++++++++++++++
src/Connection.cpp | 33 ++++++
src/DriverResultSet.cpp | 19 +++
src/Statement.cpp | 141 ++++++++++++++++++++++++++
test/CarobTestLauncher.cpp | 2
test/TestStatement.cpp | 227 ++++++++++++++++++++++++++++++++++++++++++
test/TestStatement.hpp | 74 +++++++++++++
10 files changed, 761 insertions(+), 4 deletions(-)
Index: carob/Makefile
diff -u carob/Makefile:1.9 carob/Makefile:1.10
--- carob/Makefile:1.9 Wed Nov 9 14:36:54 2005
+++ carob/Makefile Thu Nov 10 12:03:33 2005
@@ -67,6 +67,7 @@
${TESTDIR}/TestConnect.o\
${TESTDIR}/TestExecWriteRequest.o\
${TESTDIR}/TestExecReadRequest.o\
+ ${TESTDIR}/TestStatement.o\
${TESTDIR}/CarobTestLauncher.o
TEST_CFLAGS = -g3 -Wall -I${INCDIR}
TEST_LDFLAGS = -Wl,-rpath,. -L. -l${LIB_CAROB} -ldl -l${LIB_CPPUNIT}
Index: carob/include/Connection.hpp
diff -u carob/include/Connection.hpp:1.16 carob/include/Connection.hpp:1.17
--- carob/include/Connection.hpp:1.16 Fri Nov 4 10:40:21 2005
+++ carob/include/Connection.hpp Thu Nov 10 12:03:33 2005
@@ -43,7 +43,7 @@
#define Close 30
#define Reset 31
//#define FetchNextResultSetRows 32
-//#define CloseRemoteResultSet 33
+#define CloseRemoteResultSet 33
//#define RestoreConnectionState 34
#define SetAutoCommit 35
//#define ConnectionGetCatalog 36
@@ -76,11 +76,12 @@
//#define DatabaseStaticMetadata 80
//Forward declarations to reduce includes
-class DriverResultSet;
-class SelectRequest;
class AbstractRequest;
class AbstractWriteRequest;
class ConnectionParameters;
+class DriverResultSet;
+class SelectRequest;
+class Statement;
/**
* This class implements the communication protocol to the Controller.
* <p>
@@ -138,6 +139,18 @@
void rollback() throw (SocketIOException, DriverException,
UnexpectedException);
/**
+ * SQL statements without parameters are normally executed using
+ * <code>Statement</code> objects. If the same SQL statement is executed
+ * many times, it is more efficient to use a <code>PreparedStatement</code>.
+ * The <code>ResultSet</code> will be
+ * <code>TYPE_FORWARD_ONLY</cde>/<code>CONCUR_READ_ONLY</code>.
+ *
+ * @return a new <code>Statement</code> object
+ * @exception DriverSQLException passed through from the constructor
+ */
+ Statement* createStatement() throw (SocketIOException,
+ DriverException, UnexpectedException);
+ /**
* Performs a write request and return the number of rows affected.
*
* @param r the write request to execute
@@ -159,6 +172,19 @@
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
NotImplementedException, UnexpectedException);
+ /**
+ * Closes the remote ResultSet given its cursor name.
+ *
+ * @param cursorName cursor name of the ResultSet to close
+ * @throw DriverSQLException if an error occurs
+ * @throw SocketIOException if an error occurs on the socket
+ */
+ void closeRemoteResultSet(wstring cursorName) throw (SocketIOException,
+ BackendException,
+ ControllerException,
+ ProtocolException,
+ UnexpectedException);
+
protected:
/**
* Protected constructor so that no one but the connection pool
Index: carob/include/DriverResultSet.hpp
diff -u carob/include/DriverResultSet.hpp:1.5
carob/include/DriverResultSet.hpp:1.6
--- carob/include/DriverResultSet.hpp:1.5 Thu Nov 3 15:29:02 2005
+++ carob/include/DriverResultSet.hpp Thu Nov 10 12:03:33 2005
@@ -30,6 +30,37 @@
#include "SQLDataSerialization.hpp"
/**
+ * The constant indicating the type for a <code>ResultSet</code> object
+ * whose cursor may move only forward.
+ */
+#define TYPE_FORWARD_ONLY 1003
+
+/**
+ * The constant indicating the type for a <code>ResultSet</code> object
+ * that is scrollable but generally not sensitive to changes made by others.
+ */
+#define TYPE_SCROLL_INSENSITIVE 1004
+
+/**
+ * The constant indicating the type for a <code>ResultSet</code> object
+ * that is scrollable and generally sensitive to changes made by others.
+ */
+#define TYPE_SCROLL_SENSITIVE 1005
+
+/**
+ * The constant indicating the concurrency mode for a
+ * <code>ResultSet</code> object that may NOT be updated.
+ */
+#define CONCUR_READ_ONLY 1007
+
+/**
+ * The constant indicating the concurrency mode for a
+ * <code>ResultSet</code> object that may be updated.
+ */
+#define CONCUR_UPDATABLE 1008
+
+class Statement;
+/**
* A <code>ResultSet</code> provides access to a table of data generated by
* executing a Statement. The table rows are retrieved in sequence. Within a
row
* its column values can be accessed in any order.
@@ -67,6 +98,7 @@
*/
class DriverResultSet
{
+friend class Statement;
public:
/**
* Creates a DriverResultSet by deserializing infos from the given connection
@@ -113,6 +145,13 @@
*/
int32_t* getInt(int32_t columnIndex) throw (SQLException,
UnexpectedException);
+ /**
+ * Closes the remote ResultSet if the ResultSet was streamed else just closes
+ * the ResultSet locally.
+ *
+ * @exception DriverSQLException if a database access error occurs
+ */
+ void close() throw (SQLException, UnexpectedException);
protected:
/**
@@ -123,6 +162,12 @@
*/
void receiveRows() throw (SocketIOException, ProtocolException,
UnexpectedException);
+ /**
+ * Sets the statement.
+ *
+ * @param stmtPtr pointer to the statement to set
+ */
+ void setStatement(Statement* stmtPtr);
private:
/** Cursor to current row */
int32_t currentRow;
@@ -158,7 +203,7 @@
/** Warning chain */
//protected SQLWarning warnings = null;
/** Statement corresponding to this ResultSet, if any (not for metadata) */
- //protected transient Statement owningStatement;
+ Statement* owningStatementPtr;
/** The driver connection we were received from. Useful for streaming */
Connection* connectionPtr;
Index: carob/include/Statement.hpp
diff -u /dev/null carob/include/Statement.hpp:1.1
--- /dev/null Thu Nov 10 12:03:34 2005
+++ carob/include/Statement.hpp Thu Nov 10 12:03:33 2005
@@ -0,0 +1,189 @@
+/**
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005 Emic Networks
+ * 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 STATEMENT_HPP_
+#define STATEMENT_HPP_
+
+#include <string>
+#include <vector>
+
+#include "DriverResultSet.hpp"
+
+/**
+ * A <code>Statement</code> object is used for executing a static SQL
+ * statement and obtaining the results produced by it.
+ * <p>
+ * Only one <code>ResultSet</code> per <code>Statement</code> can be open at
+ * any point in time. Therefore, if the reading of one <code>ResultSet</code>
+ * is interleaved with the reading of another, each must have been generated by
+ * different <code>Statements</code>. All <code>Statements</code> execute
+ * methods implicitly close a statement's current <code>ResultSet</code> if an
+ * open one exists.
+ */
+class Statement
+{
+public:
+ Statement();
+ /** Constructs a Statement with the given connection */
+ Statement(Connection* c);
+ virtual ~Statement();
+ /**
+ * Executes a SQL statement that returns a single ResultSet
+ * @param sqlQuery typically a static SQL <code>SELECT</code> statement
+ * @param mustBroadcast whether the SelectRequest must be broadcasted on the
+ * cluster (eg. for queries like SELECT FOR UPDATE)
+ * @return a ResulSet pointer that contains the data produced by the query
+ */
+ DriverResultSet* executeQuery(std::wstring query, bool mustBroadcast)
+ throw (SocketIOException, BackendException, ControllerException,
+ ProtocolException, NotImplementedException, UnexpectedException);
+ /**
+ * Execute a SQL INSERT, UPDATE or DELETE statement. In addition SQL
+ * statements that return nothing such as SQL DDL statements can be executed
+ *
+ * @param sql a SQL statement
+ * @return either a row count, or 0 for SQL commands
+ */
+ int executeUpdate(std::wstring sql) throw
(SocketIOException,
+ BackendException, ControllerException, ProtocolException,
+ UnexpectedException);
+
+ // GETTERS AND SETTERS
+ /**
+ * Returns the current result as an update count, if the result is a
+ * <code>ResultSet</code> or there are no more results, -1 is returned. It
+ * should only be called once per result.
+ *
+ * @return the current result as an update count.
+ */
+ int getUpdateCount() { return updateCount; }
+ /**
+ * The queryTimeout limit is the number of seconds the driver will wait for a
+ * Statement to execute.
+ *
+ * @return the current query timeout limit in seconds; 0 = unlimited
+ */
+ int getQueryTimeout() { return timeout; }
+ /**
+ * Sets the number of seconds the driver will wait for a
+ * <code>Statement</code> object to execute.
+ *
+ * @param seconds the new query timeout limit in seconds; 0 means no timeout
+ * @throw DriverException if the condition
+ * seconds >= 0 is not satisfied
+ */
+ void setQueryTimeout(int seconds) throw (DriverException,
UnexpectedException);
+ /** Gets the fetch size */
+ int getFetchSize() { return fetchSize; }
+ /**
+ * Set the default fetch size for the produced ResultSet.
+ *
+ * @param rows number of rows that should be fetched from the database
+ * @throw DriverException if the condition 0 <= size <= getMaxRows()
+ * is not satisfied
+ */
+ void setFetchSize(int rows) throw (DriverException, UnexpectedException);
+ /**
+ * Retrieve the type of the generated <code>ResultSet</code>.
+ *
+ * @return one of <code>TYPE_FORWARD_ONLY</code> or
+ * <code>TYPE_SCROLL_INSENSITIVE</code>
+ */
+ /**
+ * Defines the SQL cursor name that will be used by subsequent execute
+ * methods. This name can then be used in SQL positioned update/delete
+ * statements to identify the current row in the ResultSet generated by this
+ * statement. If a database doesn't support positioned update/delete, this
+ * method is a no-op.
+ *
+ * @param name the new cursor name
+ */
+ void setCursorName(wstring name) { cursorName = name; }
+ int getResultSetType() { return resultSetType; }
+ /**
+ * @param value an <code>int</code> value
+ */
+ void setResultSetType(int value) throw (DriverException,
UnexpectedException);
+ /**
+ * Retrieves the concurrency mode for the <code>ResultSet</code>.
+ * @return <code>CONCUR_READ_ONLY</code> or <code>CONCUR_UPDATABLE</code>
+ */
+ int getResultSetConcurrency() { return resultSetConcurrency; }
+ /**
+ * Sets the concurrency mode for the <code>ResultSet</code>
+ * @param value an <code>int</code> value <code>CONCUR_READ_ONLY</code> or
+ * <code>CONCUR_UPDATABLE</code>
+ * @throw DriverException if the input value is not valid
+ */
+ void setResultSetConcurrency(int value) throw (DriverException,
+ UnexpectedException);
+ /**
+ * The maxRows limit is set to limit the number of rows that any
+ * <code>ResultSet</code> can contain. If the limit is exceeded, the excess
+ * rows are silently dropped.
+ *
+ * @return the current maximum row limit; zero means unlimited
+ */
+ int getMaxRows() { return maxRows; }
+ /**
+ * Sets the maximum number of rows that any <code>ResultSet</code> can
+ * contain.
+ *
+ * @param max the new max rows limit; 0 means unlimited
+ * @exception DriverException if the condition max >= 0 is not satisfied
+ */
+ void setMaxRows(int max) throw (DriverException, UnexpectedException);
+ /**
+ * If escape scanning is on (the default), the driver will do escape
+ * substitution before sending the SQL to the database.
+ *
+ * @param enable true to enable; false to disable
+ */
+ void setEscapeProcessing(bool enable) { escapeProcessing = enable; }
+
+private:
+ /** Connection that created us */
+ Connection* connectionPtr;
+ /** Current result for a read request */
+ DriverResultSet* resultPtr;
+ /** Update count for a write request */
+ int updateCount;
+ /** Query timeout in seconds (0 means no timeout) */
+ int timeout;
+ /** Default ResultSet fetch size */
+ int fetchSize;
+ /** Cursor name used jointly with fetch size */
+ wstring cursorName;
+ /** Type of the ResultSet defaults to TYPE_FORWARD_ONLY */
+ int resultSetType;
+ /** ResultSet Concurrency defaults to CONCUR_READ_ONLY */
+ int resultSetConcurrency;
+ /** Maximum number of rows */
+ int maxRows;
+ /** Should the driver to escape processing before sending to the DB? */
+ bool escapeProcessing;
+ /**
+ * Tests if this statement is closed.
+ * @return <code>true</code> if this statement is closed
+ */
+ bool isClosed() { return (connectionPtr == NULL); }
+};
+
+#endif /*STATEMENT_HPP_*/
Index: carob/src/Connection.cpp
diff -u carob/src/Connection.cpp:1.18 carob/src/Connection.cpp:1.19
--- carob/src/Connection.cpp:1.18 Fri Nov 4 10:40:20 2005
+++ carob/src/Connection.cpp Thu Nov 10 12:03:33 2005
@@ -25,6 +25,7 @@
#include "ConnectionParameters.hpp"
#include "DriverResultSet.hpp"
#include "SelectRequest.hpp"
+#include "Statement.hpp"
Connection::~Connection()
{
@@ -406,6 +407,13 @@
}
}
+Statement* Connection::createStatement() throw (DriverException,
+ SocketIOException, UnexpectedException)
+{
+ checkIfConnected();
+ return new Statement(this);
+}
+
void Connection::checkIfConnected() const throw (SocketIOException,
UnexpectedException)
{
@@ -518,6 +526,31 @@
return retVal;
}
+void Connection::closeRemoteResultSet(wstring cursorName)
+ throw (SocketIOException, BackendException, ControllerException,
+ ProtocolException, UnexpectedException)
+{
+ wstring fctName(L"Connection::closeRemoteResultSet");
+
+ connectionCS.Enter();
+ checkIfConnected();
+ try
+ {
+ *driverSocketPtr<<CloseRemoteResultSet;
+ *driverSocketPtr<<cursorName;
+ if (isDebugEnabled())
+ logDebug(fctName, L"Closing remote ResultSet");
+
+ receiveBoolOrException();
+ }
+ catch (...)
+ {
+ connectionCS.Leave();
+ throw;
+ }
+ connectionCS.Leave();
+}
+
bool Connection::receiveBoolOrException() throw (SocketIOException,
BackendException,
ControllerException,
Index: carob/src/DriverResultSet.cpp
diff -u carob/src/DriverResultSet.cpp:1.5 carob/src/DriverResultSet.cpp:1.6
--- carob/src/DriverResultSet.cpp:1.5 Fri Oct 28 11:06:21 2005
+++ carob/src/DriverResultSet.cpp Thu Nov 10 12:03:33 2005
@@ -23,6 +23,7 @@
#include "Common.hpp"
#include "DriverResultSet.hpp"
#include "TypeTag.hpp"
+#include "Statement.hpp"
DriverResultSet::~DriverResultSet()
{
@@ -89,6 +90,17 @@
return sRet;
}
+void DriverResultSet::setStatement(Statement* stmtPtr)
+{
+ owningStatementPtr = stmtPtr;
+ if (stmtPtr != NULL)
+ {
+ fetchSize = stmtPtr->getFetchSize();
+ resultSetConcurrency = stmtPtr->getResultSetConcurrency();
+ resultSetType = stmtPtr->getResultSetType();
+ }
+}
+
bool DriverResultSet::next() throw (SQLException, UnexpectedException)
{
checkIfClosed();
@@ -197,6 +209,13 @@
return (int32_t*)((data[currentRow])[columnIndex - 1]);
}
+void DriverResultSet::close() throw (SQLException, UnexpectedException)
+{
+ if (hasMoreData)
+ connectionPtr->closeRemoteResultSet(cursorName);
+ isClosed = true;
+}
+
void DriverResultSet::receiveRows() throw (SocketIOException,
ProtocolException,
UnexpectedException)
{
Index: carob/src/Statement.cpp
diff -u /dev/null carob/src/Statement.cpp:1.1
--- /dev/null Thu Nov 10 12:03:34 2005
+++ carob/src/Statement.cpp Thu Nov 10 12:03:33 2005
@@ -0,0 +1,141 @@
+#include "CarobException.hpp"
+#include "Common.hpp"
+#include "SelectRequest.hpp"
+#include "Statement.hpp"
+#include "UpdateRequest.hpp"
+
+using namespace std;
+
+Statement::Statement()
+{
+ Statement(NULL);
+}
+
+Statement::Statement(Connection* c) :
+connectionPtr(c),
+resultPtr(NULL),
+updateCount(-1),
+timeout(0),
+fetchSize(0),
+cursorName(L""),
+resultSetType(TYPE_FORWARD_ONLY),
+resultSetConcurrency(CONCUR_READ_ONLY),
+maxRows(0),
+escapeProcessing(true)
+{
+}
+
+Statement::~Statement()
+{
+ if (resultPtr != NULL)
+ delete resultPtr;
+}
+
+
+DriverResultSet* Statement::executeQuery(wstring query, bool mustBroadcast)
+ throw (SocketIOException, BackendException, ControllerException,
+ ProtocolException, NotImplementedException, UnexpectedException)
+{
+ wstring fctName(L"Statement::executeQuery");
+ //trims original string
+ query = trim(query);
+ if (isClosed())
+ {
+ throw DriverException(L"Unable to execute query on a closed statement");
+ }
+ updateCount = -1; // invalidate the last write result
+ if (resultPtr != NULL)
+ { // Discard the previous result
+ resultPtr->close();
+ resultPtr = NULL;
+ }
+
+ SelectRequest request(query, escapeProcessing, timeout, LINE_SEPARATOR);
+ request.setMaxRows(maxRows);
+ request.setFetchSize(fetchSize);
+ request.setCursorName(cursorName);
+ request.setMustBroadcast(mustBroadcast);
+ resultPtr = connectionPtr->execReadRequest(request);
+ resultPtr->setStatement(this);
+ return resultPtr;
+}
+
+int Statement::executeUpdate(wstring query) throw (SocketIOException,
+ BackendException, ControllerException, ProtocolException,
+ UnexpectedException)
+{
+ wstring fctName(L"Statement::executeQuery");
+ //trims original string
+ query = trim(query);
+ if (resultPtr != NULL)
+ { // Discard the previous result
+ resultPtr->close();
+ resultPtr = NULL;
+ }
+ UpdateRequest request(query, escapeProcessing, timeout, LINE_SEPARATOR);
+ int updateCount = connectionPtr->execWriteRequest(request);
+ return updateCount;
+}
+
+// GETTERS AND SETTERS
+void Statement::setQueryTimeout(int seconds) throw (DriverException,
UnexpectedException)
+{
+ if (seconds < 0)
+ {
+ throw DriverException(L"Invalid query timeout value: " +
toWString(seconds));
+ }
+ timeout = seconds;
+}
+
+void Statement::setFetchSize(int rows) throw (DriverException,
UnexpectedException)
+{
+ if (rows < 0
+ // The spec forgets the case maxRows = 0.
+ || 0 < maxRows && maxRows < rows)
+ {
+ throw DriverException(L"Invalid fetch size value: " + toWString(rows));
+ }
+ fetchSize = rows;
+}
+
+void Statement::setResultSetType(int value) throw (DriverException,
+ UnexpectedException)
+{
+ switch (value)
+ {
+ case TYPE_FORWARD_ONLY :
+ case TYPE_SCROLL_INSENSITIVE :
+ resultSetType = value;
+ break;
+ case TYPE_SCROLL_SENSITIVE :
+ throw DriverException(
+ L"TYPE_SCROLL_SENSITIVE is not a supported ResultSet type");
+ default :
+ throw DriverException(L"Invalid ResultSet type");
+ }
+}
+
+void Statement::setResultSetConcurrency(int value) throw (DriverException,
+ UnexpectedException)
+{
+ switch (value)
+ {
+ case CONCUR_READ_ONLY :
+ case CONCUR_UPDATABLE :
+ resultSetConcurrency = value;
+ break;
+ default :
+ throw DriverException(L"Invalid ResultSet concurrency mode: "
+ + toWString(value));
+ }
+}
+
+void Statement::setMaxRows(int max) throw (DriverException,
UnexpectedException)
+{
+ if (max < 0)
+ {
+ throw DriverException(L"Invalid max rows limit: " + toWString(max));
+ }
+ // this may break fetchSize <= maxRows
+ maxRows = max;
+}
Index: carob/test/CarobTestLauncher.cpp
diff -u carob/test/CarobTestLauncher.cpp:1.2
carob/test/CarobTestLauncher.cpp:1.3
--- carob/test/CarobTestLauncher.cpp:1.2 Fri Nov 4 11:27:44 2005
+++ carob/test/CarobTestLauncher.cpp Thu Nov 10 12:03:33 2005
@@ -27,6 +27,7 @@
#include "TestConnect.hpp"
#include "TestExecReadRequest.hpp"
#include "TestExecWriteRequest.hpp"
+#include "TestStatement.hpp"
int main (int argc, char **argv)
{
@@ -38,6 +39,7 @@
runner.addTest(TestExecWriteRequest::suite());
runner.addTest(TestExecReadRequest::suite());
runner.addTest(TestBeginCommitRollback::suite());
+ runner.addTest(TestStatement::suite());
runner.run();
return 0;
Index: carob/test/TestStatement.cpp
diff -u /dev/null carob/test/TestStatement.cpp:1.1
--- /dev/null Thu Nov 10 12:03:34 2005
+++ carob/test/TestStatement.cpp Thu Nov 10 12:03:33 2005
@@ -0,0 +1,227 @@
+/**
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005 Emic Networks
+ * 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):
+ */
+#include <iostream>
+
+#include "Common.hpp"
+#include "CarobException.hpp"
+#include "DriverResultSet.hpp"
+#include "TestStatement.hpp"
+#include "SelectRequest.hpp"
+#include "Statement.hpp"
+
+
+//EXECUTE QUERY
+void TestStatement::testExecuteQueryBadRequest()
+{
+ wstring fctName(L"TestStatement::testExecuteQueryBadRequest");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing dummy read");
+ }
+ statementPtr->executeQuery(L"dummy request;", false);
+ // We should receive an exception instead of coming here
+ CPPUNIT_ASSERT(false);
+ }
+ catch (BackendException sioe)
+ {
+ logError(fctName, L"BackendException "+sioe.description());
+ CPPUNIT_ASSERT(true);
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+void TestStatement::testExecuteQueryBadTable()
+{
+ wstring fctName(L"testExecuteQueryBadTable");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing bad table read");
+ }
+ statementPtr->executeQuery(L"select * from dummy;", false);
+ // We should receive an exception instead of coming here
+ CPPUNIT_ASSERT(false);
+ }
+ catch (BackendException be)
+ {
+ //logError(fctName, L"BackendException "+be.description());
+ CPPUNIT_ASSERT(true);
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+void TestStatement::testExecuteQueryGood()
+{
+ wstring fctName(L"TestStatement::testExecuteQueryGood");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing read");
+ }
+ DriverResultSet* drsPtr = statementPtr->executeQuery(
+ L"select * from address;", false);
+ logDebug(fctName, *drsPtr);
+ //Display five rows for debugging...
+// wcerr<<L"Row\tId\tName\t\tCost"<<endl;
+ wcerr<<L"Row\tId\tFirstName\t\tLastName"<<endl;
+ for (int i=0; i<50; i++)
+ {
+ drsPtr->next();
+ int32_t* iPtr = drsPtr->getInt(1);
+ wstring* wsPtr = drsPtr->getString(2);
+ wstring* ws2Ptr = drsPtr->getString(3);
+ wcerr<<i+1<<L"\t"<<*iPtr<<L"\t"<<*wsPtr<<L"\t"<<*ws2Ptr<<endl;
+ }
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+
+//EXECUTE UPDATE
+
+void TestStatement::testExecuteUpdateBadRequest()
+{
+ wstring fctName(L"TestStatement::testExecuteUpdateBadRequest");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing dummy update");
+ }
+ statementPtr->executeUpdate(L"dummy request;");
+ // We should receive an exception instead of coming here
+ CPPUNIT_ASSERT(false);
+ }
+ catch (BackendException sioe)
+ {
+ logError(fctName, L"BackendException "+sioe.description());
+ CPPUNIT_ASSERT(true);
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+void TestStatement::testExecuteUpdateBadTable()
+{
+ wstring fctName(L"testExecuteUpdateBadTable");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing bad table update");
+ }
+ statementPtr->executeUpdate(L"update dummy set name='gotit' where id=0;");
+ // We should receive an exception instead of coming here
+ CPPUNIT_ASSERT(false);
+ }
+ catch (BackendException be)
+ {
+ //logError(fctName, L"BackendException "+be.description());
+ CPPUNIT_ASSERT(true);
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+void TestStatement::testExecuteUpdateGood()
+{
+ wstring fctName(L"TestStatement::testExecuteUpdateGood");
+ Statement* statementPtr = NULL;
+ try
+ {
+ statementPtr = connectionPtr->createStatement();
+ if (isDebugEnabled())
+ {
+ logDebug(fctName, L"Executing update");
+ }
+ int32_t nbRowsAffected = statementPtr->executeUpdate(
+ L"update product set name='changed by testExecuteUpdateGood' where
id=0;");
+ CPPUNIT_ASSERT(nbRowsAffected == 1);
+ }
+ catch (...)
+ {
+ logError(fctName, L"Catched unexpected exception");
+ CPPUNIT_ASSERT(false);
+ }
+ delete statementPtr;
+}
+
+CppUnit::Test* TestStatement::suite()
+{
+ CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "TestStatement" );
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteQueryBadRequest",
+ &TestStatement::testExecuteQueryBadRequest));
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteQueryBadTable",
+ &TestStatement::testExecuteQueryBadTable));
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteQueryGood",
+ &TestStatement::testExecuteQueryGood));
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteUpdateBadRequest",
+ &TestStatement::testExecuteUpdateBadRequest));
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteUpdateBadTable",
+ &TestStatement::testExecuteUpdateBadTable));
+ suiteOfTests->addTest(new CppUnit::TestCaller<TestStatement>(
+ "testExecuteUpdateGood",
+ &TestStatement::testExecuteUpdateGood));
+
+ return suiteOfTests;
+}
Index: carob/test/TestStatement.hpp
diff -u /dev/null carob/test/TestStatement.hpp:1.1
--- /dev/null Thu Nov 10 12:03:34 2005
+++ carob/test/TestStatement.hpp Thu Nov 10 12:03:33 2005
@@ -0,0 +1,74 @@
+/**
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005 Emic Networks
+ * 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 TESTSTATEMENT_H_
+#define TESTSTATEMENT_H_
+
+#include "TestOnValidConnection.hpp"
+
+/**
+ * Test class for Statement class.
+ * This is basically a copy of exec read and exec write commands testing
+ * A controller *MUST* run locally for test success !!!
+ */
+class TestStatement : public TestOnValidConnection
+{
+public:
+ /** Suite of tests to be run */
+ static CppUnit::Test* suite();
+
+ //EXECUTE QUERY
+ /**
+ * Tries to send a dummy read request via a Statement to the controller and
+ * checks that the error is consistent.
+ */
+ void testExecuteQueryBadRequest();
+ /**
+ * Tries to do a good read request on a dummy table via a Statement and
+ * checks that the error is consistent.
+ */
+ void testExecuteQueryBadTable();
+ /**
+ * Sends a valid select request to the controller via a Statement and checks
+ * that there is no error. Also displays a part of the result for manual
+ * checking.
+ */
+ void testExecuteQueryGood();
+
+ //EXECUTE UPDATE
+ /**
+ * Tries to send a dummy write request to the controller via a Statement and
+ * checks that the error is consistent.
+ */
+ void testExecuteUpdateBadRequest();
+ /**
+ * Tries to do a good write request on a dummy table via a Statement and
+ * checks that the error is consistent.
+ */
+ void testExecuteUpdateBadTable();
+ /**
+ * Sends a valid update request to the controller via a Statement and checks
+ * that there is no error.
+ */
+ void testExecuteUpdateGood();
+};
+
+#endif /*TESTSTATEMENT_H_*/
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits