A Database Cursor (C++ programmers may prefer the term “iterator”) is a pointer to a Database item. You can use it to traverse the Database and to enumerate all items. You can enumerate items from front to back or vice versa. You can also use a Cursor to look up a key, or to overwrite, delete and insert items.
This chapter explains how to create and use Database Cursors.
Cursors are managed using a ups_cursor_t
structure. You allocate such
a Cursor structure with the ups_cursor_create
method. The first
parameter is always the ups_db_t
handle of the Database on which this
Cursor operates.
The second parameter of ups_cursor_create
is a Transaction handle; if
you do not use Transactions, then set this parameter to NULL.
Transactions are covered in a later chapter.
The third third parameter is not yet used; always set it to zero. Here is the declaration of the function:
ups_status_t
ups_cursor_create (ups_cursor_t **cursor, ups_db_t *db,
ups_txn_t *txn, uint32_t flags);
API reference of ups_cursor_create
And here is an example of the usage; it creates a Cursor which can operate on the Database db:
ups_cursor_t *cursor;
ups_status_t st;
if ((st = ups_cursor_create (&cursor, db, NULL, 0))) {
// …
After creation, the new Cursor does not point to any item in the Database.
The new Cursor is not yet of much use. Since it does not point to an item, some operations (i.e. deleting the current item) will fail. To use the Cursor, we have to position it on an item.
With ups_cursor_move
, you can move the Cursor to the first, last, next
or previous item in the Database. Here is the declaration of the
function:
ups_status_t
ups_cursor_move (ups_cursor_t *cursor, ups_key_t *key,
ups_record_t *record, uint32_t flags);
API reference of ups_cursor_move
This function sets the Cursor to the type which is specified in the
flags. This can be one of UPS_CURSOR_FIRST
, UPS_CURSOR_LAST
,
UPS_CURSOR_NEXT
or UPS_CURSOR_PREVIOUS
.
If you do not specify any direction, the Cursor will remain at the current position. (This behavior can be used to retrieve the key or record of the current item.)
If a Cursor does not point to a Database item, and you move it to
UPS_CURSOR_NEXT
(or UPS_CURSOR_PREVIOUS
), upscaledb will
automatically move the Cursor to the first (or last) element.
The key and record parameters are optional. After moving the Cursor, the key and the record of the new Database item will be retrieved copied to key and/or record, if key and/or record are not NULL.
This short example creates a Cursor and traverses the Database from the first to the last element, printing every Database key. (It is assumed that the key is of type char *, and can be printed with printf (“%s”)). Since the record of each item is not used, it is not retrieved.
ups_cursor_t *cursor;
ups_status_t st;
ups_key_t key;
if ((st = ups_cursor_create (&cursor, db, NULL, 0)))
// handle error...
while (1) {
st = ups_cursor_move (cursor, &key, NULL, UPS_CURSOR_NEXT);
if (st != UPS_STATUS_OK) {
if (st != UPS_KEY_NOT_FOUND)
printf (“database error: %d\n”, st);
exit (–1);
}
printf (“key: %s\n”, (char *)key.data);
}
Since we are only interested in the keys of the Database items, we do
not request the record. Therefore, the third parameter of
ups_cursor_move
is set to NULL.
ups_cursor_move
will return UPS_KEY_NOT_FOUND
if the Cursor points
to the last item in the Database and the next item is requested, or if
the Cursor points to the first item and the previous item is requested.
ups_cursor_insert
behaves the same as ups_insert
. If the item is
inserted successfully, the Cursor will point to the new item. Otherwise,
the Cursor is not modified. Here is the declaration of
ups_cursor_insert
:
ups_status_t
ups_cursor_insert (ups_cursor_t *cursor, ups_key_t *key,
ups_record_t *record, uint32_t flags);
API reference of ups_cursor_insert
And here is an example of the usage; it inserts the key “hello” and the record "world".
ups_key_t key = ups_make_key("hello", strlen("hello") + 1);
ups_record_t record = ups_make_record("world", strlen("world") + 1);
if ((st = ups_cursor_insert (cursor, &key, &record, 0))) {
// …
You can use Cursors to search for Database records. The function
ups_cursor_find
tries to search for a key, and positions the Database
cursor on the item with this key. If the item is not found, the Cursor
is not modified. The flags parameter is unused - set it to 0.
ups_status_t
ups_cursor_find (ups_cursor_t *cursor, ups_key_t *key,
ups_record_t *record, uint32_t flags);
API reference of ups_cursor_find
When the Cursor points to a Database item, you can delete the item (with
ups_cursor_erase
) or overwrite the record (with
ups_cursor_overwrite
).
To overwrite the record of the current item, call ups_cursor_overwrite
with a pointer to a ups_record_t
structure which contains the new
record. The third parameter, flags, is unused; set it to 0.
ups_status_t
ups_cursor_overwrite (ups_cursor_t *cursor, ups_record_t *record,
uint32_t flags);
API reference of ups_cursor_overwrite
If you try to overwrite an item while the Cursor does not point to an
item, upscaledb returns UPS_CURSOR_IS_NIL
.
To delete a record using a Cursor, position the Cursor on the record you
want to delete, then call ups_cursor_erase
. The third parameter,
flags, is unused; set it to 0.
ups_status_t
ups_cursor_erase (ups_cursor_t *cursor, uint32_t flags);
API reference of ups_cursor_erase
If you try to delete an item, but the Cursor does not point to an item,
upscaledb returns UPS_CURSOR_IS_NIL
.
If the delete operation was successful, the Cursor will be uninitialized and not point to any item at all.
upscaledb provides a function for cloning an existing Cursor.
ups_cursor_clone
creates an exact copy of a cursor which points to the
same Database item as the original Cursor and is part of the same
Transaction.
ups_status_t
ups_cursor_clone (ups_cursor_t *src, ups_cursor_t **dest);
API reference for ups_cursor_clone
Cloning Cursors is a very cheap operation and does not cost any performance.
When you finished working with a Database Cursor, you have to close and free it. This will prevent memory leaks. All Cursors must be closed before the Database is closed.
ups_status_t
ups_cursor_close (ups_cursor_t *cursor);