Skip to content
Snippets Groups Projects
Commit de042bf1 authored by Steven Murray's avatar Steven Murray
Browse files

OcciRset now inherits from DbRset

parent 25eb376c
Branches
Tags
No related merge requests found
......@@ -24,6 +24,7 @@ set (CATALOGUE_LIB_SRC_FILES
ArchiveFileRow.cpp
Catalogue.cpp
DbLogin.cpp
DbRset.cpp
TapeFileWritten.cpp
OcciConn.cpp
OcciEnv.cpp
......
/*
* 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/DbRset.hpp"
namespace cta {
namespace catalogue {
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
DbRset::~DbRset() throw() {
}
} // namespace catalogue
} // namespace cta
/*
* 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/>.
*/
#pragma once
#include <stdint.h>
namespace cta {
namespace catalogue {
/**
* Abstract class specificing the interface to the result set of an sql query.
*
* Please note that this interface intentionally uses C-strings instead of
* std::string so that it can be used by code compiled against the CXX11 ABI and
* by code compiled against a pre-CXX11 ABI.
*/
class DbRset {
public:
/**
* Destructor.
*
* Please note that this method will delete the memory asscoiated with any
* C-strings returned by the columnText() method.
*/
virtual ~DbRset() throw() = 0;
/**
* Returns the SQL statement.
*
* @return The SQL statement.
*/
virtual const char *getSql() const = 0;
/**
* Attempts to get the next row of the result set.
*
* Please note that this method will delete the memory associated with any
* C-strings returned by the columnText() method.
*
* @return True if a row has been retrieved else false if there are no more
* rows in the result set.
*/
virtual bool next() = 0;
/**
* Returns true if the specified column contains a null value.
*
* @param colName The name of the column.
* @return True if the specified column contains a null value.
*/
virtual bool columnIsNull(const char *const colName) const = 0;
/**
* Returns the value of the specified column as a string.
*
* Please note that a C-string is returned instead of an std::string so that
* this method can be used by code compiled against the CXX11 ABI and by code
* compiled against a pre-CXX11 ABI.
*
* Please note that if the value of the column is NULL within the database
* then an empty string shall be returned. Use the columnIsNull() method to
* determine whether not a column contains a NULL value.
*
* @param colName The name of the column.
* @return The string value of the specified column. Please note that the
* returned string should not be deleted. The string should be copied before
* the next call to the next() method. The DbRset class is responsible
* for freeing the memory.
*/
virtual const char *columnText(const char *const colName) const = 0;
/**
* Returns the value of the specified column as an integer.
*
* @param colName The name of the column.
* @return The value of the specified column.
*/
virtual uint64_t columnUint64(const char *const colName) const = 0;
}; // class DbRset
} // namespace catalogue
} // namespace cta
......@@ -225,6 +225,41 @@ OcciRset::~OcciRset() throw() {
}
}
//------------------------------------------------------------------------------
// getSql
//------------------------------------------------------------------------------
const char *OcciRset::getSql() const {
return m_stmt.getSql();
}
//------------------------------------------------------------------------------
// next
//------------------------------------------------------------------------------
bool OcciRset::next() {
using namespace oracle;
try {
m_textColumnCache->clear();
const occi::ResultSet::Status status = m_rset->next();
return occi::ResultSet::DATA_AVAILABLE == status;
} catch(std::exception &ne) {
throw std::runtime_error(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " +
ne.what());
}
}
//------------------------------------------------------------------------------
// columnIsNull
//------------------------------------------------------------------------------
bool OcciRset::columnIsNull(const char *const colName) const {
try {
const int colIdx = m_colNameToIdx->getIdx(colName);
return m_rset->isNull(colIdx);
} catch(std::exception &ne) {
throw std::runtime_error(std::string(__FUNCTION__) + " failed: " + ne.what());
}
}
//------------------------------------------------------------------------------
// close
//------------------------------------------------------------------------------
......@@ -251,26 +286,10 @@ oracle::occi::ResultSet *OcciRset::operator->() const {
return get();
}
//------------------------------------------------------------------------------
// next
//------------------------------------------------------------------------------
bool OcciRset::next() {
using namespace oracle;
try {
m_textColumnCache->clear();
const occi::ResultSet::Status status = m_rset->next();
return occi::ResultSet::DATA_AVAILABLE == status;
} catch(std::exception &ne) {
throw std::runtime_error(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " +
ne.what());
}
}
//------------------------------------------------------------------------------
// columnText
//------------------------------------------------------------------------------
const char * OcciRset::columnText(const char *const colName) {
const char * OcciRset::columnText(const char *const colName) const {
try {
std::lock_guard<std::mutex> lock(m_mutex);
......@@ -293,5 +312,20 @@ const char * OcciRset::columnText(const char *const colName) {
}
}
//------------------------------------------------------------------------------
// columnUint64
//------------------------------------------------------------------------------
uint64_t OcciRset::columnUint64(const char *const colName) const {
try {
std::lock_guard<std::mutex> lock(m_mutex);
const int colIdx = m_colNameToIdx->getIdx(colName);
return m_rset->getUInt(colIdx);
} catch(std::exception &ne) {
throw std::runtime_error(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " +
ne.what());
}
}
} // namespace catalogue
} // namespace cta
......@@ -18,6 +18,8 @@
#pragma once
#include "catalogue/DbRset.hpp"
#include <memory>
#include <mutex>
#include <occi.h>
......@@ -26,7 +28,7 @@ namespace cta {
namespace catalogue {
/**
* Forward declaraion to avoid a circular dependency beween OcciRset and
* Forward declaration to avoid a circular dependency between OcciRset and
* OcciStmt.
*/
class OcciStmt;
......@@ -34,7 +36,7 @@ class OcciStmt;
/**
* A convenience wrapper around an OCCI result set.
*/
class OcciRset {
class OcciRset: public DbRset {
public:
/**
......@@ -50,62 +52,92 @@ public:
/**
* Destructor.
*/
~OcciRset() throw();
/**
* Idempotent close() method. The destructor calls this method.
*/
void close();
/**
* Returns the underlying OCCI result set.
*
* This method will always return a valid pointer.
*
* @return The underlying OCCI result set.
* Please note that this method will delete the memory asscoiated with any
* C-strings returned by the columnText() method.
*/
oracle::occi::ResultSet *get() const;
virtual ~OcciRset() throw();
/**
* An alias for the get() method.
* Returns the SQL statement.
*
* @return The underlying OCCI result set.
* @return The SQL statement.
*/
oracle::occi::ResultSet *operator->() const;
virtual const char *getSql() const;
/**
* Attempts to get the next row of the result set.
*
* Please note that this method will delete the memory associated with any
* C-strings returned by the columnText() method.
*
* @return True if a row has been retrieved else false if there are no more
* rows in the result set.
*/
bool next();
virtual bool next();
/**
* Returns true if the specified column contains a null value.
*
* @param colName The name of the column.
* @return True if the specified column contains a null value.
*/
virtual bool columnIsNull(const char *const colName) const;
/**
* Returns the value of the specified column as a string.
*
* Please note that a C string is returned instead of an std::string so that
* Please note that a C-string is returned instead of an std::string so that
* this method can be used by code compiled against the CXX11 ABI and by code
* compiled against the pre-CXX11 ABI.
* compiled against a pre-CXX11 ABI.
*
* Please note that if the value of the column is NULL within the database
* then a NULL pointer is returned.
* then an empty string shall be returned. Use the columnIsNull() method to
* determine whether not a column contains a NULL value.
*
* @param colName The name of the column.
* @return The string value of the specified column or NULL if the value of
* the column within the database is NULL. Please note that the caller should
* NOT delete the returned string. The string will be automatically deleted
* when OcciRset::next() is called or when the OcciRset destructor is called.
* @return The string value of the specified column. Please note that the
* returned string should not be deleted. The string should be copied before
* the next call to the next() method. The DbRset class is responsible
* for freeing the memory.
*/
const char *columnText(const char *const colName);
virtual const char *columnText(const char *const colName) const;
/**
* Returns the value of the specified column as an integer.
*
* @param colName The name of the column.
* @return The value of the specified column.
*/
virtual uint64_t columnUint64(const char *const colName) const;
/**
* Idempotent close() method. The destructor calls this method.
*/
void close();
/**
* Returns the underlying OCCI result set.
*
* This method will always return a valid pointer.
*
* @return The underlying OCCI result set.
*/
oracle::occi::ResultSet *get() const;
/**
* An alias for the get() method.
*
* @return The underlying OCCI result set.
*/
oracle::occi::ResultSet *operator->() const;
private:
/**
* Mutex used to serialize access to this object.
*/
std::mutex m_mutex;
mutable std::mutex m_mutex;
/**
* The OCCI statement.
......@@ -134,7 +166,20 @@ private:
*/
std::unique_ptr<ColumnNameToIdx> m_colNameToIdx;
/**
* Forward declaration of the nest class TextColumnCache that is intentionally
* hidden in the cpp file of the SqliteRset class. The class is hidden in
* order to enable the SqliteRset class to be used by code compiled against
* the CXX11 ABI and used by code compiled against the pre-CXX11 ABI.
*/
class TextColumnCache;
/**
* Map from column name to column text value. This map is used to cache the
* results of calling OcciRset::columnText() in the form of C-strings so that
* the OcciRset class can provide a similar memory management policy for
* C-strings as the SQLite API.
*/
std::unique_ptr<TextColumnCache> m_textColumnCache;
/**
......
......@@ -76,4 +76,25 @@ TEST_F(cta_catalogue_OcciRsetTest, executeQueryRelyOnRsetDestructorForCacheDelet
ASSERT_EQ(std::string("X"), text);
}
TEST_F(cta_catalogue_OcciRsetTest, eexcuteQuery_uint32_t) {
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 1234 AS I FROM DUAL";
std::unique_ptr<OcciStmt> stmt(conn->createStmt(sql));
std::unique_ptr<OcciRset> rset(stmt->executeQuery());
ASSERT_TRUE(rset->next());
const uint32_t i = rset->columnUint64("I");
ASSERT_EQ(1234, i);
ASSERT_FALSE(rset->next());
}
// TODO - Implement 64-bit int test because the current code will fail
} // namespace unitTests
......@@ -45,6 +45,9 @@ public:
/**
* Destructor.
*
* Please note that this method will delete the memory asscoiated with any
* C-strings returned by the columnText() method.
*/
~SqliteRset() throw();
......@@ -58,6 +61,9 @@ public:
/**
* Attempts to get the next row of the result set.
*
* Please note that this method will delete the memory asscoiated with any
* C-strings returned by the columnText() method.
*
* @return True if a row has been retrieved else false if there are no more
* rows in the result set.
*/
......@@ -74,7 +80,7 @@ public:
/**
* Returns the value of the specified column as a string.
*
* Please note that a C string is returned instead of an std::string so that
* Please note that a C-string is returned instead of an std::string so that
* this method can be used by code compiled against the CXX11 ABI and by code
* compiled against a pre-CXX11 ABI.
*
......@@ -132,7 +138,7 @@ private:
*/
void populateColNameToIdxAndTypeMap();
}; // class SqlLiteStmt
}; // class SqlLiteRset
} // namespace catalogue
} // namespace cta
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment