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