DCL 4.1
Loading...
Searching...
No Matches
IBConnection.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <stdlib.h> // strtol
4#include <string.h> // strncpy
5
6#include <ibase.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/Numeric.h>
15#include <dcl/Regex.h>
16#include <dcl/SQLCore.h>
17
18#include "IBConnection.h"
19#include "IBQuery.h"
20
21#undef __THIS_FILE__
22static const wchar_t __THIS_FILE__[] = __T("dcl/sql/IBConnection.cpp");
23
24__DCL_BEGIN_NAMESPACE
25
27
28IBConnection::IBConnection(const wchar_t* _serverTitle)
29 : Connection(_serverTitle)
30{
31 Connection::__canTransact = true;
32
33 __dialect = SQL_DIALECT_CURRENT;
34 __dbHandle = NULL;
35 __trHandle = NULL;
36// memset(__status, 0, sizeof(ISC_STATUS) * ISC_STATUS_VECTOR_LENGTH);
37}
38
42
44{
45// cerr << "IBConnection::destory\n";
46 delete this;
47}
48
49/*
50 pszConnectionString에 가능한 property
51 USER,
52 PASSWORD,
53 SERVER, -- host name
54 DATABASE
55 SQL_DIALECT
56
57 or CREATE DATABASE statement
58*/
59
60static const char* __createDatabasePattern__ = "CREATE[[:space:]]+DATABASE";
61
62bool IBConnection::__open(const char* _connString, size_t _connlen)
63{
64 try {
65 if (Regex::test(__createDatabasePattern__, _connString, true)) {
66 // CREATE DATABASE
67 if(isc_dsql_execute_immediate(
68 __status,
69 &__dbHandle,
70 &__trHandle,
71 0,
72 (_CONST char*)_connString,
73 __dialect,
74 NULL)) {
76 return false;
77 }
78 return true;
79 }
80 }
81 catch(RegexException* e) {
82 e->destroy();
83 }
84
85 ListedByteStringToByteStringMap map;
86 Connection::splitConnectionString(_connString, _connlen, map);
87
88 ByteString strServer = map["SERVER"];
89 ByteString strDatabase = map["DATABASE"];
90 ByteString strUser = map["USER"];
91 ByteString strPassword = map["PASSWORD"];
92 ByteString strSqlDialect = map["SQL_DIALECT"];
93
94 if (!strSqlDialect.isEmpty()) {
95 int nDialect = SQL_DIALECT_CURRENT;
96 char* endptr;
97 long n = strtol(strSqlDialect, &endptr, 10);
98 if (n == LONG_MAX || n == LONG_MIN
99 || n < INT_MIN || INT_MAX < n
100 ) {
101 __SET_ERROR_MSG("연결 문자열이 잘못되었습니다. SQL_DIALECT="
102 + strSqlDialect);
103 return false;
104 }
105
106 nDialect = (int)n;
107
108 if (!(nDialect == SQL_DIALECT_V5
109 || nDialect == SQL_DIALECT_V6_TRANSITION
110 || nDialect == SQL_DIALECT_V6)) {
111 __SET_ERROR_MSG("\"SQL_DIALECT\"- invalid value");
112 return false;
113 }
114
115 __dialect = nDialect;
116 }
117
118 if ((strUser.length() > 127) || (strPassword.length() > 127)) {
119 // USER NAME 과 PASSWORD 의 길이는 127을 넘을 수 없다.
121 return false;
122 }
123
124 ByteString strDatabaseEnv;
125 if (!strServer.isEmpty())
126 strDatabaseEnv = strServer + ":";
127
128 if (!strDatabase.isEmpty())
129 strDatabaseEnv = strDatabaseEnv + strDatabase;
130
131 if (strDatabaseEnv.isEmpty()) {
133 return false;
134 }
135
136 // database parameter block
137 ByteStringBuilder dpb;
138 dpb = (char)isc_dpb_version1;
139 dpb += (char)isc_dpb_user_name;
140 dpb += (char)strUser.length();
141 dpb += strUser;
142 dpb += (char)isc_dpb_password;
143 dpb += (char)strPassword.length();
144 dpb += strPassword;
145
146 static const char __UTF8__[] = "UTF8";
147 dpb += (char)isc_dpb_lc_ctype;
148 dpb += (char)(sizeof(__UTF8__) - 1);
149 dpb += __UTF8__;
150
151#if defined(FIREBIRD_IBASE_H) && FB_API_VER >= 40
152 static const char __SET_BIND__[] =
153 "DECFLOAT TO VARCHAR;" // 20
154 "INT128 TO VARCHAR;" // 18
155 "TIME ZONE TO EXTENDED"; // 21
156 dpb += (char)isc_dpb_set_bind;
157 dpb += (char)(sizeof(__SET_BIND__) - 1);
158 dpb += __SET_BIND__;
159#endif
160
161#ifdef FIREBIRD_IBASE_H
162 #undef _CONST
163 #define _CONST const
164#endif
165
166 if (isc_attach_database(
167 __status,
168 (short) strDatabaseEnv.length(),
169 (_CONST char*) strDatabaseEnv.data(),
170 &__dbHandle,
171 (short) dpb.length(),
172 (_CONST char*) dpb.data())
173 ) {
174// __DCL_ASSERT(STATUS_FAILED(__status));
176 __dbHandle = NULL;
177 return false;
178 }
179 return true;
180}
181
183{
184 __DCL_ASSERT(__dbHandle != NULL);
185 __DCL_ASSERT(__trHandle == NULL);
186
187 if (isc_detach_database(
188 __status,
189 &__dbHandle)
190 ) {
191// __DCL_ASSERT(STATUS_FAILED(__status));
193 return false;
194 }
195 __dbHandle = NULL;
196 return true;
197}
198
205
206typedef struct {
207 StmtType type;
208 const char* pattern;
210
211static STMT_PATTERN sp[] = {
212 { StmtTransBegin, "SET[[:space:]]+TRANSACTION" },
213 { StmtTransEnd, "COMMIT|ROLLBACK" },
214 { StmtCreateDatabase, __createDatabasePattern__ },
215 { StmtOther, NULL }
216};
217
218static StmtType __GetStmtType(const char* _sql)
219{
220 for(size_t i = 0; sp[i].type != StmtOther; i++) {
221 if (Regex::test(sp[i].pattern, _sql, true))
222 return sp[i].type;
223 }
224 return StmtOther;
225}
226
227bool IBConnection::__execute(const char* _sql, size_t n)
228{
230 __DCL_ASSERT(__dbHandle != NULL);
231 if(isc_dsql_execute_immediate(
232 __status,
233 &__dbHandle,
234 &__trHandle,
235 (unsigned short int)n,
236 (_CONST char*)_sql,
237 __dialect,
238 NULL)
239 ) {
240// __DCL_ASSERT(STATUS_FAILED(__status));
242 return false;
243 }
244
245 switch (__GetStmtType(_sql)) {
246 case StmtTransBegin :
248 __DCL_ASSERT(__trHandle != NULL);
249 break;
250 case StmtTransEnd :
252 __trHandle = NULL;
253 break;
254 default :
255 ;
256 }
257
258 return true;
259}
260
262{
263 __DCL_ASSERT(__trHandle == NULL);
264 if (isc_start_transaction(
265 __status,
266 &__trHandle,
267 1,
268 &__dbHandle,
269 0,
270 NULL)
271 ) {
272// __DCL_ASSERT(STATUS_FAILED(__status));
274 return false;
275 }
276
277 return true;
278}
279
281{
282 __DCL_ASSERT(__trHandle != NULL);
283 if(isc_commit_transaction(
284 __status,
285 &__trHandle)
286 ) {
287// __DCL_ASSERT(STATUS_FAILED(__status));
289 return false;
290 }
291 __trHandle = NULL;
292
293 return true;
294}
295
297{
298 __DCL_ASSERT(__trHandle != NULL);
299 if(isc_rollback_transaction(
300 __status,
301 &__trHandle)
302 ) {
303// __DCL_ASSERT(STATUS_FAILED(__status));
305 return false;
306 }
307 __trHandle = NULL;
308
309 return true;
310}
311
313{
314 __DCL_ASSERT(_queryHandleOut != NULL);
315
316 SQL::Query* pNewQuery = new IBQuery(this);
317 if (!pNewQuery) {
319 return false;
320 }
321
322 *_queryHandleOut = pNewQuery;
323 return true;
324}
325
326bool IBConnection::__getErrorMessage(char* _buf, size_t* _buflen)
327{
328 ByteStringBuilder sb;
329 if (!__lastErrorMessage.isEmpty())
330 sb = __lastErrorMessage;
331 else {
332 char buf[512];
333 ISC_STATUS* status = __status;
334 long len = 0;
335#ifdef FIREBIRD_IBASE_H
336#define isc_interprete(buf, pp) fb_interpret(buf, sizeof(buf), (const ISC_STATUS**) pp)
337#endif
338 for(size_t i = 0; (len = isc_interprete(buf, &status))
339 && (i < ISC_STATUS_VECTOR_LENGTH); i++) {
340 if (i > 0)
341 sb += ", ";
342 sb.append(buf, 0, len);
343 }
344 }
345
346 if (sb.length() < *_buflen)
347 *_buflen = sb.length();
348
349 strncpy(_buf, sb.data(), *_buflen);
350
351 return true;
352}
353
354static char database_info_items[] = {
355 isc_info_version,
356 isc_info_db_id,
357 isc_info_end
358};
359
360bool IBConnection::__getServerInfo(char* _buf, size_t* _buflen)
361{
362 char buffer[512];
363 if (isc_database_info (
364 __status,
365 &__dbHandle,
366 sizeof(database_info_items),
367 database_info_items,
368 sizeof(buffer),
369 buffer)) {
371 return false;
372 }
373
374 ByteString strVersion;
375 ByteString strDb;
376 ByteString strSite;
377
378 char* p = buffer;
379 char item;
380 unsigned short length;
381 __DCL_ASSERT(sizeof(unsigned short) == 2);
382 while(*p != isc_info_end) {
383 item = *p++;
384 length = (unsigned short)isc_vax_integer(p, 2);
385 p += 2;
386 if (item == isc_info_version) {
387 // __DCL_ASSERT(p[0] == 1);
388 //__DCL_TRACE1(L"[%d]\n", p[0]);
389 strVersion.assign(p, 2, p[1]);
390 }
391 else if (item == isc_info_db_id) {
392 char* t = p;
393 //__DCL_TRACE1(L"[%d]\n", *t);
394 //__DCL_ASSERT(*t == 2);
395 t++;
396 unsigned short nStrLen = *t++;
397 strDb.assign(t, nStrLen);
398 t += nStrLen;
399 nStrLen = *t++;
400 strSite.assign(t, nStrLen);
401 }
402 else {
404 return false;
405 }
406 p += length;
407 }
408
409 ByteString strInfo = "InterBase " + strVersion + " \"" + strSite + ':' + strDb + "\"";
410 if (strInfo.length() < *_buflen)
411 *_buflen = strInfo.length();
412
413 strncpy(_buf, strInfo.data(), *_buflen);
414 return true;
415}
416
417__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
#define UINT16_MAX
Definition Config.h:322
#define _CONST
Definition Config.h:353
@ StmtCreateDatabase
#define __SET_ERROR(_error)
#define ISC_STATUS_VECTOR_LENGTH
Definition IBConnection.h:6
#define __SET_ERROR_MSG(str)
@ StmtTransEnd
@ StmtOther
@ StmtTransBegin
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
size_t len
ByteBuffer * buf
#define __UNSET_STATE(state)
Definition SQLCore.h:433
#define __SET_STATE(state)
Definition SQLCore.h:432
void CharsetConvertException *size_t n
Definition SQLField.cpp:254
virtual void destroy()
Definition Exception.cpp:74
virtual bool __createQueryInstance(SQL::Query **_queryHandleOut)
virtual ~IBConnection()
virtual bool __execute(const char *_sql, size_t _sqllen)
virtual void destroy()
virtual bool __commitTrans()
virtual bool __getServerInfo(char *_buf, size_t *_buflen)
virtual bool __startTrans()
virtual bool __close()
virtual bool __rollbackTrans()
virtual bool __open(const char *_connString, size_t _connlen)
virtual bool __getErrorMessage(char *_buf, size_t *_buflen)
IBConnection(const wchar_t *_serverTitle)
static bool test(const wchar_t *_regex, const wchar_t *_string, bool _icase=false) __DCL_THROWS1(RegexException *)
Definition Regex.cpp:252
@ eOutOfMemory
Definition SQLCore.h:24
@ eInvalidConnectionString
Definition SQLCore.h:31
@ eServerError
Definition SQLCore.h:21
@ eNotAvailable
Definition SQLCore.h:38