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