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 int get_item_name(DB *, const DBT *, const DBT *, DBT *);
10 
11 /*
12  * Used to extract an inventory item's name from an
13  * inventory database record. This function is used to create
14  * keys for secondary database records.
15  */
16 int
get_item_name(DB * dbp,const DBT * pkey,const DBT * pdata,DBT * skey)17 get_item_name(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey)
18 {
19     u_int offset;
20 
21     COMPQUIET(dbp, NULL);                         /* Not needed, unused. */
22     COMPQUIET(pkey, NULL);
23 
24     /*
25      * First, obtain the buffer location where we placed the
26      * item's name. In this example, the item's name is located
27      * in the primary data. It is the first string in the
28      * buffer after the price (a float) and the quantity (an int).
29      *
30      * See load_inventory_database() in example_database_load.c
31      * for how we packed the inventory information into the
32      * data DBT.
33      */
34     offset = sizeof(float) + sizeof(int);
35 
36     /* Check to make sure there's data */
37     if (pdata->size < offset)
38 	return (-1); /* Returning non-zero means that the
39 		      * secondary record is not created/updated.
40 		      */
41 
42     /* Now set the secondary key's data to be the item name */
43     memset(skey, 0, sizeof(DBT));
44     skey->data = (u_int8_t *)pdata->data + offset;
45     skey->size = (u_int32_t)strlen(skey->data) + 1;
46 
47     return (0);
48 }
49 
50 /* Opens a database */
51 int
open_database(DB ** dbpp,const char * file_name,const char * program_name,FILE * error_file_pointer,int is_secondary)52 open_database(DB **dbpp,       /* The DB handle that we are opening */
53     const char *file_name,     /* The file in which the db lives */
54     const char *program_name,  /* Name of the program */
55     FILE *error_file_pointer,
56     int is_secondary)
57 {
58     DB *dbp;    /* For convenience */
59     u_int32_t open_flags;
60     int ret;
61 
62     /* Initialize the DB handle */
63     ret = db_create(&dbp, NULL, 0);
64     if (ret != 0) {
65 	fprintf(error_file_pointer, "%s: %s\n", program_name,
66 		db_strerror(ret));
67 	return (ret);
68     }
69     /* Point to the memory malloc'd by db_create() */
70     *dbpp = dbp;
71 
72     /* Set up error handling for this database */
73     dbp->set_errfile(dbp, error_file_pointer);
74     dbp->set_errpfx(dbp, program_name);
75 
76     /*
77      * If this is a secondary database, then we want to allow
78      * sorted duplicates.
79      */
80     if (is_secondary) {
81 	ret = dbp->set_flags(dbp, DB_DUPSORT);
82 	if (ret != 0) {
83 	    dbp->err(dbp, ret, "Attempt to set DUPSORT flags failed.",
84 	      file_name);
85 	    return (ret);
86 	}
87     }
88 
89     /* Set the open flags */
90     open_flags = DB_CREATE;    /* Allow database creation */
91 
92     /* Now open the database */
93     ret = dbp->open(dbp,        /* Pointer to the database */
94 		    NULL,       /* Txn pointer */
95 		    file_name,  /* File name */
96 		    NULL,       /* Logical db name */
97 		    DB_BTREE,   /* Database type (using btree) */
98 		    open_flags, /* Open flags */
99 		    0);         /* File mode. Using defaults */
100     if (ret != 0) {
101 	dbp->err(dbp, ret, "Database '%s' open failed.", file_name);
102 	return (ret);
103     }
104 
105     return (0);
106 }
107 
108 /* opens all databases */
109 int
databases_setup(STOCK_DBS * my_stock,const char * program_name,FILE * error_file_pointer)110 databases_setup(STOCK_DBS *my_stock, const char *program_name,
111   FILE *error_file_pointer)
112 {
113     int ret;
114 
115     /* Open the vendor database */
116     ret = open_database(&(my_stock->vendor_dbp),
117       my_stock->vendor_db_name,
118       program_name, error_file_pointer,
119       PRIMARY_DB);
120     if (ret != 0)
121 	/*
122 	 * Error reporting is handled in open_database() so just return
123 	 * the return code.
124 	 */
125 	return (ret);
126 
127     /* Open the inventory database */
128     ret = open_database(&(my_stock->inventory_dbp),
129       my_stock->inventory_db_name,
130       program_name, error_file_pointer,
131       PRIMARY_DB);
132     if (ret != 0)
133 	/*
134 	 * Error reporting is handled in open_database() so just return
135 	 * the return code.
136 	 */
137 	return (ret);
138 
139     /*
140      * Open the itemname secondary database. This is used to
141      * index the product names found in the inventory
142      * database.
143      */
144     ret = open_database(&(my_stock->itemname_sdbp),
145       my_stock->itemname_db_name,
146       program_name, error_file_pointer,
147       SECONDARY_DB);
148     if (ret != 0)
149 	/*
150 	 * Error reporting is handled in open_database() so just return
151 	 * the return code.
152 	 */
153 	return (ret);
154 
155     /*
156      * Associate the itemname db with its primary db
157      * (inventory db).
158      */
159      my_stock->inventory_dbp->associate(
160        my_stock->inventory_dbp,    /* Primary db */
161        NULL,                       /* txn id */
162        my_stock->itemname_sdbp,    /* Secondary db */
163        get_item_name,              /* Secondary key creator */
164        0);                         /* Flags */
165 
166     printf("databases opened successfully\n");
167     return (0);
168 }
169 
170 /* Initializes the STOCK_DBS struct.*/
171 void
initialize_stockdbs(STOCK_DBS * my_stock)172 initialize_stockdbs(STOCK_DBS *my_stock)
173 {
174     my_stock->db_home_dir = DEFAULT_HOMEDIR;
175     my_stock->inventory_dbp = NULL;
176     my_stock->vendor_dbp = NULL;
177     my_stock->itemname_sdbp = NULL;
178     my_stock->inventory_db_name = NULL;
179     my_stock->vendor_db_name = NULL;
180     my_stock->itemname_db_name = NULL;
181 }
182 
183 /* Identify all the files that will hold our databases. */
184 void
set_db_filenames(STOCK_DBS * my_stock)185 set_db_filenames(STOCK_DBS *my_stock)
186 {
187     size_t size;
188 
189     /* Create the Inventory DB file name */
190     size = strlen(my_stock->db_home_dir) + strlen(INVENTORYDB) + 1;
191     my_stock->inventory_db_name = malloc(size);
192     snprintf(my_stock->inventory_db_name, size, "%s%s",
193       my_stock->db_home_dir, INVENTORYDB);
194 
195     /* Create the Vendor DB file name */
196     size = strlen(my_stock->db_home_dir) + strlen(VENDORDB) + 1;
197     my_stock->vendor_db_name = malloc(size);
198     snprintf(my_stock->vendor_db_name, size, "%s%s",
199       my_stock->db_home_dir, VENDORDB);
200 
201     /* Create the itemname DB file name */
202     size = strlen(my_stock->db_home_dir) + strlen(ITEMNAMEDB) + 1;
203     my_stock->itemname_db_name = malloc(size);
204     snprintf(my_stock->itemname_db_name, size, "%s%s",
205       my_stock->db_home_dir, ITEMNAMEDB);
206 
207 }
208 
209 /* Closes all the databases and secondary databases. */
210 int
databases_close(STOCK_DBS * my_stock)211 databases_close(STOCK_DBS *my_stock)
212 {
213     int ret;
214     /*
215      * Note that closing a database automatically flushes its cached data
216      * to disk, so no sync is required here.
217      */
218     if (my_stock->itemname_sdbp != NULL) {
219 	ret = my_stock->itemname_sdbp->close(my_stock->itemname_sdbp, 0);
220 	if (ret != 0)
221 	    fprintf(stderr, "Itemname database close failed: %s\n",
222 	      db_strerror(ret));
223     }
224 
225     if (my_stock->inventory_dbp != NULL) {
226 	ret = my_stock->inventory_dbp->close(my_stock->inventory_dbp, 0);
227 	if (ret != 0)
228 	    fprintf(stderr, "Inventory database close failed: %s\n",
229 	      db_strerror(ret));
230     }
231 
232     if (my_stock->vendor_dbp != NULL) {
233 	ret = my_stock->vendor_dbp->close(my_stock->vendor_dbp, 0);
234 	if (ret != 0)
235 	    fprintf(stderr, "Vendor database close failed: %s\n",
236 	      db_strerror(ret));
237     }
238 
239     printf("databases closed.\n");
240     return (0);
241 }
242