7#include <stdlib.h> // malloc, free
8#include <string.h> // memset
10#include <dcl/Object.h>
11#if __DCL_HAVE_ALLOC_DEBUG
12#undef __DCL_ALLOC_LEVEL
13#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
16#include <dcl/Numeric.h>
17#include <dcl/SQLCore.h>
19#include "IFXConnection.h"
23#include "IFXUtils.h" // for void ndebug_free(void* _pv)
27#define __DCL_TRACE0_N __DCL_TRACE0
28#define __DCL_TRACE1_N __DCL_TRACE1
29#define __DCL_TRACE2_N __DCL_TRACE2
30#define __DCL_TRACE3_N __DCL_TRACE3
31#define __DCL_TRACE4_N __DCL_TRACE4
33#define __DCL_TRACE0_N(fmt)
34#define __DCL_TRACE1_N(fmt, arg)
35#define __DCL_TRACE2_N(fmt, arg1, arg2)
36#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
37#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
41static const wchar_t __THIS_FILE__[] = __T("dcl/sql/IFXQuery.ec");
45IMPLEMENT_CLASSINFO(IFXQuery, SQL::Query)
48#define __SQ_NAME(_sq) case _sq: return L ## #_sq;
50static const wchar_t* __STMT_STRING(int _sq)
57 __SQ_NAME(SQ_EXECPROC)
63IFXQuery::IFXQuery(IFXConnection* pConnection)
67 strID = ByteString::format("%p", this);
69 __statementID = "stmt_" + strID;
70 __cursorID = "cursor_" + strID;
73 __stmtType = __SQ_UNKNOWN;
79 __cursorOpened = false;
80 __cursorDeclared = false;
92 ByteBuffer* buf = ByteBuffer::create(n);
93 bool b = conn()->__getErrorMessage(buf->data(), &n);
95 buf->__dataLength = n;
101 __DCL_TRACE1(__T("Warning! %s\n"), s.data());
104 __DCL_TRACE0(__T("Warning! Query reset error\n"));
112void IFXQuery::__destroy()
114// cerr << "IFXQuery::destory\n";
118bool IFXQuery::reset()
120 EXEC SQL BEGIN DECLARE SECTION;
121 char* pszConnectionID = conn()->connectionID();
122 char* pszStatementID = (_CONST char*)__statementID.data();
123 char* pszCursorID = (_CONST char*)__cursorID.data();
124 EXEC SQL END DECLARE SECTION;
126 EXEC SQL SET CONNECTION :pszConnectionID;
128 __SET_ERROR_SQLCODE(SQLCODE);
131 __DCL_ASSERT(SQLCODE == 0);
133 if (__cursorOpened) {
134 EXEC SQL CLOSE :pszCursorID;
135 __cursorOpened = false;
138 if (__cursorDeclared) {
139 EXEC SQL FREE :pszCursorID;
140 __cursorDeclared = false;
144 if (__stmtType != __SQ_UNKNOWN) {
145 EXEC SQL FREE :pszStatementID;
146 __stmtType = __SQ_UNKNOWN;
149 if (__outSQLDA || __inSQLDA) {
150 EXEC SQL FREE : pszStatementID;
155 Query::__affectedRows = -1;
159 __DCL_ASSERT(Query::__fieldCount > 0);
162 Query::__fieldCount = 0;
167 __DCL_ASSERT(Query::__paramCount > 0);
170 Query::__paramCount = 0;
179 // __outSQLDA는 Informix API에서 할당됨.
180 ndebug_free(__outSQLDA);
185 ndebug_free(__inSQLDA);
192bool IFXQuery::initFields()
194 __DCL_ASSERT((Query::__fieldCount == 0)
195 && (__fields == NULL)
196 && (__outBuffer == NULL)
197 && (__outSQLDA != NULL)
198 && (__outSQLDA->sqld > 0));
200 Query::__fieldCount = __outSQLDA->sqld;
201 __fields = new IFXField[Query::__fieldCount];
202 if (__fields == NULL) {
203 __SET_ERROR(SQL::eOutOfMemory);
209 ifx_sqlvar_t* sqlvar = __outSQLDA->sqlvar;
210 for(size_t i = 0; i < Query::__fieldCount; i++, sqlvar++) {
211 offset = rtypalign(offset, sqlvar->sqltype);
212 mint msize = rtypmsize(sqlvar->sqltype, sqlvar->sqllen);
213 __DCL_TRACE4_N(L"[%10hs] sqllen[%4d] msize[%4d] offset[%4d]\n",
214 rtypname(sqlvar->sqltype), sqlvar->sqllen,
216 switch (sqlvar->sqltype & SQLTYPE) {
223 sqlvar->sqllen = msize;
227 SQLTYPE sqllen rtypmsize
228 ===========================================
229 SQLCHAR 서버컬럼최대길이 sqllen + 1
230 SQLVCHAR '\0'을 포함한 버퍼의 크기
233 -------------------------------------------
234 SQLDECIMAL DECIMAL(p,s) sizeof(dec_t)
236 -------------------------------------------
237 SQLDTIME qualifier sizeof(dtime_t)
238 SQLINTERVAL qualifier sizeof(intrvl_t)
243 __outBuffer = (char*)malloc(offset);
244 __DCL_ASSERT((size_t)__outBuffer % sizeof(void*) == 0);
245 if (__outBuffer == NULL) {
246 __SET_ERROR(SQL::eOutOfMemory);
249 memset(__outBuffer, 0, offset);
252 sqlvar = __outSQLDA->sqlvar;
254 for(size_t i = 0; i < Query::__fieldCount; i++, sqlvar++) {
255 offset = rtypalign(offset, sqlvar->sqltype);
256 sqlvar->sqldata = (char*)__outBuffer + offset;
257 offset += rtypmsize(sqlvar->sqltype, sqlvar->sqllen);
259 if (!__fields[i].init(this, sqlvar))
266bool IFXQuery::initParams(size_t _paramCount)
268 __DCL_ASSERT((__params == NULL)
269 && (Query::__paramCount == 0)
270 && (__inSQLDA != NULL));
272 size_t nAllocSize = sizeof(ifx_sqlda_t) + (sizeof(ifx_sqlvar_t) * _paramCount);
273 __inSQLDA = (ifx_sqlda_t*)malloc(nAllocSize);
274 if (__inSQLDA == NULL) {
275 __SET_ERROR(SQL::eOutOfMemory);
278 memset(__inSQLDA, 0, nAllocSize);
279 __inSQLDA->sqld = _paramCount;
280 __inSQLDA->sqlvar = (ifx_sqlvar_t*)((char*)__inSQLDA + sizeof(ifx_sqlda_t));
281 __inSQLDA->desc_occ = sizeof(ifx_sqlda_t);
283 Query::__paramCount = _paramCount;
284 __params = new IFXParam[Query::__paramCount];
285 if (__params == NULL) {
286 __SET_ERROR(SQL::eOutOfMemory);
290 ifx_sqlvar_t* sqlvar = __inSQLDA->sqlvar;
291 for(size_t i = 0; i < Query::__paramCount; i++, sqlvar++) {
292 if (!__params[i].init(this, sqlvar))
299bool IFXQuery::__prepare(const char* _sql, size_t _sqllen,
305 EXEC SQL BEGIN DECLARE SECTION;
306 char* pszConnectionID = conn()->connectionID();
307 char* pszStatementID = (_CONST char*)__statementID.data();
308 char* pszSQL = (_CONST char*)_sql;
309 EXEC SQL END DECLARE SECTION;
311 EXEC SQL SET CONNECTION : pszConnectionID;
313 __SET_ERROR_SQLCODE(SQLCODE);
316 __DCL_ASSERT(SQLCODE == 0);
318 EXEC SQL PREPARE : pszStatementID FROM : pszSQL;
320 __SET_ERROR_SQLCODE(SQLCODE);
324 EXEC SQL DESCRIBE INPUT : pszStatementID INTO __inSQLDA;
326 __SET_ERROR_SQLCODE(SQLCODE);
331 __DCL_TRACE2_N(L"__inSQLDA[%p] sqld[%d]]\n",
332 __inSQLDA, __inSQLDA->sqld);
333 ifx_sqlvar_t* sqlvar = __inSQLDA->sqlvar;
334 for (int2 i = 0; i < __inSQLDA->sqld; i++, sqlvar++) {
335 __DCL_TRACE3_N(L"[%10hs][%2d] sqllen[%4d]\n",
336 rtypname(sqlvar->sqltype), sqlvar->sqltype, sqlvar->sqllen);
341 EXEC SQL DESCRIBE OUTPUT :pszStatementID INTO __outSQLDA;
343 __SET_ERROR_SQLCODE(SQLCODE);
347 __DCL_TRACE1_N(L"stmtType[%ls]\n",
348 __STMT_STRING(SQLCODE == 0 ? SQ_SELECT : SQLCODE));
350 __stmtType = sqlca.sqlcode;
352 __stmtType = SQ_SELECT;
354 switch (__stmtType) {
361 ndebug_free(__outSQLDA);
369 __DCL_TRACE2_N(L"__outSQLDA[%p] sqld[%d]\n", __outSQLDA, __outSQLDA->sqld);
370 if (__outSQLDA->sqld > 0) {
376 if (_paramCount > 0) {
377 if (!initParams(_paramCount))
384bool IFXQuery::__execute()
386 EXEC SQL BEGIN DECLARE SECTION;
387 char* pszConnectionID = conn()->connectionID();
388 char* pszStatementID = (_CONST char*)__statementID.data();
389 char* pszCursorID = (_CONST char*)__cursorID.data();
390 EXEC SQL END DECLARE SECTION;
392 EXEC SQL SET CONNECTION :pszConnectionID;
394 __SET_ERROR_SQLCODE(SQLCODE);
397 __DCL_ASSERT(SQLCODE == 0);
399 //if (__stmtType == SQ_SELECT) {
400 if (__outSQLDA && __outSQLDA->sqld > 0) {
401 if (!__cursorDeclared) {
402 EXEC SQL DECLARE :pszCursorID CURSOR FOR :pszStatementID;
404 __SET_ERROR_SQLCODE(SQLCODE);
407 __cursorDeclared = true;
410 if (__cursorOpened) {
411 EXEC SQL CLOSE :pszCursorID;
413 __SET_ERROR_SQLCODE(SQLCODE);
416 __cursorOpened = false;
420 EXEC SQL OPEN :pszCursorID USING DESCRIPTOR __inSQLDA;
422 EXEC SQL OPEN :pszCursorID;
425 __SET_ERROR_SQLCODE(SQLCODE);
429 __cursorOpened = true;
434 // 2025.05.06 __outSQLDA 조건은 CURSOR로 처리 하므로
435 // 다음 EXEC SQL EXECUTE는 의미가 없다.
436 if (__outSQLDA && __inSQLDA)
437 EXEC SQL EXECUTE :pszStatementID INTO DESCRIPTOR __outSQLDA
438 USING DESCRIPTOR __inSQLDA;
440 EXEC SQL EXECUTE :pszStatementID INTO DESCRIPTOR __outSQLDA;
444 EXEC SQL EXECUTE : pszStatementID USING DESCRIPTOR __inSQLDA;
446 EXEC SQL EXECUTE :pszStatementID;
449 __SET_ERROR_SQLCODE(SQLCODE);
450 Query::__affectedRows = -1;
455 if (__stmtType == SQ_EXECPROC) {
456 for(size_t i = 0; i < Query::__fieldCount; i++) {
457 if (!__fields[i].onAfterFetch())
462 // INSERT, UPDATE, DELETE
463 Query::__affectedRows = sqlca.sqlerrd[2];
466 // INSERT, UPDATE, DELETE
467 Query::__affectedRows = sqlca.sqlerrd[2];
471 for(size_t i = 0; i < Query::__paramCount; i++) {
472 if (!(__params[i].onAfterExecute()))
479bool IFXQuery::__fetch()
481 // SELECT, EXECUTE PROCEDURE
482 __DCL_ASSERT(!eof());
483 __DCL_ASSERT(__outSQLDA && __outSQLDA->sqld > 0);
485 EXEC SQL BEGIN DECLARE SECTION;
486 char* pszCursorID = (_CONST char*)__cursorID.data();
487 EXEC SQL END DECLARE SECTION;
489 EXEC SQL FETCH :pszCursorID USING DESCRIPTOR __outSQLDA;
492 for (size_t i = 0; i < Query::__fieldCount; i++) {
493 if (!__fields[i].onAfterFetch())
498 else if (SQLCODE == SQLNOTFOUND) {
503 __SET_ERROR_SQLCODE(SQLCODE);
507bool IFXQuery::__getField(size_t _index, SQL::Field** _fieldHandleOut)
509 __DCL_ASSERT(Query::__fieldCount > 0);
510 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
511 *_fieldHandleOut = &__fields[_index];
515bool IFXQuery::__getParam(size_t _index, SQL::Param** _paramHandleOut)
517 __DCL_ASSERT(Query::__paramCount > 0);
518 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
519 *_paramHandleOut = &__params[_index];