diff --git a/catalogue/CMakeLists.txt b/catalogue/CMakeLists.txt index c8b7d05b77f7af908fe3fd52ab1df203ddd30ff7..852de97e58cff04f068129f02638f726ed76e358 100644 --- a/catalogue/CMakeLists.txt +++ b/catalogue/CMakeLists.txt @@ -39,12 +39,11 @@ add_library (ctacatalogue SHARED install (TARGETS ctacatalogue DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) target_link_libraries (ctacatalogue + ctacommon ${ORACLE-INSTANTCLIENT_LIBRARIES} ${SQLITE_LIBRARIES}) set (CATALOGUE_UNIT_TESTS_LIB_SRC_FILES - OcciConnTest.cpp - OcciEnvTest.cpp SqliteCatalogueTest.cpp SqliteStmtTest.cpp) @@ -55,3 +54,16 @@ target_link_libraries (ctacatalogueunittests ctacatalogue) install(TARGETS ctacatalogueunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) + +set (CATALOGUE_ORA_UNIT_TESTS_LIB_SRC_FILES + OcciConnTest.cpp + OcciEnvTest.cpp + OcciStmtTest.cpp) + +add_library (ctacatalogueoraunittests SHARED + ${CATALOGUE_ORA_UNIT_TESTS_LIB_SRC_FILES}) + +target_link_libraries (ctacatalogueoraunittests + ctacatalogue) + +install(TARGETS ctacatalogueoraunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) diff --git a/catalogue/Catalogue.cpp b/catalogue/Catalogue.cpp index 6f88379318c7faa1ac6a73428a8c3aef7eb791f5..a0866c30ba3a4f2894d03a13d37c25d1b4c554b3 100644 --- a/catalogue/Catalogue.cpp +++ b/catalogue/Catalogue.cpp @@ -18,8 +18,14 @@ #include "catalogue/Catalogue.hpp" +namespace cta { +namespace catalogue { + //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::catalogue::Catalogue::~Catalogue() { +Catalogue::~Catalogue() { } + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/ColumnNameToIdx.cpp b/catalogue/ColumnNameToIdx.cpp index 91a16f9a9f38b49ef317f186976ab177655417e5..8f8522d045353818f52acca172c9b46dfab9f65c 100644 --- a/catalogue/ColumnNameToIdx.cpp +++ b/catalogue/ColumnNameToIdx.cpp @@ -19,15 +19,17 @@ #include "catalogue/ColumnNameToIdx.hpp" #include "common/exception/Exception.hpp" +namespace cta { +namespace catalogue { + //------------------------------------------------------------------------------ // addNameToIdx //------------------------------------------------------------------------------ -void cta::catalogue::ColumnNameToIdx::add(const std::string &name, - const int idx) { +void ColumnNameToIdx::add(const std::string &name, const int idx) { if(m_nameToIdx.end() != m_nameToIdx.find(name)) { exception::Exception ex; ex.getMessage() << __FUNCTION__ << " failed: Column name " << name << - " is a duplicate"; + " is a duplicate"; throw ex; } m_nameToIdx[name] = idx; @@ -36,7 +38,7 @@ void cta::catalogue::ColumnNameToIdx::add(const std::string &name, //------------------------------------------------------------------------------ // getIdx //------------------------------------------------------------------------------ -int cta::catalogue::ColumnNameToIdx::getIdx(const std::string &name) const { +int ColumnNameToIdx::getIdx(const std::string &name) const { auto it = m_nameToIdx.find(name); if(m_nameToIdx.end() == it) { exception::Exception ex; @@ -49,13 +51,16 @@ int cta::catalogue::ColumnNameToIdx::getIdx(const std::string &name) const { //------------------------------------------------------------------------------ // operator[] //------------------------------------------------------------------------------ -int cta::catalogue::ColumnNameToIdx::operator[](const std::string &name) const { +int ColumnNameToIdx::operator[](const std::string &name) const { return getIdx(name); } //------------------------------------------------------------------------------ // empty //------------------------------------------------------------------------------ -bool cta::catalogue::ColumnNameToIdx::empty() const { +bool ColumnNameToIdx::empty() const { return m_nameToIdx.empty(); } + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/OcciConn.cpp b/catalogue/OcciConn.cpp index 06ea4da15cd64785d4598389e53f211676d7d8a9..049c803edc59254b60fe54297b36457305be4ffc 100644 --- a/catalogue/OcciConn.cpp +++ b/catalogue/OcciConn.cpp @@ -16,10 +16,15 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// Version 12.1 of oracle instant client uses the pre _GLIBCXX_USE_CXX11_ABI +#define _GLIBCXX_USE_CXX11_ABI 0 + #include "catalogue/OcciConn.hpp" #include "catalogue/OcciEnv.hpp" #include "catalogue/OcciStmt.hpp" -#include "common/exception/Exception.hpp" + +#include <stdexcept> +#include <string> //------------------------------------------------------------------------------ // constructor @@ -29,10 +34,8 @@ cta::catalogue::OcciConn::OcciConn(OcciEnv &env, m_env(env), m_conn(conn) { if(NULL == conn) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << "failed" - ": The OCCI connection is a NULL pointer"; - throw ex; + throw std::runtime_error(std::string(__FUNCTION__) + " failed" + ": The OCCI connection is a NULL pointer"); } } @@ -76,15 +79,18 @@ oracle::occi::Connection *cta::catalogue::OcciConn::operator->() const { //------------------------------------------------------------------------------ // createStmt //------------------------------------------------------------------------------ -cta::catalogue::OcciStmt *cta::catalogue::OcciConn::createStmt( - const std::string &sql) { - oracle::occi::Statement *const stmt = m_conn->createStatement(sql.c_str()); - if(NULL == stmt) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed" - ": oracle::occi::createStatement() return a NULL pointer"; - throw ex; - } +cta::catalogue::OcciStmt *cta::catalogue::OcciConn::createStmt(const char *sql) { + try { + if(NULL == sql) throw std::runtime_error("sql is NULL"); + + oracle::occi::Statement *const stmt = m_conn->createStatement(sql); + if (NULL == stmt) { + throw std::runtime_error(std::string(__FUNCTION__) + " failed" + ": oracle::occi::createStatement() returned a NULL pointer"); + } - return new OcciStmt(sql, *this, stmt); + return new OcciStmt(sql, *this, stmt); + } catch(std::exception &ne) { + throw std::runtime_error(std::string(__FUNCTION__) + "failed: " + ne.what()); + } } diff --git a/catalogue/OcciConn.hpp b/catalogue/OcciConn.hpp index 66e490cf69791cb04ffc32112118abd92eeae78b..c79892fbd805a2e517f8a4ea73b7a5c42a6e5b64 100644 --- a/catalogue/OcciConn.hpp +++ b/catalogue/OcciConn.hpp @@ -20,7 +20,6 @@ #include <occi.h> #include <mutex> -#include <string> namespace cta { namespace catalogue { @@ -39,6 +38,10 @@ class OcciStmt; /** * A convenience wrapper around a connection to an OCCI database. + * + * Please note that this wrapper does not expose any data types that are + * different with respect to _GLIBCXX_USE_CXX11_ABI. For example this wrapper + * does not expose the std::string data type. */ class OcciConn { public: @@ -83,10 +86,12 @@ public: /** * Creates a prepared statement. * + * This method will throw an exception if th esql parameter is a NULL pointer. + * * @sql The SQL statement. * @return The prepared statement. */ - OcciStmt *createStmt(const std::string &sql); + OcciStmt *createStmt(const char *const sql); private: diff --git a/catalogue/OcciConnTest.cpp b/catalogue/OcciConnTest.cpp index b0e21739e71022513074e6e29c81cd8b39882a22..3cec24e73c099e2bef072877efe5816c44f16d0a 100644 --- a/catalogue/OcciConnTest.cpp +++ b/catalogue/OcciConnTest.cpp @@ -16,9 +16,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "catalogue/DbLogin.hpp" #include "catalogue/OcciEnv.hpp" #include "catalogue/OcciConn.hpp" -#include "common/exception/Exception.hpp" +#include "catalogue/OcciStmt.hpp" +#include "tests/OraUnitTestsCmdLineArgs.hpp" #include <gtest/gtest.h> #include <memory> @@ -43,7 +45,47 @@ TEST_F(cta_catalogue_OcciConnTest, constructor_null_connection) { oracle::occi::Connection *const underlyingOcciConn = NULL; std::unique_ptr<OcciConn> conn; ASSERT_THROW(conn.reset(new OcciConn(env, underlyingOcciConn)), - exception::Exception); + std::exception); +} + +TEST_F(cta_catalogue_OcciConnTest, constructor_real_connection) { + using namespace cta; + using namespace cta::catalogue; + + const DbLogin dbLogin = DbLogin::readFromFile(g_cmdLineArgs.oraDbConnFile); + OcciEnv env; + std::unique_ptr<OcciConn> conn(env.createConn( + dbLogin.username.c_str(), + dbLogin.password.c_str(), + dbLogin.database.c_str())); +} + +TEST_F(cta_catalogue_OcciConnTest, createStmt_null_sql) { + using namespace cta; + using namespace cta::catalogue; + + const DbLogin dbLogin = DbLogin::readFromFile(g_cmdLineArgs.oraDbConnFile); + OcciEnv env; + std::unique_ptr<OcciConn> conn(env.createConn( + dbLogin.username.c_str(), + dbLogin.password.c_str(), + dbLogin.database.c_str())); + const char *const sql = NULL; + ASSERT_THROW(conn->createStmt(sql), std::exception); +} + +TEST_F(cta_catalogue_OcciConnTest, createStmt) { + using namespace cta; + using namespace cta::catalogue; + + const DbLogin dbLogin = DbLogin::readFromFile(g_cmdLineArgs.oraDbConnFile); + OcciEnv env; + std::unique_ptr<OcciConn> conn(env.createConn( + dbLogin.username.c_str(), + dbLogin.password.c_str(), + dbLogin.database.c_str())); + const char *const sql = "SELECT * FROM DUAL"; + std::unique_ptr<OcciStmt> stmt(conn->createStmt(sql)); } } // namespace unitTests diff --git a/catalogue/OcciEnv.cpp b/catalogue/OcciEnv.cpp index ddf65ec4972515d576a3977e07c528a962ac3bcf..d9bbf8c6bf771cc4a8f1983cfbf599f60c62817d 100644 --- a/catalogue/OcciEnv.cpp +++ b/catalogue/OcciEnv.cpp @@ -16,10 +16,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// Version 12.1 of oracle instant client uses the pre _GLIBCXX_USE_CXX11_ABI +#define _GLIBCXX_USE_CXX11_ABI 0 + #include "catalogue/DbLogin.hpp" #include "catalogue/OcciConn.hpp" #include "catalogue/OcciEnv.hpp" -#include "common/exception/Exception.hpp" + +#include <stdexcept> //------------------------------------------------------------------------------ // constructor @@ -28,10 +32,8 @@ cta::catalogue::OcciEnv::OcciEnv() { using namespace oracle::occi; m_env = Environment::createEnvironment(Environment::THREADED_MUTEXED); if(NULL == m_env) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed" - ": oracle::occi::createEnvironment() returned a NULL pointer"; - throw ex; + throw std::runtime_error(std::string(__FUNCTION__) + "failed" + ": oracle::occi::createEnvironment() returned a NULL pointer"); } } @@ -62,16 +64,21 @@ oracle::occi::Environment *cta::catalogue::OcciEnv::operator->() const { // creatConn //------------------------------------------------------------------------------ cta::catalogue::OcciConn *cta::catalogue::OcciEnv::createConn( - const DbLogin &dbLogin) { - oracle::occi::Connection *const conn = m_env->createConnection( - dbLogin.username, - dbLogin.password, - dbLogin.database); - if(NULL == conn) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed" - ": oracle::occi::createConnection() returned a NULL pointer"; - throw ex; + const char *const username, + const char *const password, + const char *const database) { + try { + if(NULL == username) throw std::runtime_error("username is NULL"); + if(NULL == password) throw std::runtime_error("password is NULL"); + if(NULL == database) throw std::runtime_error("database is NULL"); + + oracle::occi::Connection *const conn = m_env->createConnection(username, password, database); + if (NULL == conn) { + throw std::runtime_error("oracle::occi::createConnection() returned a NULL pointer"); + } + + return new OcciConn(*this, conn); + } catch(std::exception &ne) { + throw std::runtime_error(std::string(__FUNCTION__) + " failed:" + ne.what()); } - return new OcciConn(*this, conn); } diff --git a/catalogue/OcciEnv.hpp b/catalogue/OcciEnv.hpp index bcdbb0f914a5c91ea304e160d1b66593bbd08f45..8bcdea71753be1dd0ae7d4ca665595ad6cd91428 100644 --- a/catalogue/OcciEnv.hpp +++ b/catalogue/OcciEnv.hpp @@ -23,11 +23,14 @@ namespace cta { namespace catalogue { -class DbLogin; class OcciConn; /** * A convenience wrapper around an OCCI environment. + * + * Please note that this wrapper does not expose any data types that are + * different with respect to _GLIBCXX_USE_CXX11_ABI. For example this wrapper + * does not expose the std::string data type. */ class OcciEnv { public: @@ -63,10 +66,18 @@ public: /** * Creates an OCCI connection. * - * @param dbLogin The details of the database connection. + * This method will throw an exception if either the username, password ori + * database parameters are NULL pointers. + * + * @param username The name of the database user. + * @param password The database password. + * @param database The name of the database. * @return The newly created OCCI connection. */ - OcciConn *createConn(const DbLogin &dbLogin); + OcciConn *createConn( + const char *const username, + const char *const password, + const char *const database); private: diff --git a/catalogue/OcciEnvTest.cpp b/catalogue/OcciEnvTest.cpp index 171f2debff0382f419338181e25ec928cc97cd66..2b3655886b240c0b914740800460fce1df8316c1 100644 --- a/catalogue/OcciEnvTest.cpp +++ b/catalogue/OcciEnvTest.cpp @@ -16,10 +16,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "catalogue/DbLogin.hpp" +#include "catalogue/OcciConn.hpp" #include "catalogue/OcciEnv.hpp" #include <gtest/gtest.h> -#include <memory> namespace unitTests { @@ -35,8 +36,40 @@ protected: TEST_F(cta_catalogue_OcciEnvTest, constructor) { using namespace cta::catalogue; + OcciEnv env; +} + +TEST_F(cta_catalogue_OcciEnvTest, createConn_null_username) { + using namespace cta::catalogue; + OcciEnv env; + const char *const username = NULL; + const char *const password = "Not NULL"; + const char *const database = "Not NULL"; + + ASSERT_THROW(env.createConn(username, password, database), std::exception); +} + +TEST_F(cta_catalogue_OcciEnvTest, createConn_null_password) { + using namespace cta::catalogue; OcciEnv env; + + const char *const username = "Not NULL"; + const char *const password = NULL; + const char *const database = "Not NULL"; + + ASSERT_THROW(env.createConn(username, password, database), std::exception); +} + +TEST_F(cta_catalogue_OcciEnvTest, createConn_null_database) { + using namespace cta::catalogue; + OcciEnv env; + + const char *const username = "Not NULL"; + const char *const password = "Not NULL"; + const char *const database = NULL; + + ASSERT_THROW(env.createConn(username, password, database), std::exception); } } // namespace unitTests diff --git a/catalogue/OcciRset.cpp b/catalogue/OcciRset.cpp index 416cb38414685b2baba8b8d48b4198de53388204..db6e9f9b5b328fa0368aff45b508ed98b92fcf8a 100644 --- a/catalogue/OcciRset.cpp +++ b/catalogue/OcciRset.cpp @@ -16,9 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// Version 12.1 of oracle instant client uses the pre _GLIBCXX_USE_CXX11_ABI +#define _GLIBCXX_USE_CXX11_ABI 0 + #include "catalogue/OcciRset.hpp" #include "catalogue/OcciStmt.hpp" -#include "common/exception/Exception.hpp" + +#include <stdexcept> //------------------------------------------------------------------------------ // constructor @@ -28,10 +32,7 @@ cta::catalogue::OcciRset::OcciRset(OcciStmt &stmt, m_stmt(stmt), m_rset(rset) { if(NULL == rset) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed" - ": The result set is a NULL pointer"; - throw ex; + throw std::runtime_error(std::string(__FUNCTION__) + " failed: rset is NULL"); } } @@ -40,7 +41,7 @@ cta::catalogue::OcciRset::OcciRset(OcciStmt &stmt, //------------------------------------------------------------------------------ cta::catalogue::OcciRset::~OcciRset() throw() { try { - close(); // Idempotenet close() + close(); // Idempotent close() } catch(...) { // Destructor does not throw } diff --git a/catalogue/OcciRsetTest.cpp b/catalogue/OcciRsetTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdebcbddb1da76fbb681160c9c33049149332fdd --- /dev/null +++ b/catalogue/OcciRsetTest.cpp @@ -0,0 +1,56 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "catalogue/DbLogin.hpp" +#include "catalogue/OcciEnv.hpp" +#include "catalogue/OcciConn.hpp" +#include "catalogue/OcciRset.hpp" +#include "catalogue/OcciStmt.hpp" +#include "tests/OraUnitTestsCmdLineArgs.hpp" + +#include <gtest/gtest.h> +#include <memory> + +namespace unitTests { + +class cta_catalogue_OcciRsetTest : public ::testing::Test { +protected: + + virtual void SetUp() { + } + + virtual void TearDown() { + } +}; + +TEST_F(cta_catalogue_OcciRsetTest, execute) { + using namespace cta; + using namespace cta::catalogue; + + const DbLogin dbLogin = DbLogin::readFromFile(g_cmdLineArgs.oraDbConnFile); + OcciEnv env; + std::unique_ptr<OcciConn> conn(env.createConn( + dbLogin.username.c_str(), + dbLogin.password.c_str(), + dbLogin.database.c_str())); + const char *const sql = "SELECT * FROM DUAL"; + std::unique_ptr<OcciStmt> stmt(conn->createStmt(sql)); + std::unique_ptr<OcciRset> rset(stmt->execute()); +} + +} // namespace unitTests diff --git a/catalogue/OcciStmt.cpp b/catalogue/OcciStmt.cpp index d7904bbee2ae79c6c359aa0e2750debdcd4023ba..d7683d5ed3a5368de4e4151598949328ca5033fa 100644 --- a/catalogue/OcciStmt.cpp +++ b/catalogue/OcciStmt.cpp @@ -16,30 +16,41 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// Version 12.1 of oracle instant client uses the pre _GLIBCXX_USE_CXX11_ABI +#define _GLIBCXX_USE_CXX11_ABI 0 + #include "catalogue/OcciConn.hpp" #include "catalogue/OcciStmt.hpp" -#include "common/exception/Exception.hpp" + +#include <cstring> +#include <stdexcept> //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::catalogue::OcciStmt::OcciStmt(const std::string &sql, OcciConn &conn, +cta::catalogue::OcciStmt::OcciStmt(const char *const sql, OcciConn &conn, oracle::occi::Statement *const stmt): - m_sql(sql), m_conn(conn), m_stmt(stmt) { if(NULL == stmt) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed" - ": OCCI statment is a NULL pointer"; + std::runtime_error ex(std::string(__FUNCTION__) + " failed" + ": OCCI statment is a NULL pointer"); throw ex; } + + // Work with C strings because they haven't changed with respect to _GLIBCXX_USE_CXX11_ABI + const std::size_t sqlLen = std::strlen(sql); + m_sql = new char[sqlLen + 1]; + std::memcpy(m_sql, sql, sqlLen); + m_sql[sqlLen] = '\0'; } //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ cta::catalogue::OcciStmt::~OcciStmt() throw() { + delete m_sql; + try { close(); // Idempotent close() method } catch(...) { @@ -62,7 +73,7 @@ void cta::catalogue::OcciStmt::close() { //------------------------------------------------------------------------------ // getSql //------------------------------------------------------------------------------ -const std::string &cta::catalogue::OcciStmt::getSql() const { +const char *cta::catalogue::OcciStmt::getSql() const { return m_sql; } @@ -83,19 +94,22 @@ oracle::occi::Statement *cta::catalogue::OcciStmt::operator->() const { //------------------------------------------------------------------------------ // bind //------------------------------------------------------------------------------ -void cta::catalogue::OcciStmt::bind(const std::string ¶mName, - const uint64_t paramValue) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " is not implemented"; +void cta::catalogue::OcciStmt::bind(const char *paramName, const uint64_t paramValue) { + std::runtime_error ex(std::string(__FUNCTION__) + " is not implemented"); throw ex; } //------------------------------------------------------------------------------ // bind //------------------------------------------------------------------------------ -void cta::catalogue::OcciStmt::bind(const std::string ¶mName, - const std::string ¶mValue) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " is not implemented"; +void cta::catalogue::OcciStmt::bind(const char *paramName, const char *paramValue) { + std::runtime_error ex(std::string(__FUNCTION__) + " is not implemented"); throw ex; } + +//------------------------------------------------------------------------------ +// execute +//------------------------------------------------------------------------------ +cta::catalogue::OcciRset *cta::catalogue::OcciStmt::execute() { + return NULL; +} diff --git a/catalogue/OcciStmt.hpp b/catalogue/OcciStmt.hpp index a479ce07a1c0f28c19541716557ae0b4f51e02e7..680605aae3856fb5d4210e47da88625cf51d8fce 100644 --- a/catalogue/OcciStmt.hpp +++ b/catalogue/OcciStmt.hpp @@ -23,19 +23,28 @@ #include <mutex> #include <occi.h> #include <stdint.h> -#include <string> namespace cta { namespace catalogue { /** - * Forward decalaration to avoid a circular depedency between OcciConn and - * OcciStmt. + * Forward declaration to avoid a circular dependency between OcciStmt and + * OcciConn. */ class OcciConn; +/** + * Forward declaration to avoid a circular dependency between OcciStmt and + * OcciRset. + */ +class OcciRset; + /** * A convenience wrapper around an OCCI prepared statement. + * + * Please note that this wrapper does not expose any data types that are + * different with respect to _GLIBCXX_USE_CXX11_ABI. For example this wrapper + * does not expose the std::string data type. */ class OcciStmt { public: @@ -43,14 +52,14 @@ public: /** * Constructor. * - * This constructor will throw an exception if the OCCI statement is a NULL - * pointer. - * + * This constructor will throw an exception if either the sql or stmt + * parameters are NULL. + * * @param sql The SQL statement. * @param conn The database connection. * @param stmt The prepared statement. */ - OcciStmt(const std::string &sql, OcciConn &conn, + OcciStmt(const char *const sql, OcciConn &conn, oracle::occi::Statement *const stmt); /** @@ -68,7 +77,7 @@ public: * * @return The SQL statement. */ - const std::string &getSql() const; + const char *getSql() const; /** * Returns the underlying OCCI result set. @@ -90,7 +99,7 @@ public: * @param paramName The name of the parameter. * @param paramValue The value to be bound. */ - void bind(const std::string ¶mName, const uint64_t paramValue); + void bind(const char *const paramName, const uint64_t paramValue); /** * Binds an SQL parameter. @@ -98,7 +107,12 @@ public: * @param paramName The name of the parameter. * @param paramValue The value to be bound. */ - void bind(const std::string ¶mName, const std::string ¶mValue); + void bind(const char*paramName, const char *paramValue); + + /** + * Executes the statement and returns the result set. + */ + OcciRset *execute(); private: @@ -110,7 +124,7 @@ private: /** * The SQL statement. */ - const std::string m_sql; + char *m_sql; /** * The database connection. @@ -122,7 +136,7 @@ private: */ oracle::occi::Statement *m_stmt; -}; // class SqlLiteStmt +}; // class OcciStmt } // namespace catalogue } // namespace cta diff --git a/catalogue/OcciStmtTest.cpp b/catalogue/OcciStmtTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1533bbe2a5773d2f108f2520c2d1a447138b0075 --- /dev/null +++ b/catalogue/OcciStmtTest.cpp @@ -0,0 +1,56 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "catalogue/DbLogin.hpp" +#include "catalogue/OcciEnv.hpp" +#include "catalogue/OcciConn.hpp" +#include "catalogue/OcciRset.hpp" +#include "catalogue/OcciStmt.hpp" +#include "tests/OraUnitTestsCmdLineArgs.hpp" + +#include <gtest/gtest.h> +#include <memory> + +namespace unitTests { + +class cta_catalogue_OcciStmtTest : public ::testing::Test { +protected: + + virtual void SetUp() { + } + + virtual void TearDown() { + } +}; + +TEST_F(cta_catalogue_OcciStmtTest, execute) { + using namespace cta; + using namespace cta::catalogue; + + const DbLogin dbLogin = DbLogin::readFromFile(g_cmdLineArgs.oraDbConnFile); + OcciEnv env; + std::unique_ptr<OcciConn> conn(env.createConn( + dbLogin.username.c_str(), + dbLogin.password.c_str(), + dbLogin.database.c_str())); + const char *const sql = "SELECT * FROM DUAL"; + std::unique_ptr<OcciStmt> stmt(conn->createStmt(sql)); + std::unique_ptr<OcciRset> rset(stmt->execute()); +} + +} // namespace unitTests diff --git a/cmake/Findoracle-instantclient.cmake b/cmake/Findoracle-instantclient.cmake index d739c50b246409f61efdf6c245eaf2435d0f4e1f..7c4487e7f311ca21f2f7ba8a4e32d489eba9aeac 100644 --- a/cmake/Findoracle-instantclient.cmake +++ b/cmake/Findoracle-instantclient.cmake @@ -19,25 +19,31 @@ # ORACLE-INSTANTCLIENT_INCLUDE_DIRS # ORACLE-INSTANTCLIENT_LIBRARIES +set(ORACLE-INSTANTCLIENT_VERSION 12.1) + find_path(ORACLE-INSTANTCLIENT_INCLUDE_DIRS occi.h - PATHS /usr/include/oracle/12.1/client64 - NO_DEFAULT_PATH) - -find_library(ORACLE-INSTANTCLIENT_OCCI_LIBRARY - NAME occi - PATHS /usr/lib/oracle/12.1/client64/lib + PATHS /usr/include/oracle/${ORACLE-INSTANTCLIENT_VERSION}/client64 NO_DEFAULT_PATH) find_library(ORACLE-INSTANTCLIENT_CLNTSH_LIBRARY NAME clntsh - PATHS /usr/lib/oracle/12.1/client64/lib + PATHS /usr/lib/oracle/${ORACLE-INSTANTCLIENT_VERSION}/client64/lib + NO_DEFAULT_PATH) + +find_library(ORACLE-INSTANTCLIENT_OCCI_LIBRARY + NAME occi + PATHS /usr/lib/oracle/${ORACLE-INSTANTCLIENT_VERSION}/client64/lib NO_DEFAULT_PATH) set(ORACLE-INSTANTCLIENT_LIBRARIES ${ORACLE-INSTANTCLIENT_OCCI_LIBRARY} ${ORACLE-INSTANTCLIENT_CLNTSH_LIBRARY}) +message(STATUS "ORACLE-INSTANTCLIENT_INCLUDE_DIRS=${ORACLE-INSTANTCLIENT_INCLUDE_DIRS}") +message(STATUS "ORACLE-INSTANTCLIENT_LIBRARIES=${ORACLE-INSTANTCLIENT_LIBRARIES}") + include(FindPackageHandleStandardArgs) find_package_handle_standard_args(oracle-instantclient DEFAULT_MSG - ORACLE-INSTANTCLIENT_INCLUDE_DIRS ORACLE-INSTANTCLIENT_LIBRARIES) + ORACLE-INSTANTCLIENT_INCLUDE_DIRS + ORACLE-INSTANTCLIENT_LIBRARIES) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5101549e5b651197c12df55ad5aebdaf83c8f98e..c83d2639d69a75ed75569b0f4de17094cb49ef07 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -48,6 +48,17 @@ target_link_libraries(cta-unitTests gtest pthread) +add_executable(cta-oraUnitTests + OraUnitTestsCmdLineArgs.cpp + oraUnitTests.cpp + ${GMOCK_SRC}) + +target_link_libraries(cta-oraUnitTests + ctacatalogueoraunittests + ${GMOCK_LIB} + gtest + pthread) + add_executable(cta-unitTests-multiProcess unit_tests.cpp ${GMOCK_SRC}) diff --git a/tests/OraUnitTestsCmdLineArgs.cpp b/tests/OraUnitTestsCmdLineArgs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..460dbc952b3e02c7558c0ffaee49651971a2db55 --- /dev/null +++ b/tests/OraUnitTestsCmdLineArgs.cpp @@ -0,0 +1,24 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/OraUnitTestsCmdLineArgs.hpp" + +//---------------------------------------------------------------------------------------------------------------------- +// Definition of the global variable used to store the command-line arguments so that they are visible to the tests. +//---------------------------------------------------------------------------------------------------------------------- +CmdLineArgs g_cmdLineArgs; diff --git a/tests/OraUnitTestsCmdLineArgs.hpp b/tests/OraUnitTestsCmdLineArgs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a7992ed739e180fd8193a3757f6a96f3791ca0df --- /dev/null +++ b/tests/OraUnitTestsCmdLineArgs.hpp @@ -0,0 +1,31 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string> + +struct CmdLineArgs { + /** + * The oracle database connection string. + */ + std::string oraDbConnFile; +}; + +/** + * Declaration of the global variable used to store the command-line arguments so that they are visible to the tests. + */ +extern CmdLineArgs g_cmdLineArgs; diff --git a/tests/oraUnitTests.cpp b/tests/oraUnitTests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67521c6bebbd028afbcb6567800be400c1e60a0b --- /dev/null +++ b/tests/oraUnitTests.cpp @@ -0,0 +1,70 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tests/OraUnitTestsCmdLineArgs.hpp" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <iostream> + +/** + * Prints the usage message of this unit-test program to the specified output stream. + */ +static void printUsage(std::ostream &os) { + os << + "Usage:" << std::endl << + '\t' << "cta-oraUnitTest [Google test options] databaseConnectionFile" << std::endl; +} + +/** + * Parses the specified command-line arguments. This should be called after Google test has consumed all of its + * command-line options from the command-line. + */ +static CmdLineArgs parseCmdLine(const int argc, char ** argv) { + if(argc != 2) { + std::cerr << "Invalid number of command-line arguments"; + printUsage(std::cerr); + exit(1); + } + + CmdLineArgs cmdLineArgs; + cmdLineArgs.oraDbConnFile = argv[1]; + + return cmdLineArgs; +} + +int main(int argc, char** argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. + ::testing::InitGoogleMock(&argc, argv); + + // Google test will consume its options from the command-line and leave everything else + g_cmdLineArgs = parseCmdLine(argc, argv); + + const int ret = RUN_ALL_TESTS(); + + // Close standard in, out and error so that valgrind can be used with the + // following command-line to track open file-descriptors: + // + // valgrind --track-fds=yes + close(0); + close(1); + close(2); + + return ret; +} diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp index 80b4878f02f6c60cb4b21d6e757946bd26b5de7c..336b128c4e934ebb0c551dd76ff7bf15e86646ee 100644 --- a/tests/unit_tests.cpp +++ b/tests/unit_tests.cpp @@ -31,7 +31,7 @@ int main(int argc, char** argv) { // The following line must be executed to initialize Google Mock // (and Google Test) before running the tests. ::testing::InitGoogleMock(&argc, argv); - int ret = RUN_ALL_TESTS(); + const int ret = RUN_ALL_TESTS(); // Close standard in, out and error so that valgrind can be used with the // following command-line to track open file-descriptors: