min/max calls replaced with std::min/std::max
[public/netxms.git] / src / db / dbdrv / sqlite / sqlite.cpp
1 /*
2 ** SQLite Database Driver
3 ** Copyright (C) 2005-2016 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: sqlite.cpp
20 **
21 **/
22
23 #include "sqlitedrv.h"
24
25 DECLARE_DRIVER_HEADER("SQLITE")
26
27 /**
28 * Get error message from connection
29 */
30 static void GetErrorMessage(sqlite3 *hdb, WCHAR *errorText)
31 {
32 if (errorText == NULL)
33 return;
34
35 #if UNICODE_UCS2
36 wcsncpy(errorText, (const WCHAR *)sqlite3_errmsg16(hdb), DBDRV_MAX_ERROR_TEXT);
37 #else
38 MultiByteToWideChar(CP_UTF8, 0, sqlite3_errmsg(hdb), -1, errorText, DBDRV_MAX_ERROR_TEXT);
39 #endif
40 errorText[DBDRV_MAX_ERROR_TEXT - 1] = 0;
41 RemoveTrailingCRLFW(errorText);
42 }
43
44 /**
45 * Prepare string for using in SQL query - enclose in quotes and escape as needed
46 */
47 extern "C" char EXPORT *DrvPrepareStringA(const char *str)
48 {
49 int len = (int)strlen(str) + 3; // + two quotes and \0 at the end
50 int bufferSize = len + 128;
51 char *out = (char *)malloc(bufferSize);
52 out[0] = '\'';
53
54 const char *src = str;
55 int outPos;
56 for(outPos = 1; *src != 0; src++)
57 {
58 if (*src == '\'')
59 {
60 len++;
61 if (len >= bufferSize)
62 {
63 bufferSize += 128;
64 out = (char *)realloc(out, bufferSize);
65 }
66 out[outPos++] = '\'';
67 out[outPos++] = '\'';
68 }
69 else
70 {
71 out[outPos++] = *src;
72 }
73 }
74 out[outPos++] = '\'';
75 out[outPos++] = 0;
76
77 return out;
78 }
79
80 /**
81 * Prepare string for using in SQL query - enclose in quotes and escape as needed
82 */
83 extern "C" WCHAR EXPORT *DrvPrepareStringW(const WCHAR *str)
84 {
85 int len = (int)wcslen(str) + 3; // + two quotes and \0 at the end
86 int bufferSize = len + 128;
87 WCHAR *out = (WCHAR *)malloc(bufferSize * sizeof(WCHAR));
88 out[0] = L'\'';
89
90 const WCHAR *src = str;
91 int outPos;
92 for(outPos = 1; *src != 0; src++)
93 {
94 if (*src == L'\'')
95 {
96 len++;
97 if (len >= bufferSize)
98 {
99 bufferSize += 128;
100 out = (WCHAR *)realloc(out, bufferSize * sizeof(WCHAR));
101 }
102 out[outPos++] = L'\'';
103 out[outPos++] = L'\'';
104 }
105 else
106 {
107 out[outPos++] = *src;
108 }
109 }
110 out[outPos++] = L'\'';
111 out[outPos++] = 0;
112
113 return out;
114 }
115
116 /**
117 * Initialize driver
118 */
119 extern "C" bool EXPORT DrvInit(const char *cmdLine)
120 {
121 if (!sqlite3_threadsafe() || // Fail if SQLite compiled without threading support
122 (sqlite3_initialize() != SQLITE_OK))
123 return false;
124 sqlite3_enable_shared_cache(1);
125 nxlog_debug(1, _T("SQLite version %hs"), sqlite3_libversion());
126 return true;
127 }
128
129 /**
130 * Unload handler
131 */
132 extern "C" void EXPORT DrvUnload()
133 {
134 sqlite3_shutdown();
135 }
136
137 /**
138 * Connect to database
139 */
140 extern "C" DBDRV_CONNECTION EXPORT DrvConnect(const char *host, const char *login,
141 const char *password, const char *database, const char *schema, WCHAR *errorText)
142 {
143 SQLITE_CONN *pConn;
144 sqlite3 *hdb;
145
146 if (sqlite3_open_v2(database, &hdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) == SQLITE_OK)
147 {
148 sqlite3_busy_timeout(hdb, 30000); // 30 sec. busy timeout
149
150 // Create new handle
151 pConn = (SQLITE_CONN *)malloc(sizeof(SQLITE_CONN));
152 memset(pConn, 0, sizeof(SQLITE_CONN));
153 pConn->pdb = hdb;
154 pConn->mutexQueryLock = MutexCreate();
155
156 sqlite3_exec(hdb, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
157 }
158 else
159 {
160 GetErrorMessage(hdb, errorText);
161 pConn = NULL;
162 sqlite3_close(hdb);
163 }
164 return (DBDRV_CONNECTION)pConn;
165 }
166
167 /**
168 * Disconnect from database
169 */
170 extern "C" void EXPORT DrvDisconnect(SQLITE_CONN *hConn)
171 {
172 if (hConn == NULL)
173 return;
174
175 sqlite3_close(hConn->pdb);
176 MutexDestroy(hConn->mutexQueryLock);
177 free(hConn);
178 }
179
180 /**
181 * Prepare statement
182 */
183 extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(SQLITE_CONN *hConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
184 {
185 char *pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
186 MutexLock(hConn->mutexQueryLock);
187 sqlite3_stmt *stmt;
188
189 retry:
190 int rc = sqlite3_prepare_v2(hConn->pdb, pszQueryUTF8, -1, &stmt, NULL);
191 if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
192 {
193 // database locked by another thread, retry in 10 milliseconds
194 ThreadSleepMs(10);
195 goto retry;
196 }
197 else if (rc != SQLITE_OK)
198 {
199 GetErrorMessage(hConn->pdb, errorText);
200 stmt = NULL;
201 *pdwError = DBERR_OTHER_ERROR;
202 }
203 MutexUnlock(hConn->mutexQueryLock);
204 free(pszQueryUTF8);
205 return stmt;
206 }
207
208 /**
209 * Bind parameter to statement
210 */
211 extern "C" void EXPORT DrvBind(sqlite3_stmt *stmt, int pos, int sqlType, int cType, void *buffer, int allocType)
212 {
213 switch(cType)
214 {
215 case DB_CTYPE_STRING:
216 #if UNICODE_UCS2
217 sqlite3_bind_text16(stmt, pos, buffer, (int)wcslen((WCHAR *)buffer) * sizeof(WCHAR),
218 (allocType == DB_BIND_STATIC) ? SQLITE_STATIC : ((allocType == DB_BIND_DYNAMIC) ? free : SQLITE_TRANSIENT));
219 #else
220 {
221 char *utf8String = UTF8StringFromWideString((WCHAR *)buffer);
222 sqlite3_bind_text(stmt, pos, utf8String, strlen(utf8String), free);
223 if (allocType == DB_BIND_DYNAMIC)
224 safe_free(buffer);
225 }
226 #endif
227 break;
228 case DB_CTYPE_UTF8_STRING:
229 sqlite3_bind_text(stmt, pos, (char *)buffer, (int)strlen((char *)buffer),
230 (allocType == DB_BIND_STATIC) ? SQLITE_STATIC : ((allocType == DB_BIND_DYNAMIC) ? free : SQLITE_TRANSIENT));
231 break;
232 case DB_CTYPE_INT32:
233 case DB_CTYPE_UINT32:
234 sqlite3_bind_int(stmt, pos, *((int *)buffer));
235 if (allocType == DB_BIND_DYNAMIC)
236 safe_free(buffer);
237 break;
238 case DB_CTYPE_INT64:
239 case DB_CTYPE_UINT64:
240 sqlite3_bind_int64(stmt, pos, *((sqlite3_int64 *)buffer));
241 if (allocType == DB_BIND_DYNAMIC)
242 safe_free(buffer);
243 break;
244 case DB_CTYPE_DOUBLE:
245 sqlite3_bind_double(stmt, pos, *((double *)buffer));
246 if (allocType == DB_BIND_DYNAMIC)
247 safe_free(buffer);
248 break;
249 default:
250 if (allocType == DB_BIND_DYNAMIC)
251 safe_free(buffer);
252 break;
253 }
254 }
255
256 /**
257 * Execute prepared statement
258 */
259 extern "C" DWORD EXPORT DrvExecute(SQLITE_CONN *hConn, sqlite3_stmt *stmt, WCHAR *errorText)
260 {
261 DWORD result;
262
263 MutexLock(hConn->mutexQueryLock);
264 retry:
265 int rc = sqlite3_step(stmt);
266 if ((rc == SQLITE_DONE) || (rc == SQLITE_ROW))
267 {
268 if (sqlite3_reset(stmt) == SQLITE_OK)
269 {
270 result = DBERR_SUCCESS;
271 }
272 else
273 {
274 GetErrorMessage(hConn->pdb, errorText);
275 result = DBERR_OTHER_ERROR;
276 }
277 }
278 else if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
279 {
280 // database locked by another thread, retry in 10 milliseconds
281 ThreadSleepMs(10);
282 sqlite3_reset(stmt);
283 goto retry;
284 }
285 else
286 {
287 GetErrorMessage(hConn->pdb, errorText);
288 result = DBERR_OTHER_ERROR;
289
290 sqlite3_reset(stmt);
291 }
292 MutexUnlock(hConn->mutexQueryLock);
293 return result;
294 }
295
296 /**
297 * Destroy prepared statement
298 */
299 extern "C" void EXPORT DrvFreeStatement(sqlite3_stmt *stmt)
300 {
301 if (stmt != NULL)
302 sqlite3_finalize(stmt);
303 }
304
305 /**
306 * Internal query
307 */
308 static DWORD DrvQueryInternal(SQLITE_CONN *pConn, const char *pszQuery, WCHAR *errorText)
309 {
310 DWORD result;
311
312 MutexLock(pConn->mutexQueryLock);
313 retry:
314 int rc = sqlite3_exec(pConn->pdb, pszQuery, NULL, NULL, NULL);
315 if (rc == SQLITE_OK)
316 {
317 result = DBERR_SUCCESS;
318 }
319 else if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
320 {
321 // database locked by another thread, retry in 10 milliseconds
322 ThreadSleepMs(10);
323 goto retry;
324 }
325 else
326 {
327 GetErrorMessage(pConn->pdb, errorText);
328 result = DBERR_OTHER_ERROR;
329 }
330 MutexUnlock(pConn->mutexQueryLock);
331 return result;
332 }
333
334 /**
335 * Perform non-SELECT query
336 */
337 extern "C" DWORD EXPORT DrvQuery(SQLITE_CONN *pConn, WCHAR *pwszQuery, WCHAR *errorText)
338 {
339 DWORD dwResult;
340 char *pszQueryUTF8;
341
342 pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
343 dwResult = DrvQueryInternal(pConn, pszQueryUTF8, errorText);
344 free(pszQueryUTF8);
345 return dwResult;
346 }
347
348 /**
349 * SELECT callback
350 */
351 static int SelectCallback(void *pArg, int nCols, char **ppszData, char **ppszNames)
352 {
353 int i, nPos, nMaxCol;
354
355 if (((SQLITE_RESULT *)pArg)->nCols == 0)
356 {
357 ((SQLITE_RESULT *)pArg)->nCols = nCols;
358 nMaxCol = nCols;
359 }
360 else
361 {
362 nMaxCol = std::min(((SQLITE_RESULT *)pArg)->nCols, nCols);
363 }
364
365 // Store column names
366 if ((((SQLITE_RESULT *)pArg)->ppszNames == NULL) && (nCols > 0) && (ppszNames != NULL))
367 {
368 ((SQLITE_RESULT *)pArg)->ppszNames = (char **)malloc(sizeof(char *) * nCols);
369 for(i = 0; i < nCols; i++)
370 ((SQLITE_RESULT *)pArg)->ppszNames[i] = strdup(ppszNames[i]);
371 }
372
373 nPos = ((SQLITE_RESULT *)pArg)->nRows * ((SQLITE_RESULT *)pArg)->nCols;
374 ((SQLITE_RESULT *)pArg)->nRows++;
375 ((SQLITE_RESULT *)pArg)->ppszData = (char **)realloc(((SQLITE_RESULT *)pArg)->ppszData,
376 sizeof(char *) * ((SQLITE_RESULT *)pArg)->nCols * ((SQLITE_RESULT *)pArg)->nRows);
377
378 for(i = 0; i < nMaxCol; i++, nPos++)
379 ((SQLITE_RESULT *)pArg)->ppszData[nPos] = strdup(CHECK_NULL_EX_A(ppszData[i]));
380 for(; i < ((SQLITE_RESULT *)pArg)->nCols; i++, nPos++)
381 ((SQLITE_RESULT *)pArg)->ppszData[nPos] = strdup("");
382 return 0;
383 }
384
385 /**
386 * Free SELECT results
387 */
388 extern "C" void EXPORT DrvFreeResult(SQLITE_RESULT *hResult)
389 {
390 int i, nCount;
391
392 if (hResult != NULL)
393 {
394 if (hResult->ppszData != NULL)
395 {
396 nCount = hResult->nRows * hResult->nCols;
397 for(i = 0; i < nCount; i++)
398 safe_free(hResult->ppszData[i]);
399 free(hResult->ppszData);
400
401 for(i = 0; i < hResult->nCols; i++)
402 safe_free(hResult->ppszNames[i]);
403 free(hResult->ppszNames);
404 }
405 free(hResult);
406 }
407 }
408
409 /**
410 * Perform SELECT query
411 */
412 extern "C" DBDRV_RESULT EXPORT DrvSelect(SQLITE_CONN *hConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
413 {
414 char *pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
415
416 SQLITE_RESULT *result = (SQLITE_RESULT *)malloc(sizeof(SQLITE_RESULT));
417 memset(result, 0, sizeof(SQLITE_RESULT));
418
419 MutexLock(hConn->mutexQueryLock);
420 retry:
421 int rc = sqlite3_exec(hConn->pdb, pszQueryUTF8, SelectCallback, result, NULL);
422 if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
423 {
424 // database locked by another thread, retry in 10 milliseconds
425 ThreadSleepMs(10);
426 goto retry;
427 }
428 else if (rc != SQLITE_OK)
429 {
430 GetErrorMessage(hConn->pdb, errorText);
431 DrvFreeResult(result);
432 result = NULL;
433 }
434 MutexUnlock(hConn->mutexQueryLock);
435
436 free(pszQueryUTF8);
437 *pdwError = (result != NULL) ? DBERR_SUCCESS : DBERR_OTHER_ERROR;
438 return result;
439 }
440
441 /**
442 * Perform SELECT query using prepared statement
443 */
444 extern "C" DBDRV_RESULT EXPORT DrvSelectPrepared(SQLITE_CONN *hConn, sqlite3_stmt *stmt, DWORD *pdwError, WCHAR *errorText)
445 {
446 SQLITE_RESULT *result = (SQLITE_RESULT *)malloc(sizeof(SQLITE_RESULT));
447 memset(result, 0, sizeof(SQLITE_RESULT));
448
449 MutexLock(hConn->mutexQueryLock);
450
451 int nCols = sqlite3_column_count(stmt);
452 char **cnames = (char **)malloc(sizeof(char *) * nCols * 2); // column names + values
453 char **values = &cnames[nCols];
454 bool firstRow = true;
455 while(1)
456 {
457 int rc = sqlite3_step(stmt);
458
459 if (firstRow && ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE)))
460 {
461 // database locked by another thread, retry in 10 milliseconds
462 ThreadSleepMs(10);
463 sqlite3_reset(stmt);
464 continue;
465 }
466
467 if (((rc == SQLITE_DONE) || (rc == SQLITE_ROW)) && firstRow)
468 {
469 firstRow = false;
470 for(int i = 0; i < nCols; i++)
471 cnames[i] = (char *)sqlite3_column_name(stmt, i);
472 }
473
474 if (rc == SQLITE_ROW)
475 {
476 for(int i = 0; i < nCols; i++)
477 values[i] = (char *)sqlite3_column_text(stmt, i);
478 SelectCallback(result, nCols, values, cnames);
479 }
480 else if (rc == SQLITE_DONE)
481 {
482 *pdwError = DBERR_SUCCESS;
483 break;
484 }
485 else
486 {
487 GetErrorMessage(hConn->pdb, errorText);
488 *pdwError = DBERR_OTHER_ERROR;
489 break;
490 }
491 }
492 safe_free(cnames);
493
494 if (*pdwError == DBERR_SUCCESS)
495 {
496 if (sqlite3_reset(stmt) != SQLITE_OK)
497 {
498 GetErrorMessage(hConn->pdb, errorText);
499 *pdwError = DBERR_OTHER_ERROR;
500 }
501 }
502 else
503 {
504 sqlite3_reset(stmt);
505 }
506
507 MutexUnlock(hConn->mutexQueryLock);
508
509 if (*pdwError != DBERR_SUCCESS)
510 {
511 DrvFreeResult(result);
512 result = NULL;
513 }
514
515 return result;
516 }
517
518 /**
519 * Get field length from result
520 */
521 extern "C" LONG EXPORT DrvGetFieldLength(DBDRV_RESULT hResult, int iRow, int iColumn)
522 {
523 if ((iRow < ((SQLITE_RESULT *)hResult)->nRows) &&
524 (iColumn < ((SQLITE_RESULT *)hResult)->nCols) &&
525 (iRow >= 0) && (iColumn >= 0))
526 return (LONG)strlen(((SQLITE_RESULT *)hResult)->ppszData[iRow * ((SQLITE_RESULT *)hResult)->nCols + iColumn]);
527 return -1;
528 }
529
530 /**
531 * Get field value from result
532 */
533 extern "C" WCHAR EXPORT *DrvGetField(DBDRV_RESULT hResult, int iRow, int iColumn, WCHAR *pwszBuffer, int nBufLen)
534 {
535 if ((iRow < ((SQLITE_RESULT *)hResult)->nRows) &&
536 (iColumn < ((SQLITE_RESULT *)hResult)->nCols) &&
537 (iRow >= 0) && (iColumn >= 0))
538 {
539 MultiByteToWideChar(CP_UTF8, 0, ((SQLITE_RESULT *)hResult)->ppszData[iRow * ((SQLITE_RESULT *)hResult)->nCols + iColumn],
540 -1, pwszBuffer, nBufLen);
541 pwszBuffer[nBufLen - 1] = 0;
542 return pwszBuffer;
543 }
544 return NULL;
545 }
546
547 /**
548 * Get field value from result as UTF8 string
549 */
550 extern "C" char EXPORT *DrvGetFieldUTF8(DBDRV_RESULT hResult, int iRow, int iColumn, char *buffer, int nBufLen)
551 {
552 if ((iRow < ((SQLITE_RESULT *)hResult)->nRows) &&
553 (iColumn < ((SQLITE_RESULT *)hResult)->nCols) &&
554 (iRow >= 0) && (iColumn >= 0))
555 {
556 strncpy(buffer, ((SQLITE_RESULT *)hResult)->ppszData[iRow * ((SQLITE_RESULT *)hResult)->nCols + iColumn], nBufLen);
557 buffer[nBufLen - 1] = 0;
558 return buffer;
559 }
560 return NULL;
561 }
562
563 /**
564 * Get number of rows in result
565 */
566 extern "C" int EXPORT DrvGetNumRows(SQLITE_RESULT *hResult)
567 {
568 return hResult->nRows;
569 }
570
571 /**
572 * Get column count in query result
573 */
574 extern "C" int EXPORT DrvGetColumnCount(SQLITE_RESULT *hResult)
575 {
576 return (hResult != NULL) ? hResult->nCols : 0;
577 }
578
579 /**
580 * Get column name in query result
581 */
582 extern "C" const char EXPORT *DrvGetColumnName(SQLITE_RESULT *hResult, int column)
583 {
584 char *pszRet = NULL;
585
586 if ((column >= 0) && (column < hResult->nCols))
587 {
588 pszRet = hResult->ppszNames[column];
589 }
590 return pszRet;
591 }
592
593 /**
594 * Perform unbuffered SELECT query
595 */
596 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT DrvSelectUnbuffered(SQLITE_CONN *hConn, WCHAR *pwszQuery, DWORD *pdwError, WCHAR *errorText)
597 {
598 SQLITE_UNBUFFERED_RESULT *result;
599 char *pszQueryUTF8;
600 sqlite3_stmt *stmt;
601
602 pszQueryUTF8 = UTF8StringFromWideString(pwszQuery);
603 MutexLock(hConn->mutexQueryLock);
604 retry:
605 int rc = sqlite3_prepare(hConn->pdb, pszQueryUTF8, -1, &stmt, NULL);
606 if (rc == SQLITE_OK)
607 {
608 result = (SQLITE_UNBUFFERED_RESULT *)malloc(sizeof(SQLITE_UNBUFFERED_RESULT));
609 result->connection = hConn;
610 result->stmt = stmt;
611 result->prepared = false;
612 *pdwError = DBERR_SUCCESS;
613 }
614 else if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
615 {
616 // database locked by another thread, retry in 10 milliseconds
617 ThreadSleepMs(10);
618 goto retry;
619 }
620 else
621 {
622 GetErrorMessage(hConn->pdb, errorText);
623 MutexUnlock(hConn->mutexQueryLock);
624 result = NULL;
625 *pdwError = DBERR_OTHER_ERROR;
626 }
627 free(pszQueryUTF8);
628 return result;
629 }
630
631 /**
632 * Perform unbuffered SELECT query using prepared statement
633 */
634 extern "C" DBDRV_UNBUFFERED_RESULT EXPORT DrvSelectPreparedUnbuffered(SQLITE_CONN *hConn, sqlite3_stmt *stmt, DWORD *pdwError, WCHAR *errorText)
635 {
636 if ((hConn == NULL) || (stmt == NULL))
637 return NULL;
638
639 SQLITE_UNBUFFERED_RESULT *result = (SQLITE_UNBUFFERED_RESULT *)malloc(sizeof(SQLITE_UNBUFFERED_RESULT));
640 result->connection = hConn;
641 result->stmt = stmt;
642 result->prepared = true;
643 *pdwError = DBERR_SUCCESS;
644 return result;
645 }
646
647 /**
648 * Fetch next result line from asynchronous SELECT results
649 */
650 extern "C" bool EXPORT DrvFetch(SQLITE_UNBUFFERED_RESULT *result)
651 {
652 if (result == NULL)
653 return false;
654
655 retry:
656 int rc = sqlite3_step(result->stmt);
657 if (rc == SQLITE_ROW)
658 {
659 result->numColumns = sqlite3_column_count(result->stmt);
660 return true;
661 }
662 else if ((rc == SQLITE_LOCKED) || (rc == SQLITE_LOCKED_SHAREDCACHE))
663 {
664 // database locked by another thread, retry in 10 milliseconds
665 ThreadSleepMs(10);
666 sqlite3_reset(result->stmt);
667 goto retry;
668 }
669 return false;
670 }
671
672 /**
673 * Get field length from unbuffered query result
674 */
675 extern "C" LONG EXPORT DrvGetFieldLengthUnbuffered(SQLITE_UNBUFFERED_RESULT *result, int iColumn)
676 {
677 if ((iColumn >= 0) && (iColumn < result->numColumns))
678 return (LONG)strlen((char *)sqlite3_column_text(result->stmt, iColumn));
679 return 0;
680 }
681
682 /**
683 * Get field from current row in unbuffered query result
684 */
685 extern "C" WCHAR EXPORT *DrvGetFieldUnbuffered(SQLITE_UNBUFFERED_RESULT *result, int iColumn, WCHAR *pBuffer, int iBufSize)
686 {
687 char *pszData;
688 WCHAR *pwszRet = NULL;
689
690 if ((iColumn >= 0) && (iColumn < result->numColumns))
691 {
692 pszData = (char *)sqlite3_column_text(result->stmt, iColumn);
693 if (pszData != NULL)
694 {
695 MultiByteToWideChar(CP_UTF8, 0, pszData, -1, pBuffer, iBufSize);
696 pBuffer[iBufSize - 1] = 0;
697 pwszRet = pBuffer;
698 }
699 }
700 return pwszRet;
701 }
702
703 /**
704 * Get field from current row in unbuffered query result as UTF-8 string
705 */
706 extern "C" char EXPORT *DrvGetFieldUnbufferedUTF8(SQLITE_UNBUFFERED_RESULT *result, int iColumn, char *pBuffer, int iBufSize)
707 {
708 char *pszData;
709 char *value = NULL;
710
711 if ((iColumn >= 0) && (iColumn < result->numColumns))
712 {
713 pszData = (char *)sqlite3_column_text(result->stmt, iColumn);
714 if (pszData != NULL)
715 {
716 strncpy(pBuffer, pszData, iBufSize);
717 pBuffer[iBufSize - 1] = 0;
718 value = pBuffer;
719 }
720 }
721 return value;
722 }
723
724 /**
725 * Get column count in async query result
726 */
727 extern "C" int EXPORT DrvGetColumnCountUnbuffered(SQLITE_UNBUFFERED_RESULT *result)
728 {
729 return (result != NULL) ? result->numColumns : 0;
730 }
731
732 /**
733 * Get column name in async query result
734 */
735 extern "C" const char EXPORT *DrvGetColumnNameUnbuffered(SQLITE_UNBUFFERED_RESULT *result, int column)
736 {
737 const char *pszRet = NULL;
738
739 if ((column >= 0) && (column < result->numColumns))
740 {
741 pszRet = sqlite3_column_name(result->stmt, column);
742 }
743 return pszRet;
744 }
745
746 /**
747 * Destroy result of async query
748 */
749 extern "C" void EXPORT DrvFreeUnbufferedResult(SQLITE_UNBUFFERED_RESULT *result)
750 {
751 if (result != NULL)
752 {
753 if (result->prepared)
754 sqlite3_reset(result->stmt);
755 else
756 sqlite3_finalize(result->stmt);
757 MutexUnlock(result->connection->mutexQueryLock);
758 free(result);
759 }
760 }
761
762 /**
763 * Begin transaction
764 */
765 extern "C" DWORD EXPORT DrvBegin(SQLITE_CONN *pConn)
766 {
767 return DrvQueryInternal(pConn, "BEGIN IMMEDIATE", NULL);
768 }
769
770 /**
771 * Commit transaction
772 */
773 extern "C" DWORD EXPORT DrvCommit(SQLITE_CONN *pConn)
774 {
775 return DrvQueryInternal(pConn, "COMMIT", NULL);
776 }
777
778 /**
779 * Rollback transaction
780 */
781 extern "C" DWORD EXPORT DrvRollback(SQLITE_CONN *pConn)
782 {
783 return DrvQueryInternal(pConn, "ROLLBACK", NULL);
784 }
785
786 /**
787 * Check if table exist
788 */
789 extern "C" int EXPORT DrvIsTableExist(SQLITE_CONN *pConn, const WCHAR *name)
790 {
791 WCHAR query[256];
792 #if HAVE_SWPRINTF
793 swprintf(query, 256, L"SELECT count(*) FROM sqlite_master WHERE type='table' AND upper(name)=upper('%ls')", name);
794 #else
795 wcscpy(query, L"SELECT count(*) FROM sqlite_master WHERE type='table' AND upper(name)=upper('");
796 wcscat(query, name);
797 wcscat(query, L"')");
798 #endif
799 DWORD error;
800 WCHAR errorText[DBDRV_MAX_ERROR_TEXT];
801 int rc = DBIsTableExist_Failure;
802 SQLITE_RESULT *hResult = (SQLITE_RESULT *)DrvSelect(pConn, query, &error, errorText);
803 if (hResult != NULL)
804 {
805 WCHAR buffer[64] = L"";
806 DrvGetField(hResult, 0, 0, buffer, 64);
807 rc = (wcstol(buffer, NULL, 10) > 0) ? DBIsTableExist_Found : DBIsTableExist_NotFound;
808 DrvFreeResult(hResult);
809 }
810 return rc;
811 }
812
813 #ifdef _WIN32
814
815 /**
816 * DLL Entry point
817 */
818 bool WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
819 {
820 if (dwReason == DLL_PROCESS_ATTACH)
821 DisableThreadLibraryCalls(hInstance);
822 return true;
823 }
824
825 #endif