examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

commit 5945cb6a21f6ea0a8049b928d72eb5facd43ef3b
parent c9aac4dfc79e1d117ab056a34a2e196f55a3e4f4
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Thu, 16 Feb 2023 20:55:23 +0000

sqlite: Add example demonstrating loading and saving to a SQLite database

Diffstat:
MTupfile | 3++-
Mmakefile | 3++-
Asrc/sqlite-saveload.cpp | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/Tupfile b/Tupfile @@ -4,11 +4,12 @@ CFLAGS = $(COMMON_FLAGS) CXXFLAGS = -std=c++20 $(COMMON_FLAGS) LDLIBS_aio = -lrt +LDLIBS_alsa-simple = -lasound LDLIBS_gl-asteroids = -lglfw -lGL -lm -lasound LDLIBS_io_uring = -luring LDLIBS_pulse-async-client = -lpulse LDLIBS_pulse-simple-client = -lpulse-simple -lm -LDLIBS_alsa-simple = -lasound +LDLIBS_sqlite-saveload = -lsqlite3 : foreach src/*.c |> cc $(CFLAGS) -o %o %f $(LDLIBS_%B) |> bin/%B : foreach src/*.cpp |> c++ $(CXXFLAGS) -o %o %f $(LDLIBS_%B) |> bin/%B diff --git a/makefile b/makefile @@ -20,11 +20,12 @@ clean: $(RM) -r $(c_targets) $(cpp_targets) bin/ bin/aio: -lrt +bin/alsa-simple: -lasound bin/gl-asteroids: -lglfw -lGL -lm -lasound bin/io_uring: -luring bin/pulse-async-client: -lpulse bin/pulse-simple-client: -lpulse-simple -lm -bin/alsa-simple: -lasound +bin/sqlite-saveload: -lsqlite3 bin/: mkdir -p $@ diff --git a/src/sqlite-saveload.cpp b/src/sqlite-saveload.cpp @@ -0,0 +1,119 @@ +#include <unistd.h> +#include <sqlite3.h> + +#include <iostream> +#include <iterator> +#include <memory> +#include <vector> + +auto make_sqlite_stmt(sqlite3_stmt* p) -> std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> +{ + return {p, sqlite3_finalize}; +} + +auto make_sqlite_db(sqlite3* p) -> std::unique_ptr<sqlite3, decltype(&sqlite3_close)> +{ + return {p, sqlite3_close}; +} + +std::vector<int> nums; + +void write_nums(char const* path) +{ + sqlite3 *db; + auto rc = sqlite3_open(path, &db); + auto guard_db = make_sqlite_db(db); + + if (rc) + throw std::runtime_error("Can't open database for write"); + + char* errmsg; + char const query[] = + "PRAGMA synchronous = OFF;" + "PRAGMA journal_mode = OFF;" + "CREATE TABLE nums (n int)"; + + if (sqlite3_exec(db, query, NULL, NULL, &errmsg)) + throw std::runtime_error(errmsg); + + sqlite3_stmt* stmt; + rc = sqlite3_prepare_v2(db, "INSERT INTO nums (n) VALUES (?)", -1, &stmt, NULL); + auto guard = make_sqlite_stmt(stmt); + + if (rc) + throw std::runtime_error("Error preparing statement"); + + if (sqlite3_exec(db, "begin transaction", NULL, NULL, &errmsg)) + throw std::runtime_error(errmsg); + + for (unsigned i = 0; i < nums.size(); ++i) + { + if (sqlite3_bind_int(stmt, 1, nums[i])) + throw std::runtime_error("Failed to bind int"); + + if (sqlite3_step(stmt) != SQLITE_DONE) + throw std::runtime_error("Statement failed to execute"); + + if (sqlite3_reset(stmt)) + throw std::runtime_error("Statement failed to reset"); + } + + if (sqlite3_exec(db, "end transaction", NULL, NULL, &errmsg)) + throw std::runtime_error(errmsg); +} + +void add_nums() +{ + std::copy(std::istream_iterator<int>(std::cin), + std::istream_iterator<int>(), + std::back_inserter(nums)); +} + +void read_nums(char const* path) +{ + sqlite3 *db; + auto rc = sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL); + auto guard_db = make_sqlite_db(db); + + if (rc) + throw std::runtime_error("Can't open database for read"); + + sqlite3_stmt* stmt; + rc = sqlite3_prepare_v2(db, "SELECT n FROM nums", -1, &stmt, NULL); + auto guard = make_sqlite_stmt(stmt); + + if (rc) + throw std::runtime_error("Error preparing statement"); + + while (sqlite3_step(stmt) == SQLITE_ROW) + nums.push_back(sqlite3_column_int(stmt, 0)); + + std::cout << "Read " << nums.size() << " numbers\n"; +} + +int main(int argc, char **argv) +{ + switch (argc) + { + case 3: + read_nums(argv[1]); + add_nums(); + write_nums(argv[2]); + break; + case 2: + if (not access(argv[1], F_OK)) + { + read_nums(argv[1]); + add_nums(); + truncate(argv[1], 0); + } + else + add_nums(); + + write_nums(argv[1]); + break; + default: + std::cerr << "Usage: " << argv[0] << " ( in out ) | inout\n"; + return 1; + } +}