Created
October 13, 2015 10:59
-
-
Save mitaki28/9e86923ee7f4348a7f12 to your computer and use it in GitHub Desktop.
Simple wrapper for SQLite3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Simple wrapper for SQLite3 | |
This code is Public Domain | |
**CAUTION** | |
1. No Warrantry | |
2. This code is *NOT* safe against SQL Injection. | |
3. This code can *NOT* handle BLOB or TEXT including '\0'. | |
4. You should *NOT* use this for production. | |
*/ | |
#include <cassert> | |
#include <iostream> | |
#include <vector> | |
#include <string> | |
#include <map> | |
#include <memory> | |
#include <stdexcept> | |
#include "sqlite3.h" | |
struct SQLite3 { | |
typedef std::shared_ptr<std::string> Value; | |
typedef std::vector<std::pair<std::string, Value>> Row; | |
sqlite3 *db; | |
SQLite3(const std::string &dbName); | |
~SQLite3(); | |
std::vector<Row> exec(const std::string &sql); | |
}; | |
SQLite3::SQLite3(const std::string &dbName) : db(nullptr) { | |
int err = sqlite3_open(dbName.c_str(), &db); | |
if (err != SQLITE_OK) { | |
std::string errstr = sqlite3_errmsg(db); | |
sqlite3_close_v2(db); | |
db = nullptr; | |
throw std::runtime_error(errstr); | |
} | |
} | |
SQLite3::~SQLite3() { | |
sqlite3_close_v2(db); | |
db = nullptr; | |
} | |
std::vector<SQLite3::Row> SQLite3::exec(const std::string &sql) { | |
char *errmsg = nullptr; | |
auto callback = [](void *result_, int argc, | |
char **argv, char **colNames) { | |
std::vector<Row> *ret = reinterpret_cast<std::vector<Row> *>(result_); | |
ret->push_back(Row()); | |
for (int i = 0; i < argc; i++) { | |
if (argv[i] != nullptr) { | |
ret->back() | |
.push_back(std::make_pair(colNames[i], | |
Value(new std::string(argv[i])))); | |
} else { | |
ret->back() | |
.push_back(std::make_pair(colNames[i], Value(nullptr))); | |
} | |
} | |
return SQLITE_OK; | |
}; | |
std::vector<Row> ret; | |
int err = sqlite3_exec(db, sql.c_str(), callback, &ret, &errmsg); | |
if (err != SQLITE_OK) { | |
std::string errstr = errmsg; | |
sqlite3_free(errmsg); | |
errmsg = nullptr; | |
throw std::runtime_error(errstr); | |
} | |
return ret; | |
} | |
int main() { | |
std::cout << "=== Testing ===" << std::endl; | |
SQLite3 db(":memory:"); | |
std::vector<SQLite3::Row> ret; | |
db.exec("CREATE TABLE test ( " | |
"id INTEGER PRIMARY KEY AUTOINCREMENT," | |
"name TEXT, " | |
"price INTEGER, " | |
"weight REAL, " | |
"createdAt DATE DEFAULT CURRENT_TIMESTAMP);"); | |
db.exec("INSERT INTO test (name, price, weight) VALUES " | |
"('apple', 100, 310.5);"); | |
db.exec("INSERT INTO test (name, price, weight) VALUES " | |
"('banana', 200, 135.8);"); | |
db.exec("INSERT INTO test (name, price, weight) VALUES " | |
"('orange', 130, 222.2);"); | |
ret = db.exec("SELECT * FROM test " | |
"WHERE 100 <= price AND price <= 150 " | |
"ORDER BY id DESC"); | |
std::cout << "===" << std::endl; | |
for (const auto &row : ret) { | |
// use as map | |
std::map<std::string, SQLite3::Value> rowMap(row.begin(), row.end()); | |
std::cout << "[" << *rowMap["name"] << "]" << std::endl; | |
// iteration | |
for (const auto &col : row) { | |
std::cout << col.first << ':' << *col.second << std::endl; | |
} | |
std::cout << "===" << std::endl; | |
} | |
// note: colunm name may be duplicate | |
ret = db.exec("SELECT * FROM test test1 CROSS JOIN test test2 " | |
"WHERE 100 <= test1.price AND test1.price <= 150 " | |
"ORDER BY test1.id DESC"); | |
for (const auto &row : ret) { | |
for (const auto &col : row) { | |
std::cout << col.first << ':' << *col.second << std::endl; | |
} | |
std::cout << "===" << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment