2 ** Oracle Database Driver
3 ** Copyright (C) 2007-2016 Victor Kirhenshtein
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "oracledrv.h"
25 DECLARE_DRIVER_HEADER("ORACLE")
27 static DWORD
DrvQueryInternal(ORACLE_CONN
*pConn
, const WCHAR
*pwszQuery
, WCHAR
*errorText
);
30 * Prepare string for using in SQL query - enclose in quotes and escape as needed
32 extern "C" WCHAR EXPORT
*DrvPrepareStringW(const WCHAR
*str
)
34 int len
= (int)wcslen(str
) + 3; // + two quotes and \0 at the end
35 int bufferSize
= len
+ 128;
36 WCHAR
*out
= (WCHAR
*)malloc(bufferSize
* sizeof(WCHAR
));
39 const WCHAR
*src
= str
;
41 for(outPos
= 1; *src
!= 0; src
++)
46 if (len
>= bufferSize
)
49 out
= (WCHAR
*)realloc(out
, bufferSize
* sizeof(WCHAR
));
51 out
[outPos
++] = L
'\'';
52 out
[outPos
++] = L
'\'';
59 out
[outPos
++] = L
'\'';
66 * Prepare string for using in SQL query - enclose in quotes and escape as needed
68 extern "C" char EXPORT
*DrvPrepareStringA(const char *str
)
70 int len
= (int)strlen(str
) + 3; // + two quotes and \0 at the end
71 int bufferSize
= len
+ 128;
72 char *out
= (char *)malloc(bufferSize
);
75 const char *src
= str
;
77 for(outPos
= 1; *src
!= 0; src
++)
82 if (len
>= bufferSize
)
85 out
= (char *)realloc(out
, bufferSize
);
104 extern "C" bool EXPORT
DrvInit(const char *cmdLine
)
112 extern "C" void EXPORT
DrvUnload()
114 OCITerminate(OCI_DEFAULT
);
118 * Get error text from error handle
120 static void GetErrorFromHandle(OCIError
*handle
, sb4
*errorCode
, WCHAR
*errorText
)
123 OCIErrorGet(handle
, 1, NULL
, errorCode
, (text
*)errorText
, DBDRV_MAX_ERROR_TEXT
, OCI_HTYPE_ERROR
);
124 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
126 UCS2CHAR buffer
[DBDRV_MAX_ERROR_TEXT
];
128 OCIErrorGet(handle
, 1, NULL
, errorCode
, (text
*)buffer
, DBDRV_MAX_ERROR_TEXT
, OCI_HTYPE_ERROR
);
129 buffer
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
130 ucs2_to_ucs4(buffer
, ucs2_strlen(buffer
) + 1, errorText
, DBDRV_MAX_ERROR_TEXT
);
131 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
133 RemoveTrailingCRLFW(errorText
);
137 * Set last error text
139 static void SetLastError(ORACLE_CONN
*pConn
)
141 GetErrorFromHandle(pConn
->handleError
, &pConn
->lastErrorCode
, pConn
->lastErrorText
);
145 * Check if last error was caused by lost connection to server
147 static DWORD
IsConnectionError(ORACLE_CONN
*conn
)
150 OCIAttrGet(conn
->handleServer
, OCI_HTYPE_SERVER
, &nStatus
, NULL
, OCI_ATTR_SERVER_STATUS
, conn
->handleError
);
151 return (nStatus
== OCI_SERVER_NOT_CONNECTED
) ? DBERR_CONNECTION_LOST
: DBERR_OTHER_ERROR
;
155 * Destroy query result
157 static void DestroyQueryResult(ORACLE_RESULT
*pResult
)
161 nCount
= pResult
->nCols
* pResult
->nRows
;
162 for(i
= 0; i
< nCount
; i
++)
163 free(pResult
->pData
[i
]);
164 free(pResult
->pData
);
166 for(i
= 0; i
< pResult
->nCols
; i
++)
167 free(pResult
->columnNames
[i
]);
168 free(pResult
->columnNames
);
174 * Connect to database
176 extern "C" DBDRV_CONNECTION EXPORT
DrvConnect(const char *host
, const char *login
, const char *password
,
177 const char *database
, const char *schema
, WCHAR
*errorText
)
182 pConn
= (ORACLE_CONN
*)malloc(sizeof(ORACLE_CONN
));
185 memset(pConn
, 0, sizeof(ORACLE_CONN
));
187 if (OCIEnvNlsCreate(&pConn
->handleEnv
, OCI_THREADED
| OCI_NCHAR_LITERAL_REPLACE_OFF
,
188 NULL
, NULL
, NULL
, NULL
, 0, NULL
, OCI_UTF16ID
, OCI_UTF16ID
) == OCI_SUCCESS
)
190 OCIHandleAlloc(pConn
->handleEnv
, (void **)&pConn
->handleError
, OCI_HTYPE_ERROR
, 0, NULL
);
191 OCIHandleAlloc(pConn
->handleEnv
, (void **)&pConn
->handleServer
, OCI_HTYPE_SERVER
, 0, NULL
);
192 pwszStr
= UCS2StringFromMBString(host
);
193 if (OCIServerAttach(pConn
->handleServer
, pConn
->handleError
,
194 (text
*)pwszStr
, (sb4
)ucs2_strlen(pwszStr
) * sizeof(UCS2CHAR
), OCI_DEFAULT
) == OCI_SUCCESS
)
198 // Initialize service handle
199 OCIHandleAlloc(pConn
->handleEnv
, (void **)&pConn
->handleService
, OCI_HTYPE_SVCCTX
, 0, NULL
);
200 OCIAttrSet(pConn
->handleService
, OCI_HTYPE_SVCCTX
, pConn
->handleServer
, 0, OCI_ATTR_SERVER
, pConn
->handleError
);
202 // Initialize session handle
203 OCIHandleAlloc(pConn
->handleEnv
, (void **)&pConn
->handleSession
, OCI_HTYPE_SESSION
, 0, NULL
);
204 pwszStr
= UCS2StringFromMBString(login
);
205 OCIAttrSet(pConn
->handleSession
, OCI_HTYPE_SESSION
, pwszStr
,
206 (ub4
)ucs2_strlen(pwszStr
) * sizeof(UCS2CHAR
), OCI_ATTR_USERNAME
, pConn
->handleError
);
208 pwszStr
= UCS2StringFromMBString(password
);
209 OCIAttrSet(pConn
->handleSession
, OCI_HTYPE_SESSION
, pwszStr
,
210 (ub4
)ucs2_strlen(pwszStr
) * sizeof(UCS2CHAR
), OCI_ATTR_PASSWORD
, pConn
->handleError
);
213 if (OCISessionBegin(pConn
->handleService
, pConn
->handleError
,
214 pConn
->handleSession
, OCI_CRED_RDBMS
, OCI_STMT_CACHE
) == OCI_SUCCESS
)
216 OCIAttrSet(pConn
->handleService
, OCI_HTYPE_SVCCTX
, pConn
->handleSession
, 0, OCI_ATTR_SESSION
, pConn
->handleError
);
217 pConn
->mutexQueryLock
= MutexCreate();
218 pConn
->nTransLevel
= 0;
219 pConn
->lastErrorCode
= 0;
220 pConn
->lastErrorText
[0] = 0;
221 pConn
->prefetchLimit
= 10;
223 if ((schema
!= NULL
) && (schema
[0] != 0))
226 pwszStr
= UCS2StringFromMBString(schema
);
227 OCIAttrSet(pConn
->handleSession
, OCI_HTYPE_SESSION
, pwszStr
,
228 (ub4
)ucs2_strlen(pwszStr
) * sizeof(UCS2CHAR
), OCI_ATTR_CURRENT_SCHEMA
, pConn
->handleError
);
232 DrvQueryInternal(pConn
, L
"ALTER SESSION SET NLS_LANGUAGE='AMERICAN' NLS_NUMERIC_CHARACTERS='.,'", NULL
);
234 UCS2CHAR version
[1024];
235 if (OCIServerVersion(pConn
->handleService
, pConn
->handleError
, (OraText
*)version
, sizeof(version
), OCI_HTYPE_SVCCTX
) == OCI_SUCCESS
)
238 WCHAR
*wver
= UCS4StringFromUCS2String(version
);
239 nxlog_debug(5, _T("ORACLE: connected to %s"), wver
);
242 nxlog_debug(5, _T("ORACLE: connected to %s"), version
);
248 GetErrorFromHandle(pConn
->handleError
, &pConn
->lastErrorCode
, errorText
);
249 OCIServerDetach(pConn
->handleServer
, pConn
->handleError
, OCI_DEFAULT
);
250 OCIHandleFree(pConn
->handleEnv
, OCI_HTYPE_ENV
);
257 GetErrorFromHandle(pConn
->handleError
, &pConn
->lastErrorCode
, errorText
);
258 OCIHandleFree(pConn
->handleEnv
, OCI_HTYPE_ENV
);
266 wcscpy(errorText
, L
"Cannot allocate environment handle");
273 wcscpy(errorText
, L
"Memory allocation error");
276 return (DBDRV_CONNECTION
)pConn
;
280 * Disconnect from database
282 extern "C" void EXPORT
DrvDisconnect(ORACLE_CONN
*pConn
)
287 OCISessionEnd(pConn
->handleService
, pConn
->handleError
, NULL
, OCI_DEFAULT
);
288 OCIServerDetach(pConn
->handleServer
, pConn
->handleError
, OCI_DEFAULT
);
289 OCIHandleFree(pConn
->handleEnv
, OCI_HTYPE_ENV
);
290 MutexDestroy(pConn
->mutexQueryLock
);
297 extern "C" void EXPORT
DrvSetPrefetchLimit(ORACLE_CONN
*pConn
, int limit
)
300 pConn
->prefetchLimit
= limit
;
304 * Convert query from NetXMS portable format to native Oracle format
306 static UCS2CHAR
*ConvertQuery(WCHAR
*query
)
309 UCS2CHAR
*srcQuery
= UCS2StringFromUCS4String(query
);
311 UCS2CHAR
*srcQuery
= query
;
313 int count
= NumCharsW(query
, L
'?');
319 return wcsdup(query
);
323 UCS2CHAR
*dstQuery
= (UCS2CHAR
*)malloc((ucs2_strlen(srcQuery
) + count
* 3 + 1) * sizeof(UCS2CHAR
));
324 bool inString
= false;
327 for(src
= srcQuery
, dst
= dstQuery
; *src
!= 0; src
++)
333 inString
= !inString
;
353 *dst
++ = pos
/ 10 + '0';
354 *dst
++ = pos
% 10 + '0';
358 *dst
++ = pos
/ 100 + '0';
359 *dst
++ = (pos
% 100) / 10 + '0';
360 *dst
++ = pos
% 10 + '0';
380 extern "C" ORACLE_STATEMENT EXPORT
*DrvPrepare(ORACLE_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
382 ORACLE_STATEMENT
*stmt
= NULL
;
385 UCS2CHAR
*ucs2Query
= ConvertQuery(pwszQuery
);
387 MutexLock(pConn
->mutexQueryLock
);
388 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
389 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
391 stmt
= (ORACLE_STATEMENT
*)malloc(sizeof(ORACLE_STATEMENT
));
392 stmt
->connection
= pConn
;
393 stmt
->handleStmt
= handleStmt
;
394 stmt
->bindings
= new Array(8, 8, false);
395 stmt
->batchBindings
= NULL
;
396 stmt
->buffers
= new Array(8, 8, true);
397 stmt
->batchMode
= false;
399 OCIHandleAlloc(pConn
->handleEnv
, (void **)&stmt
->handleError
, OCI_HTYPE_ERROR
, 0, NULL
);
400 *pdwError
= DBERR_SUCCESS
;
405 *pdwError
= IsConnectionError(pConn
);
408 if (errorText
!= NULL
)
410 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
411 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
413 MutexUnlock(pConn
->mutexQueryLock
);
422 extern "C" bool EXPORT
DrvOpenBatch(ORACLE_STATEMENT
*stmt
)
424 stmt
->buffers
->clear();
425 if (stmt
->batchBindings
!= NULL
)
426 stmt
->batchBindings
->clear();
428 stmt
->batchBindings
= new ObjectArray
<OracleBatchBind
>(16, 16, true);
429 stmt
->batchMode
= true;
435 * Start next batch row
437 extern "C" void EXPORT
DrvNextBatchRow(ORACLE_STATEMENT
*stmt
)
439 if (!stmt
->batchMode
)
442 for(int i
= 0; i
< stmt
->batchBindings
->size(); i
++)
444 OracleBatchBind
*bind
= stmt
->batchBindings
->get(i
);
452 * Buffer sizes for different C types
454 static DWORD s_bufferSize
[] = { 0, sizeof(LONG
), sizeof(DWORD
), sizeof(INT64
), sizeof(QWORD
), sizeof(double) };
457 * Corresponding Oracle types for C types
459 static ub2 s_oracleType
[] = { SQLT_STR
, SQLT_INT
, SQLT_UIN
, SQLT_INT
, SQLT_UIN
, SQLT_FLT
};
462 * Bind parameter to statement - normal mode (non-batch)
464 static void BindNormal(ORACLE_STATEMENT
*stmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
466 OCIBind
*handleBind
= (OCIBind
*)stmt
->bindings
->get(pos
- 1);
470 case DB_CTYPE_STRING
:
472 sqlBuffer
= UCS2StringFromUCS4String((WCHAR
*)buffer
);
473 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
474 if (allocType
== DB_BIND_DYNAMIC
)
477 if (allocType
== DB_BIND_TRANSIENT
)
479 sqlBuffer
= wcsdup((WCHAR
*)buffer
);
480 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
485 if (allocType
== DB_BIND_DYNAMIC
)
486 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
489 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
,
490 ((sb4
)ucs2_strlen((UCS2CHAR
*)sqlBuffer
) + 1) * sizeof(UCS2CHAR
),
491 (sqlType
== DB_SQLTYPE_TEXT
) ? SQLT_LNG
: SQLT_STR
,
492 NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
494 case DB_CTYPE_INT64
: // OCI prior to 11.2 cannot bind 64 bit integers
495 sqlBuffer
= malloc(sizeof(OCINumber
));
496 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
497 OCINumberFromInt(stmt
->handleError
, buffer
, sizeof(INT64
), OCI_NUMBER_SIGNED
, (OCINumber
*)sqlBuffer
);
498 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, sizeof(OCINumber
),
499 SQLT_VNU
, NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
500 if (allocType
== DB_BIND_DYNAMIC
)
503 case DB_CTYPE_UINT64
: // OCI prior to 11.2 cannot bind 64 bit integers
504 sqlBuffer
= malloc(sizeof(OCINumber
));
505 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
506 OCINumberFromInt(stmt
->handleError
, buffer
, sizeof(INT64
), OCI_NUMBER_UNSIGNED
, (OCINumber
*)sqlBuffer
);
507 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, sizeof(OCINumber
),
508 SQLT_VNU
, NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
509 if (allocType
== DB_BIND_DYNAMIC
)
518 case DB_BIND_DYNAMIC
:
520 stmt
->buffers
->set(pos
- 1, buffer
);
522 case DB_BIND_TRANSIENT
:
523 sqlBuffer
= nx_memdup(buffer
, s_bufferSize
[cType
]);
524 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
527 return; // Invalid call
529 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, s_bufferSize
[cType
],
530 s_oracleType
[cType
], NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
534 stmt
->bindings
->set(pos
- 1, handleBind
);
538 * Batch bind - constructor
540 OracleBatchBind::OracleBatchBind(int cType
, int sqlType
)
545 if ((cType
== DB_CTYPE_STRING
) || (cType
== DB_CTYPE_INT64
) || (cType
== DB_CTYPE_UINT64
))
547 m_elementSize
= sizeof(UCS2CHAR
);
549 m_oraType
= (sqlType
== DB_SQLTYPE_TEXT
) ? SQLT_LNG
: SQLT_STR
;
551 m_strings
= (UCS2CHAR
**)calloc(m_allocated
, sizeof(UCS2CHAR
*));
555 m_elementSize
= s_bufferSize
[cType
];
557 m_oraType
= s_oracleType
[cType
];
558 m_data
= calloc(m_allocated
, m_elementSize
);
564 * Batch bind - destructor
566 OracleBatchBind::~OracleBatchBind()
568 if (m_strings
!= NULL
)
570 for(int i
= 0; i
< m_size
; i
++)
571 safe_free(m_strings
[i
]);
578 * Batch bind - add row
580 void OracleBatchBind::addRow()
582 if (m_size
== m_allocated
)
587 m_strings
= (UCS2CHAR
**)realloc(m_strings
, m_allocated
* sizeof(UCS2CHAR
*));
588 memset(m_strings
+ m_size
, 0, (m_allocated
- m_size
) * sizeof(UCS2CHAR
*));
592 m_data
= realloc(m_data
, m_allocated
* m_elementSize
);
593 memset((char *)m_data
+ m_size
* m_elementSize
, 0, (m_allocated
- m_size
) * m_elementSize
);
598 // clone last element
601 UCS2CHAR
*p
= m_strings
[m_size
- 1];
602 m_strings
[m_size
] = (p
!= NULL
) ? ucs2_strdup(p
) : NULL
;
606 memcpy((char *)m_data
+ m_size
* m_elementSize
, (char *)m_data
+ (m_size
- 1) * m_elementSize
, m_elementSize
);
613 * Batch bind - set value
615 void OracleBatchBind::set(void *value
)
619 safe_free(m_strings
[m_size
- 1]);
620 m_strings
[m_size
- 1] = (UCS2CHAR
*)value
;
623 int l
= (int)(ucs2_strlen((UCS2CHAR
*)value
) + 1) * sizeof(UCS2CHAR
);
624 if (l
> m_elementSize
)
630 memcpy((char *)m_data
+ (m_size
- 1) * m_elementSize
, value
, m_elementSize
);
635 * Get data for OCI bind
637 void *OracleBatchBind::getData()
643 m_data
= calloc(m_size
, m_elementSize
);
644 char *p
= (char *)m_data
;
645 for(int i
= 0; i
< m_size
; i
++)
647 if (m_strings
[i
] == NULL
)
649 memcpy(p
, m_strings
[i
], ucs2_strlen(m_strings
[i
]) * sizeof(UCS2CHAR
));
656 * Bind parameter to statement - batch mode
658 static void BindBatch(ORACLE_STATEMENT
*stmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
660 if (stmt
->batchSize
== 0)
661 return; // no batch rows added yet
663 OracleBatchBind
*bind
= stmt
->batchBindings
->get(pos
- 1);
666 bind
= new OracleBatchBind(cType
, sqlType
);
667 stmt
->batchBindings
->set(pos
- 1, bind
);
668 for(int i
= 0; i
< stmt
->batchSize
; i
++)
672 if (bind
->getCType() != cType
)
676 switch(bind
->getCType())
678 case DB_CTYPE_STRING
:
680 sqlBuffer
= UCS2StringFromUCS4String((WCHAR
*)buffer
);
681 if (allocType
== DB_BIND_DYNAMIC
)
684 if (allocType
== DB_BIND_DYNAMIC
)
690 sqlBuffer
= wcsdup((WCHAR
*)buffer
);
693 bind
->set(sqlBuffer
);
695 case DB_CTYPE_INT64
: // OCI prior to 11.2 cannot bind 64 bit integers
697 sqlBuffer
= malloc(64 * sizeof(WCHAR
));
698 swprintf((WCHAR
*)sqlBuffer
, 64, INT64_FMTW
, *((INT64
*)buffer
));
702 snprintf(temp
, 64, INT64_FMTA
, *((INT64
*)buffer
));
703 sqlBuffer
= UCS2StringFromMBString(temp
);
706 bind
->set(sqlBuffer
);
707 if (allocType
== DB_BIND_DYNAMIC
)
710 case DB_CTYPE_UINT64
: // OCI prior to 11.2 cannot bind 64 bit integers
712 sqlBuffer
= malloc(64 * sizeof(WCHAR
));
713 swprintf((WCHAR
*)sqlBuffer
, 64, UINT64_FMTW
, *((QWORD
*)buffer
));
717 snprintf(temp
, 64, UINT64_FMTA
, *((QWORD
*)buffer
));
718 sqlBuffer
= UCS2StringFromMBString(temp
);
721 bind
->set(sqlBuffer
);
722 if (allocType
== DB_BIND_DYNAMIC
)
727 if (allocType
== DB_BIND_DYNAMIC
)
734 * Bind parameter to statement
736 extern "C" void EXPORT
DrvBind(ORACLE_STATEMENT
*stmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
739 BindBatch(stmt
, pos
, sqlType
, cType
, buffer
, allocType
);
741 BindNormal(stmt
, pos
, sqlType
, cType
, buffer
, allocType
);
745 * Execute prepared non-select statement
747 extern "C" DWORD EXPORT
DrvExecute(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, WCHAR
*errorText
)
753 if (stmt
->batchSize
== 0)
755 stmt
->batchMode
= false;
756 stmt
->batchBindings
->clear();
757 return DBERR_SUCCESS
; // empty batch
760 for(int i
= 0; i
< stmt
->batchBindings
->size(); i
++)
762 OracleBatchBind
*b
= stmt
->batchBindings
->get(i
);
766 OCIBind
*handleBind
= NULL
;
767 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, i
+ 1, b
->getData(),
768 b
->getElementSize(), b
->getOraType(), NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
772 MutexLock(pConn
->mutexQueryLock
);
773 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
774 stmt
->batchMode
? stmt
->batchSize
: 1, 0, NULL
, NULL
,
775 (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
777 dwResult
= DBERR_SUCCESS
;
782 dwResult
= IsConnectionError(pConn
);
785 if (errorText
!= NULL
)
787 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
788 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
790 MutexUnlock(pConn
->mutexQueryLock
);
794 stmt
->batchMode
= false;
795 stmt
->batchBindings
->clear();
802 * Destroy prepared statement
804 extern "C" void EXPORT
DrvFreeStatement(ORACLE_STATEMENT
*stmt
)
809 MutexLock(stmt
->connection
->mutexQueryLock
);
810 OCIStmtRelease(stmt
->handleStmt
, stmt
->handleError
, NULL
, 0, OCI_DEFAULT
);
811 OCIHandleFree(stmt
->handleError
, OCI_HTYPE_ERROR
);
812 MutexUnlock(stmt
->connection
->mutexQueryLock
);
813 delete stmt
->bindings
;
814 delete stmt
->batchBindings
;
815 delete stmt
->buffers
;
820 * Perform non-SELECT query
822 static DWORD
DrvQueryInternal(ORACLE_CONN
*pConn
, const WCHAR
*pwszQuery
, WCHAR
*errorText
)
828 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
830 const UCS2CHAR
*ucs2Query
= pwszQuery
;
833 MutexLock(pConn
->mutexQueryLock
);
834 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
835 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
837 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
, 1, 0, NULL
, NULL
,
838 (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
840 dwResult
= DBERR_SUCCESS
;
845 dwResult
= IsConnectionError(pConn
);
847 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
852 dwResult
= IsConnectionError(pConn
);
854 if (errorText
!= NULL
)
856 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
857 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
859 MutexUnlock(pConn
->mutexQueryLock
);
868 * Perform non-SELECT query - entry point
870 extern "C" DWORD EXPORT
DrvQuery(ORACLE_CONN
*conn
, const WCHAR
*query
, WCHAR
*errorText
)
872 return DrvQueryInternal(conn
, query
, errorText
);
876 * Process SELECT results
878 static ORACLE_RESULT
*ProcessQueryResults(ORACLE_CONN
*pConn
, OCIStmt
*handleStmt
, DWORD
*pdwError
)
880 OCIParam
*handleParam
;
881 OCIDefine
*handleDefine
;
885 ORACLE_FETCH_BUFFER
*pBuffers
;
888 ORACLE_RESULT
*pResult
= (ORACLE_RESULT
*)malloc(sizeof(ORACLE_RESULT
));
890 pResult
->pData
= NULL
;
891 pResult
->columnNames
= NULL
;
892 OCIAttrGet(handleStmt
, OCI_HTYPE_STMT
, &nCount
, NULL
, OCI_ATTR_PARAM_COUNT
, pConn
->handleError
);
893 pResult
->nCols
= nCount
;
894 if (pResult
->nCols
> 0)
896 // Prepare receive buffers and fetch column names
897 pResult
->columnNames
= (char **)calloc(pResult
->nCols
, sizeof(char *));
898 pBuffers
= (ORACLE_FETCH_BUFFER
*)calloc(pResult
->nCols
, sizeof(ORACLE_FETCH_BUFFER
));
899 for(int i
= 0; i
< pResult
->nCols
; i
++)
901 if ((nStatus
= OCIParamGet(handleStmt
, OCI_HTYPE_STMT
, pConn
->handleError
,
902 (void **)&handleParam
, (ub4
)(i
+ 1))) == OCI_SUCCESS
)
905 if (OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &colName
, &nCount
, OCI_ATTR_NAME
, pConn
->handleError
) == OCI_SUCCESS
)
907 // We are in UTF-16 mode, so OCIAttrGet will return UTF-16 strings
908 pResult
->columnNames
[i
] = MBStringFromUCS2String((UCS2CHAR
*)colName
);
912 pResult
->columnNames
[i
] = strdup("");
917 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &type
, NULL
, OCI_ATTR_DATA_TYPE
, pConn
->handleError
);
918 if (type
== OCI_TYPECODE_CLOB
)
920 pBuffers
[i
].pData
= NULL
;
921 OCIDescriptorAlloc(pConn
->handleEnv
, (void **)&pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
, 0, NULL
);
923 nStatus
= OCIDefineByPos(handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
924 &pBuffers
[i
].lobLocator
, 0, SQLT_CLOB
, &pBuffers
[i
].isNull
,
925 NULL
, NULL
, OCI_DEFAULT
);
929 pBuffers
[i
].lobLocator
= NULL
;
930 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &nWidth
, NULL
, OCI_ATTR_DATA_SIZE
, pConn
->handleError
);
931 pBuffers
[i
].pData
= (UCS2CHAR
*)malloc((nWidth
+ 31) * sizeof(UCS2CHAR
));
933 nStatus
= OCIDefineByPos(handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
934 pBuffers
[i
].pData
, (nWidth
+ 31) * sizeof(UCS2CHAR
),
935 SQLT_CHR
, &pBuffers
[i
].isNull
, &pBuffers
[i
].nLength
,
936 &pBuffers
[i
].nCode
, OCI_DEFAULT
);
938 if (nStatus
!= OCI_SUCCESS
)
941 *pdwError
= IsConnectionError(pConn
);
943 OCIDescriptorFree(handleParam
, OCI_DTYPE_PARAM
);
948 *pdwError
= IsConnectionError(pConn
);
953 if (nStatus
== OCI_SUCCESS
)
958 nStatus
= OCIStmtFetch2(handleStmt
, pConn
->handleError
, 1, OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
959 if (nStatus
== OCI_NO_DATA
)
961 *pdwError
= DBERR_SUCCESS
; // EOF
964 if ((nStatus
!= OCI_SUCCESS
) && (nStatus
!= OCI_SUCCESS_WITH_INFO
))
967 *pdwError
= IsConnectionError(pConn
);
973 pResult
->pData
= (WCHAR
**)realloc(pResult
->pData
, sizeof(WCHAR
*) * pResult
->nCols
* pResult
->nRows
);
974 for(int i
= 0; i
< pResult
->nCols
; i
++)
976 if (pBuffers
[i
].isNull
)
978 pResult
->pData
[nPos
] = (WCHAR
*)nx_memdup("\0\0\0", sizeof(WCHAR
));
980 else if (pBuffers
[i
].lobLocator
!= NULL
)
984 OCILobGetLength(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &length
);
985 pResult
->pData
[nPos
] = (WCHAR
*)malloc((length
+ 1) * sizeof(WCHAR
));
987 UCS2CHAR
*ucs2buffer
= (UCS2CHAR
*)malloc(sizeof(UCS2CHAR
) * length
);
988 OCILobRead(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &amount
, 1,
989 ucs2buffer
, length
* sizeof(UCS2CHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
990 ucs2_to_ucs4(ucs2buffer
, length
, pResult
->pData
[nPos
], length
+ 1);
993 OCILobRead(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &amount
, 1,
994 pResult
->pData
[nPos
], (length
+ 1) * sizeof(WCHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
996 pResult
->pData
[nPos
][length
] = 0;
1000 int length
= pBuffers
[i
].nLength
/ sizeof(UCS2CHAR
);
1001 pResult
->pData
[nPos
] = (WCHAR
*)malloc((length
+ 1) * sizeof(WCHAR
));
1003 ucs2_to_ucs4(pBuffers
[i
].pData
, length
, pResult
->pData
[nPos
], length
+ 1);
1005 memcpy(pResult
->pData
[nPos
], pBuffers
[i
].pData
, pBuffers
[i
].nLength
);
1007 pResult
->pData
[nPos
][length
] = 0;
1015 for(int i
= 0; i
< pResult
->nCols
; i
++)
1017 safe_free(pBuffers
[i
].pData
);
1018 if (pBuffers
[i
].lobLocator
!= NULL
)
1020 OCIDescriptorFree(pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
);
1025 // Destroy results in case of error
1026 if (*pdwError
!= DBERR_SUCCESS
)
1028 DestroyQueryResult(pResult
);
1037 * Perform SELECT query
1039 extern "C" DBDRV_RESULT EXPORT
DrvSelect(ORACLE_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
1041 ORACLE_RESULT
*pResult
= NULL
;
1042 OCIStmt
*handleStmt
;
1045 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
1047 UCS2CHAR
*ucs2Query
= pwszQuery
;
1050 MutexLock(pConn
->mutexQueryLock
);
1051 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
1052 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
1054 OCIAttrSet(handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1055 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
,
1056 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1058 pResult
= ProcessQueryResults(pConn
, handleStmt
, pdwError
);
1062 SetLastError(pConn
);
1063 *pdwError
= IsConnectionError(pConn
);
1065 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
1069 SetLastError(pConn
);
1070 *pdwError
= IsConnectionError(pConn
);
1072 if (errorText
!= NULL
)
1074 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1075 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1077 MutexUnlock(pConn
->mutexQueryLock
);
1086 * Perform SELECT query using prepared statement
1088 extern "C" DBDRV_RESULT EXPORT
DrvSelectPrepared(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, DWORD
*pdwError
, WCHAR
*errorText
)
1090 ORACLE_RESULT
*pResult
= NULL
;
1092 MutexLock(pConn
->mutexQueryLock
);
1093 OCIAttrSet(stmt
->handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1094 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
1095 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1097 pResult
= ProcessQueryResults(pConn
, stmt
->handleStmt
, pdwError
);
1101 SetLastError(pConn
);
1102 *pdwError
= IsConnectionError(pConn
);
1105 if (errorText
!= NULL
)
1107 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1108 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1110 MutexUnlock(pConn
->mutexQueryLock
);
1116 * Get field length from result
1118 extern "C" LONG EXPORT
DrvGetFieldLength(ORACLE_RESULT
*pResult
, int nRow
, int nColumn
)
1120 if (pResult
== NULL
)
1123 if ((nRow
>= 0) && (nRow
< pResult
->nRows
) &&
1124 (nColumn
>= 0) && (nColumn
< pResult
->nCols
))
1125 return (LONG
)wcslen(pResult
->pData
[pResult
->nCols
* nRow
+ nColumn
]);
1131 * Get field value from result
1133 extern "C" WCHAR EXPORT
*DrvGetField(ORACLE_RESULT
*pResult
, int nRow
, int nColumn
,
1134 WCHAR
*pBuffer
, int nBufLen
)
1136 WCHAR
*pValue
= NULL
;
1138 if (pResult
!= NULL
)
1140 if ((nRow
< pResult
->nRows
) && (nRow
>= 0) &&
1141 (nColumn
< pResult
->nCols
) && (nColumn
>= 0))
1144 wcsncpy_s(pBuffer
, nBufLen
, pResult
->pData
[nRow
* pResult
->nCols
+ nColumn
], _TRUNCATE
);
1146 wcsncpy(pBuffer
, pResult
->pData
[nRow
* pResult
->nCols
+ nColumn
], nBufLen
);
1147 pBuffer
[nBufLen
- 1] = 0;
1156 * Get number of rows in result
1158 extern "C" int EXPORT
DrvGetNumRows(ORACLE_RESULT
*pResult
)
1160 return (pResult
!= NULL
) ? pResult
->nRows
: 0;
1164 * Get column count in query result
1166 extern "C" int EXPORT
DrvGetColumnCount(ORACLE_RESULT
*pResult
)
1168 return (pResult
!= NULL
) ? pResult
->nCols
: 0;
1172 * Get column name in query result
1174 extern "C" const char EXPORT
*DrvGetColumnName(ORACLE_RESULT
*pResult
, int column
)
1176 return ((pResult
!= NULL
) && (column
>= 0) && (column
< pResult
->nCols
)) ? pResult
->columnNames
[column
] : NULL
;
1180 * Free SELECT results
1182 extern "C" void EXPORT
DrvFreeResult(ORACLE_RESULT
*pResult
)
1184 if (pResult
!= NULL
)
1185 DestroyQueryResult(pResult
);
1189 * Destroy unbuffered query result
1191 static void DestroyUnbufferedQueryResult(ORACLE_UNBUFFERED_RESULT
*result
, bool freeStatement
)
1196 OCIStmtRelease(result
->handleStmt
, result
->connection
->handleError
, NULL
, 0, OCI_DEFAULT
);
1198 for(i
= 0; i
< result
->nCols
; i
++)
1200 free(result
->pBuffers
[i
].pData
);
1201 if (result
->pBuffers
[i
].lobLocator
!= NULL
)
1203 OCIDescriptorFree(result
->pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
);
1206 free(result
->pBuffers
);
1208 for(i
= 0; i
< result
->nCols
; i
++)
1209 free(result
->columnNames
[i
]);
1210 free(result
->columnNames
);
1216 * Process results of unbuffered query execution (prepare for fetching results)
1218 static ORACLE_UNBUFFERED_RESULT
*ProcessUnbufferedQueryResults(ORACLE_CONN
*pConn
, OCIStmt
*handleStmt
, DWORD
*pdwError
)
1220 ORACLE_UNBUFFERED_RESULT
*result
= (ORACLE_UNBUFFERED_RESULT
*)malloc(sizeof(ORACLE_UNBUFFERED_RESULT
));
1221 result
->handleStmt
= handleStmt
;
1222 result
->connection
= pConn
;
1225 OCIAttrGet(result
->handleStmt
, OCI_HTYPE_STMT
, &nCount
, NULL
, OCI_ATTR_PARAM_COUNT
, pConn
->handleError
);
1226 result
->nCols
= nCount
;
1227 if (result
->nCols
> 0)
1229 // Prepare receive buffers and fetch column names
1230 result
->columnNames
= (char **)calloc(result
->nCols
, sizeof(char *));
1231 result
->pBuffers
= (ORACLE_FETCH_BUFFER
*)calloc(result
->nCols
, sizeof(ORACLE_FETCH_BUFFER
));
1232 for(int i
= 0; i
< result
->nCols
; i
++)
1234 OCIParam
*handleParam
;
1236 result
->pBuffers
[i
].isNull
= 1; // Mark all columns as NULL initially
1237 if (OCIParamGet(result
->handleStmt
, OCI_HTYPE_STMT
, pConn
->handleError
,
1238 (void **)&handleParam
, (ub4
)(i
+ 1)) == OCI_SUCCESS
)
1242 if (OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &colName
, &nCount
, OCI_ATTR_NAME
, pConn
->handleError
) == OCI_SUCCESS
)
1244 // We are in UTF-16 mode, so OCIAttrGet will return UTF-16 strings
1245 result
->columnNames
[i
] = MBStringFromUCS2String((UCS2CHAR
*)colName
);
1249 result
->columnNames
[i
] = strdup("");
1255 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &type
, NULL
, OCI_ATTR_DATA_TYPE
, pConn
->handleError
);
1256 OCIDefine
*handleDefine
;
1257 if (type
== OCI_TYPECODE_CLOB
)
1259 result
->pBuffers
[i
].pData
= NULL
;
1260 OCIDescriptorAlloc(pConn
->handleEnv
, (void **)&result
->pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
, 0, NULL
);
1261 handleDefine
= NULL
;
1262 nStatus
= OCIDefineByPos(result
->handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
1263 &result
->pBuffers
[i
].lobLocator
, 0, SQLT_CLOB
, &result
->pBuffers
[i
].isNull
,
1264 NULL
, NULL
, OCI_DEFAULT
);
1269 result
->pBuffers
[i
].lobLocator
= NULL
;
1270 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &nWidth
, NULL
, OCI_ATTR_DATA_SIZE
, pConn
->handleError
);
1271 result
->pBuffers
[i
].pData
= (UCS2CHAR
*)malloc((nWidth
+ 31) * sizeof(UCS2CHAR
));
1272 handleDefine
= NULL
;
1273 nStatus
= OCIDefineByPos(result
->handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
1274 result
->pBuffers
[i
].pData
, (nWidth
+ 31) * sizeof(UCS2CHAR
),
1275 SQLT_CHR
, &result
->pBuffers
[i
].isNull
, &result
->pBuffers
[i
].nLength
,
1276 &result
->pBuffers
[i
].nCode
, OCI_DEFAULT
);
1278 OCIDescriptorFree(handleParam
, OCI_DTYPE_PARAM
);
1279 if (nStatus
== OCI_SUCCESS
)
1281 *pdwError
= DBERR_SUCCESS
;
1285 SetLastError(pConn
);
1286 *pdwError
= IsConnectionError(pConn
);
1287 DestroyUnbufferedQueryResult(result
, false);
1294 SetLastError(pConn
);
1295 *pdwError
= IsConnectionError(pConn
);
1296 DestroyUnbufferedQueryResult(result
, false);
1312 * Perform unbuffered SELECT query
1314 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT
DrvSelectUnbuffered(ORACLE_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
1316 ORACLE_UNBUFFERED_RESULT
*result
= NULL
;
1319 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
1321 UCS2CHAR
*ucs2Query
= pwszQuery
;
1324 MutexLock(pConn
->mutexQueryLock
);
1326 OCIStmt
*handleStmt
;
1327 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
1328 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
1330 OCIAttrSet(handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1331 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
,
1332 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1334 result
= ProcessUnbufferedQueryResults(pConn
, handleStmt
, pdwError
);
1338 SetLastError(pConn
);
1339 *pdwError
= IsConnectionError(pConn
);
1344 SetLastError(pConn
);
1345 *pdwError
= IsConnectionError(pConn
);
1352 if ((*pdwError
== DBERR_SUCCESS
) && (result
!= NULL
))
1355 // On failure, unlock query mutex and do cleanup
1356 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
1357 if (errorText
!= NULL
)
1359 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1360 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1362 MutexUnlock(pConn
->mutexQueryLock
);
1367 * Perform SELECT query using prepared statement
1369 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT
DrvSelectPreparedUnbuffered(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, DWORD
*pdwError
, WCHAR
*errorText
)
1371 ORACLE_UNBUFFERED_RESULT
*result
= NULL
;
1373 MutexLock(pConn
->mutexQueryLock
);
1375 OCIAttrSet(stmt
->handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1376 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
1377 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1379 result
= ProcessUnbufferedQueryResults(pConn
, stmt
->handleStmt
, pdwError
);
1383 SetLastError(pConn
);
1384 *pdwError
= IsConnectionError(pConn
);
1387 if ((*pdwError
== DBERR_SUCCESS
) && (result
!= NULL
))
1390 // On failure, unlock query mutex and do cleanup
1391 if (errorText
!= NULL
)
1393 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1394 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1396 MutexUnlock(pConn
->mutexQueryLock
);
1401 * Fetch next result line from unbuffered SELECT results
1403 extern "C" bool EXPORT
DrvFetch(ORACLE_UNBUFFERED_RESULT
*result
)
1410 sword rc
= OCIStmtFetch2(result
->handleStmt
, result
->connection
->handleError
, 1, OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
1411 if ((rc
== OCI_SUCCESS
) || (rc
== OCI_SUCCESS_WITH_INFO
))
1417 SetLastError(result
->connection
);
1424 * Get field length from current row in unbuffered query result
1426 extern "C" LONG EXPORT
DrvGetFieldLengthUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int nColumn
)
1431 if ((nColumn
< 0) || (nColumn
>= result
->nCols
))
1434 if (result
->pBuffers
[nColumn
].isNull
)
1437 if (result
->pBuffers
[nColumn
].lobLocator
!= NULL
)
1440 OCILobGetLength(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &length
);
1441 return (LONG
)length
;
1444 return (LONG
)(result
->pBuffers
[nColumn
].nLength
/ sizeof(UCS2CHAR
));
1448 * Get field from current row in unbuffered query result
1450 extern "C" WCHAR EXPORT
*DrvGetFieldUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int nColumn
, WCHAR
*pBuffer
, int nBufSize
)
1457 if ((nColumn
< 0) || (nColumn
>= result
->nCols
))
1460 if (result
->pBuffers
[nColumn
].isNull
)
1464 else if (result
->pBuffers
[nColumn
].lobLocator
!= NULL
)
1467 OCILobGetLength(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &length
);
1469 nLen
= min(nBufSize
- 1, (int)length
);
1472 UCS2CHAR
*ucs2buffer
= (UCS2CHAR
*)malloc(nLen
* sizeof(UCS2CHAR
));
1473 OCILobRead(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &amount
, 1,
1474 ucs2buffer
, nLen
* sizeof(UCS2CHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
1475 ucs2_to_ucs4(ucs2buffer
, nLen
, pBuffer
, nLen
);
1478 OCILobRead(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &amount
, 1,
1479 pBuffer
, nBufSize
* sizeof(WCHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
1485 nLen
= min(nBufSize
- 1, ((int)(result
->pBuffers
[nColumn
].nLength
/ sizeof(UCS2CHAR
))));
1487 ucs2_to_ucs4(result
->pBuffers
[nColumn
].pData
, nLen
, pBuffer
, nLen
+ 1);
1489 memcpy(pBuffer
, result
->pBuffers
[nColumn
].pData
, nLen
* sizeof(WCHAR
));
1498 * Get column count in unbuffered query result
1500 extern "C" int EXPORT
DrvGetColumnCountUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
)
1502 return (result
!= NULL
) ? result
->nCols
: 0;
1506 * Get column name in unbuffered query result
1508 extern "C" const char EXPORT
*DrvGetColumnNameUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int column
)
1510 return ((result
!= NULL
) && (column
>= 0) && (column
< result
->nCols
)) ? result
->columnNames
[column
] : NULL
;
1514 * Destroy result of unbuffered query
1516 extern "C" void EXPORT
DrvFreeUnbufferedResult(ORACLE_UNBUFFERED_RESULT
*result
)
1521 MUTEX mutex
= result
->connection
->mutexQueryLock
;
1522 DestroyUnbufferedQueryResult(result
, true);
1529 extern "C" DWORD EXPORT
DrvBegin(ORACLE_CONN
*pConn
)
1532 return DBERR_INVALID_HANDLE
;
1534 MutexLock(pConn
->mutexQueryLock
);
1535 pConn
->nTransLevel
++;
1536 MutexUnlock(pConn
->mutexQueryLock
);
1537 return DBERR_SUCCESS
;
1541 * Commit transaction
1543 extern "C" DWORD EXPORT
DrvCommit(ORACLE_CONN
*pConn
)
1548 return DBERR_INVALID_HANDLE
;
1550 MutexLock(pConn
->mutexQueryLock
);
1551 if (pConn
->nTransLevel
> 0)
1553 if (OCITransCommit(pConn
->handleService
, pConn
->handleError
, OCI_DEFAULT
) == OCI_SUCCESS
)
1555 dwResult
= DBERR_SUCCESS
;
1556 pConn
->nTransLevel
= 0;
1560 SetLastError(pConn
);
1561 dwResult
= IsConnectionError(pConn
);
1566 dwResult
= DBERR_SUCCESS
;
1568 MutexUnlock(pConn
->mutexQueryLock
);
1573 * Rollback transaction
1575 extern "C" DWORD EXPORT
DrvRollback(ORACLE_CONN
*pConn
)
1580 return DBERR_INVALID_HANDLE
;
1582 MutexLock(pConn
->mutexQueryLock
);
1583 if (pConn
->nTransLevel
> 0)
1585 if (OCITransRollback(pConn
->handleService
, pConn
->handleError
, OCI_DEFAULT
) == OCI_SUCCESS
)
1587 dwResult
= DBERR_SUCCESS
;
1588 pConn
->nTransLevel
= 0;
1592 SetLastError(pConn
);
1593 dwResult
= IsConnectionError(pConn
);
1598 dwResult
= DBERR_SUCCESS
;
1600 MutexUnlock(pConn
->mutexQueryLock
);
1605 * Check if table exist
1607 extern "C" int EXPORT
DrvIsTableExist(ORACLE_CONN
*pConn
, const WCHAR
*name
)
1610 swprintf(query
, 256, L
"SELECT count(*) FROM user_tables WHERE table_name=upper('%ls')", name
);
1612 WCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1613 int rc
= DBIsTableExist_Failure
;
1614 ORACLE_RESULT
*hResult
= (ORACLE_RESULT
*)DrvSelect(pConn
, query
, &error
, errorText
);
1615 if (hResult
!= NULL
)
1617 WCHAR buffer
[64] = L
"";
1618 DrvGetField(hResult
, 0, 0, buffer
, 64);
1619 rc
= (wcstol(buffer
, NULL
, 10) > 0) ? DBIsTableExist_Found
: DBIsTableExist_NotFound
;
1620 DrvFreeResult(hResult
);
1630 bool WINAPI
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpReserved
)
1632 if (dwReason
== DLL_PROCESS_ATTACH
)
1633 DisableThreadLibraryCalls(hInstance
);