Skip to content

Instantly share code, notes, and snippets.

@mitaki28
Created October 13, 2015 10:59
Show Gist options
  • Save mitaki28/9e86923ee7f4348a7f12 to your computer and use it in GitHub Desktop.
Save mitaki28/9e86923ee7f4348a7f12 to your computer and use it in GitHub Desktop.
Simple wrapper for SQLite3
/*
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