Skip to content

Commit

Permalink
Add the db_filename method to sqlite::database
Browse files Browse the repository at this point in the history
Keep track of the filename the sqlite::database object was connected to
so that the user of the class can query it at all times.  This will be
necessary to improve error reporting on sqlite::error exceptions.
  • Loading branch information
jmmv committed Jul 7, 2015
1 parent 4462b98 commit 8003c86
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
21 changes: 21 additions & 0 deletions utils/sqlite/c_gate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <atf-c++.hpp>

#include "utils/fs/path.hpp"
#include "utils/optional.ipp"
#include "utils/sqlite/database.hpp"
#include "utils/sqlite/test_utils.hpp"

Expand Down Expand Up @@ -68,8 +69,28 @@ ATF_TEST_CASE_BODY(c_database)
}


ATF_TEST_CASE(database__db_filename);
ATF_TEST_CASE_HEAD(database__db_filename)
{
set_md_var("descr", "Ensure that the value of db_filename cached by the "
"sqlite::database class works after a connect() call");
}
ATF_TEST_CASE_BODY(database__db_filename)
{
::sqlite3* raw_db;
ATF_REQUIRE_EQ(SQLITE_OK, ::sqlite3_open_v2(
"test.db", &raw_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));

sqlite::database database = sqlite::database_c_gate::connect(raw_db);
ATF_REQUIRE_EQ(utils::make_optional(fs::path("test.db").to_absolute()),
database.db_filename());
::sqlite3_close(raw_db);
}


ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, c_database);
ATF_ADD_TEST_CASE(tcs, connect);
ATF_ADD_TEST_CASE(tcs, database__db_filename);
}
33 changes: 33 additions & 0 deletions utils/sqlite/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,36 @@ extern "C" {
#include <sqlite3.h>
}

#include <cstring>
#include <stdexcept>

#include "utils/format/macros.hpp"
#include "utils/fs/path.hpp"
#include "utils/logging/macros.hpp"
#include "utils/noncopyable.hpp"
#include "utils/optional.ipp"
#include "utils/sanity.hpp"
#include "utils/sqlite/exceptions.hpp"
#include "utils/sqlite/statement.ipp"
#include "utils/sqlite/transaction.hpp"

namespace fs = utils::fs;
namespace sqlite = utils::sqlite;

using utils::none;
using utils::optional;


/// Internal implementation for sqlite::database.
struct utils::sqlite::database::impl : utils::noncopyable {
/// Path to the database as seen by sqlite3_db_filename after construction.
///
/// We need to hold a copy of this value ourselves because we want to be
/// able to identify the database connection even after close() has been
/// called, but sqlite3_db_filename returns NULL after the connection is
/// closed.
optional< fs::path > db_filename;

/// The SQLite 3 internal database.
::sqlite3* db;

Expand All @@ -63,6 +77,11 @@ struct utils::sqlite::database::impl : utils::noncopyable {
db(db_),
owned(owned_)
{
const char* raw_db_filename = ::sqlite3_db_filename(db, "main");
if (raw_db_filename == NULL || std::strlen(raw_db_filename) == 0)
db_filename = none;
else
db_filename = utils::make_optional(fs::path(raw_db_filename));
}

/// Destructor.
Expand Down Expand Up @@ -234,6 +253,20 @@ sqlite::database::close(void)
}


/// Returns the path to the connected database.
///
/// It is OK to call this function on a live database object, even after close()
/// has been called. The returned value is consistent at all times.
///
/// \return The path to the file that matches the connected database or none if
/// the connection points to a transient database.
const optional< fs::path >&
sqlite::database::db_filename(void) const
{
return _pimpl->db_filename;
}


/// Executes an arbitrary SQL string.
///
/// As the documentation explains, this is unsafe. The code should really be
Expand Down
3 changes: 3 additions & 0 deletions utils/sqlite/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern "C" {
#include <cstddef>

#include "utils/fs/path_fwd.hpp"
#include "utils/optional_fwd.hpp"
#include "utils/shared_ptr.hpp"
#include "utils/sqlite/c_gate_fwd.hpp"
#include "utils/sqlite/statement_fwd.hpp"
Expand Down Expand Up @@ -93,6 +94,8 @@ class database {
static database temporary(void);
void close(void);

const utils::optional< utils::fs::path >& db_filename(void) const;

void exec(const std::string&);

transaction begin_transaction(void);
Expand Down
37 changes: 37 additions & 0 deletions utils/sqlite/database_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@

#include "utils/fs/operations.hpp"
#include "utils/fs/path.hpp"
#include "utils/optional.ipp"
#include "utils/sqlite/statement.ipp"
#include "utils/sqlite/test_utils.hpp"
#include "utils/sqlite/transaction.hpp"

namespace fs = utils::fs;
namespace sqlite = utils::sqlite;

using utils::optional;


ATF_TEST_CASE_WITHOUT_HEAD(in_memory);
ATF_TEST_CASE_BODY(in_memory)
Expand Down Expand Up @@ -151,6 +154,36 @@ ATF_TEST_CASE_BODY(copy)
}


ATF_TEST_CASE_WITHOUT_HEAD(db_filename__in_memory);
ATF_TEST_CASE_BODY(db_filename__in_memory)
{
const sqlite::database db = sqlite::database::in_memory();
ATF_REQUIRE(!db.db_filename());
}


ATF_TEST_CASE_WITHOUT_HEAD(db_filename__file);
ATF_TEST_CASE_BODY(db_filename__file)
{
const sqlite::database db = sqlite::database::open(fs::path("test.db"),
sqlite::open_readwrite | sqlite::open_create);
ATF_REQUIRE(db.db_filename());
ATF_REQUIRE_EQ(fs::path("test.db").to_absolute(), db.db_filename().get());
}


ATF_TEST_CASE_WITHOUT_HEAD(db_filename__ok_after_close);
ATF_TEST_CASE_BODY(db_filename__ok_after_close)
{
sqlite::database db = sqlite::database::open(fs::path("test.db"),
sqlite::open_readwrite | sqlite::open_create);
const optional< fs::path > db_filename = db.db_filename();
ATF_REQUIRE(db_filename);
db.close();
ATF_REQUIRE_EQ(db_filename, db.db_filename());
}


ATF_TEST_CASE_WITHOUT_HEAD(exec__ok);
ATF_TEST_CASE_BODY(exec__ok)
{
Expand Down Expand Up @@ -229,6 +262,10 @@ ATF_INIT_TEST_CASES(tcs)

ATF_ADD_TEST_CASE(tcs, copy);

ATF_ADD_TEST_CASE(tcs, db_filename__in_memory);
ATF_ADD_TEST_CASE(tcs, db_filename__file);
ATF_ADD_TEST_CASE(tcs, db_filename__ok_after_close);

ATF_ADD_TEST_CASE(tcs, exec__ok);
ATF_ADD_TEST_CASE(tcs, exec__fail);

Expand Down

0 comments on commit 8003c86

Please sign in to comment.