Botan  1.11.15
src/lib/vendor/sqlite3/sqlite3.cpp
Go to the documentation of this file.
00001 /*
00002 * SQLite wrapper
00003 * (C) 2012 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/sqlite3.h>
00009 #include <stdexcept>
00010 #include <sqlite3.h>
00011 
00012 namespace Botan {
00013 
00014 Sqlite3_Database::Sqlite3_Database(const std::string& db_filename)
00015    {
00016    int rc = ::sqlite3_open(db_filename.c_str(), &m_db);
00017 
00018    if(rc)
00019       {
00020       const std::string err_msg = ::sqlite3_errmsg(m_db);
00021       ::sqlite3_close(m_db);
00022       m_db = nullptr;
00023       throw std::runtime_error("sqlite3_open failed - " + err_msg);
00024       }
00025    }
00026 
00027 Sqlite3_Database::~Sqlite3_Database()
00028    {
00029    if(m_db)
00030       ::sqlite3_close(m_db);
00031    m_db = nullptr;
00032    }
00033 
00034 std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::new_statement(const std::string& base_sql) const
00035    {
00036    return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
00037    }
00038 
00039 size_t Sqlite3_Database::row_count(const std::string& table_name)
00040    {
00041    auto stmt = new_statement("select count(*) from " + table_name);
00042 
00043    if(stmt->step())
00044       return stmt->get_size_t(0);
00045    else
00046       throw std::runtime_error("Querying size of table " + table_name + " failed");
00047    }
00048 
00049 void Sqlite3_Database::create_table(const std::string& table_schema)
00050    {
00051    char* errmsg = nullptr;
00052    int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg);
00053 
00054    if(rc != SQLITE_OK)
00055       {
00056       const std::string err_msg = errmsg;
00057       ::sqlite3_free(errmsg);
00058       ::sqlite3_close(m_db);
00059       m_db = nullptr;
00060       throw std::runtime_error("sqlite3_exec for table failed - " + err_msg);
00061       }
00062    }
00063 
00064 Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(sqlite3* db, const std::string& base_sql)
00065    {
00066    int rc = ::sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, nullptr);
00067 
00068    if(rc != SQLITE_OK)
00069       throw std::runtime_error("sqlite3_prepare failed " + base_sql +
00070                                ", code " + std::to_string(rc));
00071    }
00072 
00073 void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::string& val)
00074    {
00075    int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT);
00076    if(rc != SQLITE_OK)
00077       throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
00078    }
00079 
00080 void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val)
00081    {
00082    if(val != static_cast<size_t>(static_cast<int>(val))) // is this legit?
00083       throw std::runtime_error("sqlite3 cannot store " + std::to_string(val) + " without truncation");
00084    int rc = ::sqlite3_bind_int(m_stmt, column, val);
00085    if(rc != SQLITE_OK)
00086       throw std::runtime_error("sqlite3_bind_int failed, code " + std::to_string(rc));
00087    }
00088 
00089 void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time)
00090    {
00091    const int timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
00092    bind(column, timeval);
00093    }
00094 
00095 void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<byte>& val)
00096    {
00097    int rc = ::sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT);
00098    if(rc != SQLITE_OK)
00099       throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
00100    }
00101 
00102 std::pair<const byte*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column)
00103    {
00104    BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB,
00105                 "Return value is a blob");
00106 
00107    const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
00108    const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
00109 
00110    BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
00111 
00112    return std::make_pair(static_cast<const byte*>(session_blob),
00113                          static_cast<size_t>(session_blob_size));
00114    }
00115 
00116 size_t Sqlite3_Database::Sqlite3_Statement::get_size_t(int column)
00117    {
00118    BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER,
00119                 "Return count is an integer");
00120 
00121    const int sessions_int = ::sqlite3_column_int(m_stmt, column);
00122 
00123    BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative");
00124 
00125    return static_cast<size_t>(sessions_int);
00126    }
00127 
00128 void Sqlite3_Database::Sqlite3_Statement::spin()
00129    {
00130    while(step()) {}
00131    }
00132 
00133 bool Sqlite3_Database::Sqlite3_Statement::step()
00134    {
00135    return (::sqlite3_step(m_stmt) == SQLITE_ROW);
00136    }
00137 
00138 Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement()
00139    {
00140    ::sqlite3_finalize(m_stmt);
00141    }
00142 
00143 }