1// File: excxx_example_database_read.cpp
2
3#include <iostream>
4#include <fstream>
5#include <cstdlib>
6
7#include "MyDb.hpp"
8#include "gettingStartedCommon.hpp"
9
10#ifdef _WIN32
11extern "C" {
12  extern int getopt(int, char * const *, const char *);
13  extern char *optarg;
14}
15#else
16#include <unistd.h>
17#endif
18
19// Forward declarations
20int show_item(MyDb &itemnameSDB, MyDb &vendorDB, std::string &itemName);
21int show_all_records(MyDb &inventoryDB, MyDb &vendorDB);
22int show_vendor(MyDb &vendorDB, const char *vendor);
23
24int
25usage()
26{
27    std::cout << "example_database_read [-i <path to data files>]"
28              << " [-h <database home directory>]" << std::endl;
29
30    std::cout << "Note: Any path specified to the -h parameter must end"
31              << " with your system's path delimiter (/ or \\)"
32              << std::endl;
33    return (-1);
34}
35
36int
37main (int argc, char *argv[])
38{
39
40   char ch, lastChar;
41
42   // Initialize the path to the database files
43   std::string databaseHome("./");
44   std::string itemName;
45
46   // Database names
47   std::string vDbName("vendordb.db");
48   std::string iDbName("inventorydb.db");
49   std::string itemSDbName("itemname.sdb");
50
51    // Parse the command line arguments
52    while ((ch = getopt(argc, argv, "h:i:")) != EOF)
53        switch (ch) {
54        case 'h':
55            databaseHome = optarg;
56            lastChar = databaseHome[databaseHome.size() -1];
57            if (lastChar != '/' && lastChar != '\\')
58                return (usage());
59            break;
60        case 'i':
61            itemName = optarg;
62            break;
63        case '?':
64        default:
65            return (usage());
66            break;
67        }
68
69    try
70    {
71        // Open all databases.
72        MyDb inventoryDB(databaseHome, iDbName);
73        MyDb vendorDB(databaseHome, vDbName);
74        MyDb itemnameSDB(databaseHome, itemSDbName, true);
75
76        // Associate the secondary to the primary
77        inventoryDB.getDb().associate(NULL,
78                                      &(itemnameSDB.getDb()),
79                                      get_item_name,
80                                      0);
81
82        if (itemName.empty())
83        {
84            show_all_records(inventoryDB, vendorDB);
85        } else {
86            show_item(itemnameSDB, vendorDB, itemName);
87        }
88    } catch(DbException &e) {
89        std::cerr << "Error reading databases. " << std::endl;
90        return (e.get_errno());
91    } catch(std::exception &e) {
92        std::cerr << "Error reading databases. " << std::endl;
93        std::cerr << e.what() << std::endl;
94        return (-1);
95    }
96
97    return (0);
98} // End main
99
100// Shows the records in the inventory database that
101// have a specific item name. For each inventory record
102// shown, the appropriate vendor record is also displayed.
103int
104show_item(MyDb &itemnameSDB, MyDb &vendorDB, std::string &itemName)
105{
106
107    // Get a cursor to the itemname secondary db
108    Dbc *cursorp;
109
110    try {
111        itemnameSDB.getDb().cursor(NULL, &cursorp, 0);
112
113        // Get the search key. This is the name on the inventory
114        // record that we want to examine.
115        std::cout << "Looking for " << itemName << std::endl;
116        Dbt key((void *)itemName.c_str(), (u_int32_t)itemName.length() + 1);
117        Dbt data;
118
119        // Position the cursor to the first record in the secondary
120        // database that has the appropriate key.
121        int ret = cursorp->get(&key, &data, DB_SET);
122        if (!ret) {
123            do {
124                InventoryData inventoryItem(data.get_data());
125                inventoryItem.show();
126
127                show_vendor(vendorDB, inventoryItem.getVendor().c_str());
128
129            } while (cursorp->get(&key, &data, DB_NEXT_DUP) == 0);
130        } else {
131            std::cerr << "No records found for '" << itemName
132                    << "'" << std::endl;
133        }
134    } catch(DbException &e) {
135        itemnameSDB.getDb().err(e.get_errno(), "Error in show_item");
136        cursorp->close();
137        throw e;
138    } catch(std::exception &e) {
139        itemnameSDB.getDb().errx("Error in show_item: %s", e.what());
140        cursorp->close();
141        throw e;
142    }
143
144    cursorp->close();
145    return (0);
146}
147
148// Shows all the records in the inventory database.
149// For each inventory record shown, the appropriate
150// vendor record is also displayed.
151int
152show_all_records(MyDb &inventoryDB, MyDb &vendorDB)
153{
154
155    // Get a cursor to the inventory db
156    Dbc *cursorp;
157    try {
158        inventoryDB.getDb().cursor(NULL, &cursorp, 0);
159
160        // Iterate over the inventory database, from the first record
161        // to the last, displaying each in turn
162        Dbt key, data;
163        int ret;
164        while ((ret = cursorp->get(&key, &data, DB_NEXT)) == 0 )
165        {
166            InventoryData inventoryItem(data.get_data());
167            inventoryItem.show();
168
169            show_vendor(vendorDB, inventoryItem.getVendor().c_str());
170        }
171    } catch(DbException &e) {
172        inventoryDB.getDb().err(e.get_errno(), "Error in show_all_records");
173        cursorp->close();
174        throw e;
175    } catch(std::exception &e) {
176        cursorp->close();
177        throw e;
178    }
179
180    cursorp->close();
181    return (0);
182}
183
184// Shows a vendor record. Each vendor record is an instance of
185// a vendor structure. See loadVendorDB() in
186// example_database_load for how this structure was originally
187// put into the database.
188int
189show_vendor(MyDb &vendorDB, const char *vendor)
190{
191    Dbt data;
192    VENDOR my_vendor;
193
194    try {
195        // Set the search key to the vendor's name
196        // vendor is explicitly cast to char * to stop a compiler
197        // complaint.
198        Dbt key((char *)vendor, (u_int32_t)strlen(vendor) + 1);
199
200        // Make sure we use the memory we set aside for the VENDOR
201        // structure rather than the memory that DB allocates.
202        // Some systems may require structures to be aligned in memory
203        // in a specific way, and DB may not get it right.
204
205        data.set_data(&my_vendor);
206        data.set_ulen(sizeof(VENDOR));
207        data.set_flags(DB_DBT_USERMEM);
208
209        // Get the record
210        vendorDB.getDb().get(NULL, &key, &data, 0);
211        std::cout << "        " << my_vendor.street << "\n"
212                  << "        " << my_vendor.city << ", "
213                  << my_vendor.state << "\n"
214                  << "        " << my_vendor.zipcode << "\n"
215                  << "        " << my_vendor.phone_number << "\n"
216                  << "        Contact: " << my_vendor.sales_rep << "\n"
217                  << "                 " << my_vendor.sales_rep_phone
218                  << std::endl;
219
220    } catch(DbException &e) {
221        vendorDB.getDb().err(e.get_errno(), "Error in show_vendor");
222        throw e;
223    } catch(std::exception &e) {
224        throw e;
225    }
226    return (0);
227}
228