Botan
1.11.15
|
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 }