void UnqliteCursor::seek( const char* key, int key_len, SeekMatchType match_type ) { int iPos = 0; switch (match_type) { case SEEK_MATCH_EXACT: iPos = UNQLITE_CURSOR_MATCH_EXACT; break; case SEEK_MATCH_LE: iPos = UNQLITE_CURSOR_MATCH_LE; break; case SEEK_MATCH_GE: iPos = UNQLITE_CURSOR_MATCH_GE; break; default: throw UnqliteException(UNQLITE_INVALID); } int rc = unqlite_kv_cursor_seek(this->_cursor, key, key_len, iPos); if (rc != UNQLITE_OK) throw UnqliteException(rc, this->_db); }
/* * Fetch a record by its unique ID. */ UNQLITE_PRIVATE int unqliteCollectionFetchRecordById( unqlite_col *pCol, /* Target collection */ jx9_int64 nId, /* Unique record ID */ jx9_value *pValue /* OUT: record value */ ) { SyBlob *pWorker = &pCol->sWorker; unqlite_col_record *pRec; int rc; jx9_value_null(pValue); /* Perform a cache lookup first */ pRec = CollectionCacheFetchRecord(pCol,nId); if( pRec ){ /* Copy record value */ jx9MemObjStore(&pRec->sValue,pValue); return UNQLITE_OK; } /* Reset the working buffer */ SyBlobReset(pWorker); /* Generate the unique ID */ SyBlobFormat(pWorker,"%z_%qd",&pCol->sName,nId); /* Reset the cursor */ unqlite_kv_cursor_reset(pCol->pCursor); /* Seek the cursor to the desired location */ rc = unqlite_kv_cursor_seek(pCol->pCursor, SyBlobData(pWorker),SyBlobLength(pWorker), UNQLITE_CURSOR_MATCH_EXACT ); if( rc != UNQLITE_OK ){ return rc; } /* Consume the binary JSON */ SyBlobReset(pWorker); unqlite_kv_cursor_data_callback(pCol->pCursor,unqliteDataConsumer,pWorker); if( SyBlobLength(pWorker) < 1 ){ unqliteGenErrorFormat(pCol->pVm->pDb, "Empty record '%qd'",nId ); jx9_value_null(pValue); }else{ /* Decode the binary JSON */ rc = FastJsonDecode(SyBlobData(pWorker),SyBlobLength(pWorker),pValue,0,0); if( rc == UNQLITE_OK ){ /* Install the record in the cache */ CollectionCacheInstallRecord(pCol,nId,pValue); } } return rc; }
/* * Drop a collection from the KV storage engine and the underlying * unqlite VM. */ UNQLITE_PRIVATE int unqliteDropCollection(unqlite_col *pCol) { unqlite_vm *pVm = pCol->pVm; jx9_int64 nId; int rc; /* Reset the cursor */ unqlite_kv_cursor_reset(pCol->pCursor); /* Seek the cursor to the desired location */ rc = unqlite_kv_cursor_seek(pCol->pCursor, SyStringData(&pCol->sName),SyStringLength(&pCol->sName), UNQLITE_CURSOR_MATCH_EXACT ); if( rc == UNQLITE_OK ){ /* Remove the record from the storage engine */ rc = unqlite_kv_cursor_delete_entry(pCol->pCursor); } if( rc != UNQLITE_OK ){ unqliteGenErrorFormat(pCol->pVm->pDb, "Cannot remove collection '%z' due to a read-only Key/Value storage engine", &pCol->sName ); return rc; } /* Drop collection records */ for( nId = 0 ; nId < pCol->nLastid ; ++nId ){ unqliteCollectionDropRecord(pCol,nId,0,0); } /* Cleanup */ CollectionCacheRelease(pCol); SyBlobRelease(&pCol->sHeader); SyBlobRelease(&pCol->sWorker); SyMemBackendFree(&pVm->sAlloc,(void *)SyStringData(&pCol->sName)); unqliteReleaseCursor(pVm->pDb,pCol->pCursor); /* Unlink */ if( pCol->pPrevCol ){ pCol->pPrevCol->pNextCol = pCol->pNextCol; }else{ sxu32 iBucket = pCol->nHash & (pVm->iColSize - 1); pVm->apCol[iBucket] = pCol->pNextCol; } if( pCol->pNextCol ){ pCol->pNextCol->pPrevCol = pCol->pPrevCol; } MACRO_LD_REMOVE(pVm->pCol,pCol); pVm->iCol--; SyMemBackendPoolFree(&pVm->sAlloc,pCol); return UNQLITE_OK; }
/* * Drop a record from a given collection. */ UNQLITE_PRIVATE int unqliteCollectionDropRecord( unqlite_col *pCol, /* Target collection */ jx9_int64 nId, /* Unique ID of the record to be droped */ int wr_header, /* True to alter collection header */ int log_err /* True to log error */ ) { SyBlob *pWorker = &pCol->sWorker; int rc; /* Reset the working buffer */ SyBlobReset(pWorker); /* Prepare the unique ID for this record */ SyBlobFormat(pWorker,"%z_%qd",&pCol->sName,nId); /* Reset the cursor */ unqlite_kv_cursor_reset(pCol->pCursor); /* Seek the cursor to the desired location */ rc = unqlite_kv_cursor_seek(pCol->pCursor, SyBlobData(pWorker),SyBlobLength(pWorker), UNQLITE_CURSOR_MATCH_EXACT ); if( rc != UNQLITE_OK ){ return rc; } /* Remove the record from the storage engine */ rc = unqlite_kv_cursor_delete_entry(pCol->pCursor); /* Finally, Remove the record from the cache */ unqliteCollectionCacheRemoveRecord(pCol,nId); if( rc == UNQLITE_OK ){ pCol->nTotRec--; if( wr_header ){ /* Relect in the collection header */ rc = CollectionSetHeader(0,pCol,-1,pCol->nTotRec,0); } }else if( rc == UNQLITE_NOTIMPLEMENTED ){ if( log_err ){ unqliteGenErrorFormat(pCol->pVm->pDb, "Cannot delete record from collection '%z' due to a read-only Key/Value storage engine", &pCol->sName ); } } return rc; }
void Storage::scan(const char *keyData, uint keySize, const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler, const std::function<void(const Storage::Error &error)> &errorHandler) { if (!d->db) { Error error(d->name.toStdString(), -1, "Not open"); errorHandler(error); return; } unqlite_kv_cursor *cursor; int rc = unqlite_kv_cursor_init(d->db, &cursor); if (rc != UNQLITE_OK) { d->reportDbError("unqlite_kv_cursor_init", rc, errorHandler); return; } void *keyBuffer = nullptr; int keyBufferLength = 0; void *dataBuffer = nullptr; //FIXME: 64bit ints, but feeding int lenghts to the callbacks. can result in truncation unqlite_int64 dataBufferLength = 0; if (!keyData || keySize == 0) { for (unqlite_kv_cursor_first_entry(cursor); unqlite_kv_cursor_valid_entry(cursor); unqlite_kv_cursor_next_entry(cursor)) { fetchCursorData(cursor, &keyBuffer, &keyBufferLength, &dataBuffer, &dataBufferLength, resultHandler); } } else { rc = unqlite_kv_cursor_seek(cursor, keyData, keySize, UNQLITE_CURSOR_MATCH_EXACT); if (rc == UNQLITE_OK) { fetchCursorData(cursor, &keyBuffer, &keyBufferLength, &dataBuffer, &dataBufferLength, resultHandler); } else { std::cout << "couldn't find value " << std::string(keyData, keySize) << std::endl; } } free(keyBuffer); free(dataBuffer); unqlite_kv_cursor_release(d->db, cursor); }