From 9ee8378d393778ac67314be7ea8d5bcbaeee9ee0 Mon Sep 17 00:00:00 2001 From: Aaron Seigo Date: Sun, 7 Dec 2014 10:08:07 +0100 Subject: try out unqlite --- common/unqlite/api.c | 2789 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2789 insertions(+) create mode 100644 common/unqlite/api.c (limited to 'common/unqlite/api.c') 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 @@ +/* + * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. + * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ + * Version 1.1.6 + * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES + * please contact Symisc Systems via: + * legal@symisc.net + * licensing@symisc.net + * contact@symisc.net + * or visit: + * http://unqlite.org/licensing.html + */ + /* $SymiscID: api.c v2.0 FreeBSD 2012-11-08 23:07 stable $ */ +#ifndef UNQLITE_AMALGAMATION +#include "unqliteInt.h" +#endif +/* This file implement the public interfaces presented to host-applications. + * Routines in other files are for internal use by UnQLite and should not be + * accessed by users of the library. + */ +#define UNQLITE_DB_MISUSE(DB) (DB == 0 || DB->nMagic != UNQLITE_DB_MAGIC) +#define UNQLITE_VM_MISUSE(VM) (VM == 0 || VM->nMagic == JX9_VM_STALE) +/* If another thread have released a working instance, the following macros + * evaluates to true. These macros are only used when the library + * is built with threading support enabled. + */ +#define UNQLITE_THRD_DB_RELEASE(DB) (DB->nMagic != UNQLITE_DB_MAGIC) +#define UNQLITE_THRD_VM_RELEASE(VM) (VM->nMagic == JX9_VM_STALE) +/* IMPLEMENTATION: unqlite@embedded@symisc 118-09-4785 */ +/* + * All global variables are collected in the structure named "sUnqlMPGlobal". + * That way it is clear in the code when we are using static variable because + * its name start with sUnqlMPGlobal. + */ +static struct unqlGlobal_Data +{ + SyMemBackend sAllocator; /* Global low level memory allocator */ +#if defined(UNQLITE_ENABLE_THREADS) + const SyMutexMethods *pMutexMethods; /* Mutex methods */ + SyMutex *pMutex; /* Global mutex */ + sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded + * The threading level can be set using the [unqlite_lib_config()] + * interface with a configuration verb set to + * UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE or + * UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI + */ +#endif + SySet kv_storage; /* Installed KV storage engines */ + int iPageSize; /* Default Page size */ + unqlite_vfs *pVfs; /* Underlying virtual file system (Vfs) */ + sxi32 nDB; /* Total number of active DB handles */ + unqlite *pDB; /* List of active DB handles */ + sxu32 nMagic; /* Sanity check against library misuse */ +}sUnqlMPGlobal = { + {0, 0, 0, 0, 0, 0, 0, 0, {0}}, +#if defined(UNQLITE_ENABLE_THREADS) + 0, + 0, + 0, +#endif + {0, 0, 0, 0, 0, 0, 0 }, + UNQLITE_DEFAULT_PAGE_SIZE, + 0, + 0, + 0, + 0 +}; +#define UNQLITE_LIB_MAGIC 0xEA1495BA +#define UNQLITE_LIB_MISUSE (sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC) +/* + * Supported threading level. + * These options have meaning only when the library is compiled with multi-threading + * support. That is, the UNQLITE_ENABLE_THREADS compile time directive must be defined + * when UnQLite is built. + * UNQLITE_THREAD_LEVEL_SINGLE: + * In this mode, mutexing is disabled and the library can only be used by a single thread. + * UNQLITE_THREAD_LEVEL_MULTI + * In this mode, all mutexes including the recursive mutexes on [unqlite] objects + * are enabled so that the application is free to share the same database handle + * between different threads at the same time. + */ +#define UNQLITE_THREAD_LEVEL_SINGLE 1 +#define UNQLITE_THREAD_LEVEL_MULTI 2 +/* + * Find a Key Value storage engine from the set of installed engines. + * Return a pointer to the storage engine methods on success. NULL on failure. + */ +UNQLITE_PRIVATE unqlite_kv_methods * unqliteFindKVStore( + const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */ + sxu32 nByte /* zName length */ + ) +{ + unqlite_kv_methods **apStore,*pEntry; + sxu32 n,nMax; + /* Point to the set of installed engines */ + apStore = (unqlite_kv_methods **)SySetBasePtr(&sUnqlMPGlobal.kv_storage); + nMax = SySetUsed(&sUnqlMPGlobal.kv_storage); + for( n = 0 ; n < nMax; ++n ){ + pEntry = apStore[n]; + if( nByte == SyStrlen(pEntry->zName) && SyStrnicmp(pEntry->zName,zName,nByte) == 0 ){ + /* Storage engine found */ + return pEntry; + } + } + /* No such entry, return NULL */ + return 0; +} +/* + * Configure the UnQLite library. + * Return UNQLITE_OK on success. Any other return value indicates failure. + * Refer to [unqlite_lib_config()]. + */ +static sxi32 unqliteCoreConfigure(sxi32 nOp, va_list ap) +{ + int rc = UNQLITE_OK; + switch(nOp){ + case UNQLITE_LIB_CONFIG_PAGE_SIZE: { + /* Default page size: Must be a power of two */ + int iPage = va_arg(ap,int); + if( iPage >= UNQLITE_MIN_PAGE_SIZE && iPage <= UNQLITE_MAX_PAGE_SIZE ){ + if( !(iPage & (iPage - 1)) ){ + sUnqlMPGlobal.iPageSize = iPage; + }else{ + /* Invalid page size */ + rc = UNQLITE_INVALID; + } + }else{ + /* Invalid page size */ + rc = UNQLITE_INVALID; + } + break; + } + case UNQLITE_LIB_CONFIG_STORAGE_ENGINE: { + /* Install a key value storage engine */ + unqlite_kv_methods *pMethods = va_arg(ap,unqlite_kv_methods *); + /* Make sure we are delaing with a valid methods */ + if( pMethods == 0 || SX_EMPTY_STR(pMethods->zName) || pMethods->xSeek == 0 || pMethods->xData == 0 + || pMethods->xKey == 0 || pMethods->xDataLength == 0 || pMethods->xKeyLength == 0 + || pMethods->szKv < (int)sizeof(unqlite_kv_engine) ){ + rc = UNQLITE_INVALID; + break; + } + /* Install it */ + rc = SySetPut(&sUnqlMPGlobal.kv_storage,(const void *)&pMethods); + break; + } + case UNQLITE_LIB_CONFIG_VFS:{ + /* Install a virtual file system */ + unqlite_vfs *pVfs = va_arg(ap,unqlite_vfs *); + if( pVfs ){ + sUnqlMPGlobal.pVfs = pVfs; + } + break; + } + case UNQLITE_LIB_CONFIG_USER_MALLOC: { + /* Use an alternative low-level memory allocation routines */ + const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *); + /* Save the memory failure callback (if available) */ + ProcMemError xMemErr = sUnqlMPGlobal.sAllocator.xMemError; + void *pMemErr = sUnqlMPGlobal.sAllocator.pUserData; + if( pMethods == 0 ){ + /* Use the built-in memory allocation subsystem */ + rc = SyMemBackendInit(&sUnqlMPGlobal.sAllocator, xMemErr, pMemErr); + }else{ + rc = SyMemBackendInitFromOthers(&sUnqlMPGlobal.sAllocator, pMethods, xMemErr, pMemErr); + } + break; + } + case UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK: { + /* Memory failure callback */ + ProcMemError xMemErr = va_arg(ap, ProcMemError); + void *pUserData = va_arg(ap, void *); + sUnqlMPGlobal.sAllocator.xMemError = xMemErr; + sUnqlMPGlobal.sAllocator.pUserData = pUserData; + break; + } + case UNQLITE_LIB_CONFIG_USER_MUTEX: { +#if defined(UNQLITE_ENABLE_THREADS) + /* Use an alternative low-level mutex subsystem */ + const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *); +#if defined (UNTRUST) + if( pMethods == 0 ){ + rc = UNQLITE_CORRUPT; + } +#endif + /* Sanity check */ + if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){ + /* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */ + rc = UNQLITE_CORRUPT; + break; + } + if( sUnqlMPGlobal.pMutexMethods ){ + /* Overwrite the previous mutex subsystem */ + SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); + if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){ + sUnqlMPGlobal.pMutexMethods->xGlobalRelease(); + } + sUnqlMPGlobal.pMutex = 0; + } + /* Initialize and install the new mutex subsystem */ + if( pMethods->xGlobalInit ){ + rc = pMethods->xGlobalInit(); + if ( rc != UNQLITE_OK ){ + break; + } + } + /* Create the global mutex */ + sUnqlMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); + if( sUnqlMPGlobal.pMutex == 0 ){ + /* + * If the supplied mutex subsystem is so sick that we are unable to + * create a single mutex, there is no much we can do here. + */ + if( pMethods->xGlobalRelease ){ + pMethods->xGlobalRelease(); + } + rc = UNQLITE_CORRUPT; + break; + } + sUnqlMPGlobal.pMutexMethods = pMethods; + if( sUnqlMPGlobal.nThreadingLevel == 0 ){ + /* Set a default threading level */ + sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI; + } +#endif + break; + } + case UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE: +#if defined(UNQLITE_ENABLE_THREADS) + /* Single thread mode (Only one thread is allowed to play with the library) */ + sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_SINGLE; + jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE); +#endif + break; + case UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI: +#if defined(UNQLITE_ENABLE_THREADS) + /* Multi-threading mode (library is thread safe and database handles and virtual machines + * may be shared between multiple threads). + */ + sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI; + jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_MULTI); +#endif + break; + default: + /* Unknown configuration option */ + rc = UNQLITE_CORRUPT; + break; + } + return rc; +} +/* + * [CAPIREF: unqlite_lib_config()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_lib_config(int nConfigOp,...) +{ + va_list ap; + int rc; + if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){ + /* Library is already initialized, this operation is forbidden */ + return UNQLITE_LOCKED; + } + va_start(ap,nConfigOp); + rc = unqliteCoreConfigure(nConfigOp,ap); + va_end(ap); + return rc; +} +/* + * Global library initialization + * Refer to [unqlite_lib_init()] + * This routine must be called to initialize the memory allocation subsystem, the mutex + * subsystem prior to doing any serious work with the library. The first thread to call + * this routine does the initialization process and set the magic number so no body later + * can re-initialize the library. If subsequent threads call this routine before the first + * thread have finished the initialization process, then the subsequent threads must block + * until the initialization process is done. + */ +static sxi32 unqliteCoreInitialize(void) +{ + const unqlite_kv_methods *pMethods; + const unqlite_vfs *pVfs; /* Built-in vfs */ +#if defined(UNQLITE_ENABLE_THREADS) + const SyMutexMethods *pMutexMethods = 0; + SyMutex *pMaster = 0; +#endif + int rc; + /* + * If the library is already initialized, then a call to this routine + * is a no-op. + */ + if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){ + return UNQLITE_OK; /* Already initialized */ + } + /* Point to the built-in vfs */ + pVfs = unqliteExportBuiltinVfs(); + /* Install it */ + unqlite_lib_config(UNQLITE_LIB_CONFIG_VFS, pVfs); +#if defined(UNQLITE_ENABLE_THREADS) + if( sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_SINGLE ){ + pMutexMethods = sUnqlMPGlobal.pMutexMethods; + if( pMutexMethods == 0 ){ + /* Use the built-in mutex subsystem */ + pMutexMethods = SyMutexExportMethods(); + if( pMutexMethods == 0 ){ + return UNQLITE_CORRUPT; /* Can't happen */ + } + /* Install the mutex subsystem */ + rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MUTEX, pMutexMethods); + if( rc != UNQLITE_OK ){ + return rc; + } + } + /* Obtain a static mutex so we can initialize the library without calling malloc() */ + pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1); + if( pMaster == 0 ){ + return UNQLITE_CORRUPT; /* Can't happen */ + } + } + /* Lock the master mutex */ + rc = UNQLITE_OK; + SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ + if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ +#endif + if( sUnqlMPGlobal.sAllocator.pMethods == 0 ){ + /* Install a memory subsystem */ + rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */ + if( rc != UNQLITE_OK ){ + /* If we are unable to initialize the memory backend, there is no much we can do here.*/ + goto End; + } + } +#if defined(UNQLITE_ENABLE_THREADS) + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ + /* Protect the memory allocation subsystem */ + rc = SyMemBackendMakeThreadSafe(&sUnqlMPGlobal.sAllocator, sUnqlMPGlobal.pMutexMethods); + if( rc != UNQLITE_OK ){ + goto End; + } + } +#endif + SySetInit(&sUnqlMPGlobal.kv_storage,&sUnqlMPGlobal.sAllocator,sizeof(unqlite_kv_methods *)); + /* Install the built-in Key Value storage engines */ + pMethods = unqliteExportMemKvStorage(); /* In-memory storage */ + unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods); + /* Default disk key/value storage engine */ + pMethods = unqliteExportDiskKvStorage(); /* Disk storage */ + unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods); + /* Default page size */ + if( sUnqlMPGlobal.iPageSize < UNQLITE_MIN_PAGE_SIZE ){ + unqlite_lib_config(UNQLITE_LIB_CONFIG_PAGE_SIZE,UNQLITE_DEFAULT_PAGE_SIZE); + } + /* Our library is initialized, set the magic number */ + sUnqlMPGlobal.nMagic = UNQLITE_LIB_MAGIC; + rc = UNQLITE_OK; +#if defined(UNQLITE_ENABLE_THREADS) + } /* sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC */ +#endif +End: +#if defined(UNQLITE_ENABLE_THREADS) + /* Unlock the master mutex */ + SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ +#endif + return rc; +} +/* Forward declaration */ +static int unqliteVmRelease(unqlite_vm *pVm); +/* + * Release a single instance of an unqlite database handle. + */ +static int unqliteDbRelease(unqlite *pDb) +{ + unqlite_db *pStore = &pDb->sDB; + unqlite_vm *pVm,*pNext; + int rc = UNQLITE_OK; + if( (pDb->iFlags & UNQLITE_FL_DISABLE_AUTO_COMMIT) == 0 ){ + /* Commit any outstanding transaction */ + rc = unqlitePagerCommit(pStore->pPager); + if( rc != UNQLITE_OK ){ + /* Rollback the transaction */ + rc = unqlitePagerRollback(pStore->pPager,FALSE); + } + }else{ + /* Rollback any outstanding transaction */ + rc = unqlitePagerRollback(pStore->pPager,FALSE); + } + /* Close the pager */ + unqlitePagerClose(pStore->pPager); + /* Release any active VM's */ + pVm = pDb->pVms; + for(;;){ + if( pDb->iVm < 1 ){ + break; + } + /* Point to the next entry */ + pNext = pVm->pNext; + unqliteVmRelease(pVm); + pVm = pNext; + pDb->iVm--; + } + /* Release the Jx9 handle */ + jx9_release(pStore->pJx9); + /* Set a dummy magic number */ + pDb->nMagic = 0x7250; + /* Release the whole memory subsystem */ + SyMemBackendRelease(&pDb->sMem); + /* Commit or rollback result */ + return rc; +} +/* + * Release all resources consumed by the library. + * Note: This call is not thread safe. Refer to [unqlite_lib_shutdown()]. + */ +static void unqliteCoreShutdown(void) +{ + unqlite *pDb, *pNext; + /* Release all active databases handles */ + pDb = sUnqlMPGlobal.pDB; + for(;;){ + if( sUnqlMPGlobal.nDB < 1 ){ + break; + } + pNext = pDb->pNext; + unqliteDbRelease(pDb); + pDb = pNext; + sUnqlMPGlobal.nDB--; + } + /* Release the storage methods container */ + SySetRelease(&sUnqlMPGlobal.kv_storage); +#if defined(UNQLITE_ENABLE_THREADS) + /* Release the mutex subsystem */ + if( sUnqlMPGlobal.pMutexMethods ){ + if( sUnqlMPGlobal.pMutex ){ + SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); + sUnqlMPGlobal.pMutex = 0; + } + if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){ + sUnqlMPGlobal.pMutexMethods->xGlobalRelease(); + } + sUnqlMPGlobal.pMutexMethods = 0; + } + sUnqlMPGlobal.nThreadingLevel = 0; +#endif + if( sUnqlMPGlobal.sAllocator.pMethods ){ + /* Release the memory backend */ + SyMemBackendRelease(&sUnqlMPGlobal.sAllocator); + } + sUnqlMPGlobal.nMagic = 0x1764; + /* Finally, shutdown the Jx9 library */ + jx9_lib_shutdown(); +} +/* + * [CAPIREF: unqlite_lib_init()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_lib_init(void) +{ + int rc; + rc = unqliteCoreInitialize(); + return rc; +} +/* + * [CAPIREF: unqlite_lib_shutdown()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_lib_shutdown(void) +{ + if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ + /* Already shut */ + return UNQLITE_OK; + } + unqliteCoreShutdown(); + return UNQLITE_OK; +} +/* + * [CAPIREF: unqlite_lib_is_threadsafe()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_lib_is_threadsafe(void) +{ + if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ + return 0; + } +#if defined(UNQLITE_ENABLE_THREADS) + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ + /* Muli-threading support is enabled */ + return 1; + }else{ + /* Single-threading */ + return 0; + } +#else + return 0; +#endif +} +/* + * + * [CAPIREF: unqlite_lib_version()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_lib_version(void) +{ + return UNQLITE_VERSION; +} +/* + * + * [CAPIREF: unqlite_lib_signature()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_lib_signature(void) +{ + return UNQLITE_SIG; +} +/* + * + * [CAPIREF: unqlite_lib_ident()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_lib_ident(void) +{ + return UNQLITE_IDENT; +} +/* + * + * [CAPIREF: unqlite_lib_copyright()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_lib_copyright(void) +{ + return UNQLITE_COPYRIGHT; +} +/* + * Remove harmfull and/or stale flags passed to the [unqlite_open()] interface. + */ +static unsigned int unqliteSanityzeFlag(unsigned int iFlags) +{ + iFlags &= ~UNQLITE_OPEN_EXCLUSIVE; /* Reserved flag */ + if( iFlags & UNQLITE_OPEN_TEMP_DB ){ + /* Omit journaling for temporary database */ + iFlags |= UNQLITE_OPEN_OMIT_JOURNALING|UNQLITE_OPEN_CREATE; + } + if( (iFlags & (UNQLITE_OPEN_READONLY|UNQLITE_OPEN_READWRITE)) == 0 ){ + /* Auto-append the R+W flag */ + iFlags |= UNQLITE_OPEN_READWRITE; + } + if( iFlags & UNQLITE_OPEN_CREATE ){ + iFlags &= ~(UNQLITE_OPEN_MMAP|UNQLITE_OPEN_READONLY); + /* Auto-append the R+W flag */ + iFlags |= UNQLITE_OPEN_READWRITE; + }else{ + if( iFlags & UNQLITE_OPEN_READONLY ){ + iFlags &= ~UNQLITE_OPEN_READWRITE; + }else if( iFlags & UNQLITE_OPEN_READWRITE ){ + iFlags &= ~UNQLITE_OPEN_MMAP; + } + } + return iFlags; +} +/* + * This routine does the work of initializing a database handle on behalf + * of [unqlite_open()]. + */ +static int unqliteInitDatabase( + unqlite *pDB, /* Database handle */ + SyMemBackend *pParent, /* Master memory backend */ + const char *zFilename, /* Target database */ + unsigned int iFlags /* Open flags */ + ) +{ + unqlite_db *pStorage = &pDB->sDB; + int rc; + /* Initialiaze the memory subsystem */ + SyMemBackendInitFromParent(&pDB->sMem,pParent); +#if defined(UNQLITE_ENABLE_THREADS) + /* No need for internal mutexes */ + SyMemBackendDisbaleMutexing(&pDB->sMem); +#endif + SyBlobInit(&pDB->sErr,&pDB->sMem); + /* Sanityze flags */ + iFlags = unqliteSanityzeFlag(iFlags); + /* Init the pager and the transaction manager */ + rc = unqlitePagerOpen(sUnqlMPGlobal.pVfs,pDB,zFilename,iFlags); + if( rc != UNQLITE_OK ){ + return rc; + } + /* Allocate a new Jx9 engine handle */ + rc = jx9_init(&pStorage->pJx9); + if( rc != JX9_OK ){ + return rc; + } + return UNQLITE_OK; +} +/* + * Allocate and initialize a new UnQLite Virtual Mahcine and attach it + * to the compiled Jx9 script. + */ +static int unqliteInitVm(unqlite *pDb,jx9_vm *pJx9Vm,unqlite_vm **ppOut) +{ + unqlite_vm *pVm; + + *ppOut = 0; + /* Allocate a new VM instance */ + pVm = (unqlite_vm *)SyMemBackendPoolAlloc(&pDb->sMem,sizeof(unqlite_vm)); + if( pVm == 0 ){ + return UNQLITE_NOMEM; + } + /* Zero the structure */ + SyZero(pVm,sizeof(unqlite_vm)); + /* Initialize */ + SyMemBackendInitFromParent(&pVm->sAlloc,&pDb->sMem); + /* Allocate a new collection table */ + pVm->apCol = (unqlite_col **)SyMemBackendAlloc(&pVm->sAlloc,32 * sizeof(unqlite_col *)); + if( pVm->apCol == 0 ){ + goto fail; + } + pVm->iColSize = 32; /* Must be a power of two */ + /* Zero the table */ + SyZero((void *)pVm->apCol,pVm->iColSize * sizeof(unqlite_col *)); +#if defined(UNQLITE_ENABLE_THREADS) + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ + /* Associate a recursive mutex with this instance */ + pVm->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); + if( pVm->pMutex == 0 ){ + goto fail; + } + } +#endif + /* Link the VM to the list of active virtual machines */ + pVm->pJx9Vm = pJx9Vm; + pVm->pDb = pDb; + MACRO_LD_PUSH(pDb->pVms,pVm); + pDb->iVm++; + /* Register Jx9 functions */ + unqliteRegisterJx9Functions(pVm); + /* Set the magic number */ + pVm->nMagic = JX9_VM_INIT; /* Same magic number as Jx9 */ + /* All done */ + *ppOut = pVm; + return UNQLITE_OK; +fail: + SyMemBackendRelease(&pVm->sAlloc); + SyMemBackendPoolFree(&pDb->sMem,pVm); + return UNQLITE_NOMEM; +} +/* + * Release an active VM. + */ +static int unqliteVmRelease(unqlite_vm *pVm) +{ + /* Release the Jx9 VM */ + jx9_vm_release(pVm->pJx9Vm); + /* Release the private memory backend */ + SyMemBackendRelease(&pVm->sAlloc); + /* Upper layer will discard this VM from the list + * of active VM. + */ + return UNQLITE_OK; +} +/* + * Return the default page size. + */ +UNQLITE_PRIVATE int unqliteGetPageSize(void) +{ + int iSize = sUnqlMPGlobal.iPageSize; + if( iSize < UNQLITE_MIN_PAGE_SIZE || iSize > UNQLITE_MAX_PAGE_SIZE ){ + iSize = UNQLITE_DEFAULT_PAGE_SIZE; + } + return iSize; +} +/* + * Generate an error message. + */ +UNQLITE_PRIVATE int unqliteGenError(unqlite *pDb,const char *zErr) +{ + int rc; + /* Append the error message */ + rc = SyBlobAppend(&pDb->sErr,(const void *)zErr,SyStrlen(zErr)); + /* Append a new line */ + SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char)); + return rc; +} +/* + * Generate an error message (Printf like). + */ +UNQLITE_PRIVATE int unqliteGenErrorFormat(unqlite *pDb,const char *zFmt,...) +{ + va_list ap; + int rc; + va_start(ap,zFmt); + rc = SyBlobFormatAp(&pDb->sErr,zFmt,ap); + va_end(ap); + /* Append a new line */ + SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char)); + return rc; +} +/* + * Generate an error message (Out of memory). + */ +UNQLITE_PRIVATE int unqliteGenOutofMem(unqlite *pDb) +{ + int rc; + rc = unqliteGenError(pDb,"unQLite is running out of memory"); + return rc; +} +/* + * Configure a working UnQLite database handle. + */ +static int unqliteConfigure(unqlite *pDb,int nOp,va_list ap) +{ + int rc = UNQLITE_OK; + switch(nOp){ + case UNQLITE_CONFIG_JX9_ERR_LOG: + /* Jx9 compile-time error log */ + rc = jx9EngineConfig(pDb->sDB.pJx9,JX9_CONFIG_ERR_LOG,ap); + break; + case UNQLITE_CONFIG_MAX_PAGE_CACHE: { + int max_page = va_arg(ap,int); + /* Maximum number of page to cache (Simple hint). */ + rc = unqlitePagerSetCachesize(pDb->sDB.pPager,max_page); + break; + } + case UNQLITE_CONFIG_ERR_LOG: { + /* Database error log if any */ + const char **pzPtr = va_arg(ap, const char **); + int *pLen = va_arg(ap, int *); + if( pzPtr == 0 ){ + rc = JX9_CORRUPT; + break; + } + /* NULL terminate the error-log buffer */ + SyBlobNullAppend(&pDb->sErr); + /* Point to the error-log buffer */ + *pzPtr = (const char *)SyBlobData(&pDb->sErr); + if( pLen ){ + if( SyBlobLength(&pDb->sErr) > 1 /* NULL '\0' terminator */ ){ + *pLen = (int)SyBlobLength(&pDb->sErr); + }else{ + *pLen = 0; + } + } + break; + } + case UNQLITE_CONFIG_DISABLE_AUTO_COMMIT:{ + /* Disable auto-commit */ + pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT; + break; + } + case UNQLITE_CONFIG_GET_KV_NAME: { + /* Name of the underlying KV storage engine */ + const char **pzPtr = va_arg(ap,const char **); + if( pzPtr ){ + unqlite_kv_engine *pEngine; + pEngine = unqlitePagerGetKvEngine(pDb); + /* Point to the name */ + *pzPtr = pEngine->pIo->pMethods->zName; + } + break; + } + default: + /* Unknown configuration option */ + rc = UNQLITE_UNKNOWN; + break; + } + return rc; +} +/* + * Export the global (master) memory allocator to submodules. + */ +UNQLITE_PRIVATE const SyMemBackend * unqliteExportMemBackend(void) +{ + return &sUnqlMPGlobal.sAllocator; +} +/* + * [CAPIREF: unqlite_open()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_open(unqlite **ppDB,const char *zFilename,unsigned int iMode) +{ + unqlite *pHandle; + int rc; +#if defined(UNTRUST) + if( ppDB == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + *ppDB = 0; + /* One-time automatic library initialization */ + rc = unqliteCoreInitialize(); + if( rc != UNQLITE_OK ){ + return rc; + } + /* Allocate a new database handle */ + pHandle = (unqlite *)SyMemBackendPoolAlloc(&sUnqlMPGlobal.sAllocator, sizeof(unqlite)); + if( pHandle == 0 ){ + return UNQLITE_NOMEM; + } + /* Zero the structure */ + SyZero(pHandle,sizeof(unqlite)); + if( iMode < 1 ){ + /* Assume a read-only database */ + iMode = UNQLITE_OPEN_READONLY|UNQLITE_OPEN_MMAP; + } + /* Init the database */ + rc = unqliteInitDatabase(pHandle,&sUnqlMPGlobal.sAllocator,zFilename,iMode); + if( rc != UNQLITE_OK ){ + goto Release; + } +#if defined(UNQLITE_ENABLE_THREADS) + if( !(iMode & UNQLITE_OPEN_NOMUTEX) && (sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE) ){ + /* Associate a recursive mutex with this instance */ + pHandle->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); + if( pHandle->pMutex == 0 ){ + rc = UNQLITE_NOMEM; + goto Release; + } + } +#endif + /* Link to the list of active DB handles */ +#if defined(UNQLITE_ENABLE_THREADS) + /* Enter the global mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ +#endif + MACRO_LD_PUSH(sUnqlMPGlobal.pDB,pHandle); + sUnqlMPGlobal.nDB++; +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave the global mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ +#endif + /* Set the magic number to identify a valid DB handle */ + pHandle->nMagic = UNQLITE_DB_MAGIC; + /* Make the handle available to the caller */ + *ppDB = pHandle; + return UNQLITE_OK; +Release: + SyMemBackendRelease(&pHandle->sMem); + SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pHandle); + return rc; +} +/* + * [CAPIREF: unqlite_config()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_config(unqlite *pDb,int nConfigOp,...) +{ + va_list ap; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + va_start(ap, nConfigOp); + rc = unqliteConfigure(&(*pDb),nConfigOp, ap); + va_end(ap); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_close()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_close(unqlite *pDb) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Release the database handle */ + rc = unqliteDbRelease(pDb); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + /* Release DB mutex */ + SyMutexRelease(sUnqlMPGlobal.pMutexMethods, pDb->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif +#if defined(UNQLITE_ENABLE_THREADS) + /* Enter the global mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ +#endif + /* Unlink from the list of active database handles */ + MACRO_LD_REMOVE(sUnqlMPGlobal.pDB, pDb); + sUnqlMPGlobal.nDB--; +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave the global mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ +#endif + /* Release the memory chunk allocated to this handle */ + SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pDb); + return rc; +} +/* + * [CAPIREF: unqlite_compile()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_compile(unqlite *pDb,const char *zJx9,int nByte,unqlite_vm **ppOut) +{ + jx9_vm *pVm; + int rc; + if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; + } +#endif + /* Compile the Jx9 script first */ + rc = jx9_compile(pDb->sDB.pJx9,zJx9,nByte,&pVm); + if( rc == JX9_OK ){ + /* Allocate a new unqlite VM instance */ + rc = unqliteInitVm(pDb,pVm,ppOut); + if( rc != UNQLITE_OK ){ + /* Release the Jx9 VM */ + jx9_vm_release(pVm); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_compile_file()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_compile_file(unqlite *pDb,const char *zPath,unqlite_vm **ppOut) +{ + jx9_vm *pVm; + int rc; + if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; + } +#endif + /* Compile the Jx9 script first */ + rc = jx9_compile_file(pDb->sDB.pJx9,zPath,&pVm); + if( rc == JX9_OK ){ + /* Allocate a new unqlite VM instance */ + rc = unqliteInitVm(pDb,pVm,ppOut); + if( rc != UNQLITE_OK ){ + /* Release the Jx9 VM */ + jx9_vm_release(pVm); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * Configure an unqlite virtual machine (Mostly Jx9 VM) instance. + */ +static int unqliteVmConfig(unqlite_vm *pVm,sxi32 iOp,va_list ap) +{ + int rc; + rc = jx9VmConfigure(pVm->pJx9Vm,iOp,ap); + return rc; +} +/* + * [CAPIREF: unqlite_vm_config()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_config(unqlite_vm *pVm,int iOp,...) +{ + va_list ap; + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + va_start(ap,iOp); + rc = unqliteVmConfig(pVm,iOp,ap); + va_end(ap); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_vm_exec()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_exec(unqlite_vm *pVm) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Execute the Jx9 bytecode program */ + rc = jx9VmByteCodeExec(pVm->pJx9Vm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_vm_release()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_release(unqlite_vm *pVm) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Release the VM */ + rc = unqliteVmRelease(pVm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave VM mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + /* Release VM mutex */ + SyMutexRelease(sUnqlMPGlobal.pMutexMethods,pVm->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + if( rc == UNQLITE_OK ){ + unqlite *pDb = pVm->pDb; + /* Unlink from the list of active VM's */ +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + MACRO_LD_REMOVE(pDb->pVms, pVm); + pDb->iVm--; + /* Release the memory chunk allocated to this instance */ + SyMemBackendPoolFree(&pDb->sMem,pVm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + } + return rc; +} +/* + * [CAPIREF: unqlite_vm_reset()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_reset(unqlite_vm *pVm) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Reset the Jx9 VM */ + rc = jx9VmReset(pVm->pJx9Vm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_vm_dump()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_dump(unqlite_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Dump the Jx9 VM */ + rc = jx9VmDump(pVm->pJx9Vm,xConsumer,pUserData); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_vm_extract_variable()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_vm_extract_variable(unqlite_vm *pVm,const char *zVarname) +{ + unqlite_value *pValue; + SyString sVariable; + if( UNQLITE_VM_MISUSE(pVm) ){ + return 0; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return 0; /* Another thread have released this instance */ + } +#endif + /* Extract the target variable */ + SyStringInitFromBuf(&sVariable,zVarname,SyStrlen(zVarname)); + pValue = jx9VmExtractVariable(pVm->pJx9Vm,&sVariable); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return pValue; +} +/* + * [CAPIREF: unqlite_create_function()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_create_function(unqlite_vm *pVm, const char *zName,int (*xFunc)(unqlite_context *,int,unqlite_value **),void *pUserData) +{ + SyString sName; + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } + SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); + /* Remove leading and trailing white spaces */ + SyStringFullTrim(&sName); + /* Ticket 1433-003: NULL values are not allowed */ + if( sName.nByte < 1 || xFunc == 0 ){ + return UNQLITE_INVALID; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Install the foreign function */ + rc = jx9VmInstallForeignFunction(pVm->pJx9Vm,&sName,xFunc,pUserData); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_delete_function()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_delete_function(unqlite_vm *pVm, const char *zName) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Unlink the foreign function */ + rc = jx9DeleteFunction(pVm->pJx9Vm,zName); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_create_constant()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_create_constant(unqlite_vm *pVm,const char *zName,void (*xExpand)(unqlite_value *, void *),void *pUserData) +{ + SyString sName; + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } + SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); + /* Remove leading and trailing white spaces */ + SyStringFullTrim(&sName); + if( sName.nByte < 1 ){ + /* Empty constant name */ + return UNQLITE_INVALID; + } + /* TICKET 1433-003: NULL pointer is harmless operation */ + if( xExpand == 0 ){ + return UNQLITE_INVALID; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Install the foreign constant */ + rc = jx9VmRegisterConstant(pVm->pJx9Vm,&sName,xExpand,pUserData); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_delete_constant()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_delete_constant(unqlite_vm *pVm, const char *zName) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Unlink the foreign constant */ + rc = Jx9DeleteConstant(pVm->pJx9Vm,zName); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_value_int()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_int(unqlite_value *pVal, int iValue) +{ + return jx9_value_int(pVal,iValue); +} +/* + * [CAPIREF: unqlite_value_int64()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_int64(unqlite_value *pVal,unqlite_int64 iValue) +{ + return jx9_value_int64(pVal,iValue); +} +/* + * [CAPIREF: unqlite_value_bool()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_bool(unqlite_value *pVal, int iBool) +{ + return jx9_value_bool(pVal,iBool); +} +/* + * [CAPIREF: unqlite_value_null()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_null(unqlite_value *pVal) +{ + return jx9_value_null(pVal); +} +/* + * [CAPIREF: unqlite_value_double()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_double(unqlite_value *pVal, double Value) +{ + return jx9_value_double(pVal,Value); +} +/* + * [CAPIREF: unqlite_value_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_string(unqlite_value *pVal, const char *zString, int nLen) +{ + return jx9_value_string(pVal,zString,nLen); +} +/* + * [CAPIREF: unqlite_value_string_format()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_string_format(unqlite_value *pVal, const char *zFormat,...) +{ + va_list ap; + int rc; + if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ + /* Invalidate any prior representation */ + jx9MemObjRelease(pVal); + MemObjSetType(pVal, MEMOBJ_STRING); + } + va_start(ap, zFormat); + rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap); + va_end(ap); + return UNQLITE_OK; +} +/* + * [CAPIREF: unqlite_value_reset_string_cursor()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_reset_string_cursor(unqlite_value *pVal) +{ + return jx9_value_reset_string_cursor(pVal); +} +/* + * [CAPIREF: unqlite_value_resource()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_resource(unqlite_value *pVal,void *pUserData) +{ + return jx9_value_resource(pVal,pUserData); +} +/* + * [CAPIREF: unqlite_value_release()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_release(unqlite_value *pVal) +{ + return jx9_value_release(pVal); +} +/* + * [CAPIREF: unqlite_value_to_int()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_to_int(unqlite_value *pValue) +{ + return jx9_value_to_int(pValue); +} +/* + * [CAPIREF: unqlite_value_to_bool()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_to_bool(unqlite_value *pValue) +{ + return jx9_value_to_bool(pValue); +} +/* + * [CAPIREF: unqlite_value_to_int64()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_int64 unqlite_value_to_int64(unqlite_value *pValue) +{ + return jx9_value_to_int64(pValue); +} +/* + * [CAPIREF: unqlite_value_to_double()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +double unqlite_value_to_double(unqlite_value *pValue) +{ + return jx9_value_to_double(pValue); +} +/* + * [CAPIREF: unqlite_value_to_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_value_to_string(unqlite_value *pValue, int *pLen) +{ + return jx9_value_to_string(pValue,pLen); +} +/* + * [CAPIREF: unqlite_value_to_resource()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_value_to_resource(unqlite_value *pValue) +{ + return jx9_value_to_resource(pValue); +} +/* + * [CAPIREF: unqlite_value_compare()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_compare(unqlite_value *pLeft, unqlite_value *pRight, int bStrict) +{ + return jx9_value_compare(pLeft,pRight,bStrict); +} +/* + * [CAPIREF: unqlite_result_int()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_int(unqlite_context *pCtx, int iValue) +{ + return jx9_result_int(pCtx,iValue); +} +/* + * [CAPIREF: unqlite_result_int64()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_int64(unqlite_context *pCtx, unqlite_int64 iValue) +{ + return jx9_result_int64(pCtx,iValue); +} +/* + * [CAPIREF: unqlite_result_bool()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_bool(unqlite_context *pCtx, int iBool) +{ + return jx9_result_bool(pCtx,iBool); +} +/* + * [CAPIREF: unqlite_result_double()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_double(unqlite_context *pCtx, double Value) +{ + return jx9_result_double(pCtx,Value); +} +/* + * [CAPIREF: unqlite_result_null()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_null(unqlite_context *pCtx) +{ + return jx9_result_null(pCtx); +} +/* + * [CAPIREF: unqlite_result_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_string(unqlite_context *pCtx, const char *zString, int nLen) +{ + return jx9_result_string(pCtx,zString,nLen); +} +/* + * [CAPIREF: unqlite_result_string_format()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_string_format(unqlite_context *pCtx, const char *zFormat, ...) +{ + jx9_value *p; + va_list ap; + int rc; + p = pCtx->pRet; + if( (p->iFlags & MEMOBJ_STRING) == 0 ){ + /* Invalidate any prior representation */ + jx9MemObjRelease(p); + MemObjSetType(p, MEMOBJ_STRING); + } + /* Format the given string */ + va_start(ap, zFormat); + rc = SyBlobFormatAp(&p->sBlob, zFormat, ap); + va_end(ap); + return rc; +} +/* + * [CAPIREF: unqlite_result_value()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_value(unqlite_context *pCtx, unqlite_value *pValue) +{ + return jx9_result_value(pCtx,pValue); +} +/* + * [CAPIREF: unqlite_result_resource()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_result_resource(unqlite_context *pCtx, void *pUserData) +{ + return jx9_result_resource(pCtx,pUserData); +} +/* + * [CAPIREF: unqlite_value_is_int()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_int(unqlite_value *pVal) +{ + return jx9_value_is_int(pVal); +} +/* + * [CAPIREF: unqlite_value_is_float()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_float(unqlite_value *pVal) +{ + return jx9_value_is_float(pVal); +} +/* + * [CAPIREF: unqlite_value_is_bool()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_bool(unqlite_value *pVal) +{ + return jx9_value_is_bool(pVal); +} +/* + * [CAPIREF: unqlite_value_is_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_string(unqlite_value *pVal) +{ + return jx9_value_is_string(pVal); +} +/* + * [CAPIREF: unqlite_value_is_null()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_null(unqlite_value *pVal) +{ + return jx9_value_is_null(pVal); +} +/* + * [CAPIREF: unqlite_value_is_numeric()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_numeric(unqlite_value *pVal) +{ + return jx9_value_is_numeric(pVal); +} +/* + * [CAPIREF: unqlite_value_is_callable()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_callable(unqlite_value *pVal) +{ + return jx9_value_is_callable(pVal); +} +/* + * [CAPIREF: unqlite_value_is_scalar()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_scalar(unqlite_value *pVal) +{ + return jx9_value_is_scalar(pVal); +} +/* + * [CAPIREF: unqlite_value_is_json_array()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_json_array(unqlite_value *pVal) +{ + return jx9_value_is_json_array(pVal); +} +/* + * [CAPIREF: unqlite_value_is_json_object()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_json_object(unqlite_value *pVal) +{ + return jx9_value_is_json_object(pVal); +} +/* + * [CAPIREF: unqlite_value_is_resource()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_resource(unqlite_value *pVal) +{ + return jx9_value_is_resource(pVal); +} +/* + * [CAPIREF: unqlite_value_is_empty()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_value_is_empty(unqlite_value *pVal) +{ + return jx9_value_is_empty(pVal); +} +/* + * [CAPIREF: unqlite_array_fetch()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_array_fetch(unqlite_value *pArray, const char *zKey, int nByte) +{ + return jx9_array_fetch(pArray,zKey,nByte); +} +/* + * [CAPIREF: unqlite_array_walk()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_array_walk(unqlite_value *pArray, int (*xWalk)(unqlite_value *, unqlite_value *, void *), void *pUserData) +{ + return jx9_array_walk(pArray,xWalk,pUserData); +} +/* + * [CAPIREF: unqlite_array_add_elem()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_array_add_elem(unqlite_value *pArray, unqlite_value *pKey, unqlite_value *pValue) +{ + return jx9_array_add_elem(pArray,pKey,pValue); +} +/* + * [CAPIREF: unqlite_array_add_strkey_elem()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_array_add_strkey_elem(unqlite_value *pArray, const char *zKey, unqlite_value *pValue) +{ + return jx9_array_add_strkey_elem(pArray,zKey,pValue); +} +/* + * [CAPIREF: unqlite_array_count()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_array_count(unqlite_value *pArray) +{ + return (int)jx9_array_count(pArray); +} +/* + * [CAPIREF: unqlite_vm_new_scalar()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_vm_new_scalar(unqlite_vm *pVm) +{ + unqlite_value *pValue; + if( UNQLITE_VM_MISUSE(pVm) ){ + return 0; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return 0; /* Another thread have released this instance */ + } +#endif + pValue = jx9_new_scalar(pVm->pJx9Vm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return pValue; +} +/* + * [CAPIREF: unqlite_vm_new_array()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_vm_new_array(unqlite_vm *pVm) +{ + unqlite_value *pValue; + if( UNQLITE_VM_MISUSE(pVm) ){ + return 0; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return 0; /* Another thread have released this instance */ + } +#endif + pValue = jx9_new_array(pVm->pJx9Vm); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return pValue; +} +/* + * [CAPIREF: unqlite_vm_release_value()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_vm_release_value(unqlite_vm *pVm,unqlite_value *pValue) +{ + int rc; + if( UNQLITE_VM_MISUSE(pVm) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire VM mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_VM_RELEASE(pVm) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + rc = jx9_release_value(pVm->pJx9Vm,pValue); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_context_output()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_output(unqlite_context *pCtx, const char *zString, int nLen) +{ + return jx9_context_output(pCtx,zString,nLen); +} +/* + * [CAPIREF: unqlite_context_output_format()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_output_format(unqlite_context *pCtx,const char *zFormat, ...) +{ + va_list ap; + int rc; + va_start(ap, zFormat); + rc = jx9VmOutputConsumeAp(pCtx->pVm,zFormat, ap); + va_end(ap); + return rc; +} +/* + * [CAPIREF: unqlite_context_throw_error()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_throw_error(unqlite_context *pCtx, int iErr, const char *zErr) +{ + return jx9_context_throw_error(pCtx,iErr,zErr); +} +/* + * [CAPIREF: unqlite_context_throw_error_format()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_throw_error_format(unqlite_context *pCtx, int iErr, const char *zFormat, ...) +{ + va_list ap; + int rc; + if( zFormat == 0){ + return JX9_OK; + } + va_start(ap, zFormat); + rc = jx9VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap); + va_end(ap); + return rc; +} +/* + * [CAPIREF: unqlite_context_random_num()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unsigned int unqlite_context_random_num(unqlite_context *pCtx) +{ + return jx9_context_random_num(pCtx); +} +/* + * [CAPIREF: unqlite_context_random_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_random_string(unqlite_context *pCtx, char *zBuf, int nBuflen) +{ + return jx9_context_random_string(pCtx,zBuf,nBuflen); +} +/* + * [CAPIREF: unqlite_context_user_data()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_context_user_data(unqlite_context *pCtx) +{ + return jx9_context_user_data(pCtx); +} +/* + * [CAPIREF: unqlite_context_push_aux_data()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_context_push_aux_data(unqlite_context *pCtx, void *pUserData) +{ + return jx9_context_push_aux_data(pCtx,pUserData); +} +/* + * [CAPIREF: unqlite_context_peek_aux_data()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_context_peek_aux_data(unqlite_context *pCtx) +{ + return jx9_context_peek_aux_data(pCtx); +} +/* + * [CAPIREF: unqlite_context_pop_aux_data()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_context_pop_aux_data(unqlite_context *pCtx) +{ + return jx9_context_pop_aux_data(pCtx); +} +/* + * [CAPIREF: unqlite_context_result_buf_length()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unsigned int unqlite_context_result_buf_length(unqlite_context *pCtx) +{ + return jx9_context_result_buf_length(pCtx); +} +/* + * [CAPIREF: unqlite_function_name()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +const char * unqlite_function_name(unqlite_context *pCtx) +{ + return jx9_function_name(pCtx); +} +/* + * [CAPIREF: unqlite_context_new_scalar()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_context_new_scalar(unqlite_context *pCtx) +{ + return jx9_context_new_scalar(pCtx); +} +/* + * [CAPIREF: unqlite_context_new_array()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +unqlite_value * unqlite_context_new_array(unqlite_context *pCtx) +{ + return jx9_context_new_array(pCtx); +} +/* + * [CAPIREF: unqlite_context_release_value()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void unqlite_context_release_value(unqlite_context *pCtx,unqlite_value *pValue) +{ + jx9_context_release_value(pCtx,pValue); +} +/* + * [CAPIREF: unqlite_context_alloc_chunk()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_context_alloc_chunk(unqlite_context *pCtx,unsigned int nByte,int ZeroChunk,int AutoRelease) +{ + return jx9_context_alloc_chunk(pCtx,nByte,ZeroChunk,AutoRelease); +} +/* + * [CAPIREF: unqlite_context_realloc_chunk()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void * unqlite_context_realloc_chunk(unqlite_context *pCtx,void *pChunk,unsigned int nByte) +{ + return jx9_context_realloc_chunk(pCtx,pChunk,nByte); +} +/* + * [CAPIREF: unqlite_context_free_chunk()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +void unqlite_context_free_chunk(unqlite_context *pCtx,void *pChunk) +{ + jx9_context_free_chunk(pCtx,pChunk); +} +/* + * [CAPIREF: unqlite_kv_store()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_store(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen) +{ + unqlite_kv_engine *pEngine; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + if( pEngine->pIo->pMethods->xReplace == 0 ){ + /* Storage engine does not implement such method */ + unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + /* Perform the requested operation */ + rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,pData,nDataLen); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_store_fmt()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_store_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...) +{ + unqlite_kv_engine *pEngine; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + if( pEngine->pIo->pMethods->xReplace == 0 ){ + /* Storage engine does not implement such method */ + unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + SyBlob sWorker; /* Working buffer */ + va_list ap; + SyBlobInit(&sWorker,&pDb->sMem); + /* Format the data */ + va_start(ap,zFormat); + SyBlobFormatAp(&sWorker,zFormat,ap); + va_end(ap); + /* Perform the requested operation */ + rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker)); + /* Clean up */ + SyBlobRelease(&sWorker); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_append()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_append(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen) +{ + unqlite_kv_engine *pEngine; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + if( pEngine->pIo->pMethods->xAppend == 0 ){ + /* Storage engine does not implement such method */ + unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + /* Perform the requested operation */ + rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,pData,nDataLen); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_append_fmt()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_append_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...) +{ + unqlite_kv_engine *pEngine; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + if( pEngine->pIo->pMethods->xAppend == 0 ){ + /* Storage engine does not implement such method */ + unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + SyBlob sWorker; /* Working buffer */ + va_list ap; + SyBlobInit(&sWorker,&pDb->sMem); + /* Format the data */ + va_start(ap,zFormat); + SyBlobFormatAp(&sWorker,zFormat,ap); + va_end(ap); + /* Perform the requested operation */ + rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker)); + /* Clean up */ + SyBlobRelease(&sWorker); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_fetch()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_fetch(unqlite *pDb,const void *pKey,int nKeyLen,void *pBuf,unqlite_int64 *pBufLen) +{ + unqlite_kv_methods *pMethods; + unqlite_kv_engine *pEngine; + unqlite_kv_cursor *pCur; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + pMethods = pEngine->pIo->pMethods; + pCur = pDb->sDB.pCursor; + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + /* Seek to the record position */ + rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); + } + if( rc == UNQLITE_OK ){ + if( pBuf == 0 ){ + /* Data length only */ + rc = pMethods->xDataLength(pCur,pBufLen); + }else{ + SyBlob sBlob; + /* Initialize the data consumer */ + SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)*pBufLen); + /* Consume the data */ + rc = pMethods->xData(pCur,unqliteDataConsumer,&sBlob); + /* Data length */ + *pBufLen = (unqlite_int64)SyBlobLength(&sBlob); + /* Cleanup */ + SyBlobRelease(&sBlob); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_fetch_callback()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) +{ + unqlite_kv_methods *pMethods; + unqlite_kv_engine *pEngine; + unqlite_kv_cursor *pCur; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + pMethods = pEngine->pIo->pMethods; + pCur = pDb->sDB.pCursor; + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + /* Seek to the record position */ + rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); + } + if( rc == UNQLITE_OK && xConsumer ){ + /* Consume the data directly */ + rc = pMethods->xData(pCur,xConsumer,pUserData); + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_delete()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_delete(unqlite *pDb,const void *pKey,int nKeyLen) +{ + unqlite_kv_methods *pMethods; + unqlite_kv_engine *pEngine; + unqlite_kv_cursor *pCur; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + pMethods = pEngine->pIo->pMethods; + pCur = pDb->sDB.pCursor; + if( pMethods->xDelete == 0 ){ + /* Storage engine does not implement such method */ + unqliteGenError(pDb,"xDelete() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + unqliteGenError(pDb,"Empty key"); + rc = UNQLITE_EMPTY; + }else{ + /* Seek to the record position */ + rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); + } + if( rc == UNQLITE_OK ){ + /* Exact match found, delete the entry */ + rc = pMethods->xDelete(pCur); + } + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_config()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_config(unqlite *pDb,int iOp,...) +{ + unqlite_kv_engine *pEngine; + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Point to the underlying storage engine */ + pEngine = unqlitePagerGetKvEngine(pDb); + if( pEngine->pIo->pMethods->xConfig == 0 ){ + /* Storage engine does not implements such method */ + unqliteGenError(pDb,"xConfig() method not implemented in the underlying storage engine"); + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + va_list ap; + /* Configure the storage engine */ + va_start(ap,iOp); + rc = pEngine->pIo->pMethods->xConfig(pEngine,iOp,ap); + va_end(ap); + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_init()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0 /* Noop */){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Allocate a new cursor */ + rc = unqliteInitCursor(pDb,ppOut); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_release()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) || pCur == 0 /* Noop */){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Release the cursor */ + rc = unqliteReleaseCursor(pDb,pCur); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_first_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xFirst == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Seek to the first entry */ + rc = pCursor->pStore->pIo->pMethods->xFirst(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_last_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xLast == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Seek to the last entry */ + rc = pCursor->pStore->pIo->pMethods->xLast(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_valid_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xValid == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + rc = pCursor->pStore->pIo->pMethods->xValid(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_next_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xNext == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Seek to the next entry */ + rc = pCursor->pStore->pIo->pMethods->xNext(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_prev_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xPrev == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Seek to the previous entry */ + rc = pCursor->pStore->pIo->pMethods->xPrev(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_delete_entry()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xDelete == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Delete the entry */ + rc = pCursor->pStore->pIo->pMethods->xDelete(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_reset()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor) +{ + int rc = UNQLITE_OK; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Check if the requested method is implemented by the underlying storage engine */ + if( pCursor->pStore->pIo->pMethods->xReset == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Reset */ + pCursor->pStore->pIo->pMethods->xReset(pCursor); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_seek()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos) +{ + int rc = UNQLITE_OK; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + if( nKeyLen < 0 ){ + /* Assume a null terminated string and compute it's length */ + nKeyLen = SyStrlen((const char *)pKey); + } + if( !nKeyLen ){ + rc = UNQLITE_EMPTY; + }else{ + /* Seek to the desired location */ + rc = pCursor->pStore->pIo->pMethods->xSeek(pCursor,pKey,nKeyLen,iPos); + } + return rc; +} +/* + * Default data consumer callback. That is, all retrieved is redirected to this + * routine which store the output in an internal blob. + */ +UNQLITE_PRIVATE int unqliteDataConsumer( + const void *pOut, /* Data to consume */ + unsigned int nLen, /* Data length */ + void *pUserData /* User private data */ + ) +{ + sxi32 rc; + /* Store the output in an internal BLOB */ + rc = SyBlobAppend((SyBlob *)pUserData, pOut, nLen); + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_data_callback()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Consume the key directly */ + rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,xConsumer,pUserData); + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_key()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + if( pBuf == 0 ){ + /* Key length only */ + rc = pCursor->pStore->pIo->pMethods->xKeyLength(pCursor,pnByte); + }else{ + SyBlob sBlob; + if( (*pnByte) < 0 ){ + return UNQLITE_CORRUPT; + } + /* Initialize the data consumer */ + SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte)); + /* Consume the key */ + rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,unqliteDataConsumer,&sBlob); + /* Key length */ + *pnByte = SyBlobLength(&sBlob); + /* Cleanup */ + SyBlobRelease(&sBlob); + } + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_data_callback()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + /* Consume the data directly */ + rc = pCursor->pStore->pIo->pMethods->xData(pCursor,xConsumer,pUserData); + return rc; +} +/* + * [CAPIREF: unqlite_kv_cursor_data()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnByte) +{ + int rc; +#ifdef UNTRUST + if( pCursor == 0 ){ + return UNQLITE_CORRUPT; + } +#endif + if( pBuf == 0 ){ + /* Data length only */ + rc = pCursor->pStore->pIo->pMethods->xDataLength(pCursor,pnByte); + }else{ + SyBlob sBlob; + if( (*pnByte) < 0 ){ + return UNQLITE_CORRUPT; + } + /* Initialize the data consumer */ + SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte)); + /* Consume the data */ + rc = pCursor->pStore->pIo->pMethods->xData(pCursor,unqliteDataConsumer,&sBlob); + /* Data length */ + *pnByte = SyBlobLength(&sBlob); + /* Cleanup */ + SyBlobRelease(&sBlob); + } + return rc; +} +/* + * [CAPIREF: unqlite_begin()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_begin(unqlite *pDb) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Begin the write transaction */ + rc = unqlitePagerBegin(pDb->sDB.pPager); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_commit()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_commit(unqlite *pDb) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Commit the transaction */ + rc = unqlitePagerCommit(pDb->sDB.pPager); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_rollback()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int unqlite_rollback(unqlite *pDb) +{ + int rc; + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Rollback the transaction */ + rc = unqlitePagerRollback(pDb->sDB.pPager,TRUE); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return rc; +} +/* + * [CAPIREF: unqlite_util_load_mmaped_file()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +UNQLITE_APIEXPORT int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize) +{ + const jx9_vfs *pVfs; + int rc; + if( SX_EMPTY_STR(zFile) || ppMap == 0 || pFileSize == 0){ + /* Sanity check */ + return UNQLITE_CORRUPT; + } + *ppMap = 0; + /* Extract the Jx9 Vfs */ + pVfs = jx9ExportBuiltinVfs(); + /* + * Check if the underlying vfs implement the memory map routines + * [i.e: mmap() under UNIX/MapViewOfFile() under windows]. + */ + if( pVfs == 0 || pVfs->xMmap == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + /* Try to get a read-only memory view of the whole file */ + rc = pVfs->xMmap(zFile,ppMap,pFileSize); + } + return rc; +} +/* + * [CAPIREF: unqlite_util_release_mmaped_file()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +UNQLITE_APIEXPORT int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize) +{ + const jx9_vfs *pVfs; + int rc = UNQLITE_OK; + if( pMap == 0 ){ + return UNQLITE_OK; + } + /* Extract the Jx9 Vfs */ + pVfs = jx9ExportBuiltinVfs(); + if( pVfs == 0 || pVfs->xUnmap == 0 ){ + rc = UNQLITE_NOTIMPLEMENTED; + }else{ + pVfs->xUnmap(pMap,iFileSize); + } + return rc; +} +/* + * [CAPIREF: unqlite_util_random_string()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +UNQLITE_APIEXPORT int unqlite_util_random_string(unqlite *pDb,char *zBuf,unsigned int buf_size) +{ + if( UNQLITE_DB_MISUSE(pDb) ){ + return UNQLITE_CORRUPT; + } + if( zBuf == 0 || buf_size < 3 ){ + /* Buffer must be long enough to hold three bytes */ + return UNQLITE_INVALID; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return UNQLITE_ABORT; /* Another thread have released this instance */ + } +#endif + /* Generate the random string */ + unqlitePagerRandomString(pDb->sDB.pPager,zBuf,buf_size); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return UNQLITE_OK; +} +/* + * [CAPIREF: unqlite_util_random_num()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +UNQLITE_APIEXPORT unsigned int unqlite_util_random_num(unqlite *pDb) +{ + sxu32 iNum; + if( UNQLITE_DB_MISUSE(pDb) ){ + return 0; + } +#if defined(UNQLITE_ENABLE_THREADS) + /* Acquire DB mutex */ + SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ + if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && + UNQLITE_THRD_DB_RELEASE(pDb) ){ + return 0; /* Another thread have released this instance */ + } +#endif + /* Generate the random number */ + iNum = unqlitePagerRandomNum(pDb->sDB.pPager); +#if defined(UNQLITE_ENABLE_THREADS) + /* Leave DB mutex */ + SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ +#endif + return iNum; +} -- cgit v1.2.3