hamsterdb Embedded Database  2.1.7
env2.c
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 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h> /* for exit() */
26 #include <ham/hamsterdb.h>
27 
28 void
29 error(const char *foo, ham_status_t st) {
30  printf("%s() returned error %d: %s\n", foo, st, ham_strerror(st));
31  exit(-1);
32 }
33 
34 #define MAX_DBS 3
35 
36 #define DBNAME_CUSTOMER 1
37 #define DBNAME_ORDER 2
38 #define DBNAME_C2O 3 /* C2O: Customer To Order */
39 
40 #define DBIDX_CUSTOMER 0
41 #define DBIDX_ORDER 1
42 #define DBIDX_C2O 2
43 
44 #define MAX_CUSTOMERS 4
45 #define MAX_ORDERS 8
46 
47 /* A structure for the "customer" database */
48 typedef struct {
49  ham_u32_t id; /* customer id; will be the key of the customer table */
50  char name[32]; /* customer name */
51  /* ... additional information could follow here */
52 } customer_t;
53 
54 /* A structure for the "orders" database */
55 typedef struct {
56  ham_u32_t id; /* order id; will be the key of the order table */
57  ham_u32_t customer_id;/* customer id */
58  char assignee[32]; /* assigned to whom? */
59  /* ... additional information could follow here */
60 } order_t;
61 
62 int
63 main(int argc, char **argv) {
64  int i;
65  ham_status_t st; /* status variable */
66  ham_db_t *db[MAX_DBS]; /* hamsterdb database objects */
67  ham_env_t *env; /* hamsterdb environment */
68  ham_cursor_t *cursor[MAX_DBS]; /* a cursor for each database */
69  ham_key_t key = {0};
70  ham_key_t cust_key = {0};
71  ham_key_t ord_key = {0};
72  ham_key_t c2o_key = {0};
73  ham_record_t record = {0};
74  ham_record_t cust_record = {0};
75  ham_record_t ord_record = {0};
76  ham_record_t c2o_record = {0};
77 
78  ham_parameter_t params[] = {
80  {0, }
81  };
82 
83  ham_parameter_t c2o_params[] = {
86  {0, }
87  };
88 
89  customer_t customers[MAX_CUSTOMERS] = {
90  { 1, "Alan Antonov Corp." },
91  { 2, "Barry Broke Inc." },
92  { 3, "Carl Caesar Lat." },
93  { 4, "Doris Dove Brd." }
94  };
95 
96  order_t orders[MAX_ORDERS] = {
97  { 1, 1, "Joe" },
98  { 2, 1, "Tom" },
99  { 3, 3, "Joe" },
100  { 4, 4, "Tom" },
101  { 5, 3, "Ben" },
102  { 6, 3, "Ben" },
103  { 7, 4, "Chris" },
104  { 8, 1, "Ben" }
105  };
106 
107  /* Now create a new database file for the Environment */
108  st = ham_env_create(&env, "test.db", 0, 0664, 0);
109  if (st != HAM_SUCCESS)
110  error("ham_env_create", st);
111 
112  /*
113  * Then create the two Databases in this Environment; each Database
114  * has a name - the first is our "customer" Database, the second
115  * is for the "orders"; the third manages our 1:n relation and
116  * therefore needs to enable duplicate keys
117  */
119  0, &params[0]);
120  if (st != HAM_SUCCESS)
121  error("ham_env_create_db(customer)", st);
122  st = ham_env_create_db(env, &db[DBIDX_ORDER], DBNAME_ORDER, 0, &params[0]);
123  if (st != HAM_SUCCESS)
124  error("ham_env_create_db(order)", st);
125  st = ham_env_create_db(env, &db[DBIDX_C2O], DBNAME_C2O,
126  HAM_ENABLE_DUPLICATE_KEYS, &c2o_params[0]);
127  if (st != HAM_SUCCESS)
128  error("ham_env_create_db(c2o)", st);
129 
130  /* Create a Cursor for each Database */
131  for (i = 0; i < MAX_DBS; i++) {
132  st = ham_cursor_create(&cursor[i], db[i], 0, 0);
133  if (st != HAM_SUCCESS)
134  error("ham_cursor_create" , st);
135  }
136 
137  /*
138  * Insert the customers in the customer table
139  *
140  * INSERT INTO customers VALUES (1, "Alan Antonov Corp.");
141  * INSERT INTO customers VALUES (2, "Barry Broke Inc.");
142  * etc
143  */
144  for (i = 0; i < MAX_CUSTOMERS; i++) {
145  key.size = sizeof(int);
146  key.data = &customers[i].id;
147 
148  record.size = sizeof(customer_t);
149  record.data = &customers[i];
150 
151  st = ham_db_insert(db[0], 0, &key, &record, 0);
152  if (st != HAM_SUCCESS)
153  error("ham_db_insert (customer)", st);
154  }
155 
156  /*
157  * And now the orders in the second Database; contrary to env1,
158  * we only store the assignee, not the whole structure
159  *
160  * INSERT INTO orders VALUES (1, "Joe");
161  * INSERT INTO orders VALUES (2, "Tom");
162  */
163  for (i = 0; i < MAX_ORDERS; i++) {
164  key.size = sizeof(int);
165  key.data = &orders[i].id;
166 
167  record.size = sizeof(orders[i].assignee);
168  record.data = orders[i].assignee;
169 
170  st = ham_db_insert(db[1], 0, &key, &record, 0);
171  if (st != HAM_SUCCESS)
172  error("ham_db_insert (order)", st);
173  }
174 
175  /*
176  * And now the 1:n relationships; the flag HAM_DUPLICATE creates
177  * a duplicate key, if the key already exists
178  *
179  * INSERT INTO c2o VALUES (1, 1);
180  * INSERT INTO c2o VALUES (2, 1);
181  * etc
182  */
183  for (i = 0; i < MAX_ORDERS; i++) {
184  key.size = sizeof(int);
185  key.data = &orders[i].customer_id;
186 
187  record.size = sizeof(int);
188  record.data = &orders[i].id;
189 
190  st = ham_db_insert(db[2], 0, &key, &record, HAM_DUPLICATE);
191  if (st != HAM_SUCCESS)
192  error("ham_db_insert(c2o)", st);
193  }
194 
195  /*
196  * Now start the query - we want to dump each customer with his
197  * orders
198  *
199  * loop over the customer; for each customer, loop over the 1:n table
200  * and pick those orders with the customer id. then load the order
201  * and print it
202  *
203  * the outer loop is similar to:
204  * SELECT * FROM customers WHERE 1;
205  */
206  while (1) {
207  customer_t *customer;
208 
209  st = ham_cursor_move(cursor[0], &cust_key, &cust_record, HAM_CURSOR_NEXT);
210  if (st != HAM_SUCCESS) {
211  /* reached end of the database? */
212  if (st == HAM_KEY_NOT_FOUND)
213  break;
214  else
215  error("ham_cursor_next(customer)", st);
216  }
217 
218  customer = (customer_t *)cust_record.data;
219 
220  /* print the customer id and name */
221  printf("customer %d ('%s')\n", customer->id, customer->name);
222 
223  /*
224  * loop over the 1:n table
225  *
226  * before we start the loop, we move the cursor to the
227  * first duplicate key
228  *
229  * SELECT * FROM customers, orders, c2o
230  * WHERE c2o.customer_id=customers.id AND
231  * c2o.order_id=orders.id;
232  */
233  c2o_key.data = &customer->id;
234  c2o_key.size = sizeof(int);
235  st = ham_cursor_find(cursor[2], &c2o_key, 0, 0);
236  if (st != HAM_SUCCESS) {
237  if (st == HAM_KEY_NOT_FOUND)
238  continue;
239  error("ham_cursor_find(c2o)", st);
240  }
241  st = ham_cursor_move(cursor[2], 0, &c2o_record, 0);
242  if (st != HAM_SUCCESS)
243  error("ham_cursor_move(c2o)", st);
244 
245  do {
246  int order_id;
247 
248  order_id = *(int *)c2o_record.data;
249  ord_key.data = &order_id;
250  ord_key.size = sizeof(int);
251 
252  /*
253  * load the order
254  * SELECT * FROM orders WHERE id = order_id;
255  */
256  st = ham_db_find(db[1], 0, &ord_key, &ord_record, 0);
257  if (st != HAM_SUCCESS)
258  error("ham_db_find(order)", st);
259 
260  printf(" order: %d (assigned to %s)\n",
261  order_id, (char *)ord_record.data);
262 
263  /*
264  * The flag HAM_ONLY_DUPLICATES restricts the cursor
265  * movement to the duplicate list.
266  */
267  st = ham_cursor_move(cursor[2], &c2o_key,
268  &c2o_record, HAM_CURSOR_NEXT|HAM_ONLY_DUPLICATES);
269  if (st != HAM_SUCCESS) {
270  /* reached end of the database? */
271  if (st == HAM_KEY_NOT_FOUND)
272  break;
273  else
274  error("ham_cursor_next(c2o)", st);
275  }
276  } while (1);
277  }
278 
279  /*
280  * Now close the Environment handle; the flag
281  * HAM_AUTO_CLEANUP will automatically close all Databases and
282  * Cursors
283  */
284  st = ham_env_close(env, HAM_AUTO_CLEANUP);
285  if (st != HAM_SUCCESS)
286  error("ham_env_close", st);
287 
288  printf("success!\n");
289  return (0);
290 }