5#include <ctype.h> // isspace
6#include <string.h> // strlen, strncpy
9#if __DCL_HAVE_ALLOC_DEBUG
10#undef __DCL_ALLOC_LEVEL
11#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
14#include <dcl/Numeric.h>
16#include <dcl/SQLCore.h>
18#include "IFXConnection.h"
20#include "IFXField.h" // for _getServerInfo
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
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)
38static const char_t __THIS_FILE__[] = __T("dcl/sql/IFXConnection.ec");
42#define __SET_ERROR(_error) \
43 setErrorHandle(_error, 0L, __THIS_FILE__, __LINE__)
44#define __SET_ERROR_HANDLE(_SQLCODE) \
45 setErrorHandle(SQL::eServerError, _SQLCODE, __THIS_FILE__, __LINE__)
46#define __SET_ERROR_MSG(_message) \
47 setErrorMessage(_message, __THIS_FILE__, __LINE__)
49IMPLEMENT_CLASSINFO(IFXConnection, SQL::Connection)
51IFXConnection::IFXConnection(const wchar_t* _serverTitle)
52 : Connection(_serverTitle)
56IFXConnection::~IFXConnection()
58 if (!__connectionID.isEmpty()) {
59 __DCL_TRACE0_N(L"Warning!! The connection was not closed\n");
64void IFXConnection::destroy()
77void IFXConnection::reset()
79 EXEC SQL BEGIN DECLARE SECTION;
80 char* connID = (_CONST char*) __connectionID.data();
81 EXEC SQL END DECLARE SECTION;
83 EXEC SQL SET CONNECTION :connID;
87 Connection::__canTransact = true;
88 EXEC SQL ROLLBACK WORK;
91 Connection::__canTransact = false;
94 __UNSET_STATE(stInTransaction);
97bool IFXConnection::__open(const char* _conns, size_t _connlen)
99 ListedByteStringToByteStringMap map;
100 Connection::splitConnStr(_conns, _connlen, map);
102 ByteString _SERVER = map["SERVER"];
103 ByteString _USER = map["USER"];
104 ByteString _PASSWORD = map["PASSWORD"];
105 ByteString _DATABASE = map["DATABASE"];
109 ByteStringBuilder sb = _DATABASE;
110 if (!_SERVER.isEmpty()) {
111 sb.append("@").append(_SERVER);
113 _TARGET = sb.toByteString();
114 __DCL_TRACE1_N(L"TARGET [%hs]\n", _TARGET.data());
117 ByteString connectionID = ByteString::format("conn_%zx", (size_t)this);
119 EXEC SQL BEGIN DECLARE SECTION;
120 char* user = (_CONST char*) _USER.data();
121 char* pass = (_CONST char*) _PASSWORD.data();
122 char* target = (_CONST char*) _TARGET.data();
123 char* connID = (_CONST char*) connectionID.data();
124 EXEC SQL END DECLARE SECTION;
126 EXEC SQL CONNECT TO :target AS :connID
127 USER :user USING :pass
128 WITH CONCURRENT TRANSACTION;
131 __SET_ERROR_HANDLE(SQLCODE);
134 __connectionID = connectionID;
136 if (!_DATABASE.isEmpty()) {
142bool IFXConnection::__close()
144 if (__connectionID.isEmpty()) {
145 __SET_ERROR(SQL::eNotConnected);
149 EXEC SQL BEGIN DECLARE SECTION;
150 char* connID = (_CONST char*) __connectionID.data();
151 EXEC SQL END DECLARE SECTION;
153 EXEC SQL DISCONNECT :connID;
155 __SET_ERROR_HANDLE(SQLCODE);
159 __connectionID.clear();
175static STMT_PATTERN sp[] = {
176 { StmtTransBegin, "BEGIN" },
177 { StmtTransEnd, "COMMIT|ROLLBACK" },
178 { StmtDatabase, "DATABASE" },
182static StmtType __GetStmtType(const char* _sql)
184 for(size_t i = 0; sp[i].type != StmtOther; i++) {
186 if (Regex::test(sp[i].pattern, _sql, true))
189 catch(Exception* e) {
196bool IFXConnection::__execute(const char* _sql, size_t _sqllen)
198 EXEC SQL BEGIN DECLARE SECTION;
199 char* connID = (_CONST char*) __connectionID.data();
200 char* pszSqlStatement = (_CONST char*) _sql;
201 EXEC SQL END DECLARE SECTION;
203 EXEC SQL SET CONNECTION :connID;
205 __SET_ERROR_HANDLE(SQLCODE);
209 EXEC SQL EXECUTE IMMEDIATE :pszSqlStatement;
211 __SET_ERROR_HANDLE(SQLCODE);
215 switch(__GetStmtType(_sql)) {
216 case StmtTransBegin :
217 __SET_STATE(stInTransaction);
220 __UNSET_STATE(stInTransaction);
233bool IFXConnection::__startTrans()
235 EXEC SQL BEGIN DECLARE SECTION;
236 char* connID = (_CONST char*) __connectionID.data();
237 EXEC SQL END DECLARE SECTION;
239 EXEC SQL SET CONNECTION :connID;
241 __SET_ERROR_HANDLE(SQLCODE);
247 __SET_ERROR_HANDLE(SQLCODE);
251 __SET_STATE(stInTransaction);
255bool IFXConnection::__commitTrans()
257 EXEC SQL BEGIN DECLARE SECTION;
258 char* connID = (_CONST char*) __connectionID.data();
259 EXEC SQL END DECLARE SECTION;
261 EXEC SQL SET CONNECTION :connID;
263 __SET_ERROR_HANDLE(SQLCODE);
267 EXEC SQL COMMIT WORK;
269 __SET_ERROR_HANDLE(SQLCODE);
273 __UNSET_STATE(stInTransaction);
277bool IFXConnection::__rollbackTrans()
279 EXEC SQL BEGIN DECLARE SECTION;
280 char* connID = (_CONST char*) __connectionID.data();
281 EXEC SQL END DECLARE SECTION;
283 EXEC SQL SET CONNECTION :connID;
285 __SET_ERROR_HANDLE(SQLCODE);
289 EXEC SQL ROLLBACK WORK;
291 __SET_ERROR_HANDLE(SQLCODE);
295 __UNSET_STATE(stInTransaction);
299bool IFXConnection::__createQueryInstance(SQL::Query** _queryHandleOut)
301 __DCL_ASSERT(_queryHandleOut != NULL);
303 SQL::Query* pNewQuery = new IFXQuery(this);
305 __SET_ERROR(SQL::eOutOfMemory);
309 *_queryHandleOut = pNewQuery;
313void IFXConnection::setErrorHandle(
314 SQL::Error _error, long _SQLCODE,
315 const wchar_t* _filename, int _line
318 Connection::setErrorStatus(_error, _filename, _line);
320 __lastErrorMessage.clear();
324 __DCL_ASSERT(_SQLCODE == sqlca.sqlcode);
326 ByteStringBuilder sb;
327 sb.format("SQLCODE(%d) ", _SQLCODE);
331 mint r = rgetlmsg(_SQLCODE, buf, sizeof(buf), &actual);
334 if (!isspace(buf[actual - 1]))
339 sb.format(buf, sqlca.sqlerrm);
342 sb.format("(%d)", r);
345 sb.append("Message file not found");
348 sb.append("Message number not found in message file");
351 sb.append("Cannot seek within messge file");
354 sb.append("Message buffer too small");
357 sb.append("Unkndown");
360 __lastErrorMessage = sb.toByteString();
363bool IFXConnection::__getErrorMessage(char* _buf, size_t* _buflen)
365 __DCL_ASSERT(Connection::__errorCode == SQL::eServerError);
366 if (__lastErrorMessage.length() < *_buflen) {
367 *_buflen = __lastErrorMessage.length();
368 *(_buf + *_buflen) = '\0';
370 strncpy(_buf, __lastErrorMessage.data(), *_buflen);
374bool IFXConnection::__getServerInfo(char* _buf, size_t* _buflen)
376 IFXQuery* query = new IFXQuery(this);
378 __SET_ERROR(SQL::eOutOfMemory);
382 bool localTrans = false;
383 if (!inState(SQL::Connection::stInTransaction)) {
389 "SELECT DBINFO('version', 'full')"
390 "\n FROM systables WHERE tabid = 1";
392 if (!query->prepare(_sql, ByteString::length(_sql), 0))
395 if (!query->execute())
402 __SET_ERROR(SQL::eNotAvailable);
406 IFXField* field = NULL;
407 if (!query->__getField(0, (SQL::Field**)&field))
410 size_t size = (size_t)-1;
411 if (!field->__getDataSize(&size, false) || size == (size_t)-1) {
412 __SET_ERROR(SQL::eNotAvailable);
416 if (!field->__getData(_buf, _buflen, SQL::typeText))
419 // *_buflen에 '\0'이 포함되어 있다.
420 *_buflen = ByteString::length(_buf, *_buflen);