Commit 00dd9fa7 authored by Steven Murray's avatar Steven Murray
Browse files

WIP

parent a5485043
......@@ -31,9 +31,6 @@ set(CMAKE_CXX_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter
# to be tested once we have a stable compilation on CC7:
#-Wno-unused-parameter -Wlogical-op -Wfloat-equal -Wdeclaration-after- statement -Wundef -Wno-endif-labels -Wshadow -Wunsafe-loop- optimizations -Wpointer-arith -Wbad-function-cast -Wcast-align -Wwrite- strings -Wconversion -Wmissing-field-initializers -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Wvariadic-macros -Wtraditional -Wmissing-prototypes -Wmissing-declarations -Wold-style- definition -Wc++-compat -Wstrict-prototypes -Wpadded -Wcast-qual -Wnon-virtual-dtor -Wlogical-op -Wmissing-declarations -Wsign-conversion -Wredundant-decls -Wold-style-cast -Wshadow
# Explicitly setting the C and C++ compiler flags for the RelWithDebInfo build
# in order to prevent the -O2 flag from being used.
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g")
......
......@@ -17,6 +17,7 @@ cmake_minimum_required (VERSION 2.6)
set (CATALOGUE_LIB_SRC_FILES
Catalogue.cpp
ColumnNameToIdx.cpp
DbLogin.cpp
DummyCatalogue.cpp
SqliteCatalogue.cpp
......@@ -27,7 +28,8 @@ add_library (ctacatalogue
${CATALOGUE_LIB_SRC_FILES})
set (CATALOGUE_UNIT_TESTS_LIB_SRC_FILES
SqliteCatalogueTest.cpp)
SqliteCatalogueTest.cpp
SqliteStmtTest.cpp)
add_library (ctacatalogueunittests SHARED
${CATALOGUE_UNIT_TESTS_LIB_SRC_FILES})
......
/*
* 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/ColumnNameToIdx.hpp"
#include "common/exception/Exception.hpp"
//------------------------------------------------------------------------------
// addNameToIdx
//------------------------------------------------------------------------------
void cta::catalogue::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";
throw ex;
}
m_nameToIdx[name] = idx;
}
//------------------------------------------------------------------------------
// getIdx
//------------------------------------------------------------------------------
int cta::catalogue::ColumnNameToIdx::getIdx(const std::string &name) const {
auto it = m_nameToIdx.find(name);
if(m_nameToIdx.end() == it) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: Unknown column name " << name;
throw ex;
}
return it->second;
}
//------------------------------------------------------------------------------
// operator[]
//------------------------------------------------------------------------------
int cta::catalogue::ColumnNameToIdx::operator[](const std::string &name) const {
return getIdx(name);
}
//------------------------------------------------------------------------------
// empty
//------------------------------------------------------------------------------
bool cta::catalogue::ColumnNameToIdx::empty() const {
return m_nameToIdx.empty();
}
/*
* 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 <map>
#include <string>
namespace cta {
namespace catalogue {
/**
* A map from column name to column index.
*/
class ColumnNameToIdx {
public:
/**
* Adds the specified column name to index mapping.
*
* This method throws an exception if the specified column name is a
* duplicate, in other words has already been added to the map.
*
* @param name The name of the column.
* @param idx The index of the column.
*/
void add(const std::string &name, const int idx);
/**
* Returns the index of the column with the specified name.
*
* This method throws an exception if the specified column name is not in the
* map.
*
* @return the index of the column with the specified name.
*/
int getIdx(const std::string &name) const;
/**
* Alias for the getIdx() method.
*
* @return the index of the column with the specified name.
*/
int operator[](const std::string &name) const;
/**
* Returns true if this map is empty.
*
* @return True if this map is empty.
*/
bool empty() const;
private:
/**
* The underlying STL map from column name to column index.
*/
std::map<std::string, int> m_nameToIdx;
}; // class ColumnNameToIdx
} // namespace catalogue
} // namespace cta
......@@ -46,6 +46,20 @@ void cta::catalogue::SqliteCatalogue::createDbSchema() {
"CREATOR_HOST TEXT,"
"CREATION_TIME INTEGER,"
"UPDATER_USER TEXT,"
"UPDATER_GROUP TEXT,"
"UPDATER_HOST TEXT,"
"UPDATE_TIME INTEGER);"
"CREATE TABLE ADMIN_HOST("
"HOST_NAME TEXT,"
"COMMENT TEXT,"
"CREATOR_USER TEXT,"
"CREATOR_GROUP TEXT,"
"CREATOR_HOST TEXT,"
"CREATION_TIME INTEGER,"
"UPDATER_USER TEXT,"
"UPDATER_GROUP TEXT,"
"UPDATER_HOST TEXT,"
......@@ -66,55 +80,100 @@ void cta::catalogue::SqliteCatalogue::createBootstrapAdminAndHostNoAuth(
const common::dataStructures::UserIdentity &user,
const std::string &hostName,
const std::string &comment) {
const char *sql =
"INSERT INTO ADMIN_USER("
"USER_NAME,"
"GROUP_NAME,"
"COMMENT,"
"CREATOR_USER,"
"CREATOR_GROUP,"
"CREATOR_HOST,"
"CREATION_TIME,"
"UPDATER_USER,"
"UPDATER_GROUP,"
"UPDATER_HOST,"
"UPDATE_TIME)"
"VALUES("
":USER_NAME,"
":GROUP_NAME,"
":COMMENT,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME";
SqliteStmt stmt(m_conn, sql);
const uint64_t now = time(NULL);
stmt.bind(":USER_NAME", user.name);
stmt.bind(":GROUP_NAME", user.group);
stmt.bind(":COMMENT", comment);
stmt.bind(":CREATOR_USER", cliIdentity.user.name);
stmt.bind(":CREATOR_GROUP", cliIdentity.user.group);
stmt.bind(":CREATOR_HOST", cliIdentity.host);
stmt.bind(":CREATION_TIME", now);
stmt.step();
{
const char *const sql =
"INSERT INTO ADMIN_USER("
"USER_NAME,"
"GROUP_NAME,"
"COMMENT,"
"CREATOR_USER,"
"CREATOR_GROUP,"
"CREATOR_HOST,"
"CREATION_TIME,"
"UPDATER_USER,"
"UPDATER_GROUP,"
"UPDATER_HOST,"
"UPDATE_TIME)"
"VALUES("
":USER_NAME,"
":GROUP_NAME,"
":COMMENT,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME);";
SqliteStmt stmt(m_conn, sql);
stmt.bind(":USER_NAME", user.getName());
stmt.bind(":GROUP_NAME", user.getGroup());
stmt.bind(":COMMENT", comment);
stmt.bind(":CREATOR_USER", cliIdentity.getUser().getName());
stmt.bind(":CREATOR_GROUP", cliIdentity.getUser().getGroup());
stmt.bind(":CREATOR_HOST", cliIdentity.getHost());
stmt.bind(":CREATION_TIME", now);
stmt.step();
}
{
const char *const sql =
"INSERT INTO ADMIN_HOST("
"HOST_NAME,"
"COMMENT,"
"CREATOR_USER,"
"CREATOR_GROUP,"
"CREATOR_HOST,"
"CREATION_TIME,"
"UPDATER_USER,"
"UPDATER_GROUP,"
"UPDATER_HOST,"
"UPDATE_TIME)"
"VALUES("
":HOST_NAME,"
":COMMENT,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME,"
":CREATOR_USER,"
":CREATOR_GROUP,"
":CREATOR_HOST,"
":CREATION_TIME);";
SqliteStmt stmt(m_conn, sql);
stmt.bind(":HOST_NAME", hostName);
stmt.bind(":COMMENT", comment);
stmt.bind(":CREATOR_USER", cliIdentity.getUser().getName());
stmt.bind(":CREATOR_GROUP", cliIdentity.getUser().getGroup());
stmt.bind(":CREATOR_HOST", cliIdentity.getHost());
stmt.bind(":CREATION_TIME", now);
stmt.step();
}
}
//------------------------------------------------------------------------------
// createAdminUser
//------------------------------------------------------------------------------
void cta::catalogue::SqliteCatalogue::createAdminUser(const common::dataStructures::SecurityIdentity &cliIdentity, const common::dataStructures::UserIdentity &user, const std::string &comment) {
const char *sql =
const uint64_t now = time(NULL);
const char *const sql =
"INSERT INTO ADMIN_USER("
"USER_NAME,"
"GROUP_NAME,"
......@@ -139,12 +198,11 @@ void cta::catalogue::SqliteCatalogue::createAdminUser(const common::dataStructur
":CREATOR_HOST,"
":CREATION_TIME,"
":UPDATER_USER,"
":UPDATER_GROUP,"
":UPDATER_HOST,"
":UPDATE_TIME";
":CREATOR_USER,"
":CREATER_GROUP,"
":CREATER_HOST,"
":CREATION_TIME);";
SqliteStmt stmt(m_conn, sql);
const uint64_t now = time(NULL);
stmt.bind(":USER_NAME", user.name);
stmt.bind(":GROUP_NAME", user.group);
......@@ -166,7 +224,63 @@ void cta::catalogue::SqliteCatalogue::deleteAdminUser(const common::dataStructur
//------------------------------------------------------------------------------
// getAdminUsers
//------------------------------------------------------------------------------
std::list<cta::common::dataStructures::AdminUser> cta::catalogue::SqliteCatalogue::getAdminUsers(const common::dataStructures::SecurityIdentity &requester) const { return std::list<cta::common::dataStructures::AdminUser>();}
std::list<cta::common::dataStructures::AdminUser> cta::catalogue::SqliteCatalogue::getAdminUsers(const common::dataStructures::SecurityIdentity &requester) const {
std::list<cta::common::dataStructures::AdminUser> admins;
const char *const sql =
"SELECT "
"USER_NAME AS USER_NAME,"
"GROUP_NAME AS GROUP_NAME,"
"COMMENT AS COMMENT,"
"CREATOR_USER AS CREATOR_USER,"
"CREATOR_GROUP AS CREATOR_GROUP,"
"CREATOR_HOST AS CREATOR_HOST,"
"CREATION_TIME AS CREATION_TIME,"
"UPDATER_USER AS UPDATER_USER,"
"UPDATER_GROUP AS UPDATER_GROUP,"
"UPDATER_HOST AS UPDATER_HOST,"
"UPDATE_TIME AS UPDATE_TIME "
"FROM ADMIN_USER";
SqliteStmt stmt(m_conn, sql);
ColumnNameToIdx nameToIdx;
while(SQLITE_ROW == stmt.step()) {
if(nameToIdx.empty()) {
nameToIdx = stmt.getColumnNameToIdx();
}
common::dataStructures::AdminUser admin;
common::dataStructures::UserIdentity adminUI;
adminUI.setName(stmt.columnText(nameToIdx["USER_NAME"]));
adminUI.setGroup(stmt.columnText(nameToIdx["GROUP_NAME"]));
admin.setUser(adminUI);
admin.setComment(stmt.columnText(nameToIdx["COMMENT"]));
common::dataStructures::UserIdentity creatorUI;
creatorUI.setName(stmt.columnText(nameToIdx["CREATOR_USER"]));
creatorUI.setGroup(stmt.columnText(nameToIdx["CREATOR_GROUP"]));
common::dataStructures::EntryLog creationLOg;
creationLOg.setUser(creatorUI);
creationLOg.setHost(stmt.columnText(nameToIdx["CREATOR_HOST"]));
creationLOg.setTime(stmt.columnUint64(nameToIdx["CREATION_TIME"]));
admin.setCreationLog(creationLOg);
common::dataStructures::UserIdentity updaterUI;
updaterUI.setName(stmt.columnText(nameToIdx["UPDATER_USER"]));
updaterUI.setGroup(stmt.columnText(nameToIdx["UPDATER_GROUP"]));
common::dataStructures::EntryLog updateLog;
updateLog.setUser(updaterUI);
updateLog.setHost(stmt.columnText(nameToIdx["UPDATER_HOST"]));
updateLog.setTime(stmt.columnUint64(nameToIdx["UPDATE_TIME"]));
admin.setLastModificationLog(updateLog);
admins.push_back(admin);
}
return admins;
}
//------------------------------------------------------------------------------
// modifyAdminUserComment
......
/*
* 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/SqliteCatalogue.hpp"
#include <gtest/gtest.h>
......@@ -113,7 +131,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser) {
{
std::list<common::dataStructures::AdminUser> admins;
ASSERT_NO_THROW(admins = catalogue->getAdminUsers(m_admin1));
admins = catalogue->getAdminUsers(m_admin1);
ASSERT_EQ(2, admins.size());
}
}
......
......@@ -43,7 +43,7 @@ cta::catalogue::SqliteConn::~SqliteConn() throw() {
//------------------------------------------------------------------------------
// get
//------------------------------------------------------------------------------
sqlite3 *cta::catalogue::SqliteConn::get() {
sqlite3 *cta::catalogue::SqliteConn::get() const {
if(NULL == m_conn) {
throw exception::Exception("Failed to get SQLite database connection"
": NULL pointer");
......
......@@ -47,7 +47,7 @@ public:
*
* @return the underlying database connection.
*/
sqlite3 *get();
sqlite3 *get() const;
/**
* Enables foreign key constraints.
......
......@@ -22,11 +22,12 @@
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta::catalogue::SqliteStmt::SqliteStmt(SqliteConn &conn,
cta::catalogue::SqliteStmt::SqliteStmt(const SqliteConn &conn,
const std::string &sql): m_sql(sql) {
m_stmt = NULL;
const int prepareRc = sqlite3_prepare_v2(conn.get(), sql.c_str(), 0, &m_stmt,
NULL);
const int nByte = -1; // Read SQL up to first null terminator
const int prepareRc = sqlite3_prepare_v2(conn.get(), sql.c_str(), nByte,
&m_stmt, NULL);
if(SQLITE_OK != prepareRc) {
sqlite3_finalize(m_stmt);
exception::Exception ex;
......@@ -76,7 +77,7 @@ void cta::catalogue::SqliteStmt::bind(const std::string &paramName,
void cta::catalogue::SqliteStmt::bind(const std::string &paramName,
const std::string &paramValue) {
const int paramIdx = getParamIndex(paramName);
const int bindRc = sqlite3_bind_text(m_stmt, paramIdx, paramName.c_str(), -1,
const int bindRc = sqlite3_bind_text(m_stmt, paramIdx, paramValue.c_str(), -1,
SQLITE_TRANSIENT);
if(SQLITE_OK != bindRc) {
exception::Exception ex;
......@@ -98,79 +99,59 @@ int cta::catalogue::SqliteStmt::step() {
// Throw an appropriate exception
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: " << sqliteRcToString(stepRc) <<
ex.getMessage() << __FUNCTION__ << " failed: " << sqlite3_errstr(stepRc) <<
": For SQL statement " << m_sql;
throw ex;
}
//------------------------------------------------------------------------------
// sqliteRcToString
//------------------------------------------------------------------------------
std::string cta::catalogue::SqliteStmt::sqliteRcToString(const int rc) const {
switch(rc) {
case SQLITE_ABORT:
return "Abort requested";
case SQLITE_AUTH:
return "Authorization denied";
case SQLITE_BUSY:
return "Failed to take locks";
case SQLITE_CANTOPEN:
return "Cannot open database file";
case SQLITE_CONSTRAINT:
return "Constraint violation";
case SQLITE_CORRUPT:
return "Database file corrupted";
case SQLITE_DONE:
return "Statement finished executing successfully";
case SQLITE_EMPTY:
return "Database file empty";
case SQLITE_FORMAT:
return "Database format error";
case SQLITE_FULL:
return "Database full";
case SQLITE_INTERNAL:
return "Internal SQLite library error";
case SQLITE_INTERRUPT:
return "Interrupted";
case SQLITE_IOERR:
return "I/O error";
case SQLITE_LOCKED:
return "A table is locked";
case SQLITE_MISMATCH:
return "Datatype mismatch";
case SQLITE_MISUSE:
return "Misuse";
case SQLITE_NOLFS:
return "OS cannot provide functionality";
case SQLITE_NOMEM:
return "Memory allocation error";
case SQLITE_NOTADB:
return "Not a database file";
case SQLITE_OK:
return "Operation successful";
case SQLITE_PERM:
return "Permnission denied";
case SQLITE_RANGE:
return "Invalid bind parameter index";
case SQLITE_READONLY:
return "Failed to write to read-only database";
case SQLITE_ROW:
return "A new row of data is ready for reading";
case SQLITE_SCHEMA:
return "Database schema changed";
case SQLITE_TOOBIG:
return "TEXT or BLOCK too big";
case SQLITE_ERROR:
return "Generic error";
default:
{
std::ostringstream oss;
oss << "Unknown SQLite return code " << rc;
return oss.str();
// getColumnNameToIdx
//------------------------------------------------------------------------------
cta::catalogue::ColumnNameToIdx cta::catalogue::SqliteStmt::getColumnNameToIdx()
const {
ColumnNameToIdx nameToIdx;
try {
const int nbCols = sqlite3_column_count(m_stmt);
for(int i = 0; i < nbCols; i++) {
const char *name = sqlite3_column_name(m_stmt, i);
if(NULL == name) {
exception::Exception ex;
ex.getMessage() << "Failed to get column name for column index " << i;
throw ex;
}
nameToIdx.add(name, i);
}
} catch(exception::Exception &ne) {
exception::Exception ex;
ex.getMessage() << __FUNCTION__ << " failed: For SQL statement " << m_sql
<< ": " << ne.getMessage();
throw ex;
}
return nameToIdx;
}
//------------------------------------------------------------------------------
// columnText
//------------------------------------------------------------------------------
std::string cta::catalogue::SqliteStmt::columnText(const int colIdx) {
const char *const colValue = (const char *)sqlite3_column_text(m_stmt,
colIdx);
if(NULL == colValue) {
return "";
} else {
return colValue;
}
}
//------------------------------------------------------------------------------
// columnUint64
//------------------------------------------------------------------------------
uint64_t cta::catalogue::SqliteStmt::columnUint64(const int colIdx) {
return (uint64_t)sqlite3_column_int64(m_stmt, colIdx);
}
//------------------------------------------------------------------------------
// getParamIndex
//------------------------------------------------------------------------------
......
......@@ -19,7 +19,10 @@
#pragma once
#include "catalogue/SqliteConn.hpp"
#include "catalogue/ColumnNameToIdx.hpp"
#include <map>