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>Implementing Key Extractors</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="indexes.html" title="Chapter 5. Secondary Databases" /> 12 <link rel="next" href="readSecondary.html" title="Reading Secondary Databases" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Implementing Key 19 20 <span>Extractors</span> 21 </th> 22 </tr> 23 <tr> 24 <td width="20%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td> 25 <th width="60%" align="center">Chapter 5. Secondary Databases</th> 26 <td width="20%" align="right"> <a accesskey="n" href="readSecondary.html">Next</a></td> 27 </tr> 28 </table> 29 <hr /> 30 </div> 31 <div class="sect1" lang="en" xml:lang="en"> 32 <div class="titlepage"> 33 <div> 34 <div> 35 <h2 class="title" style="clear: both"><a id="keyCreator"></a>Implementing Key 36 37 <span>Extractors</span> 38 </h2> 39 </div> 40 </div> 41 </div> 42 <div class="toc"> 43 <dl> 44 <dt> 45 <span class="sect2"> 46 <a href="keyCreator.html#multikeys">Working with Multiple Keys</a> 47 </span> 48 </dt> 49 </dl> 50 </div> 51 <p> 52 You must provide every secondary database with a 53 <span>class</span> 54 55 that creates keys from primary records. You identify this 56 <span>class</span> 57 58 59 60 <span> 61 when you associate your secondary database to your primary. 62 </span> 63 </p> 64 <p> 65 You can create keys using whatever data you want. Typically you will 66 base your key on some information found in a record's data, but you 67 can also use information found in the primary record's key. How you build 68 your keys is entirely dependent upon the nature of the index that you 69 want to maintain. 70 </p> 71 <p> 72 You implement a key extractor by writing a function that extracts 73 the necessary information from a primary record's key or data. 74 This function must conform to a specific prototype, and it must be 75 provided as a callback to the <code class="methodname">associate()</code> 76 method. 77 </p> 78 <p> 79 For example, suppose your primary database records contain data that 80 uses the following structure: 81 </p> 82 <a id="c_index3"></a> 83 <pre class="programlisting">typedef struct vendor { 84 char name[MAXFIELD]; /* Vendor name */ 85 char street[MAXFIELD]; /* Street name and number */ 86 char city[MAXFIELD]; /* City */ 87 char state[3]; /* Two-digit US state code */ 88 char zipcode[6]; /* US zipcode */ 89 char phone_number[13]; /* Vendor phone number */ 90 char sales_rep[MAXFIELD]; /* Name of sales representative */ 91 char sales_rep_phone[MAXFIELD]; /* Sales rep's phone number */ 92} VENDOR; </pre> 93 <p> 94 Further suppose that you want to be able to query your primary database 95 based on the name of a sales representative. Then you would write a 96 function that looks like this: 97 </p> 98 <a id="cxx_index4"></a> 99 <pre class="programlisting">#include <db_cxx.h> 100 101... 102 103int 104get_sales_rep(Db *sdbp, // secondary db handle 105 const Dbt *pkey, // primary db record's key 106 const Dbt *pdata, // primary db record's data 107 Dbt *skey) // secondary db record's key 108{ 109 VENDOR *vendor; 110 111 // First, extract the structure contained in the primary's data 112 vendor = (VENDOR *)pdata->get_data(); 113 114 // Now set the secondary key's data to be the representative's name 115 skey->set_data(vendor->sales_rep); 116 skey->set_size(strlen(vendor->sales_rep) + 1); 117 118 // Return 0 to indicate that the record can be created/updated. 119 return (0); 120} </pre> 121 <p> 122 In order to use this function, you provide it on the 123 <code class="methodname">associate()</code> method after the primary and 124 secondary databases have been created and opened: 125 </p> 126 <a id="cxx_index5"></a> 127 <pre class="programlisting">db.associate(NULL, // TXN id 128 &sdb, // Secondary database 129 get_sales_rep, // Callback used for key creation. 130 0); // Flags</pre> 131 <div class="sect2" lang="en" xml:lang="en"> 132 <div class="titlepage"> 133 <div> 134 <div> 135 <h3 class="title"><a id="multikeys"></a>Working with Multiple Keys</h3> 136 </div> 137 </div> 138 </div> 139 <p> 140 Until now we have only discussed indexes as if there is 141 a one-to-one relationship between the secondary key and 142 the primary database record. In fact, it is possible to 143 generate multiple keys for any given record, provided 144 that you take appropriate steps in your key creator 145 to do so. 146 </p> 147 <p> 148 For example, suppose you had a database that contained 149 information about books. Suppose further that you 150 sometimes want to look up books by author. Because 151 sometimes books have multiple authors, you may want to 152 return multiple secondary keys for every book that you 153 index. 154 </p> 155 <p> 156 To do this, you write a key extractor that returns a 157 158 <span>Dbt</span> 159 whose <code class="literal">data</code> member points to an array of 160 161 <span>Dbts.</span> 162 Each such member of this array contains a single secondary key. 163 In addition, the 164 165 <span>Dbt</span> 166 returned by your key extractor must have a size field 167 equal to the number of elements contained in the 168 169 <span>Dbt</span> 170 array. Also, the flag field for the 171 172 <span>Dbt</span> 173 returned by the callback must include 174 <code class="literal">DB_DBT_MULTIPLE</code>. For example: 175 </p> 176 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 177 <h3 class="title">Note</h3> 178 <p> 179 It is important that the array of secondary 180 keys created by your callback not contain 181 repeats. That is, every element in the array 182 must be unique. If the array does not contain 183 a unique set, then the secondary can get out 184 of sync with the primary. 185 </p> 186 </div> 187 <pre class="programlisting">int 188my_callback(Db *dbp, const Dbt *pkey, const Dbt *pdata, Dbt *skey) 189{ 190 Dbt *tmpdbt; 191 char *tmpdata1, tmpdata2; 192 193 // This example skips the step of extracting the data you 194 // want to use for building your secondary keys from the 195 // pkey or pdata Dbt. 196 197 // Assume for the purpose of this example that the data 198 // is temporarily stored in two variables, 199 // tmpdata1 and tmpdata2. 200 201 // Create an array of Dbts that is large enough for the 202 // number of keys that you want to return. In this case, 203 // we go with an array of size two. 204 205 tmpdbt = malloc(sizeof(Dbt) * 2); 206 memset(tmpdbt, 0, sizeof(Dbt) * 2); 207 208 // Now assign secondary keys to each element of the array. 209 tmpdbt[0].set_data(tmpdata1); 210 tmpdbt[0].set_size((u_int32_t)strlen(tmpdbt[0].data) + 1); 211 tmpdbt[1].set_data(tmpdata2); 212 tmpdbt[1].set_size((u_int32_t)strlen(tmpdbt[1].data) + 1); 213 214 // Now we set flags for the returned Dbt. DB_DBT_MULTIPLE is 215 // required in order for DB to know that the Dbt references an 216 // array. In addition, we set DB_DBT_APPMALLOC because we 217 // dynamically allocated memory for the Dbt's data field. 218 // DB_DBT_APPMALLOC causes DB to release that memory once it 219 // is done with the returned Dbt. 220 skey->set_flags(DB_DBT_MULTIPLE | DB_DBT_APPMALLOC); 221 222 // Point the results data field to the arrays of Dbts 223 skey->set_data(tmpdbt); 224 225 // Indicate the returned array is of size 2 226 skey->size = 2; 227 228 return (0); 229} </pre> 230 </div> 231 </div> 232 <div class="navfooter"> 233 <hr /> 234 <table width="100%" summary="Navigation footer"> 235 <tr> 236 <td width="40%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td> 237 <td width="20%" align="center"> 238 <a accesskey="u" href="indexes.html">Up</a> 239 </td> 240 <td width="40%" align="right"> <a accesskey="n" href="readSecondary.html">Next</a></td> 241 </tr> 242 <tr> 243 <td width="40%" align="left" valign="top">Chapter 5. Secondary Databases </td> 244 <td width="20%" align="center"> 245 <a accesskey="h" href="index.html">Home</a> 246 </td> 247 <td width="40%" align="right" valign="top"> Reading Secondary Databases</td> 248 </tr> 249 </table> 250 </div> 251 </body> 252</html> 253