f64fb1114e1d8e987f8184dc3267425a14b69820
[platform/upstream/rpm.git] / lib / db2.c
1 #include "system.h"
2
3 static int _debug = 1;
4
5 #include <db.h>
6
7 #include <rpmlib.h>
8
9 #include "dbindex.h"
10 /*@access dbiIndex@*/
11 /*@access dbiIndexSet@*/
12
13 #include "db2.h"
14
15 #if DB_VERSION_MAJOR == 2
16 #define __USE_DB2       1
17 #define _mymemset(_a, _b, _c)   memset((_a), (_b), (_c))
18
19 static inline DBTYPE dbi_to_dbtype(DBI_TYPE dbitype)
20 {
21     switch(dbitype) {
22     case DBI_BTREE:     return DB_BTREE;
23     case DBI_HASH:      return DB_HASH;
24     case DBI_RECNO:     return DB_RECNO;
25     }
26     /*@notreached@*/ return DB_HASH;
27 }
28
29 static inline /*@observer@*/ /*@null@*/ DB * GetDB(dbiIndex dbi) {
30     return ((DB *)dbi->dbi_db);
31 }
32
33 #if defined(__USE_DB2) || defined(__USE_DB3)
34 #if defined(__USE_DB2)
35 static /*@observer@*/ const char * db_strerror(int error)
36 {
37     if (error == 0)
38         return ("Successful return: 0");
39     if (error > 0)
40         return (strerror(error));
41
42     switch (error) {
43     case DB_INCOMPLETE:
44         return ("DB_INCOMPLETE: Cache flush was unable to complete");
45     case DB_KEYEMPTY:
46         return ("DB_KEYEMPTY: Non-existent key/data pair");
47     case DB_KEYEXIST:
48         return ("DB_KEYEXIST: Key/data pair already exists");
49     case DB_LOCK_DEADLOCK:
50         return ("DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock");
51     case DB_LOCK_NOTGRANTED:
52         return ("DB_LOCK_NOTGRANTED: Lock not granted");
53     case DB_NOTFOUND:
54         return ("DB_NOTFOUND: No matching key/data pair found");
55 #if defined(__USE_DB3)
56     case DB_OLD_VERSION:
57         return ("DB_OLDVERSION: Database requires a version upgrade");
58     case DB_RUNRECOVERY:
59         return ("DB_RUNRECOVERY: Fatal error, run database recovery");
60 #else
61     case DB_LOCK_NOTHELD:
62         return ("DB_LOCK_NOTHELD:");
63     case DB_REGISTERED:
64         return ("DB_REGISTERED:");
65 #endif
66     default:
67       {
68         /*
69          * !!!
70          * Room for a 64-bit number + slop.  This buffer is only used
71          * if we're given an unknown error, which should never happen.
72          * Note, however, we're no longer thread-safe if it does.
73          */
74         static char ebuf[40];
75
76         (void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error);
77         return(ebuf);
78       }
79     }
80     /*@notreached@*/
81 }
82
83 static int db_env_create(DB_ENV **dbenvp, int foo)
84 {
85     DB_ENV *dbenv;
86
87     if (dbenvp == NULL)
88         return 1;
89     dbenv = xcalloc(1, sizeof(*dbenv));
90
91     *dbenvp = dbenv;
92     return 0;
93 }
94 #endif  /* __USE_DB2 */
95
96 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit) {
97     int rc = 0;
98
99     if (error == 0)
100         rc = 0;
101     else if (error < 0)
102         rc = -1;
103     else if (error > 0)
104         rc = 1;
105
106     if (printit && rc) {
107         fprintf(stderr, "*** db%d %s rc %d %s\n", dbi->dbi_major, msg,
108                 rc, db_strerror(error));
109     }
110
111     return rc;
112 }
113
114 static int db_init(dbiIndex dbi, const char *home, int dbflags,
115                         DB_ENV **dbenvp, void **dbinfop)
116 {
117     DB_ENV *dbenv = NULL;
118     FILE * dberrfile = stderr;
119     const char * dberrpfx = "rpmdb";
120     int dbcachesize = 1024 * 1024;
121     int dbpagesize = 32 * 1024;                 /* 0 - 64K */
122     int rc;
123
124     if (dbenvp == NULL || dbinfop == NULL)
125         return 1;
126
127     rc = db_env_create(&dbenv, 0);
128     rc = cvtdberr(dbi, "db_env_create", rc, _debug);
129     if (rc)
130         goto errxit;
131
132 #if defined(__USE_DB3)
133   { int xx;
134  /* dbenv->set_errcall(???) */
135     xx = dbenv->set_errfile(dberrfile);
136     xx = cvtdberr(dbi, "dbenv->set_errfile", xx, _debug);
137     xx = dbenv->set_errpfx(dberrpfx);
138     xx = cvtdberr(dbi, "dbenv->set_errpfx", xx, _debug);
139  /* dbenv->set_paniccall(???) */
140  /* dbenv->set_verbose(???) */
141  /* dbenv->set_lg_max(???) */
142  /* dbenv->set_lk_conflicts(???) */
143  /* dbenv->set_lk_detect(???) */
144  /* dbenv->set_lk_max(???) */
145  /* dbenv->set_mp_mmapsize(???) */
146     xx = dbenv->set_cachesize(dbcachesize);
147     xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
148  /* dbenv->set_tx_max(???) */
149  /* dbenv->set_tx_recover(???) */
150   }
151 #else
152     dbenv->db_errfile = dberrfile;
153     dbenv->db_errpfx = dberrpfx;
154     dbenv->mp_size = dbcachesize;
155 #endif
156
157 #define _DBFMASK        (DB_CREATE|DB_NOMMAP|DB_THREAD)
158
159 #if defined(__USE_DB3)
160     rc = dbenv->open(dbenv, home, NULL, (dbflags & _DBFMASK), 0);
161     rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
162     if (rc)
163         goto errxit;
164     xx = db->set_pagesize(db, dbpagesize)
165     xx = cvtdberr(dbi, "db->set_pagesize", xx, _debug);
166     *dbinfop = NULL;
167 #else
168     rc = db_appinit(home, NULL, dbenv, (dbflags & _DBFMASK));
169     rc = cvtdberr(dbi, "db_appinit", rc, _debug);
170     if (rc)
171         goto errxit;
172     {   DB_INFO * dbinfo = xcalloc(1, sizeof(*dbinfo));
173         /* XXX W2DO? */
174         dbinfo->db_pagesize = dbpagesize;
175         *dbinfop = dbinfo;
176      }
177 #endif
178
179     *dbenvp = dbenv;
180
181     return 0;
182
183 errxit:
184
185 #if defined(__USE_DB3)
186     if (dbenv) {
187         xx = dbenv->close(dbenv);
188         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
189     }
190 #else
191     if (dbenv)  free(dbenv);
192 #endif
193     return rc;
194 }
195 #endif  /* __USE_DB2 || __USE_DB3 */
196
197 int db2open(dbiIndex dbi)
198 {
199     int rc = 0;
200
201 #if defined(__USE_DB2) || defined(__USE_DB3)
202     char * dbhome = NULL;
203     DB * db = NULL;
204     DB_ENV * dbenv = NULL;
205     void * dbinfo = NULL;
206     u_int32_t dbflags;
207
208     dbflags = ( !(dbi->dbi_flags & O_RDWR) ? DB_RDONLY :
209                 ((dbi->dbi_flags & O_CREAT) ? DB_CREATE : 0));
210
211     rc = db_init(dbi, dbhome, dbflags, &dbenv, &dbinfo);
212
213     if (rc == 0) {
214 #if defined(__USE_DB3)
215         rc = db_create(&db, dbenv, 0);
216         rc = cvtdberr(dbi, "db_create", rc, _debug);
217         if (rc == 0) {
218             rc = db->open(db, dbi->dbi_file, NULL, dbi_to_dbtype(dbi->dbi_type),
219                         dbflags, dbi->dbi_perms);
220             rc = cvtdberr(dbi, "db->open", rc, _debug);
221         }
222 #else
223         rc = db_open(dbi->dbi_file, dbi_to_dbtype(dbi->dbi_type), dbflags,
224                         dbi->dbi_perms, dbenv, dbinfo, &db);
225         rc = cvtdberr(dbi, "db_open", rc, _debug);
226 #endif  /* __USE_DB3 */
227     }
228
229     dbi->dbi_db = db;
230     dbi->dbi_dbenv = dbenv;
231     dbi->dbi_dbinfo = dbinfo;
232
233 #else
234     dbi->dbi_db = dbopen(dbi->dbi_file, dbi->dbi_flags, dbi->dbi_perms,
235                 dbi_to_dbtype(dbi->dbi_type), dbi->dbi_openinfo);
236 #endif  /* __USE_DB2 || __USE_DB3 */
237
238     if (rc == 0 && dbi->dbi_db != NULL) {
239         rc = 0;
240         dbi->dbi_major = DB_VERSION_MAJOR;
241         dbi->dbi_minor = DB_VERSION_MINOR;
242         dbi->dbi_patch = DB_VERSION_PATCH;
243     } else
244         rc = 1;
245
246     return rc;
247 }
248
249 int db2close(dbiIndex dbi, unsigned int flags) {
250     DB * db = GetDB(dbi);
251     int rc = 0, xx;
252
253 #if defined(__USE_DB2) || defined(__USE_DB3)
254
255     if (dbi->dbi_dbcursor) {
256         DBC * dbcursor = (DBC *)dbi->dbi_dbcursor;
257         xx = dbcursor->c_close(dbcursor);
258         xx = cvtdberr(dbi, "dbcursor->c_close", xx, _debug);
259         dbi->dbi_dbcursor = NULL;
260     }
261
262     if (db) {
263         rc = db->close(db, 0);
264         rc = cvtdberr(dbi, "db->close", rc, _debug);
265         db = dbi->dbi_db = NULL;
266     }
267
268     if (dbi->dbi_dbinfo) {
269         free(dbi->dbi_dbinfo);
270         dbi->dbi_dbinfo = NULL;
271     }
272     if (dbi->dbi_dbenv) {
273         DB_ENV * dbenv = (DB_ENV *)dbi->dbi_dbenv;
274 #if defined(__USE_DB3)
275         xx = dbenv->close(dbenv);
276         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
277 #else
278         xx = db_appexit(dbenv);
279         xx = cvtdberr(dbi, "db_appexit", xx, _debug);
280 #endif
281         free(dbi->dbi_dbenv);
282         dbi->dbi_dbenv = NULL;
283     }
284 #else
285     rc = db->close(db);
286 #endif
287
288     return rc;
289 }
290
291 int db2sync(dbiIndex dbi, unsigned int flags) {
292     DB * db = GetDB(dbi);
293     int rc;
294
295 #if defined(__USE_DB2) || defined(__USE_DB3)
296     rc = db->sync(db, flags);
297     rc = cvtdberr(dbi, "db->sync", rc, _debug);
298 #else
299     rc = db->sync(db, flags);
300 #endif
301
302     return rc;
303 }
304
305 int db2GetFirstKey(dbiIndex dbi, const char ** keyp) {
306     DBT key, data;
307     DB * db;
308     int rc, xx;
309
310     if (dbi == NULL || dbi->dbi_db == NULL)
311         return 1;
312
313     db = GetDB(dbi);
314     _mymemset(&key, 0, sizeof(key));
315     _mymemset(&data, 0, sizeof(data));
316
317     key.data = NULL;
318     key.size = 0;
319
320 #if defined(__USE_DB2) || defined(__USE_DB3)
321     {   DBC * dbcursor = NULL;
322         rc = db->cursor(db, NULL, &dbcursor);
323         rc = cvtdberr(dbi, "db->cursor", rc, _debug);
324         if (rc == 0) {
325             rc = dbcursor->c_get(dbcursor, &key, &data, DB_FIRST);
326             rc = cvtdberr(dbi, "dbcursor->c_get", rc, _debug);
327         }
328         if (dbcursor) {
329             xx = dbcursor->c_close(dbcursor);
330             xx = cvtdberr(dbi, "dbcursor->c_close", xx, _debug);
331         }
332     }
333 #else
334     rc = db->seq(db, &key, &data, R_FIRST);
335 #endif
336
337     if (rc == 0 && keyp) {
338         char *k = xmalloc(key.size + 1);
339         memcpy(k, key.data, key.size);
340         k[key.size] = '\0';
341         *keyp = k;
342     }
343
344     return rc;
345 }
346
347 int db2SearchIndex(dbiIndex dbi, const char * str, dbiIndexSet * set) {
348     DBT key, data;
349     DB * db = GetDB(dbi);
350     int rc;
351
352     if (set) *set = NULL;
353     _mymemset(&key, 0, sizeof(key));
354     _mymemset(&data, 0, sizeof(data));
355
356     key.data = (void *)str;
357     key.size = strlen(str);
358     data.data = NULL;
359     data.size = 0;
360
361 #if defined(__USE_DB2) || defined(__USE_DB3)
362     rc = db->get(db, NULL, &key, &data, 0);
363     rc = cvtdberr(dbi, "db->get", rc, _debug);
364 #else
365     rc = db->get(db, &key, &data, 0);
366 #endif
367
368     if (rc == 0 && set) {
369         *set = dbiCreateIndexSet();
370         (*set)->recs = xmalloc(data.size);
371         memcpy((*set)->recs, data.data, data.size);
372         (*set)->count = data.size / sizeof(*(*set)->recs);
373     }
374     return rc;
375 }
376
377 /*@-compmempass@*/
378 int db2UpdateIndex(dbiIndex dbi, const char * str, dbiIndexSet set) {
379     DBT key;
380     DB * db = GetDB(dbi);
381     int rc;
382
383     _mymemset(&key, 0, sizeof(key));
384     key.data = (void *)str;
385     key.size = strlen(str);
386
387     if (set->count) {
388         DBT data;
389
390         _mymemset(&data, 0, sizeof(data));
391         data.data = set->recs;
392         data.size = set->count * sizeof(*(set->recs));
393
394 #if defined(__USE_DB2) || defined(__USE_DB3)
395         rc = db->put(db, NULL, &key, &data, 0);
396         rc = cvtdberr(dbi, "db->put", rc, _debug);
397 #else
398         rc = db->put(db, &key, &data, 0);
399 #endif
400
401     } else {
402
403 #if defined(__USE_DB2) || defined(__USE_DB3)
404         rc = db->del(db, NULL, &key, 0);
405         rc = cvtdberr(dbi, "db->del", rc, _debug);
406 #else
407         rc = db->del(db, &key, 0);
408 #endif
409
410     }
411
412     return rc;
413 }
414 /*@=compmempass@*/
415 #endif  /* DB_VERSION_MAJOR == 2 */