DCL 3.7.6
Loading...
Searching...
No Matches
SqConnection.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <stdlib.h> // strtol
4#include <string.h> // strlen, strncpy
5
6#if defined(__ANDROID__) && defined(SQLITE_HAS_CODEC)
7#include <sqlcipher.h>
8#else
9#include <sqlite3.h>
10#endif
11
12#include <dcl/Object.h>
13#if __DCL_HAVE_ALLOC_DEBUG
14#undef __DCL_ALLOC_LEVEL
15#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
16#endif
17
18#include <dcl/size_t.h>
19#include <dcl/Numeric.h>
20#include <dcl/Regex.h>
21#include <dcl/SQLCore.h>
22
23#include "SqConnection.h"
24#include "SqQuery.h"
25
26#define __TRACE_THIS 0
27#if __TRACE_THIS
28#define __DCL_TRACE0_N __DCL_TRACE0
29#define __DCL_TRACE1_N __DCL_TRACE1
30#define __DCL_TRACE2_N __DCL_TRACE2
31#define __DCL_TRACE3_N __DCL_TRACE3
32#define __DCL_TRACE4_N __DCL_TRACE4
33#else
34#define __DCL_TRACE0_N(fmt)
35#define __DCL_TRACE1_N(fmt, arg)
36#define __DCL_TRACE2_N(fmt, arg1, arg2)
37#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
38#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
39#endif
40
41#undef __THIS_FILE__
42static const char_t __THIS_FILE__[] = __T("dcl/sql/SqConnection.cpp");
43
44__DCL_BEGIN_NAMESPACE
45
46#define __SET_ERROR(_error) \
47 setErrorStatus(_error, __THIS_FILE__, __LINE__)
48#define __SET_ERROR_MSG(_message) \
49 setErrorMessage(_message, __THIS_FILE__, __LINE__)
50
52
53SqConnection::SqConnection(const wchar_t* pszServerTitle)
54 : Connection(pszServerTitle)
55{
56 Connection::__canTransact = true;
57 __conn = NULL;
58}
59
61{
62 if (__conn) {
63 __DCL_TRACE0_N(L"Warning!! The connection was not closed\n");
64 close();
65 }
66}
67
69{
70 delete this;
71}
72
73bool SqConnection::__open(const char* _conns, size_t _connslen)
74{
75 ByteString conns(_conns, _connslen);
76 ListedByteStringToByteStringMap map;
77 Connection::splitConnStr(_conns, _connslen, map);
78
79 ByteString _DATABASE = map["DATABASE"];
80 ByteString _URI = map["URI"];
81#ifdef SQLITE_HAS_CODEC
82 ByteString _KEY = map["KEY"];
83 ByteString _REKEY = map["REKEY"];
84
85 const char* pKey = NULL;
86 int nKey = 0;
87 if (_KEY.length() > 0) {
88 pKey = _KEY.data();
89 nKey = _KEY.length();
90 }
91
92 bool hasReKey = conns.searches("REKEY", true);
93 const char* pReKey = NULL;
94 int nReKey = 0;
95 if (_REKEY.length() > 0) {
96 pReKey = _REKEY.data();
97 nReKey = _REKEY.length();
98 }
99#endif
100
101 int flags = SQLITE_OPEN_MEMORY;
102 const char* zVfs = NULL;
103 if (!(_DATABASE.isEmpty())) {
104 _URI = _DATABASE;
105 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
106 }
107 else if (!(_URI.isEmpty())) {
108 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
109 }
110 else if (!conns.isEmpty()) {
111 _URI = conns;
112 if (!_URI.isEmpty()) {
113 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
114 }
115 }
116 else {
117 flags = SQLITE_OPEN_MEMORY;
118 _URI.assign(":memory:");
119 }
120
121 if (_URI.toLowerCase().startsWith("file:")) {
122 flags |= SQLITE_OPEN_URI;
123 }
124
125#ifdef __WINNT__
126 zVfs = "win32-none";
127#else
128 zVfs = "unix-none";
129#endif
130
131 sqlite3* conn = NULL;
132 int rc = sqlite3_open_v2(_URI, &conn, flags, zVfs);
133 if (rc != SQLITE_OK) {
134 __SET_ERROR_MSG(sqlite3_errstr(rc));
135 return false;
136 }
137
138 for ( ; ; ) {
139#ifdef SQLITE_HAS_CODEC
140 rc = sqlite3_key(conn, pKey, nKey);
141 if (rc != SQLITE_OK) {
142 __SET_ERROR_MSG(sqlite3_errmsg(conn));
143 break;
144 }
145 __DCL_TRACE2_N(L"sqlite3_key [%hs][%d]\n",
146 (pKey ? pKey : "(nil)"), nKey);
147 if (hasReKey) {
148 rc = sqlite3_rekey(conn, pReKey, nReKey);
149 if (rc != SQLITE_OK) {
150 __SET_ERROR_MSG(sqlite3_errmsg(conn));
151 break;
152 }
153 }
154#endif
155 __conn = conn;
156 return true;
157 }
158
159 if (conn) {
160 sqlite3_close_v2(conn);
161 }
162 return false;
163}
164
166{
167 if (!__conn) {
169 return false;
170 }
171
172 int rc = sqlite3_close_v2(__conn);
173 __conn = NULL;
174 if (rc != SQLITE_OK) {
175 __SET_ERROR_MSG(sqlite3_errstr(rc));
176 return false;
177 }
178 return true;
179}
180
186
187typedef struct {
188 StmtType type;
189 const char* pattern;
191
192static STMT_PATTERN sp[] = {
193 { StmtTransBegin, "BEGIN" },
194 { StmtTransEnd, "COMMIT|ROLLBACK|END" },
195 { StmtOther, NULL }
196};
197
198static StmtType __GetStmtType(const char* _sql)
199{
200 for(size_t i = 0; sp[i].type != StmtOther; i++) {
201 try {
202 if (Regex::test(sp[i].pattern, _sql, true))
203 return sp[i].type;
204 }
205 catch(Exception* _e) {
206 _e->destroy();
207 }
208 }
209 return StmtOther;
210}
211
212bool SqConnection::__execute(const char* _sql, size_t _sqllen)
213{
214 char* errmsg = NULL;
215 int rc = sqlite3_exec(__conn, _sql, NULL, NULL, &errmsg);
216 if (rc != SQLITE_OK) {
217 __SET_ERROR_MSG(errmsg);
218 return false;
219 }
220
221 switch(__GetStmtType(_sql)) {
222 case StmtTransBegin :
224 break;
225 case StmtTransEnd :
227 break;
228 case StmtOther :
229 default :
230 ;
231 }
232
233 return true;
234}
235
237{
238 return __execute("BEGIN", (size_t)-1);
239}
240
242{
243 return __execute("COMMIT", (size_t)-1);
244}
245
247{
248 return __execute("ROLLBACK", (size_t)-1);
249}
250
252{
253 __DCL_ASSERT(_queryHandleOut != NULL);
254
255 SQL::Query* newQuery = new SqQuery(this);
256 if (!newQuery) {
258 return false;
259 }
260
261 *_queryHandleOut = newQuery;
262 return true;
263}
264
265bool SqConnection::__getErrorMessage(char* _buf, size_t* _buflen)
266{
267 __DCL_ASSERT(Connection::__errorCode == SQL::eServerError);
268 if (__lastErrorMessage.length() < *_buflen) {
269 *_buflen = __lastErrorMessage.length();
270 *(_buf + *_buflen) = '\0';
271 }
272 strncpy(_buf, __lastErrorMessage.data(), *_buflen);
273 return true;
274}
275
276bool SqConnection::__getServerInfo(char* _buf, size_t* _buflen)
277{
278 ByteStringBuilder sb = "SQLite ";
279 sb += sqlite3_libversion();
280#ifdef SQLITE_HAS_CODEC
281 sb += "/SQLCipher";
282#endif
283
284 if (sb.length() < *_buflen) {
285 *_buflen = sb.length();
286 *(_buf + *_buflen) = '\0';
287 }
288 strncpy(_buf, sb.data(), *_buflen);
289 return true;
290}
291
292__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:316
wchar_t char_t
Definition Config.h:251
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __SET_ERROR_MSG(_message)
@ StmtTransEnd
@ StmtOther
@ StmtTransBegin
#define __DCL_TRACE0_N(fmt)
#define __DCL_ASSERT(expr)
Definition Object.h:396
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:247
#define __T(str)
Definition Object.h:62
#define __SET_ERROR(_errorCode)
Definition SQLCore.cpp:149
#define __UNSET_STATE(state)
Definition SQLCore.h:483
#define __SET_STATE(state)
Definition SQLCore.h:482
virtual void destroy()
Definition Exception.cpp:74
static bool test(const wchar_t *_regex, const wchar_t *_string, bool _icase=false) __DCL_THROWS1(RegexException *)
Definition Regex.cpp:250
@ eOutOfMemory
Definition SQLCore.h:24
@ eServerError
Definition SQLCore.h:21
@ eNotConnected
Definition SQLCore.h:33
virtual bool __createQueryInstance(SQL::Query **_queryHandleOut)
virtual bool __startTrans()
virtual bool __rollbackTrans()
virtual bool __close()
virtual bool __commitTrans()
virtual bool __getErrorMessage(char *_buf, size_t *_buflen)
virtual ~SqConnection()
virtual bool __open(const char *_conns, size_t _connslen)
virtual bool __getServerInfo(char *_buf, size_t *_buflen)
SqConnection(const wchar_t *_serverTitle)
virtual void destroy()
virtual bool __execute(const char *_sql, size_t _sqllen)