1 /*-
2 * Copyright (c) 2004, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file EXAMPLES-LICENSE for license information.
5 */
6
7 #include "gettingstarted_common.h"
8
9 /* Forward declarations */
10 int usage(void);
11 char *show_inventory_item(void *);
12 int show_all_records(STOCK_DBS *);
13 int show_records(STOCK_DBS *, char *);
14 int show_vendor_record(char *, DB *);
15
16 int
usage()17 usage()
18 {
19 fprintf(stderr, "example_database_read [-i <item name>]");
20 fprintf(stderr, " [-h <database home>]\n");
21
22 fprintf(stderr,
23 "\tNote: Any path specified to the -h parameter must end\n");
24 fprintf(stderr, " with your system's path delimiter (/ or \\)\n");
25 return (-1);
26 }
27
28 /*
29 * Searches for a inventory item based on that item's name. The search is
30 * performed using the item name secondary database. Displays all
31 * inventory items that use the specified name, as well as the vendor
32 * associated with that inventory item.
33 *
34 * If no item name is provided, then all inventory items are displayed.
35 */
36 int
main(int argc,char * argv[])37 main(int argc, char *argv[])
38 {
39 STOCK_DBS my_stock;
40 int ch, ret;
41 char *itemname;
42
43 /* Initialize the STOCK_DBS struct */
44 initialize_stockdbs(&my_stock);
45
46 /* Parse the command line arguments */
47 itemname = NULL;
48 while ((ch = getopt(argc, argv, "h:i:?")) != EOF)
49 switch (ch) {
50 case 'h':
51 if (optarg[strlen(optarg)-1] != '/' &&
52 optarg[strlen(optarg)-1] != '\\')
53 return (usage());
54 my_stock.db_home_dir = optarg;
55 break;
56 case 'i':
57 itemname = optarg;
58 break;
59 case '?':
60 default:
61 return (usage());
62 }
63
64 /* Identify the files that hold our databases */
65 set_db_filenames(&my_stock);
66
67 /* Open all databases */
68 ret = databases_setup(&my_stock, "example_database_read", stderr);
69 if (ret != 0) {
70 fprintf(stderr, "Error opening databases\n");
71 databases_close(&my_stock);
72 return (ret);
73 }
74
75 /*
76 * Show either a single item or all items, depending
77 * on whether itemname is set to a value.
78 */
79 if (itemname == NULL)
80 ret = show_all_records(&my_stock);
81 else
82 ret = show_records(&my_stock, itemname);
83
84 /* close our databases */
85 databases_close(&my_stock);
86 return (ret);
87 }
88
show_all_records(STOCK_DBS * my_stock)89 int show_all_records(STOCK_DBS *my_stock)
90 {
91 DBC *inventory_cursorp;
92 DBT key, data;
93 char *the_vendor;
94 int exit_value, ret;
95
96 /* Initialize our DBTs. */
97 memset(&key, 0, sizeof(DBT));
98 memset(&data, 0, sizeof(DBT));
99
100 /* Get a cursor to the inventory db */
101 my_stock->inventory_dbp->cursor(my_stock->inventory_dbp, NULL,
102 &inventory_cursorp, 0);
103
104 /*
105 * Iterate over the inventory database, from the first record
106 * to the last, displaying each in turn.
107 */
108 exit_value = 0;
109 while ((ret =
110 inventory_cursorp->get(inventory_cursorp, &key, &data, DB_NEXT)) == 0)
111 {
112 the_vendor = show_inventory_item(data.data);
113 ret = show_vendor_record(the_vendor, my_stock->vendor_dbp);
114 if (ret) {
115 exit_value = ret;
116 break;
117 }
118 }
119
120 /* Close the cursor */
121 inventory_cursorp->close(inventory_cursorp);
122 return (exit_value);
123 }
124
125 /*
126 * Search for an inventory item given its name (using the inventory item
127 * secondary database) and display that record and any duplicates that may
128 * exist.
129 */
130 int
show_records(STOCK_DBS * my_stock,char * itemname)131 show_records(STOCK_DBS *my_stock, char *itemname)
132 {
133 DBC *itemname_cursorp;
134 DBT key, data;
135 char *the_vendor;
136 int ret, exit_value;
137
138 /* Initialize our DBTs. */
139 memset(&key, 0, sizeof(DBT));
140 memset(&data, 0, sizeof(DBT));
141
142 /* Get a cursor to the itemname db */
143 my_stock->itemname_sdbp->cursor(my_stock->itemname_sdbp, NULL,
144 &itemname_cursorp, 0);
145
146 /*
147 * Get the search key. This is the name on the inventory
148 * record that we want to examine.
149 */
150 key.data = itemname;
151 key.size = (u_int32_t)strlen(itemname) + 1;
152
153 /*
154 * Position our cursor to the first record in the secondary
155 * database that has the appropriate key.
156 */
157 exit_value = 0;
158 ret = itemname_cursorp->get(itemname_cursorp, &key, &data, DB_SET);
159 if (!ret) {
160 do {
161 /*
162 * Show the inventory record and the vendor responsible
163 * for this inventory item.
164 */
165 the_vendor = show_inventory_item(data.data);
166 ret = show_vendor_record(the_vendor, my_stock->vendor_dbp);
167 if (ret) {
168 exit_value = ret;
169 break;
170 }
171 /*
172 * Our secondary allows duplicates, so we need to loop over
173 * the next duplicate records and show them all. This is done
174 * because an inventory item's name is not a unique value.
175 */
176 } while (itemname_cursorp->get(itemname_cursorp, &key, &data,
177 DB_NEXT_DUP) == 0);
178 } else {
179 printf("No records found for '%s'\n", itemname);
180 }
181
182 /* Close the cursor */
183 itemname_cursorp->close(itemname_cursorp);
184
185 return (exit_value);
186 }
187
188 /*
189 * Shows an inventory item. How we retrieve the inventory
190 * item values from the provided buffer is strictly dependent
191 * on the order that those items were originally stored in the
192 * DBT. See load_inventory_database in example_database_load
193 * for how this was done.
194 */
195 char *
show_inventory_item(void * vBuf)196 show_inventory_item(void *vBuf)
197 {
198 float price;
199 int quantity;
200 size_t buf_pos;
201 char *category, *name, *sku, *vendor_name;
202 char *buf = (char *)vBuf;
203
204 /* Get the price. */
205 price = *((float *)buf);
206 buf_pos = sizeof(float);
207
208 /* Get the quantity. */
209 quantity = *((int *)(buf + buf_pos));
210 buf_pos += sizeof(int);
211
212 /* Get the inventory item's name */
213 name = buf + buf_pos;
214 buf_pos += strlen(name) + 1;
215
216 /* Get the inventory item's sku */
217 sku = buf + buf_pos;
218 buf_pos += strlen(sku) + 1;
219
220 /*
221 * Get the category (fruits, vegetables, desserts) that this
222 * item belongs to.
223 */
224 category = buf + buf_pos;
225 buf_pos += strlen(category) + 1;
226
227 /* Get the vendor's name */
228 vendor_name = buf + buf_pos;
229
230 /* Display all this information */
231 printf("name: %s\n", name);
232 printf("\tSKU: %s\n", sku);
233 printf("\tCategory: %s\n", category);
234 printf("\tPrice: %.2f\n", price);
235 printf("\tQuantity: %i\n", quantity);
236 printf("\tVendor:\n");
237
238 /* Return the vendor's name */
239 return (vendor_name);
240 }
241
242 /*
243 * Shows a vendor record. Each vendor record is an instance of
244 * a vendor structure. See load_vendor_database() in
245 * example_database_load for how this structure was originally
246 * put into the database.
247 */
248 int
show_vendor_record(char * vendor_name,DB * vendor_dbp)249 show_vendor_record(char *vendor_name, DB *vendor_dbp)
250 {
251 DBT key, data;
252 VENDOR my_vendor;
253 int ret;
254
255 /* Zero our DBTs */
256 memset(&key, 0, sizeof(DBT));
257 memset(&data, 0, sizeof(DBT));
258
259 /* Set the search key to the vendor's name */
260 key.data = vendor_name;
261 key.size = (u_int32_t)strlen(vendor_name) + 1;
262
263 /*
264 * Make sure we use the memory we set aside for the VENDOR
265 * structure rather than the memory that DB allocates.
266 * Some systems may require structures to be aligned in memory
267 * in a specific way, and DB may not get it right.
268 */
269
270 data.data = &my_vendor;
271 data.ulen = sizeof(VENDOR);
272 data.flags = DB_DBT_USERMEM;
273
274 /* Get the record */
275 ret = vendor_dbp->get(vendor_dbp, NULL, &key, &data, 0);
276 if (ret != 0) {
277 vendor_dbp->err(vendor_dbp, ret, "Error searching for vendor: '%s'",
278 vendor_name);
279 return (ret);
280 } else {
281 printf("\t\t%s\n", my_vendor.name);
282 printf("\t\t%s\n", my_vendor.street);
283 printf("\t\t%s, %s\n", my_vendor.city, my_vendor.state);
284 printf("\t\t%s\n\n", my_vendor.zipcode);
285 printf("\t\t%s\n\n", my_vendor.phone_number);
286 printf("\t\tContact: %s\n", my_vendor.sales_rep);
287 printf("\t\t%s\n", my_vendor.sales_rep_phone);
288 }
289 return (0);
290 }
291