upscaledb  2.2.1
env3.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2016 Christoph Rupp (chris@crupp.de).
3  * All Rights Reserved.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * See the file COPYING for License information.
16  */
17 
22 #include <iostream>
23 #include <stdlib.h> /* for exit() */
24 #include <ups/upscaledb.hpp>
25 
26 #define MAX_DBS 3
27 
28 #define DBNAME_CUSTOMER 1
29 #define DBNAME_ORDER 2
30 #define DBNAME_C2O 3 /* C2O: Customer To Order */
31 
32 #define DBIDX_CUSTOMER 0
33 #define DBIDX_ORDER 1
34 #define DBIDX_C2O 2
35 
36 #define MAX_CUSTOMERS 4
37 #define MAX_ORDERS 8
38 
39 /* A structure for the "customer" database */
40 typedef struct {
41  uint32_t id; /* customer id; will be the key of the customer table */
42  char name[32]; /* customer name */
43  /* ... additional information could follow here */
44 } customer_t;
45 
46 /* A structure for the "orders" database */
47 typedef struct {
48  uint32_t id; /* order id; will be the key of the order table */
49  uint32_t customer_id;/* customer id */
50  char assignee[32]; /* assigned to whom? */
51  /* ... additional information could follow here */
52 } order_t;
53 
54 int
56  int i;
57  upscaledb::env env; /* upscaledb environment */
58  upscaledb::db db[MAX_DBS]; /* upscaledb database objects */
59  upscaledb::cursor cursor[MAX_DBS]; /* a cursor for each database */
60  upscaledb::key key, cust_key, ord_key, c2o_key;
61  upscaledb::record record, cust_record, ord_record, c2o_record;
62 
63  customer_t customers[MAX_CUSTOMERS] = {
64  { 1, "Alan Antonov Corp." },
65  { 2, "Barry Broke Inc." },
66  { 3, "Carl Caesar Lat." },
67  { 4, "Doris Dove Brd." }
68  };
69 
70  order_t orders[MAX_ORDERS] = {
71  { 1, 1, "Joe" },
72  { 2, 1, "Tom" },
73  { 3, 3, "Joe" },
74  { 4, 4, "Tom" },
75  { 5, 3, "Ben" },
76  { 6, 3, "Ben" },
77  { 7, 4, "Chris" },
78  { 8, 1, "Ben" }
79  };
80 
81  /* Create a new upscaledb environment */
82  env.create("test.db");
83 
84  /*
85  * Then create the two Databases in this Environment; each Database
86  * has a name - the first is our "customer" Database, the second
87  * is for the "orders"; the third manages our 1:n relation and
88  * therefore needs to enable duplicate keys
89  *
90  * All database keys are uint32 types.
91  */
92  ups_parameter_t params[] = {
94  {0, }
95  };
96 
97  /*
98  * The "mapping" between customers and orders stores uint32 customer IDs
99  * as a key and uint32 order IDs as a record
100  */
101  ups_parameter_t c2o_params[] = {
103  {UPS_PARAM_RECORD_SIZE, sizeof(uint32_t)},
104  {0, }
105  };
106 
107  db[DBIDX_CUSTOMER] = env.create_db(DBNAME_CUSTOMER, 0, &params[0]);
108  db[DBIDX_ORDER] = env.create_db(DBNAME_ORDER, 0, &params[0]);
109  db[DBIDX_C2O] = env.create_db(DBNAME_C2O,
110  UPS_ENABLE_DUPLICATE_KEYS, &c2o_params[0]);
111 
112  /* Create a cursor for each database */
113  for (i = 0; i < MAX_DBS; i++)
114  cursor[i].create(&db[i]);
115 
116  /*
117  * Insert the customers in the customer table
118  *
119  * INSERT INTO customers VALUES (1, "Alan Antonov Corp.");
120  * INSERT INTO customers VALUES (2, "Barry Broke Inc.");
121  * etc
122  */
123  for (i = 0; i < MAX_CUSTOMERS; i++) {
124  key.set_size(sizeof(int));
125  key.set_data(&customers[i].id);
126 
127  record.set_size(sizeof(customer_t));
128  record.set_data(&customers[i]);
129 
130  db[0].insert(&key, &record);
131  }
132 
133  /*
134  * And now the orders in the second database; contrary to env1,
135  * we only store the assignee, not the whole structure
136  *
137  * INSERT INTO orders VALUES (1, "Joe");
138  * INSERT INTO orders VALUES (2, "Tom");
139  */
140  for (i = 0; i < MAX_ORDERS; i++) {
141  key.set_size(sizeof(int));
142  key.set_data(&orders[i].id);
143 
144  record.set_size(sizeof(orders[i].assignee));
145  record.set_data(orders[i].assignee);
146 
147  db[1].insert(&key, &record);
148  }
149 
150  /*
151  * And now the 1:n relationships; the flag UPS_DUPLICATE creates
152  * a duplicate key, if the key already exists
153  *
154  * INSERT INTO c2o VALUES (1, 1);
155  * INSERT INTO c2o VALUES (2, 1);
156  * etc
157  */
158  for (i = 0; i < MAX_ORDERS; i++) {
159  key.set_size(sizeof(int));
160  key.set_data(&orders[i].customer_id);
161 
162  record.set_size(sizeof(int));
163  record.set_data(&orders[i].id);
164 
165  db[2].insert(&key, &record, UPS_DUPLICATE);
166  }
167 
168  /*
169  * Now start the query - we want to dump each customer with his
170  * orders
171  *
172  * loop over the customer; for each customer, loop over the 1:n table
173  * and pick those orders with the customer id. then load the order
174  * and print it
175  *
176  * the outer loop is similar to
177  * SELECT * FROM customers WHERE 1;
178  */
179  while (1) {
180  customer_t *customer;
181 
182  try {
183  cursor[0].move_next(&cust_key, &cust_record);
184  }
185  catch (upscaledb::error &e) {
186  /* reached end of the database? */
187  if (e.get_errno() == UPS_KEY_NOT_FOUND)
188  break;
189  else {
190  std::cerr << "cursor.move_next() failed: " << e.get_string()
191  << std::endl;
192  return (-1);
193  }
194  }
195 
196  customer = (customer_t *)cust_record.get_data();
197 
198  /* print the customer id and name */
199  std::cout << "customer " << customer->id << " ('"
200  << customer->name << "')" << std::endl;
201 
202  /*
203  * Loop over the 1:n table
204  *
205  * before we start the loop, we move the cursor to the
206  * first duplicate key
207  *
208  * SELECT * FROM customers, orders, c2o
209  * WHERE c2o.customer_id=customers.id AND
210  * c2o.order_id=orders.id;
211  */
212  c2o_key.set_data(&customer->id);
213  c2o_key.set_size(sizeof(int));
214 
215  try {
216  cursor[2].find(&c2o_key);
217  }
218  catch (upscaledb::error &e) {
219  if (e.get_errno() == UPS_KEY_NOT_FOUND)
220  continue;
221  else {
222  std::cerr << "cursor.find() failed: " << e.get_string()
223  << std::endl;
224  return (-1);
225  }
226  }
227 
228  /* get the record of this database entry */
229  cursor[2].move(0, &c2o_record);
230 
231  do {
232  int order_id;
233 
234  order_id = *(int *)c2o_record.get_data();
235  ord_key.set_data(&order_id);
236  ord_key.set_size(sizeof(int));
237 
238  /*
239  * Load the order
240  * SELECT * FROM orders WHERE id = order_id;
241  */
242  ord_record = db[1].find(&ord_key);
243 
244  std::cout << " order: " << order_id << " (assigned to "
245  << (char *)ord_record.get_data() << ")" << std::endl;
246 
247  /*
248  * the flag UPS_ONLY_DUPLICATES restricts the cursor
249  * movement to the duplicate list.
250  */
251  try {
252  cursor[2].move(&c2o_key, &c2o_record,
254  }
255  catch (upscaledb::error &e) {
256  /* reached end of the database? */
257  if (e.get_errno() == UPS_KEY_NOT_FOUND)
258  break;
259  else {
260  std::cerr << "cursor.move() failed: " << e.get_string()
261  << std::endl;
262  return (-1);
263  }
264  }
265 
266  } while (1);
267  }
268 
269  /*
270  * we're done! no need to cleanup, the destructors will prevent memory
271  * leaks
272  */
273  std::cout << "success!" << std::endl;
274  return (0);
275 }
276 
277 int
278 main(int argc, char **argv)
279 {
280  try {
281  return (run_demo());
282  }
283  catch (upscaledb::error &e) {
284  std::cerr << "run_demo() failed with unexpected error "
285  << e.get_errno() << " ('"
286  << e.get_string() << "')" << std::endl;
287  return (-1);
288  }
289 }
int main(int argc, char **argv)
Definition: env3.cpp:278
void * get_data() const
Definition: upscaledb.hpp:187
void create(const char *filename, uint32_t flags=0, uint32_t mode=0644, const ups_parameter_t *param=0)
Definition: upscaledb.hpp:620
void set_size(uint32_t size)
Definition: upscaledb.hpp:202
ups_status_t get_errno() const
Definition: upscaledb.hpp:74
#define DBIDX_C2O
Definition: env3.cpp:34
#define UPS_TYPE_UINT32
Definition: upscaledb.h:322
unsigned int uint32_t
Definition: msstdint.h:85
#define MAX_ORDERS
Definition: env3.cpp:37
#define DBNAME_C2O
Definition: env3.cpp:30
db create_db(uint16_t name, uint32_t flags=0, const ups_parameter_t *param=0)
Definition: upscaledb.hpp:643
#define DBIDX_ORDER
Definition: env3.cpp:33
char name[32]
Definition: env1.c:45
#define UPS_PARAM_RECORD_SIZE
Definition: upscaledb.h:1725
#define MAX_DBS
Definition: env3.cpp:26
uint32_t id
Definition: env1.c:44
void insert(txn *t, key *k, record *r, uint32_t flags=0)
Definition: upscaledb.hpp:358
#define UPS_CURSOR_NEXT
Definition: upscaledb.h:2051
const char * get_string() const
Definition: upscaledb.hpp:79
void move(key *k, record *r, uint32_t flags=0)
Definition: upscaledb.hpp:491
void move_next(key *k=0, record *r=0)
Definition: upscaledb.hpp:509
#define UPS_ONLY_DUPLICATES
Definition: upscaledb.h:2060
void set_size(uint16_t size)
Definition: upscaledb.hpp:130
int run_demo()
Definition: env3.cpp:55
#define DBNAME_CUSTOMER
Definition: env3.cpp:28
#define UPS_ENABLE_DUPLICATE_KEYS
Definition: upscaledb.h:1309
#define DBNAME_ORDER
Definition: env3.cpp:29
#define MAX_CUSTOMERS
Definition: env3.cpp:36
void set_data(void *data)
Definition: upscaledb.hpp:192
#define DBIDX_CUSTOMER
Definition: env3.cpp:32
record find(txn *t, key *k, uint32_t flags=0)
Definition: upscaledb.hpp:334
#define UPS_DUPLICATE
Definition: upscaledb.h:1566
Definition: env1.c:50
void set_data(void *data)
Definition: upscaledb.hpp:120
void find(key *k, record *r=0, uint32_t flags=0)
Definition: upscaledb.hpp:527
#define UPS_PARAM_KEY_TYPE
Definition: upscaledb.h:1710
#define UPS_KEY_NOT_FOUND
Definition: upscaledb.h:361