14#include <ctype.h> // isspace
15#include <string.h> // strlen, strncpy
17#include <dcl/Object.h>
18#if __DCL_HAVE_ALLOC_DEBUG
19#undef __DCL_ALLOC_LEVEL
20#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
23#include <dcl/Numeric.h>
25#include <dcl/Thread.h>
27#include <dcl/SQLCore.h>
29#include "IFXConnection.h"
31#include "IFXField.h" // for _getServerInfo
34static const wchar_t __THIS_FILE__[] = __T("dcl/sql/IFXConnection.ec");
38IMPLEMENT_CLASSINFO(IFXConnection, SQL::Connection)
40static volatile long __connectionID__ = 0;
42IFXConnection::IFXConnection(const wchar_t* _serverTitle)
43 : Connection(_serverTitle)
45 __connectionID = ByteString::format("con:%ld", Thread::incrementAndGet(__connectionID__));
48IFXConnection::~IFXConnection()
52void IFXConnection::destroy()
58pszConnectionString에 가능한 프로퍼티
65void IFXConnection::reset()
67 EXEC SQL BEGIN DECLARE SECTION;
68 char* pszConnectionID = (_CONST char*) __connectionID.data();
69 EXEC SQL END DECLARE SECTION;
71 EXEC SQL SET CONNECTION :pszConnectionID;
75 Connection::__canTransact = true;
76 EXEC SQL ROLLBACK WORK;
79 Connection::__canTransact = false;
81 __UNSET_STATE(stInTransaction);
84bool IFXConnection::__open(const char* _connString, size_t _connlen)
86 ListedByteStringToByteStringMap map;
87 Connection::splitConnectionString(_connString, _connlen, map);
89 ByteString strServer = map["SERVER"];
90 ByteString strUser = map["USER"];
91 ByteString strPassword = map["PASSWORD"];
92 ByteString strDatabase = map["DATABASE"];
94 ByteString strDatabaseEnv = strDatabase;
95 if (!strServer.isEmpty()) {
96 strDatabaseEnv = strDatabaseEnv + "@" + strServer;
98 //__DCL_TRACE1(L"[%hs]\n", strDatabaseEnv.data());
100 EXEC SQL BEGIN DECLARE SECTION;
101 char* pszUserName = (_CONST char*) strUser.data();
102 char* pszPassword = (_CONST char*) strPassword.data();
103 char* pszDatabaseEnv = (_CONST char*) strDatabaseEnv.data();
104 char* pszConnectionID = NULL;
105 EXEC SQL END DECLARE SECTION;
107 pszConnectionID = (_CONST char*) __connectionID.data();
109 EXEC SQL CONNECT TO :pszDatabaseEnv AS :pszConnectionID
110 USER :pszUserName USING :pszPassword
111 WITH CONCURRENT TRANSACTION;
113 __SET_ERROR_SQLCODE(SQLCODE);
117 if (!strDatabase.isEmpty())
123bool IFXConnection::__close()
125 EXEC SQL BEGIN DECLARE SECTION;
126 char* pszConnectionID = (_CONST char*) __connectionID.data();
127 EXEC SQL END DECLARE SECTION;
129 EXEC SQL DISCONNECT :pszConnectionID;
131 __SET_ERROR_SQLCODE(SQLCODE);
150static STMT_PATTERN sp[] = {
151 { StmtTransBegin, "BEGIN" },
152 { StmtTransEnd, "COMMIT|ROLLBACK" },
153 { StmtDatabase, "DATABASE" },
157static StmtType __GetStmtType(const char* _sql)
159 for(size_t i = 0; sp[i].type != StmtOther; i++) {
161 if (Regex::test(sp[i].pattern, _sql, true))
164 catch(Exception* e) {
171bool IFXConnection::__execute(const char* _sql, size_t _sqllen)
173 EXEC SQL BEGIN DECLARE SECTION;
174 char* pszConnectionID = (_CONST char*) __connectionID.data();
175 char* pszSqlStatement = (_CONST char*) _sql;
176 EXEC SQL END DECLARE SECTION;
178 EXEC SQL SET CONNECTION :pszConnectionID;
180 __SET_ERROR_SQLCODE(SQLCODE);
184 EXEC SQL EXECUTE IMMEDIATE :pszSqlStatement;
186 __SET_ERROR_SQLCODE(SQLCODE);
190 switch(__GetStmtType(_sql)) {
191 case StmtTransBegin :
192 __SET_STATE(stInTransaction);
195 __UNSET_STATE(stInTransaction);
208bool IFXConnection::__startTrans()
210 EXEC SQL BEGIN DECLARE SECTION;
211 char* pszConnectionID = (_CONST char*) __connectionID.data();
212 EXEC SQL END DECLARE SECTION;
214 EXEC SQL SET CONNECTION :pszConnectionID;
216 __SET_ERROR_SQLCODE(SQLCODE);
222 __SET_ERROR_SQLCODE(SQLCODE);
226 __SET_STATE(stInTransaction);
230bool IFXConnection::__commitTrans()
232 EXEC SQL BEGIN DECLARE SECTION;
233 char* pszConnectionID = (_CONST char*) __connectionID.data();
234 EXEC SQL END DECLARE SECTION;
236 EXEC SQL SET CONNECTION :pszConnectionID;
238 __SET_ERROR_SQLCODE(SQLCODE);
242 EXEC SQL COMMIT WORK;
244 __SET_ERROR_SQLCODE(SQLCODE);
248 __UNSET_STATE(stInTransaction);
252bool IFXConnection::__rollbackTrans()
254 EXEC SQL BEGIN DECLARE SECTION;
255 char* pszConnectionID = (_CONST char*) __connectionID.data();
256 EXEC SQL END DECLARE SECTION;
258 EXEC SQL SET CONNECTION :pszConnectionID;
260 __SET_ERROR_SQLCODE(SQLCODE);
264 EXEC SQL ROLLBACK WORK;
266 __SET_ERROR_SQLCODE(SQLCODE);
270 __UNSET_STATE(stInTransaction);
274bool IFXConnection::__createQueryInstance(SQL::Query** _queryHandleOut)
276 __DCL_ASSERT(_queryHandleOut != NULL);
278 SQL::Query* pNewQuery = new IFXQuery(this);
280 __SET_ERROR(SQL::eOutOfMemory);
284 *_queryHandleOut = pNewQuery;
288void IFXConnection::setErrorStatus(SQL::Error _error, long _SQLCODE,
289 const wchar_t* _filename, int _line)
291 Connection::setErrorStatus(_error, _filename, _line);
293 __lastErrorMessage.clear();
297 __DCL_ASSERT(_SQLCODE == sqlca.sqlcode);
299 ByteStringBuilder sb;
300 sb.format("SQLCODE(%d) ", _SQLCODE);
304 mint r = rgetlmsg(_SQLCODE, buf, sizeof(buf), &actual);
307 if (!isspace(buf[actual - 1]))
312 sb.format(buf, sqlca.sqlerrm);
315 sb.format("(%d)", r);
318 sb.append("Message file not found");
321 sb.append("Message number not found in message file");
324 sb.append("Cannot seek within messge file");
327 sb.append("Message buffer too small");
330 sb.append("Unkndown");
333 __lastErrorMessage = sb.toByteString();
336bool IFXConnection::__getErrorMessage(char* _buf, size_t* _buflen)
338 __DCL_ASSERT(Connection::__errorCode == SQL::eServerError);
339 if (__lastErrorMessage.length() < *_buflen)
340 *_buflen = __lastErrorMessage.length();
341 strncpy(_buf, __lastErrorMessage.data(), *_buflen);
345bool IFXConnection::__getServerInfo(char* _buf, size_t* _buflen)
347 IFXQuery* pQuery = new IFXQuery(this);
348 if (pQuery == NULL) {
349 __SET_ERROR(SQL::eOutOfMemory);
353 bool localTrans = false;
354 if (!inState(SQL::Connection::stInTransaction)) {
360 "SELECT DBINFO('version', 'full')"
361 " FROM systables WHERE tabid = 1";
363 if (!pQuery->prepare(_sql, ByteString::length(_sql), 0))
366 if (!pQuery->execute())
369 if (!pQuery->fetch())
373 __SET_ERROR(SQL::eNotAvailable);
377 IFXField* pField = NULL;
378 if (!pQuery->__getField(0, (SQL::Field**)&pField))
381 if (pField->isNull()) {
382 __SET_ERROR(SQL::eNotAvailable);
386 if (!pField->__getData(_buf, _buflen, SQL::typeText))