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