582 lines
19 KiB
HTML
582 lines
19 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Getting Records Using the Cursor</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB" />
|
||
<link rel="up" href="Cursors.html" title="Chapter 4. Using Cursors" />
|
||
<link rel="previous" href="Cursors.html" title="Chapter 4. Using Cursors" />
|
||
<link rel="next" href="PutEntryWCursor.html" title="Putting Records Using Cursors" />
|
||
</head>
|
||
<body>
|
||
<div class="navheader">
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Getting Records Using the Cursor</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="Cursors.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 4. Using Cursors</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="PutEntryWCursor.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="Positioning"></a>Getting Records Using the Cursor</h2>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
To iterate over database records, from the first record to
|
||
the last, simply open the cursor and then use the
|
||
|
||
|
||
<tt class="methodname">Dbc::get()</tt>
|
||
method.
|
||
<span>Note that you need to supply the
|
||
<tt class="literal">DB_NEXT</tt> flag to this method.</span>
|
||
For example:
|
||
</p>
|
||
<a id="cxx_cursor3"></a>
|
||
<pre class="programlisting">#include <db_cxx.h>
|
||
|
||
...
|
||
|
||
Db my_database(NULL, 0);
|
||
Dbc *cursorp;
|
||
|
||
try {
|
||
// Database open omitted for clarity
|
||
|
||
// Get a cursor
|
||
my_database.cursor(NULL, &cursorp, 0);
|
||
|
||
Dbt key, data;
|
||
int ret;
|
||
|
||
// Iterate over the database, retrieving each record in turn.
|
||
while ((ret = cursorp->get(&key, &data, DB_NEXT)) == 0) {
|
||
// Do interesting things with the Dbts here.
|
||
}
|
||
if (ret != DB_NOTFOUND) {
|
||
// ret should be DB_NOTFOUND upon exiting the loop.
|
||
// Dbc::get() will by default throw an exception if any
|
||
// significant errors occur, so by default this if block
|
||
// can never be reached.
|
||
}
|
||
} catch(DbException &e) {
|
||
my_database.err(e.get_errno(), "Error!");
|
||
} catch(std::exception &e) {
|
||
my_database.errx("Error! %s", e.what());
|
||
}
|
||
|
||
// Cursors must be closed
|
||
if (cursorp != NULL)
|
||
cursorp->close();
|
||
|
||
my_database.close(0);</pre>
|
||
<p>
|
||
To iterate over the database from the last record to the first, use
|
||
<tt class="literal">DB_PREV</tt> instead of <tt class="literal">DB_NEXT</tt>:
|
||
</p>
|
||
<a id="cxx_cursor4"></a>
|
||
<pre class="programlisting">#include <db_cxx.h>
|
||
|
||
...
|
||
|
||
Db my_database(NULL, 0);
|
||
Dbc *cursorp;
|
||
|
||
try {
|
||
// Database open omitted for clarity
|
||
|
||
// Get a cursor
|
||
my_database.cursor(NULL, &cursorp, 0);
|
||
|
||
Dbt key, data;
|
||
int ret;
|
||
// Iterate over the database, retrieving each record in turn.
|
||
while ((ret = cursorp->get(&key, &data, DB_PREV)) == 0) {
|
||
// Do interesting things with the Dbts here.
|
||
}
|
||
if (ret != DB_NOTFOUND) {
|
||
// ret should be DB_NOTFOUND upon exiting the loop.
|
||
// Dbc::get() will by default throw an exception if any
|
||
// significant errors occur, so by default this if block
|
||
// can never be reached.
|
||
}
|
||
} catch(DbException &e) {
|
||
my_database.err(e.get_errno(), "Error!");
|
||
} catch(std::exception &e) {
|
||
my_database.errx("Error! %s", e.what());
|
||
}
|
||
|
||
// Cursors must be closed
|
||
if (cursorp != NULL)
|
||
cursorp->close();
|
||
|
||
my_database.close(0);</pre>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="cursorsearch"></a>Searching for Records</h3>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
You can use cursors to search for database records. You can search based
|
||
on just a key, or you can search based on both the key and the data.
|
||
You can also perform partial matches if your database supports sorted
|
||
duplicate sets. In all cases, the key and data parameters of these
|
||
methods are filled with the key and data values of the database record
|
||
to which the cursor is positioned as a result of the search.
|
||
</p>
|
||
<p>
|
||
Also, if the search fails, then cursor's state is left unchanged
|
||
and
|
||
|
||
<tt class="literal">DB_NOTFOUND</tt>
|
||
is returned.
|
||
|
||
|
||
</p>
|
||
<p>
|
||
To use a cursor to search for a record, use
|
||
|
||
<span>Dbt::get()<tt class="methodname"></tt>.</span>
|
||
When you use this method, you can provide the following flags:
|
||
</p>
|
||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||
<h3 class="title">Note</h3>
|
||
<p>
|
||
Notice in the following list that the cursor flags use the
|
||
keyword <tt class="literal">SET</tt> when the cursor examines just the key
|
||
portion of the records (in this case, the cursor is set to the
|
||
record whose key matches the value provided to the cursor).
|
||
Moreover, when the cursor uses the keyword <tt class="literal">GET</tt>,
|
||
then the cursor is positioned to both the key
|
||
<span class="emphasis"><em>and</em></span> the data values provided to the cursor.
|
||
</p>
|
||
<p>
|
||
Regardless of the keyword you use to get a record with a cursor, the
|
||
cursor's key and data
|
||
|
||
<span><tt class="classname">Dbt</tt>s</span>
|
||
are filled with the data retrieved from the record to which the
|
||
cursor is positioned.
|
||
</p>
|
||
</div>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_SET</tt>
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database with
|
||
the specified key.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_SET_RANGE</tt>
|
||
</p>
|
||
<p>
|
||
<span>Identical to
|
||
<tt class="literal">DB_SET</tt>
|
||
|
||
unless you are using the BTree access. In this case, the cursor
|
||
moves</span>
|
||
|
||
|
||
to the first record in the database whose
|
||
key is greater than or equal to the specified key. This comparison
|
||
is determined by the
|
||
|
||
<span>comparison function</span>
|
||
that you provide for the database. If no
|
||
|
||
<span>comparison function</span>
|
||
is provided, then the default
|
||
|
||
lexicographical sorting is used.
|
||
</p>
|
||
<p>
|
||
For example, suppose you have database records that use the
|
||
following
|
||
<span>Strings</span>
|
||
|
||
as keys:
|
||
</p>
|
||
<pre class="programlisting">Alabama
|
||
Alaska
|
||
Arizona</pre>
|
||
<p>
|
||
Then providing a search key of <tt class="literal">Alaska</tt> moves the
|
||
cursor to the second key noted above. Providing a key of
|
||
<tt class="literal">Al</tt> moves the cursor to the first key (<tt class="literal">Alabama</tt>), providing
|
||
a search key of <tt class="literal">Alas</tt> moves the cursor to the second key
|
||
(<tt class="literal">Alaska</tt>), and providing a key of <tt class="literal">Ar</tt> moves the
|
||
cursor to the last key (<tt class="literal">Arizona</tt>).
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_GET_BOTH</tt>
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database that uses
|
||
the specified key and data.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_GET_BOTH_RANGE</tt>
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database whose key matches the specified
|
||
key and whose data is
|
||
greater than or equal to the specified data. If the database supports
|
||
duplicate records, then on matching the key, the cursor is moved to
|
||
the duplicate record with the smallest data that is greater than or
|
||
equal to the specified data.
|
||
</p>
|
||
<p>
|
||
For example,
|
||
|
||
<span>suppose your database uses BTree
|
||
and it has </span>
|
||
database records that use the following key/data pairs:
|
||
</p>
|
||
<pre class="programlisting">Alabama/Athens
|
||
Alabama/Florence
|
||
Alaska/Anchorage
|
||
Alaska/Fairbanks
|
||
Arizona/Avondale
|
||
Arizona/Florence </pre>
|
||
<p>then providing:</p>
|
||
<div class="informaltable">
|
||
<table border="1" width="80%">
|
||
<colgroup>
|
||
<col />
|
||
<col />
|
||
<col />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>a search key of ...</th>
|
||
<th>and a search data of ...</th>
|
||
<th>moves the cursor to ...</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Alaska</td>
|
||
<td>Fa</td>
|
||
<td>Alaska/Fairbanks</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Arizona</td>
|
||
<td>Fl</td>
|
||
<td>Arizona/Florence</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Alaska</td>
|
||
<td>An</td>
|
||
<td>Alaska/Anchorage</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
For example, assuming a database containing sorted duplicate records of
|
||
U.S. States/U.S Cities key/data pairs (both as
|
||
<span>Strings),</span>
|
||
|
||
then the following code fragment can be used to position the cursor
|
||
to any record in the database and print its key/data values:
|
||
|
||
</p>
|
||
<a id="cxx_cursor5"></a>
|
||
<pre class="programlisting">#include <db_cxx.h>
|
||
#include <string.h>
|
||
|
||
...
|
||
|
||
Db my_database(NULL, 0);
|
||
Dbc *cursorp;
|
||
|
||
try {
|
||
// database open omitted for clarity
|
||
|
||
// Get a cursor
|
||
my_database.cursor(NULL, &cursorp, 0);
|
||
|
||
// Search criteria
|
||
char *search_key = "Alaska";
|
||
char *search_data = "Fa";
|
||
|
||
// Set up our DBTs
|
||
Dbt key(search_key, strlen(search_key) + 1);
|
||
Dbt data(search_data, strlen(search_data) + 1);
|
||
|
||
// Position the cursor to the first record in the database whose
|
||
// key matches the search key and whose data begins with the search
|
||
// data.
|
||
int ret = cursorp->get(&key, &data, DB_GET_BOTH_RANGE);
|
||
if (!ret) {
|
||
// Do something with the data
|
||
}
|
||
} catch(DbException &e) {
|
||
my_database.err(e.get_errno(), "Error!");
|
||
} catch(std::exception &e) {
|
||
my_database.errx("Error! %s", e.what());
|
||
}
|
||
|
||
// Close the cursor
|
||
if (cursorp != NULL)
|
||
cursorp->close();
|
||
|
||
// Close the database
|
||
my_database.close(0); </pre>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="getdups"></a>Working with Duplicate Records</h3>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
A record is a duplicate of another record if the two records share the
|
||
same key. For duplicate records, only the data portion of the record is unique.
|
||
</p>
|
||
<p>
|
||
Duplicate records are supported only for the BTree or Hash access methods.
|
||
For information on configuring your database to use duplicate records,
|
||
see <a href="btree.html#duplicateRecords">Allowing Duplicate Records</a>.
|
||
</p>
|
||
<p>
|
||
If your database supports duplicate records, then it can potentially
|
||
contain multiple records that share the same key.
|
||
|
||
|
||
|
||
<span>By default, normal database
|
||
get operations will only return the first such record in a set
|
||
of duplicate records. Typically, subsequent duplicate records are
|
||
accessed using a cursor.
|
||
</span>
|
||
|
||
The following
|
||
|
||
|
||
<span><tt class="methodname">Dbc::get()</tt> flags</span>
|
||
are interesting when working with databases that support duplicate records:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
|
||
<span>
|
||
<tt class="literal">DB_NEXT</tt>,
|
||
<tt class="literal">DB_PREV</tt>
|
||
</span>
|
||
</p>
|
||
<p>
|
||
Shows the next/previous record in the database, regardless of
|
||
whether it is a duplicate of the current record. For an example of
|
||
using these methods, see <a href="Positioning.html">Getting Records Using the Cursor</a>.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_GET_BOTH_RANGE</tt>
|
||
</p>
|
||
<p>
|
||
Useful for seeking the cursor to a specific record, regardless of
|
||
whether it is a duplicate record. See <a href="Positioning.html#cursorsearch">Searching for Records</a> for more
|
||
information.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<span>
|
||
<tt class="literal">DB_NEXT_NODUP</tt>,
|
||
<tt class="literal">DB_PREV_NODUP</tt>
|
||
</span>
|
||
</p>
|
||
<p>
|
||
Gets the next/previous non-duplicate record in the database. This
|
||
allows you to skip over all the duplicates in a set of duplicate
|
||
records. If you call
|
||
|
||
<span>
|
||
|
||
<tt class="methodname">Dbc::get()</tt>
|
||
with <tt class="literal">DB_PREV_NODUP</tt>,
|
||
</span>
|
||
then the cursor is positioned to the last record for the previous
|
||
key in the database. For example, if you have the following records
|
||
in your database:
|
||
</p>
|
||
<pre class="programlisting">Alabama/Athens
|
||
Alabama/Florence
|
||
Alaska/Anchorage
|
||
Alaska/Fairbanks
|
||
Arizona/Avondale
|
||
Arizona/Florence</pre>
|
||
<p>
|
||
and your cursor is positioned to <tt class="literal">Alaska/Fairbanks</tt>,
|
||
and you then call
|
||
|
||
<span>
|
||
|
||
<tt class="methodname">Dbc::get()</tt>
|
||
with <tt class="literal">DB_PREV_NODUP</tt>,
|
||
</span>
|
||
then the cursor is positioned to Alabama/Florence. Similarly, if
|
||
you call
|
||
|
||
<span>
|
||
|
||
<tt class="methodname">Dbc::get()</tt>
|
||
with <tt class="literal">DB_NEXT_NODUP</tt>,
|
||
</span>
|
||
|
||
then the cursor is positioned to the first record corresponding to
|
||
the next key in the database.
|
||
</p>
|
||
<p>
|
||
If there is no next/previous key in the database, then
|
||
|
||
<tt class="literal">DB_NOTFOUND</tt>
|
||
is returned, and the cursor is left unchanged.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
<tt class="literal">DB_NEXT_DUP</tt>
|
||
</p>
|
||
<p>
|
||
|
||
Gets the
|
||
|
||
<span>next</span>
|
||
record that shares the current key. If the
|
||
cursor is positioned at the last record in the duplicate set and
|
||
you call
|
||
|
||
<span>
|
||
|
||
<tt class="methodname">Dbc::get()</tt>
|
||
with <tt class="literal">DB_NEXT_DUP</tt>,
|
||
</span>
|
||
|
||
then
|
||
|
||
<tt class="literal">DB_NOTFOUND</tt>
|
||
is returned and the cursor is left unchanged.
|
||
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
For example, the following code fragment positions a cursor to a key
|
||
|
||
|
||
|
||
<span>and displays it and all its
|
||
duplicates.</span>
|
||
|
||
|
||
</p>
|
||
<a id="cxx_cursor6"></a>
|
||
<pre class="programlisting">#include <db_cxx.h>
|
||
#include <string.h>
|
||
|
||
...
|
||
|
||
char *search_key = "Al";
|
||
|
||
Db my_database(NULL, 0);
|
||
Dbc *cursorp;
|
||
|
||
try {
|
||
// database open omitted for clarity
|
||
|
||
// Get a cursor
|
||
my_database.cursor(NULL, &cursorp, 0);
|
||
|
||
// Set up our DBTs
|
||
Dbt key(search_key, strlen(search_key) + 1);
|
||
Dbt data;
|
||
|
||
// Position the cursor to the first record in the database whose
|
||
// key and data begin with the correct strings.
|
||
int ret = cursorp->get(&key, &data, DB_SET);
|
||
while (ret != DB_NOTFOUND) {
|
||
std::cout << "key: " << (char *)key.get_data()
|
||
<< "data: " << (char *)data.get_data()<< std::endl;
|
||
ret = cursorp->get(&key, &data, DB_NEXT_DUP);
|
||
}
|
||
} catch(DbException &e) {
|
||
my_database.err(e.get_errno(), "Error!");
|
||
} catch(std::exception &e) {
|
||
my_database.errx("Error! %s", e.what());
|
||
}
|
||
|
||
// Close the cursor
|
||
if (cursorp != NULL)
|
||
cursorp->close();
|
||
|
||
// Close the database
|
||
my_database.close(0); </pre>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="Cursors.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="Cursors.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="PutEntryWCursor.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Chapter 4. Using Cursors </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Putting Records Using Cursors</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|