1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: cxx_db.cpp,v 12.22 2008/01/08 20:58:09 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13#include "db_cxx.h"
14#include "dbinc/cxx_int.h"
15
16#include "dbinc/db_page.h"
17#include "dbinc_auto/db_auto.h"
18#include "dbinc_auto/crdel_auto.h"
19#include "dbinc/db_dispatch.h"
20#include "dbinc_auto/db_ext.h"
21#include "dbinc_auto/common_ext.h"
22
23// Helper macros for simple methods that pass through to the
24// underlying C method. It may return an error or raise an exception.
25// Note this macro expects that input _argspec is an argument
26// list element (e.g., "char *arg") and that _arglist is the arguments
27// that should be passed through to the C method (e.g., "(db, arg)")
28//
29#define	DB_METHOD(_name, _argspec, _arglist, _retok)			\
30int Db::_name _argspec							\
31{									\
32	int ret;							\
33	DB *db = unwrap(this);						\
34									\
35	ret = db->_name _arglist;					\
36	if (!_retok(ret))						\
37		DB_ERROR(dbenv_, "Db::" # _name, ret, error_policy());	\
38	return (ret);							\
39}
40
41#define	DB_DESTRUCTOR(_name, _argspec, _arglist, _retok)		\
42int Db::_name _argspec							\
43{									\
44	int ret;							\
45	DB *db = unwrap(this);						\
46									\
47	if (!db) {							\
48		DB_ERROR(dbenv_, "Db::" # _name, EINVAL, error_policy());	\
49		return (EINVAL);					\
50	}								\
51	ret = db->_name _arglist;					\
52	cleanup();							\
53	if (!_retok(ret))						\
54		DB_ERROR(dbenv_, "Db::" # _name, ret, error_policy());	\
55	return (ret);							\
56}
57
58#define	DB_METHOD_QUIET(_name, _argspec, _arglist)			\
59int Db::_name _argspec							\
60{									\
61	DB *db = unwrap(this);						\
62									\
63	return (db->_name _arglist);					\
64}
65
66#define	DB_METHOD_VOID(_name, _argspec, _arglist)			\
67void Db::_name _argspec							\
68{									\
69	DB *db = unwrap(this);						\
70									\
71	db->_name _arglist;						\
72}
73
74// A truism for the Db object is that there is a valid
75// DB handle from the constructor until close().
76// After the close, the DB handle is invalid and
77// no operations are permitted on the Db (other than
78// destructor).  Leaving the Db handle open and not
79// doing a close is generally considered an error.
80//
81// We used to allow Db objects to be closed and reopened.
82// This implied always keeping a valid DB object, and
83// coordinating the open objects between Db/DbEnv turned
84// out to be overly complicated.  Now we do not allow this.
85
86Db::Db(DbEnv *dbenv, u_int32_t flags)
87:	imp_(0)
88,	dbenv_(dbenv)
89,	mpf_(0)
90,	construct_error_(0)
91,	flags_(0)
92,	construct_flags_(flags)
93,	append_recno_callback_(0)
94,	associate_callback_(0)
95,	bt_compare_callback_(0)
96,	bt_prefix_callback_(0)
97,	dup_compare_callback_(0)
98,	feedback_callback_(0)
99,	h_compare_callback_(0)
100,	h_hash_callback_(0)
101{
102	if (dbenv_ == 0)
103		flags_ |= DB_CXX_PRIVATE_ENV;
104
105	if ((construct_error_ = initialize()) != 0)
106		DB_ERROR(dbenv_, "Db::Db", construct_error_, error_policy());
107}
108
109// If the DB handle is still open, we close it.  This is to make stack
110// allocation of Db objects easier so that they are cleaned up in the error
111// path.  If the environment was closed prior to this, it may cause a trap, but
112// an error message is generated during the environment close.  Applications
113// should call close explicitly in normal (non-exceptional) cases to check the
114// return value.
115//
116Db::~Db()
117{
118	DB *db;
119
120	db = unwrap(this);
121	if (db != NULL) {
122		(void)db->close(db, 0);
123		cleanup();
124	}
125}
126
127// private method to initialize during constructor.
128// initialize must create a backing DB object,
129// and if that creates a new DB_ENV, it must be tied to a new DbEnv.
130//
131int Db::initialize()
132{
133	DB *db;
134	DB_ENV *cenv = unwrap(dbenv_);
135	int ret;
136	u_int32_t cxx_flags;
137
138	cxx_flags = construct_flags_ & DB_CXX_NO_EXCEPTIONS;
139
140	// Create a new underlying DB object.
141	// We rely on the fact that if a NULL DB_ENV* is given,
142	// one is allocated by DB.
143	//
144	if ((ret = db_create(&db, cenv,
145			     construct_flags_ & ~cxx_flags)) != 0)
146		return (ret);
147
148	// Associate the DB with this object
149	imp_ = db;
150	db->api_internal = this;
151
152	// Create a new DbEnv from a DB_ENV* if it was created locally.
153	// It is deleted in Db::close().
154	//
155	if ((flags_ & DB_CXX_PRIVATE_ENV) != 0)
156		dbenv_ = new DbEnv(db->dbenv, cxx_flags);
157
158	// Create a DbMpoolFile from the DB_MPOOLFILE* in the DB handle.
159	mpf_ = new DbMpoolFile();
160	mpf_->imp_ = db->mpf;
161
162	return (0);
163}
164
165// private method to cleanup after destructor or during close.
166// If the environment was created by this Db object, we need to delete it.
167//
168void Db::cleanup()
169{
170	if (imp_ != 0) {
171		imp_ = 0;
172
173		// we must dispose of the DbEnv object if
174		// we created it.  This will be the case
175		// if a NULL DbEnv was passed into the constructor.
176		// The underlying DB_ENV object will be inaccessible
177		// after the close, so we must clean it up now.
178		//
179		if ((flags_ & DB_CXX_PRIVATE_ENV) != 0) {
180			dbenv_->cleanup();
181			delete dbenv_;
182			dbenv_ = 0;
183		}
184
185		delete mpf_;
186	}
187}
188
189// Return a tristate value corresponding to whether we should
190// throw exceptions on errors:
191//   ON_ERROR_RETURN
192//   ON_ERROR_THROW
193//   ON_ERROR_UNKNOWN
194//
195int Db::error_policy()
196{
197	if (dbenv_ != NULL)
198		return (dbenv_->error_policy());
199	else {
200		// If the dbenv_ is null, that means that the user
201		// did not attach an environment, so the correct error
202		// policy can be deduced from constructor flags
203		// for this Db.
204		//
205		if ((construct_flags_ & DB_CXX_NO_EXCEPTIONS) != 0) {
206			return (ON_ERROR_RETURN);
207		}
208		else {
209			return (ON_ERROR_THROW);
210		}
211	}
212}
213
214DB_DESTRUCTOR(close, (u_int32_t flags), (db, flags), DB_RETOK_STD)
215DB_METHOD(compact, (DbTxn *txnid, Dbt *start, Dbt *stop,
216    DB_COMPACT *c_data, u_int32_t flags, Dbt *end),
217    (db, unwrap(txnid), start, stop, c_data, flags, end), DB_RETOK_STD)
218
219// The following cast implies that Dbc can be no larger than DBC
220DB_METHOD(cursor, (DbTxn *txnid, Dbc **cursorp, u_int32_t flags),
221    (db, unwrap(txnid), (DBC **)cursorp, flags),
222    DB_RETOK_STD)
223
224DB_METHOD(del, (DbTxn *txnid, Dbt *key, u_int32_t flags),
225    (db, unwrap(txnid), key, flags),
226    DB_RETOK_DBDEL)
227
228void Db::err(int error, const char *format, ...)
229{
230	DB *db = unwrap(this);
231
232	DB_REAL_ERR(db->dbenv, error, DB_ERROR_SET, 1, format);
233}
234
235void Db::errx(const char *format, ...)
236{
237	DB *db = unwrap(this);
238
239	DB_REAL_ERR(db->dbenv, 0, DB_ERROR_NOT_SET, 1, format);
240}
241
242DB_METHOD(exists, (DbTxn *txnid, Dbt *key, u_int32_t flags),
243    (db, unwrap(txnid), key, flags), DB_RETOK_EXISTS)
244
245DB_METHOD(fd, (int *fdp), (db, fdp), DB_RETOK_STD)
246
247int Db::get(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags)
248{
249	DB *db = unwrap(this);
250	int ret;
251
252	ret = db->get(db, unwrap(txnid), key, value, flags);
253
254	if (!DB_RETOK_DBGET(ret)) {
255		if (ret == DB_BUFFER_SMALL)
256			DB_ERROR_DBT(dbenv_, "Db::get", value, error_policy());
257		else
258			DB_ERROR(dbenv_, "Db::get", ret, error_policy());
259	}
260
261	return (ret);
262}
263
264int Db::get_byteswapped(int *isswapped)
265{
266	DB *db = (DB *)unwrapConst(this);
267	return (db->get_byteswapped(db, isswapped));
268}
269
270DbEnv *Db::get_env()
271{
272	DB *db = (DB *)unwrapConst(this);
273	DB_ENV *dbenv = db->get_env(db);
274	return (dbenv != NULL ? DbEnv::get_DbEnv(dbenv) : NULL);
275}
276
277DbMpoolFile *Db::get_mpf()
278{
279	return (mpf_);
280}
281
282DB_METHOD(get_dbname, (const char **filenamep, const char **dbnamep),
283    (db, filenamep, dbnamep), DB_RETOK_STD)
284
285DB_METHOD(get_open_flags, (u_int32_t *flagsp), (db, flagsp), DB_RETOK_STD)
286
287int Db::get_type(DBTYPE *dbtype)
288{
289	DB *db = (DB *)unwrapConst(this);
290	return (db->get_type(db, dbtype));
291}
292
293// Dbc is a "compatible" subclass of DBC - that is, no virtual functions
294// or even extra data members, so these casts, although technically
295// non-portable, "should" always be okay.
296DB_METHOD(join, (Dbc **curslist, Dbc **cursorp, u_int32_t flags),
297    (db, (DBC **)curslist, (DBC **)cursorp, flags), DB_RETOK_STD)
298
299DB_METHOD(key_range,
300    (DbTxn *txnid, Dbt *key, DB_KEY_RANGE *results, u_int32_t flags),
301    (db, unwrap(txnid), key, results, flags), DB_RETOK_STD)
302
303// If an error occurred during the constructor, report it now.
304// Otherwise, call the underlying DB->open method.
305//
306int Db::open(DbTxn *txnid, const char *file, const char *database,
307	     DBTYPE type, u_int32_t flags, int mode)
308{
309	int ret;
310	DB *db = unwrap(this);
311
312	if (construct_error_ != 0)
313		ret = construct_error_;
314	else
315		ret = db->open(db, unwrap(txnid), file, database, type, flags,
316		    mode);
317
318	if (!DB_RETOK_STD(ret))
319		DB_ERROR(dbenv_, "Db::open", ret, error_policy());
320
321	return (ret);
322}
323
324int Db::pget(DbTxn *txnid, Dbt *key, Dbt *pkey, Dbt *value, u_int32_t flags)
325{
326	DB *db = unwrap(this);
327	int ret;
328
329	ret = db->pget(db, unwrap(txnid), key, pkey, value, flags);
330
331	/* The logic here is identical to Db::get - reuse the macro. */
332	if (!DB_RETOK_DBGET(ret)) {
333		if (ret == DB_BUFFER_SMALL && DB_OVERFLOWED_DBT(value))
334			DB_ERROR_DBT(dbenv_, "Db::pget", value, error_policy());
335		else
336			DB_ERROR(dbenv_, "Db::pget", ret, error_policy());
337	}
338
339	return (ret);
340}
341
342DB_METHOD(put, (DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags),
343    (db, unwrap(txnid), key, value, flags), DB_RETOK_DBPUT)
344
345DB_DESTRUCTOR(rename,
346    (const char *file, const char *database, const char *newname,
347    u_int32_t flags),
348    (db, file, database, newname, flags), DB_RETOK_STD)
349
350DB_DESTRUCTOR(remove, (const char *file, const char *database, u_int32_t flags),
351    (db, file, database, flags), DB_RETOK_STD)
352
353DB_METHOD(truncate, (DbTxn *txnid, u_int32_t *countp, u_int32_t flags),
354    (db, unwrap(txnid), countp, flags), DB_RETOK_STD)
355
356DB_METHOD(stat, (DbTxn *txnid, void *sp, u_int32_t flags),
357    (db, unwrap(txnid), sp, flags), DB_RETOK_STD)
358
359DB_METHOD(stat_print, (u_int32_t flags), (db, flags), DB_RETOK_STD)
360
361DB_METHOD(sync, (u_int32_t flags), (db, flags), DB_RETOK_STD)
362
363DB_METHOD(upgrade,
364    (const char *name, u_int32_t flags), (db, name, flags), DB_RETOK_STD)
365
366////////////////////////////////////////////////////////////////////////
367//
368// callbacks
369//
370// *_intercept_c are 'glue' functions that must be declared
371// as extern "C" so to be typesafe.  Using a C++ method, even
372// a static class method with 'correct' arguments, will not pass
373// the test; some picky compilers do not allow mixing of function
374// pointers to 'C' functions with function pointers to C++ functions.
375//
376// One wart with this scheme is that the *_callback_ method pointer
377// must be declared public to be accessible by the C intercept.
378// It's possible to accomplish the goal without this, and with
379// another public transfer method, but it's just too much overhead.
380// These callbacks are supposed to be *fast*.
381//
382// The DBTs we receive in these callbacks from the C layer may be
383// manufactured there, but we want to treat them as a Dbts.
384// Technically speaking, these DBTs were not constructed as a Dbts,
385// but it should be safe to cast them as such given that Dbt is a
386// *very* thin extension of the DBT.  That is, Dbt has no additional
387// data elements, does not use virtual functions, virtual inheritance,
388// multiple inheritance, RTI, or any other language feature that
389// causes the structure to grow or be displaced.  Although this may
390// sound risky, a design goal of C++ is complete structure
391// compatibility with C, and has the philosophy 'if you don't use it,
392// you shouldn't incur the overhead'.  If the C/C++ compilers you're
393// using on a given machine do not have matching struct layouts, then
394// a lot more things will be broken than just this.
395//
396// The alternative, creating a Dbt here in the callback, and populating
397// it from the DBT, is just too slow and cumbersome to be very useful.
398
399// These macros avoid a lot of boilerplate code for callbacks
400
401#define	DB_CALLBACK_C_INTERCEPT(_name, _rettype, _cargspec,		\
402    _return, _cxxargs)							\
403extern "C" _rettype _db_##_name##_intercept_c _cargspec			\
404{									\
405	Db *cxxthis;							\
406									\
407	/* We don't have a dbenv handle at this point. */		\
408	DB_ASSERT(NULL, cthis != NULL);					\
409	cxxthis = Db::get_Db(cthis);					\
410	DB_ASSERT(cthis->dbenv->env, cxxthis != NULL);			\
411	DB_ASSERT(cthis->dbenv->env, cxxthis->_name##_callback_ != 0);	\
412									\
413	_return (*cxxthis->_name##_callback_) _cxxargs;			\
414}
415
416#define	DB_SET_CALLBACK(_cxxname, _name, _cxxargspec, _cb)		\
417int Db::_cxxname _cxxargspec						\
418{									\
419	DB *cthis = unwrap(this);					\
420									\
421	_name##_callback_ = _cb;					\
422	return ((*(cthis->_cxxname))(cthis,				\
423	    (_cb) ? _db_##_name##_intercept_c : NULL));			\
424}
425
426/* associate callback - doesn't quite fit the pattern because of the flags */
427DB_CALLBACK_C_INTERCEPT(associate,
428    int, (DB *cthis, const DBT *key, const DBT *data, DBT *retval),
429    return, (cxxthis, Dbt::get_const_Dbt(key), Dbt::get_const_Dbt(data),
430    Dbt::get_Dbt(retval)))
431
432int Db::associate(DbTxn *txn, Db *secondary, int (*callback)(Db *, const Dbt *,
433	const Dbt *, Dbt *), u_int32_t flags)
434{
435	DB *cthis = unwrap(this);
436
437	/* Since the secondary Db is used as the first argument
438	 * to the callback, we store the C++ callback on it
439	 * rather than on 'this'.
440	 */
441	secondary->associate_callback_ = callback;
442	return ((*(cthis->associate))(cthis, unwrap(txn), unwrap(secondary),
443	    (callback) ? _db_associate_intercept_c : NULL, flags));
444}
445
446DB_CALLBACK_C_INTERCEPT(feedback,
447    void, (DB *cthis, int opcode, int pct),
448    /* no return */ (void), (cxxthis, opcode, pct))
449
450DB_SET_CALLBACK(set_feedback, feedback,
451    (void (*arg)(Db *cxxthis, int opcode, int pct)), arg)
452
453DB_CALLBACK_C_INTERCEPT(append_recno,
454    int, (DB *cthis, DBT *data, db_recno_t recno),
455    return, (cxxthis, Dbt::get_Dbt(data), recno))
456
457DB_SET_CALLBACK(set_append_recno, append_recno,
458    (int (*arg)(Db *cxxthis, Dbt *data, db_recno_t recno)), arg)
459
460DB_CALLBACK_C_INTERCEPT(bt_compare,
461    int, (DB *cthis, const DBT *data1, const DBT *data2),
462    return,
463    (cxxthis, Dbt::get_const_Dbt(data1), Dbt::get_const_Dbt(data2)))
464
465DB_SET_CALLBACK(set_bt_compare, bt_compare,
466    (int (*arg)(Db *cxxthis, const Dbt *data1, const Dbt *data2)), arg)
467
468DB_CALLBACK_C_INTERCEPT(bt_prefix,
469    size_t, (DB *cthis, const DBT *data1, const DBT *data2),
470    return,
471    (cxxthis, Dbt::get_const_Dbt(data1), Dbt::get_const_Dbt(data2)))
472
473DB_SET_CALLBACK(set_bt_prefix, bt_prefix,
474    (size_t (*arg)(Db *cxxthis, const Dbt *data1, const Dbt *data2)), arg)
475
476DB_CALLBACK_C_INTERCEPT(dup_compare,
477    int, (DB *cthis, const DBT *data1, const DBT *data2),
478    return,
479    (cxxthis, Dbt::get_const_Dbt(data1), Dbt::get_const_Dbt(data2)))
480
481DB_SET_CALLBACK(set_dup_compare, dup_compare,
482    (int (*arg)(Db *cxxthis, const Dbt *data1, const Dbt *data2)), arg)
483
484DB_CALLBACK_C_INTERCEPT(h_compare,
485    int, (DB *cthis, const DBT *data1, const DBT *data2),
486    return,
487    (cxxthis, Dbt::get_const_Dbt(data1), Dbt::get_const_Dbt(data2)))
488
489DB_SET_CALLBACK(set_h_compare, h_compare,
490    (int (*arg)(Db *cxxthis, const Dbt *data1, const Dbt *data2)), arg)
491
492DB_CALLBACK_C_INTERCEPT(h_hash,
493    u_int32_t, (DB *cthis, const void *data, u_int32_t len),
494    return, (cxxthis, data, len))
495
496DB_SET_CALLBACK(set_h_hash, h_hash,
497    (u_int32_t (*arg)(Db *cxxthis, const void *data, u_int32_t len)), arg)
498
499// This is a 'glue' function declared as extern "C" so it will
500// be compatible with picky compilers that do not allow mixing
501// of function pointers to 'C' functions with function pointers
502// to C++ functions.
503//
504extern "C"
505int _verify_callback_c(void *handle, const void *str_arg)
506{
507	char *str;
508	__DB_STD(ostream) *out;
509
510	str = (char *)str_arg;
511	out = (__DB_STD(ostream) *)handle;
512
513	(*out) << str;
514	if (out->fail())
515		return (EIO);
516
517	return (0);
518}
519
520int Db::verify(const char *name, const char *subdb,
521	       __DB_STD(ostream) *ostr, u_int32_t flags)
522{
523	DB *db = unwrap(this);
524	int ret;
525
526	if (!db)
527		ret = EINVAL;
528	else {
529		ret = __db_verify_internal(db, name, subdb, ostr,
530		    _verify_callback_c, flags);
531
532		// After a DB->verify (no matter if success or failure),
533		// the underlying DB object must not be accessed.
534		//
535		cleanup();
536	}
537
538	if (!DB_RETOK_STD(ret))
539		DB_ERROR(dbenv_, "Db::verify", ret, error_policy());
540
541	return (ret);
542}
543
544DB_METHOD(set_bt_compare, (bt_compare_fcn_type func),
545    (db, func), DB_RETOK_STD)
546DB_METHOD(get_bt_minkey, (u_int32_t *bt_minkeyp),
547    (db, bt_minkeyp), DB_RETOK_STD)
548DB_METHOD(set_bt_minkey, (u_int32_t bt_minkey),
549    (db, bt_minkey), DB_RETOK_STD)
550DB_METHOD(set_bt_prefix, (bt_prefix_fcn_type func),
551    (db, func), DB_RETOK_STD)
552DB_METHOD(set_dup_compare, (dup_compare_fcn_type func),
553    (db, func), DB_RETOK_STD)
554DB_METHOD(get_encrypt_flags, (u_int32_t *flagsp),
555    (db, flagsp), DB_RETOK_STD)
556DB_METHOD(set_encrypt, (const char *passwd, u_int32_t flags),
557    (db, passwd, flags), DB_RETOK_STD)
558DB_METHOD_VOID(get_errfile, (FILE **errfilep), (db, errfilep))
559DB_METHOD_VOID(set_errfile, (FILE *errfile), (db, errfile))
560DB_METHOD_VOID(get_errpfx, (const char **errpfx), (db, errpfx))
561DB_METHOD_VOID(set_errpfx, (const char *errpfx), (db, errpfx))
562DB_METHOD(get_flags, (u_int32_t *flagsp), (db, flagsp),
563    DB_RETOK_STD)
564DB_METHOD(set_flags, (u_int32_t flags), (db, flags),
565    DB_RETOK_STD)
566DB_METHOD(set_h_compare, (h_compare_fcn_type func),
567    (db, func), DB_RETOK_STD)
568DB_METHOD(get_h_ffactor, (u_int32_t *h_ffactorp),
569    (db, h_ffactorp), DB_RETOK_STD)
570DB_METHOD(set_h_ffactor, (u_int32_t h_ffactor),
571    (db, h_ffactor), DB_RETOK_STD)
572DB_METHOD(set_h_hash, (h_hash_fcn_type func),
573    (db, func), DB_RETOK_STD)
574DB_METHOD(get_h_nelem, (u_int32_t *h_nelemp),
575    (db, h_nelemp), DB_RETOK_STD)
576DB_METHOD(set_h_nelem, (u_int32_t h_nelem),
577    (db, h_nelem), DB_RETOK_STD)
578DB_METHOD(get_lorder, (int *db_lorderp), (db, db_lorderp),
579    DB_RETOK_STD)
580DB_METHOD(set_lorder, (int db_lorder), (db, db_lorder),
581    DB_RETOK_STD)
582DB_METHOD_VOID(get_msgfile, (FILE **msgfilep), (db, msgfilep))
583DB_METHOD_VOID(set_msgfile, (FILE *msgfile), (db, msgfile))
584DB_METHOD_QUIET(get_multiple, (), (db))
585DB_METHOD(get_pagesize, (u_int32_t *db_pagesizep),
586    (db, db_pagesizep), DB_RETOK_STD)
587DB_METHOD(set_pagesize, (u_int32_t db_pagesize),
588    (db, db_pagesize), DB_RETOK_STD)
589DB_METHOD(get_priority, (DB_CACHE_PRIORITY *priorityp),
590    (db, priorityp), DB_RETOK_STD)
591DB_METHOD(set_priority, (DB_CACHE_PRIORITY priority),
592    (db, priority), DB_RETOK_STD)
593DB_METHOD(get_re_delim, (int *re_delimp),
594    (db, re_delimp), DB_RETOK_STD)
595DB_METHOD(set_re_delim, (int re_delim),
596    (db, re_delim), DB_RETOK_STD)
597DB_METHOD(get_re_len, (u_int32_t *re_lenp),
598    (db, re_lenp), DB_RETOK_STD)
599DB_METHOD(set_re_len, (u_int32_t re_len),
600    (db, re_len), DB_RETOK_STD)
601DB_METHOD(get_re_pad, (int *re_padp),
602    (db, re_padp), DB_RETOK_STD)
603DB_METHOD(set_re_pad, (int re_pad),
604    (db, re_pad), DB_RETOK_STD)
605DB_METHOD(get_re_source, (const char **re_source),
606    (db, re_source), DB_RETOK_STD)
607DB_METHOD(set_re_source, (const char *re_source),
608    (db, re_source), DB_RETOK_STD)
609DB_METHOD(get_q_extentsize, (u_int32_t *extentsizep),
610    (db, extentsizep), DB_RETOK_STD)
611DB_METHOD(set_q_extentsize, (u_int32_t extentsize),
612    (db, extentsize), DB_RETOK_STD)
613
614DB_METHOD_QUIET(set_alloc, (db_malloc_fcn_type malloc_fcn,
615    db_realloc_fcn_type realloc_fcn, db_free_fcn_type free_fcn),
616    (db, malloc_fcn, realloc_fcn, free_fcn))
617
618void Db::set_errcall(void (*arg)(const DbEnv *, const char *, const char *))
619{
620	dbenv_->set_errcall(arg);
621}
622
623void Db::set_msgcall(void (*arg)(const DbEnv *, const char *))
624{
625	dbenv_->set_msgcall(arg);
626}
627
628void *Db::get_app_private() const
629{
630	return unwrapConst(this)->app_private;
631}
632
633void Db::set_app_private(void *value)
634{
635	unwrap(this)->app_private = value;
636}
637
638DB_METHOD(get_cachesize, (u_int32_t *gbytesp, u_int32_t *bytesp, int *ncachep),
639    (db, gbytesp, bytesp, ncachep), DB_RETOK_STD)
640DB_METHOD(set_cachesize, (u_int32_t gbytes, u_int32_t bytes, int ncache),
641    (db, gbytes, bytes, ncache), DB_RETOK_STD)
642
643int Db::set_paniccall(void (*callback)(DbEnv *, int))
644{
645	return (dbenv_->set_paniccall(callback));
646}
647
648__DB_STD(ostream) *Db::get_error_stream()
649{
650	return dbenv_->get_error_stream();
651}
652
653void Db::set_error_stream(__DB_STD(ostream) *error_stream)
654{
655	dbenv_->set_error_stream(error_stream);
656}
657
658__DB_STD(ostream) *Db::get_message_stream()
659{
660	return dbenv_->get_message_stream();
661}
662
663void Db::set_message_stream(__DB_STD(ostream) *message_stream)
664{
665	dbenv_->set_message_stream(message_stream);
666}
667
668DB_METHOD_QUIET(get_transactional, (), (db))
669