2 ** NetXMS - Network Management System
3 ** Database Abstraction Library
4 ** Copyright (C) 2003-2016 Victor Kirhenshtein
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * Check if statement handle is valid
29 #define IS_VALID_STATEMENT_HANDLE(s) ((s != NULL) && (s->m_connection != NULL))
32 * Performance counters
34 static UINT64 s_perfSelectQueries
= 0;
35 static UINT64 s_perfNonSelectQueries
= 0;
36 static UINT64 s_perfTotalQueries
= 0;
37 static UINT64 s_perfLongRunningQueries
= 0;
38 static UINT64 s_perfFailedQueries
= 0;
41 * Session init callback
43 static void (*s_sessionInitCb
)(DB_HANDLE session
) = NULL
;
46 * Invalidate all prepared statements on connection
48 static void InvalidatePreparedStatements(DB_HANDLE hConn
)
50 for(int i
= 0; i
< hConn
->m_preparedStatements
->size(); i
++)
52 db_statement_t
*stmt
= hConn
->m_preparedStatements
->get(i
);
53 hConn
->m_driver
->m_fpDrvFreeStatement(stmt
->m_statement
);
54 stmt
->m_statement
= NULL
;
55 stmt
->m_connection
= NULL
;
57 hConn
->m_preparedStatements
->clear();
63 DB_HANDLE LIBNXDB_EXPORTABLE
DBConnect(DB_DRIVER driver
, const TCHAR
*server
, const TCHAR
*dbName
,
64 const TCHAR
*login
, const TCHAR
*password
, const TCHAR
*schema
, TCHAR
*errorText
)
66 DBDRV_CONNECTION hDrvConn
;
67 DB_HANDLE hConn
= NULL
;
69 nxlog_debug(8, _T("DBConnect: server=%s db=%s login=%s schema=%s"), CHECK_NULL(server
), CHECK_NULL(dbName
), CHECK_NULL(login
), CHECK_NULL(schema
));
71 char *mbServer
= (server
== NULL
) ? NULL
: MBStringFromWideString(server
);
72 char *mbDatabase
= (dbName
== NULL
) ? NULL
: MBStringFromWideString(dbName
);
73 char *mbLogin
= (login
== NULL
) ? NULL
: MBStringFromWideString(login
);
74 char *mbPassword
= (password
== NULL
) ? NULL
: MBStringFromWideString(password
);
75 char *mbSchema
= (schema
== NULL
) ? NULL
: MBStringFromWideString(schema
);
77 hDrvConn
= driver
->m_fpDrvConnect(mbServer
, mbLogin
, mbPassword
, mbDatabase
, mbSchema
, errorText
);
79 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
80 hDrvConn
= driver
->m_fpDrvConnect(server
, login
, password
, dbName
, schema
, wcErrorText
);
81 WideCharToMultiByte(CP_ACP
, WC_DEFAULTCHAR
| WC_COMPOSITECHECK
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
82 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
86 hConn
= (DB_HANDLE
)malloc(sizeof(struct db_handle_t
));
89 hConn
->m_driver
= driver
;
90 hConn
->m_dumpSql
= driver
->m_dumpSql
;
91 hConn
->m_reconnectEnabled
= true;
92 hConn
->m_connection
= hDrvConn
;
93 hConn
->m_mutexTransLock
= MutexCreateRecursive();
94 hConn
->m_transactionLevel
= 0;
95 hConn
->m_preparedStatements
= new ObjectArray
<db_statement_t
>(4, 4, false);
97 hConn
->m_dbName
= mbDatabase
;
98 hConn
->m_login
= mbLogin
;
99 hConn
->m_password
= mbPassword
;
100 hConn
->m_server
= mbServer
;
101 hConn
->m_schema
= mbSchema
;
103 hConn
->m_dbName
= (dbName
== NULL
) ? NULL
: _tcsdup(dbName
);
104 hConn
->m_login
= (login
== NULL
) ? NULL
: _tcsdup(login
);
105 hConn
->m_password
= (password
== NULL
) ? NULL
: _tcsdup(password
);
106 hConn
->m_server
= (server
== NULL
) ? NULL
: _tcsdup(server
);
107 hConn
->m_schema
= (schema
== NULL
) ? NULL
: _tcsdup(schema
);
109 if (driver
->m_fpDrvSetPrefetchLimit
!= NULL
)
110 driver
->m_fpDrvSetPrefetchLimit(hDrvConn
, driver
->m_defaultPrefetchLimit
);
111 nxlog_debug(4, _T("New DB connection opened: handle=%p"), hConn
);
112 if (s_sessionInitCb
!= NULL
)
113 s_sessionInitCb(hConn
);
117 driver
->m_fpDrvDisconnect(hDrvConn
);
124 safe_free(mbDatabase
);
126 safe_free(mbPassword
);
134 * Disconnect from database
136 void LIBNXDB_EXPORTABLE
DBDisconnect(DB_HANDLE hConn
)
141 nxlog_debug(4, _T("DB connection %p closed"), hConn
);
143 InvalidatePreparedStatements(hConn
);
145 hConn
->m_driver
->m_fpDrvDisconnect(hConn
->m_connection
);
146 MutexDestroy(hConn
->m_mutexTransLock
);
147 safe_free(hConn
->m_dbName
);
148 safe_free(hConn
->m_login
);
149 safe_free(hConn
->m_password
);
150 safe_free(hConn
->m_server
);
151 safe_free(hConn
->m_schema
);
152 delete hConn
->m_preparedStatements
;
157 * Enable/disable reconnect
159 void LIBNXDB_EXPORTABLE
DBEnableReconnect(DB_HANDLE hConn
, bool enabled
)
163 hConn
->m_reconnectEnabled
= enabled
;
168 * Reconnect to database
170 static void DBReconnect(DB_HANDLE hConn
)
173 WCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
175 nxlog_debug(4, _T("DB reconnect: handle=%p"), hConn
);
177 InvalidatePreparedStatements(hConn
);
178 hConn
->m_driver
->m_fpDrvDisconnect(hConn
->m_connection
);
179 for(nCount
= 0; ; nCount
++)
181 hConn
->m_connection
= hConn
->m_driver
->m_fpDrvConnect(hConn
->m_server
, hConn
->m_login
,
182 hConn
->m_password
, hConn
->m_dbName
, hConn
->m_schema
, errorText
);
183 if (hConn
->m_connection
!= NULL
)
185 if (hConn
->m_driver
->m_fpDrvSetPrefetchLimit
!= NULL
)
186 hConn
->m_driver
->m_fpDrvSetPrefetchLimit(hConn
->m_connection
, hConn
->m_driver
->m_defaultPrefetchLimit
);
187 if (s_sessionInitCb
!= NULL
)
188 s_sessionInitCb(hConn
);
193 MutexLock(hConn
->m_driver
->m_mutexReconnect
);
194 if ((hConn
->m_driver
->m_reconnect
== 0) && (hConn
->m_driver
->m_fpEventHandler
!= NULL
))
195 hConn
->m_driver
->m_fpEventHandler(DBEVENT_CONNECTION_LOST
, NULL
, NULL
, true, hConn
->m_driver
->m_userArg
);
196 hConn
->m_driver
->m_reconnect
++;
197 MutexUnlock(hConn
->m_driver
->m_mutexReconnect
);
203 MutexLock(hConn
->m_driver
->m_mutexReconnect
);
204 hConn
->m_driver
->m_reconnect
--;
205 if ((hConn
->m_driver
->m_reconnect
== 0) && (hConn
->m_driver
->m_fpEventHandler
!= NULL
))
206 hConn
->m_driver
->m_fpEventHandler(DBEVENT_CONNECTION_RESTORED
, NULL
, NULL
, false, hConn
->m_driver
->m_userArg
);
207 MutexUnlock(hConn
->m_driver
->m_mutexReconnect
);
212 * Set default prefetch limit
214 void LIBNXDB_EXPORTABLE
DBSetDefaultPrefetchLimit(DB_DRIVER driver
, int limit
)
216 driver
->m_defaultPrefetchLimit
= limit
;
222 bool LIBNXDB_EXPORTABLE
DBSetPrefetchLimit(DB_HANDLE hConn
, int limit
)
224 if (hConn
->m_driver
->m_fpDrvSetPrefetchLimit
== NULL
)
225 return false; // Not supported by driver
226 return hConn
->m_driver
->m_fpDrvSetPrefetchLimit(hConn
->m_connection
, limit
);
230 * Set session initialization callback
232 void LIBNXDB_EXPORTABLE
DBSetSessionInitCallback(void (*cb
)(DB_HANDLE
))
234 s_sessionInitCb
= cb
;
238 * Perform a non-SELECT SQL query
240 bool LIBNXDB_EXPORTABLE
DBQueryEx(DB_HANDLE hConn
, const TCHAR
*szQuery
, TCHAR
*errorText
)
244 #define pwszQuery szQuery
245 #define wcErrorText errorText
247 WCHAR
*pwszQuery
= WideStringFromMBString(szQuery
);
248 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
251 MutexLock(hConn
->m_mutexTransLock
);
252 INT64 ms
= GetCurrentTimeMs();
254 dwResult
= hConn
->m_driver
->m_fpDrvQuery(hConn
->m_connection
, pwszQuery
, wcErrorText
);
255 if ((dwResult
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
258 dwResult
= hConn
->m_driver
->m_fpDrvQuery(hConn
->m_connection
, pwszQuery
, wcErrorText
);
261 s_perfNonSelectQueries
++;
262 s_perfTotalQueries
++;
264 ms
= GetCurrentTimeMs() - ms
;
265 if (hConn
->m_driver
->m_dumpSql
)
267 nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (dwResult
== DBERR_SUCCESS
) ? _T("Successful") : _T("Failed"), szQuery
, ms
);
269 if ((dwResult
== DBERR_SUCCESS
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
271 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery
, (int)ms
);
272 s_perfLongRunningQueries
++;
275 MutexUnlock(hConn
->m_mutexTransLock
);
278 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
279 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
282 if (dwResult
!= DBERR_SUCCESS
)
284 s_perfFailedQueries
++;
285 if (hConn
->m_driver
->m_logSqlErrors
)
286 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", szQuery
, errorText
);
287 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
288 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, pwszQuery
, wcErrorText
, dwResult
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
295 return dwResult
== DBERR_SUCCESS
;
300 bool LIBNXDB_EXPORTABLE
DBQuery(DB_HANDLE hConn
, const TCHAR
*query
)
302 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
303 return DBQueryEx(hConn
, query
, errorText
);
307 * Perform SELECT query
309 DB_RESULT LIBNXDB_EXPORTABLE
DBSelectEx(DB_HANDLE hConn
, const TCHAR
*szQuery
, TCHAR
*errorText
)
311 DBDRV_RESULT hResult
;
312 DB_RESULT result
= NULL
;
313 DWORD dwError
= DBERR_OTHER_ERROR
;
315 #define pwszQuery szQuery
316 #define wcErrorText errorText
318 WCHAR
*pwszQuery
= WideStringFromMBString(szQuery
);
319 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
322 MutexLock(hConn
->m_mutexTransLock
);
323 INT64 ms
= GetCurrentTimeMs();
325 s_perfSelectQueries
++;
326 s_perfTotalQueries
++;
328 hResult
= hConn
->m_driver
->m_fpDrvSelect(hConn
->m_connection
, pwszQuery
, &dwError
, wcErrorText
);
329 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
332 hResult
= hConn
->m_driver
->m_fpDrvSelect(hConn
->m_connection
, pwszQuery
, &dwError
, wcErrorText
);
335 ms
= GetCurrentTimeMs() - ms
;
336 if (hConn
->m_driver
->m_dumpSql
)
338 nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), szQuery
, (int)ms
);
340 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
342 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery
, (int)ms
);
343 s_perfLongRunningQueries
++;
345 MutexUnlock(hConn
->m_mutexTransLock
);
348 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
349 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
354 s_perfFailedQueries
++;
355 if (hConn
->m_driver
->m_logSqlErrors
)
356 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", szQuery
, errorText
);
357 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
358 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, pwszQuery
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
367 result
= (DB_RESULT
)malloc(sizeof(db_result_t
));
368 result
->m_driver
= hConn
->m_driver
;
369 result
->m_connection
= hConn
;
370 result
->m_data
= hResult
;
378 DB_RESULT LIBNXDB_EXPORTABLE
DBSelect(DB_HANDLE hConn
, const TCHAR
*query
)
380 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
382 return DBSelectEx(hConn
, query
, errorText
);
386 * Get number of columns
388 int LIBNXDB_EXPORTABLE
DBGetColumnCount(DB_RESULT hResult
)
390 return hResult
->m_driver
->m_fpDrvGetColumnCount(hResult
->m_data
);
396 bool LIBNXDB_EXPORTABLE
DBGetColumnName(DB_RESULT hResult
, int column
, TCHAR
*buffer
, int bufSize
)
400 name
= hResult
->m_driver
->m_fpDrvGetColumnName(hResult
->m_data
, column
);
404 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, name
, -1, buffer
, bufSize
);
405 buffer
[bufSize
- 1] = 0;
407 nx_strncpy(buffer
, name
, bufSize
);
414 * Get column count for unbuffered result set
416 int LIBNXDB_EXPORTABLE
DBGetColumnCount(DB_UNBUFFERED_RESULT hResult
)
418 return hResult
->m_driver
->m_fpDrvGetColumnCountUnbuffered(hResult
->m_data
);
422 * Get column name for unbuffered result set
424 bool LIBNXDB_EXPORTABLE
DBGetColumnName(DB_UNBUFFERED_RESULT hResult
, int column
, TCHAR
*buffer
, int bufSize
)
428 name
= hResult
->m_driver
->m_fpDrvGetColumnNameUnbuffered(hResult
->m_data
, column
);
432 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, name
, -1, buffer
, bufSize
);
433 buffer
[bufSize
- 1] = 0;
435 nx_strncpy(buffer
, name
, bufSize
);
442 * Get field's value. If buffer is NULL, dynamically allocated string will be returned.
443 * Caller is responsible for destroying it by calling free().
445 TCHAR LIBNXDB_EXPORTABLE
*DBGetField(DB_RESULT hResult
, int iRow
, int iColumn
, TCHAR
*pszBuffer
, int nBufLen
)
448 if (pszBuffer
!= NULL
)
451 return hResult
->m_driver
->m_fpDrvGetField(hResult
->m_data
, iRow
, iColumn
, pszBuffer
, nBufLen
);
456 LONG nLen
= hResult
->m_driver
->m_fpDrvGetFieldLength(hResult
->m_data
, iRow
, iColumn
);
464 pszTemp
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
465 hResult
->m_driver
->m_fpDrvGetField(hResult
->m_data
, iRow
, iColumn
, pszTemp
, nLen
);
470 return DBGetFieldA(hResult
, iRow
, iColumn
, pszBuffer
, nBufLen
);
475 * Get field's value as UTF8 string. If buffer is NULL, dynamically allocated string will be returned.
476 * Caller is responsible for destroying it by calling free().
478 char LIBNXDB_EXPORTABLE
*DBGetFieldUTF8(DB_RESULT hResult
, int iRow
, int iColumn
, char *pszBuffer
, int nBufLen
)
480 if (hResult
->m_driver
->m_fpDrvGetFieldUTF8
!= NULL
)
482 if (pszBuffer
!= NULL
)
485 return hResult
->m_driver
->m_fpDrvGetFieldUTF8(hResult
->m_data
, iRow
, iColumn
, pszBuffer
, nBufLen
);
490 LONG nLen
= hResult
->m_driver
->m_fpDrvGetFieldLength(hResult
->m_data
, iRow
, iColumn
);
497 nLen
= nLen
* 2 + 1; // increase buffer size because driver may return field length in characters
498 pszTemp
= (char *)malloc(nLen
);
499 hResult
->m_driver
->m_fpDrvGetFieldUTF8(hResult
->m_data
, iRow
, iColumn
, pszTemp
, nLen
);
506 LONG nLen
= hResult
->m_driver
->m_fpDrvGetFieldLength(hResult
->m_data
, iRow
, iColumn
);
509 nLen
= nLen
* 2 + 1; // increase buffer size because driver may return field length in characters
511 WCHAR
*wtemp
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
512 hResult
->m_driver
->m_fpDrvGetField(hResult
->m_data
, iRow
, iColumn
, wtemp
, nLen
);
513 char *value
= (pszBuffer
!= NULL
) ? pszBuffer
: (char *)malloc(nLen
);
514 WideCharToMultiByte(CP_UTF8
, 0, wtemp
, -1, value
, (pszBuffer
!= NULL
) ? nBufLen
: nLen
, NULL
, NULL
);
521 * Get field's value as multibyte string. If buffer is NULL, dynamically allocated string will be returned.
522 * Caller is responsible for destroying it by calling free().
524 char LIBNXDB_EXPORTABLE
*DBGetFieldA(DB_RESULT hResult
, int iRow
, int iColumn
, char *pszBuffer
, int nBufLen
)
526 WCHAR
*pwszData
, *pwszBuffer
;
530 if (pszBuffer
!= NULL
)
533 pwszBuffer
= (WCHAR
*)malloc(nBufLen
* sizeof(WCHAR
));
534 pwszData
= hResult
->m_driver
->m_fpDrvGetField(hResult
->m_data
, iRow
, iColumn
, pwszBuffer
, nBufLen
);
535 if (pwszData
!= NULL
)
537 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, pwszData
, -1, pszBuffer
, nBufLen
, NULL
, NULL
);
548 nLen
= hResult
->m_driver
->m_fpDrvGetFieldLength(hResult
->m_data
, iRow
, iColumn
);
556 pwszBuffer
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
557 pwszData
= hResult
->m_driver
->m_fpDrvGetField(hResult
->m_data
, iRow
, iColumn
, pwszBuffer
, nLen
);
558 if (pwszData
!= NULL
)
560 nLen
= (int)wcslen(pwszData
) + 1;
561 pszRet
= (char *)malloc(nLen
);
562 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, pwszData
, -1, pszRet
, nLen
, NULL
, NULL
);
575 * Get text field and escape it for XML document. Returned string
576 * always dynamically allocated and must be destroyed by caller.
578 TCHAR LIBNXDB_EXPORTABLE
*DBGetFieldForXML(DB_RESULT hResult
, int row
, int col
)
580 TCHAR
*value
= DBGetField(hResult
, row
, col
, NULL
, 0);
581 TCHAR
*xmlString
= EscapeStringForXML(value
, -1);
587 * Get field's value as unsigned long
589 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldULong(DB_RESULT hResult
, int iRow
, int iColumn
)
593 TCHAR
*pszVal
, szBuffer
[256];
595 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
599 if (*pszVal
== _T('-'))
601 iVal
= _tcstol(pszVal
, NULL
, 10);
602 memcpy(&dwVal
, &iVal
, sizeof(INT32
)); // To prevent possible conversion
606 dwVal
= _tcstoul(pszVal
, NULL
, 10);
612 * Get field's value as unsigned 64-bit int
614 UINT64 LIBNXDB_EXPORTABLE
DBGetFieldUInt64(DB_RESULT hResult
, int iRow
, int iColumn
)
618 TCHAR
*pszVal
, szBuffer
[256];
620 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
624 if (*pszVal
== _T('-'))
626 iVal
= _tcstoll(pszVal
, NULL
, 10);
627 memcpy(&qwVal
, &iVal
, sizeof(INT64
)); // To prevent possible conversion
631 qwVal
= _tcstoull(pszVal
, NULL
, 10);
637 * Get field's value as signed long
639 INT32 LIBNXDB_EXPORTABLE
DBGetFieldLong(DB_RESULT hResult
, int iRow
, int iColumn
)
641 TCHAR
*pszVal
, szBuffer
[256];
643 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
644 return pszVal
== NULL
? 0 : _tcstol(pszVal
, NULL
, 10);
648 * Get field's value as signed 64-bit int
650 INT64 LIBNXDB_EXPORTABLE
DBGetFieldInt64(DB_RESULT hResult
, int iRow
, int iColumn
)
652 TCHAR
*pszVal
, szBuffer
[256];
654 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
655 return pszVal
== NULL
? 0 : _tcstoll(pszVal
, NULL
, 10);
659 * Get field's value as double
661 double LIBNXDB_EXPORTABLE
DBGetFieldDouble(DB_RESULT hResult
, int iRow
, int iColumn
)
663 TCHAR
*pszVal
, szBuffer
[256];
665 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
666 return pszVal
== NULL
? 0 : _tcstod(pszVal
, NULL
);
670 * Get field's value as IPv4 address
672 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldIPAddr(DB_RESULT hResult
, int iRow
, int iColumn
)
674 TCHAR
*pszVal
, szBuffer
[256];
676 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
677 return pszVal
== NULL
? 0 : ntohl(_t_inet_addr(pszVal
));
681 * Get field's value as IP address
683 InetAddress LIBNXDB_EXPORTABLE
DBGetFieldInetAddr(DB_RESULT hResult
, int iRow
, int iColumn
)
685 TCHAR
*pszVal
, szBuffer
[256];
687 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
688 return pszVal
== NULL
? InetAddress() : InetAddress::parse(pszVal
);
692 * Get field's value as integer array from byte array encoded in hex
694 bool LIBNXDB_EXPORTABLE
DBGetFieldByteArray(DB_RESULT hResult
, int iRow
, int iColumn
,
695 int *pnArray
, int nSize
, int nDefault
)
700 TCHAR
*pszVal
, szBuffer
[256];
702 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
705 StrToBin(pszVal
, (BYTE
*)pbBytes
, 128);
706 nLen
= (int)_tcslen(pszVal
) / 2;
707 for(i
= 0; (i
< nSize
) && (i
< nLen
); i
++)
708 pnArray
[i
] = pbBytes
[i
];
709 for(; i
< nSize
; i
++)
710 pnArray
[i
] = nDefault
;
715 for(i
= 0; i
< nSize
; i
++)
716 pnArray
[i
] = nDefault
;
722 bool LIBNXDB_EXPORTABLE
DBGetFieldByteArray2(DB_RESULT hResult
, int iRow
, int iColumn
,
723 BYTE
*data
, int nSize
, int nDefault
)
726 TCHAR
*pszVal
, szBuffer
[256];
728 pszVal
= DBGetField(hResult
, iRow
, iColumn
, szBuffer
, 256);
731 int bytes
= (int)StrToBin(pszVal
, data
, nSize
);
733 memset(&data
[bytes
], 0, nSize
- bytes
);
738 memset(data
, nDefault
, nSize
);
745 * Get field's value as GUID
747 uuid LIBNXDB_EXPORTABLE
DBGetFieldGUID(DB_RESULT hResult
, int iRow
, int iColumn
)
750 TCHAR
*value
= DBGetField(hResult
, iRow
, iColumn
, buffer
, 256);
751 return (value
== NULL
) ? uuid::NULL_UUID
: uuid::parse(value
);
755 * Get number of rows in result
757 int LIBNXDB_EXPORTABLE
DBGetNumRows(DB_RESULT hResult
)
761 return hResult
->m_driver
->m_fpDrvGetNumRows(hResult
->m_data
);
767 void LIBNXDB_EXPORTABLE
DBFreeResult(DB_RESULT hResult
)
771 hResult
->m_driver
->m_fpDrvFreeResult(hResult
->m_data
);
777 * Unbuffered SELECT query
779 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectUnbufferedEx(DB_HANDLE hConn
, const TCHAR
*szQuery
, TCHAR
*errorText
)
781 DBDRV_UNBUFFERED_RESULT hResult
;
782 DB_UNBUFFERED_RESULT result
= NULL
;
783 DWORD dwError
= DBERR_OTHER_ERROR
;
785 #define pwszQuery szQuery
786 #define wcErrorText errorText
788 WCHAR
*pwszQuery
= WideStringFromMBString(szQuery
);
789 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
792 MutexLock(hConn
->m_mutexTransLock
);
793 INT64 ms
= GetCurrentTimeMs();
795 s_perfSelectQueries
++;
796 s_perfTotalQueries
++;
798 hResult
= hConn
->m_driver
->m_fpDrvSelectUnbuffered(hConn
->m_connection
, pwszQuery
, &dwError
, wcErrorText
);
799 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
802 hResult
= hConn
->m_driver
->m_fpDrvSelectUnbuffered(hConn
->m_connection
, pwszQuery
, &dwError
, wcErrorText
);
805 ms
= GetCurrentTimeMs() - ms
;
806 if (hConn
->m_driver
->m_dumpSql
)
808 nxlog_debug(9, _T("%s unbuffered query: \"%s\" [%d ms]"), (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), szQuery
, (int)ms
);
810 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
812 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery
, (int)ms
);
813 s_perfLongRunningQueries
++;
817 s_perfFailedQueries
++;
818 MutexUnlock(hConn
->m_mutexTransLock
);
821 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
822 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
825 if (hConn
->m_driver
->m_logSqlErrors
)
826 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", szQuery
, errorText
);
827 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
828 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, pwszQuery
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
837 result
= (DB_UNBUFFERED_RESULT
)malloc(sizeof(db_unbuffered_result_t
));
838 result
->m_driver
= hConn
->m_driver
;
839 result
->m_connection
= hConn
;
840 result
->m_data
= hResult
;
848 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectUnbuffered(DB_HANDLE hConn
, const TCHAR
*query
)
850 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
852 return DBSelectUnbufferedEx(hConn
, query
, errorText
);
856 * Fetch next row from unbuffered SELECT result
858 bool LIBNXDB_EXPORTABLE
DBFetch(DB_UNBUFFERED_RESULT hResult
)
860 return hResult
->m_driver
->m_fpDrvFetch(hResult
->m_data
);
864 * Get field's value from unbuffered SELECT result
866 TCHAR LIBNXDB_EXPORTABLE
*DBGetField(DB_UNBUFFERED_RESULT hResult
, int iColumn
, TCHAR
*pBuffer
, int iBufSize
)
871 return hResult
->m_driver
->m_fpDrvGetFieldUnbuffered(hResult
->m_data
, iColumn
, pBuffer
, iBufSize
);
878 nLen
= hResult
->m_driver
->m_fpDrvGetFieldLengthUnbuffered(hResult
->m_data
, iColumn
);
886 pszTemp
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
887 hResult
->m_driver
->m_fpDrvGetFieldUnbuffered(hResult
->m_data
, iColumn
, pszTemp
, nLen
);
892 WCHAR
*pwszData
, *pwszBuffer
;
898 pwszBuffer
= (WCHAR
*)malloc(iBufSize
* sizeof(WCHAR
));
899 if (hResult
->m_driver
->m_fpDrvGetFieldUnbuffered(hResult
->m_data
, iColumn
, pwszBuffer
, iBufSize
) != NULL
)
901 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
,
902 pwszBuffer
, -1, pBuffer
, iBufSize
, NULL
, NULL
);
913 nLen
= hResult
->m_driver
->m_fpDrvGetFieldLengthUnbuffered(hResult
->m_data
, iColumn
);
921 pwszBuffer
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
922 pwszData
= hResult
->m_driver
->m_fpDrvGetFieldUnbuffered(hResult
->m_data
, iColumn
, pwszBuffer
, nLen
);
923 if (pwszData
!= NULL
)
925 nLen
= (int)wcslen(pwszData
) + 1;
926 pszRet
= (char *)malloc(nLen
);
927 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
,
928 pwszData
, -1, pszRet
, nLen
, NULL
, NULL
);
942 * Get field's value as unsigned long from unbuffered SELECT result
944 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldULong(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
950 if (DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
)
953 if (szBuffer
[0] == _T('-'))
955 iVal
= _tcstol(szBuffer
, NULL
, 10);
956 memcpy(&dwVal
, &iVal
, sizeof(INT32
)); // To prevent possible conversion
960 dwVal
= _tcstoul(szBuffer
, NULL
, 10);
966 * Get field's value as unsigned 64-bit int from unbuffered SELECT result
968 UINT64 LIBNXDB_EXPORTABLE
DBGetFieldUInt64(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
974 if (DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
)
977 if (szBuffer
[0] == _T('-'))
979 iVal
= _tcstoll(szBuffer
, NULL
, 10);
980 memcpy(&qwVal
, &iVal
, sizeof(INT64
)); // To prevent possible conversion
984 qwVal
= _tcstoull(szBuffer
, NULL
, 10);
990 * Get field's value as signed long from unbuffered SELECT result
992 INT32 LIBNXDB_EXPORTABLE
DBGetFieldLong(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
995 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstol(szBuffer
, NULL
, 10);
999 * Get field's value as signed 64-bit int from unbuffered SELECT result
1001 INT64 LIBNXDB_EXPORTABLE
DBGetFieldInt64(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1004 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstoll(szBuffer
, NULL
, 10);
1008 * Get field's value as signed long from unbuffered SELECT result
1010 double LIBNXDB_EXPORTABLE
DBGetFieldDouble(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1013 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstod(szBuffer
, NULL
);
1017 * Get field's value as IPv4 address from unbuffered SELECT result
1019 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldIPAddr(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1022 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? INADDR_NONE
: ntohl(_t_inet_addr(buffer
));
1026 * Get field's value as IP address from unbuffered SELECT result
1028 InetAddress LIBNXDB_EXPORTABLE
DBGetFieldInetAddr(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1031 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? InetAddress() : InetAddress::parse(buffer
);
1035 * Get field's value as GUID from unbuffered SELECT result
1037 uuid LIBNXDB_EXPORTABLE
DBGetFieldGUID(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1040 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? uuid::NULL_UUID
: uuid::parse(buffer
);
1044 * Free unbuffered SELECT result
1046 void LIBNXDB_EXPORTABLE
DBFreeResult(DB_UNBUFFERED_RESULT hResult
)
1048 hResult
->m_driver
->m_fpDrvFreeUnbufferedResult(hResult
->m_data
);
1049 MutexUnlock(hResult
->m_connection
->m_mutexTransLock
);
1056 DB_STATEMENT LIBNXDB_EXPORTABLE
DBPrepareEx(DB_HANDLE hConn
, const TCHAR
*query
, TCHAR
*errorText
)
1058 DB_STATEMENT result
= NULL
;
1062 #define pwszQuery query
1063 #define wcErrorText errorText
1065 WCHAR
*pwszQuery
= WideStringFromMBString(query
);
1066 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1069 MutexLock(hConn
->m_mutexTransLock
);
1071 if (hConn
->m_driver
->m_dumpSql
)
1072 ms
= GetCurrentTimeMs();
1075 DBDRV_STATEMENT stmt
= hConn
->m_driver
->m_fpDrvPrepare(hConn
->m_connection
, pwszQuery
, &errorCode
, wcErrorText
);
1076 if ((stmt
== NULL
) && (errorCode
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1079 stmt
= hConn
->m_driver
->m_fpDrvPrepare(hConn
->m_connection
, pwszQuery
, &errorCode
, wcErrorText
);
1081 MutexUnlock(hConn
->m_mutexTransLock
);
1085 result
= (DB_STATEMENT
)malloc(sizeof(db_statement_t
));
1086 result
->m_driver
= hConn
->m_driver
;
1087 result
->m_connection
= hConn
;
1088 result
->m_statement
= stmt
;
1089 result
->m_query
= _tcsdup(query
);
1094 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1095 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1098 if (hConn
->m_driver
->m_logSqlErrors
)
1099 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", query
, errorText
);
1100 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1101 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, pwszQuery
, wcErrorText
, errorCode
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1103 s_perfFailedQueries
++;
1104 s_perfTotalQueries
++;
1107 if (hConn
->m_driver
->m_dumpSql
)
1109 ms
= GetCurrentTimeMs() - ms
;
1110 nxlog_debug(9, _T("{%p} %s prepare: \"%s\" [%d ms]"), result
, (result
!= NULL
) ? _T("Successful") : _T("Failed"), query
, ms
);
1119 hConn
->m_preparedStatements
->add(result
);
1130 DB_STATEMENT LIBNXDB_EXPORTABLE
DBPrepare(DB_HANDLE hConn
, const TCHAR
*query
)
1132 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1133 return DBPrepareEx(hConn
, query
, errorText
);
1137 * Destroy prepared statement
1139 void LIBNXDB_EXPORTABLE
DBFreeStatement(DB_STATEMENT hStmt
)
1144 if (hStmt
->m_connection
!= NULL
)
1146 hStmt
->m_connection
->m_preparedStatements
->remove(hStmt
);
1148 hStmt
->m_driver
->m_fpDrvFreeStatement(hStmt
->m_statement
);
1149 safe_free(hStmt
->m_query
);
1154 * Get source query for prepared statement
1156 const TCHAR LIBNXDB_EXPORTABLE
*DBGetStatementSource(DB_STATEMENT hStmt
)
1158 return hStmt
->m_query
;
1164 bool LIBNXDB_EXPORTABLE
DBOpenBatch(DB_STATEMENT hStmt
)
1166 if (!IS_VALID_STATEMENT_HANDLE(hStmt
) || (hStmt
->m_driver
->m_fpDrvOpenBatch
== NULL
))
1168 return hStmt
->m_driver
->m_fpDrvOpenBatch(hStmt
->m_statement
);
1172 * Start next batch row batch
1174 void LIBNXDB_EXPORTABLE
DBNextBatchRow(DB_STATEMENT hStmt
)
1176 if (IS_VALID_STATEMENT_HANDLE(hStmt
) && (hStmt
->m_driver
->m_fpDrvNextBatchRow
!= NULL
))
1177 hStmt
->m_driver
->m_fpDrvNextBatchRow(hStmt
->m_statement
);
1181 * Bind parameter (generic)
1183 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
1185 if ((pos
<= 0) || !IS_VALID_STATEMENT_HANDLE(hStmt
))
1188 if (hStmt
->m_connection
->m_driver
->m_dumpSql
)
1190 if (cType
== DB_CTYPE_STRING
)
1192 nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt
, pos
, buffer
);
1199 case DB_CTYPE_INT32
:
1200 _sntprintf(text
, 64, _T("%d"), *((INT32
*)buffer
));
1202 case DB_CTYPE_UINT32
:
1203 _sntprintf(text
, 64, _T("%u"), *((UINT32
*)buffer
));
1205 case DB_CTYPE_INT64
:
1206 _sntprintf(text
, 64, INT64_FMT
, *((INT64
*)buffer
));
1208 case DB_CTYPE_UINT64
:
1209 _sntprintf(text
, 64, UINT64_FMT
, *((UINT64
*)buffer
));
1211 case DB_CTYPE_DOUBLE
:
1212 _sntprintf(text
, 64, _T("%f"), *((double *)buffer
));
1215 nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt
, pos
, text
);
1220 #define wBuffer buffer
1221 #define realAllocType allocType
1224 int realAllocType
= allocType
;
1225 if (cType
== DB_CTYPE_STRING
)
1227 wBuffer
= (void *)WideStringFromMBString((char *)buffer
);
1228 if (allocType
== DB_BIND_DYNAMIC
)
1230 realAllocType
= DB_BIND_DYNAMIC
;
1237 hStmt
->m_driver
->m_fpDrvBind(hStmt
->m_statement
, pos
, sqlType
, cType
, wBuffer
, realAllocType
);
1239 #undef realAllocType
1243 * Bind string parameter
1245 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const TCHAR
*value
, int allocType
)
1248 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, allocType
);
1250 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)_T(""), DB_BIND_STATIC
);
1254 * Bind string parameter with length validation
1256 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const TCHAR
*value
, int allocType
, int maxLen
)
1260 if ((int)_tcslen(value
) <= maxLen
)
1262 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, allocType
);
1266 if (allocType
== DB_BIND_DYNAMIC
)
1268 ((TCHAR
*)value
)[maxLen
] = 0;
1269 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, DB_BIND_DYNAMIC
);
1273 TCHAR
*temp
= (TCHAR
*)nx_memdup(value
, sizeof(TCHAR
) * (maxLen
+ 1));
1275 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, temp
, DB_BIND_DYNAMIC
);
1281 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)_T(""), DB_BIND_STATIC
);
1286 * Bind 32 bit integer parameter
1288 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, INT32 value
)
1290 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT32
, &value
, DB_BIND_TRANSIENT
);
1294 * Bind 32 bit unsigned integer parameter
1296 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, UINT32 value
)
1298 // C type intentionally set to INT32 - unsigned numbers will be written as negatives
1299 // and correctly parsed on read by DBGetFieldULong
1300 // Setting it to UINT32 may cause INSERT/UPDATE failures on some databases
1301 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT32
, &value
, DB_BIND_TRANSIENT
);
1305 * Bind 64 bit integer parameter
1307 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, INT64 value
)
1309 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT64
, &value
, DB_BIND_TRANSIENT
);
1313 * Bind 64 bit unsigned integer parameter
1315 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, UINT64 value
)
1317 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_UINT64
, &value
, DB_BIND_TRANSIENT
);
1321 * Bind floating point parameter
1323 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, double value
)
1325 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_DOUBLE
, &value
, DB_BIND_TRANSIENT
);
1329 * Bind UUID parameter
1331 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const uuid
& value
)
1334 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, value
.toString(buffer
), DB_BIND_TRANSIENT
);
1338 * Execute prepared statement (non-SELECT)
1340 bool LIBNXDB_EXPORTABLE
DBExecuteEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1342 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1344 _tcscpy(errorText
, _T("Invalid statement handle"));
1349 #define wcErrorText errorText
1351 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1354 DB_HANDLE hConn
= hStmt
->m_connection
;
1355 MutexLock(hConn
->m_mutexTransLock
);
1356 UINT64 ms
= GetCurrentTimeMs();
1358 s_perfNonSelectQueries
++;
1359 s_perfTotalQueries
++;
1361 DWORD dwResult
= hConn
->m_driver
->m_fpDrvExecute(hConn
->m_connection
, hStmt
->m_statement
, wcErrorText
);
1362 ms
= GetCurrentTimeMs() - ms
;
1363 if (hConn
->m_driver
->m_dumpSql
)
1365 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), (dwResult
== DBERR_SUCCESS
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1367 if ((dwResult
== DBERR_SUCCESS
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1369 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1370 s_perfLongRunningQueries
++;
1373 // Do reconnect if needed, but don't retry statement execution
1374 // because it will fail anyway
1375 if ((dwResult
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1380 MutexUnlock(hConn
->m_mutexTransLock
);
1383 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1384 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1387 if (dwResult
!= DBERR_SUCCESS
)
1389 if (hConn
->m_driver
->m_logSqlErrors
)
1390 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1391 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1394 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwResult
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1396 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1397 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwResult
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1401 s_perfFailedQueries
++;
1404 return dwResult
== DBERR_SUCCESS
;
1409 * Execute prepared statement (non-SELECT)
1411 bool LIBNXDB_EXPORTABLE
DBExecute(DB_STATEMENT hStmt
)
1413 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1414 return DBExecuteEx(hStmt
, errorText
);
1418 * Execute prepared SELECT statement
1420 DB_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1422 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1424 _tcscpy(errorText
, _T("Invalid statement handle"));
1428 DB_RESULT result
= NULL
;
1430 #define wcErrorText errorText
1432 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1435 DB_HANDLE hConn
= hStmt
->m_connection
;
1436 MutexLock(hConn
->m_mutexTransLock
);
1438 s_perfSelectQueries
++;
1439 s_perfTotalQueries
++;
1441 INT64 ms
= GetCurrentTimeMs();
1442 DWORD dwError
= DBERR_OTHER_ERROR
;
1443 DBDRV_RESULT hResult
= hConn
->m_driver
->m_fpDrvSelectPrepared(hConn
->m_connection
, hStmt
->m_statement
, &dwError
, wcErrorText
);
1445 ms
= GetCurrentTimeMs() - ms
;
1446 if (hConn
->m_driver
->m_dumpSql
)
1448 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
1449 (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1451 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1453 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1454 s_perfLongRunningQueries
++;
1457 // Do reconnect if needed, but don't retry statement execution
1458 // because it will fail anyway
1459 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1464 MutexUnlock(hConn
->m_mutexTransLock
);
1467 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1468 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1471 if (hResult
== NULL
)
1473 if (hConn
->m_driver
->m_logSqlErrors
)
1474 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1475 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1478 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1480 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1481 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1485 s_perfFailedQueries
++;
1488 if (hResult
!= NULL
)
1490 result
= (DB_RESULT
)malloc(sizeof(db_result_t
));
1491 result
->m_driver
= hConn
->m_driver
;
1492 result
->m_connection
= hConn
;
1493 result
->m_data
= hResult
;
1501 * Execute prepared SELECT statement
1503 DB_RESULT LIBNXDB_EXPORTABLE
DBSelectPrepared(DB_STATEMENT hStmt
)
1505 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1506 return DBSelectPreparedEx(hStmt
, errorText
);
1510 * Execute prepared SELECT statement without caching results
1512 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedUnbufferedEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1514 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1516 _tcscpy(errorText
, _T("Invalid statement handle"));
1520 DB_UNBUFFERED_RESULT result
= NULL
;
1522 #define wcErrorText errorText
1524 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1527 DB_HANDLE hConn
= hStmt
->m_connection
;
1528 MutexLock(hConn
->m_mutexTransLock
);
1530 s_perfSelectQueries
++;
1531 s_perfTotalQueries
++;
1533 INT64 ms
= GetCurrentTimeMs();
1534 DWORD dwError
= DBERR_OTHER_ERROR
;
1535 DBDRV_UNBUFFERED_RESULT hResult
= hConn
->m_driver
->m_fpDrvSelectPreparedUnbuffered(hConn
->m_connection
, hStmt
->m_statement
, &dwError
, wcErrorText
);
1537 ms
= GetCurrentTimeMs() - ms
;
1538 if (hConn
->m_driver
->m_dumpSql
)
1540 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
1541 (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1543 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1545 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1546 s_perfLongRunningQueries
++;
1549 // Do reconnect if needed, but don't retry statement execution
1550 // because it will fail anyway
1551 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1557 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1558 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1561 if (hResult
== NULL
)
1563 MutexUnlock(hConn
->m_mutexTransLock
);
1565 if (hConn
->m_driver
->m_logSqlErrors
)
1566 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1567 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1570 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1572 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1573 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1577 s_perfFailedQueries
++;
1580 if (hResult
!= NULL
)
1582 result
= (DB_UNBUFFERED_RESULT
)malloc(sizeof(db_unbuffered_result_t
));
1583 result
->m_driver
= hConn
->m_driver
;
1584 result
->m_connection
= hConn
;
1585 result
->m_data
= hResult
;
1593 * Execute prepared SELECT statement
1595 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedUnbuffered(DB_STATEMENT hStmt
)
1597 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1598 return DBSelectPreparedUnbufferedEx(hStmt
, errorText
);
1604 bool LIBNXDB_EXPORTABLE
DBBegin(DB_HANDLE hConn
)
1609 MutexLock(hConn
->m_mutexTransLock
);
1610 if (hConn
->m_transactionLevel
== 0)
1612 dwResult
= hConn
->m_driver
->m_fpDrvBegin(hConn
->m_connection
);
1613 if ((dwResult
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1616 dwResult
= hConn
->m_driver
->m_fpDrvBegin(hConn
->m_connection
);
1618 if (dwResult
== DBERR_SUCCESS
)
1620 hConn
->m_transactionLevel
++;
1622 nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn
->m_transactionLevel
);
1626 MutexUnlock(hConn
->m_mutexTransLock
);
1627 nxlog_debug(9, _T("BEGIN TRANSACTION failed"), hConn
->m_transactionLevel
);
1632 hConn
->m_transactionLevel
++;
1634 nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn
->m_transactionLevel
);
1640 * Commit transaction
1642 bool LIBNXDB_EXPORTABLE
DBCommit(DB_HANDLE hConn
)
1646 MutexLock(hConn
->m_mutexTransLock
);
1647 if (hConn
->m_transactionLevel
> 0)
1649 hConn
->m_transactionLevel
--;
1650 if (hConn
->m_transactionLevel
== 0)
1651 bRet
= (hConn
->m_driver
->m_fpDrvCommit(hConn
->m_connection
) == DBERR_SUCCESS
);
1654 nxlog_debug(9, _T("COMMIT TRANSACTION %s (level %d)"), bRet
? _T("successful") : _T("failed"), hConn
->m_transactionLevel
);
1655 MutexUnlock(hConn
->m_mutexTransLock
);
1657 MutexUnlock(hConn
->m_mutexTransLock
);
1662 * Rollback transaction
1664 bool LIBNXDB_EXPORTABLE
DBRollback(DB_HANDLE hConn
)
1668 MutexLock(hConn
->m_mutexTransLock
);
1669 if (hConn
->m_transactionLevel
> 0)
1671 hConn
->m_transactionLevel
--;
1672 if (hConn
->m_transactionLevel
== 0)
1673 bRet
= (hConn
->m_driver
->m_fpDrvRollback(hConn
->m_connection
) == DBERR_SUCCESS
);
1676 nxlog_debug(9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet
? _T("successful") : _T("failed"), hConn
->m_transactionLevel
);
1677 MutexUnlock(hConn
->m_mutexTransLock
);
1679 MutexUnlock(hConn
->m_mutexTransLock
);
1684 * Prepare string for using in SQL statement
1686 String LIBNXDB_EXPORTABLE
DBPrepareString(DB_HANDLE conn
, const TCHAR
*str
, int maxSize
)
1688 return DBPrepareString(conn
->m_driver
, str
, maxSize
);
1692 * Prepare string for using in SQL statement
1694 String LIBNXDB_EXPORTABLE
DBPrepareString(DB_DRIVER drv
, const TCHAR
*str
, int maxSize
)
1697 if ((maxSize
> 0) && (str
!= NULL
) && (maxSize
< (int)_tcslen(str
)))
1699 TCHAR
*temp
= (TCHAR
*)malloc((maxSize
+ 1) * sizeof(TCHAR
));
1700 nx_strncpy(temp
, str
, maxSize
+ 1);
1702 out
.setBuffer(drv
->m_fpDrvPrepareStringW(temp
));
1704 out
.setBuffer(drv
->m_fpDrvPrepareStringA(temp
));
1711 out
.setBuffer(drv
->m_fpDrvPrepareStringW(CHECK_NULL_EX(str
)));
1713 out
.setBuffer(drv
->m_fpDrvPrepareStringA(CHECK_NULL_EX(str
)));
1720 * Prepare string for using in SQL statement (multi-byte string version)
1724 String LIBNXDB_EXPORTABLE
DBPrepareStringA(DB_HANDLE conn
, const char *str
, int maxSize
)
1726 WCHAR
*wcs
= WideStringFromMBString(str
);
1727 String s
= DBPrepareString(conn
, wcs
, maxSize
);
1732 String LIBNXDB_EXPORTABLE
DBPrepareStringA(DB_DRIVER drv
, const char *str
, int maxSize
)
1734 WCHAR
*wcs
= WideStringFromMBString(str
);
1735 String s
= DBPrepareString(drv
, wcs
, maxSize
);
1743 * Check if given table exist
1745 int LIBNXDB_EXPORTABLE
DBIsTableExist(DB_HANDLE conn
, const TCHAR
*table
)
1748 return conn
->m_driver
->m_fpDrvIsTableExist(conn
->m_connection
, table
);
1751 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, table
, -1, wname
, 256);
1752 return conn
->m_driver
->m_fpDrvIsTableExist(conn
->m_connection
, wname
);
1757 * Get performance counters
1759 void LIBNXDB_EXPORTABLE
DBGetPerfCounters(LIBNXDB_PERF_COUNTERS
*counters
)
1761 counters
->failedQueries
= s_perfFailedQueries
;
1762 counters
->longRunningQueries
= s_perfLongRunningQueries
;
1763 counters
->nonSelectQueries
= s_perfNonSelectQueries
;
1764 counters
->selectQueries
= s_perfSelectQueries
;
1765 counters
->totalQueries
= s_perfTotalQueries
;