license for libnxdb and libnxsrv changed to LGPL
[public/netxms.git] / src / db / libnxdb / session.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Database Abstraction Library
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
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
26
27 //
28 // Connect to database
29 //
30
31 DB_HANDLE LIBNXDB_EXPORTABLE DBConnect(DB_DRIVER driver, const TCHAR *pszServer, const TCHAR *pszDBName,
32 const TCHAR *pszLogin, const TCHAR *pszPassword)
33 {
34 DBDRV_CONNECTION hDrvConn;
35 DB_HANDLE hConn = NULL;
36
37 __DBDbgPrintf(8, _T("DBConnect: server=%s db=%s login=%s"), pszServer, pszDBName, pszLogin);
38 hDrvConn = driver->m_fpDrvConnect(pszServer, pszLogin, pszPassword, pszDBName);
39 if (hDrvConn != NULL)
40 {
41 hConn = (DB_HANDLE)malloc(sizeof(struct db_handle_t));
42 if (hConn != NULL)
43 {
44 hConn->m_driver = driver;
45 hConn->m_dumpSql = driver->m_dumpSql;
46 hConn->m_connection = hDrvConn;
47 hConn->m_mutexTransLock = MutexCreateRecursive();
48 hConn->m_transactionLevel = 0;
49 hConn->m_dbName = (pszDBName == NULL) ? NULL : _tcsdup(pszDBName);
50 hConn->m_login = (pszLogin == NULL) ? NULL : _tcsdup(pszLogin);
51 hConn->m_password = (pszPassword == NULL) ? NULL : _tcsdup(pszPassword);
52 hConn->m_server = (pszServer == NULL) ? NULL : _tcsdup(pszServer);
53 __DBDbgPrintf(4, _T("New DB connection opened: handle=%p"), hConn);
54 }
55 else
56 {
57 driver->m_fpDrvDisconnect(hDrvConn);
58 }
59 }
60 return hConn;
61 }
62
63
64 //
65 // Disconnect from database
66 //
67
68 void LIBNXDB_EXPORTABLE DBDisconnect(DB_HANDLE hConn)
69 {
70 if (hConn == NULL)
71 return;
72
73 __DBDbgPrintf(4, _T("DB connection %p closed"), hConn);
74
75 hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection);
76 MutexDestroy(hConn->m_mutexTransLock);
77 safe_free(hConn->m_dbName);
78 safe_free(hConn->m_login);
79 safe_free(hConn->m_password);
80 safe_free(hConn->m_server);
81 free(hConn);
82 }
83
84
85 //
86 // Reconnect to database
87 //
88
89 static void DBReconnect(DB_HANDLE hConn)
90 {
91 int nCount;
92
93 hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection);
94 for(nCount = 0; ; nCount++)
95 {
96 hConn->m_connection = hConn->m_driver->m_fpDrvConnect(hConn->m_server, hConn->m_login,
97 hConn->m_password, hConn->m_dbName);
98 if (hConn->m_connection != NULL)
99 break;
100 if (nCount == 0)
101 {
102 MutexLock(hConn->m_driver->m_mutexReconnect, INFINITE);
103 if ((hConn->m_driver->m_reconnect == 0) && (hConn->m_driver->m_fpEventHandler != NULL))
104 hConn->m_driver->m_fpEventHandler(DBEVENT_CONNECTION_LOST, NULL, NULL, hConn->m_driver->m_userArg);
105 hConn->m_driver->m_reconnect++;
106 MutexUnlock(hConn->m_driver->m_mutexReconnect);
107 }
108 ThreadSleepMs(1000);
109 }
110 if (nCount > 0)
111 {
112 MutexLock(hConn->m_driver->m_mutexReconnect, INFINITE);
113 hConn->m_driver->m_reconnect--;
114 if ((hConn->m_driver->m_reconnect == 0) && (hConn->m_driver->m_fpEventHandler != NULL))
115 hConn->m_driver->m_fpEventHandler(DBEVENT_CONNECTION_RESTORED, NULL, NULL, hConn->m_driver->m_userArg);
116 MutexUnlock(hConn->m_driver->m_mutexReconnect);
117 }
118 }
119
120
121 //
122 // Perform a non-SELECT SQL query
123 //
124
125 BOOL LIBNXDB_EXPORTABLE DBQueryEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText)
126 {
127 DWORD dwResult;
128 INT64 ms;
129 #ifdef UNICODE
130 #define pwszQuery szQuery
131 #else
132 WCHAR *pwszQuery = WideStringFromMBString(szQuery);
133 #endif
134
135 MutexLock(hConn->m_mutexTransLock, INFINITE);
136 if (hConn->m_driver->m_dumpSql)
137 ms = GetCurrentTimeMs();
138
139 dwResult = hConn->m_driver->m_fpDrvQuery(hConn->m_connection, pwszQuery, errorText);
140 if (dwResult == DBERR_CONNECTION_LOST)
141 {
142 DBReconnect(hConn);
143 dwResult = hConn->m_driver->m_fpDrvQuery(hConn->m_connection, pwszQuery, errorText);
144 }
145
146 #ifndef UNICODE
147 free(pwszQuery);
148 #endif
149
150 if (hConn->m_driver->m_dumpSql)
151 {
152 ms = GetCurrentTimeMs() - ms;
153 __DBDbgPrintf(9, _T("%s sync query: \"%s\" [%d ms]"), (dwResult == DBERR_SUCCESS) ? _T("Successful") : _T("Failed"), szQuery, ms);
154 }
155
156 MutexUnlock(hConn->m_mutexTransLock);
157 if (dwResult != DBERR_SUCCESS)
158 {
159 if (hConn->m_driver->m_logSqlErrors)
160 nxlog_write(g_sqlErrorMsgCode, EVENTLOG_ERROR_TYPE, "ss", szQuery, errorText);
161 if (hConn->m_driver->m_fpEventHandler != NULL)
162 hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, szQuery, errorText, hConn->m_driver->m_userArg);
163 }
164 return dwResult == DBERR_SUCCESS;
165 #undef pwszQuery
166 }
167
168 BOOL LIBNXDB_EXPORTABLE DBQuery(DB_HANDLE hConn, const TCHAR *query)
169 {
170 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
171
172 return DBQueryEx(hConn, query, errorText);
173 }
174
175
176 //
177 // Perform SELECT query
178 //
179
180 DB_RESULT LIBNXDB_EXPORTABLE DBSelectEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText)
181 {
182 DBDRV_RESULT hResult;
183 DB_RESULT result = NULL;
184 DWORD dwError;
185 INT64 ms;
186 #ifdef UNICODE
187 #define pwszQuery szQuery
188 #else
189 WCHAR *pwszQuery = WideStringFromMBString(szQuery);
190 #endif
191
192 MutexLock(hConn->m_mutexTransLock, INFINITE);
193 if (hConn->m_driver->m_dumpSql)
194 ms = GetCurrentTimeMs();
195 hResult = hConn->m_driver->m_fpDrvSelect(hConn->m_connection, pwszQuery, &dwError, errorText);
196 if ((hResult == NULL) && (dwError == DBERR_CONNECTION_LOST))
197 {
198 DBReconnect(hConn);
199 hResult = hConn->m_driver->m_fpDrvSelect(hConn->m_connection, pwszQuery, &dwError, errorText);
200 }
201
202 #ifndef UNICODE
203 free(pwszQuery);
204 #endif
205
206 if (hConn->m_driver->m_dumpSql)
207 {
208 ms = GetCurrentTimeMs() - ms;
209 __DBDbgPrintf(9, _T("%s sync query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (DWORD)ms);
210 }
211 MutexUnlock(hConn->m_mutexTransLock);
212 if (hResult == NULL)
213 {
214 if (hConn->m_driver->m_logSqlErrors)
215 nxlog_write(g_sqlErrorMsgCode, EVENTLOG_ERROR_TYPE, "ss", szQuery, errorText);
216 if (hConn->m_driver->m_fpEventHandler != NULL)
217 hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, szQuery, errorText, hConn->m_driver->m_userArg);
218 }
219
220 if (hResult != NULL)
221 {
222 result = (DB_RESULT)malloc(sizeof(db_result_t));
223 result->m_driver = hConn->m_driver;
224 result->m_connection = hConn;
225 result->m_data = hResult;
226 }
227
228 return result;
229 }
230
231 DB_RESULT LIBNXDB_EXPORTABLE DBSelect(DB_HANDLE hConn, const TCHAR *query)
232 {
233 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
234
235 return DBSelectEx(hConn, query, errorText);
236 }
237
238
239 //
240 // Get number of columns
241 //
242
243 int LIBNXDB_EXPORTABLE DBGetColumnCount(DB_RESULT hResult)
244 {
245 return hResult->m_driver->m_fpDrvGetColumnCount(hResult->m_data);
246 }
247
248
249 //
250 // Get column name
251 //
252
253 BOOL LIBNXDB_EXPORTABLE DBGetColumnName(DB_RESULT hResult, int column, TCHAR *buffer, int bufSize)
254 {
255 const char *name;
256
257 name = hResult->m_driver->m_fpDrvGetColumnName(hResult->m_data, column);
258 if (name != NULL)
259 {
260 #ifdef UNICODE
261 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, buffer, bufSize);
262 buffer[bufSize - 1] = 0;
263 #else
264 nx_strncpy(buffer, name, bufSize);
265 #endif
266 }
267 return name != NULL;
268 }
269
270
271 //
272 // Get column count for async request
273 //
274
275 int LIBNXDB_EXPORTABLE DBGetColumnCountAsync(DB_ASYNC_RESULT hResult)
276 {
277 return hResult->m_driver->m_fpDrvGetColumnCountAsync(hResult->m_data);
278 }
279
280
281 //
282 // Get column name for async request
283 //
284
285 BOOL LIBNXDB_EXPORTABLE DBGetColumnNameAsync(DB_ASYNC_RESULT hResult, int column, TCHAR *buffer, int bufSize)
286 {
287 const char *name;
288
289 name = hResult->m_driver->m_fpDrvGetColumnNameAsync(hResult->m_data, column);
290 if (name != NULL)
291 {
292 #ifdef UNICODE
293 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, buffer, bufSize);
294 buffer[bufSize - 1] = 0;
295 #else
296 nx_strncpy(buffer, name, bufSize);
297 #endif
298 }
299 return name != NULL;
300 }
301
302
303 //
304 // Get field's value
305 //
306
307 TCHAR LIBNXDB_EXPORTABLE *DBGetField(DB_RESULT hResult, int iRow, int iColumn,
308 TCHAR *pszBuffer, int nBufLen)
309 {
310 #ifdef UNICODE
311 if (pszBuffer != NULL)
312 {
313 return hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pszBuffer, nBufLen);
314 }
315 else
316 {
317 LONG nLen;
318 WCHAR *pszTemp;
319
320 nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn);
321 if (nLen == -1)
322 {
323 pszTemp = NULL;
324 }
325 else
326 {
327 nLen++;
328 pszBuffer = (WCHAR *)malloc(nLen * sizeof(WCHAR));
329 hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pszTemp, nLen);
330 }
331 return pszTemp;
332 }
333 #else
334 WCHAR *pwszData, *pwszBuffer;
335 char *pszRet;
336 int nLen;
337
338 if (pszBuffer != NULL)
339 {
340 pwszBuffer = (WCHAR *)malloc(nBufLen * sizeof(WCHAR));
341 pwszData = hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pwszBuffer, nBufLen);
342 if (pwszData != NULL)
343 {
344 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
345 pwszData, -1, pszBuffer, nBufLen, NULL, NULL);
346 pszRet = pszBuffer;
347 }
348 else
349 {
350 pszRet = NULL;
351 }
352 free(pwszBuffer);
353 }
354 else
355 {
356 nLen = hResult->m_driver->m_fpDrvGetFieldLength(hResult->m_data, iRow, iColumn);
357 if (nLen == -1)
358 {
359 pszRet = NULL;
360 }
361 else
362 {
363 nLen++;
364 pwszBuffer = (WCHAR *)malloc(nLen * sizeof(WCHAR));
365 pwszData = hResult->m_driver->m_fpDrvGetField(hResult->m_data, iRow, iColumn, pwszBuffer, nLen);
366 if (pwszData != NULL)
367 {
368 nLen = (int)wcslen(pwszData) + 1;
369 pszRet = (char *)malloc(nLen);
370 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
371 pwszData, -1, pszRet, nLen, NULL, NULL);
372 }
373 else
374 {
375 pszRet = NULL;
376 }
377 free(pwszBuffer);
378 }
379 }
380 return pszRet;
381 #endif
382 }
383
384
385 //
386 // Get field's value as unsigned long
387 //
388
389 DWORD LIBNXDB_EXPORTABLE DBGetFieldULong(DB_RESULT hResult, int iRow, int iColumn)
390 {
391 LONG iVal;
392 DWORD dwVal;
393 TCHAR *pszVal, szBuffer[256];
394
395 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
396 if (pszVal == NULL)
397 return 0;
398 iVal = _tcstol(pszVal, NULL, 10);
399 memcpy(&dwVal, &iVal, sizeof(LONG)); // To prevent possible conversion
400 return dwVal;
401 }
402
403
404 //
405 // Get field's value as unsigned 64-bit int
406 //
407
408 QWORD LIBNXDB_EXPORTABLE DBGetFieldUInt64(DB_RESULT hResult, int iRow, int iColumn)
409 {
410 INT64 iVal;
411 QWORD qwVal;
412 TCHAR *pszVal, szBuffer[256];
413
414 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
415 if (pszVal == NULL)
416 return 0;
417 iVal = _tcstoll(pszVal, NULL, 10);
418 memcpy(&qwVal, &iVal, sizeof(INT64)); // To prevent possible conversion
419 return qwVal;
420 }
421
422
423 //
424 // Get field's value as signed long
425 //
426
427 LONG LIBNXDB_EXPORTABLE DBGetFieldLong(DB_RESULT hResult, int iRow, int iColumn)
428 {
429 TCHAR *pszVal, szBuffer[256];
430
431 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
432 return pszVal == NULL ? 0 : _tcstol(pszVal, NULL, 10);
433 }
434
435
436 //
437 // Get field's value as signed 64-bit int
438 //
439
440 INT64 LIBNXDB_EXPORTABLE DBGetFieldInt64(DB_RESULT hResult, int iRow, int iColumn)
441 {
442 TCHAR *pszVal, szBuffer[256];
443
444 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
445 return pszVal == NULL ? 0 : _tcstoll(pszVal, NULL, 10);
446 }
447
448
449 //
450 // Get field's value as double
451 //
452
453 double LIBNXDB_EXPORTABLE DBGetFieldDouble(DB_RESULT hResult, int iRow, int iColumn)
454 {
455 TCHAR *pszVal, szBuffer[256];
456
457 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
458 return pszVal == NULL ? 0 : _tcstod(pszVal, NULL);
459 }
460
461
462 //
463 // Get field's value as IP address
464 //
465
466 DWORD LIBNXDB_EXPORTABLE DBGetFieldIPAddr(DB_RESULT hResult, int iRow, int iColumn)
467 {
468 TCHAR *pszVal, szBuffer[256];
469
470 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
471 return pszVal == NULL ? INADDR_NONE : ntohl(_t_inet_addr(pszVal));
472 }
473
474
475 //
476 // Get field's value as integer array from byte array encoded in hex
477 //
478
479 BOOL LIBNXDB_EXPORTABLE DBGetFieldByteArray(DB_RESULT hResult, int iRow, int iColumn,
480 int *pnArray, int nSize, int nDefault)
481 {
482 char pbBytes[128];
483 BOOL bResult;
484 int i, nLen;
485 TCHAR *pszVal, szBuffer[256];
486
487 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
488 if (pszVal != NULL)
489 {
490 StrToBin(pszVal, (BYTE *)pbBytes, 128);
491 nLen = (int)strlen(pszVal) / 2;
492 for(i = 0; (i < nSize) && (i < nLen); i++)
493 pnArray[i] = pbBytes[i];
494 for(; i < nSize; i++)
495 pnArray[i] = nDefault;
496 bResult = TRUE;
497 }
498 else
499 {
500 for(i = 0; i < nSize; i++)
501 pnArray[i] = nDefault;
502 bResult = FALSE;
503 }
504 return bResult;
505 }
506
507
508 //
509 // Get field's value as GUID
510 //
511
512 BOOL LIBNXDB_EXPORTABLE DBGetFieldGUID(DB_RESULT hResult, int iRow,
513 int iColumn, uuid_t guid)
514 {
515 TCHAR *pszVal, szBuffer[256];
516 BOOL bResult;
517
518 pszVal = DBGetField(hResult, iRow, iColumn, szBuffer, 256);
519 if (pszVal != NULL)
520 {
521 if (uuid_parse(pszVal, guid) == 0)
522 {
523 bResult = TRUE;
524 }
525 else
526 {
527 uuid_clear(guid);
528 bResult = FALSE;
529 }
530 }
531 else
532 {
533 uuid_clear(guid);
534 bResult = FALSE;
535 }
536 return bResult;
537 }
538
539
540 //
541 // Get number of rows in result
542 //
543
544 int LIBNXDB_EXPORTABLE DBGetNumRows(DB_RESULT hResult)
545 {
546 if (hResult == NULL)
547 return 0;
548 return hResult->m_driver->m_fpDrvGetNumRows(hResult->m_data);
549 }
550
551
552 //
553 // Free result
554 //
555
556 void LIBNXDB_EXPORTABLE DBFreeResult(DB_RESULT hResult)
557 {
558 if (hResult != NULL)
559 {
560 hResult->m_driver->m_fpDrvFreeResult(hResult->m_data);
561 free(hResult);
562 }
563 }
564
565
566 //
567 // Asyncronous SELECT query
568 //
569
570 DB_ASYNC_RESULT LIBNXDB_EXPORTABLE DBAsyncSelectEx(DB_HANDLE hConn, const TCHAR *szQuery, TCHAR *errorText)
571 {
572 DBDRV_ASYNC_RESULT hResult;
573 DB_ASYNC_RESULT result = NULL;
574 DWORD dwError;
575 INT64 ms;
576 #ifdef UNICODE
577 #define pwszQuery szQuery
578 #else
579 WCHAR *pwszQuery = WideStringFromMBString(szQuery);
580 #endif
581
582 MutexLock(hConn->m_mutexTransLock, INFINITE);
583 if (hConn->m_driver->m_dumpSql)
584 ms = GetCurrentTimeMs();
585 hResult = hConn->m_driver->m_fpDrvAsyncSelect(hConn->m_connection, pwszQuery, &dwError, errorText);
586 if ((hResult == NULL) && (dwError == DBERR_CONNECTION_LOST))
587 {
588 DBReconnect(hConn);
589 hResult = hConn->m_driver->m_fpDrvAsyncSelect(hConn->m_connection, pwszQuery, &dwError, errorText);
590 }
591
592 #ifndef UNICODE
593 free(pwszQuery);
594 #endif
595
596 if (hConn->m_driver->m_dumpSql)
597 {
598 ms = GetCurrentTimeMs() - ms;
599 __DBDbgPrintf(9, _T("%s async query: \"%s\" [%d ms]"), (hResult != NULL) ? _T("Successful") : _T("Failed"), szQuery, (DWORD)ms);
600 }
601 if (hResult == NULL)
602 {
603 MutexUnlock(hConn->m_mutexTransLock);
604 if (hConn->m_driver->m_logSqlErrors)
605 nxlog_write(g_sqlErrorMsgCode, EVENTLOG_ERROR_TYPE, "ss", szQuery, errorText);
606 if (hConn->m_driver->m_fpEventHandler != NULL)
607 hConn->m_driver->m_fpEventHandler(DBEVENT_QUERY_FAILED, szQuery, errorText, hConn->m_driver->m_userArg);
608 }
609
610 if (hResult != NULL)
611 {
612 result = (DB_ASYNC_RESULT)malloc(sizeof(db_async_result_t));
613 result->m_driver = hConn->m_driver;
614 result->m_connection = hConn;
615 result->m_data = hResult;
616 }
617
618 return result;
619 }
620
621 DB_ASYNC_RESULT LIBNXDB_EXPORTABLE DBAsyncSelect(DB_HANDLE hConn, const TCHAR *query)
622 {
623 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
624
625 return DBAsyncSelectEx(hConn, query, errorText);
626 }
627
628
629 //
630 // Fetch next row from asynchronous SELECT result
631 //
632
633 BOOL LIBNXDB_EXPORTABLE DBFetch(DB_ASYNC_RESULT hResult)
634 {
635 return hResult->m_driver->m_fpDrvFetch(hResult->m_data);
636 }
637
638
639 //
640 // Get field's value from asynchronous SELECT result
641 //
642
643 TCHAR LIBNXDB_EXPORTABLE *DBGetFieldAsync(DB_ASYNC_RESULT hResult, int iColumn, TCHAR *pBuffer, int iBufSize)
644 {
645 #ifdef UNICODE
646 if (pBuffer != NULL)
647 {
648 return hResult->m_driver->m_fpDrvGetFieldAsync(hResult->m_data, iColumn, pBuffer, iBufSize);
649 }
650 else
651 {
652 LONG nLen;
653 WCHAR *pszTemp;
654
655 nLen = hResult->m_driver->m_fpDrvGetFieldLengthAsync(hResult->m_data, iColumn);
656 if (nLen == -1)
657 {
658 pszTemp = NULL;
659 }
660 else
661 {
662 nLen++;
663 pszBuffer = (WCHAR *)malloc(nLen * sizeof(WCHAR));
664 hResult->m_driver->m_fpDrvGetFieldAsync(hResult->m_data, iColumn, pszTemp, nLen);
665 }
666 return pszTemp;
667 }
668 #else
669 WCHAR *pwszData, *pwszBuffer;
670 char *pszRet;
671 int nLen;
672
673 if (pBuffer != NULL)
674 {
675 pwszBuffer = (WCHAR *)malloc(iBufSize * sizeof(WCHAR));
676 if (hResult->m_driver->m_fpDrvGetFieldAsync(hResult->m_data, iColumn, pwszBuffer, iBufSize) != NULL)
677 {
678 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
679 pwszBuffer, -1, pBuffer, iBufSize, NULL, NULL);
680 pszRet = pBuffer;
681 }
682 else
683 {
684 pszRet = NULL;
685 }
686 free(pwszBuffer);
687 }
688 else
689 {
690 nLen = hResult->m_driver->m_fpDrvGetFieldLengthAsync(hResult->m_data, iColumn);
691 if (nLen == -1)
692 {
693 pszRet = NULL;
694 }
695 else
696 {
697 nLen++;
698 pwszBuffer = (WCHAR *)malloc(nLen * sizeof(WCHAR));
699 pwszData = hResult->m_driver->m_fpDrvGetFieldAsync(hResult->m_data, iColumn, pwszBuffer, nLen);
700 if (pwszData != NULL)
701 {
702 nLen = (int)wcslen(pwszData) + 1;
703 pszRet = (char *)malloc(nLen);
704 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
705 pwszData, -1, pszRet, nLen, NULL, NULL);
706 }
707 else
708 {
709 pszRet = NULL;
710 }
711 free(pwszBuffer);
712 }
713 }
714 return pszRet;
715 #endif
716 }
717
718
719 //
720 // Get field's value as unsigned long from asynchronous SELECT result
721 //
722
723 DWORD LIBNXDB_EXPORTABLE DBGetFieldAsyncULong(DB_ASYNC_RESULT hResult, int iColumn)
724 {
725 LONG iVal;
726 DWORD dwVal;
727 TCHAR szBuffer[64];
728
729 if (DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL)
730 return 0;
731 iVal = _tcstol(szBuffer, NULL, 10);
732 memcpy(&dwVal, &iVal, sizeof(LONG)); // To prevent possible conversion
733 return dwVal;
734 }
735
736
737 //
738 // Get field's value as unsigned 64-bit int from asynchronous SELECT result
739 //
740
741 QWORD LIBNXDB_EXPORTABLE DBGetFieldAsyncUInt64(DB_ASYNC_RESULT hResult, int iColumn)
742 {
743 INT64 iVal;
744 QWORD qwVal;
745 TCHAR szBuffer[64];
746
747 if (DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL)
748 return 0;
749 iVal = _tcstoll(szBuffer, NULL, 10);
750 memcpy(&qwVal, &iVal, sizeof(INT64)); // To prevent possible conversion
751 return qwVal;
752 }
753
754
755 //
756 // Get field's value as signed long from asynchronous SELECT result
757 //
758
759 LONG LIBNXDB_EXPORTABLE DBGetFieldAsyncLong(DB_ASYNC_RESULT hResult, int iColumn)
760 {
761 TCHAR szBuffer[64];
762
763 return DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstol(szBuffer, NULL, 10);
764 }
765
766
767 //
768 // Get field's value as signed 64-bit int from asynchronous SELECT result
769 //
770
771 INT64 LIBNXDB_EXPORTABLE DBGetFieldAsyncInt64(DB_ASYNC_RESULT hResult, int iColumn)
772 {
773 TCHAR szBuffer[64];
774
775 return DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstoll(szBuffer, NULL, 10);
776 }
777
778
779 //
780 // Get field's value as signed long from asynchronous SELECT result
781 //
782
783 double LIBNXDB_EXPORTABLE DBGetFieldAsyncDouble(DB_ASYNC_RESULT hResult, int iColumn)
784 {
785 TCHAR szBuffer[64];
786
787 return DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL ? 0 : _tcstod(szBuffer, NULL);
788 }
789
790
791 //
792 // Get field's value as IP address from asynchronous SELECT result
793 //
794
795 DWORD LIBNXDB_EXPORTABLE DBGetFieldAsyncIPAddr(DB_ASYNC_RESULT hResult, int iColumn)
796 {
797 TCHAR szBuffer[64];
798
799 return DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL ? INADDR_NONE :
800 ntohl(inet_addr(szBuffer));
801 }
802
803
804 //
805 // Free asynchronous SELECT result
806 //
807
808 void LIBNXDB_EXPORTABLE DBFreeAsyncResult(DB_HANDLE hConn, DB_ASYNC_RESULT hResult)
809 {
810 hResult->m_driver->m_fpDrvFreeAsyncResult(hResult->m_data);
811 free(hResult);
812 MutexUnlock(hConn->m_mutexTransLock);
813 }
814
815
816 //
817 // Begin transaction
818 //
819
820 BOOL LIBNXDB_EXPORTABLE DBBegin(DB_HANDLE hConn)
821 {
822 DWORD dwResult;
823 BOOL bRet = FALSE;
824
825 MutexLock(hConn->m_mutexTransLock, INFINITE);
826 if (hConn->m_transactionLevel == 0)
827 {
828 dwResult = hConn->m_driver->m_fpDrvBegin(hConn->m_connection);
829 if (dwResult == DBERR_CONNECTION_LOST)
830 {
831 DBReconnect(hConn);
832 dwResult = hConn->m_driver->m_fpDrvBegin(hConn->m_connection);
833 }
834 if (dwResult == DBERR_SUCCESS)
835 {
836 hConn->m_transactionLevel++;
837 bRet = TRUE;
838 __DBDbgPrintf(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
839 }
840 else
841 {
842 MutexUnlock(hConn->m_mutexTransLock);
843 __DBDbgPrintf(9, _T("BEGIN TRANSACTION failed"), hConn->m_transactionLevel);
844 }
845 }
846 else
847 {
848 hConn->m_transactionLevel++;
849 bRet = TRUE;
850 __DBDbgPrintf(9, _T("BEGIN TRANSACTION successful (level %d)"), hConn->m_transactionLevel);
851 }
852 return bRet;
853 }
854
855
856 //
857 // Commit transaction
858 //
859
860 BOOL LIBNXDB_EXPORTABLE DBCommit(DB_HANDLE hConn)
861 {
862 BOOL bRet = FALSE;
863
864 MutexLock(hConn->m_mutexTransLock, INFINITE);
865 if (hConn->m_transactionLevel > 0)
866 {
867 hConn->m_transactionLevel--;
868 if (hConn->m_transactionLevel == 0)
869 bRet = (hConn->m_driver->m_fpDrvCommit(hConn->m_connection) == DBERR_SUCCESS);
870 else
871 bRet = TRUE;
872 __DBDbgPrintf(9, _T("COMMIT TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
873 MutexUnlock(hConn->m_mutexTransLock);
874 }
875 MutexUnlock(hConn->m_mutexTransLock);
876 return bRet;
877 }
878
879
880 //
881 // Begin transaction
882 //
883
884 BOOL LIBNXDB_EXPORTABLE DBRollback(DB_HANDLE hConn)
885 {
886 BOOL bRet = FALSE;
887
888 MutexLock(hConn->m_mutexTransLock, INFINITE);
889 if (hConn->m_transactionLevel > 0)
890 {
891 hConn->m_transactionLevel--;
892 if (hConn->m_transactionLevel == 0)
893 bRet = (hConn->m_driver->m_fpDrvRollback(hConn->m_connection) == DBERR_SUCCESS);
894 else
895 bRet = TRUE;
896 __DBDbgPrintf(9, _T("ROLLBACK TRANSACTION %s (level %d)"), bRet ? _T("successful") : _T("failed"), hConn->m_transactionLevel);
897 MutexUnlock(hConn->m_mutexTransLock);
898 }
899 MutexUnlock(hConn->m_mutexTransLock);
900 return bRet;
901 }
902
903
904 //
905 // Prepare string for using in SQL statement
906 //
907
908 String LIBNXDB_EXPORTABLE DBPrepareString(DB_HANDLE conn, const TCHAR *str, int maxSize)
909 {
910 String out;
911 if ((maxSize > 0) && (str != NULL) && (maxSize < (int)_tcslen(str)))
912 {
913 TCHAR *temp = (TCHAR *)malloc((maxSize + 1) * sizeof(TCHAR));
914 nx_strncpy(temp, str, maxSize + 1);
915 out.setBuffer(conn->m_driver->m_fpDrvPrepareString(temp));
916 free(temp);
917 }
918 else
919 {
920 out.setBuffer(conn->m_driver->m_fpDrvPrepareString(CHECK_NULL_EX(str)));
921 }
922 return out;
923 }
924
925
926 //
927 // Characters to be escaped before writing to SQL
928 //
929
930 static TCHAR m_szSpecialChars[] = _T("\x01\x02\x03\x04\x05\x06\x07\x08")
931 _T("\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10")
932 _T("\x11\x12\x13\x14\x15\x16\x17\x18")
933 _T("\x19\x1A\x1B\x1C\x1D\x1E\x1F")
934 _T("#%\"\\'\x7F");
935
936
937 //
938 // Escape some special characters in string for writing into database
939 //
940
941 TCHAR LIBNXDB_EXPORTABLE *EncodeSQLString(const TCHAR *pszIn)
942 {
943 char *pszOut;
944 int iPosIn, iPosOut, iStrSize;
945
946 if ((pszIn != NULL) && (*pszIn != 0))
947 {
948 // Allocate destination buffer
949 iStrSize = (int)_tcslen(pszIn) + 1;
950 for(iPosIn = 0; pszIn[iPosIn] != 0; iPosIn++)
951 if (_tcschr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
952 iStrSize += 2;
953 pszOut = (char *)malloc(iStrSize);
954
955 // Translate string
956 for(iPosIn = 0, iPosOut = 0; pszIn[iPosIn] != 0; iPosIn++)
957 if (strchr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
958 {
959 pszOut[iPosOut++] = _T('#');
960 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] >> 4);
961 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] & 0x0F);
962 }
963 else
964 {
965 pszOut[iPosOut++] = pszIn[iPosIn];
966 }
967 pszOut[iPosOut] = 0;
968 }
969 else
970 {
971 // Encode empty strings as #00
972 pszOut = (TCHAR *)malloc(4 * sizeof(TCHAR));
973 _tcscpy(pszOut, _T("#00"));
974 }
975 return pszOut;
976 }
977
978
979 //
980 // Restore characters encoded by EncodeSQLString()
981 // Characters are decoded "in place"
982 //
983
984 void LIBNXDB_EXPORTABLE DecodeSQLString(TCHAR *pszStr)
985 {
986 int iPosIn, iPosOut;
987
988 if (pszStr == NULL)
989 return;
990
991 for(iPosIn = 0, iPosOut = 0; pszStr[iPosIn] != 0; iPosIn++)
992 {
993 if (pszStr[iPosIn] == _T('#'))
994 {
995 iPosIn++;
996 pszStr[iPosOut] = hex2bin(pszStr[iPosIn]) << 4;
997 iPosIn++;
998 pszStr[iPosOut] |= hex2bin(pszStr[iPosIn]);
999 iPosOut++;
1000 }
1001 else
1002 {
1003 pszStr[iPosOut++] = pszStr[iPosIn];
1004 }
1005 }
1006 pszStr[iPosOut] = 0;
1007 }
1008
1009
1010 //
1011 // Get database schema version
1012 // Will return 0 for unknown and -1 in case of SQL errors
1013 //
1014
1015 int LIBNXDB_EXPORTABLE DBGetSchemaVersion(DB_HANDLE conn)
1016 {
1017 DB_RESULT hResult;
1018 int version = 0;
1019
1020 // Read schema version from 'metadata' table, where it should
1021 // be stored starting from schema version 87
1022 // We ignore SQL error in this case, because table 'metadata'
1023 // may not exist in old schema versions
1024 hResult = DBSelect(conn, _T("SELECT var_value FROM metadata WHERE var_name='SchemaVersion'"));
1025 if (hResult != NULL)
1026 {
1027 if (DBGetNumRows(hResult) > 0)
1028 version = DBGetFieldLong(hResult, 0, 0);
1029 DBFreeResult(hResult);
1030 }
1031
1032 // If database schema version is less than 87, version number
1033 // will be stored in 'config' table
1034 if (version == 0)
1035 {
1036 hResult = DBSelect(conn, _T("SELECT var_value FROM config WHERE var_name='DBFormatVersion'"));
1037 if (hResult != NULL)
1038 {
1039 if (DBGetNumRows(hResult) > 0)
1040 version = DBGetFieldLong(hResult, 0, 0);
1041 DBFreeResult(hResult);
1042 }
1043 else
1044 {
1045 version = -1;
1046 }
1047 }
1048
1049 return version;
1050 }
1051
1052
1053 //
1054 // Get database syntax
1055 //
1056
1057 int LIBNXDB_EXPORTABLE DBGetSyntax(DB_HANDLE conn)
1058 {
1059 DB_RESULT hResult;
1060 TCHAR syntaxId[256];
1061 BOOL read = FALSE;
1062 int syntax;
1063
1064 // Get database syntax
1065 hResult = DBSelect(conn, _T("SELECT var_value FROM metadata WHERE var_name='Syntax'"));
1066 if (hResult != NULL)
1067 {
1068 if (DBGetNumRows(hResult) > 0)
1069 {
1070 DBGetField(hResult, 0, 0, syntaxId, sizeof(syntaxId));
1071 read = TRUE;
1072 }
1073 else
1074 {
1075 _tcscpy(syntaxId, _T("UNKNOWN"));
1076 }
1077 DBFreeResult(hResult);
1078 }
1079
1080 // If database schema version is less than 87, syntax
1081 // will be stored in 'config' table, so try it
1082 if (!read)
1083 {
1084 hResult = DBSelect(conn, _T("SELECT var_value FROM config WHERE var_name='DBSyntax'"));
1085 if (hResult != NULL)
1086 {
1087 if (DBGetNumRows(hResult) > 0)
1088 {
1089 DBGetField(hResult, 0, 0, syntaxId, sizeof(syntaxId));
1090 read = TRUE;
1091 }
1092 else
1093 {
1094 _tcscpy(syntaxId, _T("UNKNOWN"));
1095 }
1096 DBFreeResult(hResult);
1097 }
1098 }
1099
1100 if (!_tcscmp(syntaxId, _T("MYSQL")))
1101 {
1102 syntax = DB_SYNTAX_MYSQL;
1103 }
1104 else if (!_tcscmp(syntaxId, _T("PGSQL")))
1105 {
1106 syntax = DB_SYNTAX_PGSQL;
1107 }
1108 else if (!_tcscmp(syntaxId, _T("MSSQL")))
1109 {
1110 syntax = DB_SYNTAX_MSSQL;
1111 }
1112 else if (!_tcscmp(syntaxId, _T("ORACLE")))
1113 {
1114 syntax = DB_SYNTAX_ORACLE;
1115 }
1116 else if (!_tcscmp(syntaxId, _T("SQLITE")))
1117 {
1118 syntax = DB_SYNTAX_SQLITE;
1119 }
1120 else if (!_tcscmp(syntaxId, _T("DB2")))
1121 {
1122 syntax = DB_SYNTAX_DB2;
1123 }
1124 else
1125 {
1126 syntax = DB_SYNTAX_UNKNOWN;
1127 }
1128
1129 return syntax;
1130 }