1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: db_method.c,v 12.47 2008/01/31 12:50:51 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/crypto.h"
13#include "dbinc/db_page.h"
14#include "dbinc/btree.h"
15#include "dbinc/hash.h"
16#include "dbinc/lock.h"
17#include "dbinc/mp.h"
18#include "dbinc/qam.h"
19#include "dbinc/txn.h"
20
21#ifdef HAVE_RPC
22#ifdef HAVE_SYSTEM_INCLUDE_FILES
23#include <rpc/rpc.h>
24#endif
25#include "db_server.h"
26#include "dbinc_auto/rpc_client_ext.h"
27#endif
28
29static int  __db_get_byteswapped __P((DB *, int *));
30static int  __db_get_dbname __P((DB *, const char **, const char **));
31static DB_ENV *__db_get_env __P((DB *));
32static DB_MPOOLFILE *__db_get_mpf __P((DB *));
33static int  __db_get_multiple __P((DB *));
34static int  __db_get_transactional __P((DB *));
35static int  __db_get_type __P((DB *, DBTYPE *dbtype));
36static int  __db_init __P((DB *, u_int32_t));
37static int  __db_set_alloc __P((DB *, void *(*)(size_t),
38		void *(*)(void *, size_t), void (*)(void *)));
39static int  __db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t)));
40static int  __db_get_cachesize __P((DB *, u_int32_t *, u_int32_t *, int *));
41static int  __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int));
42static int  __db_set_dup_compare
43		__P((DB *, int (*)(DB *, const DBT *, const DBT *)));
44static int  __db_get_encrypt_flags __P((DB *, u_int32_t *));
45static int  __db_set_encrypt __P((DB *, const char *, u_int32_t));
46static int  __db_set_feedback __P((DB *, void (*)(DB *, int, int)));
47static void __db_map_flags __P((DB *, u_int32_t *, u_int32_t *));
48static int  __db_get_pagesize __P((DB *, u_int32_t *));
49static int  __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int)));
50static int  __db_set_priority __P((DB *, DB_CACHE_PRIORITY));
51static int  __db_get_priority __P((DB *, DB_CACHE_PRIORITY *));
52static void __db_get_errcall __P((DB *,
53	      void (**)(const DB_ENV *, const char *, const char *)));
54static void __db_set_errcall
55	      __P((DB *, void (*)(const DB_ENV *, const char *, const char *)));
56static void __db_get_errfile __P((DB *, FILE **));
57static void __db_set_errfile __P((DB *, FILE *));
58static void __db_get_errpfx __P((DB *, const char **));
59static void __db_set_errpfx __P((DB *, const char *));
60static void __db_set_msgcall
61	      __P((DB *, void (*)(const DB_ENV *, const char *)));
62static void __db_get_msgfile __P((DB *, FILE **));
63static void __db_set_msgfile __P((DB *, FILE *));
64static void __dbh_err __P((DB *, int, const char *, ...));
65static void __dbh_errx __P((DB *, const char *, ...));
66
67/*
68 * db_create --
69 *	DB constructor.
70 *
71 * EXTERN: int db_create __P((DB **, DB_ENV *, u_int32_t));
72 */
73int
74db_create(dbpp, dbenv, flags)
75	DB **dbpp;
76	DB_ENV *dbenv;
77	u_int32_t flags;
78{
79	DB_THREAD_INFO *ip;
80	ENV *env;
81	int ret;
82
83	ip = NULL;
84	env = dbenv == NULL ? NULL : dbenv->env;
85
86	/* Check for invalid function flags. */
87	switch (flags) {
88	case 0:
89		break;
90	case DB_XA_CREATE:
91		if (dbenv != NULL) {
92			__db_errx(env,
93		"XA applications may not specify an environment to db_create");
94			return (EINVAL);
95		}
96
97		/*
98		 * If it's an XA database, open it within the XA environment,
99		 * taken from the global list of environments.  (When the XA
100		 * transaction manager called our xa_start() routine the
101		 * "current" environment was moved to the start of the list.
102		 */
103		env = TAILQ_FIRST(&DB_GLOBAL(envq));
104		break;
105	default:
106		return (__db_ferr(env, "db_create", 0));
107	}
108
109	if (env != NULL)
110		ENV_ENTER(env, ip);
111	ret = __db_create_internal(dbpp, env, flags);
112	if (env != NULL)
113		ENV_LEAVE(env, ip);
114
115	return (ret);
116}
117
118/*
119 * __db_create_internal --
120 *	DB constructor internal routine.
121 *
122 * PUBLIC: int __db_create_internal  __P((DB **, ENV *, u_int32_t));
123 */
124int
125__db_create_internal(dbpp, env, flags)
126	DB **dbpp;
127	ENV *env;
128	u_int32_t flags;
129{
130	DB *dbp;
131	DB_ENV *dbenv;
132	DB_REP *db_rep;
133	int ret;
134
135	*dbpp = NULL;
136
137	/* If we don't have an environment yet, allocate a local one. */
138	if (env == NULL) {
139		if ((ret = db_env_create(&dbenv, 0)) != 0)
140			return (ret);
141		env = dbenv->env;
142		F_SET(env, ENV_DBLOCAL);
143	} else
144		dbenv = env->dbenv;
145
146	/* Allocate and initialize the DB handle. */
147	if ((ret = __os_calloc(env, 1, sizeof(*dbp), &dbp)) != 0)
148		goto err;
149
150	dbp->dbenv = env->dbenv;
151	dbp->env = env;
152	if ((ret = __db_init(dbp, flags)) != 0)
153		goto err;
154
155	MUTEX_LOCK(env, env->mtx_dblist);
156	++env->db_ref;
157	MUTEX_UNLOCK(env, env->mtx_dblist);
158
159	/*
160	 * Set the replication timestamp; it's 0 if we're not in a replicated
161	 * environment.  Don't acquire a lock to read the value, even though
162	 * it's opaque: all we check later is value equality, nothing else.
163	 */
164	dbp->timestamp = REP_ON(env) ?
165	    ((REGENV *)env->reginfo->primary)->rep_timestamp : 0;
166	/*
167	 * Set the replication generation number for fid management; valid
168	 * replication generations start at 1.  Don't acquire a lock to
169	 * read the value.  All we check later is value equality.
170	 */
171	db_rep = env->rep_handle;
172	dbp->fid_gen = REP_ON(env) ? ((REP *)db_rep->region)->gen : 0;
173
174	/* If not RPC, open a backing DB_MPOOLFILE handle in the memory pool. */
175	if (!RPC_ON(dbenv) && (ret = __memp_fcreate(env, &dbp->mpf)) != 0)
176		goto err;
177
178	dbp->type = DB_UNKNOWN;
179
180	*dbpp = dbp;
181	return (0);
182
183err:	if (dbp != NULL) {
184		if (dbp->mpf != NULL)
185			(void)__memp_fclose(dbp->mpf, 0);
186		__os_free(env, dbp);
187	}
188
189	if (F_ISSET(env, ENV_DBLOCAL))
190		(void)__env_close(dbp->dbenv, 0);
191
192	return (ret);
193}
194
195/*
196 * __db_init --
197 *	Initialize a DB structure.
198 */
199static int
200__db_init(dbp, flags)
201	DB *dbp;
202	u_int32_t flags;
203{
204	int ret;
205
206	dbp->locker = NULL;
207	LOCK_INIT(dbp->handle_lock);
208
209	TAILQ_INIT(&dbp->free_queue);
210	TAILQ_INIT(&dbp->active_queue);
211	TAILQ_INIT(&dbp->join_queue);
212	LIST_INIT(&dbp->s_secondaries);
213
214	FLD_SET(dbp->am_ok,
215	    DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO);
216
217	/* DB PUBLIC HANDLE LIST BEGIN */
218	dbp->associate = __db_associate_pp;
219	dbp->associate_foreign = __db_associate_foreign_pp;
220	dbp->close = __db_close_pp;
221	dbp->compact = __db_compact_pp;
222	dbp->cursor = __db_cursor_pp;
223	dbp->del = __db_del_pp;
224	dbp->dump = __db_dump_pp;
225	dbp->err = __dbh_err;
226	dbp->errx = __dbh_errx;
227	dbp->exists = __db_exists;
228	dbp->fd = __db_fd_pp;
229	dbp->get = __db_get_pp;
230	dbp->get_byteswapped = __db_get_byteswapped;
231	dbp->get_cachesize = __db_get_cachesize;
232	dbp->get_dbname = __db_get_dbname;
233	dbp->get_encrypt_flags = __db_get_encrypt_flags;
234	dbp->get_env = __db_get_env;
235	dbp->get_errcall = __db_get_errcall;
236	dbp->get_errfile = __db_get_errfile;
237	dbp->get_errpfx = __db_get_errpfx;
238	dbp->get_flags = __db_get_flags;
239	dbp->get_lorder = __db_get_lorder;
240	dbp->get_mpf = __db_get_mpf;
241	dbp->get_msgfile = __db_get_msgfile;
242	dbp->get_multiple = __db_get_multiple;
243	dbp->get_open_flags = __db_get_open_flags;
244	dbp->get_pagesize = __db_get_pagesize;
245	dbp->get_priority = __db_get_priority;
246	dbp->get_transactional = __db_get_transactional;
247	dbp->get_type = __db_get_type;
248	dbp->join = __db_join_pp;
249	dbp->key_range = __db_key_range_pp;
250	dbp->open = __db_open_pp;
251	dbp->pget = __db_pget_pp;
252	dbp->put = __db_put_pp;
253	dbp->remove = __db_remove_pp;
254	dbp->rename = __db_rename_pp;
255	dbp->set_alloc = __db_set_alloc;
256	dbp->set_append_recno = __db_set_append_recno;
257	dbp->set_cachesize = __db_set_cachesize;
258	dbp->set_dup_compare = __db_set_dup_compare;
259	dbp->set_encrypt = __db_set_encrypt;
260	dbp->set_errcall = __db_set_errcall;
261	dbp->set_errfile = __db_set_errfile;
262	dbp->set_errpfx = __db_set_errpfx;
263	dbp->set_feedback = __db_set_feedback;
264	dbp->set_flags = __db_set_flags;
265	dbp->set_lorder = __db_set_lorder;
266	dbp->set_msgcall = __db_set_msgcall;
267	dbp->set_msgfile = __db_set_msgfile;
268	dbp->set_pagesize = __db_set_pagesize;
269	dbp->set_paniccall = __db_set_paniccall;
270	dbp->set_priority = __db_set_priority;
271	dbp->stat = __db_stat_pp;
272	dbp->stat_print = __db_stat_print_pp;
273	dbp->sync = __db_sync_pp;
274	dbp->truncate = __db_truncate_pp;
275	dbp->upgrade = __db_upgrade_pp;
276	dbp->verify = __db_verify_pp;
277	/* DB PUBLIC HANDLE LIST END */
278
279					/* Access method specific. */
280	if ((ret = __bam_db_create(dbp)) != 0)
281		return (ret);
282	if ((ret = __ham_db_create(dbp)) != 0)
283		return (ret);
284	if ((ret = __qam_db_create(dbp)) != 0)
285		return (ret);
286
287	/*
288	 * XA specific: must be last, as we replace methods set by the
289	 * access methods.
290	 */
291	if (LF_ISSET(DB_XA_CREATE) && (ret = __db_xa_create(dbp)) != 0)
292		return (ret);
293
294#ifdef HAVE_RPC
295	/*
296	 * RPC specific: must be last, as we replace methods set by the
297	 * access methods.
298	 */
299	if (RPC_ON(dbp->dbenv)) {
300		__dbcl_dbp_init(dbp);
301		/*
302		 * !!!
303		 * We wrap the DB->open method for RPC, and the rpc.src file
304		 * can't handle that.
305		 */
306		dbp->open = __dbcl_db_open_wrap;
307		if ((ret = __dbcl_db_create(dbp, dbp->dbenv, flags)) != 0)
308			return (ret);
309	}
310#endif
311
312	return (0);
313}
314
315/*
316 * __dbh_am_chk --
317 *	Error if an unreasonable method is called.
318 *
319 * PUBLIC: int __dbh_am_chk __P((DB *, u_int32_t));
320 */
321int
322__dbh_am_chk(dbp, flags)
323	DB *dbp;
324	u_int32_t flags;
325{
326	/*
327	 * We start out allowing any access methods to be called, and as the
328	 * application calls the methods the options become restricted.  The
329	 * idea is to quit as soon as an illegal method combination is called.
330	 */
331	if ((LF_ISSET(DB_OK_BTREE) && FLD_ISSET(dbp->am_ok, DB_OK_BTREE)) ||
332	    (LF_ISSET(DB_OK_HASH) && FLD_ISSET(dbp->am_ok, DB_OK_HASH)) ||
333	    (LF_ISSET(DB_OK_QUEUE) && FLD_ISSET(dbp->am_ok, DB_OK_QUEUE)) ||
334	    (LF_ISSET(DB_OK_RECNO) && FLD_ISSET(dbp->am_ok, DB_OK_RECNO))) {
335		FLD_CLR(dbp->am_ok, ~flags);
336		return (0);
337	}
338
339	__db_errx(dbp->env,
340    "call implies an access method which is inconsistent with previous calls");
341	return (EINVAL);
342}
343
344/*
345 * __dbh_err --
346 *	Db.err method.
347 */
348static void
349#ifdef STDC_HEADERS
350__dbh_err(DB *dbp, int error, const char *fmt, ...)
351#else
352__dbh_err(dbp, error, fmt, va_alist)
353	DB *dbp;
354	int error;
355	const char *fmt;
356	va_dcl
357#endif
358{
359	/* Message with error string, to stderr by default. */
360	DB_REAL_ERR(dbp->dbenv, error, DB_ERROR_SET, 1, fmt);
361}
362
363/*
364 * __dbh_errx --
365 *	Db.errx method.
366 */
367static void
368#ifdef STDC_HEADERS
369__dbh_errx(DB *dbp, const char *fmt, ...)
370#else
371__dbh_errx(dbp, fmt, va_alist)
372	DB *dbp;
373	const char *fmt;
374	va_dcl
375#endif
376{
377	/* Message without error string, to stderr by default. */
378	DB_REAL_ERR(dbp->dbenv, 0, DB_ERROR_NOT_SET, 1, fmt);
379}
380
381/*
382 * __db_get_byteswapped --
383 *	Return if database requires byte swapping.
384 */
385static int
386__db_get_byteswapped(dbp, isswapped)
387	DB *dbp;
388	int *isswapped;
389{
390	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_byteswapped");
391
392	*isswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0;
393	return (0);
394}
395
396/*
397 * __db_get_dbname --
398 *	Get the name of the database as passed to DB->open.
399 */
400static int
401__db_get_dbname(dbp, fnamep, dnamep)
402	DB *dbp;
403	const char **fnamep, **dnamep;
404{
405	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_dbname");
406
407	if (fnamep != NULL)
408		*fnamep = dbp->fname;
409	if (dnamep != NULL)
410		*dnamep = dbp->dname;
411	return (0);
412}
413
414/*
415 * __db_get_env --
416 *	Get the DB_ENV handle that was passed to db_create.
417 */
418static DB_ENV *
419__db_get_env(dbp)
420	DB *dbp;
421{
422	return (dbp->dbenv);
423}
424
425/*
426 * __db_get_mpf --
427 *	Get the underlying DB_MPOOLFILE handle.
428 */
429static DB_MPOOLFILE *
430__db_get_mpf(dbp)
431	DB *dbp;
432{
433	return (dbp->mpf);
434}
435
436/*
437 * get_multiple --
438 *	Return whether this DB handle references a physical file with multiple
439 *	databases.
440 */
441static int
442__db_get_multiple(dbp)
443	DB *dbp;
444{
445	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_multiple");
446
447	/*
448	 * Only return TRUE if the handle is for the master database, not for
449	 * any subdatabase in the physical file.  If it's a Btree, with the
450	 * subdatabases flag set, and the meta-data page has the right value,
451	 * return TRUE.  (We don't need to check it's a Btree, I suppose, but
452	 * it doesn't hurt.)
453	 */
454	return (dbp->type == DB_BTREE &&
455	    F_ISSET(dbp, DB_AM_SUBDB) &&
456	    dbp->meta_pgno == PGNO_BASE_MD ? 1 : 0);
457}
458
459/*
460 * get_transactional --
461 *	Return whether this database was created in a transaction.
462 */
463static int
464__db_get_transactional(dbp)
465	DB *dbp;
466{
467	return (F_ISSET(dbp, DB_AM_TXN) ? 1 : 0);
468}
469
470/*
471 * __db_get_type --
472 *	Return type of underlying database.
473 */
474static int
475__db_get_type(dbp, dbtype)
476	DB *dbp;
477	DBTYPE *dbtype;
478{
479	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_type");
480
481	*dbtype = dbp->type;
482	return (0);
483}
484
485/*
486 * __db_set_append_recno --
487 *	Set record number append routine.
488 */
489static int
490__db_set_append_recno(dbp, func)
491	DB *dbp;
492	int (*func) __P((DB *, DBT *, db_recno_t));
493{
494	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_append_recno");
495	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
496
497	dbp->db_append_recno = func;
498
499	return (0);
500}
501
502/*
503 * __db_get_cachesize --
504 *	Get underlying cache size.
505 */
506static int
507__db_get_cachesize(dbp, cache_gbytesp, cache_bytesp, ncachep)
508	DB *dbp;
509	u_int32_t *cache_gbytesp, *cache_bytesp;
510	int *ncachep;
511{
512	DB_ILLEGAL_IN_ENV(dbp, "DB->get_cachesize");
513
514	return (__memp_get_cachesize(dbp->dbenv,
515	    cache_gbytesp, cache_bytesp, ncachep));
516}
517
518/*
519 * __db_set_cachesize --
520 *	Set underlying cache size.
521 */
522static int
523__db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache)
524	DB *dbp;
525	u_int32_t cache_gbytes, cache_bytes;
526	int ncache;
527{
528	DB_ILLEGAL_IN_ENV(dbp, "DB->set_cachesize");
529	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_cachesize");
530
531	return (__memp_set_cachesize(
532	    dbp->dbenv, cache_gbytes, cache_bytes, ncache));
533}
534
535/*
536 * __db_set_dup_compare --
537 *	Set duplicate comparison routine.
538 */
539static int
540__db_set_dup_compare(dbp, func)
541	DB *dbp;
542	int (*func) __P((DB *, const DBT *, const DBT *));
543{
544	int ret;
545
546	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->dup_compare");
547	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
548
549	if ((ret = __db_set_flags(dbp, DB_DUPSORT)) != 0)
550		return (ret);
551
552	dbp->dup_compare = func;
553
554	return (0);
555}
556
557/*
558 * __db_get_encrypt_flags --
559 */
560static int
561__db_get_encrypt_flags(dbp, flagsp)
562	DB *dbp;
563	u_int32_t *flagsp;
564{
565	DB_ILLEGAL_IN_ENV(dbp, "DB->get_encrypt_flags");
566
567	return (__env_get_encrypt_flags(dbp->dbenv, flagsp));
568}
569
570/*
571 * __db_set_encrypt --
572 *	Set database passwd.
573 */
574static int
575__db_set_encrypt(dbp, passwd, flags)
576	DB *dbp;
577	const char *passwd;
578	u_int32_t flags;
579{
580	DB_CIPHER *db_cipher;
581	int ret;
582
583	DB_ILLEGAL_IN_ENV(dbp, "DB->set_encrypt");
584	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_encrypt");
585
586	if ((ret = __env_set_encrypt(dbp->dbenv, passwd, flags)) != 0)
587		return (ret);
588
589	/*
590	 * In a real env, this gets initialized with the region.  In a local
591	 * env, we must do it here.
592	 */
593	db_cipher = dbp->env->crypto_handle;
594	if (!F_ISSET(db_cipher, CIPHER_ANY) &&
595	    (ret = db_cipher->init(dbp->env, db_cipher)) != 0)
596		return (ret);
597
598	return (__db_set_flags(dbp, DB_ENCRYPT));
599}
600
601static void
602__db_get_errcall(dbp, errcallp)
603	DB *dbp;
604	void (**errcallp) __P((const DB_ENV *, const char *, const char *));
605{
606	__env_get_errcall(dbp->dbenv, errcallp);
607}
608
609static void
610__db_set_errcall(dbp, errcall)
611	DB *dbp;
612	void (*errcall) __P((const DB_ENV *, const char *, const char *));
613{
614	__env_set_errcall(dbp->dbenv, errcall);
615}
616
617static void
618__db_get_errfile(dbp, errfilep)
619	DB *dbp;
620	FILE **errfilep;
621{
622	__env_get_errfile(dbp->dbenv, errfilep);
623}
624
625static void
626__db_set_errfile(dbp, errfile)
627	DB *dbp;
628	FILE *errfile;
629{
630	__env_set_errfile(dbp->dbenv, errfile);
631}
632
633static void
634__db_get_errpfx(dbp, errpfxp)
635	DB *dbp;
636	const char **errpfxp;
637{
638	__env_get_errpfx(dbp->dbenv, errpfxp);
639}
640
641static void
642__db_set_errpfx(dbp, errpfx)
643	DB *dbp;
644	const char *errpfx;
645{
646	__env_set_errpfx(dbp->dbenv, errpfx);
647}
648
649static int
650__db_set_feedback(dbp, feedback)
651	DB *dbp;
652	void (*feedback) __P((DB *, int, int));
653{
654	dbp->db_feedback = feedback;
655	return (0);
656}
657
658/*
659 * __db_map_flags --
660 *	Maps between public and internal flag values.
661 *      This function doesn't check for validity, so it can't fail.
662 */
663static void
664__db_map_flags(dbp, inflagsp, outflagsp)
665	DB *dbp;
666	u_int32_t *inflagsp, *outflagsp;
667{
668	COMPQUIET(dbp, NULL);
669
670	if (FLD_ISSET(*inflagsp, DB_CHKSUM)) {
671		FLD_SET(*outflagsp, DB_AM_CHKSUM);
672		FLD_CLR(*inflagsp, DB_CHKSUM);
673	}
674	if (FLD_ISSET(*inflagsp, DB_ENCRYPT)) {
675		FLD_SET(*outflagsp, DB_AM_ENCRYPT | DB_AM_CHKSUM);
676		FLD_CLR(*inflagsp, DB_ENCRYPT);
677	}
678	if (FLD_ISSET(*inflagsp, DB_TXN_NOT_DURABLE)) {
679		FLD_SET(*outflagsp, DB_AM_NOT_DURABLE);
680		FLD_CLR(*inflagsp, DB_TXN_NOT_DURABLE);
681	}
682}
683
684/*
685 * __db_get_flags --
686 *	The DB->get_flags method.
687 *
688 * PUBLIC: int __db_get_flags __P((DB *, u_int32_t *));
689 */
690int
691__db_get_flags(dbp, flagsp)
692	DB *dbp;
693	u_int32_t *flagsp;
694{
695	static const u_int32_t db_flags[] = {
696		DB_CHKSUM,
697		DB_DUP,
698		DB_DUPSORT,
699		DB_ENCRYPT,
700#ifdef HAVE_QUEUE
701		DB_INORDER,
702#endif
703		DB_RECNUM,
704		DB_RENUMBER,
705		DB_REVSPLITOFF,
706		DB_SNAPSHOT,
707		DB_TXN_NOT_DURABLE,
708		0
709	};
710	u_int32_t f, flags, mapped_flag;
711	int i;
712
713	flags = 0;
714	for (i = 0; (f = db_flags[i]) != 0; i++) {
715		mapped_flag = 0;
716		__db_map_flags(dbp, &f, &mapped_flag);
717		__bam_map_flags(dbp, &f, &mapped_flag);
718		__ram_map_flags(dbp, &f, &mapped_flag);
719#ifdef HAVE_QUEUE
720		__qam_map_flags(dbp, &f, &mapped_flag);
721#endif
722		DB_ASSERT(dbp->env, f == 0);
723		if (F_ISSET(dbp, mapped_flag) == mapped_flag)
724			LF_SET(db_flags[i]);
725	}
726
727	*flagsp = flags;
728	return (0);
729}
730
731/*
732 * __db_set_flags --
733 *	DB->set_flags.
734 *
735 * PUBLIC: int  __db_set_flags __P((DB *, u_int32_t));
736 */
737int
738__db_set_flags(dbp, flags)
739	DB *dbp;
740	u_int32_t flags;
741{
742	ENV *env;
743	int ret;
744
745	env = dbp->env;
746
747	if (LF_ISSET(DB_ENCRYPT) && !CRYPTO_ON(env)) {
748		__db_errx(env,
749		    "Database environment not configured for encryption");
750		return (EINVAL);
751	}
752	if (LF_ISSET(DB_TXN_NOT_DURABLE))
753		ENV_REQUIRES_CONFIG(env,
754		    env->tx_handle, "DB_NOT_DURABLE", DB_INIT_TXN);
755
756	__db_map_flags(dbp, &flags, &dbp->flags);
757
758	if ((ret = __bam_set_flags(dbp, &flags)) != 0)
759		return (ret);
760	if ((ret = __ram_set_flags(dbp, &flags)) != 0)
761		return (ret);
762#ifdef HAVE_QUEUE
763	if ((ret = __qam_set_flags(dbp, &flags)) != 0)
764		return (ret);
765#endif
766
767	return (flags == 0 ? 0 : __db_ferr(env, "DB->set_flags", 0));
768}
769
770/*
771 * __db_get_lorder --
772 *	Get whether lorder is swapped or not.
773 *
774 * PUBLIC: int  __db_get_lorder __P((DB *, int *));
775 */
776int
777__db_get_lorder(dbp, db_lorderp)
778	DB *dbp;
779	int *db_lorderp;
780{
781	int ret;
782
783	/* Flag if the specified byte order requires swapping. */
784	switch (ret = __db_byteorder(dbp->env, 1234)) {
785	case 0:
786		*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 4321 : 1234;
787		break;
788	case DB_SWAPBYTES:
789		*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 1234 : 4321;
790		break;
791	default:
792		return (ret);
793		/* NOTREACHED */
794	}
795
796	return (0);
797}
798
799/*
800 * __db_set_lorder --
801 *	Set whether lorder is swapped or not.
802 *
803 * PUBLIC: int  __db_set_lorder __P((DB *, int));
804 */
805int
806__db_set_lorder(dbp, db_lorder)
807	DB *dbp;
808	int db_lorder;
809{
810	int ret;
811
812	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_lorder");
813
814	/* Flag if the specified byte order requires swapping. */
815	switch (ret = __db_byteorder(dbp->env, db_lorder)) {
816	case 0:
817		F_CLR(dbp, DB_AM_SWAP);
818		break;
819	case DB_SWAPBYTES:
820		F_SET(dbp, DB_AM_SWAP);
821		break;
822	default:
823		return (ret);
824		/* NOTREACHED */
825	}
826	return (0);
827}
828
829static int
830__db_set_alloc(dbp, mal_func, real_func, free_func)
831	DB *dbp;
832	void *(*mal_func) __P((size_t));
833	void *(*real_func) __P((void *, size_t));
834	void (*free_func) __P((void *));
835{
836	DB_ILLEGAL_IN_ENV(dbp, "DB->set_alloc");
837	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_alloc");
838
839	return (__env_set_alloc(dbp->dbenv, mal_func, real_func, free_func));
840}
841
842static void
843__db_set_msgcall(dbp, msgcall)
844	DB *dbp;
845	void (*msgcall) __P((const DB_ENV *, const char *));
846{
847	__env_set_msgcall(dbp->dbenv, msgcall);
848}
849
850static void
851__db_get_msgfile(dbp, msgfilep)
852	DB *dbp;
853	FILE **msgfilep;
854{
855	__env_get_msgfile(dbp->dbenv, msgfilep);
856}
857
858static void
859__db_set_msgfile(dbp, msgfile)
860	DB *dbp;
861	FILE *msgfile;
862{
863	__env_set_msgfile(dbp->dbenv, msgfile);
864}
865
866static int
867__db_get_pagesize(dbp, db_pagesizep)
868	DB *dbp;
869	u_int32_t *db_pagesizep;
870{
871	*db_pagesizep = dbp->pgsize;
872	return (0);
873}
874
875/*
876 * __db_set_pagesize --
877 *	DB->set_pagesize
878 *
879 * PUBLIC: int  __db_set_pagesize __P((DB *, u_int32_t));
880 */
881int
882__db_set_pagesize(dbp, db_pagesize)
883	DB *dbp;
884	u_int32_t db_pagesize;
885{
886	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_pagesize");
887
888	if (db_pagesize < DB_MIN_PGSIZE) {
889		__db_errx(dbp->env, "page sizes may not be smaller than %lu",
890		    (u_long)DB_MIN_PGSIZE);
891		return (EINVAL);
892	}
893	if (db_pagesize > DB_MAX_PGSIZE) {
894		__db_errx(dbp->env, "page sizes may not be larger than %lu",
895		    (u_long)DB_MAX_PGSIZE);
896		return (EINVAL);
897	}
898
899	/*
900	 * We don't want anything that's not a power-of-2, as we rely on that
901	 * for alignment of various types on the pages.
902	 */
903	if (!POWER_OF_TWO(db_pagesize)) {
904		__db_errx(dbp->env, "page sizes must be a power-of-2");
905		return (EINVAL);
906	}
907
908	/*
909	 * XXX
910	 * Should we be checking for a page size that's not a multiple of 512,
911	 * so that we never try and write less than a disk sector?
912	 */
913	dbp->pgsize = db_pagesize;
914
915	return (0);
916}
917
918static int
919__db_set_paniccall(dbp, paniccall)
920	DB *dbp;
921	void (*paniccall) __P((DB_ENV *, int));
922{
923	return (__env_set_paniccall(dbp->dbenv, paniccall));
924}
925
926static int
927__db_set_priority(dbp, priority)
928	DB *dbp;
929	DB_CACHE_PRIORITY priority;
930{
931	dbp->priority = priority;
932	return (0);
933}
934
935static int
936__db_get_priority(dbp, priority)
937	DB *dbp;
938	DB_CACHE_PRIORITY *priority;
939{
940	*priority = dbp->priority;
941	return (0);
942}
943