1 /*
2    bdb2d is BerkeleyDB for D language
3    It is part of unDE project (http://unde.su)
4 
5    Copyright (C) 2009-2014 Nikolay (unDEFER) Krivchenkov <undefer@gmail.com>
6 
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 module berkeleydb.db;
22 
23 import berkeleydb.c;
24 import berkeleydb.dbenv;
25 import berkeleydb.dbexception;
26 import berkeleydb.dbtxn;
27 import berkeleydb.dbt;
28 import berkeleydb.dbc;
29 import berkeleydb.dbmpoolfile;
30 
31 import std.stdint;
32 import std.stdio;
33 import std.string;
34 import std.array;
35 import std.format;
36 import std.conv;
37 
38 alias DB_COMPACT DbCompact;
39 alias DB_KEY_RANGE DbKeyRange;
40 alias DB_CACHE_PRIORITY DbCachePriority;
41 
42 class Db
43 {
44 private:
45 	DB *db = null;
46 	DbEnv dbenv = null;
47     int opened = 0;
48     static Db[DB *] db_map;
49 
50     static Db from_DB(const DB *_db)
51     {
52         return db_map[_db];
53     }
54 
55 package:
56     @property DB *_DB() {return db;}
57     @property DbEnv _dbenv() {return dbenv;}
58     @property int _opened() {return opened;}
59 
60 public:
61     DbEnv get_env()
62     {
63         return dbenv;
64     }
65 
66     this(DbEnv dbenv, uint32_t flags = 0)
67 	{
68 		auto ret = db_create(&db, dbenv?dbenv._DB_ENV:null, flags);
69 		DbRetCodeToException(ret, dbenv);
70         db_map[db] = this;
71         this.dbenv = dbenv;
72         assert(ret == 0);
73 	}
74 
75     ~this()
76 	{
77 		if (opened >= 0) close();
78         db_map.remove(db);
79 	}
80 
81     static ~this()
82 	{
83         db_map = null;
84     }
85 
86     void open(DbTxn txnid, string file,
87                 string database, DBTYPE type, uint32_t flags, int mode)
88     {
89 		if (opened > 0) {
90 			throw new DbWrongUsingException("Opening opened Db");
91 		}
92 		if (opened < 0) {
93 			throw new DbWrongUsingException("Opening closed Db");
94 		}
95 		auto ret = db.open(db, txnid?txnid._DB_TXN:null, file.toStringz(), database.toStringz(), 
96                 type, flags, mode);
97 		DbRetCodeToException(ret, dbenv);
98         assert(ret == 0);
99         opened++;
100     }
101 
102 	void close(uint32_t flags = 0)
103 	{
104 		if (opened < 0) {
105 			throw new DbWrongUsingException("Closing closed Db");
106 		}
107 		auto ret = db.close(db, flags);
108         opened = -1;
109 		DbRetCodeToException(ret, dbenv);
110         assert(ret == 0);
111 	}
112 
113     void remove(string file, string database, uint32_t flags = 0)
114     {
115 		if (opened > 0) {
116 			throw new DbWrongUsingException("Removing opened Db");
117 		}
118 		if (opened < 0) {
119 			throw new DbWrongUsingException("Operation on closed Db");
120 		}
121 		auto ret = db.remove(db, file.toStringz(), database.toStringz(), flags);
122         opened = -1;
123 		DbRetCodeToException(ret, dbenv);
124         assert(ret == 0);
125     }
126 
127     void rename(string file, string database, string newname, uint32_t flags = 0)
128     {
129 		if (opened > 0) {
130 			throw new DbWrongUsingException("Renaming opened Db");
131 		}
132 		if (opened < 0) {
133 			throw new DbWrongUsingException("Operation on closed Db");
134 		}
135 		auto ret = db.rename(db, file.toStringz(), database.toStringz(), newname.toStringz(), flags);
136         opened = -1;
137 		DbRetCodeToException(ret, dbenv);
138         assert(ret == 0);
139     }
140 
141     void verify(string file, string database, File outfile, uint32_t flags = 0)
142     {
143 		if (opened > 0) {
144 			throw new DbWrongUsingException("Verifying opened Db");
145 		}
146 		if (opened < 0) {
147 			throw new DbWrongUsingException("Operation on closed Db");
148 		}
149 		auto ret = db.verify(db, file.toStringz(), database.toStringz(), outfile.getFP(), flags);
150         opened = -1;
151 		DbRetCodeToException(ret, dbenv);
152         assert(ret == 0);
153     }
154 
155     private
156     {
157         int function(Db secondary, ref const (Dbt) key, 
158                 ref const (Dbt) data, out Dbt result) associate_callback_refer;
159 
160         extern (C) static int associate_callback(DB *_secondary, 
161                 const (DBT) *_key, const (DBT) *_data, DBT *_result)
162         {
163             Db secondary = from_DB(_secondary);
164             const (Dbt) *key = cast(const (Dbt) *) _key;
165             const (Dbt) *data = cast(const (Dbt) *) _data;
166             Dbt *result = cast(Dbt *) _result;
167             return secondary.associate_callback_refer(secondary, *key, *data, *result);
168         }
169     }
170 
171     void associate(DbTxn txnid, Db secondary,
172                 int function(Db secondary,
173                     ref const (Dbt) key, ref const (Dbt) data, out Dbt result) callback, 
174                 uint32_t flags = 0)
175     {
176         if (opened < 0) {
177             throw new DbWrongUsingException("Operation on closed Db");
178         }
179         secondary.associate_callback_refer = callback;
180         auto ret = db.associate(db, txnid?txnid._DB_TXN:null, secondary._DB, 
181                 callback?&associate_callback:null, flags);
182         DbRetCodeToException(ret, dbenv);
183         assert(ret == 0);
184     }
185 
186     private
187     {
188             int function (Db secondary,
189                 ref const (Dbt) key, out Dbt data, ref const (Dbt) foreignkey, 
190                 out int changed) associate_foreign_callback_refer;
191 
192             extern (C) static int associate_foreign_callback(DB *_secondary,
193                 const (DBT) *_key, DBT *_data, const (DBT) *_foreignkey, int *changed)
194             {
195                 Db secondary = from_DB(_secondary);
196                 const (Dbt) *key = cast(const (Dbt) *) _key;
197                 Dbt *data = cast(Dbt *) _data;
198                 const (Dbt) *foreignkey = cast(const (Dbt) *) _foreignkey;
199                 return secondary.associate_foreign_callback_refer(secondary, *key, *data, *foreignkey, *changed);
200             }
201     }
202 
203     void associate_foreign(Db secondary, int function(Db secondary,
204                 ref const (Dbt) key, out Dbt data, ref const (Dbt) foreignkey, out int changed) callback, 
205             uint32_t flags = 0)
206     {
207         if (opened < 0) {
208             throw new DbWrongUsingException("Operation on closed Db");
209         }
210         secondary.associate_foreign_callback_refer = callback;
211         auto ret = db.associate_foreign(db, secondary._DB, 
212                 callback?&associate_foreign_callback:null, flags);
213         DbRetCodeToException(ret, dbenv);
214         assert(ret == 0);
215     }
216 
217     void compact(DbTxn txnid,
218             Dbt *start, Dbt *stop, DbCompact *c_data, uint32_t flags, Dbt *end)
219     {
220         if (opened < 0) {
221             throw new DbWrongUsingException("Operation on closed Db");
222         }
223         auto ret = db.compact(db, txnid?txnid._DB_TXN:null, &start.dbt, &stop.dbt,
224                 c_data, flags, &end.dbt);
225         DbRetCodeToException(ret, dbenv);
226         assert(ret == 0);
227     }
228 
229     int del(DbTxn txnid, Dbt *key, uint32_t flags = 0)
230     {
231         if (opened < 0) {
232             throw new DbWrongUsingException("Operation on closed Db");
233         }
234         auto ret = db.del(db, txnid?txnid._DB_TXN:null, &key.dbt, flags);
235         return DbRetCodeToException!"Db.del"(ret, dbenv);
236     }
237 
238     int get(DbTxn txnid, Dbt *key, Dbt *data, uint32_t flags = 0)
239     {
240         if (opened < 0) {
241             throw new DbWrongUsingException("Operation on closed Db");
242         }
243         auto ret = db.get(db, txnid?txnid._DB_TXN:null, &key.dbt, &data.dbt, flags);
244         DbRetCodeToException!"Db.get"(ret, dbenv, data);
245         return DbRetCodeToException!"Db.get"(ret, dbenv);
246     }
247 
248     int pget(DbTxn txnid, Dbt *key, Dbt *pkey, Dbt *data, uint32_t flags = 0)
249     {
250         if (opened < 0) {
251             throw new DbWrongUsingException("Operation on closed Db");
252         }
253         auto ret = db.pget(db, txnid?txnid._DB_TXN:null, &key.dbt, &pkey.dbt, &data.dbt, flags);
254         DbRetCodeToException!"Db.get"(ret, dbenv, data);
255         return DbRetCodeToException!"Db.get"(ret, dbenv);
256     }
257 
258     int put(DbTxn txnid, Dbt *key, Dbt *data, uint32_t flags = 0)
259     {
260         if (opened < 0) {
261             throw new DbWrongUsingException("Operation on closed Db");
262         }
263         auto ret = db.put(db, txnid?txnid._DB_TXN:null, &key.dbt, &data.dbt, flags);
264         return DbRetCodeToException!"Db.put"(ret, dbenv);
265     }
266 
267     void err(T...)(int error, string fmt, T args)
268     {
269 		if (opened < 0) {
270 			throw new DbWrongUsingException("Operation on closed Db");
271 		}
272         auto app = appender!string();
273         formattedWrite(app, fmt, args);
274         db.err(db, error, "%s".toStringz(), app.data.toStringz());
275     }
276 
277     void errx(T...)(string fmt, T args)
278     {
279 		if (opened < 0) {
280 			throw new DbWrongUsingException("Operation on closed Db");
281 		}
282         auto app = appender!string();
283         formattedWrite(app, fmt, args);
284         db.errx(db, "%s".toStringz(), app.data.toStringz());
285     }
286 
287     int exists(DbTxn txnid, Dbt *key, uint32_t flags = 0)
288     {
289         if (opened < 0) {
290             throw new DbWrongUsingException("Operation on closed Db");
291         }
292         auto ret = db.exists(db, txnid?txnid._DB_TXN:null, &key.dbt, flags);
293         return DbRetCodeToException!"exists"(ret, dbenv);
294     }
295 
296     int fd()
297     {
298         if (opened < 0) {
299             throw new DbWrongUsingException("Operation on closed Db");
300         }
301         int res;
302         auto ret = db.fd(db, &res);
303         DbRetCodeToException(ret, dbenv);
304         assert(ret == 0);
305         return res;
306     }
307 
308     int get_byteswapped()
309     {
310         if (opened <= 0) {
311             throw new DbWrongUsingException("Operation on closed or not opened Db");
312         }
313         int res;
314         auto ret = db.fd(db, &res);
315         DbRetCodeToException(ret, dbenv);
316         assert(ret == 0);
317         return res;
318     }
319 
320     void get_dbname(ref string filename, ref string dbname)
321     {
322         if (opened < 0) {
323             throw new DbWrongUsingException("Operation on closed Db");
324         }
325         const (char) *_filename;
326         const (char) *_dbname;
327         auto ret = db.get_dbname(db, &_filename, &_dbname);
328         DbRetCodeToException(ret, dbenv);
329         assert(ret == 0);
330         filename = to!string(_filename);
331         dbname = to!string(_dbname);
332     }
333 
334     int get_multiple()
335     {
336         if (opened <= 0) {
337             throw new DbWrongUsingException("Operation on closed or not opened Db");
338         }
339         return db.get_multiple(db);
340     }
341 
342     uint32_t get_open_flags()
343     {
344         if (opened <= 0) {
345             throw new DbWrongUsingException("Operation on closed or not opened Db");
346         }
347         uint32_t res;
348         auto ret = db.get_open_flags(db, &res);
349         DbRetCodeToException(ret, dbenv);
350         assert(ret == 0);
351         return res;
352     }
353 
354     DBTYPE get_type()
355     {
356         if (opened <= 0) {
357             throw new DbWrongUsingException("Operation on closed or not opened Db");
358         }
359         DBTYPE res;
360         auto ret = db.get_type(db, &res);
361         DbRetCodeToException(ret, dbenv);
362         assert(ret == 0);
363         return res;
364     }
365 
366     Dbc join(Dbc[] curslist, uint32_t flags = 0)
367     {
368         if (opened < 0) {
369             throw new DbWrongUsingException("Operation on closed Db");
370         }
371 
372         // convert Dbc[] to null-terminated array of DBC*
373         DBC*[] _curslist = new DBC*[curslist.length + 1];
374         foreach(int i, Dbc c; curslist[])
375             _curslist[i] = c._DBC;
376 
377         DBC *res;
378         auto ret = db.join(db, _curslist.ptr, &res, flags);
379         DbRetCodeToException(ret, dbenv);
380         assert(ret == 0);
381         return new Dbc(res, true, dbenv);
382     }
383 
384     DbKeyRange key_range(DbTxn txnid, Dbt *key, uint32_t flags = 0)
385     {
386         if (opened < 0) {
387             throw new DbWrongUsingException("Operation on closed Db");
388         }
389         DbKeyRange res;
390         auto ret = db.key_range(db, txnid?txnid._DB_TXN:null, &key.dbt, &res, flags);
391         DbRetCodeToException(ret, dbenv);
392         assert(ret == 0);
393         return res;
394     }
395 
396     void set_priority(DbCachePriority priority)
397     {
398         if (opened < 0) {
399             throw new DbWrongUsingException("Operation on closed Db");
400         }
401         auto ret = db.set_priority(db, priority);
402         DbRetCodeToException(ret, dbenv);
403         assert(ret == 0);
404     }
405 
406     DbCachePriority get_priority()
407     {
408         if (opened < 0) {
409             throw new DbWrongUsingException("Operation on closed Db");
410         }
411         DbCachePriority res;
412         auto ret = db.get_priority(db, &res);
413         DbRetCodeToException(ret, dbenv);
414         assert(ret == 0);
415         return res;
416     }
417 
418     void stat(DbTxn txnid, void *sp, uint32_t flags = 0)
419     {
420         if (opened <= 0) {
421             throw new DbWrongUsingException("Operation on closed or not opened Db");
422         }
423         auto ret = db.stat(db, txnid?txnid._DB_TXN:null, sp, flags);
424         DbRetCodeToException(ret, dbenv);
425         assert(ret == 0);
426     }
427 
428     void stat_print(uint32_t flags = 0)
429     {
430         if (opened <= 0) {
431             throw new DbWrongUsingException("Operation on closed or not opened Db");
432         }
433         auto ret = db.stat_print(db, flags);
434         DbRetCodeToException(ret, dbenv);
435         assert(ret == 0);
436     }
437 
438     void sync(uint32_t flags = 0)
439     {
440         if (opened < 0) {
441             throw new DbWrongUsingException("Operation on closed Db");
442         }
443         auto ret = db.sync(db, flags);
444         DbRetCodeToException(ret, dbenv);
445         assert(ret == 0);
446     }
447 
448     uint32_t truncate(DbTxn txnid, uint32_t flags = 0)
449     {
450         if (opened < 0) {
451             throw new DbWrongUsingException("Operation on closed Db");
452         }
453         uint32_t count;
454         auto ret = db.truncate(db, txnid?txnid._DB_TXN:null, &count, flags);
455         DbRetCodeToException(ret, dbenv);
456         assert(ret == 0);
457         return count;
458     }
459 
460     void upgrade(string file, uint32_t flags = 0)
461     {
462         if (opened < 0) {
463             throw new DbWrongUsingException("Operation on closed Db");
464         }
465         auto ret = db.upgrade(db, file.toStringz(), flags);
466         DbRetCodeToException(ret, dbenv);
467         assert(ret == 0);
468     }
469 
470     Dbc cursor(DbTxn txnid, uint32_t flags = 0)
471     {
472         if (opened < 0) {
473             throw new DbWrongUsingException("Operation on closed Db");
474         }
475 
476         DBC *res;
477         auto ret = db.cursor(db, txnid?txnid._DB_TXN:null, &res, flags);
478         DbRetCodeToException(ret, dbenv);
479         assert(ret == 0);
480         return new Dbc(res, false, dbenv);
481     }
482 
483     /* Database Configuration */
484 
485     private
486     {
487         uint32_t function (Db db, Dbt *key) db_partition_callback_refer;
488 
489         extern (C) static uint32_t db_partition_callback(DB *_db, DBT *_key)
490         {
491                 Db db = from_DB(_db);
492                 Dbt *key = cast(Dbt *) _key;
493                 return db.db_partition_callback_refer(db, key);
494         }
495     }
496 
497     void set_partition(uint32_t parts,  Dbt[] keys,
498                 uint32_t function (Db db, Dbt *key) db_partition_fcn)
499     {
500         if (opened < 0) {
501             throw new DbWrongUsingException("Configuration on closed Db");
502         }
503         if ( (parts-1) != keys.length  )
504         {
505             throw new DbWrongUsingException("Length of keys must be one less than parts");
506         }
507         db_partition_callback_refer = db_partition_fcn;
508         auto ret = db.set_partition(db, parts, cast(DBT*)keys.ptr, 
509                 db_partition_fcn?&db_partition_callback:null);
510         DbRetCodeToException(ret, dbenv);
511         assert(ret == 0);
512     }
513 
514     /*FIXME: What we must return when callback reference is null??? O_o*/
515     void get_partition_callback(ref uint32_t parts,
516             ref uint32_t function (Db dbp, Dbt *key) callback_fcn)
517     {
518         if (opened < 0) {
519             throw new DbWrongUsingException("Get configuration on closed Db");
520         }
521 
522         callback_fcn = db_partition_callback_refer;
523 
524         extern (C) uint32_t function(DB *_db, DBT *_key) n;
525         auto ret = db.get_partition_callback(db, &parts, &n);
526         DbRetCodeToException(ret, dbenv);
527         assert(ret == 0);
528     }
529 
530     void get_partition_keys(ref uint32_t parts, ref Dbt[] keys)
531     {
532         if (opened < 0) {
533             throw new DbWrongUsingException("Get configuration on closed Db");
534         }
535 
536         DBT *_keys;
537         auto ret = db.get_partition_keys(db, &parts, &_keys);
538         DbRetCodeToException(ret, dbenv);
539         assert(ret == 0);
540 
541         /*"parts-1" - is not error, it is really length of keys array according
542           BerkeleyDb documentation */
543         keys = (cast(Dbt*)_keys)[0..parts-1];
544     }
545 
546     Dbt[] get_partition_keys()
547     {
548         if (opened < 0) {
549             throw new DbWrongUsingException("Get configuration on closed Db");
550         }
551 
552         uint32_t parts;
553         DBT *_keys;
554         auto ret = db.get_partition_keys(db, &parts, &_keys);
555         DbRetCodeToException(ret, dbenv);
556         assert(ret == 0);
557 
558         /*"parts-1" - is not error, it is really length of keys array according
559           BerkeleyDb documentation */
560         return (cast(Dbt*)_keys)[0..parts-1];
561     }
562 
563     extern (C) void set_alloc(void *function(size_t) app_malloc,
564             void *function(void *, size_t) app_realloc, 
565             void function(void *) app_free)
566     {
567         if (opened < 0) {
568             throw new DbWrongUsingException("Configuration on closed DbEnv");
569         }
570         if (opened > 0) {
571             throw new DbWrongUsingException("Configuration of opened DbEnv");
572         }
573         auto ret = db.set_alloc(db, app_malloc, app_realloc, app_free);
574         DbRetCodeToException(ret, dbenv);
575         assert(ret == 0);
576     }
577 
578     void set_cachesize(uint32_t gbytes, uint32_t bytes, int ncache)
579     {
580         if (opened < 0) {
581             throw new DbWrongUsingException("Configuration on closed Db");
582         }
583         if (opened > 0) {
584             throw new DbWrongUsingException("Configuration of opened Db");
585         }
586 
587         auto ret = db.set_cachesize(db, gbytes, bytes, ncache);
588         DbRetCodeToException(ret, dbenv);
589         assert(ret == 0);
590     }
591 
592     void set_cachesize(uint64_t bytes, int ncache)
593     {
594         uint32_t _gbytes = cast(uint32_t) bytes/(1024*1024*1024);
595         uint32_t _bytes = bytes%(1024*1024*1024);
596         set_cachesize(_gbytes, _bytes, ncache);
597     }
598 
599     void get_cachesize(ref uint32_t gbytes, ref uint32_t bytes, ref int ncache)
600     {
601         if (opened < 0) {
602             throw new DbWrongUsingException("Get configuration on closed Db");
603         }
604         auto ret = db.get_cachesize(db, &gbytes, &bytes, &ncache);
605         DbRetCodeToException(ret, dbenv);
606         assert(ret == 0);
607     }
608 
609     void get_cachesize(ref uint64_t bytes, ref int ncache)
610     {
611         uint32_t _gbytes;
612         uint32_t _bytes;
613         get_cachesize(_gbytes, _bytes, ncache);
614         bytes = (1024UL*1024*1024)*_gbytes + _bytes;
615     }
616 
617     uint64_t get_cachesize(ref int ncache)
618     {
619         uint64_t bytes;
620         get_cachesize(bytes, ncache);
621         return bytes;
622     }
623 
624     void set_create_dir(string dir)
625     {
626         if (opened < 0) {
627             throw new DbWrongUsingException("Configuration on closed Db");
628         }
629         if (opened > 0) {
630             throw new DbWrongUsingException("Configuration of opened Db");
631         }
632 
633         auto ret = db.set_create_dir(db, dir.toStringz());
634         DbRetCodeToException(ret, dbenv);
635         assert(ret == 0);
636     }
637 
638     string get_create_dir()
639     {
640         if (opened < 0) {
641             throw new DbWrongUsingException("Get configuration on closed Db");
642         }
643         const (char) *res;
644         auto ret = db.get_create_dir(db, &res);
645         DbRetCodeToException(ret, dbenv);
646         assert(ret == 0);
647         return to!string(res);
648     }
649 
650     private
651     {
652 version(VERSION_6)
653 {
654         int function(Db db,
655                 const (Dbt) *dbt1, const (Dbt) *dbt2, size_t *locp) dup_compare_callback_refer;
656 
657         extern (C) static int dup_compare_callback(DB *_db,
658                 const (DBT) *_dbt1, const (DBT) *_dbt2, size_t *locp)
659         {
660                 Db db = from_DB(_db);
661                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
662                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
663                 return db.dup_compare_callback_refer(db, dbt1, dbt2, locp);
664         }
665 
666         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2, size_t *locp) dup_compare_fcn_t;
667 }
668 else
669 {
670         int function(Db db,
671                 const (Dbt) *dbt1, const (Dbt) *dbt2) dup_compare_callback_refer;
672 
673         extern (C) static int dup_compare_callback(DB *_db,
674                 const (DBT) *_dbt1, const (DBT) *_dbt2)
675         {
676                 Db db = from_DB(_db);
677                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
678                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
679                 return db.dup_compare_callback_refer(db, dbt1, dbt2);
680         }
681         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2) dup_compare_fcn_t;
682 }
683     }
684 
685     void set_dup_compare(dup_compare_fcn_t dup_compare_fcn)
686     {
687         if (opened < 0) {
688             throw new DbWrongUsingException("Configuration on closed Db");
689         }
690         if (opened > 0) {
691             throw new DbWrongUsingException("Configuration of opened Db");
692         }
693         dup_compare_callback_refer = dup_compare_fcn;
694         auto ret = db.set_dup_compare(db, 
695                 dup_compare_fcn?&dup_compare_callback:null);
696         DbRetCodeToException(ret, dbenv);
697         assert(ret == 0);
698     }
699 
700     void set_encrypt(string passwd, uint32_t flags = 0)
701     {
702         if (opened < 0) {
703             throw new DbWrongUsingException("Configuration on closed Db");
704         }
705         if (opened > 0) {
706             throw new DbWrongUsingException("Configuration of opened Db");
707         }
708         auto ret = db.set_encrypt(db, passwd.toStringz(), flags);
709         DbRetCodeToException(ret, dbenv);
710         assert(ret == 0);
711     }
712 
713     uint32_t get_encrypt_flags()
714     {
715         if (opened < 0) {
716             throw new DbWrongUsingException("Get configuration on closed Db");
717         }
718         uint32_t res;
719         auto ret = db.get_encrypt_flags(db, &res);
720         DbRetCodeToException(ret, dbenv);
721         assert(ret == 0);
722         return res;
723     }
724 
725     private File _errfile;
726 
727     void set_errfile(File errfile)
728     {
729         if (opened < 0) {
730             throw new DbWrongUsingException("Configuration on closed Db");
731         }
732         if (dbenv) dbenv.set_errfile(errfile);
733         else
734         {
735             _errfile = errfile;
736             db.set_errfile(db, errfile.getFP());
737         }
738     }
739 
740     File get_errfile()
741     {
742         if (opened < 0) {
743             throw new DbWrongUsingException("Get configuration on closed Db");
744         }
745         if (dbenv) return dbenv.get_errfile();
746         else return _errfile;
747     }
748 
749     void set_errpfx(string errpfx)
750     {
751         if (opened < 0) {
752             throw new DbWrongUsingException("Configuration on closed Db");
753         }
754         db.set_errpfx(db, errpfx.toStringz());
755     }
756 
757     string get_errpfx()
758     {
759         if (opened < 0) {
760             throw new DbWrongUsingException("Get configuration on closed Db");
761         }
762         const (char) *res;
763         db.get_errpfx(db, &res);
764         return to!string(res);
765     }
766 
767     private
768     {
769         void function(Db db, int opcode, int percent) db_feedback_callback_refer;
770 
771         extern (C) static void db_feedback_callback(DB *dbp, int opcode, int percent)
772         {
773                 Db db = from_DB(dbp);
774                 return db.db_feedback_callback_refer(db, opcode, percent);
775         }
776     }
777 
778     void set_feedback(void function(Db db, int opcode, int percent) db_feedback_fcn)
779     {
780         if (opened < 0) {
781             throw new DbWrongUsingException("Configuration on closed Db");
782         }
783         db_feedback_callback_refer = db_feedback_fcn;
784         auto ret = db.set_feedback(db, db_feedback_fcn?&db_feedback_callback:null);
785         DbRetCodeToException(ret, dbenv);
786         assert(ret == 0);
787     }
788 
789     void set_flags(uint32_t flags = 0)
790     {
791         if (opened < 0) {
792             throw new DbWrongUsingException("Configuration on closed Db");
793         }
794         if (opened > 0) {
795             throw new DbWrongUsingException("Configuration of opened Db");
796         }
797         auto ret = db.set_flags(db, flags);
798         DbRetCodeToException(ret, dbenv);
799         assert(ret == 0);
800     }
801 
802     uint32_t get_flags()
803     {
804         if (opened < 0) {
805             throw new DbWrongUsingException("Get configuration on closed Db");
806         }
807         uint32_t res;
808         auto ret = db.get_flags(db, &res);
809         DbRetCodeToException(ret, dbenv);
810         assert(ret == 0);
811         return res;
812     }
813 
814     void set_lk_exclusive(int nowait_onoff)
815     {
816         if (opened < 0) {
817             throw new DbWrongUsingException("Operation on closed Db");
818         }
819         if (opened > 0) {
820             throw new DbWrongUsingException("Configuration of opened Db");
821         }
822         auto ret = db.set_lk_exclusive(db, nowait_onoff);
823         DbRetCodeToException(ret, dbenv);
824         assert(ret == 0);
825     }
826 
827     void get_lk_exclusive(ref int onoff, ref int nowait)
828     {
829         if (opened < 0) {
830             throw new DbWrongUsingException("Get configuration on closed Db");
831         }
832         auto ret = db.get_lk_exclusive(db, &onoff, &nowait);
833         DbRetCodeToException(ret, dbenv);
834         assert(ret == 0);
835     }
836 
837     void set_lorder(int lorder)
838     {
839         if (opened < 0) {
840             throw new DbWrongUsingException("Configuration on closed Db");
841         }
842         if (opened > 0) {
843             throw new DbWrongUsingException("Configuration of opened Db");
844         }
845         auto ret = db.set_lorder(db, lorder);
846         DbRetCodeToException(ret, dbenv);
847         assert(ret == 0);
848     }
849 
850     int get_lorder()
851     {
852         if (opened < 0) {
853             throw new DbWrongUsingException("Get configuration on closed Db");
854         }
855         int res;
856         auto ret = db.get_lorder(db, &res);
857         DbRetCodeToException(ret, dbenv);
858         assert(ret == 0);
859         return res;
860     }
861 
862     void set_msgcall(void function(const DbEnv dbenv, string msg) db_msgcall_fcn)
863     {
864         if (opened < 0) {
865             throw new DbWrongUsingException("Configuration on closed DbEnv");
866         }
867         if (dbenv) dbenv.set_msgcall(db_msgcall_fcn);
868         else assert(0, "Use extern(C) version of set_msgcall()");
869     }
870 
871     extern (C) void set_msgcall(void function(const (DB_ENV) *dbenv, const (char) *msg) db_msgcall_fcn)
872     {
873         if (opened < 0) {
874             throw new DbWrongUsingException("Configuration on closed DbEnv");
875         }
876         db.set_msgcall(db, db_msgcall_fcn);
877     }
878 
879     private File _msgfile;
880 
881     void set_msgfile(File msgfile)
882     {
883         if (opened < 0) {
884             throw new DbWrongUsingException("Configuration on closed Db");
885         }
886         if (dbenv) dbenv.set_msgfile(msgfile);
887         else
888         {
889             _msgfile = msgfile;
890             db.set_msgfile(db, msgfile.getFP());
891         }
892     }
893 
894     File get_msgfile()
895     {
896         if (opened < 0) {
897             throw new DbWrongUsingException("Get configuration on closed Db");
898         }
899         if (dbenv) return dbenv.get_msgfile();
900         return _msgfile;
901     }
902 
903     void set_pagesize(uint32_t pagesize)
904     {
905         if (opened < 0) {
906             throw new DbWrongUsingException("Operation on closed Db");
907         }
908         if (opened > 0) {
909             throw new DbWrongUsingException("Configuration of opened Db");
910         }
911         auto ret = db.set_pagesize(db, pagesize);
912         DbRetCodeToException(ret, dbenv);
913         assert(ret == 0);
914     }
915 
916     uint32_t get_pagesize()
917     {
918         if (opened <= 0) {
919             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
920         }
921         uint32_t res;
922         auto ret = db.get_pagesize(db, &res);
923         DbRetCodeToException(ret, dbenv);
924         assert(ret == 0);
925         return res;
926     }
927 
928     void set_partition_dirs(string[] dirs)
929     {
930         if (opened < 0) {
931             throw new DbWrongUsingException("Operation on closed Db");
932         }
933         if (opened > 0) {
934             throw new DbWrongUsingException("Configuration of opened Db");
935         }
936 
937         const (char) *[]_dirs = new const (char) *[dirs.length+1];
938         foreach(int i, string dir; dirs)
939             _dirs[i] = dirs[i].toStringz();
940 
941         auto ret = db.set_partition_dirs(db, _dirs.ptr);
942         DbRetCodeToException(ret, dbenv);
943         assert(ret == 0);
944     }
945 
946     string[] get_partition_dirs()
947     {
948         if (opened < 0) {
949             throw new DbWrongUsingException("Get configuration on closed Db");
950         }
951         const (char) **_res;
952         auto ret = db.get_partition_dirs(db, &_res);
953         DbRetCodeToException(ret, dbenv);
954         assert(ret == 0);
955 
956         string[] res = [];
957         for (const (char) **_r = _res; *_r; _r++)
958             res ~= to!string(*_r);
959 
960         return res;
961     }
962 
963     /* Btree/Recno Configuration */
964 
965     private
966     {
967         int function(Db db, Dbt *data, db_recno_t recno) db_append_recno_callback_refer;
968         
969         extern (C) static int db_append_recno_callback(DB *_db, DBT *_data, db_recno_t recno)
970         {
971                 Db db = from_DB(_db);
972                 Dbt *data = cast(Dbt *) _data;
973                 return db.db_append_recno_callback_refer(db, data, recno);
974         }
975     }
976 
977     void set_append_recno(int function(Db db, Dbt *data, db_recno_t recno) db_append_recno_fcn)
978     {
979         if (opened < 0) {
980             throw new DbWrongUsingException("Operation on closed Db");
981         }
982         if (opened > 0) {
983             throw new DbWrongUsingException("Configuration of opened Db");
984         }
985         db_append_recno_callback_refer = db_append_recno_fcn;
986         auto ret = db.set_append_recno(db, db_append_recno_fcn?&db_append_recno_callback:null);
987         DbRetCodeToException(ret, dbenv);
988         assert(ret == 0);
989     }
990 
991     private
992     {
993 version(VERSION_6)
994 {
995         int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2, size_t *locp) bt_compare_callback_refer;
996 
997         extern (C) static int bt_compare_callback(DB *_db, const (DBT) *_dbt1, const (DBT) *_dbt2, size_t *locp)
998         {
999                 Db db = from_DB(_db);
1000                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
1001                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
1002                 return db.bt_compare_callback_refer(db, dbt1, dbt2, locp);
1003         }
1004         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2, size_t *locp) bt_compare_fcn_t;
1005 }
1006 else
1007 {
1008         int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2) bt_compare_callback_refer;
1009 
1010         extern (C) static int bt_compare_callback(DB *_db, const (DBT) *_dbt1, const (DBT) *_dbt2)
1011         {
1012                 Db db = from_DB(_db);
1013                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
1014                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
1015                 return db.bt_compare_callback_refer(db, dbt1, dbt2);
1016         }
1017         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2) bt_compare_fcn_t;
1018 }
1019     }
1020 
1021     void set_bt_compare(bt_compare_fcn_t bt_compare_fcn)
1022     {
1023         if (opened < 0) {
1024             throw new DbWrongUsingException("Operation on closed Db");
1025         }
1026         if (opened > 0) {
1027             throw new DbWrongUsingException("Configuration of opened Db");
1028         }
1029         bt_compare_callback_refer = bt_compare_fcn;
1030         auto ret = db.set_bt_compare(db, bt_compare_fcn?&bt_compare_callback:null);
1031         DbRetCodeToException(ret, dbenv);
1032         assert(ret == 0);
1033     }
1034 
1035     private
1036     {
1037         int function(Db db, const (Dbt) *prevKey, 
1038                 const (Dbt) *prevData, const (Dbt) *key, const (Dbt) *data, 
1039                 Dbt *dest) bt_compress_callback_refer;
1040 
1041         extern (C) static int bt_compress_callback(DB *_db, const (DBT) *_prevKey, 
1042                 const (DBT) *_prevData, const (DBT) *_key, const (DBT) *_data, DBT *_dest)
1043         {
1044                 Db db = from_DB(_db);
1045                 const (Dbt) *prevKey = cast(const (Dbt) *) _prevKey;
1046                 const (Dbt) *prevData = cast(const (Dbt) *) _prevData;
1047                 const (Dbt) *key = cast(const (Dbt) *) _key;
1048                 const (Dbt) *data = cast(const (Dbt) *) _data;
1049                 Dbt *dest = cast(Dbt *) _dest;
1050                 return db.bt_compress_callback_refer(db, prevKey, prevData, key, data, dest);
1051         }
1052 
1053         int function(Db db, const (Dbt) *prevKey, 
1054             const (Dbt) *prevData, Dbt *compressed, Dbt *destKey, 
1055             Dbt *destData) bt_decompress_callback_refer;
1056 
1057         extern (C) static int bt_decompress_callback(DB *_db, const (DBT) *_prevKey, 
1058             const (DBT) *_prevData, DBT *_compressed, DBT *_destKey, 
1059             DBT *_destData)
1060         {
1061                 Db db = from_DB(_db);
1062                 const (Dbt) *prevKey = cast(const (Dbt) *) _prevKey;
1063                 const (Dbt) *prevData = cast(const (Dbt) *) _prevData;
1064                 Dbt *compressed = cast(Dbt *) _compressed;
1065                 Dbt *destKey = cast(Dbt *) _destKey;
1066                 Dbt *destData = cast(Dbt *) _destData;
1067                 return db.bt_decompress_callback_refer(db, prevKey, prevData, 
1068                         compressed, destKey, destData);
1069         }
1070     }
1071 
1072     void set_bt_compress(int function(Db db, const (Dbt) *prevKey, const (Dbt) *prevData, 
1073                 const (Dbt) *key, const (Dbt) *data, Dbt *dest) bt_compress_fcn,
1074                 int function(Db db, const (Dbt) *prevKey, 
1075                     const (Dbt) *prevData, Dbt *compressed, Dbt *destKey, 
1076                     Dbt *destData) bt_decompress_fcn)
1077     {
1078         if (opened < 0) {
1079             throw new DbWrongUsingException("Operation on closed Db");
1080         }
1081         if (opened > 0) {
1082             throw new DbWrongUsingException("Configuration of opened Db");
1083         }
1084         bt_compress_callback_refer = bt_compress_fcn;
1085         bt_decompress_callback_refer = bt_decompress_fcn;
1086         auto ret = db.set_bt_compress(db, 
1087                 bt_compress_fcn?&bt_compress_callback:null,
1088                 bt_decompress_fcn?&bt_decompress_callback:null);
1089         DbRetCodeToException(ret, dbenv);
1090         assert(ret == 0);
1091     }
1092 
1093     void set_bt_minkey(uint32_t bt_minkey)
1094     {
1095         if (opened < 0) {
1096             throw new DbWrongUsingException("Operation on closed Db");
1097         }
1098         if (opened > 0) {
1099             throw new DbWrongUsingException("Configuration of opened Db");
1100         }
1101         auto ret = db.set_bt_minkey(db, bt_minkey);
1102         DbRetCodeToException(ret, dbenv);
1103         assert(ret == 0);
1104     }
1105 
1106     uint32_t get_bt_minkey()
1107     {
1108         if (opened < 0) {
1109             throw new DbWrongUsingException("Get configuration on closed Db");
1110         }
1111         uint32_t res;
1112         auto ret = db.get_bt_minkey(db, &res);
1113         DbRetCodeToException(ret, dbenv);
1114         assert(ret == 0);
1115         return res;
1116     }
1117 
1118     private
1119     {
1120         size_t function(Db, const (Dbt) *dbt1, const (Dbt) *dbt2) bt_prefix_callback_refer;
1121 
1122         extern (C) static size_t bt_prefix_callback(DB *_db, const (DBT) *_dbt1, const (DBT) *_dbt2)
1123         {
1124                 Db db = from_DB(_db);
1125                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
1126                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
1127                 return db.bt_prefix_callback_refer(db, dbt1, dbt2);
1128         }
1129     }
1130 
1131     void set_bt_prefix(size_t function(Db, const (Dbt) *dbt1, const (Dbt) *dbt2) bt_prefix_fcn)
1132     {
1133         if (opened < 0) {
1134             throw new DbWrongUsingException("Operation on closed Db");
1135         }
1136         if (opened > 0) {
1137             throw new DbWrongUsingException("Configuration of opened Db");
1138         }
1139         bt_prefix_callback_refer = bt_prefix_fcn;
1140         auto ret = db.set_bt_prefix(db, &bt_prefix_callback);
1141         DbRetCodeToException(ret, dbenv);
1142         assert(ret == 0);
1143     }
1144 
1145     void set_re_delim(int re_delim)
1146     {
1147         if (opened < 0) {
1148             throw new DbWrongUsingException("Operation on closed Db");
1149         }
1150         if (opened > 0) {
1151             throw new DbWrongUsingException("Configuration of opened Db");
1152         }
1153         auto ret = db.set_re_delim(db, re_delim);
1154         DbRetCodeToException(ret, dbenv);
1155         assert(ret == 0);
1156     }
1157 
1158     int get_re_delim()
1159     {
1160         if (opened <= 0) {
1161             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1162         }
1163         int res;
1164         auto ret = db.get_re_delim(db, &res);
1165         DbRetCodeToException(ret, dbenv);
1166         assert(ret == 0);
1167         return res;
1168     }
1169 
1170     void set_re_len(uint32_t re_len)
1171     {
1172         if (opened < 0) {
1173             throw new DbWrongUsingException("Operation on closed Db");
1174         }
1175         if (opened > 0) {
1176             throw new DbWrongUsingException("Configuration of opened Db");
1177         }
1178         auto ret = db.set_re_len(db, re_len);
1179         DbRetCodeToException(ret, dbenv);
1180         assert(ret == 0);
1181     }
1182 
1183     uint32_t get_re_len()
1184     {
1185         if (opened <= 0) {
1186             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1187         }
1188         uint32_t res;
1189         auto ret = db.get_re_len(db, &res);
1190         DbRetCodeToException(ret, dbenv);
1191         assert(ret == 0);
1192         return res;
1193     }
1194 
1195     void set_re_pad(int re_pad)
1196     {
1197         if (opened < 0) {
1198             throw new DbWrongUsingException("Operation on closed Db");
1199         }
1200         if (opened > 0) {
1201             throw new DbWrongUsingException("Configuration of opened Db");
1202         }
1203         auto ret = db.set_re_pad(db, re_pad);
1204         DbRetCodeToException(ret, dbenv);
1205         assert(ret == 0);
1206     }
1207 
1208     int get_re_pad()
1209     {
1210         if (opened <= 0) {
1211             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1212         }
1213         int res;
1214         auto ret = db.get_re_pad(db, &res);
1215         DbRetCodeToException(ret, dbenv);
1216         assert(ret == 0);
1217         return res;
1218     }
1219 
1220     void set_re_source(string source)
1221     {
1222         if (opened < 0) {
1223             throw new DbWrongUsingException("Operation on closed Db");
1224         }
1225         if (opened > 0) {
1226             throw new DbWrongUsingException("Configuration of opened Db");
1227         }
1228         auto ret = db.set_re_source(db, source.toStringz());
1229         DbRetCodeToException(ret, dbenv);
1230         assert(ret == 0);
1231     }
1232 
1233     string get_re_source()
1234     {
1235         if (opened <= 0) {
1236             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1237         }
1238         const (char) *res;
1239         auto ret = db.get_re_source(db, &res);
1240         DbRetCodeToException(ret, dbenv);
1241         assert(ret == 0);
1242         return to!string(res);
1243     }
1244 
1245     /* Hash Configuration */
1246     private
1247     {
1248 version(VERSION_6)
1249 {
1250         int function(Db db, const (Dbt) *dbt1,
1251                 const (Dbt) *dbt2, size_t *locp) compare_callback_refer;
1252 
1253         extern (C) static int compare_callback(DB *_db,
1254                 const (DBT) *_dbt1, const (DBT) *_dbt2, size_t *locp)
1255         {
1256                 Db db = from_DB(_db);
1257                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
1258                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
1259                 return db.compare_callback_refer(db, dbt1, dbt2, locp);
1260         }
1261 
1262         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2, size_t *locp) compare_fcn_t;
1263 }
1264 else
1265 {
1266         int function(Db db, const (Dbt) *dbt1,
1267                 const (Dbt) *dbt2) compare_callback_refer;
1268 
1269         extern (C) static int compare_callback(DB *_db,
1270                 const (DBT) *_dbt1, const (DBT) *_dbt2)
1271         {
1272                 Db db = from_DB(_db);
1273                 const (Dbt) *dbt1 = cast(const (Dbt) *) _dbt1;
1274                 const (Dbt) *dbt2 = cast(const (Dbt) *) _dbt2;
1275                 return db.compare_callback_refer(db, dbt1, dbt2);
1276         }
1277 
1278         alias int function(Db db, const (Dbt) *dbt1, const (Dbt) *dbt2) compare_fcn_t;
1279 }
1280     }
1281 
1282     void set_h_compare(compare_fcn_t compare_fcn)
1283     {
1284         if (opened < 0) {
1285             throw new DbWrongUsingException("Operation on closed Db");
1286         }
1287         if (opened > 0) {
1288             throw new DbWrongUsingException("Configuration of opened Db");
1289         }
1290         compare_callback_refer = compare_fcn;
1291         auto ret = db.set_h_compare(db, compare_fcn?&compare_callback:null);
1292         DbRetCodeToException(ret, dbenv);
1293         assert(ret == 0);
1294     }
1295 
1296     void set_h_ffactor(uint32_t h_ffactor)
1297     {
1298         if (opened < 0) {
1299             throw new DbWrongUsingException("Operation on closed Db");
1300         }
1301         if (opened > 0) {
1302             throw new DbWrongUsingException("Configuration of opened Db");
1303         }
1304         auto ret = db.set_h_ffactor(db, h_ffactor);
1305         DbRetCodeToException(ret, dbenv);
1306         assert(ret == 0);
1307     }
1308 
1309     uint32_t get_h_ffactor()
1310     {
1311         if (opened < 0) {
1312             throw new DbWrongUsingException("Get configuration on closed Db");
1313         }
1314         uint32_t res;
1315         auto ret = db.get_h_ffactor(db, &res);
1316         DbRetCodeToException(ret, dbenv);
1317         assert(ret == 0);
1318         return res;
1319     }
1320 
1321     private
1322     {
1323         uint32_t function(Db dbp, const (ubyte)[] bytes) h_hash_callback_refer;
1324 
1325         extern (C) static uint32_t h_hash_callback(DB *_db, const (void) *_bytes, uint32_t length)
1326         {
1327                 Db db = from_DB(_db);
1328                 const (ubyte)[] bytes = (cast(ubyte*) _bytes)[0..length];
1329                 return db.h_hash_callback_refer(db, bytes);
1330         }
1331     }
1332 
1333     void set_h_hash(uint32_t function(Db dbp, const (ubyte)[] bytes) h_hash_fcn)
1334     {
1335         if (opened < 0) {
1336             throw new DbWrongUsingException("Operation on closed Db");
1337         }
1338         if (opened > 0) {
1339             throw new DbWrongUsingException("Configuration of opened Db");
1340         }
1341         h_hash_callback_refer = h_hash_fcn;
1342         auto ret = db.set_h_hash(db, &h_hash_callback);
1343         DbRetCodeToException(ret, dbenv);
1344         assert(ret == 0);
1345     }
1346 
1347     void set_h_nelem(uint32_t h_nelem)
1348     {
1349         if (opened < 0) {
1350             throw new DbWrongUsingException("Operation on closed Db");
1351         }
1352         if (opened > 0) {
1353             throw new DbWrongUsingException("Configuration of opened Db");
1354         }
1355         auto ret = db.set_h_nelem(db, h_nelem);
1356         DbRetCodeToException(ret, dbenv);
1357         assert(ret == 0);
1358     }
1359 
1360     uint32_t get_h_nelem(uint32_t *h_nelemp)
1361     {
1362         if (opened < 0) {
1363             throw new DbWrongUsingException("Get configuration on closed Db");
1364         }
1365         uint32_t res;
1366         auto ret = db.get_h_nelem(db, &res);
1367         DbRetCodeToException(ret, dbenv);
1368         assert(ret == 0);
1369         return res;
1370     }
1371 
1372     /* Queue Configuration */
1373     void set_q_extentsize(uint32_t extentsize)
1374     {
1375         if (opened < 0) {
1376             throw new DbWrongUsingException("Operation on closed Db");
1377         }
1378         if (opened > 0) {
1379             throw new DbWrongUsingException("Configuration of opened Db");
1380         }
1381         auto ret = db.set_q_extentsize(db, extentsize);
1382         DbRetCodeToException(ret, dbenv);
1383         assert(ret == 0);
1384     }
1385 
1386     uint32_t get_q_extentsize()
1387     {
1388         if (opened <= 0) {
1389             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1390         }
1391         uint32_t res;
1392         auto ret = db.get_q_extentsize(db, &res);
1393         DbRetCodeToException(ret, dbenv);
1394         assert(ret == 0);
1395         return res;
1396     }
1397 
1398     /* Heap */
1399     void set_heapsize(uint32_t gbytes, uint32_t bytes, uint32_t flags = 0)
1400     {
1401         if (opened < 0) {
1402             throw new DbWrongUsingException("Operation on closed Db");
1403         }
1404         if (opened > 0) {
1405             throw new DbWrongUsingException("Configuration of opened Db");
1406         }
1407         auto ret = db.set_heapsize(db, gbytes, bytes, flags);
1408         DbRetCodeToException(ret, dbenv);
1409         assert(ret == 0);
1410     }
1411 
1412     void set_heapsize(uint64_t bytes, uint32_t flags = 0)
1413     {
1414         uint32_t _gbytes = cast(uint32_t) bytes/(1024*1024*1024);
1415         uint32_t _bytes = bytes%(1024*1024*1024);
1416         set_heapsize(_gbytes, _bytes, flags);
1417     }
1418 
1419     void get_heapsize(ref uint32_t gbytes, ref uint32_t bytes)
1420     {
1421         if (opened <= 0) {
1422             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1423         }
1424         auto ret = db.get_heapsize(db, &gbytes, &bytes);
1425         DbRetCodeToException(ret, dbenv);
1426         assert(ret == 0);
1427     }
1428 
1429     uint64_t get_heapsize()
1430     {
1431         uint32_t _gbytes;
1432         uint32_t _bytes;
1433         get_heapsize(_gbytes, _bytes);
1434         return (1024UL*1024*1024)*_gbytes + _bytes;
1435     }
1436 
1437     void set_heap_regionsize(uint32_t npages)
1438     {
1439         if (opened < 0) {
1440             throw new DbWrongUsingException("Operation on closed Db");
1441         }
1442         if (opened > 0) {
1443             throw new DbWrongUsingException("Configuration of opened Db");
1444         }
1445         auto ret = db.set_heap_regionsize(db, npages);
1446         DbRetCodeToException(ret, dbenv);
1447         assert(ret == 0);
1448     }
1449 
1450     uint32_t get_heap_regionsize()
1451     {
1452         if (opened <= 0) {
1453             throw new DbWrongUsingException("Get configuration on closed or not opened Db");
1454         }
1455         uint32_t res;
1456         auto ret = db.get_heap_regionsize(db, &res);
1457         DbRetCodeToException(ret, dbenv);
1458         assert(ret == 0);
1459         return res;
1460     }
1461 
1462     /* Memory Pools and Related Methods */
1463     DbMpoolfile get_mpf()
1464     {
1465         if (opened < 0) {
1466             throw new DbWrongUsingException("Operation on closed Db");
1467         }
1468         DB_MPOOLFILE *res = db.get_mpf(db);
1469         return new DbMpoolfile(res, dbenv);
1470     }
1471 
1472     /* Transaction Subsystem Configuration */
1473     int get_transactional()
1474     {
1475         if (opened < 0) {
1476             throw new DbWrongUsingException("Operation on closed Db");
1477         }
1478         return db.get_transactional(db);
1479     }
1480 
1481     /* BLOB Configuration */
1482 version(VERSION_6)
1483 {
1484     void set_blob_dir(string dir)
1485     {
1486         if (opened < 0) {
1487             throw new DbWrongUsingException("Configuration on closed Db");
1488         }
1489         if (opened > 0) {
1490             throw new DbWrongUsingException("Configuration of opened Db");
1491         }
1492         auto ret = db.set_blob_dir(db, dir.toStringz());
1493         DbRetCodeToException(ret, dbenv);
1494         assert(ret == 0);
1495     }
1496 
1497     string get_blob_dir()
1498     {
1499         if (opened < 0) {
1500             throw new DbWrongUsingException("Get configuration on closed Db");
1501         }
1502         const (char) *res;
1503         auto ret = db.get_blob_dir(db, &res);
1504         DbRetCodeToException(ret, dbenv);
1505         assert(ret == 0);
1506         return to!string(res);
1507     }
1508 
1509     void set_blob_threshold(uint32_t bytes, uint32_t flags = 0)
1510     {
1511         if (opened < 0) {
1512             throw new DbWrongUsingException("Configuration on closed Db");
1513         }
1514         if (opened > 0) {
1515             throw new DbWrongUsingException("Configuration of opened Db");
1516         }
1517         auto ret = db.set_blob_threshold(db, bytes, flags);
1518         DbRetCodeToException(ret, dbenv);
1519         assert(ret == 0);
1520     }
1521 
1522     uint32_t get_blob_threshold()
1523     {
1524         if (opened < 0) {
1525             throw new DbWrongUsingException("Get configuration on closed Db");
1526         }
1527         uint32_t res;
1528         auto ret = db.get_blob_threshold(db, &res);
1529         DbRetCodeToException(ret, dbenv);
1530         assert(ret == 0);
1531         return res;
1532     }
1533 }
1534 }
1535 
1536 void db_copy(DbEnv dbenv, string dbfile, string target, 
1537         string password)
1538 {
1539         if (dbenv._opened < 0) {
1540             throw new DbWrongUsingException("Operation on closed DbEnv");
1541         }
1542         auto ret = berkeleydb.c.db_copy(dbenv?dbenv._DB_ENV:null, dbfile.toStringz(), 
1543                 target.toStringz(), password.toStringz());
1544         DbRetCodeToException(ret, dbenv);
1545         assert(ret == 0);
1546 }
1547 
1548 unittest
1549 {
1550     auto db = new Db(null, 0);
1551     db.set_partition_dirs(["a", "b", "d"]);
1552     assert(db.get_partition_dirs() == ["a", "b", "d"]);
1553 }
1554 
1555 unittest
1556 {
1557     import std.file;
1558 
1559     try{
1560         rmdirRecurse("/tmp/berkeleydb.test");
1561     } catch (FileException file)
1562     {
1563     }
1564 
1565     try{
1566         mkdir("/tmp/berkeleydb.test");
1567     } catch (FileException file)
1568     {
1569     }
1570     
1571     struct customer {
1572            char[4] cust_id;
1573            char[15] last_name;
1574            char[15] first_name;
1575     }
1576     struct order {
1577            char[4] order_id;
1578            int order_number;
1579            char[4] cust_id;
1580     }
1581 
1582     DbEnv dbenv = new DbEnv(0);
1583 
1584     uint32_t env_flags = DB_CREATE |    /* Create the environment if it does 
1585                                 * not already exist. */
1586                 DB_INIT_TXN  | /* Initialize transactions */
1587                 DB_INIT_LOCK | /* Initialize locking. */
1588                 DB_INIT_LOG  | /* Initialize logging */
1589                 DB_INIT_MPOOL; /* Initialize the in-memory cache. */
1590 
1591     dbenv.open("/tmp/berkeleydb.test/", env_flags, octal!666);
1592 
1593     Db db = new Db(dbenv, 0);
1594     db.open(null, "orders.db", null, DB_BTREE, DB_CREATE, octal!600);
1595 
1596     Db sdb = new Db(dbenv, 0);
1597     sdb.set_flags(DB_DUP | DB_DUPSORT);
1598 
1599     sdb.open(null, "orders_cust_ids.db", null, DB_BTREE, DB_CREATE, octal!600);
1600     
1601     static int getcustid(Db secondary, ref const (Dbt) pkey, ref const (Dbt) pdata, out Dbt skey)
1602     {
1603            /*
1604             * Since the secondary key is a simple structure member of the
1605             * record, we don't have to do anything fancy to return it.  If
1606             * we have composite keys that need to be constructed from the
1607             * record, rather than simply pointing into it, then the user's
1608             * function might need to allocate space and copy data.  In
1609             * this case, the DB_DBT_APPMALLOC flag should be set in the
1610             * secondary key DBT.
1611             */
1612            const order *o = pdata.to!(const order *)();
1613            skey = o.cust_id;
1614            return 0;
1615     }
1616 
1617     db.associate(null, sdb, &getcustid, 0);
1618 
1619     Db fdb = new Db(dbenv, 0);
1620     fdb.open(null, "customers.db", null, DB_BTREE, DB_CREATE, octal!600);
1621     fdb.associate_foreign(sdb, null, DB_FOREIGN_CASCADE);
1622 
1623     string PadString(string str, int len)
1624     {
1625         while (str.length < len)
1626             str ~= '\0';
1627         return str;
1628     }
1629 
1630     Dbt key, data;
1631     customer cust;
1632     cust.cust_id = "0001";
1633     cust.last_name = PadString("Last", 15);
1634     cust.first_name = PadString("First", 15);
1635     key = cust.cust_id;
1636     data = cust;
1637     int res = fdb.put(null, &key, &data, 0);
1638     assert(res == 0);
1639 
1640     cust.cust_id = "0002";
1641     cust.last_name = PadString("Petrov", 15);
1642     cust.first_name = PadString("Ivan", 15);
1643     res = fdb.put(null, &key, &data, 0);
1644     assert(res == 0);
1645 
1646     cust.cust_id = "0003";
1647     cust.last_name = PadString("Smeyana", 15);
1648     cust.first_name = PadString("Lena", 15);
1649     res = fdb.put(null, &key, &data, 0);
1650     assert(res == 0);
1651     
1652     order ord;
1653     ord.order_id = "0001";
1654     ord.order_number = 1;
1655     ord.cust_id = "0001";
1656     key = ord.order_id;
1657     data = ord;
1658     res = db.put(null, &key, &data, 0);
1659     assert(res == 0);
1660 
1661     ord.order_id = "0002";
1662     ord.order_number = 2;
1663     ord.cust_id = "0001";
1664     res = db.put(null, &key, &data, 0);
1665     assert(res == 0);
1666 
1667     ord.order_id = "0003";
1668     ord.order_number = 3;
1669     ord.cust_id = "0002";
1670     res = db.put(null, &key, &data, 0);
1671     assert(res == 0);
1672 
1673     ord.order_id = "0004";
1674     ord.order_number = 4;
1675     ord.cust_id = "0005";
1676     int except = 0;
1677     try
1678     {
1679         res = db.put(null, &key, &data, 0);
1680         assert(res == 0);
1681     }
1682     catch (DbException exc)
1683     {
1684         assert(exc.dberrno == DB_FOREIGN_CONFLICT);
1685         except = 1;
1686     }
1687     assert(except == 1);
1688 
1689     Dbc cursor = fdb.cursor(null, 0);
1690     res = cursor.get(&key, &data, DB_NEXT);
1691     assert(res == 0);
1692     cust.cust_id = "0001";
1693     cust.last_name = PadString("Last", 15);
1694     cust.first_name = PadString("First", 15);
1695     char[4] cust_key = key.to!(char[])();
1696     customer *cust_p = data.to!(customer*)();
1697     assert(cust_key == cust.cust_id);
1698     assert(*cust_p == cust);
1699 
1700     res = cursor.get(&key, &data, DB_NEXT);
1701     assert(res == 0);
1702     cust.cust_id = "0002";
1703     cust.last_name = PadString("Petrov", 15);
1704     cust.first_name = PadString("Ivan", 15);
1705     cust_key = key.to!(char[])();
1706     cust_p = data.to!(customer*)();
1707     assert(cust_key == cust.cust_id);
1708     assert(*cust_p == cust);
1709 
1710     res = cursor.get(&key, &data, DB_NEXT);
1711     assert(res == 0);
1712     cust.cust_id = "0003";
1713     cust.last_name = PadString("Smeyana", 15);
1714     cust.first_name = PadString("Lena", 15);
1715     cust_key = key.to!(char[])();
1716     cust_p = data.to!(customer*)();
1717     assert(cust_key == cust.cust_id);
1718     assert(*cust_p == cust);
1719 
1720     res = cursor.get(&key, &data, DB_NEXT);
1721     assert(res == DB_NOTFOUND);
1722 
1723     cursor.close();
1724     fdb.close(0);
1725     sdb.close(0);
1726     db.close(0);
1727 
1728     dbenv.close(0);
1729 }