hamsterdb Embedded Database 1.1.15
|
00001 00015 #include <iostream> 00016 #include <stdlib.h> /* for exit() */ 00017 #include <ham/hamsterdb.hpp> 00018 00019 #define MAX_DBS 3 00020 00021 #define DBNAME_CUSTOMER 1 00022 #define DBNAME_ORDER 2 00023 #define DBNAME_C2O 3 /* C2O: Customer To Order */ 00024 00025 #define DBIDX_CUSTOMER 0 00026 #define DBIDX_ORDER 1 00027 #define DBIDX_C2O 2 00028 00029 #define MAX_CUSTOMERS 4 00030 #define MAX_ORDERS 8 00031 00032 /* 00033 * a structure for the "customer" database 00034 */ 00035 typedef struct 00036 { 00037 int id; /* customer id - will be the key of the 00038 customer table */ 00039 char name[32]; /* customer name */ 00040 /* ... additional information could follow here */ 00041 } customer_t; 00042 00043 /* 00044 * a structure for the "orders" database 00045 */ 00046 typedef struct 00047 { 00048 int id; /* order id - will be the key of the 00049 order table */ 00050 int customer_id; /* customer id */ 00051 char assignee[32]; /* assigned to whom? */ 00052 /* ... additional information could follow here */ 00053 } order_t; 00054 00055 int 00056 run_demo(void) 00057 { 00058 int i; 00059 ham::env env; /* hamsterdb environment */ 00060 ham::db db[MAX_DBS]; /* hamsterdb database objects */ 00061 ham::cursor cursor[MAX_DBS]; /* a cursor for each database */ 00062 ham::key key, cust_key, ord_key, c2o_key; 00063 ham::record record, cust_record, ord_record, c2o_record; 00064 00065 customer_t customers[MAX_CUSTOMERS]={ 00066 { 1, "Alan Antonov Corp." }, 00067 { 2, "Barry Broke Inc." }, 00068 { 3, "Carl Caesar Lat." }, 00069 { 4, "Doris Dove Brd." } 00070 }; 00071 00072 order_t orders[MAX_ORDERS]={ 00073 { 1, 1, "Joe" }, 00074 { 2, 1, "Tom" }, 00075 { 3, 3, "Joe" }, 00076 { 4, 4, "Tom" }, 00077 { 5, 3, "Ben" }, 00078 { 6, 3, "Ben" }, 00079 { 7, 4, "Chris" }, 00080 { 8, 1, "Ben" } 00081 }; 00082 00083 /* 00084 * create a new database file for the environment 00085 */ 00086 env.create("test.db"); 00087 00088 /* 00089 * then create the two databases in this environment; each database 00090 * has a name - the first is our "customer" database, the second 00091 * is for the "orders"; the third manages our 1:n relation and 00092 * therefore needs to enable duplicate keys 00093 */ 00094 db[DBIDX_CUSTOMER]=env.create_db(DBNAME_CUSTOMER); 00095 db[DBIDX_ORDER] =env.create_db(DBNAME_ORDER); 00096 db[DBIDX_C2O] =env.create_db(DBNAME_C2O, HAM_ENABLE_DUPLICATES); 00097 00098 /* 00099 * create a cursor for each database 00100 */ 00101 for (i=0; i<MAX_DBS; i++) { 00102 cursor[i].create(&db[i]); 00103 } 00104 00105 /* 00106 * insert the customers in the customer table 00107 * 00108 * INSERT INTO customers VALUES (1, "Alan Antonov Corp."); 00109 * INSERT INTO customers VALUES (2, "Barry Broke Inc."); 00110 * etc 00111 */ 00112 for (i=0; i<MAX_CUSTOMERS; i++) { 00113 key.set_size(sizeof(int)); 00114 key.set_data(&customers[i].id); 00115 00116 record.set_size(sizeof(customer_t)); 00117 record.set_data(&customers[i]); 00118 00119 db[0].insert(&key, &record); 00120 } 00121 00122 /* 00123 * and now the orders in the second database; contrary to env1, 00124 * we only store the assignee, not the whole structure 00125 * 00126 * INSERT INTO orders VALUES (1, "Joe"); 00127 * INSERT INTO orders VALUES (2, "Tom"); 00128 */ 00129 for (i=0; i<MAX_ORDERS; i++) { 00130 key.set_size(sizeof(int)); 00131 key.set_data(&orders[i].id); 00132 00133 record.set_size(sizeof(orders[i].assignee)); 00134 record.set_data(orders[i].assignee); 00135 00136 db[1].insert(&key, &record); 00137 } 00138 00139 /* 00140 * and now the 1:n relationships; the flag HAM_DUPLICATE creates 00141 * a duplicate key, if the key already exists 00142 * 00143 * INSERT INTO c2o VALUES (1, 1); 00144 * INSERT INTO c2o VALUES (2, 1); 00145 * etc 00146 */ 00147 for (i=0; i<MAX_ORDERS; i++) { 00148 key.set_size(sizeof(int)); 00149 key.set_data(&orders[i].customer_id); 00150 00151 record.set_size(sizeof(int)); 00152 record.set_data(&orders[i].id); 00153 00154 db[2].insert(&key, &record, HAM_DUPLICATE); 00155 } 00156 00157 /* 00158 * now start the query - we want to dump each customer with his 00159 * orders 00160 * 00161 * loop over the customer; for each customer, loop over the 1:n table 00162 * and pick those orders with the customer id. then load the order 00163 * and print it 00164 * 00165 * the outer loop is similar to 00166 * SELECT * FROM customers WHERE 1; 00167 */ 00168 while (1) { 00169 customer_t *customer; 00170 00171 try { 00172 cursor[0].move_next(&cust_key, &cust_record); 00173 } 00174 catch (ham::error &e) { 00175 /* reached end of the database? */ 00176 if (e.get_errno()==HAM_KEY_NOT_FOUND) 00177 break; 00178 else { 00179 std::cerr << "cursor.move_next() failed: " << e.get_string() 00180 << std::endl; 00181 return (-1); 00182 } 00183 } 00184 00185 customer=(customer_t *)cust_record.get_data(); 00186 00187 /* print the customer id and name */ 00188 std::cout << "customer " << customer->id << " ('" 00189 << customer->name << "')" << std::endl; 00190 00191 /* 00192 * loop over the 1:n table 00193 * 00194 * before we start the loop, we move the cursor to the 00195 * first duplicate key 00196 * 00197 * SELECT * FROM customers, orders, c2o 00198 * WHERE c2o.customer_id=customers.id AND 00199 * c2o.order_id=orders.id; 00200 */ 00201 c2o_key.set_data(&customer->id); 00202 c2o_key.set_size(sizeof(int)); 00203 00204 try { 00205 cursor[2].find(&c2o_key); 00206 } 00207 catch (ham::error &e) { 00208 if (e.get_errno()==HAM_KEY_NOT_FOUND) 00209 continue; 00210 else { 00211 std::cerr << "cursor.find() failed: " << e.get_string() 00212 << std::endl; 00213 return (-1); 00214 } 00215 } 00216 00217 /* get the record of this database entry */ 00218 cursor[2].move(0, &c2o_record); 00219 00220 do { 00221 int order_id; 00222 00223 order_id=*(int *)c2o_record.get_data(); 00224 ord_key.set_data(&order_id); 00225 ord_key.set_size(sizeof(int)); 00226 00227 /* 00228 * load the order 00229 * SELECT * FROM orders WHERE id = order_id; 00230 */ 00231 ord_record=db[1].find(&ord_key); 00232 00233 std::cout << " order: " << order_id << " (assigned to " 00234 << (char *)ord_record.get_data() << ")" << std::endl; 00235 00236 /* 00237 * the flag HAM_ONLY_DUPLICATES restricts the cursor 00238 * movement to the duplicate list. 00239 */ 00240 try { 00241 cursor[2].move(&c2o_key, &c2o_record, 00242 HAM_CURSOR_NEXT|HAM_ONLY_DUPLICATES); 00243 } 00244 catch (ham::error &e) { 00245 /* reached end of the database? */ 00246 if (e.get_errno()==HAM_KEY_NOT_FOUND) 00247 break; 00248 else { 00249 std::cerr << "cursor.move() failed: " << e.get_string() 00250 << std::endl; 00251 return (-1); 00252 } 00253 } 00254 00255 } while(1); 00256 } 00257 00258 /* 00259 * we're done! no need to cleanup, the destructors will prevent memory 00260 * leaks 00261 */ 00262 00263 std::cout << "success!" << std::endl; 00264 return (0); 00265 } 00266 00267 int 00268 main(int argc, char **argv) 00269 { 00270 try { 00271 return (run_demo()); 00272 } 00273 catch (ham::error &e) { 00274 std::cerr << "run_demo() failed with unexpected error " 00275 << e.get_errno() << " ('" 00276 << e.get_string() << "')" << std::endl; 00277 return (-1); 00278 } 00279 }