1<?xml version="1.0" encoding="UTF-8" standalone="no"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <title>Using C Structures with DB</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 9 <link rel="home" href="index.html" title="Getting Started with Berkeley DB" /> 10 <link rel="up" href="DBEntry.html" title="Chapter 3. Database Records" /> 11 <link rel="previous" href="usingDbt.html" title="Reading and Writing Database Records" /> 12 <link rel="next" href="DbUsage.html" title="Database Usage Example" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Using C Structures with DB</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="usingDbt.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 3. Database Records</th> 23 <td width="20%" align="right"> <a accesskey="n" href="DbUsage.html">Next</a></td> 24 </tr> 25 </table> 26 <hr /> 27 </div> 28 <div class="sect1" lang="en" xml:lang="en"> 29 <div class="titlepage"> 30 <div> 31 <div> 32 <h2 class="title" style="clear: both"><a id="cstructs"></a>Using C Structures with DB</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 Storing data in structures is a handy way to pack varied types of 39 information into each database record. DB databases are sometimes 40 thought of as a two column table where column 1 is the key and column 2 is 41 the data. By using structures, you can effectively turn this table into 42 <span class="emphasis"><em>n</em></span> columns where <span class="emphasis"><em>n-1</em></span> columns 43 are contained in the structure. 44 </p> 45 <p> 46 So long as a C structure contains fields that are not pointers, you can safely 47 store and retrieve them in the same way as you would any primitive 48 datatype. The following code fragment illustrates this: 49 </p> 50 <a id="c_dbt6"></a> 51 <pre class="programlisting">#include <db.h> 52#include <string.h> 53 54typedef struct my_struct { 55 int id; 56 char familiar_name[MAXLINE]; /* Some suitably large value */ 57 char surname[MAXLINE]; 58} MY_STRUCT; 59 60... 61 62DBT key, data; 63DB *my_database; 64MY_STRUCT user; 65char *fname = "David"; 66char *sname = "Rider"; 67 68/* Database open omitted for clarity */ 69 70user.id = 1; 71strncpy(user.familiar_name, fname, strlen(fname)+1); 72strncpy(user.surname, sname, strlen(sname)+1); 73 74/* Zero out the DBTs before using them. */ 75memset(&key, 0, sizeof(DBT)); 76memset(&data, 0, sizeof(DBT)); 77 78key.data = &(user.id); 79key.size = sizeof(int); 80 81data.data = &user; 82data.size = sizeof(MY_STRUCT); 83 84my_database->put(my_database, NULL, &key, &data, DB_NOOVERWRITE);</pre> 85 <p> 86 To retrieve the structure, make sure you supply your own 87 memory. The reason why is that like real numbers, some systems require 88 structures to be aligned in a specific way. Because it is possible that 89 the memory DB provides is not aligned properly, for safest result simply 90 use your own memory: 91 </p> 92 <a id="c_dbt7"></a> 93 <pre class="programlisting">#include <db.h> 94#include <string.h> 95 96... 97 98DBT key, data; 99DB *my_database; 100MY_STRUCT user; 101 102/* Database open omitted for clarity */ 103 104/* Zero out the DBTs before using them. */ 105memset(&key, 0, sizeof(DBT)); 106memset(&data, 0, sizeof(DBT)); 107 108/* Initialize the structure */ 109memset(&user, 0, sizeof(MY_STRUCT)); 110user.id = 1; 111 112key.data = &user.id; 113key.size = sizeof(int); 114 115/* Use our memory to retrieve the structure */ 116data.data = &user; 117data.ulen = sizeof(MY_STRUCT); 118data.flags = DB_DBT_USERMEM; 119 120my_database->get(my_database, NULL, &key, &data, 0); 121 122printf("Familiar name: %s\n", user.familiar_name); 123printf("Surname: %s\n", user.surname); </pre> 124 <p> 125 Be aware that while this is the easiest way to manage structures stored 126 in DB databases, this approach does suffer from causing your 127 database to be larger than is strictly necessary. Each structure stored 128 in the database is of a fixed size, and you do not see any space savings 129 from storing a (for example) 5 character surname versus a 20 character 130 surname. 131 </p> 132 <p> 133 For a simple example such as this, the padding stored with each record 134 is probably not critical. However, if you are storing structures that 135 contain a very large number of character arrays, or if you are simply 136 storing millions of records, then you may want to avoid this approach. 137 The wasted space in each record will only serve to make your databases 138 larger than need be, which will in turn require a larger cache and more 139 disk I/O than you would ordinarily need. 140 </p> 141 <p> 142 An alternative approach is described next. 143 </p> 144 <div class="sect2" lang="en" xml:lang="en"> 145 <div class="titlepage"> 146 <div> 147 <div> 148 <h3 class="title"><a id="cstructdynamic"></a>C Structures with Pointers</h3> 149 </div> 150 </div> 151 <div></div> 152 </div> 153 <p> 154 It is often necessary in C structures 155 156 157 to use fields 158 159 160 that are pointers to 161 dynamically allocated memory. This is particularly 162 true if you want to store character strings (or any kind of an array for 163 that matter), and you want to avoid any overhead caused by 164 pre-designating the size of the array. 165 </p> 166 <p> 167 When storing structures 168 169 like these you need to make sure that all of 170 the data pointed to and contained by the structure 171 172 173 is lined up in a 174 single contiguous block of memory. Remember that DB stores data 175 located at a specific address and of a particular size. If your structure 176 177 includes fields 178 179 that are pointing to dynamically allocated memory, then 180 the data that you want to store can be located in different, not 181 necessarily contiguous, locations on the heap. 182 </p> 183 <p> 184 The easiest way to solve this problem is to pack your data 185 into a single memory location and then store the data in that location. 186 (This process is sometimes called <span class="emphasis"><em>marshalling the 187 data</em></span>.) 188 For example: 189 </p> 190 <a id="c_dbt8"></a> 191 <pre class="programlisting">#include <db.h> 192#include <string.h> 193#include <stdlib.h> 194 195typedef struct my_struct { 196 int id; 197 char *familiar_name; 198 char *surname; 199} MY_STRUCT; 200 201... 202 203DBT key, data; 204DB *my_database; 205MY_STRUCT user; 206int buffsize, bufflen; 207char fname[ ] = "Pete"; 208char sname[10]; 209char *databuff; 210 211strncpy(sname, "Oar", strlen("Oar")+1); 212 213/* Database open omitted for clarity */ 214 215user.id = 1; 216user.familiar_name = fname; 217user.surname = sname; 218 219/* Some of the structure's data is on the stack, and 220 * some is on the heap. To store this structure's data, we 221 * need to marshall it -- pack it all into a single location 222 * in memory. 223 */ 224 225/* Get the buffer */ 226buffsize = sizeof(int) + 227 (strlen(user.familiar_name) + strlen(user.surname) + 2); 228databuff = malloc(buffsize); 229memset(databuff, 0, buffsize); 230 231/* copy everything to the buffer */ 232memcpy(databuff, &(user.id), sizeof(int)); 233bufflen = sizeof(int); 234 235memcpy(databuff + bufflen, user.familiar_name, 236 strlen(user.familiar_name) + 1); 237bufflen += strlen(user.familiar_name) + 1; 238 239memcpy(databuff + bufflen, user.surname, 240 strlen(user.surname) + 1); 241bufflen += strlen(user.surname) + 1; 242 243/* Now store it */ 244 245/* Zero out the DBTs before using them. */ 246memset(&key, 0, sizeof(DBT)); 247memset(&data, 0, sizeof(DBT)); 248 249key.data = &(user.id); 250key.size = sizeof(int); 251 252data.data = databuff; 253data.size = bufflen; 254 255my_database->put(my_database, NULL, &key, &data, DB_NOOVERWRITE); 256free(sname); 257free(databuff);</pre> 258 <p> 259 To retrieve the stored structure: 260 </p> 261 <a id="c_dbt9"></a> 262 <pre class="programlisting">#include <db.h> 263#include <string.h> 264#include <stdlib.h> 265 266typedef struct my_struct { 267 char *familiar_name; 268 char *surname; 269 int id; 270} MY_STRUCT; 271 272... 273 274int id; 275DBT key, data; 276DB *my_database; 277MY_STRUCT user; 278char *buffer; 279 280/* Database open omitted for clarity */ 281 282 283/* Zero out the DBTs before using them. */ 284memset(&key, 0, sizeof(DBT)); 285memset(&data, 0, sizeof(DBT)); 286 287id = 1; 288key.data = &id; 289key.size = sizeof(int); 290 291my_database->get(my_database, NULL, &key, &data, 0); 292 293/* 294 * Some compilers won't allow pointer arithmetic on void *'s, 295 * so use a char * instead. 296 */ 297buffer = data.data; 298 299user.id = *((int *)data.data); 300user.familiar_name = buffer + sizeof(int); 301user.surname = buffer + sizeof(int) + strlen(user.familiar_name) + 1; </pre> 302 </div> 303 </div> 304 <div class="navfooter"> 305 <hr /> 306 <table width="100%" summary="Navigation footer"> 307 <tr> 308 <td width="40%" align="left"><a accesskey="p" href="usingDbt.html">Prev</a> </td> 309 <td width="20%" align="center"> 310 <a accesskey="u" href="DBEntry.html">Up</a> 311 </td> 312 <td width="40%" align="right"> <a accesskey="n" href="DbUsage.html">Next</a></td> 313 </tr> 314 <tr> 315 <td width="40%" align="left" valign="top">Reading and Writing Database Records </td> 316 <td width="20%" align="center"> 317 <a accesskey="h" href="index.html">Home</a> 318 </td> 319 <td width="40%" align="right" valign="top"> Database Usage Example</td> 320 </tr> 321 </table> 322 </div> 323 </body> 324</html> 325