1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2004,2008 Oracle.  All rights reserved.
5 */
6
7#include "gettingstarted_common.h"
8
9int 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 */
16int
17get_item_name(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey)
18{
19    u_int offset;
20
21    dbp = NULL;                         /* Not needed, unused. */
22    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 */
51int
52open_database(DB **dbpp, const char *file_name,
53  const char *program_name, FILE *error_file_pointer,
54  int is_secondary)
55{
56    DB *dbp;    /* For convenience */
57    u_int32_t open_flags;
58    int ret;
59
60    /* Initialize the DB handle */
61    ret = db_create(&dbp, NULL, 0);
62    if (ret != 0) {
63	fprintf(error_file_pointer, "%s: %s\n", program_name,
64		db_strerror(ret));
65	return (ret);
66    }
67    /* Point to the memory malloc'd by db_create() */
68    *dbpp = dbp;
69
70    /* Set up error handling for this database */
71    dbp->set_errfile(dbp, error_file_pointer);
72    dbp->set_errpfx(dbp, program_name);
73
74    /*
75     * If this is a secondary database, then we want to allow
76     * sorted duplicates.
77     */
78    if (is_secondary) {
79	ret = dbp->set_flags(dbp, DB_DUPSORT);
80	if (ret != 0) {
81	    dbp->err(dbp, ret, "Attempt to set DUPSORT flags failed.",
82	      file_name);
83	    return (ret);
84	}
85    }
86
87    /* Set the open flags */
88    open_flags = DB_CREATE;    /* Allow database creation */
89
90    /* Now open the database */
91    ret = dbp->open(dbp,        /* Pointer to the database */
92		    NULL,       /* Txn pointer */
93		    file_name,  /* File name */
94		    NULL,       /* Logical db name */
95		    DB_BTREE,   /* Database type (using btree) */
96		    open_flags, /* Open flags */
97		    0);         /* File mode. Using defaults */
98    if (ret != 0) {
99	dbp->err(dbp, ret, "Database '%s' open failed.", file_name);
100	return (ret);
101    }
102
103    return (0);
104}
105
106/* opens all databases */
107int
108databases_setup(STOCK_DBS *my_stock, const char *program_name,
109  FILE *error_file_pointer)
110{
111    int ret;
112
113    /* Open the vendor database */
114    ret = open_database(&(my_stock->vendor_dbp),
115      my_stock->vendor_db_name,
116      program_name, error_file_pointer,
117      PRIMARY_DB);
118    if (ret != 0)
119	/*
120	 * Error reporting is handled in open_database() so just return
121	 * the return code.
122	 */
123	return (ret);
124
125    /* Open the inventory database */
126    ret = open_database(&(my_stock->inventory_dbp),
127      my_stock->inventory_db_name,
128      program_name, error_file_pointer,
129      PRIMARY_DB);
130    if (ret != 0)
131	/*
132	 * Error reporting is handled in open_database() so just return
133	 * the return code.
134	 */
135	return (ret);
136
137    /*
138     * Open the itemname secondary database. This is used to
139     * index the product names found in the inventory
140     * database.
141     */
142    ret = open_database(&(my_stock->itemname_sdbp),
143      my_stock->itemname_db_name,
144      program_name, error_file_pointer,
145      SECONDARY_DB);
146    if (ret != 0)
147	/*
148	 * Error reporting is handled in open_database() so just return
149	 * the return code.
150	 */
151	return (0);
152
153    /*
154     * Associate the itemname db with its primary db
155     * (inventory db).
156     */
157     my_stock->inventory_dbp->associate(
158       my_stock->inventory_dbp,    /* Primary db */
159       NULL,                       /* txn id */
160       my_stock->itemname_sdbp,    /* Secondary db */
161       get_item_name,              /* Secondary key creator */
162       0);                         /* Flags */
163
164    printf("databases opened successfully\n");
165    return (0);
166}
167
168/* Initializes the STOCK_DBS struct.*/
169void
170initialize_stockdbs(STOCK_DBS *my_stock)
171{
172    my_stock->db_home_dir = DEFAULT_HOMEDIR;
173    my_stock->inventory_dbp = NULL;
174    my_stock->vendor_dbp = NULL;
175    my_stock->itemname_sdbp = NULL;
176    my_stock->vendor_db_name = NULL;
177    my_stock->inventory_db_name = NULL;
178    my_stock->itemname_db_name = NULL;
179}
180
181/* Identify all the files that will hold our databases. */
182void
183set_db_filenames(STOCK_DBS *my_stock)
184{
185    size_t size;
186
187    /* Create the Inventory DB file name */
188    size = strlen(my_stock->db_home_dir) + strlen(INVENTORYDB) + 1;
189    my_stock->inventory_db_name = malloc(size);
190    snprintf(my_stock->inventory_db_name, size, "%s%s",
191      my_stock->db_home_dir, INVENTORYDB);
192
193    /* Create the Vendor DB file name */
194    size = strlen(my_stock->db_home_dir) + strlen(VENDORDB) + 1;
195    my_stock->vendor_db_name = malloc(size);
196    snprintf(my_stock->vendor_db_name, size, "%s%s",
197      my_stock->db_home_dir, VENDORDB);
198
199    /* Create the itemname DB file name */
200    size = strlen(my_stock->db_home_dir) + strlen(ITEMNAMEDB) + 1;
201    my_stock->itemname_db_name = malloc(size);
202    snprintf(my_stock->itemname_db_name, size, "%s%s",
203      my_stock->db_home_dir, ITEMNAMEDB);
204
205}
206
207/* Closes all the databases and secondary databases. */
208int
209databases_close(STOCK_DBS *my_stock)
210{
211    int ret;
212    /*
213     * Note that closing a database automatically flushes its cached data
214     * to disk, so no sync is required here.
215     */
216    if (my_stock->itemname_sdbp != NULL) {
217	ret = my_stock->itemname_sdbp->close(my_stock->itemname_sdbp, 0);
218	if (ret != 0)
219	    fprintf(stderr, "Itemname database close failed: %s\n",
220	      db_strerror(ret));
221    }
222
223    if (my_stock->inventory_dbp != NULL) {
224	ret = my_stock->inventory_dbp->close(my_stock->inventory_dbp, 0);
225	if (ret != 0)
226	    fprintf(stderr, "Inventory database close failed: %s\n",
227	      db_strerror(ret));
228    }
229
230    if (my_stock->vendor_dbp != NULL) {
231	ret = my_stock->vendor_dbp->close(my_stock->vendor_dbp, 0);
232	if (ret != 0)
233	    fprintf(stderr, "Vendor database close failed: %s\n",
234	      db_strerror(ret));
235    }
236
237    printf("databases closed.\n");
238    return (0);
239}
240