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 OCINumberFromInt(stmt
->handleError
, buffer
, sizeof(INT64
), OCI_NUMBER_SIGNED
, (OCINumber
*)sqlBuffer
);
497 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, sizeof(OCINumber
),
498 SQLT_VNU
, NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
499 if (allocType
== DB_BIND_DYNAMIC
)
502 case DB_CTYPE_UINT64
: // OCI prior to 11.2 cannot bind 64 bit integers
503 sqlBuffer
= malloc(sizeof(OCINumber
));
504 OCINumberFromInt(stmt
->handleError
, buffer
, sizeof(INT64
), OCI_NUMBER_UNSIGNED
, (OCINumber
*)sqlBuffer
);
505 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, sizeof(OCINumber
),
506 SQLT_VNU
, NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
507 if (allocType
== DB_BIND_DYNAMIC
)
516 case DB_BIND_DYNAMIC
:
518 stmt
->buffers
->set(pos
- 1, buffer
);
520 case DB_BIND_TRANSIENT
:
521 sqlBuffer
= nx_memdup(buffer
, s_bufferSize
[cType
]);
522 stmt
->buffers
->set(pos
- 1, sqlBuffer
);
525 return; // Invalid call
527 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, pos
, sqlBuffer
, s_bufferSize
[cType
],
528 s_oracleType
[cType
], NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
532 stmt
->bindings
->set(pos
- 1, handleBind
);
536 * Batch bind - constructor
538 OracleBatchBind::OracleBatchBind(int cType
, int sqlType
)
543 if ((cType
== DB_CTYPE_STRING
) || (cType
== DB_CTYPE_INT64
) || (cType
== DB_CTYPE_UINT64
))
545 m_elementSize
= sizeof(UCS2CHAR
);
547 m_oraType
= (sqlType
== DB_SQLTYPE_TEXT
) ? SQLT_LNG
: SQLT_STR
;
549 m_strings
= (UCS2CHAR
**)calloc(m_allocated
, sizeof(UCS2CHAR
*));
553 m_elementSize
= s_bufferSize
[cType
];
555 m_oraType
= s_oracleType
[cType
];
556 m_data
= calloc(m_allocated
, m_elementSize
);
562 * Batch bind - destructor
564 OracleBatchBind::~OracleBatchBind()
566 if (m_strings
!= NULL
)
568 for(int i
= 0; i
< m_size
; i
++)
569 safe_free(m_strings
[i
]);
576 * Batch bind - add row
578 void OracleBatchBind::addRow()
580 if (m_size
== m_allocated
)
585 m_strings
= (UCS2CHAR
**)realloc(m_strings
, m_allocated
* sizeof(UCS2CHAR
*));
586 memset(m_strings
+ m_size
, 0, (m_allocated
- m_size
) * sizeof(UCS2CHAR
*));
590 m_data
= realloc(m_data
, m_allocated
* m_elementSize
);
591 memset((char *)m_data
+ m_size
* m_elementSize
, 0, (m_allocated
- m_size
) * m_elementSize
);
596 // clone last element
599 UCS2CHAR
*p
= m_strings
[m_size
- 1];
600 m_strings
[m_size
] = (p
!= NULL
) ? ucs2_strdup(p
) : NULL
;
604 memcpy((char *)m_data
+ m_size
* m_elementSize
, (char *)m_data
+ (m_size
- 1) * m_elementSize
, m_elementSize
);
611 * Batch bind - set value
613 void OracleBatchBind::set(void *value
)
617 safe_free(m_strings
[m_size
- 1]);
618 m_strings
[m_size
- 1] = (UCS2CHAR
*)value
;
621 int l
= (int)(ucs2_strlen((UCS2CHAR
*)value
) + 1) * sizeof(UCS2CHAR
);
622 if (l
> m_elementSize
)
628 memcpy((char *)m_data
+ (m_size
- 1) * m_elementSize
, value
, m_elementSize
);
633 * Get data for OCI bind
635 void *OracleBatchBind::getData()
641 m_data
= calloc(m_size
, m_elementSize
);
642 char *p
= (char *)m_data
;
643 for(int i
= 0; i
< m_size
; i
++)
645 if (m_strings
[i
] == NULL
)
647 memcpy(p
, m_strings
[i
], ucs2_strlen(m_strings
[i
]) * sizeof(UCS2CHAR
));
654 * Bind parameter to statement - batch mode
656 static void BindBatch(ORACLE_STATEMENT
*stmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
658 if (stmt
->batchSize
== 0)
659 return; // no batch rows added yet
661 OracleBatchBind
*bind
= stmt
->batchBindings
->get(pos
- 1);
664 bind
= new OracleBatchBind(cType
, sqlType
);
665 stmt
->batchBindings
->set(pos
- 1, bind
);
666 for(int i
= 0; i
< stmt
->batchSize
; i
++)
670 if (bind
->getCType() != cType
)
674 switch(bind
->getCType())
676 case DB_CTYPE_STRING
:
678 sqlBuffer
= UCS2StringFromUCS4String((WCHAR
*)buffer
);
679 if (allocType
== DB_BIND_DYNAMIC
)
682 if (allocType
== DB_BIND_DYNAMIC
)
688 sqlBuffer
= wcsdup((WCHAR
*)buffer
);
691 bind
->set(sqlBuffer
);
693 case DB_CTYPE_INT64
: // OCI prior to 11.2 cannot bind 64 bit integers
695 sqlBuffer
= malloc(64 * sizeof(WCHAR
));
696 swprintf((WCHAR
*)sqlBuffer
, 64, INT64_FMTW
, *((INT64
*)buffer
));
700 snprintf(temp
, 64, INT64_FMTA
, *((INT64
*)buffer
));
701 sqlBuffer
= UCS2StringFromMBString(temp
);
704 bind
->set(sqlBuffer
);
705 if (allocType
== DB_BIND_DYNAMIC
)
708 case DB_CTYPE_UINT64
: // OCI prior to 11.2 cannot bind 64 bit integers
710 sqlBuffer
= malloc(64 * sizeof(WCHAR
));
711 swprintf((WCHAR
*)sqlBuffer
, 64, UINT64_FMTW
, *((QWORD
*)buffer
));
715 snprintf(temp
, 64, UINT64_FMTA
, *((QWORD
*)buffer
));
716 sqlBuffer
= UCS2StringFromMBString(temp
);
719 bind
->set(sqlBuffer
);
720 if (allocType
== DB_BIND_DYNAMIC
)
725 if (allocType
== DB_BIND_DYNAMIC
)
732 * Bind parameter to statement
734 extern "C" void EXPORT
DrvBind(ORACLE_STATEMENT
*stmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
737 BindBatch(stmt
, pos
, sqlType
, cType
, buffer
, allocType
);
739 BindNormal(stmt
, pos
, sqlType
, cType
, buffer
, allocType
);
743 * Execute prepared non-select statement
745 extern "C" DWORD EXPORT
DrvExecute(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, WCHAR
*errorText
)
751 if (stmt
->batchSize
== 0)
753 stmt
->batchMode
= false;
754 stmt
->batchBindings
->clear();
755 return DBERR_SUCCESS
; // empty batch
758 for(int i
= 0; i
< stmt
->batchBindings
->size(); i
++)
760 OracleBatchBind
*b
= stmt
->batchBindings
->get(i
);
764 OCIBind
*handleBind
= NULL
;
765 OCIBindByPos(stmt
->handleStmt
, &handleBind
, stmt
->handleError
, i
+ 1, b
->getData(),
766 b
->getElementSize(), b
->getOraType(), NULL
, NULL
, NULL
, 0, NULL
, OCI_DEFAULT
);
770 MutexLock(pConn
->mutexQueryLock
);
771 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
772 stmt
->batchMode
? stmt
->batchSize
: 1, 0, NULL
, NULL
,
773 (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
775 dwResult
= DBERR_SUCCESS
;
780 dwResult
= IsConnectionError(pConn
);
783 if (errorText
!= NULL
)
785 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
786 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
788 MutexUnlock(pConn
->mutexQueryLock
);
792 stmt
->batchMode
= false;
793 stmt
->batchBindings
->clear();
800 * Destroy prepared statement
802 extern "C" void EXPORT
DrvFreeStatement(ORACLE_STATEMENT
*stmt
)
807 MutexLock(stmt
->connection
->mutexQueryLock
);
808 OCIStmtRelease(stmt
->handleStmt
, stmt
->handleError
, NULL
, 0, OCI_DEFAULT
);
809 OCIHandleFree(stmt
->handleError
, OCI_HTYPE_ERROR
);
810 MutexUnlock(stmt
->connection
->mutexQueryLock
);
811 delete stmt
->bindings
;
812 delete stmt
->batchBindings
;
813 delete stmt
->buffers
;
818 * Perform non-SELECT query
820 static DWORD
DrvQueryInternal(ORACLE_CONN
*pConn
, const WCHAR
*pwszQuery
, WCHAR
*errorText
)
826 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
828 const UCS2CHAR
*ucs2Query
= pwszQuery
;
831 MutexLock(pConn
->mutexQueryLock
);
832 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
833 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
835 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
, 1, 0, NULL
, NULL
,
836 (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
838 dwResult
= DBERR_SUCCESS
;
843 dwResult
= IsConnectionError(pConn
);
845 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
850 dwResult
= IsConnectionError(pConn
);
852 if (errorText
!= NULL
)
854 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
855 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
857 MutexUnlock(pConn
->mutexQueryLock
);
866 * Perform non-SELECT query - entry point
868 extern "C" DWORD EXPORT
DrvQuery(ORACLE_CONN
*conn
, const WCHAR
*query
, WCHAR
*errorText
)
870 return DrvQueryInternal(conn
, query
, errorText
);
874 * Process SELECT results
876 static ORACLE_RESULT
*ProcessQueryResults(ORACLE_CONN
*pConn
, OCIStmt
*handleStmt
, DWORD
*pdwError
)
878 OCIParam
*handleParam
;
879 OCIDefine
*handleDefine
;
883 ORACLE_FETCH_BUFFER
*pBuffers
;
886 ORACLE_RESULT
*pResult
= (ORACLE_RESULT
*)malloc(sizeof(ORACLE_RESULT
));
888 pResult
->pData
= NULL
;
889 pResult
->columnNames
= NULL
;
890 OCIAttrGet(handleStmt
, OCI_HTYPE_STMT
, &nCount
, NULL
, OCI_ATTR_PARAM_COUNT
, pConn
->handleError
);
891 pResult
->nCols
= nCount
;
892 if (pResult
->nCols
> 0)
894 // Prepare receive buffers and fetch column names
895 pResult
->columnNames
= (char **)calloc(pResult
->nCols
, sizeof(char *));
896 pBuffers
= (ORACLE_FETCH_BUFFER
*)calloc(pResult
->nCols
, sizeof(ORACLE_FETCH_BUFFER
));
897 for(int i
= 0; i
< pResult
->nCols
; i
++)
899 if ((nStatus
= OCIParamGet(handleStmt
, OCI_HTYPE_STMT
, pConn
->handleError
,
900 (void **)&handleParam
, (ub4
)(i
+ 1))) == OCI_SUCCESS
)
903 if (OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &colName
, &nCount
, OCI_ATTR_NAME
, pConn
->handleError
) == OCI_SUCCESS
)
905 // We are in UTF-16 mode, so OCIAttrGet will return UTF-16 strings
906 pResult
->columnNames
[i
] = MBStringFromUCS2String((UCS2CHAR
*)colName
);
910 pResult
->columnNames
[i
] = strdup("");
915 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &type
, NULL
, OCI_ATTR_DATA_TYPE
, pConn
->handleError
);
916 if (type
== OCI_TYPECODE_CLOB
)
918 pBuffers
[i
].pData
= NULL
;
919 OCIDescriptorAlloc(pConn
->handleEnv
, (void **)&pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
, 0, NULL
);
921 nStatus
= OCIDefineByPos(handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
922 &pBuffers
[i
].lobLocator
, 0, SQLT_CLOB
, &pBuffers
[i
].isNull
,
923 NULL
, NULL
, OCI_DEFAULT
);
927 pBuffers
[i
].lobLocator
= NULL
;
928 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &nWidth
, NULL
, OCI_ATTR_DATA_SIZE
, pConn
->handleError
);
929 pBuffers
[i
].pData
= (UCS2CHAR
*)malloc((nWidth
+ 31) * sizeof(UCS2CHAR
));
931 nStatus
= OCIDefineByPos(handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
932 pBuffers
[i
].pData
, (nWidth
+ 31) * sizeof(UCS2CHAR
),
933 SQLT_CHR
, &pBuffers
[i
].isNull
, &pBuffers
[i
].nLength
,
934 &pBuffers
[i
].nCode
, OCI_DEFAULT
);
936 if (nStatus
!= OCI_SUCCESS
)
939 *pdwError
= IsConnectionError(pConn
);
941 OCIDescriptorFree(handleParam
, OCI_DTYPE_PARAM
);
946 *pdwError
= IsConnectionError(pConn
);
951 if (nStatus
== OCI_SUCCESS
)
956 nStatus
= OCIStmtFetch2(handleStmt
, pConn
->handleError
, 1, OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
957 if (nStatus
== OCI_NO_DATA
)
959 *pdwError
= DBERR_SUCCESS
; // EOF
962 if ((nStatus
!= OCI_SUCCESS
) && (nStatus
!= OCI_SUCCESS_WITH_INFO
))
965 *pdwError
= IsConnectionError(pConn
);
971 pResult
->pData
= (WCHAR
**)realloc(pResult
->pData
, sizeof(WCHAR
*) * pResult
->nCols
* pResult
->nRows
);
972 for(int i
= 0; i
< pResult
->nCols
; i
++)
974 if (pBuffers
[i
].isNull
)
976 pResult
->pData
[nPos
] = (WCHAR
*)nx_memdup("\0\0\0", sizeof(WCHAR
));
978 else if (pBuffers
[i
].lobLocator
!= NULL
)
982 OCILobGetLength(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &length
);
983 pResult
->pData
[nPos
] = (WCHAR
*)malloc((length
+ 1) * sizeof(WCHAR
));
985 UCS2CHAR
*ucs2buffer
= (UCS2CHAR
*)malloc(sizeof(UCS2CHAR
) * length
);
986 OCILobRead(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &amount
, 1,
987 ucs2buffer
, length
* sizeof(UCS2CHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
988 ucs2_to_ucs4(ucs2buffer
, length
, pResult
->pData
[nPos
], length
+ 1);
991 OCILobRead(pConn
->handleService
, pConn
->handleError
, pBuffers
[i
].lobLocator
, &amount
, 1,
992 pResult
->pData
[nPos
], (length
+ 1) * sizeof(WCHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
994 pResult
->pData
[nPos
][length
] = 0;
998 int length
= pBuffers
[i
].nLength
/ sizeof(UCS2CHAR
);
999 pResult
->pData
[nPos
] = (WCHAR
*)malloc((length
+ 1) * sizeof(WCHAR
));
1001 ucs2_to_ucs4(pBuffers
[i
].pData
, length
, pResult
->pData
[nPos
], length
+ 1);
1003 memcpy(pResult
->pData
[nPos
], pBuffers
[i
].pData
, pBuffers
[i
].nLength
);
1005 pResult
->pData
[nPos
][length
] = 0;
1013 for(int i
= 0; i
< pResult
->nCols
; i
++)
1015 safe_free(pBuffers
[i
].pData
);
1016 if (pBuffers
[i
].lobLocator
!= NULL
)
1018 OCIDescriptorFree(pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
);
1023 // Destroy results in case of error
1024 if (*pdwError
!= DBERR_SUCCESS
)
1026 DestroyQueryResult(pResult
);
1035 * Perform SELECT query
1037 extern "C" DBDRV_RESULT EXPORT
DrvSelect(ORACLE_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
1039 ORACLE_RESULT
*pResult
= NULL
;
1040 OCIStmt
*handleStmt
;
1043 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
1045 UCS2CHAR
*ucs2Query
= pwszQuery
;
1048 MutexLock(pConn
->mutexQueryLock
);
1049 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
1050 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
1052 OCIAttrSet(handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1053 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
,
1054 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1056 pResult
= ProcessQueryResults(pConn
, handleStmt
, pdwError
);
1060 SetLastError(pConn
);
1061 *pdwError
= IsConnectionError(pConn
);
1063 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
1067 SetLastError(pConn
);
1068 *pdwError
= IsConnectionError(pConn
);
1070 if (errorText
!= NULL
)
1072 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1073 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1075 MutexUnlock(pConn
->mutexQueryLock
);
1084 * Perform SELECT query using prepared statement
1086 extern "C" DBDRV_RESULT EXPORT
DrvSelectPrepared(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, DWORD
*pdwError
, WCHAR
*errorText
)
1088 ORACLE_RESULT
*pResult
= NULL
;
1090 MutexLock(pConn
->mutexQueryLock
);
1091 OCIAttrSet(stmt
->handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1092 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
1093 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1095 pResult
= ProcessQueryResults(pConn
, stmt
->handleStmt
, pdwError
);
1099 SetLastError(pConn
);
1100 *pdwError
= IsConnectionError(pConn
);
1103 if (errorText
!= NULL
)
1105 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1106 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1108 MutexUnlock(pConn
->mutexQueryLock
);
1114 * Get field length from result
1116 extern "C" LONG EXPORT
DrvGetFieldLength(ORACLE_RESULT
*pResult
, int nRow
, int nColumn
)
1118 if (pResult
== NULL
)
1121 if ((nRow
>= 0) && (nRow
< pResult
->nRows
) &&
1122 (nColumn
>= 0) && (nColumn
< pResult
->nCols
))
1123 return (LONG
)wcslen(pResult
->pData
[pResult
->nCols
* nRow
+ nColumn
]);
1129 * Get field value from result
1131 extern "C" WCHAR EXPORT
*DrvGetField(ORACLE_RESULT
*pResult
, int nRow
, int nColumn
,
1132 WCHAR
*pBuffer
, int nBufLen
)
1134 WCHAR
*pValue
= NULL
;
1136 if (pResult
!= NULL
)
1138 if ((nRow
< pResult
->nRows
) && (nRow
>= 0) &&
1139 (nColumn
< pResult
->nCols
) && (nColumn
>= 0))
1142 wcsncpy_s(pBuffer
, nBufLen
, pResult
->pData
[nRow
* pResult
->nCols
+ nColumn
], _TRUNCATE
);
1144 wcsncpy(pBuffer
, pResult
->pData
[nRow
* pResult
->nCols
+ nColumn
], nBufLen
);
1145 pBuffer
[nBufLen
- 1] = 0;
1154 * Get number of rows in result
1156 extern "C" int EXPORT
DrvGetNumRows(ORACLE_RESULT
*pResult
)
1158 return (pResult
!= NULL
) ? pResult
->nRows
: 0;
1162 * Get column count in query result
1164 extern "C" int EXPORT
DrvGetColumnCount(ORACLE_RESULT
*pResult
)
1166 return (pResult
!= NULL
) ? pResult
->nCols
: 0;
1170 * Get column name in query result
1172 extern "C" const char EXPORT
*DrvGetColumnName(ORACLE_RESULT
*pResult
, int column
)
1174 return ((pResult
!= NULL
) && (column
>= 0) && (column
< pResult
->nCols
)) ? pResult
->columnNames
[column
] : NULL
;
1178 * Free SELECT results
1180 extern "C" void EXPORT
DrvFreeResult(ORACLE_RESULT
*pResult
)
1182 if (pResult
!= NULL
)
1183 DestroyQueryResult(pResult
);
1187 * Destroy unbuffered query result
1189 static void DestroyUnbufferedQueryResult(ORACLE_UNBUFFERED_RESULT
*result
, bool freeStatement
)
1194 OCIStmtRelease(result
->handleStmt
, result
->connection
->handleError
, NULL
, 0, OCI_DEFAULT
);
1196 for(i
= 0; i
< result
->nCols
; i
++)
1198 free(result
->pBuffers
[i
].pData
);
1199 if (result
->pBuffers
[i
].lobLocator
!= NULL
)
1201 OCIDescriptorFree(result
->pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
);
1204 free(result
->pBuffers
);
1206 for(i
= 0; i
< result
->nCols
; i
++)
1207 free(result
->columnNames
[i
]);
1208 free(result
->columnNames
);
1214 * Process results of unbuffered query execution (prepare for fetching results)
1216 static ORACLE_UNBUFFERED_RESULT
*ProcessUnbufferedQueryResults(ORACLE_CONN
*pConn
, OCIStmt
*handleStmt
, DWORD
*pdwError
)
1218 ORACLE_UNBUFFERED_RESULT
*result
= (ORACLE_UNBUFFERED_RESULT
*)malloc(sizeof(ORACLE_UNBUFFERED_RESULT
));
1219 result
->handleStmt
= handleStmt
;
1220 result
->connection
= pConn
;
1223 OCIAttrGet(result
->handleStmt
, OCI_HTYPE_STMT
, &nCount
, NULL
, OCI_ATTR_PARAM_COUNT
, pConn
->handleError
);
1224 result
->nCols
= nCount
;
1225 if (result
->nCols
> 0)
1227 // Prepare receive buffers and fetch column names
1228 result
->columnNames
= (char **)calloc(result
->nCols
, sizeof(char *));
1229 result
->pBuffers
= (ORACLE_FETCH_BUFFER
*)calloc(result
->nCols
, sizeof(ORACLE_FETCH_BUFFER
));
1230 for(int i
= 0; i
< result
->nCols
; i
++)
1232 OCIParam
*handleParam
;
1234 result
->pBuffers
[i
].isNull
= 1; // Mark all columns as NULL initially
1235 if (OCIParamGet(result
->handleStmt
, OCI_HTYPE_STMT
, pConn
->handleError
,
1236 (void **)&handleParam
, (ub4
)(i
+ 1)) == OCI_SUCCESS
)
1240 if (OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &colName
, &nCount
, OCI_ATTR_NAME
, pConn
->handleError
) == OCI_SUCCESS
)
1242 // We are in UTF-16 mode, so OCIAttrGet will return UTF-16 strings
1243 result
->columnNames
[i
] = MBStringFromUCS2String((UCS2CHAR
*)colName
);
1247 result
->columnNames
[i
] = strdup("");
1253 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &type
, NULL
, OCI_ATTR_DATA_TYPE
, pConn
->handleError
);
1254 OCIDefine
*handleDefine
;
1255 if (type
== OCI_TYPECODE_CLOB
)
1257 result
->pBuffers
[i
].pData
= NULL
;
1258 OCIDescriptorAlloc(pConn
->handleEnv
, (void **)&result
->pBuffers
[i
].lobLocator
, OCI_DTYPE_LOB
, 0, NULL
);
1259 handleDefine
= NULL
;
1260 nStatus
= OCIDefineByPos(result
->handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
1261 &result
->pBuffers
[i
].lobLocator
, 0, SQLT_CLOB
, &result
->pBuffers
[i
].isNull
,
1262 NULL
, NULL
, OCI_DEFAULT
);
1267 result
->pBuffers
[i
].lobLocator
= NULL
;
1268 OCIAttrGet(handleParam
, OCI_DTYPE_PARAM
, &nWidth
, NULL
, OCI_ATTR_DATA_SIZE
, pConn
->handleError
);
1269 result
->pBuffers
[i
].pData
= (UCS2CHAR
*)malloc((nWidth
+ 31) * sizeof(UCS2CHAR
));
1270 handleDefine
= NULL
;
1271 nStatus
= OCIDefineByPos(result
->handleStmt
, &handleDefine
, pConn
->handleError
, i
+ 1,
1272 result
->pBuffers
[i
].pData
, (nWidth
+ 31) * sizeof(UCS2CHAR
),
1273 SQLT_CHR
, &result
->pBuffers
[i
].isNull
, &result
->pBuffers
[i
].nLength
,
1274 &result
->pBuffers
[i
].nCode
, OCI_DEFAULT
);
1276 OCIDescriptorFree(handleParam
, OCI_DTYPE_PARAM
);
1277 if (nStatus
== OCI_SUCCESS
)
1279 *pdwError
= DBERR_SUCCESS
;
1283 SetLastError(pConn
);
1284 *pdwError
= IsConnectionError(pConn
);
1285 DestroyUnbufferedQueryResult(result
, false);
1292 SetLastError(pConn
);
1293 *pdwError
= IsConnectionError(pConn
);
1294 DestroyUnbufferedQueryResult(result
, false);
1310 * Perform unbuffered SELECT query
1312 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT
DrvSelectUnbuffered(ORACLE_CONN
*pConn
, WCHAR
*pwszQuery
, DWORD
*pdwError
, WCHAR
*errorText
)
1314 ORACLE_UNBUFFERED_RESULT
*result
= NULL
;
1317 UCS2CHAR
*ucs2Query
= UCS2StringFromUCS4String(pwszQuery
);
1319 UCS2CHAR
*ucs2Query
= pwszQuery
;
1322 MutexLock(pConn
->mutexQueryLock
);
1324 OCIStmt
*handleStmt
;
1325 if (OCIStmtPrepare2(pConn
->handleService
, &handleStmt
, pConn
->handleError
, (text
*)ucs2Query
,
1326 (ub4
)ucs2_strlen(ucs2Query
) * sizeof(UCS2CHAR
), NULL
, 0, OCI_NTV_SYNTAX
, OCI_DEFAULT
) == OCI_SUCCESS
)
1328 OCIAttrSet(handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1329 if (OCIStmtExecute(pConn
->handleService
, handleStmt
, pConn
->handleError
,
1330 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1332 result
= ProcessUnbufferedQueryResults(pConn
, handleStmt
, pdwError
);
1336 SetLastError(pConn
);
1337 *pdwError
= IsConnectionError(pConn
);
1342 SetLastError(pConn
);
1343 *pdwError
= IsConnectionError(pConn
);
1350 if ((*pdwError
== DBERR_SUCCESS
) && (result
!= NULL
))
1353 // On failure, unlock query mutex and do cleanup
1354 OCIStmtRelease(handleStmt
, pConn
->handleError
, NULL
, 0, OCI_DEFAULT
);
1355 if (errorText
!= NULL
)
1357 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1358 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1360 MutexUnlock(pConn
->mutexQueryLock
);
1365 * Perform SELECT query using prepared statement
1367 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT
DrvSelectPreparedUnbuffered(ORACLE_CONN
*pConn
, ORACLE_STATEMENT
*stmt
, DWORD
*pdwError
, WCHAR
*errorText
)
1369 ORACLE_UNBUFFERED_RESULT
*result
= NULL
;
1371 MutexLock(pConn
->mutexQueryLock
);
1373 OCIAttrSet(stmt
->handleStmt
, OCI_HTYPE_STMT
, &pConn
->prefetchLimit
, 0, OCI_ATTR_PREFETCH_ROWS
, pConn
->handleError
);
1374 if (OCIStmtExecute(pConn
->handleService
, stmt
->handleStmt
, pConn
->handleError
,
1375 0, 0, NULL
, NULL
, (pConn
->nTransLevel
== 0) ? OCI_COMMIT_ON_SUCCESS
: OCI_DEFAULT
) == OCI_SUCCESS
)
1377 result
= ProcessUnbufferedQueryResults(pConn
, stmt
->handleStmt
, pdwError
);
1381 SetLastError(pConn
);
1382 *pdwError
= IsConnectionError(pConn
);
1385 if ((*pdwError
== DBERR_SUCCESS
) && (result
!= NULL
))
1388 // On failure, unlock query mutex and do cleanup
1389 if (errorText
!= NULL
)
1391 wcsncpy(errorText
, pConn
->lastErrorText
, DBDRV_MAX_ERROR_TEXT
);
1392 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1394 MutexUnlock(pConn
->mutexQueryLock
);
1399 * Fetch next result line from unbuffered SELECT results
1401 extern "C" bool EXPORT
DrvFetch(ORACLE_UNBUFFERED_RESULT
*result
)
1408 sword rc
= OCIStmtFetch2(result
->handleStmt
, result
->connection
->handleError
, 1, OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
1409 if ((rc
== OCI_SUCCESS
) || (rc
== OCI_SUCCESS_WITH_INFO
))
1415 SetLastError(result
->connection
);
1422 * Get field length from current row in unbuffered query result
1424 extern "C" LONG EXPORT
DrvGetFieldLengthUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int nColumn
)
1429 if ((nColumn
< 0) || (nColumn
>= result
->nCols
))
1432 if (result
->pBuffers
[nColumn
].isNull
)
1435 if (result
->pBuffers
[nColumn
].lobLocator
!= NULL
)
1438 OCILobGetLength(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &length
);
1439 return (LONG
)length
;
1442 return (LONG
)(result
->pBuffers
[nColumn
].nLength
/ sizeof(UCS2CHAR
));
1446 * Get field from current row in unbuffered query result
1448 extern "C" WCHAR EXPORT
*DrvGetFieldUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int nColumn
, WCHAR
*pBuffer
, int nBufSize
)
1455 if ((nColumn
< 0) || (nColumn
>= result
->nCols
))
1458 if (result
->pBuffers
[nColumn
].isNull
)
1462 else if (result
->pBuffers
[nColumn
].lobLocator
!= NULL
)
1465 OCILobGetLength(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &length
);
1467 nLen
= min(nBufSize
- 1, (int)length
);
1470 UCS2CHAR
*ucs2buffer
= (UCS2CHAR
*)malloc(nLen
* sizeof(UCS2CHAR
));
1471 OCILobRead(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &amount
, 1,
1472 ucs2buffer
, nLen
* sizeof(UCS2CHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
1473 ucs2_to_ucs4(ucs2buffer
, nLen
, pBuffer
, nLen
);
1476 OCILobRead(result
->connection
->handleService
, result
->connection
->handleError
, result
->pBuffers
[nColumn
].lobLocator
, &amount
, 1,
1477 pBuffer
, nBufSize
* sizeof(WCHAR
), NULL
, NULL
, OCI_UCS2ID
, SQLCS_IMPLICIT
);
1483 nLen
= min(nBufSize
- 1, ((int)(result
->pBuffers
[nColumn
].nLength
/ sizeof(UCS2CHAR
))));
1485 ucs2_to_ucs4(result
->pBuffers
[nColumn
].pData
, nLen
, pBuffer
, nLen
+ 1);
1487 memcpy(pBuffer
, result
->pBuffers
[nColumn
].pData
, nLen
* sizeof(WCHAR
));
1496 * Get column count in unbuffered query result
1498 extern "C" int EXPORT
DrvGetColumnCountUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
)
1500 return (result
!= NULL
) ? result
->nCols
: 0;
1504 * Get column name in unbuffered query result
1506 extern "C" const char EXPORT
*DrvGetColumnNameUnbuffered(ORACLE_UNBUFFERED_RESULT
*result
, int column
)
1508 return ((result
!= NULL
) && (column
>= 0) && (column
< result
->nCols
)) ? result
->columnNames
[column
] : NULL
;
1512 * Destroy result of unbuffered query
1514 extern "C" void EXPORT
DrvFreeUnbufferedResult(ORACLE_UNBUFFERED_RESULT
*result
)
1519 MUTEX mutex
= result
->connection
->mutexQueryLock
;
1520 DestroyUnbufferedQueryResult(result
, true);
1527 extern "C" DWORD EXPORT
DrvBegin(ORACLE_CONN
*pConn
)
1530 return DBERR_INVALID_HANDLE
;
1532 MutexLock(pConn
->mutexQueryLock
);
1533 pConn
->nTransLevel
++;
1534 MutexUnlock(pConn
->mutexQueryLock
);
1535 return DBERR_SUCCESS
;
1539 * Commit transaction
1541 extern "C" DWORD EXPORT
DrvCommit(ORACLE_CONN
*pConn
)
1546 return DBERR_INVALID_HANDLE
;
1548 MutexLock(pConn
->mutexQueryLock
);
1549 if (pConn
->nTransLevel
> 0)
1551 if (OCITransCommit(pConn
->handleService
, pConn
->handleError
, OCI_DEFAULT
) == OCI_SUCCESS
)
1553 dwResult
= DBERR_SUCCESS
;
1554 pConn
->nTransLevel
= 0;
1558 SetLastError(pConn
);
1559 dwResult
= IsConnectionError(pConn
);
1564 dwResult
= DBERR_SUCCESS
;
1566 MutexUnlock(pConn
->mutexQueryLock
);
1571 * Rollback transaction
1573 extern "C" DWORD EXPORT
DrvRollback(ORACLE_CONN
*pConn
)
1578 return DBERR_INVALID_HANDLE
;
1580 MutexLock(pConn
->mutexQueryLock
);
1581 if (pConn
->nTransLevel
> 0)
1583 if (OCITransRollback(pConn
->handleService
, pConn
->handleError
, OCI_DEFAULT
) == OCI_SUCCESS
)
1585 dwResult
= DBERR_SUCCESS
;
1586 pConn
->nTransLevel
= 0;
1590 SetLastError(pConn
);
1591 dwResult
= IsConnectionError(pConn
);
1596 dwResult
= DBERR_SUCCESS
;
1598 MutexUnlock(pConn
->mutexQueryLock
);
1603 * Check if table exist
1605 extern "C" int EXPORT
DrvIsTableExist(ORACLE_CONN
*pConn
, const WCHAR
*name
)
1608 swprintf(query
, 256, L
"SELECT count(*) FROM user_tables WHERE table_name=upper('%ls')", name
);
1610 WCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1611 int rc
= DBIsTableExist_Failure
;
1612 ORACLE_RESULT
*hResult
= (ORACLE_RESULT
*)DrvSelect(pConn
, query
, &error
, errorText
);
1613 if (hResult
!= NULL
)
1615 WCHAR buffer
[64] = L
"";
1616 DrvGetField(hResult
, 0, 0, buffer
, 64);
1617 rc
= (wcstol(buffer
, NULL
, 10) > 0) ? DBIsTableExist_Found
: DBIsTableExist_NotFound
;
1618 DrvFreeResult(hResult
);
1628 bool WINAPI
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpReserved
)
1630 if (dwReason
== DLL_PROCESS_ATTACH
)
1631 DisableThreadLibraryCalls(hInstance
);