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