forked from qicosmos/SmartDB1.03
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSmartDB.hpp
364 lines (304 loc) · 7.96 KB
/
SmartDB.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#pragma once
/*
*文件名称:SweetDB.hpp
*文件标识:
*摘要:数据库操作类,提供简洁统一的操作接口
*当前版本:1.0.0
*作者:祁宇
*完成日期:2013年8月1日
*/
#include <sqlite3.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <cctype>
#include <functional>
#include <unordered_map>
#include <memory>
#include <type_traits>
using namespace std;
#include "Define.h"
#include "detail\BindParams.hpp"
#include "detail\Json.hpp"
#include "detail\Tuple.hpp"
#include <NonCopyable.hpp>
class SmartDB : NonCopyable
{
public:
SmartDB() : m_jsonHelper(m_buf, m_code){}
/**
* 连接数据库
* 如果数据库不存在,数据库将被创建并打开, 如果创建失败则设置失败标志
* @param[in] fileName:数据库文件的位置。
*/
explicit SmartDB(const string& fileName) : m_dbHandle(nullptr), m_statement(nullptr), m_isConned(false), m_code(0), m_jsonHelper(m_buf, m_code)
{
Open(fileName);
}
/**
* 释放资源,关闭数据库
*/
~SmartDB()
{
Close();
}
/**
* 打开数据库
*/
void Open(const string& fileName)
{
m_code = sqlite3_open(fileName.data(), &m_dbHandle);
if (SQLITE_OK == m_code)
{
m_isConned = true;
}
}
/**
* 释放资源,关闭数据库
*/
bool Close()
{
if (m_dbHandle == nullptr)
return true;
sqlite3_finalize(m_statement);
m_code = CloseDBHandle();
bool ret = (SQLITE_OK == m_code);
m_statement = nullptr;
m_dbHandle = nullptr;
return ret;
}
/**
* 是否已连接数据库
*/
bool IsConned() const
{
return m_isConned;
}
/**
* 不带占位符。执行sql,不带返回结果, 如insert,update,delete等
* @param[in] query: sql语句, 不带占位符
* @return bool, 成功返回true,否则返回false
*/
bool Excecute(const string& sqlStr)
{
m_code = sqlite3_exec(m_dbHandle, sqlStr.data(), nullptr, nullptr, nullptr);
return SQLITE_OK == m_code;
}
/**
* 带占位符。执行sql,不带返回结果, 如insert,update,delete等
* @param[in] query: sql语句, 可能带占位符"?"
* @param[in] args: 参数列表,用来填充占位符
* @return bool, 成功返回true,否则返回false
*/
template <typename... Args>
bool Excecute(const string& sqlStr, Args && ... args)
{
if (!Prepare(sqlStr))
{
return false;
}
return ExcecuteArgs(std::forward<Args>(args)...);
}
/**
* 批量操作之前准备sql接口,必须和ExcecuteBulk一起调用,准备批量操作的sql,可能带占位符
* @param[in] query: sql语句, 带占位符"?"
* @return bool, 成功返回true,否则返回false
*/
bool Prepare(const string& sqlStr)
{
m_code = sqlite3_prepare_v2(m_dbHandle, sqlStr.data(), -1, &m_statement, nullptr);
if (m_code != SQLITE_OK)
{
return false;
}
return true;
}
/**
* 批量操作接口,必须先调用Prepare接口
* @param[in] args: 参数列表
* @return bool, 成功返回true,否则返回false
*/
template <typename... Args>
bool ExcecuteArgs(Args && ... args)
{
if (SQLITE_OK != detail::BindParams(m_statement, 1, std::forward<Args>(args)...))
{
return false;
}
m_code = sqlite3_step(m_statement);
sqlite3_reset(m_statement);
return m_code == SQLITE_DONE;
}
template<typename Tuple>
bool ExcecuteTuple(const string& sqlStr, Tuple&& t)
{
if (!Prepare(sqlStr))
{
return false;
}
m_code = detail::ExcecuteTuple(m_statement, detail::MakeIndexes<std::tuple_size<Tuple>::value>::type(), std::forward<Tuple>(t));
return m_code == SQLITE_DONE;
}
bool ExcecuteJson(const string& sqlStr, const char* json)
{
rapidjson::Document doc;
doc.Parse<0>(json);
if (doc.HasParseError())
{
cout << doc.GetParseError() << endl;
return false;
}
if (!Prepare(sqlStr))
{
return false;
}
return JsonTransaction(doc);
}
/**
* 执行sql,返回函数执行的一个值, 执行简单的汇聚函数,如select count(*), select max(*)等
* 返回结果可能有多种类型,返回Value类型,在外面通过get函数去取
* @param[in] query: sql语句, 可能带占位符"?"
* @param[in] args: 参数列表,用来填充占位符
* @return int: 返回结果值,失败则返回-1
*/
template < typename R = sqlite_int64, typename... Args>
R ExecuteScalar(const string& sqlStr, Args&&... args)
{
if (!Prepare(sqlStr))
return GetErrorVal<R>();
if (SQLITE_OK != detail::BindParams(m_statement, 1, std::forward<Args>(args)...))
{
return GetErrorVal<R>();
}
m_code = sqlite3_step(m_statement);
if (m_code != SQLITE_ROW)
return GetErrorVal<R>();
SqliteValue val = GetValue(m_statement, 0);
R result = val.Get<R>();// get<R>(val);
sqlite3_reset(m_statement);
return result;
}
template <typename... Args>
std::shared_ptr<rapidjson::Document> Query(const string& query, Args&&... args)
{
if (!PrepareStatement(query, std::forward<Args>(args)...))
nullptr;
auto doc = std::make_shared<rapidjson::Document>();
m_buf.Clear();
m_jsonHelper.BuildJsonObject(m_statement);
doc->Parse<0>(m_buf.GetString());
return doc;
}
bool Begin()
{
return Excecute(BEGIN);
}
bool RollBack()
{
return Excecute(ROLLBACK);
}
bool Commit()
{
return Excecute(COMMIT);
}
int GetLastErrorCode()
{
return m_code;
}
private:
int CloseDBHandle()
{
int code = sqlite3_close(m_dbHandle);
while (code == SQLITE_BUSY)
{
// set rc to something that will exit the while loop
code = SQLITE_OK;
sqlite3_stmt * stmt = sqlite3_next_stmt(m_dbHandle, NULL);
if (stmt == nullptr)
break;
code = sqlite3_finalize(stmt);
if (code == SQLITE_OK)
{
code = sqlite3_close(m_dbHandle);
}
}
return code;
}
template <typename... Args>
bool PrepareStatement(const string& sqlStr, Args&&... args)
{
if (!Prepare(sqlStr))
{
return false;
}
if (SQLITE_OK != detail::BindParams(m_statement, 1, std::forward<Args>(args)...))
{
return false;
}
return true;
}
//通过json串写到数据库中
bool JsonTransaction(const rapidjson::Document& doc)
{
Begin();
for (size_t i = 0, size = doc.Size(); i < size; i++)
{
if (!m_jsonHelper.ExcecuteJson(m_statement, doc[i]))
{
RollBack();
break;
}
}
if (m_code != SQLITE_DONE)
return false;
Commit();
return true;
}
private:
/** 取列的值 **/
SqliteValue GetValue(sqlite3_stmt *stmt, const int& index)
{
int type = sqlite3_column_type(stmt, index);
auto it = m_valmap.find(type);
if (it == m_valmap.end())
throw std::invalid_argument("can not find this type");
return it->second(stmt, index);
}
template<typename T>
typename std::enable_if <std::is_arithmetic<T>::value, T>::type
GetErrorVal()
{
return T(-9999);
}
template<typename T>
typename std::enable_if <!std::is_arithmetic<T>::value&&!std::is_same<T, blob>::value, T>::type
GetErrorVal()
{
return "";
}
template<typename T>
typename std::enable_if <std::is_same<T, blob>::value, T>::type
GetErrorVal()
{
return {nullptr, 0};
}
private:
sqlite3* m_dbHandle;
sqlite3_stmt* m_statement;
bool m_isConned;
int m_code;//记录最近一次的错误码
//JsonBuilder m_jsonBuilder; //写json串
detail::JsonHelper m_jsonHelper;
rapidjson::StringBuffer m_buf; //json字符串的buf
static std::unordered_map<int, std::function <SqliteValue(sqlite3_stmt*, int)>> m_valmap;
};
std::unordered_map<int, std::function <SqliteValue(sqlite3_stmt*, int)>> SmartDB::m_valmap =
{
{ std::make_pair(SQLITE_INTEGER, [](sqlite3_stmt *stmt, int index){return sqlite3_column_int64(stmt, index); }) },
{ std::make_pair(SQLITE_FLOAT, [](sqlite3_stmt *stmt, int index){return sqlite3_column_double(stmt, index); }) },
{ std::make_pair(SQLITE_BLOB, [](sqlite3_stmt *stmt, int index){return string((const char*) sqlite3_column_blob(stmt, index));/* SmartDB::GetBlobVal(stmt, index);*/ }) },
{ std::make_pair(SQLITE_TEXT, [](sqlite3_stmt *stmt, int index){return string((const char*) sqlite3_column_text(stmt, index)); }) },
{ std::make_pair(SQLITE_NULL, [](sqlite3_stmt *stmt, int index){return nullptr; }) }
};