summaryrefslogtreecommitdiffstats
path: root/common/unqlite/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/unqlite/api.c')
-rw-r--r--common/unqlite/api.c2789
1 files changed, 2789 insertions, 0 deletions
diff --git a/common/unqlite/api.c b/common/unqlite/api.c
new file mode 100644
index 0000000..9915d14
--- /dev/null
+++ b/common/unqlite/api.c
@@ -0,0 +1,2789 @@
1/*
2 * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine.
3 * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/
4 * Version 1.1.6
5 * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
6 * please contact Symisc Systems via:
7 * legal@symisc.net
8 * licensing@symisc.net
9 * contact@symisc.net
10 * or visit:
11 * http://unqlite.org/licensing.html
12 */
13 /* $SymiscID: api.c v2.0 FreeBSD 2012-11-08 23:07 stable <chm@symisc.net> $ */
14#ifndef UNQLITE_AMALGAMATION
15#include "unqliteInt.h"
16#endif
17/* This file implement the public interfaces presented to host-applications.
18 * Routines in other files are for internal use by UnQLite and should not be
19 * accessed by users of the library.
20 */
21#define UNQLITE_DB_MISUSE(DB) (DB == 0 || DB->nMagic != UNQLITE_DB_MAGIC)
22#define UNQLITE_VM_MISUSE(VM) (VM == 0 || VM->nMagic == JX9_VM_STALE)
23/* If another thread have released a working instance, the following macros
24 * evaluates to true. These macros are only used when the library
25 * is built with threading support enabled.
26 */
27#define UNQLITE_THRD_DB_RELEASE(DB) (DB->nMagic != UNQLITE_DB_MAGIC)
28#define UNQLITE_THRD_VM_RELEASE(VM) (VM->nMagic == JX9_VM_STALE)
29/* IMPLEMENTATION: unqlite@embedded@symisc 118-09-4785 */
30/*
31 * All global variables are collected in the structure named "sUnqlMPGlobal".
32 * That way it is clear in the code when we are using static variable because
33 * its name start with sUnqlMPGlobal.
34 */
35static struct unqlGlobal_Data
36{
37 SyMemBackend sAllocator; /* Global low level memory allocator */
38#if defined(UNQLITE_ENABLE_THREADS)
39 const SyMutexMethods *pMutexMethods; /* Mutex methods */
40 SyMutex *pMutex; /* Global mutex */
41 sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded
42 * The threading level can be set using the [unqlite_lib_config()]
43 * interface with a configuration verb set to
44 * UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE or
45 * UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI
46 */
47#endif
48 SySet kv_storage; /* Installed KV storage engines */
49 int iPageSize; /* Default Page size */
50 unqlite_vfs *pVfs; /* Underlying virtual file system (Vfs) */
51 sxi32 nDB; /* Total number of active DB handles */
52 unqlite *pDB; /* List of active DB handles */
53 sxu32 nMagic; /* Sanity check against library misuse */
54}sUnqlMPGlobal = {
55 {0, 0, 0, 0, 0, 0, 0, 0, {0}},
56#if defined(UNQLITE_ENABLE_THREADS)
57 0,
58 0,
59 0,
60#endif
61 {0, 0, 0, 0, 0, 0, 0 },
62 UNQLITE_DEFAULT_PAGE_SIZE,
63 0,
64 0,
65 0,
66 0
67};
68#define UNQLITE_LIB_MAGIC 0xEA1495BA
69#define UNQLITE_LIB_MISUSE (sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC)
70/*
71 * Supported threading level.
72 * These options have meaning only when the library is compiled with multi-threading
73 * support. That is, the UNQLITE_ENABLE_THREADS compile time directive must be defined
74 * when UnQLite is built.
75 * UNQLITE_THREAD_LEVEL_SINGLE:
76 * In this mode, mutexing is disabled and the library can only be used by a single thread.
77 * UNQLITE_THREAD_LEVEL_MULTI
78 * In this mode, all mutexes including the recursive mutexes on [unqlite] objects
79 * are enabled so that the application is free to share the same database handle
80 * between different threads at the same time.
81 */
82#define UNQLITE_THREAD_LEVEL_SINGLE 1
83#define UNQLITE_THREAD_LEVEL_MULTI 2
84/*
85 * Find a Key Value storage engine from the set of installed engines.
86 * Return a pointer to the storage engine methods on success. NULL on failure.
87 */
88UNQLITE_PRIVATE unqlite_kv_methods * unqliteFindKVStore(
89 const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */
90 sxu32 nByte /* zName length */
91 )
92{
93 unqlite_kv_methods **apStore,*pEntry;
94 sxu32 n,nMax;
95 /* Point to the set of installed engines */
96 apStore = (unqlite_kv_methods **)SySetBasePtr(&sUnqlMPGlobal.kv_storage);
97 nMax = SySetUsed(&sUnqlMPGlobal.kv_storage);
98 for( n = 0 ; n < nMax; ++n ){
99 pEntry = apStore[n];
100 if( nByte == SyStrlen(pEntry->zName) && SyStrnicmp(pEntry->zName,zName,nByte) == 0 ){
101 /* Storage engine found */
102 return pEntry;
103 }
104 }
105 /* No such entry, return NULL */
106 return 0;
107}
108/*
109 * Configure the UnQLite library.
110 * Return UNQLITE_OK on success. Any other return value indicates failure.
111 * Refer to [unqlite_lib_config()].
112 */
113static sxi32 unqliteCoreConfigure(sxi32 nOp, va_list ap)
114{
115 int rc = UNQLITE_OK;
116 switch(nOp){
117 case UNQLITE_LIB_CONFIG_PAGE_SIZE: {
118 /* Default page size: Must be a power of two */
119 int iPage = va_arg(ap,int);
120 if( iPage >= UNQLITE_MIN_PAGE_SIZE && iPage <= UNQLITE_MAX_PAGE_SIZE ){
121 if( !(iPage & (iPage - 1)) ){
122 sUnqlMPGlobal.iPageSize = iPage;
123 }else{
124 /* Invalid page size */
125 rc = UNQLITE_INVALID;
126 }
127 }else{
128 /* Invalid page size */
129 rc = UNQLITE_INVALID;
130 }
131 break;
132 }
133 case UNQLITE_LIB_CONFIG_STORAGE_ENGINE: {
134 /* Install a key value storage engine */
135 unqlite_kv_methods *pMethods = va_arg(ap,unqlite_kv_methods *);
136 /* Make sure we are delaing with a valid methods */
137 if( pMethods == 0 || SX_EMPTY_STR(pMethods->zName) || pMethods->xSeek == 0 || pMethods->xData == 0
138 || pMethods->xKey == 0 || pMethods->xDataLength == 0 || pMethods->xKeyLength == 0
139 || pMethods->szKv < (int)sizeof(unqlite_kv_engine) ){
140 rc = UNQLITE_INVALID;
141 break;
142 }
143 /* Install it */
144 rc = SySetPut(&sUnqlMPGlobal.kv_storage,(const void *)&pMethods);
145 break;
146 }
147 case UNQLITE_LIB_CONFIG_VFS:{
148 /* Install a virtual file system */
149 unqlite_vfs *pVfs = va_arg(ap,unqlite_vfs *);
150 if( pVfs ){
151 sUnqlMPGlobal.pVfs = pVfs;
152 }
153 break;
154 }
155 case UNQLITE_LIB_CONFIG_USER_MALLOC: {
156 /* Use an alternative low-level memory allocation routines */
157 const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *);
158 /* Save the memory failure callback (if available) */
159 ProcMemError xMemErr = sUnqlMPGlobal.sAllocator.xMemError;
160 void *pMemErr = sUnqlMPGlobal.sAllocator.pUserData;
161 if( pMethods == 0 ){
162 /* Use the built-in memory allocation subsystem */
163 rc = SyMemBackendInit(&sUnqlMPGlobal.sAllocator, xMemErr, pMemErr);
164 }else{
165 rc = SyMemBackendInitFromOthers(&sUnqlMPGlobal.sAllocator, pMethods, xMemErr, pMemErr);
166 }
167 break;
168 }
169 case UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK: {
170 /* Memory failure callback */
171 ProcMemError xMemErr = va_arg(ap, ProcMemError);
172 void *pUserData = va_arg(ap, void *);
173 sUnqlMPGlobal.sAllocator.xMemError = xMemErr;
174 sUnqlMPGlobal.sAllocator.pUserData = pUserData;
175 break;
176 }
177 case UNQLITE_LIB_CONFIG_USER_MUTEX: {
178#if defined(UNQLITE_ENABLE_THREADS)
179 /* Use an alternative low-level mutex subsystem */
180 const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *);
181#if defined (UNTRUST)
182 if( pMethods == 0 ){
183 rc = UNQLITE_CORRUPT;
184 }
185#endif
186 /* Sanity check */
187 if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){
188 /* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */
189 rc = UNQLITE_CORRUPT;
190 break;
191 }
192 if( sUnqlMPGlobal.pMutexMethods ){
193 /* Overwrite the previous mutex subsystem */
194 SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex);
195 if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){
196 sUnqlMPGlobal.pMutexMethods->xGlobalRelease();
197 }
198 sUnqlMPGlobal.pMutex = 0;
199 }
200 /* Initialize and install the new mutex subsystem */
201 if( pMethods->xGlobalInit ){
202 rc = pMethods->xGlobalInit();
203 if ( rc != UNQLITE_OK ){
204 break;
205 }
206 }
207 /* Create the global mutex */
208 sUnqlMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
209 if( sUnqlMPGlobal.pMutex == 0 ){
210 /*
211 * If the supplied mutex subsystem is so sick that we are unable to
212 * create a single mutex, there is no much we can do here.
213 */
214 if( pMethods->xGlobalRelease ){
215 pMethods->xGlobalRelease();
216 }
217 rc = UNQLITE_CORRUPT;
218 break;
219 }
220 sUnqlMPGlobal.pMutexMethods = pMethods;
221 if( sUnqlMPGlobal.nThreadingLevel == 0 ){
222 /* Set a default threading level */
223 sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI;
224 }
225#endif
226 break;
227 }
228 case UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE:
229#if defined(UNQLITE_ENABLE_THREADS)
230 /* Single thread mode (Only one thread is allowed to play with the library) */
231 sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_SINGLE;
232 jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE);
233#endif
234 break;
235 case UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI:
236#if defined(UNQLITE_ENABLE_THREADS)
237 /* Multi-threading mode (library is thread safe and database handles and virtual machines
238 * may be shared between multiple threads).
239 */
240 sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI;
241 jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_MULTI);
242#endif
243 break;
244 default:
245 /* Unknown configuration option */
246 rc = UNQLITE_CORRUPT;
247 break;
248 }
249 return rc;
250}
251/*
252 * [CAPIREF: unqlite_lib_config()]
253 * Please refer to the official documentation for function purpose and expected parameters.
254 */
255int unqlite_lib_config(int nConfigOp,...)
256{
257 va_list ap;
258 int rc;
259 if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){
260 /* Library is already initialized, this operation is forbidden */
261 return UNQLITE_LOCKED;
262 }
263 va_start(ap,nConfigOp);
264 rc = unqliteCoreConfigure(nConfigOp,ap);
265 va_end(ap);
266 return rc;
267}
268/*
269 * Global library initialization
270 * Refer to [unqlite_lib_init()]
271 * This routine must be called to initialize the memory allocation subsystem, the mutex
272 * subsystem prior to doing any serious work with the library. The first thread to call
273 * this routine does the initialization process and set the magic number so no body later
274 * can re-initialize the library. If subsequent threads call this routine before the first
275 * thread have finished the initialization process, then the subsequent threads must block
276 * until the initialization process is done.
277 */
278static sxi32 unqliteCoreInitialize(void)
279{
280 const unqlite_kv_methods *pMethods;
281 const unqlite_vfs *pVfs; /* Built-in vfs */
282#if defined(UNQLITE_ENABLE_THREADS)
283 const SyMutexMethods *pMutexMethods = 0;
284 SyMutex *pMaster = 0;
285#endif
286 int rc;
287 /*
288 * If the library is already initialized, then a call to this routine
289 * is a no-op.
290 */
291 if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){
292 return UNQLITE_OK; /* Already initialized */
293 }
294 /* Point to the built-in vfs */
295 pVfs = unqliteExportBuiltinVfs();
296 /* Install it */
297 unqlite_lib_config(UNQLITE_LIB_CONFIG_VFS, pVfs);
298#if defined(UNQLITE_ENABLE_THREADS)
299 if( sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_SINGLE ){
300 pMutexMethods = sUnqlMPGlobal.pMutexMethods;
301 if( pMutexMethods == 0 ){
302 /* Use the built-in mutex subsystem */
303 pMutexMethods = SyMutexExportMethods();
304 if( pMutexMethods == 0 ){
305 return UNQLITE_CORRUPT; /* Can't happen */
306 }
307 /* Install the mutex subsystem */
308 rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MUTEX, pMutexMethods);
309 if( rc != UNQLITE_OK ){
310 return rc;
311 }
312 }
313 /* Obtain a static mutex so we can initialize the library without calling malloc() */
314 pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1);
315 if( pMaster == 0 ){
316 return UNQLITE_CORRUPT; /* Can't happen */
317 }
318 }
319 /* Lock the master mutex */
320 rc = UNQLITE_OK;
321 SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
322 if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){
323#endif
324 if( sUnqlMPGlobal.sAllocator.pMethods == 0 ){
325 /* Install a memory subsystem */
326 rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */
327 if( rc != UNQLITE_OK ){
328 /* If we are unable to initialize the memory backend, there is no much we can do here.*/
329 goto End;
330 }
331 }
332#if defined(UNQLITE_ENABLE_THREADS)
333 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){
334 /* Protect the memory allocation subsystem */
335 rc = SyMemBackendMakeThreadSafe(&sUnqlMPGlobal.sAllocator, sUnqlMPGlobal.pMutexMethods);
336 if( rc != UNQLITE_OK ){
337 goto End;
338 }
339 }
340#endif
341 SySetInit(&sUnqlMPGlobal.kv_storage,&sUnqlMPGlobal.sAllocator,sizeof(unqlite_kv_methods *));
342 /* Install the built-in Key Value storage engines */
343 pMethods = unqliteExportMemKvStorage(); /* In-memory storage */
344 unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods);
345 /* Default disk key/value storage engine */
346 pMethods = unqliteExportDiskKvStorage(); /* Disk storage */
347 unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods);
348 /* Default page size */
349 if( sUnqlMPGlobal.iPageSize < UNQLITE_MIN_PAGE_SIZE ){
350 unqlite_lib_config(UNQLITE_LIB_CONFIG_PAGE_SIZE,UNQLITE_DEFAULT_PAGE_SIZE);
351 }
352 /* Our library is initialized, set the magic number */
353 sUnqlMPGlobal.nMagic = UNQLITE_LIB_MAGIC;
354 rc = UNQLITE_OK;
355#if defined(UNQLITE_ENABLE_THREADS)
356 } /* sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC */
357#endif
358End:
359#if defined(UNQLITE_ENABLE_THREADS)
360 /* Unlock the master mutex */
361 SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
362#endif
363 return rc;
364}
365/* Forward declaration */
366static int unqliteVmRelease(unqlite_vm *pVm);
367/*
368 * Release a single instance of an unqlite database handle.
369 */
370static int unqliteDbRelease(unqlite *pDb)
371{
372 unqlite_db *pStore = &pDb->sDB;
373 unqlite_vm *pVm,*pNext;
374 int rc = UNQLITE_OK;
375 if( (pDb->iFlags & UNQLITE_FL_DISABLE_AUTO_COMMIT) == 0 ){
376 /* Commit any outstanding transaction */
377 rc = unqlitePagerCommit(pStore->pPager);
378 if( rc != UNQLITE_OK ){
379 /* Rollback the transaction */
380 rc = unqlitePagerRollback(pStore->pPager,FALSE);
381 }
382 }else{
383 /* Rollback any outstanding transaction */
384 rc = unqlitePagerRollback(pStore->pPager,FALSE);
385 }
386 /* Close the pager */
387 unqlitePagerClose(pStore->pPager);
388 /* Release any active VM's */
389 pVm = pDb->pVms;
390 for(;;){
391 if( pDb->iVm < 1 ){
392 break;
393 }
394 /* Point to the next entry */
395 pNext = pVm->pNext;
396 unqliteVmRelease(pVm);
397 pVm = pNext;
398 pDb->iVm--;
399 }
400 /* Release the Jx9 handle */
401 jx9_release(pStore->pJx9);
402 /* Set a dummy magic number */
403 pDb->nMagic = 0x7250;
404 /* Release the whole memory subsystem */
405 SyMemBackendRelease(&pDb->sMem);
406 /* Commit or rollback result */
407 return rc;
408}
409/*
410 * Release all resources consumed by the library.
411 * Note: This call is not thread safe. Refer to [unqlite_lib_shutdown()].
412 */
413static void unqliteCoreShutdown(void)
414{
415 unqlite *pDb, *pNext;
416 /* Release all active databases handles */
417 pDb = sUnqlMPGlobal.pDB;
418 for(;;){
419 if( sUnqlMPGlobal.nDB < 1 ){
420 break;
421 }
422 pNext = pDb->pNext;
423 unqliteDbRelease(pDb);
424 pDb = pNext;
425 sUnqlMPGlobal.nDB--;
426 }
427 /* Release the storage methods container */
428 SySetRelease(&sUnqlMPGlobal.kv_storage);
429#if defined(UNQLITE_ENABLE_THREADS)
430 /* Release the mutex subsystem */
431 if( sUnqlMPGlobal.pMutexMethods ){
432 if( sUnqlMPGlobal.pMutex ){
433 SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex);
434 sUnqlMPGlobal.pMutex = 0;
435 }
436 if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){
437 sUnqlMPGlobal.pMutexMethods->xGlobalRelease();
438 }
439 sUnqlMPGlobal.pMutexMethods = 0;
440 }
441 sUnqlMPGlobal.nThreadingLevel = 0;
442#endif
443 if( sUnqlMPGlobal.sAllocator.pMethods ){
444 /* Release the memory backend */
445 SyMemBackendRelease(&sUnqlMPGlobal.sAllocator);
446 }
447 sUnqlMPGlobal.nMagic = 0x1764;
448 /* Finally, shutdown the Jx9 library */
449 jx9_lib_shutdown();
450}
451/*
452 * [CAPIREF: unqlite_lib_init()]
453 * Please refer to the official documentation for function purpose and expected parameters.
454 */
455int unqlite_lib_init(void)
456{
457 int rc;
458 rc = unqliteCoreInitialize();
459 return rc;
460}
461/*
462 * [CAPIREF: unqlite_lib_shutdown()]
463 * Please refer to the official documentation for function purpose and expected parameters.
464 */
465int unqlite_lib_shutdown(void)
466{
467 if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){
468 /* Already shut */
469 return UNQLITE_OK;
470 }
471 unqliteCoreShutdown();
472 return UNQLITE_OK;
473}
474/*
475 * [CAPIREF: unqlite_lib_is_threadsafe()]
476 * Please refer to the official documentation for function purpose and expected parameters.
477 */
478int unqlite_lib_is_threadsafe(void)
479{
480 if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){
481 return 0;
482 }
483#if defined(UNQLITE_ENABLE_THREADS)
484 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){
485 /* Muli-threading support is enabled */
486 return 1;
487 }else{
488 /* Single-threading */
489 return 0;
490 }
491#else
492 return 0;
493#endif
494}
495/*
496 *
497 * [CAPIREF: unqlite_lib_version()]
498 * Please refer to the official documentation for function purpose and expected parameters.
499 */
500const char * unqlite_lib_version(void)
501{
502 return UNQLITE_VERSION;
503}
504/*
505 *
506 * [CAPIREF: unqlite_lib_signature()]
507 * Please refer to the official documentation for function purpose and expected parameters.
508 */
509const char * unqlite_lib_signature(void)
510{
511 return UNQLITE_SIG;
512}
513/*
514 *
515 * [CAPIREF: unqlite_lib_ident()]
516 * Please refer to the official documentation for function purpose and expected parameters.
517 */
518const char * unqlite_lib_ident(void)
519{
520 return UNQLITE_IDENT;
521}
522/*
523 *
524 * [CAPIREF: unqlite_lib_copyright()]
525 * Please refer to the official documentation for function purpose and expected parameters.
526 */
527const char * unqlite_lib_copyright(void)
528{
529 return UNQLITE_COPYRIGHT;
530}
531/*
532 * Remove harmfull and/or stale flags passed to the [unqlite_open()] interface.
533 */
534static unsigned int unqliteSanityzeFlag(unsigned int iFlags)
535{
536 iFlags &= ~UNQLITE_OPEN_EXCLUSIVE; /* Reserved flag */
537 if( iFlags & UNQLITE_OPEN_TEMP_DB ){
538 /* Omit journaling for temporary database */
539 iFlags |= UNQLITE_OPEN_OMIT_JOURNALING|UNQLITE_OPEN_CREATE;
540 }
541 if( (iFlags & (UNQLITE_OPEN_READONLY|UNQLITE_OPEN_READWRITE)) == 0 ){
542 /* Auto-append the R+W flag */
543 iFlags |= UNQLITE_OPEN_READWRITE;
544 }
545 if( iFlags & UNQLITE_OPEN_CREATE ){
546 iFlags &= ~(UNQLITE_OPEN_MMAP|UNQLITE_OPEN_READONLY);
547 /* Auto-append the R+W flag */
548 iFlags |= UNQLITE_OPEN_READWRITE;
549 }else{
550 if( iFlags & UNQLITE_OPEN_READONLY ){
551 iFlags &= ~UNQLITE_OPEN_READWRITE;
552 }else if( iFlags & UNQLITE_OPEN_READWRITE ){
553 iFlags &= ~UNQLITE_OPEN_MMAP;
554 }
555 }
556 return iFlags;
557}
558/*
559 * This routine does the work of initializing a database handle on behalf
560 * of [unqlite_open()].
561 */
562static int unqliteInitDatabase(
563 unqlite *pDB, /* Database handle */
564 SyMemBackend *pParent, /* Master memory backend */
565 const char *zFilename, /* Target database */
566 unsigned int iFlags /* Open flags */
567 )
568{
569 unqlite_db *pStorage = &pDB->sDB;
570 int rc;
571 /* Initialiaze the memory subsystem */
572 SyMemBackendInitFromParent(&pDB->sMem,pParent);
573#if defined(UNQLITE_ENABLE_THREADS)
574 /* No need for internal mutexes */
575 SyMemBackendDisbaleMutexing(&pDB->sMem);
576#endif
577 SyBlobInit(&pDB->sErr,&pDB->sMem);
578 /* Sanityze flags */
579 iFlags = unqliteSanityzeFlag(iFlags);
580 /* Init the pager and the transaction manager */
581 rc = unqlitePagerOpen(sUnqlMPGlobal.pVfs,pDB,zFilename,iFlags);
582 if( rc != UNQLITE_OK ){
583 return rc;
584 }
585 /* Allocate a new Jx9 engine handle */
586 rc = jx9_init(&pStorage->pJx9);
587 if( rc != JX9_OK ){
588 return rc;
589 }
590 return UNQLITE_OK;
591}
592/*
593 * Allocate and initialize a new UnQLite Virtual Mahcine and attach it
594 * to the compiled Jx9 script.
595 */
596static int unqliteInitVm(unqlite *pDb,jx9_vm *pJx9Vm,unqlite_vm **ppOut)
597{
598 unqlite_vm *pVm;
599
600 *ppOut = 0;
601 /* Allocate a new VM instance */
602 pVm = (unqlite_vm *)SyMemBackendPoolAlloc(&pDb->sMem,sizeof(unqlite_vm));
603 if( pVm == 0 ){
604 return UNQLITE_NOMEM;
605 }
606 /* Zero the structure */
607 SyZero(pVm,sizeof(unqlite_vm));
608 /* Initialize */
609 SyMemBackendInitFromParent(&pVm->sAlloc,&pDb->sMem);
610 /* Allocate a new collection table */
611 pVm->apCol = (unqlite_col **)SyMemBackendAlloc(&pVm->sAlloc,32 * sizeof(unqlite_col *));
612 if( pVm->apCol == 0 ){
613 goto fail;
614 }
615 pVm->iColSize = 32; /* Must be a power of two */
616 /* Zero the table */
617 SyZero((void *)pVm->apCol,pVm->iColSize * sizeof(unqlite_col *));
618#if defined(UNQLITE_ENABLE_THREADS)
619 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){
620 /* Associate a recursive mutex with this instance */
621 pVm->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
622 if( pVm->pMutex == 0 ){
623 goto fail;
624 }
625 }
626#endif
627 /* Link the VM to the list of active virtual machines */
628 pVm->pJx9Vm = pJx9Vm;
629 pVm->pDb = pDb;
630 MACRO_LD_PUSH(pDb->pVms,pVm);
631 pDb->iVm++;
632 /* Register Jx9 functions */
633 unqliteRegisterJx9Functions(pVm);
634 /* Set the magic number */
635 pVm->nMagic = JX9_VM_INIT; /* Same magic number as Jx9 */
636 /* All done */
637 *ppOut = pVm;
638 return UNQLITE_OK;
639fail:
640 SyMemBackendRelease(&pVm->sAlloc);
641 SyMemBackendPoolFree(&pDb->sMem,pVm);
642 return UNQLITE_NOMEM;
643}
644/*
645 * Release an active VM.
646 */
647static int unqliteVmRelease(unqlite_vm *pVm)
648{
649 /* Release the Jx9 VM */
650 jx9_vm_release(pVm->pJx9Vm);
651 /* Release the private memory backend */
652 SyMemBackendRelease(&pVm->sAlloc);
653 /* Upper layer will discard this VM from the list
654 * of active VM.
655 */
656 return UNQLITE_OK;
657}
658/*
659 * Return the default page size.
660 */
661UNQLITE_PRIVATE int unqliteGetPageSize(void)
662{
663 int iSize = sUnqlMPGlobal.iPageSize;
664 if( iSize < UNQLITE_MIN_PAGE_SIZE || iSize > UNQLITE_MAX_PAGE_SIZE ){
665 iSize = UNQLITE_DEFAULT_PAGE_SIZE;
666 }
667 return iSize;
668}
669/*
670 * Generate an error message.
671 */
672UNQLITE_PRIVATE int unqliteGenError(unqlite *pDb,const char *zErr)
673{
674 int rc;
675 /* Append the error message */
676 rc = SyBlobAppend(&pDb->sErr,(const void *)zErr,SyStrlen(zErr));
677 /* Append a new line */
678 SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char));
679 return rc;
680}
681/*
682 * Generate an error message (Printf like).
683 */
684UNQLITE_PRIVATE int unqliteGenErrorFormat(unqlite *pDb,const char *zFmt,...)
685{
686 va_list ap;
687 int rc;
688 va_start(ap,zFmt);
689 rc = SyBlobFormatAp(&pDb->sErr,zFmt,ap);
690 va_end(ap);
691 /* Append a new line */
692 SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char));
693 return rc;
694}
695/*
696 * Generate an error message (Out of memory).
697 */
698UNQLITE_PRIVATE int unqliteGenOutofMem(unqlite *pDb)
699{
700 int rc;
701 rc = unqliteGenError(pDb,"unQLite is running out of memory");
702 return rc;
703}
704/*
705 * Configure a working UnQLite database handle.
706 */
707static int unqliteConfigure(unqlite *pDb,int nOp,va_list ap)
708{
709 int rc = UNQLITE_OK;
710 switch(nOp){
711 case UNQLITE_CONFIG_JX9_ERR_LOG:
712 /* Jx9 compile-time error log */
713 rc = jx9EngineConfig(pDb->sDB.pJx9,JX9_CONFIG_ERR_LOG,ap);
714 break;
715 case UNQLITE_CONFIG_MAX_PAGE_CACHE: {
716 int max_page = va_arg(ap,int);
717 /* Maximum number of page to cache (Simple hint). */
718 rc = unqlitePagerSetCachesize(pDb->sDB.pPager,max_page);
719 break;
720 }
721 case UNQLITE_CONFIG_ERR_LOG: {
722 /* Database error log if any */
723 const char **pzPtr = va_arg(ap, const char **);
724 int *pLen = va_arg(ap, int *);
725 if( pzPtr == 0 ){
726 rc = JX9_CORRUPT;
727 break;
728 }
729 /* NULL terminate the error-log buffer */
730 SyBlobNullAppend(&pDb->sErr);
731 /* Point to the error-log buffer */
732 *pzPtr = (const char *)SyBlobData(&pDb->sErr);
733 if( pLen ){
734 if( SyBlobLength(&pDb->sErr) > 1 /* NULL '\0' terminator */ ){
735 *pLen = (int)SyBlobLength(&pDb->sErr);
736 }else{
737 *pLen = 0;
738 }
739 }
740 break;
741 }
742 case UNQLITE_CONFIG_DISABLE_AUTO_COMMIT:{
743 /* Disable auto-commit */
744 pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT;
745 break;
746 }
747 case UNQLITE_CONFIG_GET_KV_NAME: {
748 /* Name of the underlying KV storage engine */
749 const char **pzPtr = va_arg(ap,const char **);
750 if( pzPtr ){
751 unqlite_kv_engine *pEngine;
752 pEngine = unqlitePagerGetKvEngine(pDb);
753 /* Point to the name */
754 *pzPtr = pEngine->pIo->pMethods->zName;
755 }
756 break;
757 }
758 default:
759 /* Unknown configuration option */
760 rc = UNQLITE_UNKNOWN;
761 break;
762 }
763 return rc;
764}
765/*
766 * Export the global (master) memory allocator to submodules.
767 */
768UNQLITE_PRIVATE const SyMemBackend * unqliteExportMemBackend(void)
769{
770 return &sUnqlMPGlobal.sAllocator;
771}
772/*
773 * [CAPIREF: unqlite_open()]
774 * Please refer to the official documentation for function purpose and expected parameters.
775 */
776int unqlite_open(unqlite **ppDB,const char *zFilename,unsigned int iMode)
777{
778 unqlite *pHandle;
779 int rc;
780#if defined(UNTRUST)
781 if( ppDB == 0 ){
782 return UNQLITE_CORRUPT;
783 }
784#endif
785 *ppDB = 0;
786 /* One-time automatic library initialization */
787 rc = unqliteCoreInitialize();
788 if( rc != UNQLITE_OK ){
789 return rc;
790 }
791 /* Allocate a new database handle */
792 pHandle = (unqlite *)SyMemBackendPoolAlloc(&sUnqlMPGlobal.sAllocator, sizeof(unqlite));
793 if( pHandle == 0 ){
794 return UNQLITE_NOMEM;
795 }
796 /* Zero the structure */
797 SyZero(pHandle,sizeof(unqlite));
798 if( iMode < 1 ){
799 /* Assume a read-only database */
800 iMode = UNQLITE_OPEN_READONLY|UNQLITE_OPEN_MMAP;
801 }
802 /* Init the database */
803 rc = unqliteInitDatabase(pHandle,&sUnqlMPGlobal.sAllocator,zFilename,iMode);
804 if( rc != UNQLITE_OK ){
805 goto Release;
806 }
807#if defined(UNQLITE_ENABLE_THREADS)
808 if( !(iMode & UNQLITE_OPEN_NOMUTEX) && (sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE) ){
809 /* Associate a recursive mutex with this instance */
810 pHandle->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
811 if( pHandle->pMutex == 0 ){
812 rc = UNQLITE_NOMEM;
813 goto Release;
814 }
815 }
816#endif
817 /* Link to the list of active DB handles */
818#if defined(UNQLITE_ENABLE_THREADS)
819 /* Enter the global mutex */
820 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
821#endif
822 MACRO_LD_PUSH(sUnqlMPGlobal.pDB,pHandle);
823 sUnqlMPGlobal.nDB++;
824#if defined(UNQLITE_ENABLE_THREADS)
825 /* Leave the global mutex */
826 SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
827#endif
828 /* Set the magic number to identify a valid DB handle */
829 pHandle->nMagic = UNQLITE_DB_MAGIC;
830 /* Make the handle available to the caller */
831 *ppDB = pHandle;
832 return UNQLITE_OK;
833Release:
834 SyMemBackendRelease(&pHandle->sMem);
835 SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pHandle);
836 return rc;
837}
838/*
839 * [CAPIREF: unqlite_config()]
840 * Please refer to the official documentation for function purpose and expected parameters.
841 */
842int unqlite_config(unqlite *pDb,int nConfigOp,...)
843{
844 va_list ap;
845 int rc;
846 if( UNQLITE_DB_MISUSE(pDb) ){
847 return UNQLITE_CORRUPT;
848 }
849#if defined(UNQLITE_ENABLE_THREADS)
850 /* Acquire DB mutex */
851 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
852 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
853 UNQLITE_THRD_DB_RELEASE(pDb) ){
854 return UNQLITE_ABORT; /* Another thread have released this instance */
855 }
856#endif
857 va_start(ap, nConfigOp);
858 rc = unqliteConfigure(&(*pDb),nConfigOp, ap);
859 va_end(ap);
860#if defined(UNQLITE_ENABLE_THREADS)
861 /* Leave DB mutex */
862 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
863#endif
864 return rc;
865}
866/*
867 * [CAPIREF: unqlite_close()]
868 * Please refer to the official documentation for function purpose and expected parameters.
869 */
870int unqlite_close(unqlite *pDb)
871{
872 int rc;
873 if( UNQLITE_DB_MISUSE(pDb) ){
874 return UNQLITE_CORRUPT;
875 }
876#if defined(UNQLITE_ENABLE_THREADS)
877 /* Acquire DB mutex */
878 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
879 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
880 UNQLITE_THRD_DB_RELEASE(pDb) ){
881 return UNQLITE_ABORT; /* Another thread have released this instance */
882 }
883#endif
884 /* Release the database handle */
885 rc = unqliteDbRelease(pDb);
886#if defined(UNQLITE_ENABLE_THREADS)
887 /* Leave DB mutex */
888 SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
889 /* Release DB mutex */
890 SyMutexRelease(sUnqlMPGlobal.pMutexMethods, pDb->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
891#endif
892#if defined(UNQLITE_ENABLE_THREADS)
893 /* Enter the global mutex */
894 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
895#endif
896 /* Unlink from the list of active database handles */
897 MACRO_LD_REMOVE(sUnqlMPGlobal.pDB, pDb);
898 sUnqlMPGlobal.nDB--;
899#if defined(UNQLITE_ENABLE_THREADS)
900 /* Leave the global mutex */
901 SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */
902#endif
903 /* Release the memory chunk allocated to this handle */
904 SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pDb);
905 return rc;
906}
907/*
908 * [CAPIREF: unqlite_compile()]
909 * Please refer to the official documentation for function purpose and expected parameters.
910 */
911int unqlite_compile(unqlite *pDb,const char *zJx9,int nByte,unqlite_vm **ppOut)
912{
913 jx9_vm *pVm;
914 int rc;
915 if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){
916 return UNQLITE_CORRUPT;
917 }
918#if defined(UNQLITE_ENABLE_THREADS)
919 /* Acquire DB mutex */
920 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
921 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
922 UNQLITE_THRD_DB_RELEASE(pDb) ){
923 return UNQLITE_ABORT;
924 }
925#endif
926 /* Compile the Jx9 script first */
927 rc = jx9_compile(pDb->sDB.pJx9,zJx9,nByte,&pVm);
928 if( rc == JX9_OK ){
929 /* Allocate a new unqlite VM instance */
930 rc = unqliteInitVm(pDb,pVm,ppOut);
931 if( rc != UNQLITE_OK ){
932 /* Release the Jx9 VM */
933 jx9_vm_release(pVm);
934 }
935 }
936#if defined(UNQLITE_ENABLE_THREADS)
937 /* Leave DB mutex */
938 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
939#endif
940 return rc;
941}
942/*
943 * [CAPIREF: unqlite_compile_file()]
944 * Please refer to the official documentation for function purpose and expected parameters.
945 */
946int unqlite_compile_file(unqlite *pDb,const char *zPath,unqlite_vm **ppOut)
947{
948 jx9_vm *pVm;
949 int rc;
950 if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){
951 return UNQLITE_CORRUPT;
952 }
953#if defined(UNQLITE_ENABLE_THREADS)
954 /* Acquire DB mutex */
955 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
956 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
957 UNQLITE_THRD_DB_RELEASE(pDb) ){
958 return UNQLITE_ABORT;
959 }
960#endif
961 /* Compile the Jx9 script first */
962 rc = jx9_compile_file(pDb->sDB.pJx9,zPath,&pVm);
963 if( rc == JX9_OK ){
964 /* Allocate a new unqlite VM instance */
965 rc = unqliteInitVm(pDb,pVm,ppOut);
966 if( rc != UNQLITE_OK ){
967 /* Release the Jx9 VM */
968 jx9_vm_release(pVm);
969 }
970 }
971#if defined(UNQLITE_ENABLE_THREADS)
972 /* Leave DB mutex */
973 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
974#endif
975 return rc;
976}
977/*
978 * Configure an unqlite virtual machine (Mostly Jx9 VM) instance.
979 */
980static int unqliteVmConfig(unqlite_vm *pVm,sxi32 iOp,va_list ap)
981{
982 int rc;
983 rc = jx9VmConfigure(pVm->pJx9Vm,iOp,ap);
984 return rc;
985}
986/*
987 * [CAPIREF: unqlite_vm_config()]
988 * Please refer to the official documentation for function purpose and expected parameters.
989 */
990int unqlite_vm_config(unqlite_vm *pVm,int iOp,...)
991{
992 va_list ap;
993 int rc;
994 if( UNQLITE_VM_MISUSE(pVm) ){
995 return UNQLITE_CORRUPT;
996 }
997#if defined(UNQLITE_ENABLE_THREADS)
998 /* Acquire VM mutex */
999 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1000 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1001 UNQLITE_THRD_VM_RELEASE(pVm) ){
1002 return UNQLITE_ABORT; /* Another thread have released this instance */
1003 }
1004#endif
1005 va_start(ap,iOp);
1006 rc = unqliteVmConfig(pVm,iOp,ap);
1007 va_end(ap);
1008#if defined(UNQLITE_ENABLE_THREADS)
1009 /* Leave DB mutex */
1010 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1011#endif
1012 return rc;
1013}
1014/*
1015 * [CAPIREF: unqlite_vm_exec()]
1016 * Please refer to the official documentation for function purpose and expected parameters.
1017 */
1018int unqlite_vm_exec(unqlite_vm *pVm)
1019{
1020 int rc;
1021 if( UNQLITE_VM_MISUSE(pVm) ){
1022 return UNQLITE_CORRUPT;
1023 }
1024#if defined(UNQLITE_ENABLE_THREADS)
1025 /* Acquire VM mutex */
1026 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1027 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1028 UNQLITE_THRD_VM_RELEASE(pVm) ){
1029 return UNQLITE_ABORT; /* Another thread have released this instance */
1030 }
1031#endif
1032 /* Execute the Jx9 bytecode program */
1033 rc = jx9VmByteCodeExec(pVm->pJx9Vm);
1034#if defined(UNQLITE_ENABLE_THREADS)
1035 /* Leave DB mutex */
1036 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1037#endif
1038 return rc;
1039}
1040/*
1041 * [CAPIREF: unqlite_vm_release()]
1042 * Please refer to the official documentation for function purpose and expected parameters.
1043 */
1044int unqlite_vm_release(unqlite_vm *pVm)
1045{
1046 int rc;
1047 if( UNQLITE_VM_MISUSE(pVm) ){
1048 return UNQLITE_CORRUPT;
1049 }
1050#if defined(UNQLITE_ENABLE_THREADS)
1051 /* Acquire VM mutex */
1052 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1053 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1054 UNQLITE_THRD_VM_RELEASE(pVm) ){
1055 return UNQLITE_ABORT; /* Another thread have released this instance */
1056 }
1057#endif
1058 /* Release the VM */
1059 rc = unqliteVmRelease(pVm);
1060#if defined(UNQLITE_ENABLE_THREADS)
1061 /* Leave VM mutex */
1062 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1063 /* Release VM mutex */
1064 SyMutexRelease(sUnqlMPGlobal.pMutexMethods,pVm->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1065#endif
1066 if( rc == UNQLITE_OK ){
1067 unqlite *pDb = pVm->pDb;
1068 /* Unlink from the list of active VM's */
1069#if defined(UNQLITE_ENABLE_THREADS)
1070 /* Acquire DB mutex */
1071 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1072 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1073 UNQLITE_THRD_DB_RELEASE(pDb) ){
1074 return UNQLITE_ABORT; /* Another thread have released this instance */
1075 }
1076#endif
1077 MACRO_LD_REMOVE(pDb->pVms, pVm);
1078 pDb->iVm--;
1079 /* Release the memory chunk allocated to this instance */
1080 SyMemBackendPoolFree(&pDb->sMem,pVm);
1081#if defined(UNQLITE_ENABLE_THREADS)
1082 /* Leave DB mutex */
1083 SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1084#endif
1085 }
1086 return rc;
1087}
1088/*
1089 * [CAPIREF: unqlite_vm_reset()]
1090 * Please refer to the official documentation for function purpose and expected parameters.
1091 */
1092int unqlite_vm_reset(unqlite_vm *pVm)
1093{
1094 int rc;
1095 if( UNQLITE_VM_MISUSE(pVm) ){
1096 return UNQLITE_CORRUPT;
1097 }
1098#if defined(UNQLITE_ENABLE_THREADS)
1099 /* Acquire VM mutex */
1100 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1101 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1102 UNQLITE_THRD_VM_RELEASE(pVm) ){
1103 return UNQLITE_ABORT; /* Another thread have released this instance */
1104 }
1105#endif
1106 /* Reset the Jx9 VM */
1107 rc = jx9VmReset(pVm->pJx9Vm);
1108#if defined(UNQLITE_ENABLE_THREADS)
1109 /* Leave DB mutex */
1110 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1111#endif
1112 return rc;
1113}
1114/*
1115 * [CAPIREF: unqlite_vm_dump()]
1116 * Please refer to the official documentation for function purpose and expected parameters.
1117 */
1118int unqlite_vm_dump(unqlite_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData)
1119{
1120 int rc;
1121 if( UNQLITE_VM_MISUSE(pVm) ){
1122 return UNQLITE_CORRUPT;
1123 }
1124#if defined(UNQLITE_ENABLE_THREADS)
1125 /* Acquire VM mutex */
1126 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1127 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1128 UNQLITE_THRD_VM_RELEASE(pVm) ){
1129 return UNQLITE_ABORT; /* Another thread have released this instance */
1130 }
1131#endif
1132 /* Dump the Jx9 VM */
1133 rc = jx9VmDump(pVm->pJx9Vm,xConsumer,pUserData);
1134#if defined(UNQLITE_ENABLE_THREADS)
1135 /* Leave DB mutex */
1136 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1137#endif
1138 return rc;
1139}
1140/*
1141 * [CAPIREF: unqlite_vm_extract_variable()]
1142 * Please refer to the official documentation for function purpose and expected parameters.
1143 */
1144unqlite_value * unqlite_vm_extract_variable(unqlite_vm *pVm,const char *zVarname)
1145{
1146 unqlite_value *pValue;
1147 SyString sVariable;
1148 if( UNQLITE_VM_MISUSE(pVm) ){
1149 return 0;
1150 }
1151#if defined(UNQLITE_ENABLE_THREADS)
1152 /* Acquire VM mutex */
1153 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1154 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1155 UNQLITE_THRD_VM_RELEASE(pVm) ){
1156 return 0; /* Another thread have released this instance */
1157 }
1158#endif
1159 /* Extract the target variable */
1160 SyStringInitFromBuf(&sVariable,zVarname,SyStrlen(zVarname));
1161 pValue = jx9VmExtractVariable(pVm->pJx9Vm,&sVariable);
1162#if defined(UNQLITE_ENABLE_THREADS)
1163 /* Leave DB mutex */
1164 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1165#endif
1166 return pValue;
1167}
1168/*
1169 * [CAPIREF: unqlite_create_function()]
1170 * Please refer to the official documentation for function purpose and expected parameters.
1171 */
1172int unqlite_create_function(unqlite_vm *pVm, const char *zName,int (*xFunc)(unqlite_context *,int,unqlite_value **),void *pUserData)
1173{
1174 SyString sName;
1175 int rc;
1176 if( UNQLITE_VM_MISUSE(pVm) ){
1177 return UNQLITE_CORRUPT;
1178 }
1179 SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
1180 /* Remove leading and trailing white spaces */
1181 SyStringFullTrim(&sName);
1182 /* Ticket 1433-003: NULL values are not allowed */
1183 if( sName.nByte < 1 || xFunc == 0 ){
1184 return UNQLITE_INVALID;
1185 }
1186#if defined(UNQLITE_ENABLE_THREADS)
1187 /* Acquire VM mutex */
1188 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1189 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1190 UNQLITE_THRD_VM_RELEASE(pVm) ){
1191 return UNQLITE_ABORT; /* Another thread have released this instance */
1192 }
1193#endif
1194 /* Install the foreign function */
1195 rc = jx9VmInstallForeignFunction(pVm->pJx9Vm,&sName,xFunc,pUserData);
1196#if defined(UNQLITE_ENABLE_THREADS)
1197 /* Leave DB mutex */
1198 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1199#endif
1200 return rc;
1201}
1202/*
1203 * [CAPIREF: unqlite_delete_function()]
1204 * Please refer to the official documentation for function purpose and expected parameters.
1205 */
1206int unqlite_delete_function(unqlite_vm *pVm, const char *zName)
1207{
1208 int rc;
1209 if( UNQLITE_VM_MISUSE(pVm) ){
1210 return UNQLITE_CORRUPT;
1211 }
1212#if defined(UNQLITE_ENABLE_THREADS)
1213 /* Acquire VM mutex */
1214 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1215 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1216 UNQLITE_THRD_VM_RELEASE(pVm) ){
1217 return UNQLITE_ABORT; /* Another thread have released this instance */
1218 }
1219#endif
1220 /* Unlink the foreign function */
1221 rc = jx9DeleteFunction(pVm->pJx9Vm,zName);
1222#if defined(UNQLITE_ENABLE_THREADS)
1223 /* Leave DB mutex */
1224 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1225#endif
1226 return rc;
1227}
1228/*
1229 * [CAPIREF: unqlite_create_constant()]
1230 * Please refer to the official documentation for function purpose and expected parameters.
1231 */
1232int unqlite_create_constant(unqlite_vm *pVm,const char *zName,void (*xExpand)(unqlite_value *, void *),void *pUserData)
1233{
1234 SyString sName;
1235 int rc;
1236 if( UNQLITE_VM_MISUSE(pVm) ){
1237 return UNQLITE_CORRUPT;
1238 }
1239 SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
1240 /* Remove leading and trailing white spaces */
1241 SyStringFullTrim(&sName);
1242 if( sName.nByte < 1 ){
1243 /* Empty constant name */
1244 return UNQLITE_INVALID;
1245 }
1246 /* TICKET 1433-003: NULL pointer is harmless operation */
1247 if( xExpand == 0 ){
1248 return UNQLITE_INVALID;
1249 }
1250#if defined(UNQLITE_ENABLE_THREADS)
1251 /* Acquire VM mutex */
1252 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1253 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1254 UNQLITE_THRD_VM_RELEASE(pVm) ){
1255 return UNQLITE_ABORT; /* Another thread have released this instance */
1256 }
1257#endif
1258 /* Install the foreign constant */
1259 rc = jx9VmRegisterConstant(pVm->pJx9Vm,&sName,xExpand,pUserData);
1260#if defined(UNQLITE_ENABLE_THREADS)
1261 /* Leave DB mutex */
1262 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1263#endif
1264 return rc;
1265}
1266/*
1267 * [CAPIREF: unqlite_delete_constant()]
1268 * Please refer to the official documentation for function purpose and expected parameters.
1269 */
1270int unqlite_delete_constant(unqlite_vm *pVm, const char *zName)
1271{
1272 int rc;
1273 if( UNQLITE_VM_MISUSE(pVm) ){
1274 return UNQLITE_CORRUPT;
1275 }
1276#if defined(UNQLITE_ENABLE_THREADS)
1277 /* Acquire VM mutex */
1278 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1279 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1280 UNQLITE_THRD_VM_RELEASE(pVm) ){
1281 return UNQLITE_ABORT; /* Another thread have released this instance */
1282 }
1283#endif
1284 /* Unlink the foreign constant */
1285 rc = Jx9DeleteConstant(pVm->pJx9Vm,zName);
1286#if defined(UNQLITE_ENABLE_THREADS)
1287 /* Leave DB mutex */
1288 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1289#endif
1290 return rc;
1291}
1292/*
1293 * [CAPIREF: unqlite_value_int()]
1294 * Please refer to the official documentation for function purpose and expected parameters.
1295 */
1296int unqlite_value_int(unqlite_value *pVal, int iValue)
1297{
1298 return jx9_value_int(pVal,iValue);
1299}
1300/*
1301 * [CAPIREF: unqlite_value_int64()]
1302 * Please refer to the official documentation for function purpose and expected parameters.
1303 */
1304int unqlite_value_int64(unqlite_value *pVal,unqlite_int64 iValue)
1305{
1306 return jx9_value_int64(pVal,iValue);
1307}
1308/*
1309 * [CAPIREF: unqlite_value_bool()]
1310 * Please refer to the official documentation for function purpose and expected parameters.
1311 */
1312int unqlite_value_bool(unqlite_value *pVal, int iBool)
1313{
1314 return jx9_value_bool(pVal,iBool);
1315}
1316/*
1317 * [CAPIREF: unqlite_value_null()]
1318 * Please refer to the official documentation for function purpose and expected parameters.
1319 */
1320int unqlite_value_null(unqlite_value *pVal)
1321{
1322 return jx9_value_null(pVal);
1323}
1324/*
1325 * [CAPIREF: unqlite_value_double()]
1326 * Please refer to the official documentation for function purpose and expected parameters.
1327 */
1328int unqlite_value_double(unqlite_value *pVal, double Value)
1329{
1330 return jx9_value_double(pVal,Value);
1331}
1332/*
1333 * [CAPIREF: unqlite_value_string()]
1334 * Please refer to the official documentation for function purpose and expected parameters.
1335 */
1336int unqlite_value_string(unqlite_value *pVal, const char *zString, int nLen)
1337{
1338 return jx9_value_string(pVal,zString,nLen);
1339}
1340/*
1341 * [CAPIREF: unqlite_value_string_format()]
1342 * Please refer to the official documentation for function purpose and expected parameters.
1343 */
1344int unqlite_value_string_format(unqlite_value *pVal, const char *zFormat,...)
1345{
1346 va_list ap;
1347 int rc;
1348 if((pVal->iFlags & MEMOBJ_STRING) == 0 ){
1349 /* Invalidate any prior representation */
1350 jx9MemObjRelease(pVal);
1351 MemObjSetType(pVal, MEMOBJ_STRING);
1352 }
1353 va_start(ap, zFormat);
1354 rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap);
1355 va_end(ap);
1356 return UNQLITE_OK;
1357}
1358/*
1359 * [CAPIREF: unqlite_value_reset_string_cursor()]
1360 * Please refer to the official documentation for function purpose and expected parameters.
1361 */
1362int unqlite_value_reset_string_cursor(unqlite_value *pVal)
1363{
1364 return jx9_value_reset_string_cursor(pVal);
1365}
1366/*
1367 * [CAPIREF: unqlite_value_resource()]
1368 * Please refer to the official documentation for function purpose and expected parameters.
1369 */
1370int unqlite_value_resource(unqlite_value *pVal,void *pUserData)
1371{
1372 return jx9_value_resource(pVal,pUserData);
1373}
1374/*
1375 * [CAPIREF: unqlite_value_release()]
1376 * Please refer to the official documentation for function purpose and expected parameters.
1377 */
1378int unqlite_value_release(unqlite_value *pVal)
1379{
1380 return jx9_value_release(pVal);
1381}
1382/*
1383 * [CAPIREF: unqlite_value_to_int()]
1384 * Please refer to the official documentation for function purpose and expected parameters.
1385 */
1386int unqlite_value_to_int(unqlite_value *pValue)
1387{
1388 return jx9_value_to_int(pValue);
1389}
1390/*
1391 * [CAPIREF: unqlite_value_to_bool()]
1392 * Please refer to the official documentation for function purpose and expected parameters.
1393 */
1394int unqlite_value_to_bool(unqlite_value *pValue)
1395{
1396 return jx9_value_to_bool(pValue);
1397}
1398/*
1399 * [CAPIREF: unqlite_value_to_int64()]
1400 * Please refer to the official documentation for function purpose and expected parameters.
1401 */
1402unqlite_int64 unqlite_value_to_int64(unqlite_value *pValue)
1403{
1404 return jx9_value_to_int64(pValue);
1405}
1406/*
1407 * [CAPIREF: unqlite_value_to_double()]
1408 * Please refer to the official documentation for function purpose and expected parameters.
1409 */
1410double unqlite_value_to_double(unqlite_value *pValue)
1411{
1412 return jx9_value_to_double(pValue);
1413}
1414/*
1415 * [CAPIREF: unqlite_value_to_string()]
1416 * Please refer to the official documentation for function purpose and expected parameters.
1417 */
1418const char * unqlite_value_to_string(unqlite_value *pValue, int *pLen)
1419{
1420 return jx9_value_to_string(pValue,pLen);
1421}
1422/*
1423 * [CAPIREF: unqlite_value_to_resource()]
1424 * Please refer to the official documentation for function purpose and expected parameters.
1425 */
1426void * unqlite_value_to_resource(unqlite_value *pValue)
1427{
1428 return jx9_value_to_resource(pValue);
1429}
1430/*
1431 * [CAPIREF: unqlite_value_compare()]
1432 * Please refer to the official documentation for function purpose and expected parameters.
1433 */
1434int unqlite_value_compare(unqlite_value *pLeft, unqlite_value *pRight, int bStrict)
1435{
1436 return jx9_value_compare(pLeft,pRight,bStrict);
1437}
1438/*
1439 * [CAPIREF: unqlite_result_int()]
1440 * Please refer to the official documentation for function purpose and expected parameters.
1441 */
1442int unqlite_result_int(unqlite_context *pCtx, int iValue)
1443{
1444 return jx9_result_int(pCtx,iValue);
1445}
1446/*
1447 * [CAPIREF: unqlite_result_int64()]
1448 * Please refer to the official documentation for function purpose and expected parameters.
1449 */
1450int unqlite_result_int64(unqlite_context *pCtx, unqlite_int64 iValue)
1451{
1452 return jx9_result_int64(pCtx,iValue);
1453}
1454/*
1455 * [CAPIREF: unqlite_result_bool()]
1456 * Please refer to the official documentation for function purpose and expected parameters.
1457 */
1458int unqlite_result_bool(unqlite_context *pCtx, int iBool)
1459{
1460 return jx9_result_bool(pCtx,iBool);
1461}
1462/*
1463 * [CAPIREF: unqlite_result_double()]
1464 * Please refer to the official documentation for function purpose and expected parameters.
1465 */
1466int unqlite_result_double(unqlite_context *pCtx, double Value)
1467{
1468 return jx9_result_double(pCtx,Value);
1469}
1470/*
1471 * [CAPIREF: unqlite_result_null()]
1472 * Please refer to the official documentation for function purpose and expected parameters.
1473 */
1474int unqlite_result_null(unqlite_context *pCtx)
1475{
1476 return jx9_result_null(pCtx);
1477}
1478/*
1479 * [CAPIREF: unqlite_result_string()]
1480 * Please refer to the official documentation for function purpose and expected parameters.
1481 */
1482int unqlite_result_string(unqlite_context *pCtx, const char *zString, int nLen)
1483{
1484 return jx9_result_string(pCtx,zString,nLen);
1485}
1486/*
1487 * [CAPIREF: unqlite_result_string_format()]
1488 * Please refer to the official documentation for function purpose and expected parameters.
1489 */
1490int unqlite_result_string_format(unqlite_context *pCtx, const char *zFormat, ...)
1491{
1492 jx9_value *p;
1493 va_list ap;
1494 int rc;
1495 p = pCtx->pRet;
1496 if( (p->iFlags & MEMOBJ_STRING) == 0 ){
1497 /* Invalidate any prior representation */
1498 jx9MemObjRelease(p);
1499 MemObjSetType(p, MEMOBJ_STRING);
1500 }
1501 /* Format the given string */
1502 va_start(ap, zFormat);
1503 rc = SyBlobFormatAp(&p->sBlob, zFormat, ap);
1504 va_end(ap);
1505 return rc;
1506}
1507/*
1508 * [CAPIREF: unqlite_result_value()]
1509 * Please refer to the official documentation for function purpose and expected parameters.
1510 */
1511int unqlite_result_value(unqlite_context *pCtx, unqlite_value *pValue)
1512{
1513 return jx9_result_value(pCtx,pValue);
1514}
1515/*
1516 * [CAPIREF: unqlite_result_resource()]
1517 * Please refer to the official documentation for function purpose and expected parameters.
1518 */
1519int unqlite_result_resource(unqlite_context *pCtx, void *pUserData)
1520{
1521 return jx9_result_resource(pCtx,pUserData);
1522}
1523/*
1524 * [CAPIREF: unqlite_value_is_int()]
1525 * Please refer to the official documentation for function purpose and expected parameters.
1526 */
1527int unqlite_value_is_int(unqlite_value *pVal)
1528{
1529 return jx9_value_is_int(pVal);
1530}
1531/*
1532 * [CAPIREF: unqlite_value_is_float()]
1533 * Please refer to the official documentation for function purpose and expected parameters.
1534 */
1535int unqlite_value_is_float(unqlite_value *pVal)
1536{
1537 return jx9_value_is_float(pVal);
1538}
1539/*
1540 * [CAPIREF: unqlite_value_is_bool()]
1541 * Please refer to the official documentation for function purpose and expected parameters.
1542 */
1543int unqlite_value_is_bool(unqlite_value *pVal)
1544{
1545 return jx9_value_is_bool(pVal);
1546}
1547/*
1548 * [CAPIREF: unqlite_value_is_string()]
1549 * Please refer to the official documentation for function purpose and expected parameters.
1550 */
1551int unqlite_value_is_string(unqlite_value *pVal)
1552{
1553 return jx9_value_is_string(pVal);
1554}
1555/*
1556 * [CAPIREF: unqlite_value_is_null()]
1557 * Please refer to the official documentation for function purpose and expected parameters.
1558 */
1559int unqlite_value_is_null(unqlite_value *pVal)
1560{
1561 return jx9_value_is_null(pVal);
1562}
1563/*
1564 * [CAPIREF: unqlite_value_is_numeric()]
1565 * Please refer to the official documentation for function purpose and expected parameters.
1566 */
1567int unqlite_value_is_numeric(unqlite_value *pVal)
1568{
1569 return jx9_value_is_numeric(pVal);
1570}
1571/*
1572 * [CAPIREF: unqlite_value_is_callable()]
1573 * Please refer to the official documentation for function purpose and expected parameters.
1574 */
1575int unqlite_value_is_callable(unqlite_value *pVal)
1576{
1577 return jx9_value_is_callable(pVal);
1578}
1579/*
1580 * [CAPIREF: unqlite_value_is_scalar()]
1581 * Please refer to the official documentation for function purpose and expected parameters.
1582 */
1583int unqlite_value_is_scalar(unqlite_value *pVal)
1584{
1585 return jx9_value_is_scalar(pVal);
1586}
1587/*
1588 * [CAPIREF: unqlite_value_is_json_array()]
1589 * Please refer to the official documentation for function purpose and expected parameters.
1590 */
1591int unqlite_value_is_json_array(unqlite_value *pVal)
1592{
1593 return jx9_value_is_json_array(pVal);
1594}
1595/*
1596 * [CAPIREF: unqlite_value_is_json_object()]
1597 * Please refer to the official documentation for function purpose and expected parameters.
1598 */
1599int unqlite_value_is_json_object(unqlite_value *pVal)
1600{
1601 return jx9_value_is_json_object(pVal);
1602}
1603/*
1604 * [CAPIREF: unqlite_value_is_resource()]
1605 * Please refer to the official documentation for function purpose and expected parameters.
1606 */
1607int unqlite_value_is_resource(unqlite_value *pVal)
1608{
1609 return jx9_value_is_resource(pVal);
1610}
1611/*
1612 * [CAPIREF: unqlite_value_is_empty()]
1613 * Please refer to the official documentation for function purpose and expected parameters.
1614 */
1615int unqlite_value_is_empty(unqlite_value *pVal)
1616{
1617 return jx9_value_is_empty(pVal);
1618}
1619/*
1620 * [CAPIREF: unqlite_array_fetch()]
1621 * Please refer to the official documentation for function purpose and expected parameters.
1622 */
1623unqlite_value * unqlite_array_fetch(unqlite_value *pArray, const char *zKey, int nByte)
1624{
1625 return jx9_array_fetch(pArray,zKey,nByte);
1626}
1627/*
1628 * [CAPIREF: unqlite_array_walk()]
1629 * Please refer to the official documentation for function purpose and expected parameters.
1630 */
1631int unqlite_array_walk(unqlite_value *pArray, int (*xWalk)(unqlite_value *, unqlite_value *, void *), void *pUserData)
1632{
1633 return jx9_array_walk(pArray,xWalk,pUserData);
1634}
1635/*
1636 * [CAPIREF: unqlite_array_add_elem()]
1637 * Please refer to the official documentation for function purpose and expected parameters.
1638 */
1639int unqlite_array_add_elem(unqlite_value *pArray, unqlite_value *pKey, unqlite_value *pValue)
1640{
1641 return jx9_array_add_elem(pArray,pKey,pValue);
1642}
1643/*
1644 * [CAPIREF: unqlite_array_add_strkey_elem()]
1645 * Please refer to the official documentation for function purpose and expected parameters.
1646 */
1647int unqlite_array_add_strkey_elem(unqlite_value *pArray, const char *zKey, unqlite_value *pValue)
1648{
1649 return jx9_array_add_strkey_elem(pArray,zKey,pValue);
1650}
1651/*
1652 * [CAPIREF: unqlite_array_count()]
1653 * Please refer to the official documentation for function purpose and expected parameters.
1654 */
1655int unqlite_array_count(unqlite_value *pArray)
1656{
1657 return (int)jx9_array_count(pArray);
1658}
1659/*
1660 * [CAPIREF: unqlite_vm_new_scalar()]
1661 * Please refer to the official documentation for function purpose and expected parameters.
1662 */
1663unqlite_value * unqlite_vm_new_scalar(unqlite_vm *pVm)
1664{
1665 unqlite_value *pValue;
1666 if( UNQLITE_VM_MISUSE(pVm) ){
1667 return 0;
1668 }
1669#if defined(UNQLITE_ENABLE_THREADS)
1670 /* Acquire VM mutex */
1671 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1672 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1673 UNQLITE_THRD_VM_RELEASE(pVm) ){
1674 return 0; /* Another thread have released this instance */
1675 }
1676#endif
1677 pValue = jx9_new_scalar(pVm->pJx9Vm);
1678#if defined(UNQLITE_ENABLE_THREADS)
1679 /* Leave DB mutex */
1680 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1681#endif
1682 return pValue;
1683}
1684/*
1685 * [CAPIREF: unqlite_vm_new_array()]
1686 * Please refer to the official documentation for function purpose and expected parameters.
1687 */
1688unqlite_value * unqlite_vm_new_array(unqlite_vm *pVm)
1689{
1690 unqlite_value *pValue;
1691 if( UNQLITE_VM_MISUSE(pVm) ){
1692 return 0;
1693 }
1694#if defined(UNQLITE_ENABLE_THREADS)
1695 /* Acquire VM mutex */
1696 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1697 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1698 UNQLITE_THRD_VM_RELEASE(pVm) ){
1699 return 0; /* Another thread have released this instance */
1700 }
1701#endif
1702 pValue = jx9_new_array(pVm->pJx9Vm);
1703#if defined(UNQLITE_ENABLE_THREADS)
1704 /* Leave DB mutex */
1705 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1706#endif
1707 return pValue;
1708}
1709/*
1710 * [CAPIREF: unqlite_vm_release_value()]
1711 * Please refer to the official documentation for function purpose and expected parameters.
1712 */
1713int unqlite_vm_release_value(unqlite_vm *pVm,unqlite_value *pValue)
1714{
1715 int rc;
1716 if( UNQLITE_VM_MISUSE(pVm) ){
1717 return UNQLITE_CORRUPT;
1718 }
1719#if defined(UNQLITE_ENABLE_THREADS)
1720 /* Acquire VM mutex */
1721 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1722 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1723 UNQLITE_THRD_VM_RELEASE(pVm) ){
1724 return UNQLITE_ABORT; /* Another thread have released this instance */
1725 }
1726#endif
1727 rc = jx9_release_value(pVm->pJx9Vm,pValue);
1728#if defined(UNQLITE_ENABLE_THREADS)
1729 /* Leave DB mutex */
1730 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1731#endif
1732 return rc;
1733}
1734/*
1735 * [CAPIREF: unqlite_context_output()]
1736 * Please refer to the official documentation for function purpose and expected parameters.
1737 */
1738int unqlite_context_output(unqlite_context *pCtx, const char *zString, int nLen)
1739{
1740 return jx9_context_output(pCtx,zString,nLen);
1741}
1742/*
1743 * [CAPIREF: unqlite_context_output_format()]
1744 * Please refer to the official documentation for function purpose and expected parameters.
1745 */
1746int unqlite_context_output_format(unqlite_context *pCtx,const char *zFormat, ...)
1747{
1748 va_list ap;
1749 int rc;
1750 va_start(ap, zFormat);
1751 rc = jx9VmOutputConsumeAp(pCtx->pVm,zFormat, ap);
1752 va_end(ap);
1753 return rc;
1754}
1755/*
1756 * [CAPIREF: unqlite_context_throw_error()]
1757 * Please refer to the official documentation for function purpose and expected parameters.
1758 */
1759int unqlite_context_throw_error(unqlite_context *pCtx, int iErr, const char *zErr)
1760{
1761 return jx9_context_throw_error(pCtx,iErr,zErr);
1762}
1763/*
1764 * [CAPIREF: unqlite_context_throw_error_format()]
1765 * Please refer to the official documentation for function purpose and expected parameters.
1766 */
1767int unqlite_context_throw_error_format(unqlite_context *pCtx, int iErr, const char *zFormat, ...)
1768{
1769 va_list ap;
1770 int rc;
1771 if( zFormat == 0){
1772 return JX9_OK;
1773 }
1774 va_start(ap, zFormat);
1775 rc = jx9VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap);
1776 va_end(ap);
1777 return rc;
1778}
1779/*
1780 * [CAPIREF: unqlite_context_random_num()]
1781 * Please refer to the official documentation for function purpose and expected parameters.
1782 */
1783unsigned int unqlite_context_random_num(unqlite_context *pCtx)
1784{
1785 return jx9_context_random_num(pCtx);
1786}
1787/*
1788 * [CAPIREF: unqlite_context_random_string()]
1789 * Please refer to the official documentation for function purpose and expected parameters.
1790 */
1791int unqlite_context_random_string(unqlite_context *pCtx, char *zBuf, int nBuflen)
1792{
1793 return jx9_context_random_string(pCtx,zBuf,nBuflen);
1794}
1795/*
1796 * [CAPIREF: unqlite_context_user_data()]
1797 * Please refer to the official documentation for function purpose and expected parameters.
1798 */
1799void * unqlite_context_user_data(unqlite_context *pCtx)
1800{
1801 return jx9_context_user_data(pCtx);
1802}
1803/*
1804 * [CAPIREF: unqlite_context_push_aux_data()]
1805 * Please refer to the official documentation for function purpose and expected parameters.
1806 */
1807int unqlite_context_push_aux_data(unqlite_context *pCtx, void *pUserData)
1808{
1809 return jx9_context_push_aux_data(pCtx,pUserData);
1810}
1811/*
1812 * [CAPIREF: unqlite_context_peek_aux_data()]
1813 * Please refer to the official documentation for function purpose and expected parameters.
1814 */
1815void * unqlite_context_peek_aux_data(unqlite_context *pCtx)
1816{
1817 return jx9_context_peek_aux_data(pCtx);
1818}
1819/*
1820 * [CAPIREF: unqlite_context_pop_aux_data()]
1821 * Please refer to the official documentation for function purpose and expected parameters.
1822 */
1823void * unqlite_context_pop_aux_data(unqlite_context *pCtx)
1824{
1825 return jx9_context_pop_aux_data(pCtx);
1826}
1827/*
1828 * [CAPIREF: unqlite_context_result_buf_length()]
1829 * Please refer to the official documentation for function purpose and expected parameters.
1830 */
1831unsigned int unqlite_context_result_buf_length(unqlite_context *pCtx)
1832{
1833 return jx9_context_result_buf_length(pCtx);
1834}
1835/*
1836 * [CAPIREF: unqlite_function_name()]
1837 * Please refer to the official documentation for function purpose and expected parameters.
1838 */
1839const char * unqlite_function_name(unqlite_context *pCtx)
1840{
1841 return jx9_function_name(pCtx);
1842}
1843/*
1844 * [CAPIREF: unqlite_context_new_scalar()]
1845 * Please refer to the official documentation for function purpose and expected parameters.
1846 */
1847unqlite_value * unqlite_context_new_scalar(unqlite_context *pCtx)
1848{
1849 return jx9_context_new_scalar(pCtx);
1850}
1851/*
1852 * [CAPIREF: unqlite_context_new_array()]
1853 * Please refer to the official documentation for function purpose and expected parameters.
1854 */
1855unqlite_value * unqlite_context_new_array(unqlite_context *pCtx)
1856{
1857 return jx9_context_new_array(pCtx);
1858}
1859/*
1860 * [CAPIREF: unqlite_context_release_value()]
1861 * Please refer to the official documentation for function purpose and expected parameters.
1862 */
1863void unqlite_context_release_value(unqlite_context *pCtx,unqlite_value *pValue)
1864{
1865 jx9_context_release_value(pCtx,pValue);
1866}
1867/*
1868 * [CAPIREF: unqlite_context_alloc_chunk()]
1869 * Please refer to the official documentation for function purpose and expected parameters.
1870 */
1871void * unqlite_context_alloc_chunk(unqlite_context *pCtx,unsigned int nByte,int ZeroChunk,int AutoRelease)
1872{
1873 return jx9_context_alloc_chunk(pCtx,nByte,ZeroChunk,AutoRelease);
1874}
1875/*
1876 * [CAPIREF: unqlite_context_realloc_chunk()]
1877 * Please refer to the official documentation for function purpose and expected parameters.
1878 */
1879void * unqlite_context_realloc_chunk(unqlite_context *pCtx,void *pChunk,unsigned int nByte)
1880{
1881 return jx9_context_realloc_chunk(pCtx,pChunk,nByte);
1882}
1883/*
1884 * [CAPIREF: unqlite_context_free_chunk()]
1885 * Please refer to the official documentation for function purpose and expected parameters.
1886 */
1887void unqlite_context_free_chunk(unqlite_context *pCtx,void *pChunk)
1888{
1889 jx9_context_free_chunk(pCtx,pChunk);
1890}
1891/*
1892 * [CAPIREF: unqlite_kv_store()]
1893 * Please refer to the official documentation for function purpose and expected parameters.
1894 */
1895int unqlite_kv_store(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen)
1896{
1897 unqlite_kv_engine *pEngine;
1898 int rc;
1899 if( UNQLITE_DB_MISUSE(pDb) ){
1900 return UNQLITE_CORRUPT;
1901 }
1902#if defined(UNQLITE_ENABLE_THREADS)
1903 /* Acquire DB mutex */
1904 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1905 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1906 UNQLITE_THRD_DB_RELEASE(pDb) ){
1907 return UNQLITE_ABORT; /* Another thread have released this instance */
1908 }
1909#endif
1910 /* Point to the underlying storage engine */
1911 pEngine = unqlitePagerGetKvEngine(pDb);
1912 if( pEngine->pIo->pMethods->xReplace == 0 ){
1913 /* Storage engine does not implement such method */
1914 unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine");
1915 rc = UNQLITE_NOTIMPLEMENTED;
1916 }else{
1917 if( nKeyLen < 0 ){
1918 /* Assume a null terminated string and compute it's length */
1919 nKeyLen = SyStrlen((const char *)pKey);
1920 }
1921 if( !nKeyLen ){
1922 unqliteGenError(pDb,"Empty key");
1923 rc = UNQLITE_EMPTY;
1924 }else{
1925 /* Perform the requested operation */
1926 rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,pData,nDataLen);
1927 }
1928 }
1929#if defined(UNQLITE_ENABLE_THREADS)
1930 /* Leave DB mutex */
1931 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1932#endif
1933 return rc;
1934}
1935/*
1936 * [CAPIREF: unqlite_kv_store_fmt()]
1937 * Please refer to the official documentation for function purpose and expected parameters.
1938 */
1939int unqlite_kv_store_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...)
1940{
1941 unqlite_kv_engine *pEngine;
1942 int rc;
1943 if( UNQLITE_DB_MISUSE(pDb) ){
1944 return UNQLITE_CORRUPT;
1945 }
1946#if defined(UNQLITE_ENABLE_THREADS)
1947 /* Acquire DB mutex */
1948 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1949 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
1950 UNQLITE_THRD_DB_RELEASE(pDb) ){
1951 return UNQLITE_ABORT; /* Another thread have released this instance */
1952 }
1953#endif
1954 /* Point to the underlying storage engine */
1955 pEngine = unqlitePagerGetKvEngine(pDb);
1956 if( pEngine->pIo->pMethods->xReplace == 0 ){
1957 /* Storage engine does not implement such method */
1958 unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine");
1959 rc = UNQLITE_NOTIMPLEMENTED;
1960 }else{
1961 if( nKeyLen < 0 ){
1962 /* Assume a null terminated string and compute it's length */
1963 nKeyLen = SyStrlen((const char *)pKey);
1964 }
1965 if( !nKeyLen ){
1966 unqliteGenError(pDb,"Empty key");
1967 rc = UNQLITE_EMPTY;
1968 }else{
1969 SyBlob sWorker; /* Working buffer */
1970 va_list ap;
1971 SyBlobInit(&sWorker,&pDb->sMem);
1972 /* Format the data */
1973 va_start(ap,zFormat);
1974 SyBlobFormatAp(&sWorker,zFormat,ap);
1975 va_end(ap);
1976 /* Perform the requested operation */
1977 rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
1978 /* Clean up */
1979 SyBlobRelease(&sWorker);
1980 }
1981 }
1982#if defined(UNQLITE_ENABLE_THREADS)
1983 /* Leave DB mutex */
1984 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
1985#endif
1986 return rc;
1987}
1988/*
1989 * [CAPIREF: unqlite_kv_append()]
1990 * Please refer to the official documentation for function purpose and expected parameters.
1991 */
1992int unqlite_kv_append(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen)
1993{
1994 unqlite_kv_engine *pEngine;
1995 int rc;
1996 if( UNQLITE_DB_MISUSE(pDb) ){
1997 return UNQLITE_CORRUPT;
1998 }
1999#if defined(UNQLITE_ENABLE_THREADS)
2000 /* Acquire DB mutex */
2001 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2002 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2003 UNQLITE_THRD_DB_RELEASE(pDb) ){
2004 return UNQLITE_ABORT; /* Another thread have released this instance */
2005 }
2006#endif
2007 /* Point to the underlying storage engine */
2008 pEngine = unqlitePagerGetKvEngine(pDb);
2009 if( pEngine->pIo->pMethods->xAppend == 0 ){
2010 /* Storage engine does not implement such method */
2011 unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine");
2012 rc = UNQLITE_NOTIMPLEMENTED;
2013 }else{
2014 if( nKeyLen < 0 ){
2015 /* Assume a null terminated string and compute it's length */
2016 nKeyLen = SyStrlen((const char *)pKey);
2017 }
2018 if( !nKeyLen ){
2019 unqliteGenError(pDb,"Empty key");
2020 rc = UNQLITE_EMPTY;
2021 }else{
2022 /* Perform the requested operation */
2023 rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,pData,nDataLen);
2024 }
2025 }
2026#if defined(UNQLITE_ENABLE_THREADS)
2027 /* Leave DB mutex */
2028 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2029#endif
2030 return rc;
2031}
2032/*
2033 * [CAPIREF: unqlite_kv_append_fmt()]
2034 * Please refer to the official documentation for function purpose and expected parameters.
2035 */
2036int unqlite_kv_append_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...)
2037{
2038 unqlite_kv_engine *pEngine;
2039 int rc;
2040 if( UNQLITE_DB_MISUSE(pDb) ){
2041 return UNQLITE_CORRUPT;
2042 }
2043#if defined(UNQLITE_ENABLE_THREADS)
2044 /* Acquire DB mutex */
2045 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2046 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2047 UNQLITE_THRD_DB_RELEASE(pDb) ){
2048 return UNQLITE_ABORT; /* Another thread have released this instance */
2049 }
2050#endif
2051 /* Point to the underlying storage engine */
2052 pEngine = unqlitePagerGetKvEngine(pDb);
2053 if( pEngine->pIo->pMethods->xAppend == 0 ){
2054 /* Storage engine does not implement such method */
2055 unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine");
2056 rc = UNQLITE_NOTIMPLEMENTED;
2057 }else{
2058 if( nKeyLen < 0 ){
2059 /* Assume a null terminated string and compute it's length */
2060 nKeyLen = SyStrlen((const char *)pKey);
2061 }
2062 if( !nKeyLen ){
2063 unqliteGenError(pDb,"Empty key");
2064 rc = UNQLITE_EMPTY;
2065 }else{
2066 SyBlob sWorker; /* Working buffer */
2067 va_list ap;
2068 SyBlobInit(&sWorker,&pDb->sMem);
2069 /* Format the data */
2070 va_start(ap,zFormat);
2071 SyBlobFormatAp(&sWorker,zFormat,ap);
2072 va_end(ap);
2073 /* Perform the requested operation */
2074 rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
2075 /* Clean up */
2076 SyBlobRelease(&sWorker);
2077 }
2078 }
2079#if defined(UNQLITE_ENABLE_THREADS)
2080 /* Leave DB mutex */
2081 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2082#endif
2083 return rc;
2084}
2085/*
2086 * [CAPIREF: unqlite_kv_fetch()]
2087 * Please refer to the official documentation for function purpose and expected parameters.
2088 */
2089int unqlite_kv_fetch(unqlite *pDb,const void *pKey,int nKeyLen,void *pBuf,unqlite_int64 *pBufLen)
2090{
2091 unqlite_kv_methods *pMethods;
2092 unqlite_kv_engine *pEngine;
2093 unqlite_kv_cursor *pCur;
2094 int rc;
2095 if( UNQLITE_DB_MISUSE(pDb) ){
2096 return UNQLITE_CORRUPT;
2097 }
2098#if defined(UNQLITE_ENABLE_THREADS)
2099 /* Acquire DB mutex */
2100 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2101 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2102 UNQLITE_THRD_DB_RELEASE(pDb) ){
2103 return UNQLITE_ABORT; /* Another thread have released this instance */
2104 }
2105#endif
2106 /* Point to the underlying storage engine */
2107 pEngine = unqlitePagerGetKvEngine(pDb);
2108 pMethods = pEngine->pIo->pMethods;
2109 pCur = pDb->sDB.pCursor;
2110 if( nKeyLen < 0 ){
2111 /* Assume a null terminated string and compute it's length */
2112 nKeyLen = SyStrlen((const char *)pKey);
2113 }
2114 if( !nKeyLen ){
2115 unqliteGenError(pDb,"Empty key");
2116 rc = UNQLITE_EMPTY;
2117 }else{
2118 /* Seek to the record position */
2119 rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT);
2120 }
2121 if( rc == UNQLITE_OK ){
2122 if( pBuf == 0 ){
2123 /* Data length only */
2124 rc = pMethods->xDataLength(pCur,pBufLen);
2125 }else{
2126 SyBlob sBlob;
2127 /* Initialize the data consumer */
2128 SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)*pBufLen);
2129 /* Consume the data */
2130 rc = pMethods->xData(pCur,unqliteDataConsumer,&sBlob);
2131 /* Data length */
2132 *pBufLen = (unqlite_int64)SyBlobLength(&sBlob);
2133 /* Cleanup */
2134 SyBlobRelease(&sBlob);
2135 }
2136 }
2137#if defined(UNQLITE_ENABLE_THREADS)
2138 /* Leave DB mutex */
2139 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2140#endif
2141 return rc;
2142}
2143/*
2144 * [CAPIREF: unqlite_kv_fetch_callback()]
2145 * Please refer to the official documentation for function purpose and expected parameters.
2146 */
2147int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
2148{
2149 unqlite_kv_methods *pMethods;
2150 unqlite_kv_engine *pEngine;
2151 unqlite_kv_cursor *pCur;
2152 int rc;
2153 if( UNQLITE_DB_MISUSE(pDb) ){
2154 return UNQLITE_CORRUPT;
2155 }
2156#if defined(UNQLITE_ENABLE_THREADS)
2157 /* Acquire DB mutex */
2158 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2159 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2160 UNQLITE_THRD_DB_RELEASE(pDb) ){
2161 return UNQLITE_ABORT; /* Another thread have released this instance */
2162 }
2163#endif
2164 /* Point to the underlying storage engine */
2165 pEngine = unqlitePagerGetKvEngine(pDb);
2166 pMethods = pEngine->pIo->pMethods;
2167 pCur = pDb->sDB.pCursor;
2168 if( nKeyLen < 0 ){
2169 /* Assume a null terminated string and compute it's length */
2170 nKeyLen = SyStrlen((const char *)pKey);
2171 }
2172 if( !nKeyLen ){
2173 unqliteGenError(pDb,"Empty key");
2174 rc = UNQLITE_EMPTY;
2175 }else{
2176 /* Seek to the record position */
2177 rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT);
2178 }
2179 if( rc == UNQLITE_OK && xConsumer ){
2180 /* Consume the data directly */
2181 rc = pMethods->xData(pCur,xConsumer,pUserData);
2182 }
2183#if defined(UNQLITE_ENABLE_THREADS)
2184 /* Leave DB mutex */
2185 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2186#endif
2187 return rc;
2188}
2189/*
2190 * [CAPIREF: unqlite_kv_delete()]
2191 * Please refer to the official documentation for function purpose and expected parameters.
2192 */
2193int unqlite_kv_delete(unqlite *pDb,const void *pKey,int nKeyLen)
2194{
2195 unqlite_kv_methods *pMethods;
2196 unqlite_kv_engine *pEngine;
2197 unqlite_kv_cursor *pCur;
2198 int rc;
2199 if( UNQLITE_DB_MISUSE(pDb) ){
2200 return UNQLITE_CORRUPT;
2201 }
2202#if defined(UNQLITE_ENABLE_THREADS)
2203 /* Acquire DB mutex */
2204 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2205 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2206 UNQLITE_THRD_DB_RELEASE(pDb) ){
2207 return UNQLITE_ABORT; /* Another thread have released this instance */
2208 }
2209#endif
2210 /* Point to the underlying storage engine */
2211 pEngine = unqlitePagerGetKvEngine(pDb);
2212 pMethods = pEngine->pIo->pMethods;
2213 pCur = pDb->sDB.pCursor;
2214 if( pMethods->xDelete == 0 ){
2215 /* Storage engine does not implement such method */
2216 unqliteGenError(pDb,"xDelete() method not implemented in the underlying storage engine");
2217 rc = UNQLITE_NOTIMPLEMENTED;
2218 }else{
2219 if( nKeyLen < 0 ){
2220 /* Assume a null terminated string and compute it's length */
2221 nKeyLen = SyStrlen((const char *)pKey);
2222 }
2223 if( !nKeyLen ){
2224 unqliteGenError(pDb,"Empty key");
2225 rc = UNQLITE_EMPTY;
2226 }else{
2227 /* Seek to the record position */
2228 rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT);
2229 }
2230 if( rc == UNQLITE_OK ){
2231 /* Exact match found, delete the entry */
2232 rc = pMethods->xDelete(pCur);
2233 }
2234 }
2235#if defined(UNQLITE_ENABLE_THREADS)
2236 /* Leave DB mutex */
2237 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2238#endif
2239 return rc;
2240}
2241/*
2242 * [CAPIREF: unqlite_kv_config()]
2243 * Please refer to the official documentation for function purpose and expected parameters.
2244 */
2245int unqlite_kv_config(unqlite *pDb,int iOp,...)
2246{
2247 unqlite_kv_engine *pEngine;
2248 int rc;
2249 if( UNQLITE_DB_MISUSE(pDb) ){
2250 return UNQLITE_CORRUPT;
2251 }
2252#if defined(UNQLITE_ENABLE_THREADS)
2253 /* Acquire DB mutex */
2254 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2255 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2256 UNQLITE_THRD_DB_RELEASE(pDb) ){
2257 return UNQLITE_ABORT; /* Another thread have released this instance */
2258 }
2259#endif
2260 /* Point to the underlying storage engine */
2261 pEngine = unqlitePagerGetKvEngine(pDb);
2262 if( pEngine->pIo->pMethods->xConfig == 0 ){
2263 /* Storage engine does not implements such method */
2264 unqliteGenError(pDb,"xConfig() method not implemented in the underlying storage engine");
2265 rc = UNQLITE_NOTIMPLEMENTED;
2266 }else{
2267 va_list ap;
2268 /* Configure the storage engine */
2269 va_start(ap,iOp);
2270 rc = pEngine->pIo->pMethods->xConfig(pEngine,iOp,ap);
2271 va_end(ap);
2272 }
2273#if defined(UNQLITE_ENABLE_THREADS)
2274 /* Leave DB mutex */
2275 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2276#endif
2277 return rc;
2278}
2279/*
2280 * [CAPIREF: unqlite_kv_cursor_init()]
2281 * Please refer to the official documentation for function purpose and expected parameters.
2282 */
2283int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut)
2284{
2285 int rc;
2286 if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0 /* Noop */){
2287 return UNQLITE_CORRUPT;
2288 }
2289#if defined(UNQLITE_ENABLE_THREADS)
2290 /* Acquire DB mutex */
2291 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2292 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2293 UNQLITE_THRD_DB_RELEASE(pDb) ){
2294 return UNQLITE_ABORT; /* Another thread have released this instance */
2295 }
2296#endif
2297 /* Allocate a new cursor */
2298 rc = unqliteInitCursor(pDb,ppOut);
2299#if defined(UNQLITE_ENABLE_THREADS)
2300 /* Leave DB mutex */
2301 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2302#endif
2303 return rc;
2304}
2305/*
2306 * [CAPIREF: unqlite_kv_cursor_release()]
2307 * Please refer to the official documentation for function purpose and expected parameters.
2308 */
2309int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur)
2310{
2311 int rc;
2312 if( UNQLITE_DB_MISUSE(pDb) || pCur == 0 /* Noop */){
2313 return UNQLITE_CORRUPT;
2314 }
2315#if defined(UNQLITE_ENABLE_THREADS)
2316 /* Acquire DB mutex */
2317 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2318 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2319 UNQLITE_THRD_DB_RELEASE(pDb) ){
2320 return UNQLITE_ABORT; /* Another thread have released this instance */
2321 }
2322#endif
2323 /* Release the cursor */
2324 rc = unqliteReleaseCursor(pDb,pCur);
2325#if defined(UNQLITE_ENABLE_THREADS)
2326 /* Leave DB mutex */
2327 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2328#endif
2329 return rc;
2330}
2331/*
2332 * [CAPIREF: unqlite_kv_cursor_first_entry()]
2333 * Please refer to the official documentation for function purpose and expected parameters.
2334 */
2335int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor)
2336{
2337 int rc;
2338#ifdef UNTRUST
2339 if( pCursor == 0 ){
2340 return UNQLITE_CORRUPT;
2341 }
2342#endif
2343 /* Check if the requested method is implemented by the underlying storage engine */
2344 if( pCursor->pStore->pIo->pMethods->xFirst == 0 ){
2345 rc = UNQLITE_NOTIMPLEMENTED;
2346 }else{
2347 /* Seek to the first entry */
2348 rc = pCursor->pStore->pIo->pMethods->xFirst(pCursor);
2349 }
2350 return rc;
2351}
2352/*
2353 * [CAPIREF: unqlite_kv_cursor_last_entry()]
2354 * Please refer to the official documentation for function purpose and expected parameters.
2355 */
2356int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor)
2357{
2358 int rc;
2359#ifdef UNTRUST
2360 if( pCursor == 0 ){
2361 return UNQLITE_CORRUPT;
2362 }
2363#endif
2364 /* Check if the requested method is implemented by the underlying storage engine */
2365 if( pCursor->pStore->pIo->pMethods->xLast == 0 ){
2366 rc = UNQLITE_NOTIMPLEMENTED;
2367 }else{
2368 /* Seek to the last entry */
2369 rc = pCursor->pStore->pIo->pMethods->xLast(pCursor);
2370 }
2371 return rc;
2372}
2373/*
2374 * [CAPIREF: unqlite_kv_cursor_valid_entry()]
2375 * Please refer to the official documentation for function purpose and expected parameters.
2376 */
2377int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor)
2378{
2379 int rc;
2380#ifdef UNTRUST
2381 if( pCursor == 0 ){
2382 return UNQLITE_CORRUPT;
2383 }
2384#endif
2385 /* Check if the requested method is implemented by the underlying storage engine */
2386 if( pCursor->pStore->pIo->pMethods->xValid == 0 ){
2387 rc = UNQLITE_NOTIMPLEMENTED;
2388 }else{
2389 rc = pCursor->pStore->pIo->pMethods->xValid(pCursor);
2390 }
2391 return rc;
2392}
2393/*
2394 * [CAPIREF: unqlite_kv_cursor_next_entry()]
2395 * Please refer to the official documentation for function purpose and expected parameters.
2396 */
2397int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor)
2398{
2399 int rc;
2400#ifdef UNTRUST
2401 if( pCursor == 0 ){
2402 return UNQLITE_CORRUPT;
2403 }
2404#endif
2405 /* Check if the requested method is implemented by the underlying storage engine */
2406 if( pCursor->pStore->pIo->pMethods->xNext == 0 ){
2407 rc = UNQLITE_NOTIMPLEMENTED;
2408 }else{
2409 /* Seek to the next entry */
2410 rc = pCursor->pStore->pIo->pMethods->xNext(pCursor);
2411 }
2412 return rc;
2413}
2414/*
2415 * [CAPIREF: unqlite_kv_cursor_prev_entry()]
2416 * Please refer to the official documentation for function purpose and expected parameters.
2417 */
2418int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor)
2419{
2420 int rc;
2421#ifdef UNTRUST
2422 if( pCursor == 0 ){
2423 return UNQLITE_CORRUPT;
2424 }
2425#endif
2426 /* Check if the requested method is implemented by the underlying storage engine */
2427 if( pCursor->pStore->pIo->pMethods->xPrev == 0 ){
2428 rc = UNQLITE_NOTIMPLEMENTED;
2429 }else{
2430 /* Seek to the previous entry */
2431 rc = pCursor->pStore->pIo->pMethods->xPrev(pCursor);
2432 }
2433 return rc;
2434}
2435/*
2436 * [CAPIREF: unqlite_kv_cursor_delete_entry()]
2437 * Please refer to the official documentation for function purpose and expected parameters.
2438 */
2439int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor)
2440{
2441 int rc;
2442#ifdef UNTRUST
2443 if( pCursor == 0 ){
2444 return UNQLITE_CORRUPT;
2445 }
2446#endif
2447 /* Check if the requested method is implemented by the underlying storage engine */
2448 if( pCursor->pStore->pIo->pMethods->xDelete == 0 ){
2449 rc = UNQLITE_NOTIMPLEMENTED;
2450 }else{
2451 /* Delete the entry */
2452 rc = pCursor->pStore->pIo->pMethods->xDelete(pCursor);
2453 }
2454 return rc;
2455}
2456/*
2457 * [CAPIREF: unqlite_kv_cursor_reset()]
2458 * Please refer to the official documentation for function purpose and expected parameters.
2459 */
2460int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor)
2461{
2462 int rc = UNQLITE_OK;
2463#ifdef UNTRUST
2464 if( pCursor == 0 ){
2465 return UNQLITE_CORRUPT;
2466 }
2467#endif
2468 /* Check if the requested method is implemented by the underlying storage engine */
2469 if( pCursor->pStore->pIo->pMethods->xReset == 0 ){
2470 rc = UNQLITE_NOTIMPLEMENTED;
2471 }else{
2472 /* Reset */
2473 pCursor->pStore->pIo->pMethods->xReset(pCursor);
2474 }
2475 return rc;
2476}
2477/*
2478 * [CAPIREF: unqlite_kv_cursor_seek()]
2479 * Please refer to the official documentation for function purpose and expected parameters.
2480 */
2481int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos)
2482{
2483 int rc = UNQLITE_OK;
2484#ifdef UNTRUST
2485 if( pCursor == 0 ){
2486 return UNQLITE_CORRUPT;
2487 }
2488#endif
2489 if( nKeyLen < 0 ){
2490 /* Assume a null terminated string and compute it's length */
2491 nKeyLen = SyStrlen((const char *)pKey);
2492 }
2493 if( !nKeyLen ){
2494 rc = UNQLITE_EMPTY;
2495 }else{
2496 /* Seek to the desired location */
2497 rc = pCursor->pStore->pIo->pMethods->xSeek(pCursor,pKey,nKeyLen,iPos);
2498 }
2499 return rc;
2500}
2501/*
2502 * Default data consumer callback. That is, all retrieved is redirected to this
2503 * routine which store the output in an internal blob.
2504 */
2505UNQLITE_PRIVATE int unqliteDataConsumer(
2506 const void *pOut, /* Data to consume */
2507 unsigned int nLen, /* Data length */
2508 void *pUserData /* User private data */
2509 )
2510{
2511 sxi32 rc;
2512 /* Store the output in an internal BLOB */
2513 rc = SyBlobAppend((SyBlob *)pUserData, pOut, nLen);
2514 return rc;
2515}
2516/*
2517 * [CAPIREF: unqlite_kv_cursor_data_callback()]
2518 * Please refer to the official documentation for function purpose and expected parameters.
2519 */
2520int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
2521{
2522 int rc;
2523#ifdef UNTRUST
2524 if( pCursor == 0 ){
2525 return UNQLITE_CORRUPT;
2526 }
2527#endif
2528 /* Consume the key directly */
2529 rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,xConsumer,pUserData);
2530 return rc;
2531}
2532/*
2533 * [CAPIREF: unqlite_kv_cursor_key()]
2534 * Please refer to the official documentation for function purpose and expected parameters.
2535 */
2536int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte)
2537{
2538 int rc;
2539#ifdef UNTRUST
2540 if( pCursor == 0 ){
2541 return UNQLITE_CORRUPT;
2542 }
2543#endif
2544 if( pBuf == 0 ){
2545 /* Key length only */
2546 rc = pCursor->pStore->pIo->pMethods->xKeyLength(pCursor,pnByte);
2547 }else{
2548 SyBlob sBlob;
2549 if( (*pnByte) < 0 ){
2550 return UNQLITE_CORRUPT;
2551 }
2552 /* Initialize the data consumer */
2553 SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte));
2554 /* Consume the key */
2555 rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,unqliteDataConsumer,&sBlob);
2556 /* Key length */
2557 *pnByte = SyBlobLength(&sBlob);
2558 /* Cleanup */
2559 SyBlobRelease(&sBlob);
2560 }
2561 return rc;
2562}
2563/*
2564 * [CAPIREF: unqlite_kv_cursor_data_callback()]
2565 * Please refer to the official documentation for function purpose and expected parameters.
2566 */
2567int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
2568{
2569 int rc;
2570#ifdef UNTRUST
2571 if( pCursor == 0 ){
2572 return UNQLITE_CORRUPT;
2573 }
2574#endif
2575 /* Consume the data directly */
2576 rc = pCursor->pStore->pIo->pMethods->xData(pCursor,xConsumer,pUserData);
2577 return rc;
2578}
2579/*
2580 * [CAPIREF: unqlite_kv_cursor_data()]
2581 * Please refer to the official documentation for function purpose and expected parameters.
2582 */
2583int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnByte)
2584{
2585 int rc;
2586#ifdef UNTRUST
2587 if( pCursor == 0 ){
2588 return UNQLITE_CORRUPT;
2589 }
2590#endif
2591 if( pBuf == 0 ){
2592 /* Data length only */
2593 rc = pCursor->pStore->pIo->pMethods->xDataLength(pCursor,pnByte);
2594 }else{
2595 SyBlob sBlob;
2596 if( (*pnByte) < 0 ){
2597 return UNQLITE_CORRUPT;
2598 }
2599 /* Initialize the data consumer */
2600 SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte));
2601 /* Consume the data */
2602 rc = pCursor->pStore->pIo->pMethods->xData(pCursor,unqliteDataConsumer,&sBlob);
2603 /* Data length */
2604 *pnByte = SyBlobLength(&sBlob);
2605 /* Cleanup */
2606 SyBlobRelease(&sBlob);
2607 }
2608 return rc;
2609}
2610/*
2611 * [CAPIREF: unqlite_begin()]
2612 * Please refer to the official documentation for function purpose and expected parameters.
2613 */
2614int unqlite_begin(unqlite *pDb)
2615{
2616 int rc;
2617 if( UNQLITE_DB_MISUSE(pDb) ){
2618 return UNQLITE_CORRUPT;
2619 }
2620#if defined(UNQLITE_ENABLE_THREADS)
2621 /* Acquire DB mutex */
2622 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2623 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2624 UNQLITE_THRD_DB_RELEASE(pDb) ){
2625 return UNQLITE_ABORT; /* Another thread have released this instance */
2626 }
2627#endif
2628 /* Begin the write transaction */
2629 rc = unqlitePagerBegin(pDb->sDB.pPager);
2630#if defined(UNQLITE_ENABLE_THREADS)
2631 /* Leave DB mutex */
2632 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2633#endif
2634 return rc;
2635}
2636/*
2637 * [CAPIREF: unqlite_commit()]
2638 * Please refer to the official documentation for function purpose and expected parameters.
2639 */
2640int unqlite_commit(unqlite *pDb)
2641{
2642 int rc;
2643 if( UNQLITE_DB_MISUSE(pDb) ){
2644 return UNQLITE_CORRUPT;
2645 }
2646#if defined(UNQLITE_ENABLE_THREADS)
2647 /* Acquire DB mutex */
2648 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2649 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2650 UNQLITE_THRD_DB_RELEASE(pDb) ){
2651 return UNQLITE_ABORT; /* Another thread have released this instance */
2652 }
2653#endif
2654 /* Commit the transaction */
2655 rc = unqlitePagerCommit(pDb->sDB.pPager);
2656#if defined(UNQLITE_ENABLE_THREADS)
2657 /* Leave DB mutex */
2658 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2659#endif
2660 return rc;
2661}
2662/*
2663 * [CAPIREF: unqlite_rollback()]
2664 * Please refer to the official documentation for function purpose and expected parameters.
2665 */
2666int unqlite_rollback(unqlite *pDb)
2667{
2668 int rc;
2669 if( UNQLITE_DB_MISUSE(pDb) ){
2670 return UNQLITE_CORRUPT;
2671 }
2672#if defined(UNQLITE_ENABLE_THREADS)
2673 /* Acquire DB mutex */
2674 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2675 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2676 UNQLITE_THRD_DB_RELEASE(pDb) ){
2677 return UNQLITE_ABORT; /* Another thread have released this instance */
2678 }
2679#endif
2680 /* Rollback the transaction */
2681 rc = unqlitePagerRollback(pDb->sDB.pPager,TRUE);
2682#if defined(UNQLITE_ENABLE_THREADS)
2683 /* Leave DB mutex */
2684 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2685#endif
2686 return rc;
2687}
2688/*
2689 * [CAPIREF: unqlite_util_load_mmaped_file()]
2690 * Please refer to the official documentation for function purpose and expected parameters.
2691 */
2692UNQLITE_APIEXPORT int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize)
2693{
2694 const jx9_vfs *pVfs;
2695 int rc;
2696 if( SX_EMPTY_STR(zFile) || ppMap == 0 || pFileSize == 0){
2697 /* Sanity check */
2698 return UNQLITE_CORRUPT;
2699 }
2700 *ppMap = 0;
2701 /* Extract the Jx9 Vfs */
2702 pVfs = jx9ExportBuiltinVfs();
2703 /*
2704 * Check if the underlying vfs implement the memory map routines
2705 * [i.e: mmap() under UNIX/MapViewOfFile() under windows].
2706 */
2707 if( pVfs == 0 || pVfs->xMmap == 0 ){
2708 rc = UNQLITE_NOTIMPLEMENTED;
2709 }else{
2710 /* Try to get a read-only memory view of the whole file */
2711 rc = pVfs->xMmap(zFile,ppMap,pFileSize);
2712 }
2713 return rc;
2714}
2715/*
2716 * [CAPIREF: unqlite_util_release_mmaped_file()]
2717 * Please refer to the official documentation for function purpose and expected parameters.
2718 */
2719UNQLITE_APIEXPORT int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize)
2720{
2721 const jx9_vfs *pVfs;
2722 int rc = UNQLITE_OK;
2723 if( pMap == 0 ){
2724 return UNQLITE_OK;
2725 }
2726 /* Extract the Jx9 Vfs */
2727 pVfs = jx9ExportBuiltinVfs();
2728 if( pVfs == 0 || pVfs->xUnmap == 0 ){
2729 rc = UNQLITE_NOTIMPLEMENTED;
2730 }else{
2731 pVfs->xUnmap(pMap,iFileSize);
2732 }
2733 return rc;
2734}
2735/*
2736 * [CAPIREF: unqlite_util_random_string()]
2737 * Please refer to the official documentation for function purpose and expected parameters.
2738 */
2739UNQLITE_APIEXPORT int unqlite_util_random_string(unqlite *pDb,char *zBuf,unsigned int buf_size)
2740{
2741 if( UNQLITE_DB_MISUSE(pDb) ){
2742 return UNQLITE_CORRUPT;
2743 }
2744 if( zBuf == 0 || buf_size < 3 ){
2745 /* Buffer must be long enough to hold three bytes */
2746 return UNQLITE_INVALID;
2747 }
2748#if defined(UNQLITE_ENABLE_THREADS)
2749 /* Acquire DB mutex */
2750 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2751 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2752 UNQLITE_THRD_DB_RELEASE(pDb) ){
2753 return UNQLITE_ABORT; /* Another thread have released this instance */
2754 }
2755#endif
2756 /* Generate the random string */
2757 unqlitePagerRandomString(pDb->sDB.pPager,zBuf,buf_size);
2758#if defined(UNQLITE_ENABLE_THREADS)
2759 /* Leave DB mutex */
2760 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2761#endif
2762 return UNQLITE_OK;
2763}
2764/*
2765 * [CAPIREF: unqlite_util_random_num()]
2766 * Please refer to the official documentation for function purpose and expected parameters.
2767 */
2768UNQLITE_APIEXPORT unsigned int unqlite_util_random_num(unqlite *pDb)
2769{
2770 sxu32 iNum;
2771 if( UNQLITE_DB_MISUSE(pDb) ){
2772 return 0;
2773 }
2774#if defined(UNQLITE_ENABLE_THREADS)
2775 /* Acquire DB mutex */
2776 SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2777 if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE &&
2778 UNQLITE_THRD_DB_RELEASE(pDb) ){
2779 return 0; /* Another thread have released this instance */
2780 }
2781#endif
2782 /* Generate the random number */
2783 iNum = unqlitePagerRandomNum(pDb->sDB.pPager);
2784#if defined(UNQLITE_ENABLE_THREADS)
2785 /* Leave DB mutex */
2786 SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */
2787#endif
2788 return iNum;
2789}