hamsterdb Embedded Database 1.1.14

env3.cpp

Go to the documentation of this file.
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 }