Path: blob/main/contrib/kyua/utils/sqlite/database.cpp
48178 views
// Copyright 2011 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include "utils/sqlite/database.hpp"2930extern "C" {31#include <sqlite3.h>32}3334#include <cstring>35#include <stdexcept>3637#include "utils/format/macros.hpp"38#include "utils/fs/path.hpp"39#include "utils/logging/macros.hpp"40#include "utils/noncopyable.hpp"41#include "utils/optional.ipp"42#include "utils/sanity.hpp"43#include "utils/sqlite/exceptions.hpp"44#include "utils/sqlite/statement.ipp"45#include "utils/sqlite/transaction.hpp"4647namespace fs = utils::fs;48namespace sqlite = utils::sqlite;4950using utils::none;51using utils::optional;525354/// Internal implementation for sqlite::database.55struct utils::sqlite::database::impl : utils::noncopyable {56/// Path to the database as seen at construction time.57optional< fs::path > db_filename;5859/// The SQLite 3 internal database.60::sqlite3* db;6162/// Whether we own the database or not (to decide if we close it).63bool owned;6465/// Constructor.66///67/// \param db_filename_ The path to the database as seen at construction68/// time, if any, or none for in-memory databases. We should use69/// sqlite3_db_filename instead, but this function appeared in 3.7.1070/// and Ubuntu 12.04 LTS (which we support for Travis CI builds as of71/// 2015-07-07) ships with 3.7.9.72/// \param db_ The SQLite internal database.73/// \param owned_ Whether this object owns the db_ object or not. If it74/// does, the internal db_ will be released during destruction.75impl(optional< fs::path > db_filename_, ::sqlite3* db_, const bool owned_) :76db_filename(db_filename_), db(db_), owned(owned_)77{78}7980/// Destructor.81///82/// It is important to keep this as part of the 'impl' class instead of the83/// container class. The 'impl' class is destroyed exactly once (because it84/// is managed by a shared_ptr) and thus releasing the resources here is85/// OK. However, the container class is potentially released many times,86/// which means that we would be double-freeing the internal object and87/// reusing invalid data.88~impl(void)89{90if (owned && db != NULL)91close();92}9394/// Exception-safe version of sqlite3_open_v2.95///96/// \param file The path to the database file to be opened.97/// \param flags The flags to be passed to the open routine.98///99/// \return The opened database.100///101/// \throw std::bad_alloc If there is not enough memory to open the102/// database.103/// \throw api_error If there is any problem opening the database.104static ::sqlite3*105safe_open(const char* file, const int flags)106{107::sqlite3* db;108const int error = ::sqlite3_open_v2(file, &db, flags, NULL);109if (error != SQLITE_OK) {110if (db == NULL)111throw std::bad_alloc();112else {113sqlite::database error_db(utils::make_optional(fs::path(file)),114db, true);115throw sqlite::api_error::from_database(error_db,116"sqlite3_open_v2");117}118}119INV(db != NULL);120return db;121}122123/// Shared code for the public close() method.124void125close(void)126{127PRE(db != NULL);128int error = ::sqlite3_close(db);129// For now, let's consider a return of SQLITE_BUSY an error. We should130// not be trying to close a busy database in our code. Maybe revisit131// this later to raise busy errors as exceptions.132PRE(error == SQLITE_OK);133db = NULL;134}135};136137138/// Initializes the SQLite database.139///140/// You must share the same database object alongside the lifetime of your141/// SQLite session. As soon as the object is destroyed, the session is142/// terminated.143///144/// \param db_filename_ The path to the database as seen at construction145/// time, if any, or none for in-memory databases.146/// \param db_ Raw pointer to the C SQLite 3 object.147/// \param owned_ Whether this instance will own the pointer or not.148sqlite::database::database(149const utils::optional< utils::fs::path >& db_filename_, void* db_,150const bool owned_) :151_pimpl(new impl(db_filename_, static_cast< ::sqlite3* >(db_), owned_))152{153}154155156/// Destructor for the SQLite 3 database.157///158/// Closes the session unless it has already been closed by calling the159/// close() method. It is recommended to explicitly close the session in the160/// code.161sqlite::database::~database(void)162{163}164165166/// Opens a memory-based temporary SQLite database.167///168/// \return An in-memory database instance.169///170/// \throw std::bad_alloc If there is not enough memory to open the database.171/// \throw api_error If there is any problem opening the database.172sqlite::database173sqlite::database::in_memory(void)174{175return database(none, impl::safe_open(":memory:", SQLITE_OPEN_READWRITE),176true);177}178179180/// Opens a named on-disk SQLite database.181///182/// \param file The path to the database file to be opened. This does not183/// accept the values "" and ":memory:"; use temporary() and in_memory()184/// instead.185/// \param open_flags The flags to be passed to the open routine.186///187/// \return A file-backed database instance.188///189/// \throw std::bad_alloc If there is not enough memory to open the database.190/// \throw api_error If there is any problem opening the database.191sqlite::database192sqlite::database::open(const fs::path& file, int open_flags)193{194PRE_MSG(!file.str().empty(), "Use database::temporary() instead");195PRE_MSG(file.str() != ":memory:", "Use database::in_memory() instead");196197int flags = 0;198if (open_flags & open_readonly) {199flags |= SQLITE_OPEN_READONLY;200open_flags &= ~open_readonly;201}202if (open_flags & open_readwrite) {203flags |= SQLITE_OPEN_READWRITE;204open_flags &= ~open_readwrite;205}206if (open_flags & open_create) {207flags |= SQLITE_OPEN_CREATE;208open_flags &= ~open_create;209}210PRE(open_flags == 0);211212return database(utils::make_optional(file),213impl::safe_open(file.c_str(), flags), true);214}215216217/// Opens an unnamed on-disk SQLite database.218///219/// \return A file-backed database instance.220///221/// \throw std::bad_alloc If there is not enough memory to open the database.222/// \throw api_error If there is any problem opening the database.223sqlite::database224sqlite::database::temporary(void)225{226return database(none, impl::safe_open("", SQLITE_OPEN_READWRITE), true);227}228229230/// Gets the internal sqlite3 object.231///232/// \return The raw SQLite 3 database. This is returned as a void pointer to233/// prevent including the sqlite3.h header file from our public interface. The234/// only way to call this method is by using the c_gate module, and c_gate takes235/// care of casting this object to the appropriate type.236void*237sqlite::database::raw_database(void)238{239return _pimpl->db;240}241242243/// Terminates the connection to the database.244///245/// It is recommended to call this instead of relying on the destructor to do246/// the cleanup, but it is not a requirement to use close().247///248/// \pre close() has not yet been called.249void250sqlite::database::close(void)251{252_pimpl->close();253}254255256/// Returns the path to the connected database.257///258/// It is OK to call this function on a live database object, even after close()259/// has been called. The returned value is consistent at all times.260///261/// \return The path to the file that matches the connected database or none if262/// the connection points to a transient database.263const optional< fs::path >&264sqlite::database::db_filename(void) const265{266return _pimpl->db_filename;267}268269270/// Executes an arbitrary SQL string.271///272/// As the documentation explains, this is unsafe. The code should really be273/// preparing statements and executing them step by step. However, it is274/// perfectly fine to use this function for, e.g. the initial creation of275/// tables in a database and in tests.276///277/// \param sql The SQL commands to be executed.278///279/// \throw api_error If there is any problem while processing the SQL.280void281sqlite::database::exec(const std::string& sql)282{283const int error = ::sqlite3_exec(_pimpl->db, sql.c_str(), NULL, NULL, NULL);284if (error != SQLITE_OK)285throw api_error::from_database(*this, "sqlite3_exec");286}287288289/// Opens a new transaction.290///291/// \return An object representing the state of the transaction.292///293/// \throw api_error If there is any problem while opening the transaction.294sqlite::transaction295sqlite::database::begin_transaction(void)296{297exec("BEGIN TRANSACTION");298return transaction(*this);299}300301302/// Prepares a new statement.303///304/// \param sql The SQL statement to prepare.305///306/// \return The prepared statement.307sqlite::statement308sqlite::database::create_statement(const std::string& sql)309{310LD(F("Creating statement: %s") % sql);311sqlite3_stmt* stmt;312const int error = ::sqlite3_prepare_v2(_pimpl->db, sql.c_str(),313sql.length() + 1, &stmt, NULL);314if (error != SQLITE_OK)315throw api_error::from_database(*this, "sqlite3_prepare_v2");316return statement(*this, static_cast< void* >(stmt));317}318319320/// Returns the row identifier of the last insert.321///322/// \return A row identifier.323int64_t324sqlite::database::last_insert_rowid(void)325{326return ::sqlite3_last_insert_rowid(_pimpl->db);327}328329330