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="usingDbt.html" title="Reading and Writing Database Records" /> 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="usingDbt.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="DbCXXUsage"></a>Database Usage Example</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 In <a href="CoreDbCXXUsage.html">Database Example</a> we created 39 a class that opens and closes a database for us. 40 We now make use of that class to load inventory data into 41 two databases that we will use for our inventory system. 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_cxx/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="VENDORCXXStruct"></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 have created 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 We now show the definition of the VENDOR structure. 67 Note that the VENDOR structure uses fixed-length fields. 68 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 <a id="cxx_dbt10"></a> 75 <pre class="programlisting">// File: gettingStartedCommon.hpp 76#define MAXFIELD 20 77typedef struct vendor { 78 char name[MAXFIELD]; // Vendor name 79 char street[MAXFIELD]; // Street name and number 80 char city[MAXFIELD]; // City 81 char state[3]; // Two-digit US state code 82 char zipcode[6]; // US zipcode 83 char phone_number[13]; // Vendor phone number 84 char sales_rep[MAXFIELD]; // Name of sales representative 85 char sales_rep_phone[MAXFIELD]; // Sales rep's phone number 86} VENDOR;</pre> 87 </div> 88 <div class="example"> 89 <a id="InventoryData"></a> 90 <p class="title"> 91 <b>Example 3.2 InventoryData Class</b> 92 </p> 93 <p> 94 In order to manage our actual inventory data, we create a class that 95 encapsulates the data that we want to store for each inventory 96 record. Beyond simple data encapsulation, this class is also capable 97 of marshaling the inventory data into a single contiguous buffer 98 for the purposes of storing in that data in a DB database. 99 </p> 100 <p> 101 We also provide two constructors for this class. The default 102 constructor simply initializes all our data members for us. A second 103 constructor is also provided that is capable of populating our data 104 members from a <tt class="literal">void *</tt>. This second constructor is 105 not really needed until the next chapter where we show how to read 106 data from the databases, but we include it here for the purpose of 107 completeness anyway. 108 </p> 109 <p> 110 To simplify things a bit, we include the entire implementation for this 111 class in <tt class="filename">gettingStartedCommon.hpp</tt> along with 112 our <tt class="literal">VENDOR</tt> structure definition. 113 </p> 114 <p> 115 To begin, we create the public getter and setter methods that we 116 use with our class' private members. We also show the implementation 117 of the method that we use to initialize all our private members. 118 </p> 119 <a id="cxx_dbt11"></a> 120 <pre class="programlisting">class InventoryData 121{ 122public: 123 inline void setPrice(double price) {price_ = price;} 124 inline void setQuantity(long quantity) {quantity_ = quantity;} 125 inline void setCategory(std::string &category) {category_ = category;} 126 inline void setName(std::string &name) {name_ = name;} 127 inline void setVendor(std::string &vendor) {vendor_ = vendor;} 128 inline void setSKU(std::string &sku) {sku_ = sku;} 129 130 inline double& getPrice() {return(price_);} 131 inline long& getQuantity() {return(quantity_);} 132 inline std::string& getCategory() {return(category_);} 133 inline std::string& getName() {return(name_);} 134 inline std::string& getVendor() {return(vendor_);} 135 inline std::string& getSKU() {return(sku_);} 136 137 // Initialize our data members 138 void clear() 139 { 140 price_ = 0.0; 141 quantity_ = 0; 142 category_.clear(); 143 name_.clear(); 144 vendor_.clear(); 145 sku_.clear(); 146 } </pre> 147 <p> 148 Next we implement our constructors. The default constructor simply calls 149 the <tt class="methodname">clear()</tt>. The second constructor takes a 150 <tt class="literal">void *</tt> as an argument, which it then uses to 151 initialize the data members. Note, again, that we will not actually use 152 this second constructor in this chapter, but we show it here just to be 153 complete anyway. 154 </p> 155 <a id="cxx_dbt12"></a> 156 <pre class="programlisting"> // Default constructor 157 InventoryData() { clear(); } 158 159 // Constructor from a void * 160 // For use with the data returned from a bdb get 161 InventoryData(void *buffer) 162 { 163 char *buf = (char *)buffer; 164 165 price_ = *((double *)buf); 166 bufLen_ = sizeof(double); 167 168 quantity_ = *((long *)(buf + bufLen_)); 169 bufLen_ += sizeof(long); 170 171 name_ = buf + bufLen_; 172 bufLen_ += name_.size() + 1; 173 174 sku_ = buf + bufLen_; 175 bufLen_ += sku_.size() + 1; 176 177 category_ = buf + bufLen_; 178 bufLen_ += category_.size() + 1; 179 180 vendor_ = buf + bufLen_; 181 bufLen_ += vendor_.size() + 1; 182 } </pre> 183 <p> 184 Next we provide a couple of methods for returning the class' buffer and 185 the size of the buffer. These are used for actually storing the class' 186 data in a DB database. 187 </p> 188 <a id="cxx_dbt13"></a> 189 <pre class="programlisting"> // Marshalls this classes data members into a single 190 // contiguous memory location for the purpose of storing 191 // the data in a database. 192 char * 193 getBuffer() 194 { 195 // Zero out the buffer 196 memset(databuf_, 0, 500); 197 // Now pack the data into a single contiguous memory location for 198 // storage. 199 bufLen_ = 0; 200 int dataLen = 0; 201 202 dataLen = sizeof(double); 203 memcpy(databuf_, &price_, dataLen); 204 bufLen_ += dataLen; 205 206 dataLen = sizeof(long); 207 memcpy(databuf_ + bufLen_, &quantity_, dataLen); 208 bufLen_ += dataLen; 209 210 packString(databuf_, name_); 211 packString(databuf_, sku_); 212 packString(databuf_, category_); 213 packString(databuf_, vendor_); 214 215 return (databuf_); 216 } 217 218 // Returns the size of the buffer. Used for storing 219 // the buffer in a database. 220 inline int getBufferSize() { return (bufLen_); } </pre> 221 <p> 222 Our last public method is a utility method that we use to get the class 223 to show itself. 224 </p> 225 <a id="cxx_dbt14"></a> 226 <pre class="programlisting"> // Utility function used to show the contents of this class 227 void 228 show() { 229 std::cout << "\nName: " << name_ << std::endl; 230 std::cout << " SKU: " << sku_ << std::endl; 231 std::cout << " Price: " << price_ << std::endl; 232 std::cout << " Quantity: " << quantity_ << std::endl; 233 std::cout << " Category: " << category_ << std::endl; 234 std::cout << " Vendor: " << vendor_ << std::endl; 235 } </pre> 236 <p> 237 Finally, we provide a private method that is used to help us pack data 238 into our buffer, and we declare our private data members. 239 </p> 240 <a id="cxx_dbt15"></a> 241 <pre class="programlisting">private: 242 243 // Utility function that appends a char * to the end of 244 // the buffer. 245 void 246 packString(char *buffer, std::string &theString) 247 { 248 int string_size = theString.size() + 1; 249 memcpy(buffer+bufLen_, theString.c_str(), string_size); 250 bufLen_ += string_size; 251 } 252 253 // Data members 254 std::string category_, name_, vendor_, sku_; 255 double price_; 256 long quantity_; 257 int bufLen_; 258 char databuf_[500]; 259}; </pre> 260 </div> 261 <div class="example"> 262 <a id="exampledbload-cxx"></a> 263 <p class="title"> 264 <b>Example 3.3 example_database_load</b> 265 </p> 266 <p> 267 Our initial sample application loads database information from 268 several flat files. To save space, we won't show all the details of 269 this example program. However, as always you can find the complete 270 implementation for this program here: 271 </p> 272 <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_cxx/getting_started</pre> 273 <p> 274 where <tt class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></tt> is the location where you 275 placed your DB distribution. 276 </p> 277 <p> 278 We begin with the normal include directives and forward declarations: 279 </p> 280 <a id="cxx_dbt16"></a> 281 <pre class="programlisting">// File: example_database_load.cpp 282#include <iostream> 283#include <fstream> 284#include <cstdlib> 285 286#include "MyDb.hpp" 287#include "gettingStartedCommon.hpp" 288 289// Forward declarations 290void loadVendorDB(MyDb&, std::string&); 291void loadInventoryDB(MyDb&, std::string&); 292</pre> 293 <p> 294 Next we begin our <tt class="function">main()</tt> function with the variable 295 declarations and command line parsing that is normal for most command 296 line applications: 297 </p> 298 <a id="cxx_dbt17"></a> 299 <pre class="programlisting">// Loads the contents of vendors.txt and inventory.txt into 300// Berkeley DB databases. 301int 302main(int argc, char *argv[]) 303{ 304 // Initialize the path to the database files 305 std::string basename("./"); 306 std::string databaseHome("./"); 307 308 // Database names 309 std::string vDbName("vendordb.db"); 310 std::string iDbName("inventorydb.db"); 311 312 // Parse the command line arguments here and determine 313 // the location of the flat text files containing the 314 // inventory data here. This step is omitted for clarity. 315 316 // Identify the full name for our input files, which should 317 // also include some path information. 318 std::string inventoryFile = basename + "inventory.txt"; 319 std::string vendorFile = basename + "vendors.txt"; 320 321 try 322 { 323 // Open all databases. 324 MyDb inventoryDB(databaseHome, iDbName); 325 MyDb vendorDB(databaseHome, vDbName); 326 327 // Load the vendor database 328 loadVendorDB(vendorDB, vendorFile); 329 330 // Load the inventory database 331 loadInventoryDB(inventoryDB, inventoryFile); 332 } catch(DbException &e) { 333 std::cerr << "Error loading databases. " << std::endl; 334 std::cerr << e.what() << std::endl; 335 return(e.get_errno()); 336 } catch(std::exception &e) { 337 std::cerr << "Error loading databases. " << std::endl; 338 std::cerr << e.what() << std::endl; 339 return(-1); 340 } 341 342 return(0); 343} // End main </pre> 344 <p> 345 Note that we do not explicitly close our databases here. This is because 346 the databases are encapsulated in <tt class="classname">MyDb</tt> class 347 objects, and those objects are on the stack. When they go out of scope, 348 their destructors will cause the database close to occur. 349 </p> 350 <p> 351 Notice that there is not a lot to this function because we have pushed 352 off all the database activity to other places. 353 </p> 354 <p> 355 Next we show the implementation of 356 <tt class="function">loadVendorDB()</tt>. We load this data by 357 scanning (line by line) the contents of the 358 <tt class="filename">vendors.txt</tt> file into a VENDOR structure. Once we have a 359 line scanned into the structure, we can store that structure into our 360 vendors database. 361 </p> 362 <p> 363 Note that we use the vendor's name as the key here. In doing so, we 364 assume that the vendor's name is unique in our database. If it was not, 365 we would either have to select a different key, or architect our 366 application such that it could cope with multiple vendor records with 367 the same name. 368 </p> 369 <a id="cxx_dbt18"></a> 370 <pre class="programlisting">// Loads the contents of the vendors.txt file into a database 371void 372loadVendorDB(MyDb &vendorDB, std::string &vendorFile) 373{ 374 std::ifstream inFile(vendorFile.c_str(), std::ios::in); 375 if ( !inFile ) 376 { 377 std::cerr << "Could not open file '" << vendorFile 378 << "'. Giving up." << std::endl; 379 throw std::exception(); 380 } 381 382 VENDOR my_vendor; 383 while (!inFile.eof()) 384 { 385 std::string stringBuf; 386 std::getline(inFile, stringBuf); 387 memset(&my_vendor, 0, sizeof(VENDOR)); 388 389 // Scan the line into the structure. 390 // Convenient, but not particularly safe. 391 // In a real program, there would be a lot more 392 // defensive code here. 393 sscanf(stringBuf.c_str(), 394 "%20[^#]#%20[^#]#%20[^#]#%3[^#]#%6[^#]#%13[^#]#%20[^#]#%20[^\n]", 395 my_vendor.name, my_vendor.street, 396 my_vendor.city, my_vendor.state, 397 my_vendor.zipcode, my_vendor.phone_number, 398 my_vendor.sales_rep, my_vendor.sales_rep_phone); 399 400 Dbt key(my_vendor.name, strlen(my_vendor.name) + 1); 401 Dbt data(&my_vendor, sizeof(VENDOR)); 402 403 vendorDB.getDb().put(NULL, &key, &data, 0); 404 } 405 inFile.close(); 406} </pre> 407 <p> 408 Finally, we need to write the 409 <tt class="function">loadInventoryDB()</tt> function. To load the inventory information, 410 we read in each line of the inventory.txt file, obtain each field from 411 it, then we load this data into an <tt class="classname">InventoryData</tt> 412 instance. 413 </p> 414 <p> 415 To help us obtain the various fields from each line of input, 416 we also create a simple helper function that locates the position of the 417 first a field delimiter (a pound (#) sign) from a line of input. 418 </p> 419 <p> 420 Note that we could have simply decided to store our inventory data in a 421 structure very much like the VENDOR structure that we use above. 422 However, by storing this data in the 423 <tt class="classname">InventoryData</tt> class, which identifies the size of 424 the data that it contains, 425 we can use the smallest amount of space possible for the data that we 426 are storing. The result is that our cache can be smaller than it might 427 otherwise be and our database will take less space on disk than if we used 428 a structure with fixed-length fields. 429 </p> 430 <p> 431 For a trivial dataset such as what we use for these examples, these 432 resource savings are negligible. But if we were storing hundreds of 433 millions of records, then the cost savings may become significant. 434 </p> 435 <a id="cxx_dbt19"></a> 436 <pre class="programlisting">// Used to locate the first pound sign (a field delimiter) 437// in the input string. 438int 439getNextPound(std::string &theString, std::string &substring) 440{ 441 int pos = theString.find("#"); 442 substring.assign(theString, 0, pos); 443 theString.assign(theString, pos + 1, theString.size()); 444 return (pos); 445} 446 447 448// Loads the contents of the inventory.txt file into a database 449void 450loadInventoryDB(MyDb &inventoryDB, std::string &inventoryFile) 451{ 452 InventoryData inventoryData; 453 std::string substring; 454 int nextPound; 455 456 std::ifstream inFile(inventoryFile.c_str(), std::ios::in); 457 if (!inFile) 458 { 459 std::cerr << "Could not open file '" << inventoryFile 460 << "'. Giving up." << std::endl; 461 throw std::exception(); 462 } 463 464 while (!inFile.eof()) 465 { 466 inventoryData.clear(); 467 std::string stringBuf; 468 std::getline(inFile, stringBuf); 469 470 // Now parse the line 471 if (!stringBuf.empty()) 472 { 473 nextPound = getNextPound(stringBuf, substring); 474 inventoryData.setName(substring); 475 476 nextPound = getNextPound(stringBuf, substring); 477 inventoryData.setSKU(substring); 478 479 nextPound = getNextPound(stringBuf, substring); 480 inventoryData.setPrice(strtod(substring.c_str(), 0)); 481 482 nextPound = getNextPound(stringBuf, substring); 483 inventoryData.setQuantity(strtol(substring.c_str(), 0, 10)); 484 485 nextPound = getNextPound(stringBuf, substring); 486 inventoryData.setCategory(substring); 487 488 nextPound = getNextPound(stringBuf, substring); 489 inventoryData.setVendor(substring); 490 491 void *buff = (void *)inventoryData.getSKU().c_str(); 492 int size = inventoryData.getSKU().size()+1; 493 Dbt key(buff, size); 494 495 buff = inventoryData.getBuffer(); 496 size = inventoryData.getBufferSize(); 497 Dbt data(buff, size); 498 499 inventoryDB.getDb().put(NULL, &key, &data, 0); 500 } 501 } 502 inFile.close(); 503} </pre> 504 <p> 505 In the next chapter we provide an example that shows how to read 506 the inventory and vendor databases. 507 </p> 508 </div> 509 </div> 510 <div class="navfooter"> 511 <hr /> 512 <table width="100%" summary="Navigation footer"> 513 <tr> 514 <td width="40%" align="left"><a accesskey="p" href="usingDbt.html">Prev</a> </td> 515 <td width="20%" align="center"> 516 <a accesskey="u" href="DBEntry.html">Up</a> 517 </td> 518 <td width="40%" align="right"> <a accesskey="n" href="Cursors.html">Next</a></td> 519 </tr> 520 <tr> 521 <td width="40%" align="left" valign="top">Reading and Writing Database Records </td> 522 <td width="20%" align="center"> 523 <a accesskey="h" href="index.html">Home</a> 524 </td> 525 <td width="40%" align="right" valign="top"> Chapter 4. Using Cursors</td> 526 </tr> 527 </table> 528 </div> 529 </body> 530</html> 531