Commit | Line | Data |
---|---|---|
8a7cd6bb VK |
1 | /* |
2 | ** NetXMS - Network Management System | |
3 | ** Database Abstraction Library | |
2df047f4 | 4 | ** Copyright (C) 2003-2016 Victor Kirhenshtein |
8a7cd6bb VK |
5 | ** |
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. | |
10 | ** | |
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. | |
15 | ** | |
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. | |
19 | ** | |
20 | ** File: session.cpp | |
21 | ** | |
22 | **/ | |
23 | ||
24 | #include "libnxdb.h" | |
25 | ||
74d4ba34 VK |
26 | /** |
27 | * Check if statement handle is valid | |
28 | */ | |
29 | #define IS_VALID_STATEMENT_HANDLE(s) ((s != NULL) && (s->m_connection != NULL)) | |
30 | ||
a4809f58 VK |
31 | /** |
32 | * Performance counters | |
33 | */ | |
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; | |
39 | ||
3abf5b29 VK |
40 | /** |
41 | * Session init callback | |
42 | */ | |
43 | static void (*s_sessionInitCb)(DB_HANDLE session) = NULL; | |
44 | ||
74d4ba34 VK |
45 | /** |
46 | * Invalidate all prepared statements on connection | |
47 | */ | |
48 | static void InvalidatePreparedStatements(DB_HANDLE hConn) | |
49 | { | |
50 | for(int i = 0; i < hConn->m_preparedStatements->size(); i++) | |
51 | { | |
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; | |
56 | } | |
eb60ea85 | 57 | hConn->m_preparedStatements->clear(); |
74d4ba34 VK |
58 | } |
59 | ||
22aaa779 VK |
60 | /** |
61 | * Connect to database | |
62 | */ | |
8a7cd6bb VK |
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) | |
65 | { | |
66 | DBDRV_CONNECTION hDrvConn; | |
67 | DB_HANDLE hConn = NULL; | |
68 | ||
2df047f4 | 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)); |
8a7cd6bb VK |
70 | #ifdef UNICODE |
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); | |
76 | errorText[0] = 0; | |
77 | hDrvConn = driver->m_fpDrvConnect(mbServer, mbLogin, mbPassword, mbDatabase, mbSchema, errorText); | |
78 | #else | |
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; | |
83 | #endif | |
84 | if (hDrvConn != NULL) | |
85 | { | |
86 | hConn = (DB_HANDLE)malloc(sizeof(struct db_handle_t)); | |
87 | if (hConn != NULL) | |
88 | { | |
89 | hConn->m_driver = driver; | |
90 | hConn->m_dumpSql = driver->m_dumpSql; | |
533ce8c0 | 91 | hConn->m_reconnectEnabled = true; |
8a7cd6bb VK |
92 | hConn->m_connection = hDrvConn; |
93 | hConn->m_mutexTransLock = MutexCreateRecursive(); | |
94 | hConn->m_transactionLevel = 0; | |
74d4ba34 | 95 | hConn->m_preparedStatements = new ObjectArray<db_statement_t>(4, 4, false); |
8a7cd6bb VK |
96 | #ifdef UNICODE |
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; | |
102 | #else | |
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); | |
108 | #endif | |
85dfb586 VK |
109 | if (driver->m_fpDrvSetPrefetchLimit != NULL) |
110 | driver->m_fpDrvSetPrefetchLimit(hDrvConn, driver->m_defaultPrefetchLimit); | |
2df047f4 | 111 | nxlog_debug(4, _T("New DB connection opened: handle=%p"), hConn); |
3abf5b29 VK |
112 | if (s_sessionInitCb != NULL) |
113 | s_sessionInitCb(hConn); | |
8a7cd6bb VK |
114 | } |
115 | else | |
116 | { | |
117 | driver->m_fpDrvDisconnect(hDrvConn); | |
118 | } | |
119 | } | |
120 | #ifdef UNICODE | |
121 | if (hConn == NULL) | |
122 | { | |
123 | safe_free(mbServer); | |
124 | safe_free(mbDatabase); | |
125 | safe_free(mbLogin); | |
126 | safe_free(mbPassword); | |
0df58041 | 127 | safe_free(mbSchema); |
8a7cd6bb VK |
128 | } |
129 | #endif | |
130 | return hConn; | |
131 | } | |
132 | ||
22aaa779 VK |
133 | /** |
134 | * Disconnect from database | |
135 | */ | |
8a7cd6bb VK |
136 | void LIBNXDB_EXPORTABLE DBDisconnect(DB_HANDLE hConn) |
137 | { | |
138 | if (hConn == NULL) | |
139 | return; | |
140 | ||
2df047f4 | 141 | nxlog_debug(4, _T("DB connection %p closed"), hConn); |
8a7cd6bb | 142 | |
74d4ba34 VK |
143 | InvalidatePreparedStatements(hConn); |
144 | ||
8a7cd6bb VK |
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); | |
74d4ba34 | 152 | delete hConn->m_preparedStatements; |
8a7cd6bb VK |
153 | free(hConn); |
154 | } | |
155 | ||
22aaa779 VK |
156 | /** |
157 | * Enable/disable reconnect | |
158 | */ | |
533ce8c0 VK |
159 | void LIBNXDB_EXPORTABLE DBEnableReconnect(DB_HANDLE hConn, bool enabled) |
160 | { | |
161 | if (hConn != NULL) | |
162 | { | |
163 | hConn->m_reconnectEnabled = enabled; | |
164 | } | |
165 | } | |
166 | ||
22aaa779 VK |
167 | /** |
168 | * Reconnect to database | |
169 | */ | |
8a7cd6bb VK |
170 | static void DBReconnect(DB_HANDLE hConn) |
171 | { | |
172 | int nCount; | |
173 | WCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
174 | ||
2df047f4 | 175 | nxlog_debug(4, _T("DB reconnect: handle=%p"), hConn); |
22aaa779 | 176 | |
74d4ba34 | 177 | InvalidatePreparedStatements(hConn); |
8a7cd6bb VK |
178 | hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection); |
179 | for(nCount = 0; ; nCount++) | |
180 | { | |
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) | |
85dfb586 VK |
184 | { |
185 | if (hConn->m_driver->m_fpDrvSetPrefetchLimit != NULL) | |
186 | hConn->m_driver->m_fpDrvSetPrefetchLimit(hConn->m_connection, hConn->m_driver->m_defaultPrefetchLimit); | |
3abf5b29 VK |
187 | if (s_sessionInitCb != NULL) |
188 | s_sessionInitCb(hConn); | |
8a7cd6bb | 189 | break; |
85dfb586 | 190 | } |
8a7cd6bb VK |
191 | if (nCount == 0) |
192 | { | |
c17f6cbc | 193 | MutexLock(hConn->m_driver->m_mutexReconnect); |
8a7cd6bb | 194 | if ((hConn->m_driver->m_reconnect == 0) && (hConn->m_driver->m_fpEventHandler != NULL)) |
526ae8b8 | 195 | hConn->m_driver->m_fpEventHandler(DBEVENT_CONNECTION_LOST, NULL, NULL, true, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
196 | hConn->m_driver->m_reconnect++; |
197 | MutexUnlock(hConn->m_driver->m_mutexReconnect); | |
198 | } | |
199 | ThreadSleepMs(1000); | |
200 | } | |
201 | if (nCount > 0) | |
202 | { | |
c17f6cbc | 203 | MutexLock(hConn->m_driver->m_mutexReconnect); |
8a7cd6bb VK |
204 | hConn->m_driver->m_reconnect--; |
205 | if ((hConn->m_driver->m_reconnect == 0) && (hConn->m_driver->m_fpEventHandler != NULL)) | |
526ae8b8 | 206 | hConn->m_driver->m_fpEventHandler(DBEVENT_CONNECTION_RESTORED, NULL, NULL, false, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
207 | MutexUnlock(hConn->m_driver->m_mutexReconnect); |
208 | } | |
209 | } | |
210 | ||
85dfb586 VK |
211 | /** |
212 | * Set default prefetch limit | |
213 | */ | |
214 | void LIBNXDB_EXPORTABLE DBSetDefaultPrefetchLimit(DB_DRIVER driver, int limit) | |
215 | { | |
216 | driver->m_defaultPrefetchLimit = limit; | |
217 | } | |
218 | ||
219 | /** | |
220 | * Set prefetch limit | |
221 | */ | |
222 | bool LIBNXDB_EXPORTABLE DBSetPrefetchLimit(DB_HANDLE hConn, int limit) | |
223 | { | |
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); | |
227 | } | |
228 | ||
3abf5b29 VK |
229 | /** |
230 | * Set session initialization callback | |
231 | */ | |
232 | void LIBNXDB_EXPORTABLE DBSetSessionInitCallback(void (*cb)(DB_HANDLE)) | |
233 | { | |
234 | s_sessionInitCb = cb; | |
235 | } | |
236 | ||
22aaa779 VK |
237 | /** |
238 | * Perform a non-SELECT SQL query | |
239 | */ | |
750d59f2 | 240 | bool LIBNXDB_EXPORTABLE DBQueryEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText) |
8a7cd6bb VK |
241 | { |
242 | DWORD dwResult; | |
8a7cd6bb VK |
243 | #ifdef UNICODE |
244 | #define pwszQuery szQuery | |
245 | #define wcErrorText errorText | |
246 | #else | |
247 | WCHAR *pwszQuery = WideStringFromMBString(szQuery); | |
248 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
249 | #endif | |
250 | ||
c17f6cbc | 251 | MutexLock(hConn->m_mutexTransLock); |
58f1f627 | 252 | INT64 ms = GetCurrentTimeMs(); |
8a7cd6bb VK |
253 | |
254 | dwResult = hConn->m_driver->m_fpDrvQuery(hConn->m_connection, pwszQuery, wcErrorText); | |
533ce8c0 | 255 | if ((dwResult == DBERR_CONNECTION_LOST) && hConn->m_reconnectEnabled) |
8a7cd6bb VK |
256 | { |
257 | DBReconnect(hConn); | |
258 | dwResult = hConn->m_driver->m_fpDrvQuery(hConn->m_connection, pwszQuery, wcErrorText); | |
259 | } | |
260 | ||
a4809f58 VK |
261 | s_perfNonSelectQueries++; |
262 | s_perfTotalQueries++; | |
263 | ||
58f1f627 | 264 | ms = GetCurrentTimeMs() - ms; |
8a7cd6bb VK |
265 | if (hConn->m_driver->m_dumpSql) |
266 | { | |
2df047f4 | 267 | nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), szQuery, ms); |
8a7cd6bb | 268 | } |
58f1f627 VK |
269 | if ((dwResult == DBERR_SUCCESS) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) |
270 | { | |
2df047f4 | 271 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms); |
a4809f58 | 272 | s_perfLongRunningQueries++; |
58f1f627 | 273 | } |
8a7cd6bb VK |
274 | |
275 | MutexUnlock(hConn->m_mutexTransLock); | |
276 | ||
277 | #ifndef UNICODE | |
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; | |
280 | #endif | |
281 | ||
282 | if (dwResult != DBERR_SUCCESS) | |
283 | { | |
a4809f58 | 284 | s_perfFailedQueries++; |
8a7cd6bb VK |
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) | |
526ae8b8 | 288 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, pwszQuery, wcErrorText, dwResult == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
289 | } |
290 | ||
291 | #ifndef UNICODE | |
292 | free(pwszQuery); | |
293 | #endif | |
294 | ||
295 | return dwResult == DBERR_SUCCESS; | |
296 | #undef pwszQuery | |
297 | #undef wcErrorText | |
298 | } | |
299 | ||
750d59f2 | 300 | bool LIBNXDB_EXPORTABLE DBQuery(DB_HANDLE hConn, const TCHAR *query) |
8a7cd6bb VK |
301 | { |
302 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
8a7cd6bb VK |
303 | return DBQueryEx(hConn, query, errorText); |
304 | } | |
305 | ||
22aaa779 VK |
306 | /** |
307 | * Perform SELECT query | |
308 | */ | |
8a7cd6bb VK |
309 | DB_RESULT LIBNXDB_EXPORTABLE DBSelectEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText) |
310 | { | |
311 | DBDRV_RESULT hResult; | |
312 | DB_RESULT result = NULL; | |
6e3f4556 | 313 | DWORD dwError = DBERR_OTHER_ERROR; |
8a7cd6bb VK |
314 | #ifdef UNICODE |
315 | #define pwszQuery szQuery | |
316 | #define wcErrorText errorText | |
317 | #else | |
318 | WCHAR *pwszQuery = WideStringFromMBString(szQuery); | |
319 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
320 | #endif | |
321 | ||
c17f6cbc | 322 | MutexLock(hConn->m_mutexTransLock); |
58f1f627 | 323 | INT64 ms = GetCurrentTimeMs(); |
a4809f58 VK |
324 | |
325 | s_perfSelectQueries++; | |
326 | s_perfTotalQueries++; | |
327 | ||
8a7cd6bb | 328 | hResult = hConn->m_driver->m_fpDrvSelect(hConn->m_connection, pwszQuery, &dwError, wcErrorText); |
533ce8c0 | 329 | if ((hResult == NULL) && (dwError == DBERR_CONNECTION_LOST) && hConn->m_reconnectEnabled) |
8a7cd6bb VK |
330 | { |
331 | DBReconnect(hConn); | |
332 | hResult = hConn->m_driver->m_fpDrvSelect(hConn->m_connection, pwszQuery, &dwError, wcErrorText); | |
333 | } | |
334 | ||
58f1f627 | 335 | ms = GetCurrentTimeMs() - ms; |
8a7cd6bb VK |
336 | if (hConn->m_driver->m_dumpSql) |
337 | { | |
2df047f4 | 338 | nxlog_debug(9, _T("%s sync query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms); |
58f1f627 VK |
339 | } |
340 | if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) | |
341 | { | |
2df047f4 | 342 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms); |
a4809f58 | 343 | s_perfLongRunningQueries++; |
8a7cd6bb VK |
344 | } |
345 | MutexUnlock(hConn->m_mutexTransLock); | |
346 | ||
347 | #ifndef UNICODE | |
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; | |
350 | #endif | |
351 | ||
352 | if (hResult == NULL) | |
353 | { | |
a4809f58 | 354 | s_perfFailedQueries++; |
8a7cd6bb VK |
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) | |
526ae8b8 | 358 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, pwszQuery, wcErrorText, dwError == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
359 | } |
360 | ||
361 | #ifndef UNICODE | |
362 | free(pwszQuery); | |
363 | #endif | |
364 | ||
365 | if (hResult != NULL) | |
366 | { | |
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; | |
371 | } | |
372 | ||
373 | return result; | |
374 | #undef pwszQuery | |
375 | #undef wcErrorText | |
376 | } | |
377 | ||
378 | DB_RESULT LIBNXDB_EXPORTABLE DBSelect(DB_HANDLE hConn, const TCHAR *query) | |
379 | { | |
380 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
381 | ||
382 | return DBSelectEx(hConn, query, errorText); | |
383 | } | |
384 | ||
74d4ba34 VK |
385 | /** |
386 | * Get number of columns | |
387 | */ | |
8a7cd6bb VK |
388 | int LIBNXDB_EXPORTABLE DBGetColumnCount(DB_RESULT hResult) |
389 | { | |
390 | return hResult->m_driver->m_fpDrvGetColumnCount(hResult->m_data); | |
391 | } | |
392 | ||
74d4ba34 VK |
393 | /** |
394 | * Get column name | |
395 | */ | |
750d59f2 | 396 | bool LIBNXDB_EXPORTABLE DBGetColumnName(DB_RESULT hResult, int column, TCHAR *buffer, int bufSize) |
8a7cd6bb VK |
397 | { |
398 | const char *name; | |
399 | ||
400 | name = hResult->m_driver->m_fpDrvGetColumnName(hResult->m_data, column); | |
401 | if (name != NULL) | |
402 | { | |
403 | #ifdef UNICODE | |
404 | MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, buffer, bufSize); | |
405 | buffer[bufSize - 1] = 0; | |
406 | #else | |
407 | nx_strncpy(buffer, name, bufSize); | |
408 | #endif | |
409 | } | |
410 | return name != NULL; | |
411 | } | |
412 | ||
74d4ba34 | 413 | /** |
f17cf019 | 414 | * Get column count for unbuffered result set |
74d4ba34 | 415 | */ |
f17cf019 | 416 | int LIBNXDB_EXPORTABLE DBGetColumnCount(DB_UNBUFFERED_RESULT hResult) |
8a7cd6bb | 417 | { |
f17cf019 | 418 | return hResult->m_driver->m_fpDrvGetColumnCountUnbuffered(hResult->m_data); |
8a7cd6bb VK |
419 | } |
420 | ||
74d4ba34 | 421 | /** |
f17cf019 | 422 | * Get column name for unbuffered result set |
74d4ba34 | 423 | */ |
f17cf019 | 424 | bool LIBNXDB_EXPORTABLE DBGetColumnName(DB_UNBUFFERED_RESULT hResult, int column, TCHAR *buffer, int bufSize) |
8a7cd6bb VK |
425 | { |
426 | const char *name; | |
427 | ||
f17cf019 | 428 | name = hResult->m_driver->m_fpDrvGetColumnNameUnbuffered(hResult->m_data, column); |
8a7cd6bb VK |
429 | if (name != NULL) |
430 | { | |
431 | #ifdef UNICODE | |
432 | MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, buffer, bufSize); | |
433 | buffer[bufSize - 1] = 0; | |
434 | #else | |
435 | nx_strncpy(buffer, name, bufSize); | |
436 | #endif | |
437 | } | |
438 | return name != NULL; | |
439 | } | |
440 | ||
271c3551 VK |
441 | /** |
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(). | |
444 | */ | |
8a7cd6bb VK |
445 | TCHAR LIBNXDB_EXPORTABLE *DBGetField(DB_RESULT hResult, int iRow, int iColumn, TCHAR *pszBuffer, int nBufLen) |
446 | { | |
447 | #ifdef UNICODE | |
448 | if (pszBuffer != NULL) | |
449 | { | |
c55ab1c2 | 450 | *pszBuffer = 0; |
8a7cd6bb VK |
451 | return hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pszBuffer, nBufLen); |
452 | } | |
453 | else | |
454 | { | |
8a7cd6bb | 455 | WCHAR *pszTemp; |
43526096 | 456 | LONG nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn); |
8a7cd6bb VK |
457 | if (nLen == -1) |
458 | { | |
459 | pszTemp = NULL; | |
460 | } | |
461 | else | |
462 | { | |
463 | nLen++; | |
464 | pszTemp = (WCHAR *)malloc(nLen * sizeof(WCHAR)); | |
465 | hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pszTemp, nLen); | |
466 | } | |
467 | return pszTemp; | |
468 | } | |
469 | #else | |
470 | return DBGetFieldA(hResult, iRow, iColumn, pszBuffer, nBufLen); | |
471 | #endif | |
472 | } | |
473 | ||
43526096 VK |
474 | /** |
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(). | |
477 | */ | |
478 | char LIBNXDB_EXPORTABLE *DBGetFieldUTF8(DB_RESULT hResult, int iRow, int iColumn, char *pszBuffer, int nBufLen) | |
479 | { | |
480 | if (hResult->m_driver->m_fpDrvGetFieldUTF8 != NULL) | |
481 | { | |
482 | if (pszBuffer != NULL) | |
483 | { | |
c55ab1c2 | 484 | *pszBuffer = 0; |
43526096 VK |
485 | return hResult->m_driver->m_fpDrvGetFieldUTF8(hResult->m_data, iRow, iColumn, pszBuffer, nBufLen); |
486 | } | |
487 | else | |
488 | { | |
489 | char *pszTemp; | |
490 | LONG nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn); | |
491 | if (nLen == -1) | |
492 | { | |
493 | pszTemp = NULL; | |
494 | } | |
495 | else | |
496 | { | |
343559f4 | 497 | nLen = nLen * 2 + 1; // increase buffer size because driver may return field length in characters |
43526096 VK |
498 | pszTemp = (char *)malloc(nLen); |
499 | hResult->m_driver->m_fpDrvGetFieldUTF8(hResult->m_data, iRow, iColumn, pszTemp, nLen); | |
500 | } | |
501 | return pszTemp; | |
502 | } | |
503 | } | |
504 | else | |
505 | { | |
506 | LONG nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn); | |
507 | if (nLen == -1) | |
508 | return NULL; | |
343559f4 | 509 | nLen = nLen * 2 + 1; // increase buffer size because driver may return field length in characters |
43526096 VK |
510 | |
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); | |
515 | free(wtemp); | |
516 | return value; | |
517 | } | |
518 | } | |
519 | ||
520 | /** | |
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(). | |
523 | */ | |
8a7cd6bb VK |
524 | char LIBNXDB_EXPORTABLE *DBGetFieldA(DB_RESULT hResult, int iRow, int iColumn, char *pszBuffer, int nBufLen) |
525 | { | |
526 | WCHAR *pwszData, *pwszBuffer; | |
527 | char *pszRet; | |
528 | int nLen; | |
529 | ||
530 | if (pszBuffer != NULL) | |
531 | { | |
c55ab1c2 | 532 | *pszBuffer = 0; |
8a7cd6bb VK |
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) | |
536 | { | |
7bdb43c3 | 537 | WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszData, -1, pszBuffer, nBufLen, NULL, NULL); |
8a7cd6bb VK |
538 | pszRet = pszBuffer; |
539 | } | |
540 | else | |
541 | { | |
542 | pszRet = NULL; | |
543 | } | |
544 | free(pwszBuffer); | |
545 | } | |
546 | else | |
547 | { | |
548 | nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn); | |
549 | if (nLen == -1) | |
550 | { | |
551 | pszRet = NULL; | |
552 | } | |
553 | else | |
554 | { | |
555 | nLen++; | |
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) | |
559 | { | |
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); | |
563 | } | |
564 | else | |
565 | { | |
566 | pszRet = NULL; | |
567 | } | |
568 | free(pwszBuffer); | |
569 | } | |
570 | } | |
571 | return pszRet; | |
572 | } | |
573 | ||
60b9b39c VK |
574 | /** |
575 | * Get text field and escape it for XML document. Returned string | |
576 | * always dynamically allocated and must be destroyed by caller. | |
577 | */ | |
578 | TCHAR LIBNXDB_EXPORTABLE *DBGetFieldForXML(DB_RESULT hResult, int row, int col) | |
579 | { | |
580 | TCHAR *value = DBGetField(hResult, row, col, NULL, 0); | |
581 | TCHAR *xmlString = EscapeStringForXML(value, -1); | |
582 | safe_free(value); | |
583 | return xmlString; | |
584 | } | |
585 | ||
22aaa779 VK |
586 | /** |
587 | * Get field's value as unsigned long | |
588 | */ | |
967893bb | 589 | UINT32 LIBNXDB_EXPORTABLE DBGetFieldULong(DB_RESULT hResult, int iRow, int iColumn) |
8a7cd6bb | 590 | { |
967893bb VK |
591 | INT32 iVal; |
592 | UINT32 dwVal; | |
8a7cd6bb VK |
593 | TCHAR *pszVal, szBuffer[256]; |
594 | ||
595 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
596 | if (pszVal == NULL) | |
597 | return 0; | |
dab4332d VK |
598 | StrStrip(pszVal); |
599 | if (*pszVal == _T('-')) | |
600 | { | |
601 | iVal = _tcstol(pszVal, NULL, 10); | |
967893bb | 602 | memcpy(&dwVal, &iVal, sizeof(INT32)); // To prevent possible conversion |
dab4332d VK |
603 | } |
604 | else | |
605 | { | |
606 | dwVal = _tcstoul(pszVal, NULL, 10); | |
607 | } | |
8a7cd6bb VK |
608 | return dwVal; |
609 | } | |
610 | ||
440c555e VK |
611 | /** |
612 | * Get field's value as unsigned 64-bit int | |
613 | */ | |
967893bb | 614 | UINT64 LIBNXDB_EXPORTABLE DBGetFieldUInt64(DB_RESULT hResult, int iRow, int iColumn) |
8a7cd6bb VK |
615 | { |
616 | INT64 iVal; | |
967893bb | 617 | UINT64 qwVal; |
8a7cd6bb VK |
618 | TCHAR *pszVal, szBuffer[256]; |
619 | ||
620 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
621 | if (pszVal == NULL) | |
622 | return 0; | |
dab4332d VK |
623 | StrStrip(pszVal); |
624 | if (*pszVal == _T('-')) | |
625 | { | |
626 | iVal = _tcstoll(pszVal, NULL, 10); | |
627 | memcpy(&qwVal, &iVal, sizeof(INT64)); // To prevent possible conversion | |
628 | } | |
629 | else | |
630 | { | |
631 | qwVal = _tcstoull(pszVal, NULL, 10); | |
632 | } | |
8a7cd6bb VK |
633 | return qwVal; |
634 | } | |
635 | ||
440c555e VK |
636 | /** |
637 | * Get field's value as signed long | |
638 | */ | |
967893bb | 639 | INT32 LIBNXDB_EXPORTABLE DBGetFieldLong(DB_RESULT hResult, int iRow, int iColumn) |
8a7cd6bb VK |
640 | { |
641 | TCHAR *pszVal, szBuffer[256]; | |
642 | ||
643 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
644 | return pszVal == NULL ? 0 : _tcstol(pszVal, NULL, 10); | |
645 | } | |
646 | ||
43526096 VK |
647 | /** |
648 | * Get field's value as signed 64-bit int | |
649 | */ | |
8a7cd6bb VK |
650 | INT64 LIBNXDB_EXPORTABLE DBGetFieldInt64(DB_RESULT hResult, int iRow, int iColumn) |
651 | { | |
652 | TCHAR *pszVal, szBuffer[256]; | |
653 | ||
654 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
655 | return pszVal == NULL ? 0 : _tcstoll(pszVal, NULL, 10); | |
656 | } | |
657 | ||
43526096 VK |
658 | /** |
659 | * Get field's value as double | |
660 | */ | |
8a7cd6bb VK |
661 | double LIBNXDB_EXPORTABLE DBGetFieldDouble(DB_RESULT hResult, int iRow, int iColumn) |
662 | { | |
663 | TCHAR *pszVal, szBuffer[256]; | |
664 | ||
665 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
666 | return pszVal == NULL ? 0 : _tcstod(pszVal, NULL); | |
667 | } | |
668 | ||
43526096 | 669 | /** |
43709a0c | 670 | * Get field's value as IPv4 address |
43526096 | 671 | */ |
967893bb | 672 | UINT32 LIBNXDB_EXPORTABLE DBGetFieldIPAddr(DB_RESULT hResult, int iRow, int iColumn) |
8a7cd6bb VK |
673 | { |
674 | TCHAR *pszVal, szBuffer[256]; | |
675 | ||
676 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
87f0faf1 | 677 | return pszVal == NULL ? 0 : ntohl(_t_inet_addr(pszVal)); |
43709a0c VK |
678 | } |
679 | ||
680 | /** | |
681 | * Get field's value as IP address | |
682 | */ | |
683 | InetAddress LIBNXDB_EXPORTABLE DBGetFieldInetAddr(DB_RESULT hResult, int iRow, int iColumn) | |
684 | { | |
685 | TCHAR *pszVal, szBuffer[256]; | |
686 | ||
687 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
688 | return pszVal == NULL ? InetAddress() : InetAddress::parse(pszVal); | |
8a7cd6bb VK |
689 | } |
690 | ||
43526096 VK |
691 | /** |
692 | * Get field's value as integer array from byte array encoded in hex | |
693 | */ | |
750d59f2 | 694 | bool LIBNXDB_EXPORTABLE DBGetFieldByteArray(DB_RESULT hResult, int iRow, int iColumn, |
1e6b68a6 | 695 | int *pnArray, int nSize, int nDefault) |
8a7cd6bb VK |
696 | { |
697 | char pbBytes[128]; | |
750d59f2 | 698 | bool bResult; |
8a7cd6bb VK |
699 | int i, nLen; |
700 | TCHAR *pszVal, szBuffer[256]; | |
701 | ||
702 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
703 | if (pszVal != NULL) | |
704 | { | |
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; | |
750d59f2 | 711 | bResult = true; |
8a7cd6bb VK |
712 | } |
713 | else | |
714 | { | |
715 | for(i = 0; i < nSize; i++) | |
716 | pnArray[i] = nDefault; | |
750d59f2 | 717 | bResult = false; |
8a7cd6bb VK |
718 | } |
719 | return bResult; | |
720 | } | |
721 | ||
750d59f2 | 722 | bool LIBNXDB_EXPORTABLE DBGetFieldByteArray2(DB_RESULT hResult, int iRow, int iColumn, |
1e6b68a6 VK |
723 | BYTE *data, int nSize, int nDefault) |
724 | { | |
750d59f2 | 725 | bool bResult; |
1e6b68a6 VK |
726 | TCHAR *pszVal, szBuffer[256]; |
727 | ||
728 | pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256); | |
729 | if (pszVal != NULL) | |
730 | { | |
731 | int bytes = (int)StrToBin(pszVal, data, nSize); | |
732 | if (bytes < nSize) | |
733 | memset(&data[bytes], 0, nSize - bytes); | |
750d59f2 | 734 | bResult = true; |
1e6b68a6 VK |
735 | } |
736 | else | |
737 | { | |
738 | memset(data, nDefault, nSize); | |
750d59f2 | 739 | bResult = false; |
1e6b68a6 VK |
740 | } |
741 | return bResult; | |
742 | } | |
743 | ||
6e3f4556 VK |
744 | /** |
745 | * Get field's value as GUID | |
746 | */ | |
de4af576 | 747 | uuid LIBNXDB_EXPORTABLE DBGetFieldGUID(DB_RESULT hResult, int iRow, int iColumn) |
8a7cd6bb | 748 | { |
de4af576 VK |
749 | TCHAR buffer[256]; |
750 | TCHAR *value = DBGetField(hResult, iRow, iColumn, buffer, 256); | |
751 | return (value == NULL) ? uuid::NULL_UUID : uuid::parse(value); | |
8a7cd6bb VK |
752 | } |
753 | ||
6e3f4556 VK |
754 | /** |
755 | * Get number of rows in result | |
756 | */ | |
8a7cd6bb VK |
757 | int LIBNXDB_EXPORTABLE DBGetNumRows(DB_RESULT hResult) |
758 | { | |
759 | if (hResult == NULL) | |
760 | return 0; | |
761 | return hResult->m_driver->m_fpDrvGetNumRows(hResult->m_data); | |
762 | } | |
763 | ||
6e3f4556 VK |
764 | /** |
765 | * Free result | |
766 | */ | |
8a7cd6bb VK |
767 | void LIBNXDB_EXPORTABLE DBFreeResult(DB_RESULT hResult) |
768 | { | |
769 | if (hResult != NULL) | |
770 | { | |
771 | hResult->m_driver->m_fpDrvFreeResult(hResult->m_data); | |
772 | free(hResult); | |
773 | } | |
774 | } | |
775 | ||
6e3f4556 | 776 | /** |
f17cf019 | 777 | * Unbuffered SELECT query |
6e3f4556 | 778 | */ |
f17cf019 | 779 | DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectUnbufferedEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText) |
8a7cd6bb | 780 | { |
f17cf019 VK |
781 | DBDRV_UNBUFFERED_RESULT hResult; |
782 | DB_UNBUFFERED_RESULT result = NULL; | |
e169a297 | 783 | DWORD dwError = DBERR_OTHER_ERROR; |
8a7cd6bb VK |
784 | #ifdef UNICODE |
785 | #define pwszQuery szQuery | |
786 | #define wcErrorText errorText | |
787 | #else | |
788 | WCHAR *pwszQuery = WideStringFromMBString(szQuery); | |
789 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
790 | #endif | |
791 | ||
c17f6cbc | 792 | MutexLock(hConn->m_mutexTransLock); |
58f1f627 | 793 | INT64 ms = GetCurrentTimeMs(); |
a4809f58 VK |
794 | |
795 | s_perfSelectQueries++; | |
796 | s_perfTotalQueries++; | |
797 | ||
f17cf019 | 798 | hResult = hConn->m_driver->m_fpDrvSelectUnbuffered(hConn->m_connection, pwszQuery, &dwError, wcErrorText); |
533ce8c0 | 799 | if ((hResult == NULL) && (dwError == DBERR_CONNECTION_LOST) && hConn->m_reconnectEnabled) |
8a7cd6bb VK |
800 | { |
801 | DBReconnect(hConn); | |
f17cf019 | 802 | hResult = hConn->m_driver->m_fpDrvSelectUnbuffered(hConn->m_connection, pwszQuery, &dwError, wcErrorText); |
8a7cd6bb VK |
803 | } |
804 | ||
58f1f627 | 805 | ms = GetCurrentTimeMs() - ms; |
8a7cd6bb VK |
806 | if (hConn->m_driver->m_dumpSql) |
807 | { | |
2df047f4 | 808 | nxlog_debug(9, _T("%s unbuffered query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (int)ms); |
58f1f627 VK |
809 | } |
810 | if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) | |
811 | { | |
2df047f4 | 812 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), szQuery, (int)ms); |
a4809f58 | 813 | s_perfLongRunningQueries++; |
8a7cd6bb VK |
814 | } |
815 | if (hResult == NULL) | |
816 | { | |
a4809f58 | 817 | s_perfFailedQueries++; |
8a7cd6bb VK |
818 | MutexUnlock(hConn->m_mutexTransLock); |
819 | ||
820 | #ifndef UNICODE | |
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; | |
823 | #endif | |
824 | ||
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) | |
526ae8b8 | 828 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, pwszQuery, wcErrorText, dwError == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
829 | } |
830 | ||
831 | #ifndef UNICODE | |
832 | free(pwszQuery); | |
833 | #endif | |
834 | ||
835 | if (hResult != NULL) | |
836 | { | |
f17cf019 | 837 | result = (DB_UNBUFFERED_RESULT)malloc(sizeof(db_unbuffered_result_t)); |
8a7cd6bb VK |
838 | result->m_driver = hConn->m_driver; |
839 | result->m_connection = hConn; | |
840 | result->m_data = hResult; | |
841 | } | |
842 | ||
843 | return result; | |
844 | #undef pwszQuery | |
845 | #undef wcErrorText | |
846 | } | |
847 | ||
f17cf019 | 848 | DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectUnbuffered(DB_HANDLE hConn, const TCHAR *query) |
8a7cd6bb VK |
849 | { |
850 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
851 | ||
f17cf019 | 852 | return DBSelectUnbufferedEx(hConn, query, errorText); |
8a7cd6bb VK |
853 | } |
854 | ||
6e3f4556 | 855 | /** |
f17cf019 | 856 | * Fetch next row from unbuffered SELECT result |
6e3f4556 | 857 | */ |
f17cf019 | 858 | bool LIBNXDB_EXPORTABLE DBFetch(DB_UNBUFFERED_RESULT hResult) |
8a7cd6bb VK |
859 | { |
860 | return hResult->m_driver->m_fpDrvFetch(hResult->m_data); | |
861 | } | |
862 | ||
84ee0f9c | 863 | /** |
f17cf019 | 864 | * Get field's value from unbuffered SELECT result |
84ee0f9c | 865 | */ |
f17cf019 | 866 | TCHAR LIBNXDB_EXPORTABLE *DBGetField(DB_UNBUFFERED_RESULT hResult, int iColumn, TCHAR *pBuffer, int iBufSize) |
8a7cd6bb VK |
867 | { |
868 | #ifdef UNICODE | |
869 | if (pBuffer != NULL) | |
870 | { | |
f17cf019 | 871 | return hResult->m_driver->m_fpDrvGetFieldUnbuffered(hResult->m_data, iColumn, pBuffer, iBufSize); |
8a7cd6bb VK |
872 | } |
873 | else | |
874 | { | |
967893bb | 875 | INT32 nLen; |
8a7cd6bb VK |
876 | WCHAR *pszTemp; |
877 | ||
f17cf019 | 878 | nLen = hResult->m_driver->m_fpDrvGetFieldLengthUnbuffered(hResult->m_data, iColumn); |
8a7cd6bb VK |
879 | if (nLen == -1) |
880 | { | |
881 | pszTemp = NULL; | |
882 | } | |
883 | else | |
884 | { | |
885 | nLen++; | |
886 | pszTemp = (WCHAR *)malloc(nLen * sizeof(WCHAR)); | |
f17cf019 | 887 | hResult->m_driver->m_fpDrvGetFieldUnbuffered(hResult->m_data, iColumn, pszTemp, nLen); |
8a7cd6bb VK |
888 | } |
889 | return pszTemp; | |
890 | } | |
891 | #else | |
892 | WCHAR *pwszData, *pwszBuffer; | |
893 | char *pszRet; | |
894 | int nLen; | |
895 | ||
896 | if (pBuffer != NULL) | |
897 | { | |
898 | pwszBuffer = (WCHAR *)malloc(iBufSize * sizeof(WCHAR)); | |
f17cf019 | 899 | if (hResult->m_driver->m_fpDrvGetFieldUnbuffered(hResult->m_data, iColumn, pwszBuffer, iBufSize) != NULL) |
8a7cd6bb VK |
900 | { |
901 | WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, | |
902 | pwszBuffer, -1, pBuffer, iBufSize, NULL, NULL); | |
903 | pszRet = pBuffer; | |
904 | } | |
905 | else | |
906 | { | |
907 | pszRet = NULL; | |
908 | } | |
909 | free(pwszBuffer); | |
910 | } | |
911 | else | |
912 | { | |
f17cf019 | 913 | nLen = hResult->m_driver->m_fpDrvGetFieldLengthUnbuffered(hResult->m_data, iColumn); |
8a7cd6bb VK |
914 | if (nLen == -1) |
915 | { | |
916 | pszRet = NULL; | |
917 | } | |
918 | else | |
919 | { | |
920 | nLen++; | |
921 | pwszBuffer = (WCHAR *)malloc(nLen * sizeof(WCHAR)); | |
f17cf019 | 922 | pwszData = hResult->m_driver->m_fpDrvGetFieldUnbuffered(hResult->m_data, iColumn, pwszBuffer, nLen); |
8a7cd6bb VK |
923 | if (pwszData != NULL) |
924 | { | |
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); | |
929 | } | |
930 | else | |
931 | { | |
932 | pszRet = NULL; | |
933 | } | |
934 | free(pwszBuffer); | |
935 | } | |
936 | } | |
937 | return pszRet; | |
938 | #endif | |
939 | } | |
940 | ||
89e5f052 VK |
941 | /** |
942 | * Get field's value from unbuffered SELECT result as UTF-8 string | |
943 | */ | |
7f8e3ccf | 944 | char LIBNXDB_EXPORTABLE *DBGetFieldUTF8(DB_UNBUFFERED_RESULT hResult, int iColumn, char *buffer, int iBufSize) |
89e5f052 | 945 | { |
7f8e3ccf | 946 | if (hResult->m_driver->m_fpDrvGetFieldUTF8 != NULL) |
89e5f052 | 947 | { |
7f8e3ccf VK |
948 | if (buffer != NULL) |
949 | { | |
950 | *buffer = 0; | |
951 | return hResult->m_driver->m_fpDrvGetFieldUnbufferedUTF8(hResult->m_data, iColumn, buffer, iBufSize); | |
952 | } | |
953 | else | |
954 | { | |
955 | char *pszTemp; | |
956 | LONG nLen = hResult->m_driver->m_fpDrvGetFieldLengthUnbuffered(hResult->m_data, iColumn); | |
957 | if (nLen == -1) | |
958 | { | |
959 | pszTemp = NULL; | |
960 | } | |
961 | else | |
962 | { | |
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); | |
966 | } | |
967 | return pszTemp; | |
968 | } | |
89e5f052 VK |
969 | } |
970 | else | |
971 | { | |
7f8e3ccf VK |
972 | LONG nLen = hResult->m_driver->m_fpDrvGetFieldLengthUnbuffered(hResult->m_data, iColumn); |
973 | if (nLen == -1) | |
974 | return NULL; | |
975 | nLen = nLen * 2 + 1; // increase buffer size because driver may return field length in characters | |
976 | ||
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); | |
981 | free(wtemp); | |
982 | return value; | |
89e5f052 | 983 | } |
89e5f052 VK |
984 | } |
985 | ||
6e3f4556 | 986 | /** |
f17cf019 | 987 | * Get field's value as unsigned long from unbuffered SELECT result |
6e3f4556 | 988 | */ |
f17cf019 | 989 | UINT32 LIBNXDB_EXPORTABLE DBGetFieldULong(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb | 990 | { |
967893bb VK |
991 | INT32 iVal; |
992 | UINT32 dwVal; | |
8a7cd6bb VK |
993 | TCHAR szBuffer[64]; |
994 | ||
f17cf019 | 995 | if (DBGetField(hResult, iColumn, szBuffer, 64) == NULL) |
8a7cd6bb | 996 | return 0; |
dab4332d VK |
997 | StrStrip(szBuffer); |
998 | if (szBuffer[0] == _T('-')) | |
999 | { | |
1000 | iVal = _tcstol(szBuffer, NULL, 10); | |
967893bb | 1001 | memcpy(&dwVal, &iVal, sizeof(INT32)); // To prevent possible conversion |
dab4332d VK |
1002 | } |
1003 | else | |
1004 | { | |
1005 | dwVal = _tcstoul(szBuffer, NULL, 10); | |
1006 | } | |
8a7cd6bb VK |
1007 | return dwVal; |
1008 | } | |
1009 | ||
6e3f4556 | 1010 | /** |
f17cf019 | 1011 | * Get field's value as unsigned 64-bit int from unbuffered SELECT result |
6e3f4556 | 1012 | */ |
f17cf019 | 1013 | UINT64 LIBNXDB_EXPORTABLE DBGetFieldUInt64(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb VK |
1014 | { |
1015 | INT64 iVal; | |
967893bb | 1016 | UINT64 qwVal; |
8a7cd6bb VK |
1017 | TCHAR szBuffer[64]; |
1018 | ||
f17cf019 | 1019 | if (DBGetField(hResult, iColumn, szBuffer, 64) == NULL) |
8a7cd6bb | 1020 | return 0; |
dab4332d VK |
1021 | StrStrip(szBuffer); |
1022 | if (szBuffer[0] == _T('-')) | |
1023 | { | |
1024 | iVal = _tcstoll(szBuffer, NULL, 10); | |
1025 | memcpy(&qwVal, &iVal, sizeof(INT64)); // To prevent possible conversion | |
1026 | } | |
1027 | else | |
1028 | { | |
1029 | qwVal = _tcstoull(szBuffer, NULL, 10); | |
1030 | } | |
8a7cd6bb VK |
1031 | return qwVal; |
1032 | } | |
1033 | ||
22aaa779 | 1034 | /** |
f17cf019 | 1035 | * Get field's value as signed long from unbuffered SELECT result |
22aaa779 | 1036 | */ |
f17cf019 | 1037 | INT32 LIBNXDB_EXPORTABLE DBGetFieldLong(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb VK |
1038 | { |
1039 | TCHAR szBuffer[64]; | |
f17cf019 | 1040 | return DBGetField(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstol(szBuffer, NULL, 10); |
8a7cd6bb VK |
1041 | } |
1042 | ||
22aaa779 | 1043 | /** |
f17cf019 | 1044 | * Get field's value as signed 64-bit int from unbuffered SELECT result |
22aaa779 | 1045 | */ |
f17cf019 | 1046 | INT64 LIBNXDB_EXPORTABLE DBGetFieldInt64(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb VK |
1047 | { |
1048 | TCHAR szBuffer[64]; | |
f17cf019 | 1049 | return DBGetField(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstoll(szBuffer, NULL, 10); |
8a7cd6bb VK |
1050 | } |
1051 | ||
22aaa779 | 1052 | /** |
f17cf019 | 1053 | * Get field's value as signed long from unbuffered SELECT result |
22aaa779 | 1054 | */ |
f17cf019 | 1055 | double LIBNXDB_EXPORTABLE DBGetFieldDouble(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb VK |
1056 | { |
1057 | TCHAR szBuffer[64]; | |
f17cf019 | 1058 | return DBGetField(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstod(szBuffer, NULL); |
8a7cd6bb VK |
1059 | } |
1060 | ||
22aaa779 | 1061 | /** |
f17cf019 | 1062 | * Get field's value as IPv4 address from unbuffered SELECT result |
22aaa779 | 1063 | */ |
f17cf019 | 1064 | UINT32 LIBNXDB_EXPORTABLE DBGetFieldIPAddr(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb | 1065 | { |
f17cf019 VK |
1066 | TCHAR buffer[64]; |
1067 | return (DBGetField(hResult, iColumn, buffer, 64) == NULL) ? INADDR_NONE : ntohl(_t_inet_addr(buffer)); | |
8a7cd6bb VK |
1068 | } |
1069 | ||
43709a0c | 1070 | /** |
f17cf019 | 1071 | * Get field's value as IP address from unbuffered SELECT result |
43709a0c | 1072 | */ |
f17cf019 | 1073 | InetAddress LIBNXDB_EXPORTABLE DBGetFieldInetAddr(DB_UNBUFFERED_RESULT hResult, int iColumn) |
43709a0c | 1074 | { |
f17cf019 VK |
1075 | TCHAR buffer[64]; |
1076 | return (DBGetField(hResult, iColumn, buffer, 64) == NULL) ? InetAddress() : InetAddress::parse(buffer); | |
43709a0c VK |
1077 | } |
1078 | ||
74d4ba34 | 1079 | /** |
f17cf019 | 1080 | * Get field's value as GUID from unbuffered SELECT result |
74d4ba34 | 1081 | */ |
f17cf019 | 1082 | uuid LIBNXDB_EXPORTABLE DBGetFieldGUID(DB_UNBUFFERED_RESULT hResult, int iColumn) |
8a7cd6bb | 1083 | { |
f17cf019 VK |
1084 | TCHAR buffer[64]; |
1085 | return (DBGetField(hResult, iColumn, buffer, 64) == NULL) ? uuid::NULL_UUID : uuid::parse(buffer); | |
1086 | } | |
1087 | ||
1088 | /** | |
1089 | * Free unbuffered SELECT result | |
1090 | */ | |
1091 | void LIBNXDB_EXPORTABLE DBFreeResult(DB_UNBUFFERED_RESULT hResult) | |
1092 | { | |
1093 | hResult->m_driver->m_fpDrvFreeUnbufferedResult(hResult->m_data); | |
8a7cd6bb VK |
1094 | MutexUnlock(hResult->m_connection->m_mutexTransLock); |
1095 | free(hResult); | |
1096 | } | |
1097 | ||
74d4ba34 VK |
1098 | /** |
1099 | * Prepare statement | |
1100 | */ | |
8a7cd6bb VK |
1101 | DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepareEx(DB_HANDLE hConn, const TCHAR *query, TCHAR *errorText) |
1102 | { | |
1103 | DB_STATEMENT result = NULL; | |
dab4332d | 1104 | INT64 ms; |
8a7cd6bb VK |
1105 | |
1106 | #ifdef UNICODE | |
1107 | #define pwszQuery query | |
1108 | #define wcErrorText errorText | |
1109 | #else | |
1110 | WCHAR *pwszQuery = WideStringFromMBString(query); | |
1111 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
1112 | #endif | |
1113 | ||
de1d708f VK |
1114 | MutexLock(hConn->m_mutexTransLock); |
1115 | ||
dab4332d VK |
1116 | if (hConn->m_driver->m_dumpSql) |
1117 | ms = GetCurrentTimeMs(); | |
1118 | ||
de1d708f VK |
1119 | DWORD errorCode; |
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) | |
1122 | { | |
1123 | DBReconnect(hConn); | |
1124 | stmt = hConn->m_driver->m_fpDrvPrepare(hConn->m_connection, pwszQuery, &errorCode, wcErrorText); | |
1125 | } | |
1126 | MutexUnlock(hConn->m_mutexTransLock); | |
1127 | ||
8a7cd6bb VK |
1128 | if (stmt != NULL) |
1129 | { | |
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); | |
1135 | } | |
1136 | else | |
1137 | { | |
1138 | #ifndef UNICODE | |
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; | |
1141 | #endif | |
1142 | ||
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) | |
526ae8b8 | 1146 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, pwszQuery, wcErrorText, errorCode == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
a4809f58 VK |
1147 | |
1148 | s_perfFailedQueries++; | |
1149 | s_perfTotalQueries++; | |
8a7cd6bb VK |
1150 | } |
1151 | ||
dab4332d VK |
1152 | if (hConn->m_driver->m_dumpSql) |
1153 | { | |
1154 | ms = GetCurrentTimeMs() - ms; | |
2df047f4 | 1155 | nxlog_debug(9, _T("{%p} %s prepare: \"%s\" [%d ms]"), result, (result != NULL) ? _T("Successful") : _T("Failed"), query, ms); |
dab4332d VK |
1156 | } |
1157 | ||
8a7cd6bb VK |
1158 | #ifndef UNICODE |
1159 | free(pwszQuery); | |
1160 | #endif | |
1161 | ||
74d4ba34 VK |
1162 | if (result != NULL) |
1163 | { | |
1164 | hConn->m_preparedStatements->add(result); | |
1165 | } | |
1166 | ||
8a7cd6bb VK |
1167 | return result; |
1168 | #undef pwszQuery | |
1169 | #undef wcErrorText | |
1170 | } | |
1171 | ||
74d4ba34 VK |
1172 | /** |
1173 | * Prepare statement | |
1174 | */ | |
8a7cd6bb VK |
1175 | DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepare(DB_HANDLE hConn, const TCHAR *query) |
1176 | { | |
1177 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
1178 | return DBPrepareEx(hConn, query, errorText); | |
1179 | } | |
1180 | ||
74d4ba34 VK |
1181 | /** |
1182 | * Destroy prepared statement | |
1183 | */ | |
8a7cd6bb VK |
1184 | void LIBNXDB_EXPORTABLE DBFreeStatement(DB_STATEMENT hStmt) |
1185 | { | |
74d4ba34 VK |
1186 | if (hStmt == NULL) |
1187 | return; | |
1188 | ||
1189 | if (hStmt->m_connection != NULL) | |
1190 | { | |
1191 | hStmt->m_connection->m_preparedStatements->remove(hStmt); | |
1192 | } | |
1193 | hStmt->m_driver->m_fpDrvFreeStatement(hStmt->m_statement); | |
2223a4d7 | 1194 | free(hStmt->m_query); |
8a7cd6bb VK |
1195 | free(hStmt); |
1196 | } | |
1197 | ||
84ee0f9c VK |
1198 | /** |
1199 | * Get source query for prepared statement | |
1200 | */ | |
1201 | const TCHAR LIBNXDB_EXPORTABLE *DBGetStatementSource(DB_STATEMENT hStmt) | |
1202 | { | |
1203 | return hStmt->m_query; | |
1204 | } | |
1205 | ||
66c11d49 VK |
1206 | /** |
1207 | * Open batch | |
1208 | */ | |
1209 | bool LIBNXDB_EXPORTABLE DBOpenBatch(DB_STATEMENT hStmt) | |
1210 | { | |
1211 | if (!IS_VALID_STATEMENT_HANDLE(hStmt) || (hStmt->m_driver->m_fpDrvOpenBatch == NULL)) | |
1212 | return false; | |
1213 | return hStmt->m_driver->m_fpDrvOpenBatch(hStmt->m_statement); | |
1214 | } | |
1215 | ||
1216 | /** | |
1217 | * Start next batch row batch | |
1218 | */ | |
1219 | void LIBNXDB_EXPORTABLE DBNextBatchRow(DB_STATEMENT hStmt) | |
1220 | { | |
1221 | if (IS_VALID_STATEMENT_HANDLE(hStmt) && (hStmt->m_driver->m_fpDrvNextBatchRow != NULL)) | |
1222 | hStmt->m_driver->m_fpDrvNextBatchRow(hStmt->m_statement); | |
1223 | } | |
1224 | ||
dd651102 VK |
1225 | /** |
1226 | * Bind parameter (generic) | |
1227 | */ | |
8a7cd6bb VK |
1228 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, int cType, void *buffer, int allocType) |
1229 | { | |
74d4ba34 | 1230 | if ((pos <= 0) || !IS_VALID_STATEMENT_HANDLE(hStmt)) |
47a89886 VK |
1231 | return; |
1232 | ||
6449475d VK |
1233 | if (hStmt->m_connection->m_driver->m_dumpSql) |
1234 | { | |
1235 | if (cType == DB_CTYPE_STRING) | |
1236 | { | |
2df047f4 | 1237 | nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, buffer); |
6449475d | 1238 | } |
b8849590 VK |
1239 | else if (cType == DB_CTYPE_UTF8_STRING) |
1240 | { | |
1241 | nxlog_debug(9, _T("{%p} bind at pos %d (UTF-8): \"%hs\""), hStmt, pos, buffer); | |
1242 | } | |
6449475d VK |
1243 | else |
1244 | { | |
1245 | TCHAR text[64]; | |
1246 | switch(cType) | |
1247 | { | |
1248 | case DB_CTYPE_INT32: | |
967893bb | 1249 | _sntprintf(text, 64, _T("%d"), *((INT32 *)buffer)); |
6449475d VK |
1250 | break; |
1251 | case DB_CTYPE_UINT32: | |
967893bb | 1252 | _sntprintf(text, 64, _T("%u"), *((UINT32 *)buffer)); |
6449475d VK |
1253 | break; |
1254 | case DB_CTYPE_INT64: | |
1255 | _sntprintf(text, 64, INT64_FMT, *((INT64 *)buffer)); | |
1256 | break; | |
1257 | case DB_CTYPE_UINT64: | |
967893bb | 1258 | _sntprintf(text, 64, UINT64_FMT, *((UINT64 *)buffer)); |
6449475d VK |
1259 | break; |
1260 | case DB_CTYPE_DOUBLE: | |
1261 | _sntprintf(text, 64, _T("%f"), *((double *)buffer)); | |
1262 | break; | |
1263 | } | |
2df047f4 | 1264 | nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, text); |
6449475d VK |
1265 | } |
1266 | } | |
70d5f4b0 VK |
1267 | |
1268 | #ifdef UNICODE | |
1269 | #define wBuffer buffer | |
1270 | #define realAllocType allocType | |
1271 | #else | |
1272 | void *wBuffer; | |
1273 | int realAllocType = allocType; | |
1274 | if (cType == DB_CTYPE_STRING) | |
1275 | { | |
1276 | wBuffer = (void *)WideStringFromMBString((char *)buffer); | |
1277 | if (allocType == DB_BIND_DYNAMIC) | |
1278 | free(buffer); | |
1279 | realAllocType = DB_BIND_DYNAMIC; | |
1280 | } | |
1281 | else | |
1282 | { | |
1283 | wBuffer = buffer; | |
1284 | } | |
1285 | #endif | |
1286 | hStmt->m_driver->m_fpDrvBind(hStmt->m_statement, pos, sqlType, cType, wBuffer, realAllocType); | |
1287 | #undef wBuffer | |
1288 | #undef realAllocType | |
8a7cd6bb VK |
1289 | } |
1290 | ||
dd651102 VK |
1291 | /** |
1292 | * Bind string parameter | |
1293 | */ | |
8a7cd6bb VK |
1294 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, const TCHAR *value, int allocType) |
1295 | { | |
511bea22 VK |
1296 | if (value != NULL) |
1297 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, (void *)value, allocType); | |
1298 | else | |
1299 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, (void *)_T(""), DB_BIND_STATIC); | |
8a7cd6bb VK |
1300 | } |
1301 | ||
dd651102 | 1302 | /** |
526ae8b8 | 1303 | * Bind string parameter with length validation |
dd651102 VK |
1304 | */ |
1305 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, const TCHAR *value, int allocType, int maxLen) | |
1306 | { | |
1307 | if (value != NULL) | |
1308 | { | |
1309 | if ((int)_tcslen(value) <= maxLen) | |
1310 | { | |
1311 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, (void *)value, allocType); | |
1312 | } | |
1313 | else | |
1314 | { | |
1315 | if (allocType == DB_BIND_DYNAMIC) | |
1316 | { | |
1317 | ((TCHAR *)value)[maxLen] = 0; | |
1318 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, (void *)value, DB_BIND_DYNAMIC); | |
1319 | } | |
1320 | else | |
1321 | { | |
1322 | TCHAR *temp = (TCHAR *)nx_memdup(value, sizeof(TCHAR) * (maxLen + 1)); | |
1323 | temp[maxLen] = 0; | |
1324 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, temp, DB_BIND_DYNAMIC); | |
1325 | } | |
1326 | } | |
1327 | } | |
1328 | else | |
1329 | { | |
1330 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, (void *)_T(""), DB_BIND_STATIC); | |
1331 | } | |
1332 | } | |
1333 | ||
1334 | /** | |
1335 | * Bind 32 bit integer parameter | |
1336 | */ | |
967893bb | 1337 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, INT32 value) |
8a7cd6bb VK |
1338 | { |
1339 | DBBind(hStmt, pos, sqlType, DB_CTYPE_INT32, &value, DB_BIND_TRANSIENT); | |
1340 | } | |
1341 | ||
dd651102 VK |
1342 | /** |
1343 | * Bind 32 bit unsigned integer parameter | |
1344 | */ | |
967893bb | 1345 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, UINT32 value) |
8a7cd6bb | 1346 | { |
dab4332d VK |
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); | |
8a7cd6bb VK |
1351 | } |
1352 | ||
dd651102 VK |
1353 | /** |
1354 | * Bind 64 bit integer parameter | |
1355 | */ | |
8a7cd6bb VK |
1356 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, INT64 value) |
1357 | { | |
1358 | DBBind(hStmt, pos, sqlType, DB_CTYPE_INT64, &value, DB_BIND_TRANSIENT); | |
1359 | } | |
1360 | ||
dd651102 VK |
1361 | /** |
1362 | * Bind 64 bit unsigned integer parameter | |
1363 | */ | |
967893bb | 1364 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, UINT64 value) |
8a7cd6bb VK |
1365 | { |
1366 | DBBind(hStmt, pos, sqlType, DB_CTYPE_UINT64, &value, DB_BIND_TRANSIENT); | |
1367 | } | |
1368 | ||
dd651102 VK |
1369 | /** |
1370 | * Bind floating point parameter | |
1371 | */ | |
8a7cd6bb VK |
1372 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, double value) |
1373 | { | |
1374 | DBBind(hStmt, pos, sqlType, DB_CTYPE_DOUBLE, &value, DB_BIND_TRANSIENT); | |
1375 | } | |
1376 | ||
de4af576 VK |
1377 | /** |
1378 | * Bind UUID parameter | |
1379 | */ | |
1380 | void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, const uuid& value) | |
1381 | { | |
1382 | TCHAR buffer[64]; | |
1383 | DBBind(hStmt, pos, sqlType, DB_CTYPE_STRING, value.toString(buffer), DB_BIND_TRANSIENT); | |
1384 | } | |
1385 | ||
967893bb VK |
1386 | /** |
1387 | * Execute prepared statement (non-SELECT) | |
1388 | */ | |
750d59f2 | 1389 | bool LIBNXDB_EXPORTABLE DBExecuteEx(DB_STATEMENT hStmt, TCHAR *errorText) |
8a7cd6bb | 1390 | { |
74d4ba34 VK |
1391 | if (!IS_VALID_STATEMENT_HANDLE(hStmt)) |
1392 | { | |
1393 | _tcscpy(errorText, _T("Invalid statement handle")); | |
750d59f2 | 1394 | return false; |
74d4ba34 VK |
1395 | } |
1396 | ||
8a7cd6bb VK |
1397 | #ifdef UNICODE |
1398 | #define wcErrorText errorText | |
1399 | #else | |
1400 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
1401 | #endif | |
8a7cd6bb VK |
1402 | |
1403 | DB_HANDLE hConn = hStmt->m_connection; | |
c17f6cbc | 1404 | MutexLock(hConn->m_mutexTransLock); |
58f1f627 | 1405 | UINT64 ms = GetCurrentTimeMs(); |
8a7cd6bb | 1406 | |
a4809f58 VK |
1407 | s_perfNonSelectQueries++; |
1408 | s_perfTotalQueries++; | |
1409 | ||
8a7cd6bb | 1410 | DWORD dwResult = hConn->m_driver->m_fpDrvExecute(hConn->m_connection, hStmt->m_statement, wcErrorText); |
58f1f627 | 1411 | ms = GetCurrentTimeMs() - ms; |
8a7cd6bb VK |
1412 | if (hConn->m_driver->m_dumpSql) |
1413 | { | |
2df047f4 | 1414 | nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms); |
58f1f627 VK |
1415 | } |
1416 | if ((dwResult == DBERR_SUCCESS) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) | |
1417 | { | |
2df047f4 | 1418 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms); |
a4809f58 | 1419 | s_perfLongRunningQueries++; |
8a7cd6bb | 1420 | } |
22aaa779 VK |
1421 | |
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) | |
1425 | { | |
1426 | DBReconnect(hConn); | |
1427 | } | |
8a7cd6bb VK |
1428 | |
1429 | MutexUnlock(hConn->m_mutexTransLock); | |
1430 | ||
1431 | #ifndef UNICODE | |
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; | |
1434 | #endif | |
1435 | ||
1436 | if (dwResult != DBERR_SUCCESS) | |
1437 | { | |
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) | |
1441 | { | |
1442 | #ifdef UNICODE | |
526ae8b8 | 1443 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, hStmt->m_query, wcErrorText, dwResult == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
1444 | #else |
1445 | WCHAR *query = WideStringFromMBString(hStmt->m_query); | |
526ae8b8 | 1446 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, query, wcErrorText, dwResult == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
1447 | free(query); |
1448 | #endif | |
1449 | } | |
a4809f58 | 1450 | s_perfFailedQueries++; |
8a7cd6bb VK |
1451 | } |
1452 | ||
1453 | return dwResult == DBERR_SUCCESS; | |
1454 | #undef wcErrorText | |
1455 | } | |
1456 | ||
74d4ba34 VK |
1457 | /** |
1458 | * Execute prepared statement (non-SELECT) | |
1459 | */ | |
750d59f2 | 1460 | bool LIBNXDB_EXPORTABLE DBExecute(DB_STATEMENT hStmt) |
8a7cd6bb VK |
1461 | { |
1462 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
1463 | return DBExecuteEx(hStmt, errorText); | |
1464 | } | |
1465 | ||
480e036b VK |
1466 | /** |
1467 | * Execute prepared SELECT statement | |
1468 | */ | |
8a7cd6bb VK |
1469 | DB_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedEx(DB_STATEMENT hStmt, TCHAR *errorText) |
1470 | { | |
74d4ba34 VK |
1471 | if (!IS_VALID_STATEMENT_HANDLE(hStmt)) |
1472 | { | |
1473 | _tcscpy(errorText, _T("Invalid statement handle")); | |
1474 | return NULL; | |
1475 | } | |
1476 | ||
8a7cd6bb | 1477 | DB_RESULT result = NULL; |
8a7cd6bb VK |
1478 | #ifdef UNICODE |
1479 | #define wcErrorText errorText | |
1480 | #else | |
1481 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
1482 | #endif | |
1483 | ||
1484 | DB_HANDLE hConn = hStmt->m_connection; | |
c17f6cbc | 1485 | MutexLock(hConn->m_mutexTransLock); |
74d4ba34 | 1486 | |
a4809f58 VK |
1487 | s_perfSelectQueries++; |
1488 | s_perfTotalQueries++; | |
1489 | ||
58f1f627 | 1490 | INT64 ms = GetCurrentTimeMs(); |
6e3f4556 | 1491 | DWORD dwError = DBERR_OTHER_ERROR; |
74d4ba34 | 1492 | DBDRV_RESULT hResult = hConn->m_driver->m_fpDrvSelectPrepared(hConn->m_connection, hStmt->m_statement, &dwError, wcErrorText); |
8a7cd6bb | 1493 | |
58f1f627 | 1494 | ms = GetCurrentTimeMs() - ms; |
8a7cd6bb VK |
1495 | if (hConn->m_driver->m_dumpSql) |
1496 | { | |
2df047f4 | 1497 | nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), |
58f1f627 VK |
1498 | (hResult != NULL) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms); |
1499 | } | |
1500 | if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) | |
1501 | { | |
2df047f4 | 1502 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms); |
a4809f58 | 1503 | s_perfLongRunningQueries++; |
8a7cd6bb | 1504 | } |
22aaa779 VK |
1505 | |
1506 | // Do reconnect if needed, but don't retry statement execution | |
1507 | // because it will fail anyway | |
6e3f4556 | 1508 | if ((hResult == NULL) && (dwError == DBERR_CONNECTION_LOST) && hConn->m_reconnectEnabled) |
22aaa779 VK |
1509 | { |
1510 | DBReconnect(hConn); | |
1511 | } | |
1512 | ||
8a7cd6bb VK |
1513 | MutexUnlock(hConn->m_mutexTransLock); |
1514 | ||
1515 | #ifndef UNICODE | |
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; | |
1518 | #endif | |
1519 | ||
1520 | if (hResult == NULL) | |
1521 | { | |
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) | |
1525 | { | |
1526 | #ifdef UNICODE | |
526ae8b8 | 1527 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, hStmt->m_query, wcErrorText, dwError == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
1528 | #else |
1529 | WCHAR *query = WideStringFromMBString(hStmt->m_query); | |
526ae8b8 | 1530 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, query, wcErrorText, dwError == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); |
8a7cd6bb VK |
1531 | free(query); |
1532 | #endif | |
1533 | } | |
a4809f58 | 1534 | s_perfFailedQueries++; |
8a7cd6bb VK |
1535 | } |
1536 | ||
1537 | if (hResult != NULL) | |
1538 | { | |
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; | |
1543 | } | |
1544 | ||
1545 | return result; | |
1546 | #undef wcErrorText | |
1547 | } | |
1548 | ||
480e036b VK |
1549 | /** |
1550 | * Execute prepared SELECT statement | |
1551 | */ | |
8a7cd6bb VK |
1552 | DB_RESULT LIBNXDB_EXPORTABLE DBSelectPrepared(DB_STATEMENT hStmt) |
1553 | { | |
1554 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
1555 | return DBSelectPreparedEx(hStmt, errorText); | |
1556 | } | |
1557 | ||
f17cf019 VK |
1558 | /** |
1559 | * Execute prepared SELECT statement without caching results | |
1560 | */ | |
1561 | DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedUnbufferedEx(DB_STATEMENT hStmt, TCHAR *errorText) | |
1562 | { | |
1563 | if (!IS_VALID_STATEMENT_HANDLE(hStmt)) | |
1564 | { | |
1565 | _tcscpy(errorText, _T("Invalid statement handle")); | |
1566 | return NULL; | |
1567 | } | |
1568 | ||
1569 | DB_UNBUFFERED_RESULT result = NULL; | |
1570 | #ifdef UNICODE | |
1571 | #define wcErrorText errorText | |
1572 | #else | |
1573 | WCHAR wcErrorText[DBDRV_MAX_ERROR_TEXT] = L""; | |
1574 | #endif | |
1575 | ||
1576 | DB_HANDLE hConn = hStmt->m_connection; | |
1577 | MutexLock(hConn->m_mutexTransLock); | |
1578 | ||
1579 | s_perfSelectQueries++; | |
1580 | s_perfTotalQueries++; | |
1581 | ||
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); | |
1585 | ||
1586 | ms = GetCurrentTimeMs() - ms; | |
1587 | if (hConn->m_driver->m_dumpSql) | |
1588 | { | |
2df047f4 | 1589 | nxlog_debug(9, _T("%s prepared sync query: \"%s\" [%d ms]"), |
f17cf019 VK |
1590 | (hResult != NULL) ? _T("Successful") : _T("Failed"), hStmt->m_query, (int)ms); |
1591 | } | |
1592 | if ((hResult != NULL) && ((UINT32)ms > g_sqlQueryExecTimeThreshold)) | |
1593 | { | |
2df047f4 | 1594 | nxlog_debug(3, _T("Long running query: \"%s\" [%d ms]"), hStmt->m_query, (int)ms); |
f17cf019 VK |
1595 | s_perfLongRunningQueries++; |
1596 | } | |
1597 | ||
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) | |
1601 | { | |
1602 | DBReconnect(hConn); | |
1603 | } | |
1604 | ||
1605 | #ifndef UNICODE | |
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; | |
1608 | #endif | |
1609 | ||
1610 | if (hResult == NULL) | |
1611 | { | |
1612 | MutexUnlock(hConn->m_mutexTransLock); | |
1613 | ||
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) | |
1617 | { | |
1618 | #ifdef UNICODE | |
1619 | hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, hStmt->m_query, wcErrorText, dwError == DBERR_CONNECTION_LOST, hConn->m_driver->m_userArg); | |
1620 | #else | |
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); | |
1623 | free(query); | |
1624 | #endif | |
1625 | } | |
1626 | s_perfFailedQueries++; | |
1627 | } | |
1628 | ||
1629 | if (hResult != NULL) | |
1630 | { | |
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; | |
1635 | } | |
1636 | ||
1637 | return result; | |
1638 | #undef wcErrorText | |
1639 | } | |
1640 | ||
1641 | /** | |
1642 | * Execute prepared SELECT statement | |
1643 | */ | |
1644 | DB_UNBUFFERED_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedUnbuffered(DB_STATEMENT hStmt) | |
1645 | { | |
1646 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; | |
1647 | return DBSelectPreparedUnbufferedEx(hStmt, errorText); | |
1648 | } | |
1649 | ||
480e036b VK |
1650 | /** |
1651 | * Begin transaction | |
1652 | */ | |
750d59f2 | 1653 | bool LIBNXDB_EXPORTABLE DBBegin(DB_HANDLE hConn) |
8a7cd6bb VK |
1654 | { |
1655 | DWORD dwResult; | |
750d59f2 | 1656 | bool bRet = false; |
8a7cd6bb | 1657 | |
c17f6cbc | 1658 | MutexLock(hConn->m_mutexTransLock); |
8a7cd6bb VK |
1659 | if (hConn->m_transactionLevel == 0) |
1660 | { | |
1661 | dwResult = hConn->m_driver->m_fpDrvBegin(hConn->m_connection); | |
533ce8c0 | 1662 | if ((dwResult == DBERR_CONNECTION_LOST) && hConn->m_reconnectEnabled) |
8a7cd6bb VK |
1663 | { |
1664 | DBReconnect(hConn); | |
1665 | dwResult = hConn->m_driver->m_fpDrvBegin(hConn->m_connection); | |
1666 | } | |
1667 | if (dwResult == DBERR_SUCCESS) | |
1668 | { | |
1669 | hConn->m_transactionLevel++; | |
750d59f2 | 1670 | bRet = true; |
2df047f4 | 1671 | nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel); |
8a7cd6bb VK |
1672 | } |
1673 | else | |
1674 | { | |
1675 | MutexUnlock(hConn->m_mutexTransLock); | |
2df047f4 | 1676 | nxlog_debug(9, _T("BEGIN TRANSACTION failed"), hConn->m_transactionLevel); |
8a7cd6bb VK |
1677 | } |
1678 | } | |
1679 | else | |
1680 | { | |
1681 | hConn->m_transactionLevel++; | |
750d59f2 | 1682 | bRet = true; |
2df047f4 | 1683 | nxlog_debug(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel); |
8a7cd6bb VK |
1684 | } |
1685 | return bRet; | |
1686 | } | |
1687 | ||
480e036b VK |
1688 | /** |
1689 | * Commit transaction | |
1690 | */ | |
750d59f2 | 1691 | bool LIBNXDB_EXPORTABLE DBCommit(DB_HANDLE hConn) |
8a7cd6bb | 1692 | { |
750d59f2 | 1693 | bool bRet = false; |
8a7cd6bb | 1694 | |
c17f6cbc | 1695 | MutexLock(hConn->m_mutexTransLock); |
8a7cd6bb VK |
1696 | if (hConn->m_transactionLevel > 0) |
1697 | { | |
1698 | hConn->m_transactionLevel--; | |
1699 | if (hConn->m_transactionLevel == 0) | |
1700 | bRet = (hConn->m_driver->m_fpDrvCommit(hConn->m_connection) == DBERR_SUCCESS); | |
1701 | else | |
750d59f2 | 1702 | bRet = true; |
2df047f4 | 1703 | nxlog_debug(9, _T("COMMIT TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel); |
8a7cd6bb VK |
1704 | MutexUnlock(hConn->m_mutexTransLock); |
1705 | } | |
1706 | MutexUnlock(hConn->m_mutexTransLock); | |
1707 | return bRet; | |
1708 | } | |
1709 | ||
480e036b VK |
1710 | /** |
1711 | * Rollback transaction | |
1712 | */ | |
750d59f2 | 1713 | bool LIBNXDB_EXPORTABLE DBRollback(DB_HANDLE hConn) |
8a7cd6bb | 1714 | { |
750d59f2 | 1715 | bool bRet = false; |
8a7cd6bb | 1716 | |
c17f6cbc | 1717 | MutexLock(hConn->m_mutexTransLock); |
8a7cd6bb VK |
1718 | if (hConn->m_transactionLevel > 0) |
1719 | { | |
1720 | hConn->m_transactionLevel--; | |
1721 | if (hConn->m_transactionLevel == 0) | |
1722 | bRet = (hConn->m_driver->m_fpDrvRollback(hConn->m_connection) == DBERR_SUCCESS); | |
1723 | else | |
750d59f2 | 1724 | bRet = true; |
2df047f4 | 1725 | nxlog_debug(9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel); |
8a7cd6bb VK |
1726 | MutexUnlock(hConn->m_mutexTransLock); |
1727 | } | |
1728 | MutexUnlock(hConn->m_mutexTransLock); | |
1729 | return bRet; | |
1730 | } | |
1731 | ||
480e036b VK |
1732 | /** |
1733 | * Prepare string for using in SQL statement | |
1734 | */ | |
8a7cd6bb | 1735 | String LIBNXDB_EXPORTABLE DBPrepareString(DB_HANDLE conn, const TCHAR *str, int maxSize) |
9bd1bace VK |
1736 | { |
1737 | return DBPrepareString(conn->m_driver, str, maxSize); | |
1738 | } | |
1739 | ||
1740 | /** | |
1741 | * Prepare string for using in SQL statement | |
1742 | */ | |
1743 | String LIBNXDB_EXPORTABLE DBPrepareString(DB_DRIVER drv, const TCHAR *str, int maxSize) | |
8a7cd6bb VK |
1744 | { |
1745 | String out; | |
1746 | if ((maxSize > 0) && (str != NULL) && (maxSize < (int)_tcslen(str))) | |
1747 | { | |
1748 | TCHAR *temp = (TCHAR *)malloc((maxSize + 1) * sizeof(TCHAR)); | |
1749 | nx_strncpy(temp, str, maxSize + 1); | |
1750 | #ifdef UNICODE | |
9bd1bace | 1751 | out.setBuffer(drv->m_fpDrvPrepareStringW(temp)); |
8a7cd6bb | 1752 | #else |
9bd1bace | 1753 | out.setBuffer(drv->m_fpDrvPrepareStringA(temp)); |
8a7cd6bb VK |
1754 | #endif |
1755 | free(temp); | |
1756 | } | |
1757 | else | |
1758 | { | |
1759 | #ifdef UNICODE | |
9bd1bace | 1760 | out.setBuffer(drv->m_fpDrvPrepareStringW(CHECK_NULL_EX(str))); |
8a7cd6bb | 1761 | #else |
9bd1bace | 1762 | out.setBuffer(drv->m_fpDrvPrepareStringA(CHECK_NULL_EX(str))); |
8a7cd6bb VK |
1763 | #endif |
1764 | } | |
1765 | return out; | |
1766 | } | |
1767 | ||
480e036b VK |
1768 | /** |
1769 | * Prepare string for using in SQL statement (multi-byte string version) | |
1770 | */ | |
8a7cd6bb VK |
1771 | #ifdef UNICODE |
1772 | ||
1773 | String LIBNXDB_EXPORTABLE DBPrepareStringA(DB_HANDLE conn, const char *str, int maxSize) | |
1774 | { | |
1775 | WCHAR *wcs = WideStringFromMBString(str); | |
1776 | String s = DBPrepareString(conn, wcs, maxSize); | |
1777 | free(wcs); | |
1778 | return s; | |
1779 | } | |
1780 | ||
9bd1bace VK |
1781 | String LIBNXDB_EXPORTABLE DBPrepareStringA(DB_DRIVER drv, const char *str, int maxSize) |
1782 | { | |
1783 | WCHAR *wcs = WideStringFromMBString(str); | |
1784 | String s = DBPrepareString(drv, wcs, maxSize); | |
1785 | free(wcs); | |
1786 | return s; | |
1787 | } | |
1788 | ||
8a7cd6bb VK |
1789 | #endif |
1790 | ||
daf3c104 VK |
1791 | /** |
1792 | * Check if given table exist | |
1793 | */ | |
1794 | int LIBNXDB_EXPORTABLE DBIsTableExist(DB_HANDLE conn, const TCHAR *table) | |
1795 | { | |
1796 | #ifdef UNICODE | |
1797 | return conn->m_driver->m_fpDrvIsTableExist(conn->m_connection, table); | |
1798 | #else | |
1799 | WCHAR wname[256]; | |
1800 | MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, table, -1, wname, 256); | |
1801 | return conn->m_driver->m_fpDrvIsTableExist(conn->m_connection, wname); | |
1802 | #endif | |
1803 | } | |
a4809f58 VK |
1804 | |
1805 | /** | |
1806 | * Get performance counters | |
1807 | */ | |
1808 | void LIBNXDB_EXPORTABLE DBGetPerfCounters(LIBNXDB_PERF_COUNTERS *counters) | |
1809 | { | |
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; | |
1815 | } |