DCL 3.7.4
Loading...
Searching...
No Matches
OciQuery.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <oci.h>
4
5#if defined(_AIX) || defined(__sun__)
6 #include <alloca.h>
7#endif
8#include <stdlib.h> // malloc, free, alloca
9#include <string.h> // memset
10
11#include <dcl/Object.h>
12#if __DCL_HAVE_ALLOC_DEBUG
13#undef __DCL_ALLOC_LEVEL
14#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
15#endif
16
17#include <dcl/size_t.h>
18#include <dcl/SQLCore.h>
19
20#include "OciConnection.h"
21#include "OciQuery.h"
22#include "OciField.h"
23#include "OciParam.h"
24
25#define __TRACE_THIS 0
26#if __TRACE_THIS
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
32#define __DCL_TRACE5_N __DCL_TRACE5
33#define __DCL_TRACE6_N __DCL_TRACE6
34#else
35#define __DCL_TRACE0_N(fmt)
36#define __DCL_TRACE1_N(fmt, arg)
37#define __DCL_TRACE2_N(fmt, arg1, arg2)
38#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
39#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
40#define __DCL_TRACE5_N(fmt, arg1, arg2, arg3, arg4, arg5)
41#define __DCL_TRACE6_N(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
42#endif
43
44#undef __THIS_FILE__
45static const char_t __THIS_FILE__[] = __T("dcl/sql/OciQuery.cpp");
46
47__DCL_BEGIN_NAMESPACE
48
49#define __SET_ERROR_HANDLE(_error, _status, _OCIError) \
50 conn()->setErrorHandle(_error, _status, _OCIError, \
51 true, __THIS_FILE__, __LINE__)
52#define __SET_ERROR_NORESET(_error, _status, _OCIError) \
53 conn()->setErrorHandle(_error, _status, _OCIError, \
54 false, __THIS_FILE__, __LINE__)
55#define __SET_ERROR_MSG(_msg) \
56 conn()->setErrorMessage(_msg, __THIS_FILE__, __LINE__)
57
59
61 : Query(_connHandle)
62{
63 Query::__placeholder = L':';
64
65 __stmt = NULL;
66 __stmtType = __OCI_STMT_TYPE_UNKNOWN;
67
68 __fieldsBuffer = NULL;
69
70 __params = NULL;
71 __fields = NULL;
72}
73
75{
76#ifdef __DCL_DEBUG
77 if (!reset()) {
78 char buf[256];
79 size_t buflen = sizeof(buf) - 1;
80 bool b = conn()->__getErrorMessage(buf, &buflen);
81 buf[b ? buflen : 0] = '\0';
82 __DCL_TRACE1(L"Warning! Query reset error! %hs\n", buf);
83 }
84#else
85 (void)reset();
86#endif
87}
88
90{
91 delete this;
92}
93
95{
96 Query::__eof = true;
97 Query::__affectedRows = -1;
99
100 if (__fields) {
101 __DCL_ASSERT(Query::__fieldCount > 0);
102 delete[] __fields;
103 __fields = NULL;
104 Query::__fieldCount = 0;
105 }
106
107 if (__params) {
108 __DCL_ASSERT(Query::__paramCount > 0);
109 delete[] __params;
110 __params = NULL;
111 Query::__paramCount = 0;
112 }
113
114 if (__fieldsBuffer) {
115 free(__fieldsBuffer);
117 }
118
119 if (__stmt) {
120 sword status = OCIStmtRelease(
121 __stmt, // OCIStmt *stmthp
122 conn()->errorHandle(), // OCIError *errhp
123 NULL, // const OraText *key
124 0, // ub4 keylen
125 OCI_DEFAULT // ub4 mode
126 );
127 if (status != OCI_SUCCESS) {
129 return false;
130 }
131 __stmt = NULL;
132 }
133
134 return true;
135}
136
137bool OciQuery::initParams(size_t _paramCount)
138{
140 && (_paramCount > 0)
141 && (Query::__paramCount == 0)
142 && (__params == NULL)
143 );
144
145#if defined(__DCL_DEBUG) && 1
146 ub4 bindCount = 0;
147 ub4 size = sizeof(bindCount);
148 sword status = OCIAttrGet(
149 __stmt, // const void *trgthndlp
150 OCI_HTYPE_STMT, // ub4 trghndltyp
151 &bindCount, // void *attributep
152 &size, // ub4 *sizep
153 OCI_ATTR_BIND_COUNT, // ub4 attrtype
154 conn()->errorHandle() // OCIError *errhp
155 );
156 __DCL_ASSERT(size == sizeof(bindCount));
157 if (status != OCI_SUCCESS) {
158 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
159 return false;
160 }
161 __DCL_ASSERT(bindCount == _paramCount);
162#endif
163
164 Query::__paramCount = _paramCount;
165 __params = new OciParam[Query::__paramCount];
166 if (__params == NULL) {
168 return false;
169 }
170
171 for(ub4 i = 0; i < Query::__paramCount; i++) {
172 if (!__params[i].init(this, i + 1))
173 return false;
174 }
175
176 return true;
177}
178
179typedef struct __TYPESIZE {
180 ub2 sqlt;
183
185{
187 && (Query::__fieldCount == 0)
188 && (__fields == NULL)
189 && (__fieldsBuffer == NULL)
190 );
191
192 ub4 fieldCount = 0;
193 ub4 size = sizeof(fieldCount);
194 sword status = OCIAttrGet(
195 __stmt, // const void *trgthndlp
196 OCI_HTYPE_STMT, // ub4 trghndltyp
197 &fieldCount, // void *attributep
198 &size, // ub4 *sizep
199 OCI_ATTR_PARAM_COUNT, // ub4 attrtype
200 conn()->errorHandle() // OCIError *errhp
201 );
202 __DCL_ASSERT(size == sizeof(fieldCount));
203 if (status != OCI_SUCCESS) {
204 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
205 return false;
206 }
207
208 TYPESIZE* ts = (TYPESIZE*)alloca(sizeof(TYPESIZE) * fieldCount);
209 for (ub4 i = 0; i < fieldCount; i++) {
210 OCIParam* param = NULL;
211 status = OCIParamGet(
212 __stmt, // const void *hndlp
213 OCI_HTYPE_STMT, // ub4 htype
214 conn()->errorHandle(), // OCIError *errhp
215 (dvoid**)&param, // void **parmdpp
216 i + 1 // ub4 pos
217 );
218 if (status != OCI_SUCCESS) {
219 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
220 return false;
221 }
222
223 ub2 sqlt = 0;
224 size = sizeof(sqlt);
225 status = OCIAttrGet(
226 param, // const void *trgthndlp
227 OCI_DTYPE_PARAM, // ub4 trghndltyp
228 &sqlt, // void *attributep
229 &size, // ub4 *sizep
230 OCI_ATTR_DATA_TYPE, // ub4 attrtype
231 conn()->errorHandle() // OCIError *errhp
232 );
233 __DCL_ASSERT(size == sizeof(sqlt));
234 if (status != OCI_SUCCESS) {
235 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
236 return false;
237 }
238
239 // ub2 dataSize 이었었는데, Assert failed 되었다.
240 // 반환값의 범위는 0 ~ 4000이다.
241 ub4 dataSize = 0;
242 size = sizeof(dataSize);
243 status = OCIAttrGet(
244 param, // const void *trgthndlp
245 OCI_DTYPE_PARAM, // ub4 trghndltyp
246 &dataSize, // void *attributep
247 &size, // ub4 *sizep
248 OCI_ATTR_DATA_SIZE, // ub4 attrtype
249 conn()->errorHandle() // OCIError *errhp
250 );
251 __DCL_ASSERT(size == sizeof(dataSize));
252 if (status != OCI_SUCCESS) {
253 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
254 return false;
255 }
256
257 ts[i].sqlt = sqlt;
258 ts[i].buflen = OciData::__TYPE_SIZE(ts[i].sqlt, dataSize);
259 __DCL_TRACE5_N(L"Field [%2d] size [%6d %6d] type [%3d %ls]\n",
260 i + 1, dataSize, ts[i].buflen,
261 ts[i].sqlt, OciData::__TYPE_NAME(ts[i].sqlt)
262 );
263 }
264
265 // __fieldsBuffer에 적용할, 레코드 버퍼 크기를 계산한다.
266 size_t offset = 0;
267 for (ub4 i = 0; i < fieldCount; i++) {
268 offset = OciData::__TYPE_ALIGN(offset, ts[i].sqlt);
269 __DCL_TRACE5_N(L"Field [%2d] offset [%6zd %6d] type [%3d %ls]\n",
270 i + 1, offset, ts[i].buflen, ts[i].sqlt, OciData::__TYPE_NAME(ts[i].sqlt));
271 offset += ts[i].buflen;
272 }
273
274 __DCL_TRACE1_N(L"outBuffer [%zd]\n", offset);
275 // Oracle에서 __TYPE_SIZE(field) == 0인 경우는 없다.
276 __fieldsBuffer = malloc(offset);
277 if (__fieldsBuffer == NULL) {
279 return false;
280 }
281
282 Query::__fieldCount = fieldCount;
283 __fields = new OciField[Query::__fieldCount];
284 if (__fields == NULL) {
286 return false;
287 }
288
289 offset = 0;
290 for (ub4 i = 0; i < Query::__fieldCount; i++) {
291 offset = OciData::__TYPE_ALIGN(offset, ts[i].sqlt);
292 char* buf = (char*)__fieldsBuffer + offset;
293 //__DCL_TRACE3_N(L"offset [%4zd %4d] [%p]\n", offset, ts[i].buflen, buf);
294 if (!(__fields[i].init(this, i + 1, ts[i].sqlt,
295 buf, ts[i].buflen))
296 ) {
297 return false;
298 }
299 offset += ts[i].buflen;
300 }
301
302 return true;
303}
304
306 const char* _sql, size_t _sqllen,
307 size_t _paramCount
308)
309{
310 if (!reset()) {
311 return false;
312 }
313
314 sword status = OCIStmtPrepare2(
315 conn()->svcHandle(), // OCISvcCtx *svchp
316 &__stmt, // OCIStmt **stmthp
317 conn()->errorHandle(), // OCIError *errhp
318 (const text* )_sql, // const OraText *stmttext
319 (ub4)_sqllen, // ub4 stmt_len
320 NULL, // const OraText *key
321 0, // ub4 keylen
322 OCI_NTV_SYNTAX, // ub4 language
323 OCI_DEFAULT // ub4 mode
324 );
325 if (status != OCI_SUCCESS) {
326 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
327 return false;
328 }
329
330 ub4 size = sizeof(__stmtType);
331 status = OCIAttrGet(
332 __stmt, // const void *trgthndlp
333 OCI_HTYPE_STMT, // ub4 trghndltyp
334 &__stmtType, // void *attributep
335 &size, // ub4 *sizep
336 OCI_ATTR_STMT_TYPE, // ub4 attrtype
337 conn()->errorHandle() // OCIError *errhp
338 );
339 __DCL_ASSERT(size == sizeof(__stmtType));
340 if (status != OCI_SUCCESS) {
341 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
342 return false;
343 }
344
345 if (_paramCount > 0) {
346 if (!initParams(_paramCount))
347 return false;
348 }
349
350 return true;
351}
352
354{
355 for(size_t i = 0; i < Query::__paramCount; i++) {
356 if (!__params[i].doBind())
357 return false;
358 }
359
360 sword status = OCIStmtExecute(
361 conn()->svcHandle(), // OCISvcCtx *svchp
362 __stmt, // OCIStmt *stmtp
363 conn()->errorHandle(), // OCIError *errhp
364 (__stmtType == OCI_STMT_SELECT) ? 0 : 1, // ub4 iters
365 0, // ub4 rowoff
366 NULL, // const OCISnapshot *snap_in
367 NULL, // OCISnapshot *snap_out
368 OCI_DEFAULT // ub4 mode
369 );
370 if (status != OCI_SUCCESS) {
371 __SET_ERROR_NORESET(SQL::eServerError, status, conn()->errorHandle());
372 return false;
373 }
374
375 // OCI의 경우 stmt execute 후 fields를 결정할 수 있다.
376 if (__stmtType == OCI_STMT_SELECT) {
377 if (!initFields()) {
378 return false;
379 }
380
381 Query::__eof = false;
382 }
383
384 for(size_t i = 0; i < Query::__paramCount; i++) {
385 if (!__params[i].onAfterExecute()) {
386 return false;
387 }
388 }
389
390 if (__stmtType == OCI_STMT_UPDATE
391 || __stmtType == OCI_STMT_INSERT
392 || __stmtType == OCI_STMT_DELETE) {
393
394 ub8 rowCount = 0;
395 ub4 size = sizeof(rowCount);
396 status = OCIAttrGet(
397 __stmt, // const void *trgthndlp
398 OCI_HTYPE_STMT, // ub4 trghndltyp
399 &rowCount, // void *attributep
400 &size, // ub4 *sizep
401 OCI_ATTR_UB8_ROW_COUNT, // ub4 attrtype
402 conn()->errorHandle() // OCIError *errhp
403 );
404 __DCL_ASSERT(size == sizeof(rowCount));
405 if (status != OCI_SUCCESS) {
406 __SET_ERROR_HANDLE(SQL::eServerError, status, conn()->errorHandle());
407 return false;
408 }
409 Query::__affectedRows = rowCount;
410 }
411 return true;
412}
413
415{
416 __DCL_ASSERT(!Query::__eof);
417 sword status = OCIStmtFetch2(
418 __stmt, // OCIStmt *stmthp
419 conn()->errorHandle(), // OCIError *errhp
420 1, // ub4 nrows
421 OCI_FETCH_NEXT, // ub2 orientation
422 0, // sb4 fetchOffset
423 OCI_DEFAULT // ub4 mode
424 );
425 switch (status) {
426 case OCI_NO_DATA: {
427 Query::__eof = true;
428 return true;
429 }
430 case OCI_SUCCESS_WITH_INFO: {
431 // 2026-02-28
432 // 19.30.0.0.0 버전 AIX에서 처음 발견되었다.
433 // 구체적인 내용을 확인해야 한다.
434 // 아마도 ODBC의 경우와 유사할 것으로 추정된다.
435 }
436 case OCI_SUCCESS: {
437 for (size_t i = 0; i < Query::__fieldCount; i++) {
438 if (!__fields[i].onAfterFetch())
439 return false;
440 }
441 return true;
442 }
443 default: {
444 ;
445 }
446 }
447
448 __SET_ERROR_NORESET(SQL::eServerError, status, conn()->errorHandle());
449 return false;
450}
451
452bool OciQuery::__getField(size_t _index, SQL::Field** _fieldHandleOut)
453{
454 __DCL_ASSERT(Query::__fieldCount > 0);
455 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
456 *_fieldHandleOut = &__fields[_index];
457 return true;
458}
459
460bool OciQuery::__getParam(size_t _index, SQL::Param** _paramHandleOut)
461{
462 __DCL_ASSERT(Query::__paramCount > 0);
463 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
464 *_paramHandleOut = &__params[_index];
465 return true;
466}
467
468__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
wchar_t char_t
Definition Config.h:247
#define __DCL_TRACE1_N(fmt, arg)
#define __SET_ERROR_HANDLE(_SQLCODE)
#define __DCL_TRACE5_N(fmt, arg1, arg2, arg3, arg4, arg5)
Definition ODBCQuery.cpp:44
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:245
#define __T(str)
Definition Object.h:60
#define __SET_ERROR_NORESET(_error, _status, _OCIError)
Definition OciQuery.cpp:52
struct __TYPESIZE TYPESIZE
#define __OCI_STMT_TYPE_UNKNOWN
Definition OciQuery.h:6
static const wchar_t * __TYPE_NAME(ub2 _sqlt)
Definition OciData.cpp:924
static size_t __TYPE_ALIGN(size_t _offset, ub2 _sqlt)
Definition OciData.cpp:997
static ub4 __TYPE_SIZE(ub2 _sqlt, ub4 _size)
Definition OciData.cpp:952
virtual bool __fetch()
Definition OciQuery.cpp:414
bool initFields()
Definition OciQuery.cpp:184
virtual void __destroy()
Definition OciQuery.cpp:89
virtual bool __getParam(size_t _index, SQL::Param **_paramHandleOut)
Definition OciQuery.cpp:460
OciQuery(OciConnection *_connHandle)
virtual bool __getField(size_t _index, SQL::Field **_fieldHandleOut)
Definition OciQuery.cpp:452
void * __fieldsBuffer
Definition OciQuery.h:23
ub2 __stmtType
Definition OciQuery.h:21
OciField * __fields
Definition OciQuery.h:26
OCIStmt * __stmt
Definition OciQuery.h:20
virtual bool __execute()
Definition OciQuery.cpp:353
OciParam * __params
Definition OciQuery.h:25
virtual bool __prepare(const char *_sql, size_t _sqllen, size_t _paramCount)
Definition OciQuery.cpp:305
bool initParams(size_t _paramCount)
Definition OciQuery.cpp:137
bool reset()
Definition OciQuery.cpp:94
virtual ~OciQuery()
Definition OciQuery.cpp:74
@ eOutOfMemory
Definition SQLCore.h:24
@ eServerError
Definition SQLCore.h:21