summary refs log tree commit diff stats
path: root/generator/database.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'generator/database.cpp')
-rw-r--r--generator/database.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/generator/database.cpp b/generator/database.cpp new file mode 100644 index 0000000..c7e4cfa --- /dev/null +++ b/generator/database.cpp
@@ -0,0 +1,173 @@
1#include "database.h"
2#include <sqlite3.h>
3#include <cassert>
4#include <fstream>
5#include <stdexcept>
6#include <cstdio>
7#include <sstream>
8#include "field.h"
9#include "../lib/util.h"
10
11namespace verbly {
12 namespace generator {
13
14 sqlite3_error::sqlite3_error(
15 const std::string& what,
16 const std::string& db_err) :
17 what_(what + " (" + db_err + ")"),
18 db_err_(db_err)
19 {
20 }
21
22 const char* sqlite3_error::what() const noexcept
23 {
24 return what_.c_str();
25 }
26
27 const char* sqlite3_error::db_err() const noexcept
28 {
29 return db_err_.c_str();
30 }
31
32 database::database(std::string path)
33 {
34 // If there is already a file at this path, overwrite it.
35 if (std::ifstream(path))
36 {
37 if (std::remove(path.c_str()))
38 {
39 throw std::logic_error("Could not overwrite file at path");
40 }
41 }
42
43 if (sqlite3_open_v2(path.c_str(), &ppdb_, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
44 {
45 // We still have to free the resources allocated. In the event that
46 // allocation failed, ppdb will be null and sqlite3_close_v2 will just
47 // ignore it.
48 std::string errmsg(sqlite3_errmsg(ppdb_));
49 sqlite3_close_v2(ppdb_);
50
51 throw sqlite3_error("Could not create output datafile", errmsg);
52 }
53 }
54
55 database::database(database&& other) : database()
56 {
57 swap(*this, other);
58 }
59
60 database& database::operator=(database&& other)
61 {
62 swap(*this, other);
63
64 return *this;
65 }
66
67 void swap(database& first, database& second)
68 {
69 std::swap(first.ppdb_, second.ppdb_);
70 }
71
72 database::~database()
73 {
74 sqlite3_close_v2(ppdb_);
75 }
76
77 void database::runQuery(std::string query)
78 {
79 // This can only happen when doing bad things with move semantics.
80 assert(ppdb_ != nullptr);
81
82 sqlite3_stmt* ppstmt;
83
84 if (sqlite3_prepare_v2(ppdb_, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
85 {
86 throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_));
87 }
88
89 int result = sqlite3_step(ppstmt);
90 sqlite3_finalize(ppstmt);
91
92 if (result != SQLITE_DONE)
93 {
94 throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_));
95 }
96 }
97
98 void database::insertIntoTable(std::string table, std::list<field> fields)
99 {
100 // This can only happen when doing bad things with move semantics.
101 assert(ppdb_ != nullptr);
102
103 // This shouldn't happen.
104 assert(!fields.empty());
105
106 std::list<std::string> fieldNames;
107 std::list<std::string> qs;
108 for (field& f : fields)
109 {
110 fieldNames.push_back(f.getName());
111 qs.push_back("?");
112 }
113
114 std::ostringstream query;
115 query << "INSERT INTO ";
116 query << table;
117 query << " (";
118 query << implode(std::begin(fieldNames), std::end(fieldNames), ", ");
119 query << ") VALUES (";
120 query << implode(std::begin(qs), std::end(qs), ", ");
121 query << ")";
122
123 std::string query_str = query.str();
124
125 sqlite3_stmt* ppstmt;
126
127 if (sqlite3_prepare_v2(ppdb_, query_str.c_str(), query_str.length(), &ppstmt, NULL) != SQLITE_OK)
128 {
129 throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_));
130 }
131
132 int i = 1;
133 for (field& f : fields)
134 {
135 switch (f.getType())
136 {
137 case field::type::integer:
138 {
139 sqlite3_bind_int(ppstmt, i, f.getInteger());
140
141 break;
142 }
143
144 case field::type::string:
145 {
146 sqlite3_bind_text(ppstmt, i, f.getString().c_str(), f.getString().length(), SQLITE_TRANSIENT);
147
148 break;
149 }
150
151 case field::type::invalid:
152 {
153 // Fields can only be invalid when doing bad things with move semantics.
154 assert(false);
155
156 break;
157 }
158 }
159
160 i++;
161 }
162
163 int result = sqlite3_step(ppstmt);
164 sqlite3_finalize(ppstmt);
165
166 if (result != SQLITE_DONE)
167 {
168 throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_));
169 }
170 }
171
172 };
173};