DCL 3.7.4
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#define __TRACE_THIS 0
22#if __TRACE_THIS
23#define __DCL_TRACE0_N __DCL_TRACE0
24#define __DCL_TRACE1_N __DCL_TRACE1
25#define __DCL_TRACE2_N __DCL_TRACE2
26#define __DCL_TRACE3_N __DCL_TRACE3
27#define __DCL_TRACE4_N __DCL_TRACE4
28#else
29#define __DCL_TRACE0_N(fmt)
30#define __DCL_TRACE1_N(fmt, arg)
31#define __DCL_TRACE2_N(fmt, arg1, arg2)
32#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
33#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
34#endif
35
36#undef __THIS_FILE__
37static const char_t __THIS_FILE__[] = __T("dcl/sql/IBConnection.cpp");
38
39__DCL_BEGIN_NAMESPACE
40
41#define __SET_ERROR(_error) \
42 setErrorHandle(_error, __THIS_FILE__, __LINE__)
43#define __SET_ERROR_MSG(_msg) \
44 setErrorMessage(_msg, __THIS_FILE__, __LINE__)
45
47
48IBConnection::IBConnection(const wchar_t* _serverTitle)
49 : Connection(_serverTitle)
50{
51 Connection::__canTransact = true;
52
53 __dialect = SQL_DIALECT_CURRENT; // default ibase 6
54 __dbHandle = NULL_HANDLE;
55 __trHandle = NULL_HANDLE;
56// memset(__status, 0, sizeof(ISC_STATUS) * ISC_STATUS_VECTOR_LENGTH);
57}
58
60{
61 if (__dbHandle) {
62 __DCL_TRACE0_N(L"Warning!! The connection was not closed\n");
63 close();
64 }
65}
66
68{
69 delete this;
70}
71
72/*
73_conns에 가능한 property
74 USER,
75 PASSWORD,
76 SERVER, -- host name
77 DATABASE
78 SQL_DIALECT
79
80 or CREATE DATABASE statement
81*/
82
83static const char* __createDatabasePattern__ = "CREATE[[:space:]]+DATABASE";
84
85bool IBConnection::__open(const char* _conns, size_t _connlen)
86{
87 try {
88 if (Regex::test(__createDatabasePattern__, _conns, true)) {
89 // CREATE DATABASE
90 if(isc_dsql_execute_immediate(
91 __status,
92 &__dbHandle,
93 &__trHandle,
94 0,
95 (_CONST char*)_conns,
96 __dialect,
97 NULL
98 )) {
100 return false;
101 }
102 return true;
103 }
104 }
105 catch(RegexException* e) {
106 e->destroy();
107 }
108
109 ListedByteStringToByteStringMap map;
110 Connection::splitConnStr(_conns, _connlen, map);
111
112 ByteString _SERVER = map["SERVER"];
113 ByteString _DATABASE = map["DATABASE"];
114 ByteString _USER = map["USER"];
115 ByteString _PASSWORD = map["PASSWORD"];
116 ByteString _SQL_DIALECT = map["SQL_DIALECT"];
117
118 if (!_SQL_DIALECT.isEmpty()) {
119 int nDialect = SQL_DIALECT_CURRENT;
120 char* endptr;
121 long n = strtol(_SQL_DIALECT, &endptr, 10);
122 if (n == LONG_MAX || n == LONG_MIN
123 || n < INT_MIN || INT_MAX < n
124 ) {
125 __SET_ERROR_MSG("연결 문자열이 잘못되었습니다. SQL_DIALECT="
126 + _SQL_DIALECT);
127 return false;
128 }
129
130 nDialect = (int)n;
131
132 if (!(nDialect == SQL_DIALECT_V5
133 || nDialect == SQL_DIALECT_V6_TRANSITION
134 || nDialect == SQL_DIALECT_V6)
135 ) {
136 __SET_ERROR_MSG("\"SQL_DIALECT\"- invalid value");
137 return false;
138 }
139
140 __dialect = nDialect;
141 }
142
143 if ((_USER.length() > 127) || (_PASSWORD.length() > 127)) {
144 // USER NAME 과 PASSWORD 의 길이는 127을 넘을 수 없다.
146 return false;
147 }
148
149 ByteString dbEnv;
150 if (!_SERVER.isEmpty())
151 dbEnv = _SERVER + ":";
152
153 if (!_DATABASE.isEmpty())
154 dbEnv = dbEnv + _DATABASE;
155
156 if (dbEnv.isEmpty()) {
158 return false;
159 }
160
161 // database parameter block
162 ByteStringBuilder dpb;
163 dpb = (char)isc_dpb_version1;
164 dpb += (char)isc_dpb_user_name;
165 dpb += (char)_USER.length();
166 dpb += _USER;
167 dpb += (char)isc_dpb_password;
168 dpb += (char)_PASSWORD.length();
169 dpb += _PASSWORD;
170
171 static const char __UTF8__[] = "UTF8";
172 dpb += (char)isc_dpb_lc_ctype;
173 dpb += (char)(sizeof(__UTF8__) - 1);
174 dpb += __UTF8__;
175
176#if defined(FIREBIRD_IBASE_H) && FB_API_VER >= 40
177 static const char __SET_BIND__[] =
178 "DECFLOAT TO VARCHAR;" // 20
179 "INT128 TO VARCHAR;" // 18
180 "TIME ZONE TO EXTENDED"; // 21
181 dpb += (char)isc_dpb_set_bind;
182 dpb += (char)(sizeof(__SET_BIND__) - 1);
183 dpb += __SET_BIND__;
184#endif
185
186#ifdef FIREBIRD_IBASE_H
187 #undef _CONST
188 #define _CONST const
189#endif
190
191 if (isc_attach_database(
192 __status,
193 (short) dbEnv.length(),
194 (_CONST char*) dbEnv.data(),
195 &__dbHandle,
196 (short) dpb.length(),
197 (_CONST char*) dpb.data())
198 ) {
199// __DCL_ASSERT(STATUS_FAILED(__status));
201 __dbHandle = NULL_HANDLE;
202 return false;
203 }
204 return true;
205}
206
208{
209 if (!__dbHandle) {
211 return false;
212 }
213 __DCL_ASSERT(__trHandle == NULL_HANDLE);
214
215 if (isc_detach_database(
216 __status,
217 &__dbHandle
218 )) {
219// __DCL_ASSERT(STATUS_FAILED(__status));
221 return false;
222 }
223 __dbHandle = NULL_HANDLE;
224 return true;
225}
226
233
234typedef struct {
235 StmtType type;
236 const char* pattern;
238
239static STMT_PATTERN sp[] = {
240 { StmtTransBegin, "SET[[:space:]]+TRANSACTION" },
241 { StmtTransEnd, "COMMIT|ROLLBACK" },
242 { StmtCreateDatabase, __createDatabasePattern__ },
243 { StmtOther, NULL }
244};
245
246static StmtType __GetStmtType(const char* _sql)
247{
248 for(size_t i = 0; sp[i].type != StmtOther; i++) {
249 if (Regex::test(sp[i].pattern, _sql, true))
250 return sp[i].type;
251 }
252 return StmtOther;
253}
254
255bool IBConnection::__execute(const char* _sql, size_t n)
256{
258 __DCL_ASSERT(__dbHandle != NULL_HANDLE);
259 if(isc_dsql_execute_immediate(
260 __status,
261 &__dbHandle,
262 &__trHandle,
263 (unsigned short int)n,
264 (_CONST char*)_sql,
265 __dialect,
266 NULL
267 )) {
268// __DCL_ASSERT(STATUS_FAILED(__status));
270 return false;
271 }
272
273 switch (__GetStmtType(_sql)) {
274 case StmtTransBegin :
276 __DCL_ASSERT(__trHandle != NULL_HANDLE);
277 break;
278 case StmtTransEnd :
280 __trHandle = NULL_HANDLE;
281 break;
282 default :
283 ;
284 }
285
286 return true;
287}
288
290{
291 __DCL_ASSERT(__trHandle == NULL_HANDLE);
292 if (isc_start_transaction(
293 __status,
294 &__trHandle,
295 1,
296 &__dbHandle,
297 0,
298 NULL
299 )) {
300// __DCL_ASSERT(STATUS_FAILED(__status));
302 return false;
303 }
304
305 return true;
306}
307
309{
310 __DCL_ASSERT(__trHandle != NULL_HANDLE);
311 if(isc_commit_transaction(
312 __status,
313 &__trHandle
314 )) {
315// __DCL_ASSERT(STATUS_FAILED(__status));
317 return false;
318 }
319 __trHandle = NULL_HANDLE;
320
321 return true;
322}
323
325{
326 __DCL_ASSERT(__trHandle != NULL_HANDLE);
327 if(isc_rollback_transaction(
328 __status,
329 &__trHandle
330 )) {
331// __DCL_ASSERT(STATUS_FAILED(__status));
333 return false;
334 }
335 __trHandle = NULL_HANDLE;
336
337 return true;
338}
339
341{
342 __DCL_ASSERT(_queryHandleOut != NULL);
343
344 SQL::Query* newQuery = new IBQuery(this);
345 if (!newQuery) {
347 return false;
348 }
349
350 *_queryHandleOut = newQuery;
351 return true;
352}
353
354bool IBConnection::__getErrorMessage(char* _buf, size_t* _buflen)
355{
356 ByteStringBuilder sb;
357 if (!__lastErrorMessage.isEmpty())
358 sb = __lastErrorMessage;
359 else {
360 char buf[512];
361 ISC_STATUS* status = __status;
362 size_t len = 0;
363#ifdef FIREBIRD_IBASE_H
364#define isc_interprete(buf, pp) fb_interpret(buf, sizeof(buf), (const ISC_STATUS**) pp)
365#endif
366 for(size_t i = 0; (len = isc_interprete(buf, &status))
367 && (i < ISC_STATUS_VECTOR_LENGTH); i++) {
368 if (i > 0)
369 sb += ", ";
370 sb.append(buf, 0, len);
371 }
372 }
373
374 if (sb.length() < *_buflen) {
375 *_buflen = sb.length();
376 *(_buf + *_buflen) = '\0';
377 }
378 strncpy(_buf, sb.data(), *_buflen);
379 return true;
380}
381
382static char database_info_items[] = {
383 isc_info_version,
384 //isc_info_db_id,
385 isc_info_end
386};
387
388bool IBConnection::__getServerInfo(char* _buf, size_t* _buflen)
389{
390 char buffer[512];
391 if (isc_database_info (
392 __status,
393 &__dbHandle,
394 sizeof(database_info_items),
395 database_info_items,
396 sizeof(buffer),
397 buffer
398 )) {
400 return false;
401 }
402
403 ByteString version;
404 ByteString dbId;
405 ByteString site;
406
407 char* p = buffer;
408 char item;
409 unsigned short length;
410 __DCL_ASSERT(sizeof(unsigned short) == 2);
411 while(*p != isc_info_end) {
412 item = *p++;
413 length = (unsigned short)isc_vax_integer(p, 2);
414 p += 2;
415 if (item == isc_info_version) {
416 // __DCL_ASSERT(p[0] == 1);
417 //__DCL_TRACE1(L"[%d]\n", p[0]);
418 version.assign(p, 2, p[1]);
419 }
420 else if (item == isc_info_db_id) {
421 char* t = p;
422 //__DCL_TRACE1(L"[%d]\n", *t);
423 //__DCL_ASSERT(*t == 2);
424 t++;
425 unsigned short strlen = *t++;
426 dbId.assign(t, strlen);
427 t += strlen;
428 strlen = *t++;
429 site.assign(t, strlen);
430 }
431 else {
433 return false;
434 }
435 p += length;
436 }
437
438 ByteString info =
439#ifndef FIREBIRD_IBASE_H
440 "InterBase " + version
441#else
442 version
443#endif
444 // +" \"" + site + ':' + dbId + "\""
445 ;
446
447 if (info.length() < *_buflen)
448 *_buflen = info.length();
449
450 strncpy(_buf, info.data(), *_buflen);
451 return true;
452}
453
454__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
#define UINT16_MAX
Definition Config.h:294
wchar_t char_t
Definition Config.h:247
#define _CONST
Definition Config.h:325
@ StmtCreateDatabase
#define ISC_STATUS_VECTOR_LENGTH
#define NULL_HANDLE
#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
virtual bool __open(const char *_conns, size_t _connlen)
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 __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:250
@ eOutOfMemory
Definition SQLCore.h:24
@ eInvalidConnectionString
Definition SQLCore.h:31
@ eServerError
Definition SQLCore.h:21
@ eNotConnected
Definition SQLCore.h:33
@ eNotAvailable
Definition SQLCore.h:38