DCL 4.0
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.ec");
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 EXEC SQL BEGIN DECLARE SECTION;
266 char* pszConnectionID = conn()->connectionID();
267 char* pszStatementID = (_CONST char*)__statementID.data();
268 char* pszCursorID = (_CONST char*)__cursorID.data();
269 EXEC SQL END DECLARE SECTION;
270
271 EXEC SQL SET CONNECTION :pszConnectionID;
272 if (SQLCODE < 0) {
273 __SET_ERROR_SQLCODE(SQLCODE);
274 return false;
275 }
276 __DCL_ASSERT(SQLCODE == 0);
277
278 if (__outSQLDA && __outSQLDA->sqld > 0) {
279 if (!__cursorDeclared) {
280 EXEC SQL DECLARE :pszCursorID CURSOR FOR :pszStatementID;
281 if (SQLCODE < 0) {
282 __SET_ERROR_SQLCODE(SQLCODE);
283 return false;
284 }
285 __cursorDeclared = true;
286 }
287
288 if (__cursorOpened) {
289 EXEC SQL CLOSE :pszCursorID;
290 if (SQLCODE < 0) {
291 __SET_ERROR_SQLCODE(SQLCODE);
292 return false;
293 }
294 __cursorOpened = false;
295 }
296
297 if (__inSQLDA)
298 EXEC SQL OPEN :pszCursorID USING DESCRIPTOR __inSQLDA;
299 else
300 EXEC SQL OPEN :pszCursorID;
301
302 if (SQLCODE < 0) {
303 __SET_ERROR_SQLCODE(SQLCODE);
304 return false;
305 }
306
307 __cursorOpened = true;
308 __eof = false;
309 }
310 else {
311#if 0
312 // 2025.05.06 __outSQLDA 조건은 CURSOR로 처리 하므로
313 // 다음 EXEC SQL EXECUTE는 의미가 없다.
314 if (__outSQLDA && __inSQLDA)
315 EXEC SQL EXECUTE :pszStatementID INTO DESCRIPTOR __outSQLDA
316 USING DESCRIPTOR __inSQLDA;
317 else if (__outSQLDA)
318 EXEC SQL EXECUTE :pszStatementID INTO DESCRIPTOR __outSQLDA;
319 else
320#endif
321 if (__inSQLDA)
322 EXEC SQL EXECUTE :pszStatementID USING DESCRIPTOR __inSQLDA;
323 else
324 EXEC SQL EXECUTE :pszStatementID;
325
326 if (SQLCODE < 0) {
327 __SET_ERROR_SQLCODE(SQLCODE);
328 Query::__affectedRows = -1;
329 return false;
330 }
331
332 // INSERT, UPDATE, DELETE
333 Query::__affectedRows = sqlca.sqlerrd[2];
334 }
335
336 for(size_t i = 0; i < Query::__paramCount; i++) {
337 if (!(__params[i].onAfterExecute()))
338 return false;
339 }
340
341 return true;
342}
343
344bool PgQuery::__fetch()
345{
346 // SELECT, CALL
347 __DCL_ASSERT(!eof());
348 __DCL_ASSERT(__outSQLDA && __outSQLDA->sqld > 0);
349
350 EXEC SQL BEGIN DECLARE SECTION;
351 char* pszCursorID = (_CONST char*)__cursorID.data();
352 EXEC SQL END DECLARE SECTION;
353
354 EXEC SQL FETCH :pszCursorID USING DESCRIPTOR __outSQLDA;
355
356 if (SQLCODE == ECPG_NO_ERROR) {
357#if 0
358 __DCL_TRACE1(L"[%p]\n", __outSQLDA);
359 __DCL_TRACE4(L"[%hs] [%ld] sqln[%d] sqld[%d]\n",
360 __outSQLDA->sqldaid, __outSQLDA->sqldabc,
361 __outSQLDA->sqln, __outSQLDA->sqld
362 );
363 for (int i = 0; i < __outSQLDA->sqld; i++) {
364 sqlvar_t* p = &(__outSQLDA->sqlvar[i]);
365 __DCL_TRACE4(L"[%19ls] [%hd] [%p] [%p]\n",
366 __dataTypeName(p), p->sqllen, p->sqldata, p->sqlind
367 );
368 }
369#endif
370 sqlvar_t* sqlvar = __outSQLDA->sqlvar;
371 for (size_t i = 0; i < Query::__fieldCount; i++) {
372 if (!__fields[i].onAfterFetch(sqlvar++))
373 return false;
374 }
375 return true;
376 }
377 else if (SQLCODE == ECPG_NOT_FOUND) {
378 Query::__eof = true;
379 return true;
380 }
381
382 __SET_ERROR_SQLCODE(SQLCODE);
383 return false;
384}
385
386bool PgQuery::__getField(size_t _index, SQL::Field** _fieldHandleOut)
387{
388 __DCL_ASSERT(Query::__fieldCount > 0);
389 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
390 *_fieldHandleOut = &__fields[_index];
391 return true;
392}
393
394bool PgQuery::__getParam(size_t _index, SQL::Param** _paramHandleOut)
395{
396 __DCL_ASSERT(Query::__paramCount > 0);
397 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
398 *_paramHandleOut = &__params[_index];
399 return true;
400}
401
402__DCL_END_NAMESPACE