DCL 3.7.4
Loading...
Searching...
No Matches
PeQuery.pgc
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <stdlib.h> // malloc, free
4
5#include <ecpgtype.h>
6#include <sqlda.h>
7#include <pgtypes_numeric.h>
8#include <pgtypes_date.h>
9#include <pgtypes_interval.h>
10#include <pgtypes_timestamp.h>
11
12#include <dcl/Object.h>
13#if __DCL_HAVE_ALLOC_DEBUG
14#undef __DCL_ALLOC_LEVEL
15#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
16#endif
17
18#include <dcl/Numeric.h>
19#include <dcl/SQLCore.h>
20
21#include "PeConnection.h"
22#include "PeQuery.h"
23#include "PeField.h"
24#include "PeParam.h"
25
26#undef __THIS_FILE__
27static const char_t __THIS_FILE__[] = __T("dcl/sql/PeQuery.pgc");
28
29__DCL_BEGIN_NAMESPACE
30
31#define __SET_ERROR(_error) \
32 conn()->setErrorHandle(_error, 0L, __THIS_FILE__, __LINE__)
33#define __SET_ERROR_HANDLE(_SQLCODE) \
34 conn()->setErrorHandle(SQL::eServerError, _SQLCODE, __THIS_FILE__, __LINE__)
35#define __SET_ERROR_MSG(_message) \
36 conn()->setErrorMessage(_message, __THIS_FILE__, __LINE__)
37
38IMPLEMENT_CLASSINFO(PeQuery, SQL::Query)
39
40PeQuery::PeQuery(PeConnection* pConnection)
41 : Query(pConnection)
42{
43 ByteString strID;
44 strID = ByteString::format("%zx", (size_t)this);
45 __statementID = "stmt_" + strID;
46 __cursorID = "curs_" + strID;
47
48 __inSQLDA = NULL;
49 __outSQLDA = NULL;
50
51 __cursorOpened = false;
52 __cursorDeclared = false;
53
54 __fields = NULL;
55 __params = NULL;
56}
57
58PeQuery::~PeQuery()
59{
60#ifdef __DCL_DEBUG
61 if (!reset()) {
62 char buf[256];
63 size_t buflen = sizeof(buf) - 1;
64 bool b = conn()->__getErrorMessage(buf, &buflen);
65 buf[b ? buflen : 0] = '\0';
66 __DCL_TRACE1(L"Warning! Query reset error! %hs\n", buf);
67 }
68#else
69 (void)reset();
70#endif
71}
72
73void PeQuery::__destroy()
74{
75// cerr << "PeQuery::destory\n";
76 delete this;
77}
78
79bool PeQuery::reset()
80{
81 bool r = true;
82
83 EXEC SQL BEGIN DECLARE SECTION;
84 char* connID = conn()->connectionID();
85 char* stmtID = (_CONST char*)__statementID.data();
86 char* cursorID = (_CONST char*)__cursorID.data();
87 EXEC SQL END DECLARE SECTION;
88
89 EXEC SQL SET CONNECTION :connID;
90 if (r && SQLCODE < 0) {
91 __SET_ERROR_HANDLE(SQLCODE);
92 return false;
93 }
94 __DCL_ASSERT(SQLCODE == 0);
95
96 if (__cursorOpened) {
97 __cursorOpened = false;
98 EXEC SQL CLOSE :cursorID;
99 if (r && SQLCODE < 0) {
100 __SET_ERROR_HANDLE(SQLCODE);
101 r = false;
102 }
103 }
104
105 if (__cursorDeclared) {
106 __cursorDeclared = false;
107#if 0
108 EXEC SQL FREE :cursorID;
109 if (r && SQLCODE < 0) {
110 __SET_ERROR_HANDLE(SQLCODE);
111 r = false;
112 }
113#endif
114 }
115
116 if (__outSQLDA) {
117 EXEC SQL FREE :stmtID;
118 if (r && SQLCODE < 0) {
119 __SET_ERROR_HANDLE(SQLCODE);
120 r = false;
121 }
122 }
123
124 Query::__eof = true;
125 Query::__affectedRows = -1;
126
127 // clear fields
128 if (__fields) {
129 __DCL_ASSERT(Query::__fieldCount > 0);
130 delete[] __fields;
131 __fields = NULL;
132 Query::__fieldCount = 0;
133 }
134
135 // clear binds
136 if (__params) {
137 __DCL_ASSERT(Query::__paramCount > 0);
138 delete[] __params;
139 __params = NULL;
140 Query::__paramCount = 0;
141 }
142
143 if (__outSQLDA) {
144 // __outSQLDA는 Informix API에서 할당됨.
145 __outSQLDA = NULL;
146 }
147
148 if (__inSQLDA) {
149 free(__inSQLDA);
150 __inSQLDA = NULL;
151 }
152
153 return r;
154}
155
156bool PeQuery::initFields()
157{
158 __DCL_ASSERT(
159 (__fields == NULL)
160 && (Query::__fieldCount == 0)
161 && (__outSQLDA != NULL)
162 && (__outSQLDA->sqld > 0)
163 );
164
165 Query::__fieldCount = __outSQLDA->sqld;
166 __fields = new PeField[Query::__fieldCount];
167 if (__fields == NULL) {
168 __SET_ERROR(SQL::eOutOfMemory);
169 return false;
170 }
171
172 sqlvar_t* sqlvar = __outSQLDA->sqlvar;
173 for(size_t i = 0; i < Query::__fieldCount; i++, sqlvar++) {
174 if (!__fields[i].init(this, sqlvar))
175 return false;
176 }
177
178 return true;
179}
180
181bool PeQuery::initParams(size_t _paramCount)
182{
183 __DCL_ASSERT((__params == NULL)
184 && (Query::__paramCount == 0)
185 && (__outSQLDA != NULL)
186 );
187
188 size_t nAllocSize = sizeof(sqlda_t)
189 + (sizeof(sqlvar_t) * _paramCount);
190 __inSQLDA = (sqlda_t*)malloc(nAllocSize);
191 if (__inSQLDA == NULL) {
192 __SET_ERROR(SQL::eOutOfMemory);
193 return false;
194 }
195 memset(__inSQLDA, 0, nAllocSize);
196 __inSQLDA->sqln = (short)_paramCount;
197
198 Query::__paramCount = _paramCount;
199 __params = new PeParam[Query::__paramCount];
200 if (__params == NULL) {
201 __SET_ERROR(SQL::eOutOfMemory);
202 return false;
203 }
204
205 sqlvar_t* sqlvar = __inSQLDA->sqlvar;
206 for(size_t i = 0; i < Query::__paramCount; i++, sqlvar++) {
207 if (!__params[i].init(this, sqlvar))
208 return false;
209 }
210
211 return true;
212}
213
214const wchar_t* __dataTypeName(const sqlvar_t* _sqlvar);
215
216bool PeQuery::__prepare(const char* _sql, size_t _sqllen,
217 size_t _paramCount)
218{
219 if(!reset())
220 return false;
221
222 EXEC SQL BEGIN DECLARE SECTION;
223 char* connID = conn()->connectionID();
224 char* stmtID = (_CONST char*)__statementID.data();
225 char* sql = (_CONST char*)_sql;
226 EXEC SQL END DECLARE SECTION;
227
228 EXEC SQL SET CONNECTION :connID;
229 if (SQLCODE < 0) {
230 __SET_ERROR_HANDLE(SQLCODE);
231 return false;
232 }
233 __DCL_ASSERT(SQLCODE == 0);
234
235 EXEC SQL PREPARE :stmtID FROM :sql;
236
237 if (SQLCODE < 0) {
238 __SET_ERROR_HANDLE(SQLCODE);
239 return false;
240 }
241
242 EXEC SQL DESCRIBE :stmtID INTO __outSQLDA;
243
244 if (SQLCODE < 0) {
245 __SET_ERROR_HANDLE(SQLCODE);
246 return false;
247 }
248
249 if (__outSQLDA) {
250#if 0
251 __DCL_TRACE1(L"[%p]\n", __outSQLDA);
252 __DCL_TRACE4(L"[%hs] [%ld] sqln[%d] sqld[%d]\n",
253 __outSQLDA->sqldaid, __outSQLDA->sqldabc,
254 __outSQLDA->sqln, __outSQLDA->sqld
255 );
256 for (int i = 0; i < __outSQLDA->sqld; i++) {
257 sqlvar_t* p = &(__outSQLDA->sqlvar[i]);
258 __DCL_TRACE4(L"[%19ls] [%hd] [%p] [%p]\n",
259 __dataTypeName(p), p->sqllen, p->sqldata, p->sqlind
260 );
261 }
262#endif
263 if (__outSQLDA->sqld > 0) {
264 if (!initFields())
265 return false;
266 }
267 }
268
269 if (_paramCount > 0) {
270 if (!initParams(_paramCount))
271 return false;
272 }
273
274 return true;
275}
276
277bool PeQuery::__execute()
278{
279#ifdef __DCL_DEBUG
280 for (size_t i = 0; i < Query::__paramCount; i++) {
281 __params[i].onBeforeExecute();
282 }
283#endif
284
285 EXEC SQL BEGIN DECLARE SECTION;
286 char* connID = conn()->connectionID();
287 char* stmtID = (_CONST char*)__statementID.data();
288 char* cursorID = (_CONST char*)__cursorID.data();
289 EXEC SQL END DECLARE SECTION;
290
291 EXEC SQL SET CONNECTION :connID;
292 if (SQLCODE < 0) {
293 __SET_ERROR_HANDLE(SQLCODE);
294 return false;
295 }
296 __DCL_ASSERT(SQLCODE == 0);
297
298 if (__outSQLDA && __outSQLDA->sqld > 0) {
299 if (!__cursorDeclared) {
300 EXEC SQL DECLARE :cursorID CURSOR FOR :stmtID;
301 if (SQLCODE < 0) {
302 __SET_ERROR_HANDLE(SQLCODE);
303 return false;
304 }
305 __cursorDeclared = true;
306 }
307
308 if (__inSQLDA)
309 EXEC SQL OPEN :cursorID USING DESCRIPTOR __inSQLDA;
310 else
311 EXEC SQL OPEN :cursorID;
312
313 if (SQLCODE < 0) {
314 __SET_ERROR_HANDLE(SQLCODE);
315 return false;
316 }
317
318 __cursorOpened = true;
319 __eof = false;
320 }
321 else {
322#if 0
323 // 2025.05.06 __outSQLDA 조건은 CURSOR로 처리 하므로
324 // 다음 EXEC SQL EXECUTE는 의미가 없다.
325 if (__outSQLDA && __inSQLDA)
326 EXEC SQL EXECUTE :stmtID INTO DESCRIPTOR __outSQLDA
327 USING DESCRIPTOR __inSQLDA;
328 else if (__outSQLDA)
329 EXEC SQL EXECUTE :stmtID INTO DESCRIPTOR __outSQLDA;
330 else
331#endif
332 if (__inSQLDA)
333 EXEC SQL EXECUTE :stmtID USING DESCRIPTOR __inSQLDA;
334 else
335 EXEC SQL EXECUTE :stmtID;
336
337 if (SQLCODE < 0) {
338 __SET_ERROR_HANDLE(SQLCODE);
339 Query::__affectedRows = -1;
340 return false;
341 }
342
343 // INSERT, UPDATE, DELETE
344 Query::__affectedRows = sqlca.sqlerrd[2];
345 }
346
347 for(size_t i = 0; i < Query::__paramCount; i++) {
348 if (!(__params[i].onAfterExecute()))
349 return false;
350 }
351
352 return true;
353}
354
355bool PeQuery::__fetch()
356{
357 // SELECT, CALL
358 __DCL_ASSERT(!eof());
359 __DCL_ASSERT(__outSQLDA && __outSQLDA->sqld > 0);
360
361 EXEC SQL BEGIN DECLARE SECTION;
362 char* connID = conn()->connectionID();
363 char* cursorID = (_CONST char*)__cursorID.data();
364 EXEC SQL END DECLARE SECTION;
365
366 EXEC SQL SET CONNECTION :connID;
367 if (SQLCODE < 0) {
368 __SET_ERROR_HANDLE(SQLCODE);
369 return false;
370 }
371 __DCL_ASSERT(SQLCODE == 0);
372
373 EXEC SQL FETCH :cursorID USING DESCRIPTOR __outSQLDA;
374
375 if (SQLCODE == ECPG_NO_ERROR) {
376#if 0
377 __DCL_TRACE1(L"[%p]\n", __outSQLDA);
378 __DCL_TRACE4(L"[%hs] [%ld] sqln[%d] sqld[%d]\n",
379 __outSQLDA->sqldaid, __outSQLDA->sqldabc,
380 __outSQLDA->sqln, __outSQLDA->sqld
381 );
382 for (int i = 0; i < __outSQLDA->sqld; i++) {
383 sqlvar_t* p = &(__outSQLDA->sqlvar[i]);
384 __DCL_TRACE4(L"[%19ls] [%hd] [%p] [%p]\n",
385 __dataTypeName(p), p->sqllen, p->sqldata, p->sqlind
386 );
387 }
388#endif
389 sqlvar_t* sqlvar = __outSQLDA->sqlvar;
390 for (size_t i = 0; i < Query::__fieldCount; i++) {
391 if (!__fields[i].onAfterFetch(sqlvar++))
392 return false;
393 }
394 return true;
395 }
396 else if (SQLCODE == ECPG_NOT_FOUND) {
397 Query::__eof = true;
398 if (__cursorOpened) {
399 __cursorOpened = false;
400 EXEC SQL CLOSE :cursorID;
401 if (SQLCODE < 0) {
402 __SET_ERROR_HANDLE(SQLCODE);
403 return false;
404 }
405 }
406 return true;
407 }
408
409 __SET_ERROR_HANDLE(SQLCODE);
410 return false;
411}
412
413bool PeQuery::__getField(size_t _index, SQL::Field** _fieldHandleOut)
414{
415 __DCL_ASSERT(Query::__fieldCount > 0);
416 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
417 *_fieldHandleOut = &__fields[_index];
418 return true;
419}
420
421bool PeQuery::__getParam(size_t _index, SQL::Param** _paramHandleOut)
422{
423 __DCL_ASSERT(Query::__paramCount > 0);
424 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
425 *_paramHandleOut = &__params[_index];
426 return true;
427}
428
429__DCL_END_NAMESPACE