1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml">
4  <head>
5    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6    <title>Secondary Database Example</title>
7    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
8    <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
9    <link rel="start" href="index.html" title="Getting Started with Berkeley DB" />
10    <link rel="up" href="indexes.html" title="Chapter 5. Secondary Databases" />
11    <link rel="prev" href="joins.html" title="Database Joins" />
12    <link rel="next" href="dbconfig.html" title="Chapter 6. Database Configuration" />
13  </head>
14  <body>
15    <div class="navheader">
16      <table width="100%" summary="Navigation header">
17        <tr>
18          <th colspan="3" align="center">Secondary Database Example</th>
19        </tr>
20        <tr>
21          <td width="20%" align="left"><a accesskey="p" href="joins.html">Prev</a> </td>
22          <th width="60%" align="center">Chapter 5. Secondary Databases</th>
23          <td width="20%" align="right"> <a accesskey="n" href="dbconfig.html">Next</a></td>
24        </tr>
25      </table>
26      <hr />
27    </div>
28    <div class="sect1" lang="en" xml:lang="en">
29      <div class="titlepage">
30        <div>
31          <div>
32            <h2 class="title" style="clear: both"><a id="coreindexusage"></a>Secondary Database Example</h2>
33          </div>
34        </div>
35      </div>
36      <div class="toc">
37        <dl>
38          <dt>
39            <span class="sect2">
40              <a href="coreindexusage.html#edlWIndexes">Secondary Databases with example_database_load</a>
41            </span>
42          </dt>
43          <dt>
44            <span class="sect2">
45              <a href="coreindexusage.html#edrWIndexes">Secondary Databases with example_database_read</a>
46            </span>
47          </dt>
48        </dl>
49      </div>
50      <p>
51        In previous chapters in this book, we built applications that load
52        and display several DB databases. In this example, we will extend those
53        examples to use secondary databases. Specifically:
54    </p>
55      <div class="itemizedlist">
56        <ul type="disc">
57          <li>
58            <p>
59            In 
60                <a class="xref" href="DbUsage.html" title="Database Usage Example">Database Usage Example</a> 
61                 
62            we built an application that can open and load data into several databases.
63            In <a class="xref" href="coreindexusage.html#edlWIndexes" title="Secondary Databases with example_database_load">Secondary Databases with example_database_load</a> we will extend
64            that application to also open a secondary database for the purpose
65            of indexing inventory item names.
66        </p>
67          </li>
68          <li>
69            <p>
70            In <a class="xref" href="CoreCursorUsage.html" title="Cursor Example">Cursor Example</a> we
71            built an application to display our inventory database (and related
72            vendor information). In 
73            <a class="xref" href="coreindexusage.html#edrWIndexes" title="Secondary Databases with example_database_read">Secondary Databases with example_database_read</a>
74            we will extend that application to
75            show inventory records based on the index we cause to be loaded using
76            <code class="function">example_database_load</code>.
77        </p>
78          </li>
79        </ul>
80      </div>
81      <div class="sect2" lang="en" xml:lang="en">
82        <div class="titlepage">
83          <div>
84            <div>
85              <h3 class="title"><a id="edlWIndexes"></a>Secondary Databases with example_database_load</h3>
86            </div>
87          </div>
88        </div>
89        <p>
90            <code class="function">example_database_load</code> uses several utility
91            functions to open and close its databases. In order to cause 
92            <code class="function">example_database_load</code> to maintain an index of
93            inventory item names, all we really need to do is update the utility
94            functions to:
95        </p>
96        <div class="orderedlist">
97          <ol type="1">
98            <li>
99              <p>
100                    Create a new database to be used as a secondary database.
101                </p>
102            </li>
103            <li>
104              <p>
105                    Associate our new database to the inventory primary
106                    database.
107                </p>
108            </li>
109            <li>
110              <p>
111                    Close the secondary database when we close the rest of our
112                    databases.
113                </p>
114            </li>
115          </ol>
116        </div>
117        <p>
118            We also need a function that can create our secondary keys for us.
119        </p>
120        <p>
121            Because DB maintains secondary databases for us; once this work
122            is done we need not make any other changes to <code class="function">example_database_load</code>. 
123
124            <span>Therefore, we can limit
125            all our work to the code found in <code class="filename">gettingstarted_common.h</code>
126            and <code class="filename">gettingstarted_common.c</code>.
127            </span>
128        </p>
129        <p>
130            Remember that you can find the complete implementation of these functions
131            in:
132        </p>
133        <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/getting_started</pre>
134        <p>
135            where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
136            placed your DB distribution.
137        </p>
138        <p>
139            To begin, we need to update the <code class="literal">stock_dbs</code>
140            structure to accommodate the additional database. We defined this
141            structure in <code class="filename">gettingstarted_common.h</code>. We can
142            limit our update to this file to just that structure definition:
143        </p>
144        <p>
145            Remember that new code is in <strong class="userinput"><code>bold</code></strong>.
146        </p>
147        <a id="c_index10"></a>
148        <pre class="programlisting">/* file: gettingstarted_common.h */
149#include &lt;db.h&gt;
150
151typedef struct stock_dbs {
152    DB *inventory_dbp; /* Database containing inventory information */
153    DB *vendor_dbp;    /* Database containing vendor information */
154    <strong class="userinput"><code>DB *itemname_sdbp; /* Index based on the item name index */</code></strong>
155                                                                                                                                
156    char *db_home_dir;       /* Directory containing the database files */
157    <strong class="userinput"><code>char *itemname_db_name;  /* Itemname secondary database */</code></strong>
158    char *inventory_db_name; /* Name of the inventory database */
159    char *vendor_db_name;    /* Name of the vendor database */
160} STOCK_DBS;
161
162/* Function prototypes */
163int databases_setup(STOCK_DBS *, const char *, FILE *);
164int databases_close(STOCK_DBS *);
165void initialize_stockdbs(STOCK_DBS *);
166int open_database(DB **, const char *, const char *, FILE *, <strong class="userinput"><code>int</code></strong>);
167void set_db_filenames(STOCK_DBS *my_stock);
168
169</pre>
170        <p>
171            Because we updated our stock_dbs structure, we need to update our
172            stock_dbs utility functions 
173            (<a class="xref" href="CoreDbUsage.html#stock-db-functions" title="Example 2.2 The stock_db Utility Functions">The stock_db Utility Functions</a>)
174            accordingly. The updates are trivial and so we won't show them here
175            in the interest of space. You can find their complete implementation
176            in the <code class="filename">gettingstarted_common.c</code> file
177            accompanying this example in your DB distribution.
178        </p>
179        <p>
180            More importantly, however, we need to go to 
181            <code class="filename">gettingstarted_common.c</code>
182            and create our secondary key extractor function. When we
183            store our inventory items, we place the item name in the buffer
184            immediately after a <code class="literal">float</code> and an
185            <code class="literal">int</code>, so retrieving the string from the buffer is
186            fairly easy to do:
187        </p>
188        <a id="c_index11"></a>
189        <pre class="programlisting">/* file: gettingstarted_common.c */
190#include "gettingstarted_common.h"
191                                                                                                                                  
192<strong class="userinput"><code>/*
193 * Used to extract an inventory item's name from an
194 * inventory database record. This function is used to create
195 * keys for secondary database records.
196 */
197int
198get_item_name(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey)
199{
200    int offset;
201                                                                                                                                  
202    /*
203     * First, obtain the buffer location where we placed the
204     * item's name. In this example, the item's name is located
205     * in the primary data. It is the first string in the
206     * buffer after the price (a float) and the quantity (an int).
207     *
208     * See load_inventory_database() in example_database_load.c
209     * for how we marshalled the inventory information into the
210     * data DBT.
211     */
212    offset = sizeof(float) + sizeof(int);
213                                                                                                                                  
214    /* Check to make sure there's data */
215    if (pdata-&gt;size &lt; offset)
216        return (-1); /* Returning non-zero means that the
217                      * secondary record is not created/updated.
218                      */
219                                                                                                                                  
220    /* Now set the secondary key's data to be the item name */
221    memset(skey, 0, sizeof(DBT));
222    skey-&gt;data = pdata-&gt;data + offset;
223    skey-&gt;size = strlen(skey-&gt;data) + 1;
224                                                                                                                                  
225    return (0);
226}</code></strong> </pre>
227        <p>
228        Having completed that function, we need to update 
229        <code class="function">set_db_filenames()</code> and 
230        <code class="function">initialize_stockdbs()</code> to handle the
231        new secondary databases that our application will now use.
232        These functions were originally introduced in 
233        <a class="xref" href="CoreDbUsage.html#stock-db-functions" title="Example 2.2 The stock_db Utility Functions">The stock_db Utility Functions</a>.
234    </p>
235        <a id="c_index11.1"></a>
236        <pre class="programlisting">
237/* Initializes the STOCK_DBS struct.*/
238void
239initialize_stockdbs(STOCK_DBS *my_stock)
240{
241    my_stock-&gt;db_home_dir = DEFAULT_HOMEDIR;
242    my_stock-&gt;inventory_dbp = NULL;
243    my_stock-&gt;vendor_dbp = NULL;
244    <strong class="userinput"><code>my_stock-&gt;itemname_sdbp = NULL;</code></strong>
245
246    my_stock-&gt;inventory_db_name = NULL;
247    my_stock-&gt;vendor_db_name = NULL;
248    <strong class="userinput"><code>my_stock-&gt;itemname_db_name = NULL;</code></strong>
249}
250
251/* Identify all the files that will hold our databases. */
252void
253set_db_filenames(STOCK_DBS *my_stock)
254{
255    size_t size;
256
257    /* Create the Inventory DB file name */
258    size = strlen(my_stock-&gt;db_home_dir) + strlen(INVENTORYDB) + 1;
259    my_stock-&gt;inventory_db_name = malloc(size);
260    snprintf(my_stock-&gt;inventory_db_name, size, "%s%s",
261      my_stock-&gt;db_home_dir, INVENTORYDB);
262    
263    /* Create the Vendor DB file name */
264    size = strlen(my_stock-&gt;db_home_dir) + strlen(VENDORDB) + 1;
265    my_stock-&gt;vendor_db_name = malloc(size);
266    snprintf(my_stock-&gt;vendor_db_name, size, "%s%s",
267      my_stock-&gt;db_home_dir, VENDORDB);
268
269    <strong class="userinput"><code>/* Create the itemname DB file name */
270    size = strlen(my_stock-&gt;db_home_dir) + strlen(ITEMNAMEDB) + 1;
271    my_stock-&gt;itemname_db_name = malloc(size);
272    snprintf(my_stock-&gt;itemname_db_name, size, "%s%s",
273      my_stock-&gt;db_home_dir, ITEMNAMEDB);</code></strong>
274} </pre>
275        <p>
276        We also need to update the
277        <code class="function">open_database()</code> (as described in
278        <a class="xref" href="CoreDbUsage.html#open-db" title="Example 2.3 open_database() Function">open_database() Function</a>)
279        to take special actions if we are
280        opening a secondary database. Unlike our primary databases, we want to
281        support sorted duplicates for our secondary database. This is because we
282        are indexing based on an item's name, and item names are
283        shared by multiple inventory records. As a result every key the secondary
284        database (an item name) will be used by multiple records (pointers to
285        records in our primary database). We allow this by configuring our
286        secondary database to support duplicate records. Further, because
287        BTrees perform best when their records are sorted, we go ahead and
288        configure our secondary database for sorted duplicates.
289    </p>
290        <p>
291        To do this, we add a parameter to the function that indicates whether we are
292        opening a secondary database, and we add in the few lines of code
293        necessary to set the sorted duplicates flags.
294    </p>
295        <a id="c_index12"></a>
296        <pre class="programlisting">/* Opens a database */
297int
298open_database(DB **dbpp,       /* The DB handle that we are opening */
299    const char *file_name,     /* The file in which the db lives */
300    const char *program_name,  /* Name of the program calling this
301                                * function */
302    FILE *error_file_pointer,
303    <strong class="userinput"><code>int is_secondary</code></strong>)
304{
305    DB *dbp;    /* For convenience */
306    u_int32_t open_flags;
307    int ret;
308
309    /* Initialize the DB handle */
310    ret = db_create(&amp;dbp, NULL, 0);
311    if (ret != 0) {
312        fprintf(error_file_pointer, "%s: %s\n", program_name,
313                db_strerror(ret));
314        return (ret);
315    }
316
317    /* Point to the memory malloc'd by db_create() */
318    *dbpp = dbp;
319
320    /* Set up error handling for this database */
321    dbp-&gt;set_errfile(dbp, error_file_pointer);
322    dbp-&gt;set_errpfx(dbp, program_name);
323
324    <strong class="userinput"><code>/*
325     * If this is a secondary database, then we want to allow
326     * sorted duplicates.
327     */
328    if (is_secondary) {
329        ret = dbp-&gt;set_flags(dbp, DB_DUPSORT);
330        if (ret != 0) {
331            dbp-&gt;err(dbp, ret, "Attempt to set DUPSORT flag failed.",
332              file_name);
333            return (ret);
334        }
335    }</code></strong>
336
337    /* Set the open flags */
338    open_flags = DB_CREATE;
339
340    /* Now open the database */
341    ret = dbp-&gt;open(dbp,        /* Pointer to the database */
342                    NULL,       /* Txn pointer */
343                    file_name,  /* File name */
344                    NULL,       /* Logical db name (unneeded) */
345                    DB_BTREE,   /* Database type (using btree) */
346                    open_flags, /* Open flags */
347                    0);         /* File mode. Using defaults */
348    if (ret != 0) {
349        dbp-&gt;err(dbp, ret, "Database '%s' open failed.", file_name);
350        return (ret);
351    }
352
353    return (ret);
354}   </pre>
355        <p>
356        That done, we can now update <code class="function">databases_setup()</code> 
357        (see <a class="xref" href="CoreDbUsage.html#databasesetup" title="Example 2.4 The databases_setup() Function">The databases_setup() Function</a>) to create
358        and open our secondary database. To do this, we have to add a flag to
359        each call to <code class="function">open_database()</code> that indicates whether
360        the database is a secondary. We also have to associate our secondary
361        database with the inventory database (the primary). 
362    </p>
363        <p>
364        Note that we do not anywhere in this example show the definition of
365        <code class="literal">PRIMARY_DB</code> and <code class="literal">SECONDARY_DB</code>. See
366        <code class="filename">gettingstarted_common.h</code> in your DB examples
367        directory for those definitions (they are just <code class="literal">0</code> and
368        <code class="literal">1</code>, respectively).
369    </p>
370        <a id="c_index13"></a>
371        <pre class="programlisting">/* opens all databases */
372int
373databases_setup(STOCK_DBS *my_stock, const char *program_name,
374  FILE *error_file_pointer)
375{
376    int ret;
377
378    /* Open the vendor database */
379    ret = open_database(&amp;(my_stock-&gt;vendor_dbp),
380      my_stock-&gt;vendor_db_name,
381      program_name, error_file_pointer,
382      <strong class="userinput"><code>PRIMARY_DB</code></strong>);
383    if (ret != 0)
384        /*
385         * Error reporting is handled in open_database() so just return
386         * the return code here.
387         */
388        return (ret);
389
390    /* Open the inventory database */
391    ret = open_database(&amp;(my_stock-&gt;inventory_dbp),
392      my_stock-&gt;inventory_db_name,
393      program_name, error_file_pointer,
394      <strong class="userinput"><code>PRIMARY_DB</code></strong>);
395    if (ret != 0)
396        /*
397         * Error reporting is handled in open_database() so just return
398         * the return code here.
399         */
400        return (ret);
401
402    <strong class="userinput"><code>/*
403     * Open the itemname secondary database. This is used to
404     * index the product names found in the inventory
405     * database.
406     */
407    ret = open_database(&amp;(my_stock-&gt;itemname_sdbp),
408      my_stock-&gt;itemname_db_name,
409      program_name, error_file_pointer,
410      SECONDARY_DB);
411    if (ret != 0)
412        /*
413         * Error reporting is handled in open_database() so just return
414         * the return code here.
415         */
416        return (ret);
417                                                                                                                                
418    /*
419     * Associate the itemname db with its primary db
420     * (inventory db).
421     */
422     my_stock-&gt;inventory_dbp-&gt;associate(
423       my_stock-&gt;inventory_dbp,    /* Primary db */
424       NULL,                       /* txn id */
425       my_stock-&gt;itemname_sdbp,    /* Secondary db */
426       get_item_name,              /* Secondary key extractor */
427       0);                         /* Flags */
428     </code></strong>
429
430    printf("databases opened successfully\n");
431    return (0);
432}</pre>
433        <p>
434        Finally, we need to update <code class="function">databases_close()</code> 
435        (<a class="xref" href="CoreDbUsage.html#database_close" title="Example 2.5 The databases_close() Function">The databases_close() Function</a>)
436        to close our
437        new secondary database. Note that we are careful to close the secondary
438        before the primary, even though the database close routine is single
439        threaded.
440    </p>
441        <a id="c_index14"></a>
442        <pre class="programlisting">/* Closes all the databases and secondary databases. */
443int
444databases_close(STOCK_DBS *my_stock)
445{
446    int ret;
447    /*
448     * Note that closing a database automatically flushes its cached data
449     * to disk, so no sync is required here.
450     */
451
452    <strong class="userinput"><code>if (my_stock-&gt;itemname_sdbp != NULL) {
453        ret = my_stock-&gt;itemname_sdbp-&gt;close(my_stock-&gt;itemname_sdbp, 0);
454        if (ret != 0)
455            fprintf(stderr, "Itemname database close failed: %s\n",
456              db_strerror(ret));
457    }</code></strong>
458
459    if (my_stock-&gt;inventory_dbp != NULL) {
460        ret = my_stock-&gt;inventory_dbp-&gt;close(my_stock-&gt;inventory_dbp, 0);
461        if (ret != 0)
462            fprintf(stderr, "Inventory database close failed: %s\n",
463              db_strerror(ret));
464    }
465
466    if (my_stock-&gt;vendor_dbp != NULL) {
467        ret = my_stock-&gt;vendor_dbp-&gt;close(my_stock-&gt;vendor_dbp, 0);
468        if (ret != 0)
469            fprintf(stderr, "Vendor database close failed: %s\n",
470              db_strerror(ret));
471    }
472
473    printf("databases closed.\n");
474    return (0);
475} </pre>
476        <p>
477        And the implementation changes slightly to take advantage of the new
478        boolean. Note that to save space, we just show the constructor where the
479        code actually changes:
480    </p>
481        <p>
482        That completes our update to <code class="function">example_database_load</code>.
483        Now when this program is called, it will automatically index inventory
484        items based on their names. We can then query for those items using the
485        new index. We show how to do that in the next section.
486    </p>
487      </div>
488      <div class="sect2" lang="en" xml:lang="en">
489        <div class="titlepage">
490          <div>
491            <div>
492              <h3 class="title"><a id="edrWIndexes"></a>Secondary Databases with example_database_read</h3>
493            </div>
494          </div>
495        </div>
496        <p>
497            In <a class="xref" href="CoreCursorUsage.html" title="Cursor Example">Cursor Example</a> we
498            wrote an application that displays every inventory item in the
499            Inventory database. In this section, we will update that example to
500            allow us to search for and display an inventory item given a
501            specific name. To do this, we will make use of the secondary
502            database that <code class="function">example_database_load</code> now
503            creates.
504        </p>
505        <p>
506            Because we manage all our database open and close activities in
507            <code class="function">databases_setup()</code> and
508            <code class="function">databases_close()</code>,
509            the update to <code class="function">example_database_read</code> is
510            relatively modest. We need only add a command line parameter on
511            which we can specify the item name, and we will need a new function
512            in which we will perform the query and display the results.
513        </p>
514        <p>
515            To begin, we add a single forward declaration to the application,
516            and update our usage function slightly:
517        </p>
518        <a id="c_index15"></a>
519        <pre class="programlisting">/* File: example_database_read.c */
520/* gettingstarted_common.h includes db.h for us */
521#include "gettingstarted_common.h"
522                                                                                                                                  
523/* Forward declarations */
524char * show_inventory_item(void *);
525int show_all_records(STOCK_DBS *);
526<strong class="userinput"><code>int show_records(STOCK_DBS *, char *);</code></strong>
527int show_vendor_record(char *, DB *); </pre>
528        <p>
529        Next, we update <code class="function">main()</code> to 
530        
531        accept the new command line switch.
532        We also need a new variable to contain the item's name.        
533    </p>
534        <a id="c_index16"></a>
535        <pre class="programlisting">/*
536<strong class="userinput"><code> * Searches for a inventory item based on that item's name. The search is
537 * performed using the item name secondary database. Displays all
538 * inventory items that use the specified name, as well as the vendor
539 * associated with that inventory item.
540 *
541 * If no item name is provided, then all inventory items are displayed.</code></strong>
542 */
543int
544main(int argc, char *argv[])
545{
546    STOCK_DBS my_stock;
547    int ret;
548    <strong class="userinput"><code>char *itemname</code></strong>;
549                                                                                                                                         
550    /* Initialize the STOCK_DBS struct */
551    initialize_stockdbs(&amp;my_stock);
552                                                                                                                                         
553    <strong class="userinput"><code>itemname = NULL;</code></strong>
554    /*
555     * Parse the command line arguments here and determine
556     * the location of the database files <strong class="userinput"><code>as well as the
557     * inventory item we want displayed, if any.</code></strong> This step is
558     * omitted for brevity.
559     */
560                                                                                                                                         
561    /*
562     * Identify the files that will hold our databases
563     * This function uses information obtained from the
564     * command line to identify the directory in which
565     * the database files reside.
566     */
567    set_db_filenames(&amp;my_stock);
568                                                                                                                                         
569    /* Open all databases */
570    ret = databases_setup(&amp;my_stock, "example_database_read", stderr);
571    if (ret != 0) {
572        fprintf(stderr, "Error opening databases\n");
573        databases_close(&amp;my_stock);
574        return (ret);
575    }</pre>
576        <p>
577        The final update to the <code class="function">main()</code> entails a little bit
578        of logic to determine whether we want to display all available inventory
579        items, or just the ones that match a name provided on the
580        <code class="literal">-i</code> command line parameter.
581    </p>
582        <a id="c_index17"></a>
583        <pre class="programlisting">    /* 
584     * Show either a single item or all items, depending
585     * on whether itemname is set to a value.
586     */
587    <strong class="userinput"><code>if (itemname == NULL)
588        ret = show_all_records(&amp;my_stock);
589    else
590        ret = show_records(&amp;my_stock, itemname);</code></strong>
591                                                                                                                                  
592    /* Close our databases */
593    databases_close(&amp;my_stock);
594    return (ret);
595} </pre>
596        <p>
597        The only other thing that we need to add to the application is the
598        implementation of the 
599            <code class="function">show_records()</code> 
600             
601        function.
602    </p>
603        <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
604          <h3 class="title">Note</h3>
605          <p>
606            In the interest of space, we refrain from showing the other
607            functions used by this application. For their implementation, please
608            see <a class="xref" href="CoreCursorUsage.html" title="Cursor Example">Cursor Example</a>.
609            Alternatively, you can see the entire implementation of this
610            application
611            in:
612        </p>
613          <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/getting_started</pre>
614          <p>
615            where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
616            placed your DB distribution.
617        </p>
618        </div>
619        <a id="c_index18"></a>
620        <pre class="programlisting">/*
621 * Search for an inventory item given its name (using the inventory item
622 * secondary database) and display that record and any duplicates that may
623 * exist.
624 */
625int
626show_records(STOCK_DBS *my_stock, char *itemname)
627{
628    DBC *itemname_cursorp;
629    DBT key, data;
630    char *the_vendor;
631    int ret, exit_value;
632                                                                                                                                  
633    /* Initialize our DBTs. */
634    memset(&amp;key, 0, sizeof(DBT));
635    memset(&amp;data, 0, sizeof(DBT));
636                                                                                                                                  
637    /* Get a cursor to the itemname db */
638    my_stock-&gt;itemname_sdbp-&gt;cursor(my_stock-&gt;itemname_sdbp, 0,
639      &amp;itemname_cursorp, 0);
640                                                                                                                                  
641    /*
642     * Get the search key. This is the name on the inventory
643     * record that we want to examine.
644     */
645    key.data = itemname;
646    key.size = strlen(itemname) + 1;
647                                                                                                                                  
648    /*
649     * Position our cursor to the first record in the secondary
650     * database that has the appropriate key.
651     */
652    exit_value = 0;
653    ret = itemname_cursorp-&gt;get(itemname_cursorp, &amp;key, &amp;data, DB_SET);
654    if (!ret) {
655        do {
656            /*
657             * Show the inventory record and the vendor responsible
658             * for this inventory item.
659             */
660            the_vendor = show_inventory_item(data.data);
661            ret = show_vendor_record(the_vendor, my_stock-&gt;vendor_dbp);
662            if (ret) {
663                exit_value = ret;
664                break;
665            }
666            /*
667             * Our secondary allows duplicates, so we need to loop over
668             * the next duplicate records and show them all. This is done
669             * because an inventory item's name is not a unique value.
670             */
671        } while(itemname_cursorp-&gt;get(itemname_cursorp, &amp;key, &amp;data,
672            DB_NEXT_DUP) == 0);
673    } else {
674        printf("No records found for '%s'\n", itemname);
675    }
676                                                                                                                                  
677    /* Close the cursor */
678    itemname_cursorp-&gt;close(itemname_cursorp);
679                                                                                                                                  
680    return (exit_value);
681} </pre>
682        <p>
683        This completes our update to
684        <code class="classname">example_inventory_read</code>. Using this update, you
685        can now search for and show all inventory items that match a particular
686        name. For example:
687    </p>
688        <pre class="programlisting">    example_inventory_read -i "Zulu Nut"</pre>
689      </div>
690    </div>
691    <div class="navfooter">
692      <hr />
693      <table width="100%" summary="Navigation footer">
694        <tr>
695          <td width="40%" align="left"><a accesskey="p" href="joins.html">Prev</a> </td>
696          <td width="20%" align="center">
697            <a accesskey="u" href="indexes.html">Up</a>
698          </td>
699          <td width="40%" align="right"> <a accesskey="n" href="dbconfig.html">Next</a></td>
700        </tr>
701        <tr>
702          <td width="40%" align="left" valign="top">Database Joins </td>
703          <td width="20%" align="center">
704            <a accesskey="h" href="index.html">Home</a>
705          </td>
706          <td width="40%" align="right" valign="top"> Chapter 6. Database Configuration</td>
707        </tr>
708      </table>
709    </div>
710  </body>
711</html>
712