An Embeddable NoSQL Database Engine |
Tweet |
Follow @unqlite_db |
UnQLite C/C++ API Reference - Using Database Cursors.
Opening Database Cursors
int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut);
int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur);
int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor);
Positioning Database Cursors
int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos);
int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor);
int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor);
int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor);
int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor);
int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor);
Extracting Data from Database Cursors
int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte);
int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnData);
int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
Deleting Records using Database Cursors
int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor);
Description
Cursors provide a mechanism by which you can iterate over the records in a database. Using cursors, you can seek, fetch, move, and delete database records.
Before playing with cursors, you must first allocate a new cursor handle using unqlite_kv_cursor_init(). This is often the first UnQLite cursor API call that an application makes and is a prerequisite in order to use cursors. When done, you must call unqlite_kv_cursor_release() to release any allocated resource by the cursor and thus to avoid memory leaks.
To iterate over database records, from the first record to the last, simply call unqlite_kv_cursor_first_entry() with successive call to unqlite_kv_cursor_next_entry() until it return a value other than UNQLITE_OK (See example below). Note that you can call unqlite_kv_cursor_valid_entry() to check if the cursor is pointing to a valid record (This will return 1 when valid. 0 otherwise).
To iterate over database records, from the last record to the first, simply call unqlite_kv_cursor_last_entry() with successive call to unqlite_kv_cursor_prev_entry() until it return a value other than UNQLITE_OK (See example below). Note that you can call unqlite_kv_cursor_valid_entry() to check if the cursor is pointing to a valid record (This will return 1 when valid. 0 otherwise).
You can also use cursors to search for records and start the iteration process from there. To do that, simply call unqlite_kv_cursor_seek() with the target record key and the seek direction (Last argument). The seek direction can take the following value:
UNQLITE_CURSOR_MATCH_EXACT or 0 (default)
Default search method supported by all key/value storage subsystem. An exact match is performed. If the record exists, the cursor is left pointing to it. Otherwise it is left pointing to EOF and UNQLITE_NOTFOUND is returned.
UNQLITE_CURSOR_MATCH_LE
The cursor is left pointing to the largest key in the database that is smaller than (pKey/nKey). If the database contains no keys smaller than (pKey/nKey), the cursor is left at EOF.
This option have sense only if the underlying key/value storage subsystem support range search (i.e: B+Tree, R+Tree, etc.). Otherwise this option is ignored and an exact match is performed.
UNQLITE_CURSOR_MATCH_GE
The cursor is left pointing to the smallest key in the database that is larger than (pKey/nKey). If the database contains no keys larger than (pKey/nKey), the cursor is left at EOF.
This option have sense only if the underlying key/value storage subsystem support range search (i.e: B+Tree, R+Tree, etc.). Otherwise this option is ignored and an exact match is performed.
To retrieve record key/data from a valid cursor (Tip: call unqlite_kv_cursor_valid_entry() to test cursor validity ) simply use the following interface:
unqlite_kv_cursor_key();
unqlite_kv_cursor_key_callback();
unqlite_kv_cursor_data();
unqlite_kv_cursor_data_callback();
These interfaces works exactly like their high-level thread-safe client: unqlite_kv_fetch() and unqlite_kv_fetch_callback(). See below for an usage or example or refer to the high-level client API description for additional information.
To delete a record from the database using the cursor interface, simply point to the target record using unqlite_kv_cursor_seek() and call unqlite_kv_cursor_delete_entry() after successful seek (See below for an usage example).
unqlite_kv_cursor_init() and unqlite_kv_cursor_release() are thread-safe while the other interfaces are not. Caller must ensure that no other thread can access the same cursor handle. Otherwise the result is undefined.
Parameters
pCursor |
A pointer to a correctly initialized database cursor. |
Return value
UNQLITE_OK is returned on successfull seek. Any other return value typically UNQLITE_EOF, UNQLITE_NOTFOUND indicates invalid seek (i.e. No more records to fetch).
Example
Compile this C file for a smart introduction to these interface.
int rc;
unqlite *pDb;
unqlite_kv_cursor *pCursor;
unqlite_int64 iData;
// Open our database;
rc = unqlite_open(&pDb,"test.db",UNQLITE_OPEN_CREATE);
if( rc != UNQLITE_OK ){ return; }
//Store some records unqlite_kv_store(), unqlite_kv_append()...
/* Allocate a new cursor instance */
rc = unqlite_kv_cursor_init(pDb,&pCursor);
if(
rc != UNQLITE_OK ){ return; }
/* Point to the first record */
for( unqlite_kv_cursor_first_entry(pCursor) ; unqlite_kv_cursor_valid_entry(pCursor) ; unqlite_kv_cursor_next_entry(pCursor) ){
/* Consume the key */
printf("\nKey ==>\n\t");
unqlite_kv_cursor_key_callback(pCursor,DataConsumerCallback,0);
/* Extract data length */
unqlite_kv_cursor_data(pCursor,NULL,&iData);
printf("\nData length ==> %lld\n\t",iData);
/* Consume the data */
unqlite_kv_cursor_data_callback(pCursor,DataConsumerCallback,0);
}
/* Delete a record */
rc = unqlite_kv_cursor_seek(pCursor,"MyRecord",-1 /* Key length */,UNQLITE_CURSOR_MATCH_EXACT);
if( rc == UNQLITE_OK ){
rc = unqlite_kv_cursor_delete_entry(pCursor);
if( rc != UNQLITE_OK ){ return; }
}
/* Point to the last record */
rc = unqlite_kv_cursor_last_entry(pCursor);
if( rc != UNQLITE_OK ){ return; }
/* Iterate over the records */
while( unqlite_kv_cursor_valid_entry(pCursor) ){
/* Consume the key */
printf("\nKey ==>\n\t");
unqlite_kv_cursor_key_callback(pCursor,DataConsumerCallback,0);
/* Extract data length */
unqlite_kv_cursor_data(pCursor,NULL,&iData);
printf("\nData length ==> %lld\n\t",iData);
/* Consume the data */
unqlite_kv_cursor_data_callback(pCursor,DataConsumerCallback,0);
/* Point to the previous record */
unqlite_kv_cursor_prev_entry(pCursor);
}
/* Finally, Release our cursor */
unqlite_kv_cursor_release(pDb,pCursor);
//Auto-commit the transaction and close our handle
unqlite_close(pDb);
See also
unqlite_kv_fetch, unqlite_kv_fetch_callback, unqlite_kv_append, unqlite_kv_store, unqlite_open, unqlite_close.