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