sqlite-saveload.cpp (2643B)
1 #include <unistd.h> 2 #include <sqlite3.h> 3 4 #include <iostream> 5 #include <iterator> 6 #include <memory> 7 #include <vector> 8 9 auto make_sqlite_stmt(sqlite3_stmt* p) -> std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> 10 { 11 return {p, sqlite3_finalize}; 12 } 13 14 auto make_sqlite_db(sqlite3* p) -> std::unique_ptr<sqlite3, decltype(&sqlite3_close)> 15 { 16 return {p, sqlite3_close}; 17 } 18 19 std::vector<int> nums; 20 21 void write_nums(char const* path) 22 { 23 sqlite3 *db; 24 auto rc = sqlite3_open(path, &db); 25 auto guard_db = make_sqlite_db(db); 26 27 if (rc) 28 throw std::runtime_error("Can't open database for write"); 29 30 char* errmsg; 31 char const query[] = 32 "PRAGMA synchronous = OFF;" 33 "PRAGMA journal_mode = OFF;" 34 "CREATE TABLE nums (n int)"; 35 36 if (sqlite3_exec(db, query, NULL, NULL, &errmsg)) 37 throw std::runtime_error(errmsg); 38 39 sqlite3_stmt* stmt; 40 rc = sqlite3_prepare_v2(db, "INSERT INTO nums (n) VALUES (?)", -1, &stmt, NULL); 41 auto guard = make_sqlite_stmt(stmt); 42 43 if (rc) 44 throw std::runtime_error("Error preparing statement"); 45 46 if (sqlite3_exec(db, "begin transaction", NULL, NULL, &errmsg)) 47 throw std::runtime_error(errmsg); 48 49 for (unsigned i = 0; i < nums.size(); ++i) 50 { 51 if (sqlite3_bind_int(stmt, 1, nums[i])) 52 throw std::runtime_error("Failed to bind int"); 53 54 if (sqlite3_step(stmt) != SQLITE_DONE) 55 throw std::runtime_error("Statement failed to execute"); 56 57 if (sqlite3_reset(stmt)) 58 throw std::runtime_error("Statement failed to reset"); 59 } 60 61 if (sqlite3_exec(db, "end transaction", NULL, NULL, &errmsg)) 62 throw std::runtime_error(errmsg); 63 } 64 65 void add_nums() 66 { 67 std::copy(std::istream_iterator<int>(std::cin), 68 std::istream_iterator<int>(), 69 std::back_inserter(nums)); 70 } 71 72 void read_nums(char const* path) 73 { 74 sqlite3 *db; 75 auto rc = sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL); 76 auto guard_db = make_sqlite_db(db); 77 78 if (rc) 79 throw std::runtime_error("Can't open database for read"); 80 81 sqlite3_stmt* stmt; 82 rc = sqlite3_prepare_v2(db, "SELECT n FROM nums", -1, &stmt, NULL); 83 auto guard = make_sqlite_stmt(stmt); 84 85 if (rc) 86 throw std::runtime_error("Error preparing statement"); 87 88 while (sqlite3_step(stmt) == SQLITE_ROW) 89 nums.push_back(sqlite3_column_int(stmt, 0)); 90 91 std::cout << "Read " << nums.size() << " numbers\n"; 92 } 93 94 int main(int argc, char **argv) 95 { 96 switch (argc) 97 { 98 case 3: 99 read_nums(argv[1]); 100 add_nums(); 101 write_nums(argv[2]); 102 break; 103 case 2: 104 if (not access(argv[1], F_OK)) 105 { 106 read_nums(argv[1]); 107 add_nums(); 108 truncate(argv[1], 0); 109 } 110 else 111 add_nums(); 112 113 write_nums(argv[1]); 114 break; 115 default: 116 std::cerr << "Usage: " << argv[0] << " ( in out ) | inout\n"; 117 return 1; 118 } 119 }