DCL 3.7.4
Loading...
Searching...
No Matches
OciConnection.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <oci.h>
4
5#include <ctype.h> // isspace
6#include <string.h> // strncpy, strlen
7
8#include <dcl/Object.h>
9#if __DCL_HAVE_ALLOC_DEBUG
10#undef __DCL_ALLOC_LEVEL
11#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
12#endif
13
14#include <dcl/Regex.h>
15#include <dcl/SQLCore.h>
16
17#include "OciConnection.h"
18#include "OciQuery.h"
19
20#define __TRACE_THIS 0
21#if __TRACE_THIS
22#define __DCL_TRACE0_N __DCL_TRACE0
23#define __DCL_TRACE1_N __DCL_TRACE1
24#define __DCL_TRACE2_N __DCL_TRACE2
25#define __DCL_TRACE3_N __DCL_TRACE3
26#define __DCL_TRACE4_N __DCL_TRACE4
27#else
28#define __DCL_TRACE0_N(fmt)
29#define __DCL_TRACE1_N(fmt, arg)
30#define __DCL_TRACE2_N(fmt, arg1, arg2)
31#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
32#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
33#endif
34
35#undef __THIS_FILE__
36static const char_t __THIS_FILE__[] = __T("dcl/sql/OciConnection.cpp");
37
38__DCL_BEGIN_NAMESPACE
39
40#define __SET_ERROR_HANDLE(_error, status, _OCIError) \
41 setErrorHandle(_error, status, _OCIError, \
42 true, __THIS_FILE__, __LINE__)
43#define __SET_ERROR_MSG(_msg) \
44 setErrorMessage(_msg, __THIS_FILE__, __LINE__)
45
47
48OciConnection::OciConnection(const wchar_t* _serverTitle)
49 : Connection(_serverTitle)
50{
51 Connection::__canTransact = true;
52
53 __lastStatus = OCI_SUCCESS;
54 __lastError = NULL;
55
56 __env = NULL;
57 __error = NULL;
58 __error2 = NULL;
59
60 __server = NULL;
61 __svcctx = NULL;
62 __session = NULL;
63 __trans = NULL;
64
65 __serverAttached = false;
66 __sessionStarted = false;
67}
68
70{
71 sword status = OCI_SUCCESS;
72 if (__sessionStarted) {
73 __DCL_TRACE0_N(L"Warning!! The connection was not closed\n");
74 close();
75 }
76
77 if (__error) {
78 status = OCIHandleFree(__error, OCI_HTYPE_ERROR);
79 if (status != OCI_SUCCESS) {
80 __DCL_TRACE0_N(L"OCIHandleFree Fail! : __error\n");
81 }
82 __error = NULL;
83 }
84
85 if (__env) {
86 status = OCIHandleFree(__env, OCI_HTYPE_ENV);
87 if (status != OCI_SUCCESS) {
88 __DCL_TRACE0_N(L"OCIHandleFree Fail! : __env\n");
89 }
90 __env = NULL;
91 }
92}
93
95{
96 delete this;
97}
98
99/*
100 _conns 에 가능한 property
101 USER,
102 PASSWORD,
103 DATABASE,
104 MODE
105*/
106
107bool OciConnection::__open(const char* _conns, size_t _connlen)
108{
109 ListedByteStringToByteStringMap map;
110 Connection::splitConnStr(_conns, _connlen, map);
111
112 ByteString _DATABASE = map["DATABASE"];
113 ByteString _USER = map["USER"];
114 ByteString _PASSWORD = map["PASSWORD"];
115 ByteString _MODE = map["MODE"];
116
117 ub4 operationMode = OCI_DEFAULT;
118 if (!_MODE.isEmpty()) {
119 if (!_MODE.compareNoCase("SYSDBA"))
120 operationMode = OCI_SYSDBA;
121 else if (!_MODE.compareNoCase("SYSOPER"))
122 operationMode = OCI_SYSOPER;
123 else {
125 return false;
126 }
127 }
128
129 if (_USER.isEmpty()) {
131 return false;
132 }
133
134 for ( ; ; ) {
135 sword status = OCI_SUCCESS;
136 // __env, __error은 ~OciConnection에서 OCIHandleFree한다.
137 // close후 다시 open할 수 있다.
138 if (!__env) {
139 status = OCIEnvCreate(
140 &__env, // OCIEnv **envhpp
141 OCI_ENV_NO_MUTEX // ub4 mode
142 | OCI_THREADED | OCI_OBJECT,
143 NULL, // const void *ctxp
144 NULL, // const void *(*malocfp)
145 NULL, // const void *(*ralocfp)
146 NULL, // const void (*mfreefp)
147 0, // size_t xtramemsz
148 NULL // void **usrmempp
149 );
150 if (status != OCI_SUCCESS) {
152 break; // goto __on_error;
153 }
154 }
155
156 if (!__error) {
157 status = HandleAlloc((void**)&__error, OCI_HTYPE_ERROR);
158 if (status != OCI_SUCCESS) {
160 break; // goto __on_error;
161 }
162 }
163
164 status = HandleAlloc((void**)&__error2, OCI_HTYPE_ERROR);
165 if (status != OCI_SUCCESS) {
167 break; // goto __on_error;
168 }
169
170 status = HandleAlloc((void**)&__server, OCI_HTYPE_SERVER);
171 if (status != OCI_SUCCESS) {
173 break; // goto __on_error;
174 }
175
176 status = HandleAlloc((void**)&__svcctx, OCI_HTYPE_SVCCTX);
177 if (status != OCI_SUCCESS) {
179 break; // goto __on_error;
180 }
181
182 status = HandleAlloc((void**)&__session, OCI_HTYPE_SESSION);
183 if (status != OCI_SUCCESS) {
185 break; // goto __on_error;
186 }
187
188 status = HandleAlloc((void**)&__trans, OCI_HTYPE_TRANS);
189 if (status != OCI_SUCCESS) {
191 break; // goto __on_error;;
192 }
193
194 status = OCIServerAttach(
195 __server, // OCIServer *srvhp
196 __error, // OCIError *errhp
197 _DATABASE.isEmpty() // const OraText *dblink
198 ? NULL : (text*)_DATABASE.data(),
199 _DATABASE.isEmpty() // sb4 dblink_len
200 ? 0 : (sb4) _DATABASE.length(),
201 OCI_DEFAULT // ub4 mode
202 );
203 if (status != OCI_SUCCESS) {
205 break; // goto __on_error;
206 }
207 __serverAttached = true;
208
209#if defined(__DCL_DEBUG) && __TRACE_THIS
210 char buf[256];
211 status = OCINlsGetInfo(
212 __env, // void* hndl
213 __error, // OCIError *errhp
214 (OraText*)buf, // OraText *buf
215 sizeof(buf), // size_t buflen
216 OCI_NLS_CHARACTER_SET // ub2 item
217 );
218 if (status == OCI_SUCCESS) {
219 __DCL_TRACE1_N(L"[%hs]\n", buf);
220 }
221 else {
222 __DCL_TRACE1_N(L"[%d]\n", status);
223 }
224 status = OCINlsGetInfo(
225 __env, // void* hndl
226 __error, // OCIError *errhp
227 (OraText*)buf, // OraText *buf
228 sizeof(buf), // size_t buflen
229 OCI_NLS_LANGUAGE // ub2 item
230 );
231 if (status == OCI_SUCCESS) {
232 __DCL_TRACE1_N(L"[%hs]\n", buf);
233 }
234 else {
235 __DCL_TRACE1_N(L"[%d]\n", status);
236 }
237 status = OCINlsGetInfo(
238 __env, // void* hndl
239 __error, // OCIError *errhp
240 (OraText*)buf, // OraText *buf
241 sizeof(buf), // size_t buflen
242 OCI_NLS_ABLANGUAGE // ub2 item
243 );
244 if (status == OCI_SUCCESS) {
245 __DCL_TRACE1_N(L"[%hs]\n", buf);
246 }
247 else {
248 __DCL_TRACE1_N(L"[%d]\n", status);
249 }
250 status = OCINlsGetInfo(
251 __env, // void* hndl
252 __error, // OCIError *errhp
253 (OraText*)buf, // OraText *buf
254 sizeof(buf), // size_t buflen
255 OCI_NLS_TERRITORY // ub2 item
256 );
257 if (status == OCI_SUCCESS) {
258 __DCL_TRACE1_N(L"[%hs]\n", buf);
259 }
260 else {
261 __DCL_TRACE1_N(L"[%d]\n", status);
262 }
263#endif
264
265 status = OCIAttrSet(
266 __svcctx, // void *trgthndlp
267 OCI_HTYPE_SVCCTX, // ub4 trghndltyp
268 __server, // void *attributep
269 0, // ub4 size
270 OCI_ATTR_SERVER, // ub4 attrtype
271 __error // OCIError *errhp
272 );
273 if (status != OCI_SUCCESS) {
275 break; // goto __on_error;
276 }
277
278 status = OCIAttrSet(
279 __session, // void *trgthndlp
280 OCI_HTYPE_SESSION, // ub4 trghndltyp
281 (void*)_USER.data(), // void *attributep
282 (ub4) _USER.length(), // ub4 size
283 OCI_ATTR_USERNAME, // ub4 attrtype
284 __error // OCIError *errhp
285 );
286 if (status != OCI_SUCCESS) {
288 break; // goto __on_error;
289 }
290
291 status = OCIAttrSet(
292 __session, // void *trgthndlp
293 OCI_HTYPE_SESSION, // ub4 trghndltyp
294 (void*)_PASSWORD.data(), // void *attributep
295 (ub4) _PASSWORD.length(), // ub4 size
296 OCI_ATTR_PASSWORD, // ub4 attrtype
297 __error // OCIError *errhp
298 );
299 if (status != OCI_SUCCESS) {
301 break; // goto __on_error;
302 }
303
304 status = OCISessionBegin(
305 __svcctx, // OCISvcCtx *svchp
306 __error, // OCIError *errhp
307 __session, // OCISession *usrhp
308 OCI_CRED_RDBMS, // ub4 credt
309 operationMode // ub4 mode
310 );
311 if (status != OCI_SUCCESS) {
313 break; // goto __on_error;
314 }
315
316 __sessionStarted = true;
317 status = OCIAttrSet(
318 __svcctx, // void *trgthndlp
319 OCI_HTYPE_SVCCTX, // ub4 trghndltyp
320 __server, // void *attributep
321 0, // ub4 size
322 OCI_ATTR_SERVER, // ub4 attrtype
323 __error // OCIError *errhp
324 );
325 if (status != OCI_SUCCESS) {
327 break; // goto __on_error;
328 }
329
330 status = OCIAttrSet(
331 __svcctx, // void *trgthndlp
332 OCI_HTYPE_SVCCTX, // ub4 trghndltyp
333 (void*)__session, // void *attributep
334 0, // ub4 size
335 OCI_ATTR_SESSION, // ub4 attrtype
336 __error // OCIError *errhp
337 );
338 if (status != OCI_SUCCESS) {
340 break; // goto __on_error;
341 }
342
343 status = OCIAttrSet(
344 __svcctx, // void *trgthndlp
345 OCI_HTYPE_SVCCTX, // ub4 trghndltyp
346 __trans, // void *attributep
347 0, // ub4 size
348 OCI_ATTR_TRANS, // ub4 attrtype
349 __error // OCIError *errhp
350 );
351 if (status != OCI_SUCCESS) {
353 break; // goto __on_error;
354 }
355
356 return true;
357 }
358
359// __on_error:
360 closeHelper(false);
361 return false;
362}
363
365{
366 return closeHelper(true);
367}
368
370{
371 sword status = OCI_SUCCESS;
372 OCIError* _OCIError = __error;
373 bool r = true;
374
375 if (!_normal) {
376 // 이전에 오류가 있었다.
377 // cleanup에서 __error2가 사용된다.
378 _OCIError = __error2;
379 }
380
381 if (__sessionStarted) {
382 status = OCISessionEnd(
383 __svcctx, // OCISvcCtx *svchp
384 _OCIError, // OCIError *errhp
385 __session, // OCISession *usrhp
386 OCI_DEFAULT // ub4 mode
387 );
388 if ((status != OCI_SUCCESS) && _normal) {
390 r = false;
391 }
392 __sessionStarted = false;
393 }
394
395 if (__serverAttached) {
396 status = OCIServerDetach(
397 __server, // OCIServer *srvhp
398 _OCIError, // OCIError *errhp
399 OCI_DEFAULT // ub4 mode
400 );
401 if ((status != OCI_SUCCESS) && _normal) {
403 r = false;
404 }
405 __serverAttached = false;
406 }
407
408 if (__trans) {
409 status = OCIHandleFree(__trans, OCI_HTYPE_TRANS);
410 if ((status != OCI_SUCCESS) && _normal) {
412 r = false;
413 }
414 __trans = NULL;
415 }
416
417 if (__session) {
418 status = OCIHandleFree(__session, OCI_HTYPE_SESSION);
419 if ((status != OCI_SUCCESS) && _normal) {
421 r = false;
422 }
423 __session = NULL;
424 }
425
426 if (__server) {
427 status = OCIHandleFree(__server, OCI_HTYPE_SERVER);
428 if ((status != OCI_SUCCESS) && _normal) {
430 r = false;
431 }
432 __server = NULL;
433 }
434
435 if (__svcctx) {
436 status = OCIHandleFree(__svcctx, OCI_HTYPE_SVCCTX);
437 if ((status != OCI_SUCCESS) && _normal) {
439 r = false;
440 }
441 __svcctx = NULL;
442 }
443
444 if (__error2) {
445 status = OCIHandleFree(__error2, OCI_HTYPE_ERROR);
446 if ((status != OCI_SUCCESS) && _normal) {
448 r = false;
449 }
450 __error2 = NULL;
451 }
452
453 return r;
454}
455
456bool OciConnection::executeHelper(const char* _sql, size_t _sqllen)
457{
458 OCIStmt* stmt = NULL;
459 for ( ; ; ) {
460 sword status = HandleAlloc((void**)&stmt, OCI_HTYPE_STMT);
461 if (status != OCI_SUCCESS) {
463 break; // goto __on_error;
464 }
465
466 status = OCIStmtPrepare2(
467 svcHandle(), // OCISvcCtx *svchp
468 &stmt, // OCIStmt **stmthp
469 errorHandle(), // OCIError *errhp
470 (const text*)_sql, // const OraText *stmttext
471 (ub4)_sqllen, // ub4 stmt_len
472 NULL, // const OraText *key
473 0, // ub4 keylen
474 OCI_NTV_SYNTAX, // ub4 language
475 OCI_DEFAULT // ub4 mode
476 );
477 if (status != OCI_SUCCESS) {
479 break; // goto __on_error;
480 }
481
482 ub2 stmtType = __OCI_STMT_TYPE_UNKNOWN;
483 ub4 size = sizeof(stmtType);
484 status = OCIAttrGet(
485 stmt, // const void *trgthndlp
486 OCI_DTYPE_PARAM, // ub4 trghndltyp
487 &stmtType, // void *attributep
488 &size, // ub4 *sizep
489 OCI_ATTR_SCALE, // ub4 attrtype
490 errorHandle() // OCIError *errhp
491 );
492 __DCL_ASSERT(size == sizeof(stmtType));
493 if (status != OCI_SUCCESS) {
495 break; // goto __on_error;
496 }
497
498 status = OCIStmtExecute(
499 svcHandle(), // OCISvcCtx *svchp
500 stmt, // OCIStmt *stmtp
501 errorHandle(), // OCIError *errhp
502 (stmtType == OCI_STMT_SELECT) ? 0 : 1, // ub4 iters
503 0, // ub4 rowoff
504 NULL, // const OCISnapshot *snap_in
505 NULL, // OCISnapshot *snap_out
506 OCI_DEFAULT // ub4 mode
507 );
508 if (status != OCI_SUCCESS) {
510 break; // goto __on_error;
511 }
512
513 OCIHandleFree(stmt, OCI_HTYPE_STMT);
514 return true;
515 }
516
517// __on_error:
518 if (stmt) {
519 OCIHandleFree(stmt, OCI_HTYPE_STMT);
520 }
521 return false;
522}
523
529
530typedef struct {
531 StmtType type;
532 const char* pattern;
534
535static STMT_PATTERN sp[] = {
536 { StmtTransBegin, "SET[[:space:]]+TRANSACTION" },
537 { StmtTransEnd, "COMMIT|ROLLBACK" },
538 { StmtOther, NULL }
539};
540
541static StmtType __GetStmtType(const char* _sql)
542{
543 for(size_t i = 0; sp[i].type != StmtOther; i++) {
544 try {
545 if (Regex::test(sp[i].pattern, _sql, true))
546 return sp[i].type;
547 }
548 catch(Exception* _e) {
549 _e->destroy();
550 }
551 }
552 return StmtOther;
553}
554
555bool OciConnection::__execute(const char* _sql, size_t _sqllen)
556{
557 if(executeHelper(_sql, _sqllen)) {
558 switch(__GetStmtType(_sql)) {
559 case StmtTransBegin :
560 __SET_STATE(Connection::stInTransaction);
561 break;
562 case StmtTransEnd :
563 __UNSET_STATE(Connection::stInTransaction);
564 break;
565 case StmtOther :
566 default :
567 ;
568 }
569 return true;
570 }
571
572 return false;
573}
574
576{
578 uword timeout = 60;
579 ub4 flags = OCI_TRANS_READWRITE;
580 sword status = OCITransStart(
581 __svcctx, // OCISvcCtx *svchp
582 __error, // OCIError *errhp
583 timeout, // uword timeout
584 flags // ub4 flags
585 );
586 if (status != OCI_SUCCESS) {
588 return false;
589 }
590 __SET_STATE(Connection::stInTransaction);
591 return true;
592}
593
595{
597 sword status = OCITransCommit(
598 __svcctx, // OCISvcCtx *svchp
599 __error, // OCIError *errhp
600 OCI_DEFAULT // ub4 flags
601 );
602 if (status != OCI_SUCCESS) {
604 return false;
605 }
607 return true;
608}
609
611{
613 sword status = OCITransRollback(
614 __svcctx, // OCISvcCtx *svchp
615 __error, // OCIError *errhp
616 OCI_DEFAULT // ub4 flags
617 );
618 if (status != OCI_SUCCESS) {
620 return false;
621 }
623 return true;
624}
625
627{
628 __DCL_ASSERT(_queryHandleOut != NULL);
629 SQL::Query* pNewQuery = new OciQuery(this);
630 if (!pNewQuery) {
632 return false;
633 }
634 *_queryHandleOut = pNewQuery;
635 return true;
636}
637
638// oci.h
639// OCI_ERROR_MAXMSG_SIZE 1024
640bool OciConnection::__getErrorMessage(char* _buf, size_t* _buflen)
641{
642 size_t len = 0;
643 if (__lastStatus == OCI_ERROR) {
644 sb4 errorcode = 0;
645 if (OCIErrorGet(
646 __error, // void *hndlp
647 (ub4)1, // ub4 recordno
648 (text*)NULL, // OraText *sqlstate
649 &errorcode, // sb4 *errcodep
650 (text*)_buf, // OraText *bufp
651 (ub4) *_buflen, // ub4 bufsiz
652 OCI_HTYPE_ERROR // ub4 type
653 ) != OCI_SUCCESS) {
654 // 드라이버 버그!!
655 *_buflen = 0;
656 return false;
657 }
658 len = ByteString::length(_buf, *_buflen);
659 for(; len > 0; len--) {
660 if (!isspace((unsigned)_buf[len - 1]))
661 break;
662 }
663 }
664 else {
665 const char* psz = "";
666 switch(__lastStatus) {
667 case OCI_SUCCESS_WITH_INFO :
668 psz = "OCI_SUCCESS_WITH_INFO";
669 break;
670 case OCI_RESERVED_FOR_INT_USE :
671 psz = "OCI_RESERVED_FOR_INT_USE";
672 break;
673 case OCI_NO_DATA :
674 psz = "OCI_NO_DATA";
675 break;
676 case OCI_ERROR :
677 psz = "OCI_ERROR";
678 break;
679 case OCI_INVALID_HANDLE :
680 psz = "OCI_INVALID_HANDLE";
681 break;
682 case OCI_NEED_DATA :
683 psz = "OCI_NEED_DATA";
684 break;
685 case OCI_STILL_EXECUTING :
686 psz = "OCI_STILL_EXECUTING";
687 break;
688 case OCI_CONTINUE :
689 psz = "OCI_CONTINUE";
690 break;
691 case OCI_ROWCBK_DONE :
692 psz = "OCI_ROWCBK_DONE";
693 break;
694 default :
695 // __DCL_ASSERT(false);
696 ;
697 }
698
699 len = strlen(psz);
700 if (*_buflen < len) {
701 len = *_buflen;
702 }
703 strncpy(_buf, psz, len);
704 }
705
706 if (!__errorMessage.isEmpty()) {
707 ByteString str;
708 if (len)
709 str = ", " + __errorMessage;
710 else
711 str = __errorMessage;
712
713 if ((*_buflen - len) >= str.length()) {
714 // 버퍼가 남이 있다면
715 // 이전에 len > 0 이면 버퍼의 시작위치를 옮기다.
716 _buf += len;
717 strncpy(_buf, str.data(), str.length());
718 len += str.length();
719 }
720 }
721
722 if (len < *_buflen) {
723 *_buflen = len;
724 *(_buf + *_buflen) = '\0';
725 }
726 return len > 0;
727}
728
729bool OciConnection::__getServerInfo(char* _buf, size_t* _buflen)
730{
731 sword status = OCIServerVersion(
732 __server, // void *hndlp
733 __error, // OCIError *errhp
734 (text*)_buf, // OraText *bufp
735 (ub4) *_buflen, // ub4 bufsz
736 OCI_HTYPE_SERVER // ub1 hndltype
737 );
738 if (status != OCI_SUCCESS) {
740 return false;
741 }
742 *_buflen = ByteString::length(_buf, *_buflen);
743 return true;
744}
745
746__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)
@ StmtTransEnd
@ StmtOther
@ StmtTransBegin
#define __DCL_TRACE0_N(fmt)
#define __SET_ERROR_HANDLE(_SQLCODE)
IOException *size_t r
Definition MediaInfo.cpp:82
#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 __OCI_STMT_TYPE_UNKNOWN
Definition OciQuery.h:6
#define __UNSET_STATE(state)
Definition SQLCore.h:483
#define __SET_STATE(state)
Definition SQLCore.h:482
virtual void destroy()
Definition Exception.cpp:74
virtual bool __open(const char *_cons, size_t _conslen)
virtual ~OciConnection()
virtual void destroy()
virtual bool __getErrorMessage(char *_buf, size_t *_buflen)
bool closeHelper(bool bEnableDebugInfo)
virtual bool __startTrans()
OCISession * __session
virtual bool __commitTrans()
OCIError * errorHandle() const
virtual bool __createQueryInstance(SQL::Query **_queryHandleOut)
OciConnection(const wchar_t *_serverTitle)
bool executeHelper(const char *_sql, size_t _sqllen)
OCIServer * __server
virtual bool __execute(const char *_sql, size_t _sqllen)
OCISvcCtx * __svcctx
virtual bool __close()
OCISvcCtx * svcHandle() const
virtual bool __getServerInfo(char *_buf, size_t *_buflen)
OCIError * __error2
sword HandleAlloc(void **_hndlpp, ub4 _type, size_t _xtramem_sz=0, void **_usrmempp=NULL)
virtual bool __rollbackTrans()
OCITrans * __trans
OCIError * __error
static bool test(const wchar_t *_regex, const wchar_t *_string, bool _icase=false) __DCL_THROWS1(RegexException *)
Definition Regex.cpp:250
@ eOutOfMemory
Definition SQLCore.h:24
@ eInvalidConnectionString
Definition SQLCore.h:31
@ eServerError
Definition SQLCore.h:21