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 54 <span>callback</span> 55 that creates keys from primary records. You identify this 56 57 <span>callback</span> 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="c_index4"></a> 99 <pre class="programlisting">#include <db.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 = pdata->data; 113 114 /* Now set the secondary key's data to be the representative's name */ 115 memset(skey, 0, sizeof(DBT)); 116 skey->data = vendor->sales_rep; 117 skey->size = strlen(vendor->sales_rep) + 1; 118 119 /* Return 0 to indicate that the record can be created/updated. */ 120 return (0); 121} </pre> 122 <p> 123 In order to use this function, you provide it on the 124 <code class="methodname">associate()</code> method after the primary and 125 secondary databases have been created and opened: 126 </p> 127 <a id="c_index5"></a> 128 <pre class="programlisting">dbp->associate(dbp, /* Primary database */ 129 NULL, /* TXN id */ 130 sdbp, /* Secondary database */ 131 get_sales_rep, /* Callback used for key creation. */ 132 0); /* Flags */</pre> 133 <div class="sect2" lang="en" xml:lang="en"> 134 <div class="titlepage"> 135 <div> 136 <div> 137 <h3 class="title"><a id="multikeys"></a>Working with Multiple Keys</h3> 138 </div> 139 </div> 140 </div> 141 <p> 142 Until now we have only discussed indexes as if there is 143 a one-to-one relationship between the secondary key and 144 the primary database record. In fact, it is possible to 145 generate multiple keys for any given record, provided 146 that you take appropriate steps in your key creator 147 to do so. 148 </p> 149 <p> 150 For example, suppose you had a database that contained 151 information about books. Suppose further that you 152 sometimes want to look up books by author. Because 153 sometimes books have multiple authors, you may want to 154 return multiple secondary keys for every book that you 155 index. 156 </p> 157 <p> 158 To do this, you write a key extractor that returns a 159 <span>DBT</span> 160 161 whose <code class="literal">data</code> member points to an array of 162 <span>DBTs.</span> 163 164 Each such member of this array contains a single secondary key. 165 In addition, the 166 <span>DBT</span> 167 168 returned by your key extractor must have a size field 169 equal to the number of elements contained in the 170 <span>DBT</span> 171 172 array. Also, the flag field for the 173 <span>DBT</span> 174 175 returned by the callback must include 176 <code class="literal">DB_DBT_MULTIPLE</code>. For example: 177 </p> 178 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 179 <h3 class="title">Note</h3> 180 <p> 181 It is important that the array of secondary 182 keys created by your callback not contain 183 repeats. That is, every element in the array 184 must be unique. If the array does not contain 185 a unique set, then the secondary can get out 186 of sync with the primary. 187 </p> 188 </div> 189 <pre class="programlisting">int 190my_callback(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) 191{ 192 DBT *tmpdbt; 193 char *tmpdata1, tmpdata2; 194 195 /* 196 * This example skips the step of extracting the data you 197 * want to use for building your secondary keys from the 198 * pkey or pdata DBT. 199 * 200 * Assume for the purpose of this example that the data 201 * is temporarily stored in two variables, 202 * tmpdata1 and tmpdata2. 203 */ 204 205 /* 206 * Create an array of DBTs that is large enough for the 207 * number of keys that you want to return. In this case, 208 * we go with an array of size two. 209 */ 210 211 tmpdbt = malloc(sizeof(DBT) * 2); 212 memset(tmpdbt, 0, sizeof(DBT) * 2); 213 214 /* Now assign secondary keys to each element of the array. */ 215 tmpdbt[0].data = tmpdata1; 216 tmpdbt[0].size = (u_int32_t)strlen(tmpdbt[0].data) + 1; 217 tmpdbt[1].data = tmpdata2; 218 tmpdbt[1].size = (u_int32_t)strlen(tmpdbt[1].data) + 1; 219 220 /* 221 * Now we set flags for the returned DBT. DB_DBT_MULTIPLE is 222 * required in order for DB to know that the DBT references an 223 * array. In addition, we set DB_DBT_APPMALLOC because we 224 * dynamically allocated memory for the DBT's data field. 225 * DB_DBT_APPMALLOC causes DB to release that memory once it 226 * is done with the returned DBT. 227 */ 228 skey->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC; 229 230 /* Point the results data field to the arrays of DBTs */ 231 skey->data = tmpdbt; 232 233 /* Indicate the returned array is of size 2 */ 234 skey->size = 2; 235 236 return (0); 237} </pre> 238 </div> 239 </div> 240 <div class="navfooter"> 241 <hr /> 242 <table width="100%" summary="Navigation footer"> 243 <tr> 244 <td width="40%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td> 245 <td width="20%" align="center"> 246 <a accesskey="u" href="indexes.html">Up</a> 247 </td> 248 <td width="40%" align="right"> <a accesskey="n" href="readSecondary.html">Next</a></td> 249 </tr> 250 <tr> 251 <td width="40%" align="left" valign="top">Chapter 5. Secondary Databases </td> 252 <td width="20%" align="center"> 253 <a accesskey="h" href="index.html">Home</a> 254 </td> 255 <td width="40%" align="right" valign="top"> Reading Secondary Databases</td> 256 </tr> 257 </table> 258 </div> 259 </body> 260</html> 261