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 from unbuffered SELECT result as UTF-8 string
944 char LIBNXDB_EXPORTABLE
*DBGetFieldUTF8(DB_UNBUFFERED_RESULT hResult
, int iColumn
, char *buffer
, int iBufSize
)
946 if (hResult
->m_driver
->m_fpDrvGetFieldUTF8
!= NULL
)
951 return hResult
->m_driver
->m_fpDrvGetFieldUnbufferedUTF8(hResult
->m_data
, iColumn
, buffer
, iBufSize
);
956 LONG nLen
= hResult
->m_driver
->m_fpDrvGetFieldLengthUnbuffered(hResult
->m_data
, iColumn
);
963 nLen
= nLen
* 2 + 1; // increase buffer size because driver may return field length in characters
964 pszTemp
= (char *)malloc(nLen
);
965 hResult
->m_driver
->m_fpDrvGetFieldUnbufferedUTF8(hResult
->m_data
, iColumn
, pszTemp
, nLen
);
972 LONG nLen
= hResult
->m_driver
->m_fpDrvGetFieldLengthUnbuffered(hResult
->m_data
, iColumn
);
975 nLen
= nLen
* 2 + 1; // increase buffer size because driver may return field length in characters
977 WCHAR
*wtemp
= (WCHAR
*)malloc(nLen
* sizeof(WCHAR
));
978 hResult
->m_driver
->m_fpDrvGetFieldUnbuffered(hResult
->m_data
, iColumn
, wtemp
, nLen
);
979 char *value
= (buffer
!= NULL
) ? buffer
: (char *)malloc(nLen
);
980 WideCharToMultiByte(CP_UTF8
, 0, wtemp
, -1, value
, (buffer
!= NULL
) ? iBufSize
: nLen
, NULL
, NULL
);
987 * Get field's value as unsigned long from unbuffered SELECT result
989 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldULong(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
995 if (DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
)
998 if (szBuffer
[0] == _T('-'))
1000 iVal
= _tcstol(szBuffer
, NULL
, 10);
1001 memcpy(&dwVal
, &iVal
, sizeof(INT32
)); // To prevent possible conversion
1005 dwVal
= _tcstoul(szBuffer
, NULL
, 10);
1011 * Get field's value as unsigned 64-bit int from unbuffered SELECT result
1013 UINT64 LIBNXDB_EXPORTABLE
DBGetFieldUInt64(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1019 if (DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
)
1022 if (szBuffer
[0] == _T('-'))
1024 iVal
= _tcstoll(szBuffer
, NULL
, 10);
1025 memcpy(&qwVal
, &iVal
, sizeof(INT64
)); // To prevent possible conversion
1029 qwVal
= _tcstoull(szBuffer
, NULL
, 10);
1035 * Get field's value as signed long from unbuffered SELECT result
1037 INT32 LIBNXDB_EXPORTABLE
DBGetFieldLong(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1040 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstol(szBuffer
, NULL
, 10);
1044 * Get field's value as signed 64-bit int from unbuffered SELECT result
1046 INT64 LIBNXDB_EXPORTABLE
DBGetFieldInt64(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1049 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstoll(szBuffer
, NULL
, 10);
1053 * Get field's value as signed long from unbuffered SELECT result
1055 double LIBNXDB_EXPORTABLE
DBGetFieldDouble(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1058 return DBGetField(hResult
, iColumn
, szBuffer
, 64) == NULL
? 0 : _tcstod(szBuffer
, NULL
);
1062 * Get field's value as IPv4 address from unbuffered SELECT result
1064 UINT32 LIBNXDB_EXPORTABLE
DBGetFieldIPAddr(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1067 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? INADDR_NONE
: ntohl(_t_inet_addr(buffer
));
1071 * Get field's value as IP address from unbuffered SELECT result
1073 InetAddress LIBNXDB_EXPORTABLE
DBGetFieldInetAddr(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1076 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? InetAddress() : InetAddress::parse(buffer
);
1080 * Get field's value as GUID from unbuffered SELECT result
1082 uuid LIBNXDB_EXPORTABLE
DBGetFieldGUID(DB_UNBUFFERED_RESULT hResult
, int iColumn
)
1085 return (DBGetField(hResult
, iColumn
, buffer
, 64) == NULL
) ? uuid::NULL_UUID
: uuid::parse(buffer
);
1089 * Free unbuffered SELECT result
1091 void LIBNXDB_EXPORTABLE
DBFreeResult(DB_UNBUFFERED_RESULT hResult
)
1093 hResult
->m_driver
->m_fpDrvFreeUnbufferedResult(hResult
->m_data
);
1094 MutexUnlock(hResult
->m_connection
->m_mutexTransLock
);
1101 DB_STATEMENT LIBNXDB_EXPORTABLE
DBPrepareEx(DB_HANDLE hConn
, const TCHAR
*query
, TCHAR
*errorText
)
1103 DB_STATEMENT result
= NULL
;
1107 #define pwszQuery query
1108 #define wcErrorText errorText
1110 WCHAR
*pwszQuery
= WideStringFromMBString(query
);
1111 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1114 MutexLock(hConn
->m_mutexTransLock
);
1116 if (hConn
->m_driver
->m_dumpSql
)
1117 ms
= GetCurrentTimeMs();
1120 DBDRV_STATEMENT stmt
= hConn
->m_driver
->m_fpDrvPrepare(hConn
->m_connection
, pwszQuery
, &errorCode
, wcErrorText
);
1121 if ((stmt
== NULL
) && (errorCode
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1124 stmt
= hConn
->m_driver
->m_fpDrvPrepare(hConn
->m_connection
, pwszQuery
, &errorCode
, wcErrorText
);
1126 MutexUnlock(hConn
->m_mutexTransLock
);
1130 result
= (DB_STATEMENT
)malloc(sizeof(db_statement_t
));
1131 result
->m_driver
= hConn
->m_driver
;
1132 result
->m_connection
= hConn
;
1133 result
->m_statement
= stmt
;
1134 result
->m_query
= _tcsdup(query
);
1139 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1140 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1143 if (hConn
->m_driver
->m_logSqlErrors
)
1144 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", query
, errorText
);
1145 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1146 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, pwszQuery
, wcErrorText
, errorCode
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1148 s_perfFailedQueries
++;
1149 s_perfTotalQueries
++;
1152 if (hConn
->m_driver
->m_dumpSql
)
1154 ms
= GetCurrentTimeMs() - ms
;
1155 nxlog_debug(9, _T("{%p} %s prepare: \"%s\" [%d ms]"), result
, (result
!= NULL
) ? _T("Successful") : _T("Failed"), query
, ms
);
1164 hConn
->m_preparedStatements
->add(result
);
1175 DB_STATEMENT LIBNXDB_EXPORTABLE
DBPrepare(DB_HANDLE hConn
, const TCHAR
*query
)
1177 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1178 return DBPrepareEx(hConn
, query
, errorText
);
1182 * Destroy prepared statement
1184 void LIBNXDB_EXPORTABLE
DBFreeStatement(DB_STATEMENT hStmt
)
1189 if (hStmt
->m_connection
!= NULL
)
1191 hStmt
->m_connection
->m_preparedStatements
->remove(hStmt
);
1193 hStmt
->m_driver
->m_fpDrvFreeStatement(hStmt
->m_statement
);
1194 free(hStmt
->m_query
);
1199 * Get source query for prepared statement
1201 const TCHAR LIBNXDB_EXPORTABLE
*DBGetStatementSource(DB_STATEMENT hStmt
)
1203 return hStmt
->m_query
;
1209 bool LIBNXDB_EXPORTABLE
DBOpenBatch(DB_STATEMENT hStmt
)
1211 if (!IS_VALID_STATEMENT_HANDLE(hStmt
) || (hStmt
->m_driver
->m_fpDrvOpenBatch
== NULL
))
1213 return hStmt
->m_driver
->m_fpDrvOpenBatch(hStmt
->m_statement
);
1217 * Start next batch row batch
1219 void LIBNXDB_EXPORTABLE
DBNextBatchRow(DB_STATEMENT hStmt
)
1221 if (IS_VALID_STATEMENT_HANDLE(hStmt
) && (hStmt
->m_driver
->m_fpDrvNextBatchRow
!= NULL
))
1222 hStmt
->m_driver
->m_fpDrvNextBatchRow(hStmt
->m_statement
);
1226 * Bind parameter (generic)
1228 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, int cType
, void *buffer
, int allocType
)
1230 if ((pos
<= 0) || !IS_VALID_STATEMENT_HANDLE(hStmt
))
1233 if (hStmt
->m_connection
->m_driver
->m_dumpSql
)
1235 if (cType
== DB_CTYPE_STRING
)
1237 nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt
, pos
, buffer
);
1239 else if (cType
== DB_CTYPE_UTF8_STRING
)
1241 nxlog_debug(9, _T("{%p} bind at pos %d (UTF-8): \"%hs\""), hStmt
, pos
, buffer
);
1248 case DB_CTYPE_INT32
:
1249 _sntprintf(text
, 64, _T("%d"), *((INT32
*)buffer
));
1251 case DB_CTYPE_UINT32
:
1252 _sntprintf(text
, 64, _T("%u"), *((UINT32
*)buffer
));
1254 case DB_CTYPE_INT64
:
1255 _sntprintf(text
, 64, INT64_FMT
, *((INT64
*)buffer
));
1257 case DB_CTYPE_UINT64
:
1258 _sntprintf(text
, 64, UINT64_FMT
, *((UINT64
*)buffer
));
1260 case DB_CTYPE_DOUBLE
:
1261 _sntprintf(text
, 64, _T("%f"), *((double *)buffer
));
1264 nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt
, pos
, text
);
1269 #define wBuffer buffer
1270 #define realAllocType allocType
1273 int realAllocType
= allocType
;
1274 if (cType
== DB_CTYPE_STRING
)
1276 wBuffer
= (void *)WideStringFromMBString((char *)buffer
);
1277 if (allocType
== DB_BIND_DYNAMIC
)
1279 realAllocType
= DB_BIND_DYNAMIC
;
1286 hStmt
->m_driver
->m_fpDrvBind(hStmt
->m_statement
, pos
, sqlType
, cType
, wBuffer
, realAllocType
);
1288 #undef realAllocType
1292 * Bind string parameter
1294 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const TCHAR
*value
, int allocType
)
1297 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, allocType
);
1299 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)_T(""), DB_BIND_STATIC
);
1303 * Bind string parameter with length validation
1305 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const TCHAR
*value
, int allocType
, int maxLen
)
1309 if ((int)_tcslen(value
) <= maxLen
)
1311 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, allocType
);
1315 if (allocType
== DB_BIND_DYNAMIC
)
1317 ((TCHAR
*)value
)[maxLen
] = 0;
1318 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)value
, DB_BIND_DYNAMIC
);
1322 TCHAR
*temp
= (TCHAR
*)nx_memdup(value
, sizeof(TCHAR
) * (maxLen
+ 1));
1324 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, temp
, DB_BIND_DYNAMIC
);
1330 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, (void *)_T(""), DB_BIND_STATIC
);
1335 * Bind 32 bit integer parameter
1337 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, INT32 value
)
1339 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT32
, &value
, DB_BIND_TRANSIENT
);
1343 * Bind 32 bit unsigned integer parameter
1345 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, UINT32 value
)
1347 // C type intentionally set to INT32 - unsigned numbers will be written as negatives
1348 // and correctly parsed on read by DBGetFieldULong
1349 // Setting it to UINT32 may cause INSERT/UPDATE failures on some databases
1350 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT32
, &value
, DB_BIND_TRANSIENT
);
1354 * Bind 64 bit integer parameter
1356 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, INT64 value
)
1358 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_INT64
, &value
, DB_BIND_TRANSIENT
);
1362 * Bind 64 bit unsigned integer parameter
1364 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, UINT64 value
)
1366 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_UINT64
, &value
, DB_BIND_TRANSIENT
);
1370 * Bind floating point parameter
1372 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, double value
)
1374 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_DOUBLE
, &value
, DB_BIND_TRANSIENT
);
1378 * Bind UUID parameter
1380 void LIBNXDB_EXPORTABLE
DBBind(DB_STATEMENT hStmt
, int pos
, int sqlType
, const uuid
& value
)
1383 DBBind(hStmt
, pos
, sqlType
, DB_CTYPE_STRING
, value
.toString(buffer
), DB_BIND_TRANSIENT
);
1387 * Execute prepared statement (non-SELECT)
1389 bool LIBNXDB_EXPORTABLE
DBExecuteEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1391 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1393 _tcscpy(errorText
, _T("Invalid statement handle"));
1398 #define wcErrorText errorText
1400 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1403 DB_HANDLE hConn
= hStmt
->m_connection
;
1404 MutexLock(hConn
->m_mutexTransLock
);
1405 UINT64 ms
= GetCurrentTimeMs();
1407 s_perfNonSelectQueries
++;
1408 s_perfTotalQueries
++;
1410 DWORD dwResult
= hConn
->m_driver
->m_fpDrvExecute(hConn
->m_connection
, hStmt
->m_statement
, wcErrorText
);
1411 ms
= GetCurrentTimeMs() - ms
;
1412 if (hConn
->m_driver
->m_dumpSql
)
1414 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), (dwResult
== DBERR_SUCCESS
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1416 if ((dwResult
== DBERR_SUCCESS
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1418 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1419 s_perfLongRunningQueries
++;
1422 // Do reconnect if needed, but don't retry statement execution
1423 // because it will fail anyway
1424 if ((dwResult
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1429 MutexUnlock(hConn
->m_mutexTransLock
);
1432 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1433 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1436 if (dwResult
!= DBERR_SUCCESS
)
1438 if (hConn
->m_driver
->m_logSqlErrors
)
1439 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1440 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1443 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwResult
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1445 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1446 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwResult
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1450 s_perfFailedQueries
++;
1453 return dwResult
== DBERR_SUCCESS
;
1458 * Execute prepared statement (non-SELECT)
1460 bool LIBNXDB_EXPORTABLE
DBExecute(DB_STATEMENT hStmt
)
1462 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1463 return DBExecuteEx(hStmt
, errorText
);
1467 * Execute prepared SELECT statement
1469 DB_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1471 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1473 _tcscpy(errorText
, _T("Invalid statement handle"));
1477 DB_RESULT result
= NULL
;
1479 #define wcErrorText errorText
1481 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1484 DB_HANDLE hConn
= hStmt
->m_connection
;
1485 MutexLock(hConn
->m_mutexTransLock
);
1487 s_perfSelectQueries
++;
1488 s_perfTotalQueries
++;
1490 INT64 ms
= GetCurrentTimeMs();
1491 DWORD dwError
= DBERR_OTHER_ERROR
;
1492 DBDRV_RESULT hResult
= hConn
->m_driver
->m_fpDrvSelectPrepared(hConn
->m_connection
, hStmt
->m_statement
, &dwError
, wcErrorText
);
1494 ms
= GetCurrentTimeMs() - ms
;
1495 if (hConn
->m_driver
->m_dumpSql
)
1497 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
1498 (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1500 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1502 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1503 s_perfLongRunningQueries
++;
1506 // Do reconnect if needed, but don't retry statement execution
1507 // because it will fail anyway
1508 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1513 MutexUnlock(hConn
->m_mutexTransLock
);
1516 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1517 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1520 if (hResult
== NULL
)
1522 if (hConn
->m_driver
->m_logSqlErrors
)
1523 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1524 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1527 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1529 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1530 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1534 s_perfFailedQueries
++;
1537 if (hResult
!= NULL
)
1539 result
= (DB_RESULT
)malloc(sizeof(db_result_t
));
1540 result
->m_driver
= hConn
->m_driver
;
1541 result
->m_connection
= hConn
;
1542 result
->m_data
= hResult
;
1550 * Execute prepared SELECT statement
1552 DB_RESULT LIBNXDB_EXPORTABLE
DBSelectPrepared(DB_STATEMENT hStmt
)
1554 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1555 return DBSelectPreparedEx(hStmt
, errorText
);
1559 * Execute prepared SELECT statement without caching results
1561 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedUnbufferedEx(DB_STATEMENT hStmt
, TCHAR
*errorText
)
1563 if (!IS_VALID_STATEMENT_HANDLE(hStmt
))
1565 _tcscpy(errorText
, _T("Invalid statement handle"));
1569 DB_UNBUFFERED_RESULT result
= NULL
;
1571 #define wcErrorText errorText
1573 WCHAR wcErrorText
[DBDRV_MAX_ERROR_TEXT
] = L
"";
1576 DB_HANDLE hConn
= hStmt
->m_connection
;
1577 MutexLock(hConn
->m_mutexTransLock
);
1579 s_perfSelectQueries
++;
1580 s_perfTotalQueries
++;
1582 INT64 ms
= GetCurrentTimeMs();
1583 DWORD dwError
= DBERR_OTHER_ERROR
;
1584 DBDRV_UNBUFFERED_RESULT hResult
= hConn
->m_driver
->m_fpDrvSelectPreparedUnbuffered(hConn
->m_connection
, hStmt
->m_statement
, &dwError
, wcErrorText
);
1586 ms
= GetCurrentTimeMs() - ms
;
1587 if (hConn
->m_driver
->m_dumpSql
)
1589 nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"),
1590 (hResult
!= NULL
) ? _T("Successful") : _T("Failed"), hStmt
->m_query
, (int)ms
);
1592 if ((hResult
!= NULL
) && ((UINT32
)ms
> g_sqlQueryExecTimeThreshold
))
1594 nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt
->m_query
, (int)ms
);
1595 s_perfLongRunningQueries
++;
1598 // Do reconnect if needed, but don't retry statement execution
1599 // because it will fail anyway
1600 if ((hResult
== NULL
) && (dwError
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1606 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, wcErrorText
, -1, errorText
, DBDRV_MAX_ERROR_TEXT
, NULL
, NULL
);
1607 errorText
[DBDRV_MAX_ERROR_TEXT
- 1] = 0;
1610 if (hResult
== NULL
)
1612 MutexUnlock(hConn
->m_mutexTransLock
);
1614 if (hConn
->m_driver
->m_logSqlErrors
)
1615 nxlog_write(g_sqlErrorMsgCode
, EVENTLOG_ERROR_TYPE
, "ss", hStmt
->m_query
, errorText
);
1616 if (hConn
->m_driver
->m_fpEventHandler
!= NULL
)
1619 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, hStmt
->m_query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1621 WCHAR
*query
= WideStringFromMBString(hStmt
->m_query
);
1622 hConn
->m_driver
->m_fpEventHandler(DBEVENT_QUERY_FAILED
, query
, wcErrorText
, dwError
== DBERR_CONNECTION_LOST
, hConn
->m_driver
->m_userArg
);
1626 s_perfFailedQueries
++;
1629 if (hResult
!= NULL
)
1631 result
= (DB_UNBUFFERED_RESULT
)malloc(sizeof(db_unbuffered_result_t
));
1632 result
->m_driver
= hConn
->m_driver
;
1633 result
->m_connection
= hConn
;
1634 result
->m_data
= hResult
;
1642 * Execute prepared SELECT statement
1644 DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE
DBSelectPreparedUnbuffered(DB_STATEMENT hStmt
)
1646 TCHAR errorText
[DBDRV_MAX_ERROR_TEXT
];
1647 return DBSelectPreparedUnbufferedEx(hStmt
, errorText
);
1653 bool LIBNXDB_EXPORTABLE
DBBegin(DB_HANDLE hConn
)
1658 MutexLock(hConn
->m_mutexTransLock
);
1659 if (hConn
->m_transactionLevel
== 0)
1661 dwResult
= hConn
->m_driver
->m_fpDrvBegin(hConn
->m_connection
);
1662 if ((dwResult
== DBERR_CONNECTION_LOST
) && hConn
->m_reconnectEnabled
)
1665 dwResult
= hConn
->m_driver
->m_fpDrvBegin(hConn
->m_connection
);
1667 if (dwResult
== DBERR_SUCCESS
)
1669 hConn
->m_transactionLevel
++;
1671 nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn
->m_transactionLevel
);
1675 MutexUnlock(hConn
->m_mutexTransLock
);
1676 nxlog_debug(9, _T("BEGIN TRANSACTION failed"), hConn
->m_transactionLevel
);
1681 hConn
->m_transactionLevel
++;
1683 nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn
->m_transactionLevel
);
1689 * Commit transaction
1691 bool LIBNXDB_EXPORTABLE
DBCommit(DB_HANDLE hConn
)
1695 MutexLock(hConn
->m_mutexTransLock
);
1696 if (hConn
->m_transactionLevel
> 0)
1698 hConn
->m_transactionLevel
--;
1699 if (hConn
->m_transactionLevel
== 0)
1700 bRet
= (hConn
->m_driver
->m_fpDrvCommit(hConn
->m_connection
) == DBERR_SUCCESS
);
1703 nxlog_debug(9, _T("COMMIT TRANSACTION %s (level %d)"), bRet
? _T("successful") : _T("failed"), hConn
->m_transactionLevel
);
1704 MutexUnlock(hConn
->m_mutexTransLock
);
1706 MutexUnlock(hConn
->m_mutexTransLock
);
1711 * Rollback transaction
1713 bool LIBNXDB_EXPORTABLE
DBRollback(DB_HANDLE hConn
)
1717 MutexLock(hConn
->m_mutexTransLock
);
1718 if (hConn
->m_transactionLevel
> 0)
1720 hConn
->m_transactionLevel
--;
1721 if (hConn
->m_transactionLevel
== 0)
1722 bRet
= (hConn
->m_driver
->m_fpDrvRollback(hConn
->m_connection
) == DBERR_SUCCESS
);
1725 nxlog_debug(9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet
? _T("successful") : _T("failed"), hConn
->m_transactionLevel
);
1726 MutexUnlock(hConn
->m_mutexTransLock
);
1728 MutexUnlock(hConn
->m_mutexTransLock
);
1733 * Prepare string for using in SQL statement
1735 String LIBNXDB_EXPORTABLE
DBPrepareString(DB_HANDLE conn
, const TCHAR
*str
, int maxSize
)
1737 return DBPrepareString(conn
->m_driver
, str
, maxSize
);
1741 * Prepare string for using in SQL statement
1743 String LIBNXDB_EXPORTABLE
DBPrepareString(DB_DRIVER drv
, const TCHAR
*str
, int maxSize
)
1746 if ((maxSize
> 0) && (str
!= NULL
) && (maxSize
< (int)_tcslen(str
)))
1748 TCHAR
*temp
= (TCHAR
*)malloc((maxSize
+ 1) * sizeof(TCHAR
));
1749 nx_strncpy(temp
, str
, maxSize
+ 1);
1751 out
.setBuffer(drv
->m_fpDrvPrepareStringW(temp
));
1753 out
.setBuffer(drv
->m_fpDrvPrepareStringA(temp
));
1760 out
.setBuffer(drv
->m_fpDrvPrepareStringW(CHECK_NULL_EX(str
)));
1762 out
.setBuffer(drv
->m_fpDrvPrepareStringA(CHECK_NULL_EX(str
)));
1769 * Prepare string for using in SQL statement (multi-byte string version)
1773 String LIBNXDB_EXPORTABLE
DBPrepareStringA(DB_HANDLE conn
, const char *str
, int maxSize
)
1775 WCHAR
*wcs
= WideStringFromMBString(str
);
1776 String s
= DBPrepareString(conn
, wcs
, maxSize
);
1781 String LIBNXDB_EXPORTABLE
DBPrepareStringA(DB_DRIVER drv
, const char *str
, int maxSize
)
1783 WCHAR
*wcs
= WideStringFromMBString(str
);
1784 String s
= DBPrepareString(drv
, wcs
, maxSize
);
1792 * Check if given table exist
1794 int LIBNXDB_EXPORTABLE
DBIsTableExist(DB_HANDLE conn
, const TCHAR
*table
)
1797 return conn
->m_driver
->m_fpDrvIsTableExist(conn
->m_connection
, table
);
1800 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, table
, -1, wname
, 256);
1801 return conn
->m_driver
->m_fpDrvIsTableExist(conn
->m_connection
, wname
);
1806 * Get performance counters
1808 void LIBNXDB_EXPORTABLE
DBGetPerfCounters(LIBNXDB_PERF_COUNTERS
*counters
)
1810 counters
->failedQueries
= s_perfFailedQueries
;
1811 counters
->longRunningQueries
= s_perfLongRunningQueries
;
1812 counters
->nonSelectQueries
= s_perfNonSelectQueries
;
1813 counters
->selectQueries
= s_perfSelectQueries
;
1814 counters
->totalQueries
= s_perfTotalQueries
;