hamsterdb Embedded Database  2.1.7
env3.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2014 Christoph Rupp (chris@crupp.de).
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
21 #include <iostream>
22 #include <stdlib.h> /* for exit() */
23 #include <ham/hamsterdb.hpp>
24 
25 #define MAX_DBS 3
26 
27 #define DBNAME_CUSTOMER 1
28 #define DBNAME_ORDER 2
29 #define DBNAME_C2O 3 /* C2O: Customer To Order */
30 
31 #define DBIDX_CUSTOMER 0
32 #define DBIDX_ORDER 1
33 #define DBIDX_C2O 2
34 
35 #define MAX_CUSTOMERS 4
36 #define MAX_ORDERS 8
37 
38 /* A structure for the "customer" database */
39 typedef struct {
40  ham_u32_t id; /* customer id; will be the key of the customer table */
41  char name[32]; /* customer name */
42  /* ... additional information could follow here */
43 } customer_t;
44 
45 /* A structure for the "orders" database */
46 typedef struct {
47  ham_u32_t id; /* order id; will be the key of the order table */
48  ham_u32_t customer_id;/* customer id */
49  char assignee[32]; /* assigned to whom? */
50  /* ... additional information could follow here */
51 } order_t;
52 
53 int
55  int i;
56  hamsterdb::env env; /* hamsterdb environment */
57  hamsterdb::db db[MAX_DBS]; /* hamsterdb database objects */
58  hamsterdb::cursor cursor[MAX_DBS]; /* a cursor for each database */
59  hamsterdb::key key, cust_key, ord_key, c2o_key;
60  hamsterdb::record record, cust_record, ord_record, c2o_record;
61 
62  customer_t customers[MAX_CUSTOMERS] = {
63  { 1, "Alan Antonov Corp." },
64  { 2, "Barry Broke Inc." },
65  { 3, "Carl Caesar Lat." },
66  { 4, "Doris Dove Brd." }
67  };
68 
69  order_t orders[MAX_ORDERS] = {
70  { 1, 1, "Joe" },
71  { 2, 1, "Tom" },
72  { 3, 3, "Joe" },
73  { 4, 4, "Tom" },
74  { 5, 3, "Ben" },
75  { 6, 3, "Ben" },
76  { 7, 4, "Chris" },
77  { 8, 1, "Ben" }
78  };
79 
80  /* Create a new hamsterdb environment */
81  env.create("test.db");
82 
83  /*
84  * Then create the two Databases in this Environment; each Database
85  * has a name - the first is our "customer" Database, the second
86  * is for the "orders"; the third manages our 1:n relation and
87  * therefore needs to enable duplicate keys
88  *
89  * All database keys are uint32 types.
90  */
91  ham_parameter_t params[] = {
93  {0, }
94  };
95 
96  /*
97  * The "mapping" between customers and orders stores uint32 customer IDs
98  * as a key and uint32 order IDs as a record
99  */
100  ham_parameter_t c2o_params[] = {
102  {HAM_PARAM_RECORD_SIZE, sizeof(ham_u32_t)},
103  {0, }
104  };
105 
106  db[DBIDX_CUSTOMER] = env.create_db(DBNAME_CUSTOMER, 0, &params[0]);
107  db[DBIDX_ORDER] = env.create_db(DBNAME_ORDER, 0, &params[0]);
108  db[DBIDX_C2O] = env.create_db(DBNAME_C2O,
109  HAM_ENABLE_DUPLICATE_KEYS, &c2o_params[0]);
110 
111  /* Create a cursor for each database */
112  for (i = 0; i < MAX_DBS; i++)
113  cursor[i].create(&db[i]);
114 
115  /*
116  * Insert the customers in the customer table
117  *
118  * INSERT INTO customers VALUES (1, "Alan Antonov Corp.");
119  * INSERT INTO customers VALUES (2, "Barry Broke Inc.");
120  * etc
121  */
122  for (i = 0; i < MAX_CUSTOMERS; i++) {
123  key.set_size(sizeof(int));
124  key.set_data(&customers[i].id);
125 
126  record.set_size(sizeof(customer_t));
127  record.set_data(&customers[i]);
128 
129  db[0].insert(&key, &record);
130  }
131 
132  /*
133  * And now the orders in the second database; contrary to env1,
134  * we only store the assignee, not the whole structure
135  *
136  * INSERT INTO orders VALUES (1, "Joe");
137  * INSERT INTO orders VALUES (2, "Tom");
138  */
139  for (i = 0; i < MAX_ORDERS; i++) {
140  key.set_size(sizeof(int));
141  key.set_data(&orders[i].id);
142 
143  record.set_size(sizeof(orders[i].assignee));
144  record.set_data(orders[i].assignee);
145 
146  db[1].insert(&key, &record);
147  }
148 
149  /*
150  * And now the 1:n relationships; the flag HAM_DUPLICATE creates
151  * a duplicate key, if the key already exists
152  *
153  * INSERT INTO c2o VALUES (1, 1);
154  * INSERT INTO c2o VALUES (2, 1);
155  * etc
156  */
157  for (i = 0; i < MAX_ORDERS; i++) {
158  key.set_size(sizeof(int));
159  key.set_data(&orders[i].customer_id);
160 
161  record.set_size(sizeof(int));
162  record.set_data(&orders[i].id);
163 
164  db[2].insert(&key, &record, HAM_DUPLICATE);
165  }
166 
167  /*
168  * Now start the query - we want to dump each customer with his
169  * orders
170  *
171  * loop over the customer; for each customer, loop over the 1:n table
172  * and pick those orders with the customer id. then load the order
173  * and print it
174  *
175  * the outer loop is similar to
176  * SELECT * FROM customers WHERE 1;
177  */
178  while (1) {
179  customer_t *customer;
180 
181  try {
182  cursor[0].move_next(&cust_key, &cust_record);
183  }
184  catch (hamsterdb::error &e) {
185  /* reached end of the database? */
186  if (e.get_errno() == HAM_KEY_NOT_FOUND)
187  break;
188  else {
189  std::cerr << "cursor.move_next() failed: " << e.get_string()
190  << std::endl;
191  return (-1);
192  }
193  }
194 
195  customer = (customer_t *)cust_record.get_data();
196 
197  /* print the customer id and name */
198  std::cout << "customer " << customer->id << " ('"
199  << customer->name << "')" << std::endl;
200 
201  /*
202  * Loop over the 1:n table
203  *
204  * before we start the loop, we move the cursor to the
205  * first duplicate key
206  *
207  * SELECT * FROM customers, orders, c2o
208  * WHERE c2o.customer_id=customers.id AND
209  * c2o.order_id=orders.id;
210  */
211  c2o_key.set_data(&customer->id);
212  c2o_key.set_size(sizeof(int));
213 
214  try {
215  cursor[2].find(&c2o_key);
216  }
217  catch (hamsterdb::error &e) {
218  if (e.get_errno() == HAM_KEY_NOT_FOUND)
219  continue;
220  else {
221  std::cerr << "cursor.find() failed: " << e.get_string()
222  << std::endl;
223  return (-1);
224  }
225  }
226 
227  /* get the record of this database entry */
228  cursor[2].move(0, &c2o_record);
229 
230  do {
231  int order_id;
232 
233  order_id = *(int *)c2o_record.get_data();
234  ord_key.set_data(&order_id);
235  ord_key.set_size(sizeof(int));
236 
237  /*
238  * Load the order
239  * SELECT * FROM orders WHERE id = order_id;
240  */
241  ord_record = db[1].find(&ord_key);
242 
243  std::cout << " order: " << order_id << " (assigned to "
244  << (char *)ord_record.get_data() << ")" << std::endl;
245 
246  /*
247  * the flag HAM_ONLY_DUPLICATES restricts the cursor
248  * movement to the duplicate list.
249  */
250  try {
251  cursor[2].move(&c2o_key, &c2o_record,
253  }
254  catch (hamsterdb::error &e) {
255  /* reached end of the database? */
256  if (e.get_errno() == HAM_KEY_NOT_FOUND)
257  break;
258  else {
259  std::cerr << "cursor.move() failed: " << e.get_string()
260  << std::endl;
261  return (-1);
262  }
263  }
264 
265  } while (1);
266  }
267 
268  /*
269  * we're done! no need to cleanup, the destructors will prevent memory
270  * leaks
271  */
272  std::cout << "success!" << std::endl;
273  return (0);
274 }
275 
276 int
277 main(int argc, char **argv)
278 {
279  try {
280  return (run_demo());
281  }
282  catch (hamsterdb::error &e) {
283  std::cerr << "run_demo() failed with unexpected error "
284  << e.get_errno() << " ('"
285  << e.get_string() << "')" << std::endl;
286  return (-1);
287  }
288 }