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>Database Usage Example</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 9 <link rel="home" href="index.html" title="Getting Started with Berkeley DB" /> 10 <link rel="up" href="DBEntry.html" title="Chapter 3. Database Records" /> 11 <link rel="previous" href="cstructs.html" title="Using C Structures with DB" /> 12 <link rel="next" href="Cursors.html" title="Chapter 4. Using Cursors" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Database Usage Example</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="cstructs.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 3. Database Records</th> 23 <td width="20%" align="right"> <a accesskey="n" href="Cursors.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="DbUsage"></a>Database Usage Example</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 In <a href="CoreDbUsage.html">Database Example</a> we created several 39 functions that will open and close the databases that we will use for 40 our inventory application. We now make use of those functions to load inventory data into 41 the two databases that we use for this application. 42 </p> 43 <p> 44 Again, remember that you can find the complete implementation for these functions 45 in: 46 </p> 47 <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/getting_started</pre> 48 <p> 49 where <tt class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></tt> is the location where you 50 placed your DB distribution. 51 </p> 52 <div class="example"> 53 <a id="VENDORStruct"></a> 54 <p class="title"> 55 <b>Example 3.1 VENDOR Structure</b> 56 </p> 57 <p> 58 We want to store data related to an inventory system. There are two 59 types of information that we want to manage: inventory data and related 60 vendor contact information. To manage this information, we could 61 create a structure for each type of data, but to illustrate 62 storing mixed data without a structure we refrain from creating one 63 for the inventory data. 64 </p> 65 <p> 66 For the vendor data, we add the VENDOR structure to the same file as holds 67 our STOCK_DBS structure. Note that the VENDOR structure uses 68 fixed-length fields. This is not necessary and in fact could 69 represent a waste of resources if the number of vendors stored in 70 our database scales to very large numbers. However, for simplicity we use 71 fixed-length fields anyway, especially 72 given that our sample data contains so few vendor records. 73 </p> 74 <p> 75 Note that for the inventory data, we will store the data by 76 marshaling it into a buffer, described below. 77 </p> 78 <a id="c_dbt10"></a> 79 <pre class="programlisting">/* File: gettingstarted_common.h */ 80#include <db.h> 81 82... 83 84<b class="userinput"><tt>typedef struct vendor { 85 char name[MAXFIELD]; /* Vendor name */ 86 char street[MAXFIELD]; /* Street name and number */ 87 char city[MAXFIELD]; /* City */ 88 char state[3]; /* Two-digit US state code */ 89 char zipcode[6]; /* US zipcode */ 90 char phone_number[13]; /* Vendor phone number */ 91 char sales_rep[MAXFIELD]; /* Name of sales representative */ 92 char sales_rep_phone[MAXFIELD]; /* Sales rep's phone number */ 93} VENDOR;</tt></b> </pre> 94 </div> 95 <div class="example"> 96 <a id="exampledbload"></a> 97 <p class="title"> 98 <b>Example 3.2 example_database_load</b> 99 </p> 100 <p> 101 Our initial sample application will load database information from 102 several flat files. To save space, we won't show all the details of 103 this example program. However, as always you can find the complete 104 implementation for this program here: 105 </p> 106 <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/getting_started</pre> 107 <p> 108 where <tt class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></tt> is the location where you 109 placed your DB distribution. 110 </p> 111 <p> 112 We begin with the normal include directives and forward declarations: 113 </p> 114 <a id="c_dbt11"></a> 115 <pre class="programlisting">/* example_database_load.c */ 116#include "gettingstarted_common.h" 117 118 119/* Forward declarations */ 120int load_vendors_database(STOCK_DBS, char *); 121int pack_string(char *, char *, int); 122int load_inventory_database(STOCK_DBS, char *); </pre> 123 <p> 124 Next we begin our <tt class="function">main()</tt> function with the variable 125 declarations and command line parsing that is normal for most command 126 line applications: 127 </p> 128 <a id="c_dbt12"></a> 129 <pre class="programlisting">/* 130 * Loads the contents of vendors.txt and inventory.txt into 131 * Berkeley DB databases. 132 */ 133int 134main(int argc, char *argv[]) 135{ 136 STOCK_DBS my_stock; 137 int ret, size; 138 char *basename, *inventory_file, *vendor_file; 139 140 /* Initialize the STOCK_DBS struct */ 141 initialize_stockdbs(&my_stock); 142 143 /* 144 * Initialize the base path. This path is used to 145 * identify the location of the flat-text data 146 * input files. 147 */ 148 basename = "./"; 149 150 /* 151 * Parse the command line arguments here and determine 152 * the location of the flat text files containing the 153 * inventory data here. This step is omitted for clarity. 154 */ 155 156 /* 157 * Identify the files that will hold our databases 158 * This function uses information obtained from the 159 * command line to identify the directory in which 160 * the database files reside. 161 */ 162 set_db_filenames(&my_stock); 163 164 /* Find our input files */ 165 size = strlen(basename) + strlen(INVENTORY_FILE) + 1; 166 inventory_file = malloc(size); 167 snprintf(inventory_file, size, "%s%s", basename, INVENTORY_FILE); 168 169 size = strlen(basename) + strlen(VENDORS_FILE) + 1; 170 vendor_file = malloc(size); 171 snprintf(vendor_file, size, "%s%s", basename, VENDORS_FILE); 172 173 /* Open all databases */ 174 ret = databases_setup(&my_stock, "example_database_load", stderr); 175 if (ret != 0) { 176 fprintf(stderr, "Error opening databases\n"); 177 databases_close(&my_stock); 178 return (ret); 179 } 180 181 ret = load_vendors_database(my_stock, vendor_file); 182 if (!ret) { 183 fprintf(stderr, "Error loading vendors database.\n"); 184 databases_close(&my_stock); 185 return (ret); 186 } 187 ret = load_inventory_database(my_stock, inventory_file); 188 if (!ret) { 189 fprintf(stderr, "Error loading inventory database.\n"); 190 databases_close(&my_stock); 191 return (ret); 192 } 193 194 /* close our environment and databases */ 195 databases_close(&my_stock); 196 197 printf("Done loading databases.\n"); 198 return (0); 199}</pre> 200 <p> 201 Notice that there is not a lot to this function because we have pushed 202 off all the database activity to other places. In particular our 203 databases are all opened and configured in 204 <tt class="function">databases_setup()</tt> which we implemented in 205 <a href="CoreDbUsage.html#databasesetup">The databases_setup() Function</a>. 206 </p> 207 <p> 208 Next we show the implementation of 209 <tt class="function">load_vendors_database()</tt>. We load this data by 210 scanning (line by line) the contents of the 211 <tt class="filename">vendors.txt</tt> into a VENDOR structure. Once we have a 212 line scanned into the structure, we can store that structure into our 213 vendors database. 214 </p> 215 <p> 216 Note that we use the vendor's name as the key here. In doing so, we 217 assume that the vendor's name is unique in our database. If it was not, 218 we would either have to select a different key, or architect our 219 application such that it could cope with multiple vendor records with 220 the same name. 221 </p> 222 <a id="c_dbt13"></a> 223 <pre class="programlisting">/* 224 * Loads the contents of the vendors.txt file into 225 * a database. 226 */ 227int 228load_vendors_database(STOCK_DBS my_stock, char *vendor_file) 229{ 230 DBT key, data; 231 FILE *ifp; 232 VENDOR my_vendor; 233 char buf[MAXLINE]; 234 235 /* Open the vendor file for read access */ 236 ifp = fopen(vendor_file, "r"); 237 if (ifp == NULL) { 238 fprintf(stderr, "Error opening file '%s'\n", vendor_file); 239 return(-1); 240 } 241 242 /* Iterate over the vendor file */ 243 while(fgets(buf, MAXLINE, ifp) != NULL) { 244 /* zero out the structure */ 245 memset(&my_vendor, 0, sizeof(VENDOR)); 246 /* Zero out the DBTs */ 247 memset(&key, 0, sizeof(DBT)); 248 memset(&data, 0, sizeof(DBT)); 249 250 /* 251 * Scan the line into the structure. 252 * Convenient, but not particularly safe. 253 * In a real program, there would be a lot more 254 * defensive code here. 255 */ 256 sscanf(buf, 257 "%20[^#]#%20[^#]#%20[^#]#%3[^#]#%6[^#]#%13[^#]#%20[^#]#%20[^\n]", 258 my_vendor.name, my_vendor.street, 259 my_vendor.city, my_vendor.state, 260 my_vendor.zipcode, my_vendor.phone_number, 261 my_vendor.sales_rep, my_vendor.sales_rep_phone); 262 263 /* 264 * Now that we have our structure we can load it 265 * into the database. 266 */ 267 268 /* Set up the database record's key */ 269 key.data = my_vendor.name; 270 key.size = strlen(my_vendor.name) + 1; 271 272 /* Set up the database record's data */ 273 data.data = &my_vendor; 274 data.size = sizeof(my_vendor); 275 276 /* 277 * Note that given the way we built our struct, there are extra 278 * bytes in it. Essentially we're using fixed-width fields with 279 * the unused portion of some fields padded with zeros. This 280 * is the easiest thing to do, but it does result in a bloated 281 * database. Look at load_inventory_data() for an example of how 282 * to avoid this. 283 */ 284 285 /* Put the data into the database. 286 * Omitting error handling for clarity. 287 */ 288 my_stock.vendor_dbp->put(my_stock.vendor_dbp, 0, &key, &data, 0); 289 } /* end vendors database while loop */ 290 291 /* Close the vendor.txt file */ 292 fclose(ifp); 293 return(0); 294} </pre> 295 <p> 296 Finally, we need to write the 297 <tt class="function">load_inventory_database()</tt> function. We made this function a 298 bit more complicated than is necessary by avoiding the use of a 299 structure to manage the data. Instead, we manually pack all our inventory 300 data into a single block of memory, and store that data in the 301 database. 302 </p> 303 <p> 304 While this complicates our code somewhat, this approach allows us to 305 use the smallest amount of space possible for the data that we want to 306 store. The result is that our cache can be smaller than it might 307 otherwise be and our database will take less space on disk than if we used 308 a structure with fixed-length fields. 309 </p> 310 <p> 311 For a trivial dataset such as what we use for these examples, these 312 resource savings are negligible. But if we were storing hundreds of 313 millions of records, then the cost savings may become significant. 314 </p> 315 <p> 316 Before we actually implement our inventory loading function, it is useful 317 to create a simple utility function that copies a character array into a 318 buffer at a designated offset: 319 </p> 320 <a id="c_dbt14"></a> 321 <pre class="programlisting">/* 322 * Simple little convenience function that takes a buffer, a string, 323 * and an offset and copies that string into the buffer at the 324 * appropriate location. Used to ensure that all our strings 325 * are contained in a single contiguous chunk of memory. 326 */ 327int 328pack_string(char *buffer, char *string, int start_pos) 329{ 330 int string_size = strlen(string) + 1; 331 332 memcpy(buffer+start_pos, string, string_size); 333 334 return(start_pos + string_size); 335} </pre> 336 <p> 337 That done, we can now load the inventory database: 338 </p> 339 <a id="c_dbt15"></a> 340 <pre class="programlisting">/* 341 * Loads the contents of the inventory.txt file into 342 * a database. 343 */ 344int 345load_inventory_database(STOCK_DBS my_stock, char *inventory_file) 346{ 347 DBT key, data; 348 char buf[MAXLINE]; 349 void *databuf; 350 int bufLen, dataLen; 351 FILE *ifp; 352 353 /* 354 * Rather than lining everything up nicely in a struct, we're being 355 * deliberately a bit sloppy here. This function illustrates how to 356 * store mixed data that might be obtained from various locations 357 * in your application. 358 */ 359 float price; 360 int quantity; 361 char category[MAXFIELD], name[MAXFIELD]; 362 char vendor[MAXFIELD], sku[MAXFIELD]; 363 364 /* Load the inventory database */ 365 ifp = fopen(inventory_file, "r"); 366 if (ifp == NULL) { 367 fprintf(stderr, "Error opening file '%s'\n", inventory_file); 368 return(-1); 369 } 370 371 /* Get our buffer. MAXDATABUF is some suitably large number */ 372 databuf = malloc(MAXDATABUF); 373 374 /* 375 * Read the inventory.txt file line by line, saving each line off to the 376 * database as we go. 377 */ 378 while(fgets(buf, MAXLINE, ifp) != NULL) { 379 /* 380 * Scan the line into the appropriate buffers and variables. 381 * Convenient, but not particularly safe. In a real 382 * program, there would be a lot more defensive code here. 383 */ 384 sscanf(buf, 385 "%20[^#]#%20[^#]#%f#%i#%20[^#]#%20[^\n]", 386 name, sku, &price, &quantity, category, vendor); 387 388 /* 389 * Now pack it into a single contiguous memory location for 390 * storage. 391 */ 392 memset(databuf, 0, MAXDATABUF); 393 bufLen = 0; 394 dataLen = 0; 395 396 /* 397 * We first store the fixed-length elements. This makes our code to 398 * retrieve this data from the database a little bit easier. 399 */ 400 401 /* First discover how long the data element is. */ 402 dataLen = sizeof(float); 403 /* Then copy it to our buffer */ 404 memcpy(databuf, &price, dataLen); 405 /* 406 * Then figure out how much data is actually in our buffer. 407 * We repeat this pattern for all the data we want to store. 408 */ 409 bufLen += dataLen; 410 411 /* Rinse, lather, repeat. */ 412 dataLen = sizeof(int); 413 memcpy(databuf + bufLen, &quantity, dataLen); 414 bufLen += dataLen; 415 416 bufLen = pack_string(databuf, name, bufLen); 417 bufLen = pack_string(databuf, sku, bufLen); 418 bufLen = pack_string(databuf, category, bufLen); 419 bufLen = pack_string(databuf, vendor, bufLen); 420 421 /* 422 * Now actually save the contents of the buffer off 423 * to our database. 424 */ 425 426 /* Zero out the DBTs */ 427 memset(&key, 0, sizeof(DBT)); 428 memset(&data, 0, sizeof(DBT)); 429 430 /* 431 * The key is the item's SKU. This is a unique value, so we need not 432 * support duplicates for this database. 433 */ 434 key.data = sku; 435 key.size = strlen(sku) + 1; 436 437 /* The data is the information that we packed into databuf. */ 438 data.data = databuf; 439 data.size = bufLen; 440 441 /* Put the data into the database */ 442 my_stock.vendor_dbp->put(my_stock.inventory_dbp, 0, &key, &data, 0); 443 } /* end vendors database while loop */ 444 445 /* Cleanup */ 446 fclose(ifp); 447 if (databuf != NULL) 448 free(databuf); 449 450 return(0); 451} </pre> 452 <p> 453 In the next chapter we provide an example that shows how to read 454 the inventory and vendor databases. 455 </p> 456 </div> 457 </div> 458 <div class="navfooter"> 459 <hr /> 460 <table width="100%" summary="Navigation footer"> 461 <tr> 462 <td width="40%" align="left"><a accesskey="p" href="cstructs.html">Prev</a> </td> 463 <td width="20%" align="center"> 464 <a accesskey="u" href="DBEntry.html">Up</a> 465 </td> 466 <td width="40%" align="right"> <a accesskey="n" href="Cursors.html">Next</a></td> 467 </tr> 468 <tr> 469 <td width="40%" align="left" valign="top">Using C Structures with DB </td> 470 <td width="20%" align="center"> 471 <a accesskey="h" href="index.html">Home</a> 472 </td> 473 <td width="40%" align="right" valign="top"> Chapter 4. Using Cursors</td> 474 </tr> 475 </table> 476 </div> 477 </body> 478</html> 479