1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/btree.h"
14#include "dbinc/hash.h"
15#ifndef HAVE_QUEUE
16#include "dbinc/qam.h"			/* For __db_no_queue_am(). */
17#endif
18#include "dbinc/lock.h"
19#include "dbinc/log.h"
20#include "dbinc/mp.h"
21#include "dbinc/partition.h"
22#include "dbinc/txn.h"
23
24static int __db_associate_arg __P((DB *, DB *,
25	       int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t));
26static int __dbc_del_arg __P((DBC *, u_int32_t));
27static int __dbc_pget_arg __P((DBC *, DBT *, u_int32_t));
28static int __dbc_put_arg __P((DBC *, DBT *, DBT *, u_int32_t));
29static int __db_curinval __P((const ENV *));
30static int __db_cursor_arg __P((DB *, u_int32_t));
31static int __db_del_arg __P((DB *, DBT *, u_int32_t));
32static int __db_get_arg __P((const DB *, DBT *, DBT *, u_int32_t));
33static int __db_join_arg __P((DB *, DBC **, u_int32_t));
34static int __db_open_arg __P((DB *,
35	       DB_TXN *, const char *, const char *, DBTYPE, u_int32_t));
36static int __db_pget_arg __P((DB *, DBT *, u_int32_t));
37static int __db_put_arg __P((DB *, DBT *, DBT *, u_int32_t));
38static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));
39static int __db_associate_foreign_arg __P((DB *, DB *,
40		int (*)(DB *, const DBT *, DBT *, const DBT *, int *),
41		u_int32_t));
42
43/*
44 * These functions implement the Berkeley DB API.  They are organized in a
45 * layered fashion.  The interface functions (XXX_pp) perform all generic
46 * error checks (for example, PANIC'd region, replication state change
47 * in progress, inconsistent transaction usage), call function-specific
48 * check routines (_arg) to check for proper flag usage, etc., do pre-amble
49 * processing (incrementing handle counts, handling local transactions),
50 * call the function and then do post-amble processing (local transactions,
51 * decrement handle counts).
52 *
53 * The basic structure is:
54 *	Check for simple/generic errors (PANIC'd region)
55 *	Check if replication is changing state (increment handle count).
56 *	Call function-specific argument checking routine
57 *	Create internal transaction if necessary
58 *	Call underlying worker function
59 *	Commit/abort internal transaction if necessary
60 *	Decrement handle count
61 */
62
63/*
64 * __db_associate_pp --
65 *	DB->associate pre/post processing.
66 *
67 * PUBLIC: int __db_associate_pp __P((DB *, DB_TXN *, DB *,
68 * PUBLIC:     int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t));
69 */
70int
71__db_associate_pp(dbp, txn, sdbp, callback, flags)
72	DB *dbp, *sdbp;
73	DB_TXN *txn;
74	int (*callback) __P((DB *, const DBT *, const DBT *, DBT *));
75	u_int32_t flags;
76{
77	DBC *sdbc;
78	DB_THREAD_INFO *ip;
79	ENV *env;
80	int handle_check, ret, t_ret, txn_local;
81
82	env = dbp->env;
83	txn_local = 0;
84
85	STRIP_AUTO_COMMIT(flags);
86
87	ENV_ENTER(env, ip);
88
89	/* Check for replication block. */
90	handle_check = IS_ENV_REPLICATED(env);
91	if (handle_check &&
92	    (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
93		handle_check = 0;
94		goto err;
95	}
96
97	/*
98	 * Secondary cursors may have the primary's lock file ID, so we need
99	 * to make sure that no older cursors are lying around when we make
100	 * the transition.
101	 */
102	if (TAILQ_FIRST(&sdbp->active_queue) != NULL ||
103	    TAILQ_FIRST(&sdbp->join_queue) != NULL) {
104		__db_errx(env,
105    "Databases may not become secondary indices while cursors are open");
106		ret = EINVAL;
107		goto err;
108	}
109
110	if ((ret = __db_associate_arg(dbp, sdbp, callback, flags)) != 0)
111		goto err;
112
113	/*
114	 * Create a local transaction as necessary, check for consistent
115	 * transaction usage, and, if we have no transaction but do have
116	 * locking on, acquire a locker id for the handle lock acquisition.
117	 */
118	if (IS_DB_AUTO_COMMIT(dbp, txn)) {
119		if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0)
120			goto err;
121		txn_local = 1;
122	}
123
124	/* Check for consistent transaction usage. */
125	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
126		goto err;
127
128	while ((sdbc = TAILQ_FIRST(&sdbp->free_queue)) != NULL)
129		if ((ret = __dbc_destroy(sdbc)) != 0)
130			goto err;
131
132	ret = __db_associate(dbp, ip, txn, sdbp, callback, flags);
133
134err:	if (txn_local &&
135	    (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0)
136		ret = t_ret;
137
138	/* Release replication block. */
139	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
140		ret = t_ret;
141	ENV_LEAVE(env, ip);
142	return (ret);
143}
144
145/*
146 * __db_associate_arg --
147 *	Check DB->associate arguments.
148 */
149static int
150__db_associate_arg(dbp, sdbp, callback, flags)
151	DB *dbp, *sdbp;
152	int (*callback) __P((DB *, const DBT *, const DBT *, DBT *));
153	u_int32_t flags;
154{
155	ENV *env;
156	int ret;
157
158	env = dbp->env;
159
160	if (F_ISSET(sdbp, DB_AM_SECONDARY)) {
161		__db_errx(env,
162		    "Secondary index handles may not be re-associated");
163		return (EINVAL);
164	}
165	if (F_ISSET(dbp, DB_AM_SECONDARY)) {
166		__db_errx(env,
167		    "Secondary indices may not be used as primary databases");
168		return (EINVAL);
169	}
170	if (F_ISSET(dbp, DB_AM_DUP)) {
171		__db_errx(env,
172		    "Primary databases may not be configured with duplicates");
173		return (EINVAL);
174	}
175	if (F_ISSET(dbp, DB_AM_RENUMBER)) {
176		__db_errx(env,
177	    "Renumbering recno databases may not be used as primary databases");
178		return (EINVAL);
179	}
180
181	/*
182	 * It's OK for the primary and secondary to not share an environment IFF
183	 * the environments are local to the DB handle.  (Specifically, cursor
184	 * adjustment will work correctly in this case.)  The environment being
185	 * local implies the environment is not configured for either locking or
186	 * transactions, as neither of those could work correctly.
187	 */
188	if (dbp->env != sdbp->env &&
189	    (!F_ISSET(dbp->env, ENV_DBLOCAL) ||
190	     !F_ISSET(sdbp->env, ENV_DBLOCAL))) {
191		__db_errx(env,
192	    "The primary and secondary must be opened in the same environment");
193		return (EINVAL);
194	}
195	if ((DB_IS_THREADED(dbp) && !DB_IS_THREADED(sdbp)) ||
196	    (!DB_IS_THREADED(dbp) && DB_IS_THREADED(sdbp))) {
197		__db_errx(env,
198	    "The DB_THREAD setting must be the same for primary and secondary");
199		return (EINVAL);
200	}
201	if (callback == NULL &&
202	    (!F_ISSET(dbp, DB_AM_RDONLY) || !F_ISSET(sdbp, DB_AM_RDONLY))) {
203		__db_errx(env,
204    "Callback function may be NULL only when database handles are read-only");
205		return (EINVAL);
206	}
207
208	if ((ret = __db_fchk(env, "DB->associate", flags, DB_CREATE |
209	    DB_IMMUTABLE_KEY)) != 0)
210		return (ret);
211
212	return (0);
213}
214
215/*
216 * __db_close_pp --
217 *	DB->close pre/post processing.
218 *
219 * PUBLIC: int __db_close_pp __P((DB *, u_int32_t));
220 */
221int
222__db_close_pp(dbp, flags)
223	DB *dbp;
224	u_int32_t flags;
225{
226	DB_THREAD_INFO *ip;
227	ENV *env;
228	int handle_check, ret, t_ret;
229
230	env = dbp->env;
231	ret = 0;
232
233	/*
234	 * Close a DB handle -- as a handle destructor, we can't fail.
235	 *
236	 * !!!
237	 * The actual argument checking is simple, do it inline, outside of
238	 * the replication block.
239	 */
240	if (flags != 0 && flags != DB_NOSYNC)
241		ret = __db_ferr(env, "DB->close", 0);
242
243	ENV_ENTER(env, ip);
244
245	/* Check for replication block. */
246	handle_check = IS_ENV_REPLICATED(env);
247	if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) {
248		handle_check = 0;
249		if (ret == 0)
250			ret = t_ret;
251	}
252
253	if ((t_ret = __db_close(dbp, NULL, flags)) != 0 && ret == 0)
254		ret = t_ret;
255
256	/* Release replication block. */
257	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
258		ret = t_ret;
259
260	ENV_LEAVE(env, ip);
261	return (ret);
262}
263
264/*
265 * __db_cursor_pp --
266 *	DB->cursor pre/post processing.
267 *
268 * PUBLIC: int __db_cursor_pp __P((DB *, DB_TXN *, DBC **, u_int32_t));
269 */
270int
271__db_cursor_pp(dbp, txn, dbcp, flags)
272	DB *dbp;
273	DB_TXN *txn;
274	DBC **dbcp;
275	u_int32_t flags;
276{
277	DB_THREAD_INFO *ip;
278	ENV *env;
279	REGENV *renv;
280	int rep_blocked, ret;
281
282	env = dbp->env;
283
284	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor");
285
286	ENV_ENTER(env, ip);
287
288	/* Check for replication block. */
289	rep_blocked = 0;
290	if (txn == NULL && IS_ENV_REPLICATED(env)) {
291		if ((ret = __op_rep_enter(env)) != 0)
292			goto err;
293		rep_blocked = 1;
294		renv = env->reginfo->primary;
295		if (dbp->timestamp != renv->rep_timestamp) {
296			__db_errx(env, "%s %s",
297		    "replication recovery unrolled committed transactions;",
298		    "open DB and DBcursor handles must be closed");
299			ret = DB_REP_HANDLE_DEAD;
300			goto err;
301		}
302	}
303	if ((ret = __db_cursor_arg(dbp, flags)) != 0)
304		goto err;
305
306	/*
307	 * Check for consistent transaction usage.  For now, assume this
308	 * cursor might be used for read operations only (in which case
309	 * it may not require a txn).  We'll check more stringently in
310	 * c_del and c_put.  (Note this means the read-op txn tests have
311	 * to be a subset of the write-op ones.)
312	 */
313	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
314		goto err;
315
316	ret = __db_cursor(dbp, ip, txn, dbcp, flags);
317
318err:	/* Release replication block on error. */
319	if (ret != 0 && rep_blocked)
320		(void)__op_rep_exit(env);
321
322	ENV_LEAVE(env, ip);
323	return (ret);
324}
325
326/*
327 * __db_cursor --
328 *	DB->cursor.
329 *
330 * PUBLIC: int __db_cursor __P((DB *,
331 * PUBLIC:      DB_THREAD_INFO *, DB_TXN *, DBC **, u_int32_t));
332 */
333int
334__db_cursor(dbp, ip, txn, dbcp, flags)
335	DB *dbp;
336	DB_THREAD_INFO *ip;
337	DB_TXN *txn;
338	DBC **dbcp;
339	u_int32_t flags;
340{
341	DBC *dbc;
342	ENV *env;
343	db_lockmode_t mode;
344	int ret;
345
346	env = dbp->env;
347
348	if (MULTIVERSION(dbp) && txn == NULL && (LF_ISSET(DB_TXN_SNAPSHOT) ||
349	    F_ISSET(env->dbenv, DB_ENV_TXN_SNAPSHOT))) {
350		if ((ret =
351		    __txn_begin(env, ip, NULL, &txn, DB_TXN_SNAPSHOT)) != 0)
352			return (ret);
353		F_SET(txn, TXN_PRIVATE);
354	}
355
356	if ((ret = __db_cursor_int(dbp, ip, txn, dbp->type, PGNO_INVALID,
357	    LF_ISSET(DB_CURSOR_BULK | DB_CURSOR_TRANSIENT), NULL, &dbc)) != 0)
358		return (ret);
359
360	/*
361	 * If this is CDB, do all the locking in the interface, which is
362	 * right here.
363	 */
364	if (CDB_LOCKING(env)) {
365		mode = (LF_ISSET(DB_WRITELOCK)) ? DB_LOCK_WRITE :
366		    ((LF_ISSET(DB_WRITECURSOR) || txn != NULL) ?
367		    DB_LOCK_IWRITE : DB_LOCK_READ);
368		if ((ret = __lock_get(env, dbc->locker, 0,
369		    &dbc->lock_dbt, mode, &dbc->mylock)) != 0)
370			goto err;
371		if (LF_ISSET(DB_WRITECURSOR))
372			F_SET(dbc, DBC_WRITECURSOR);
373		if (LF_ISSET(DB_WRITELOCK))
374			F_SET(dbc, DBC_WRITER);
375	}
376
377	if (LF_ISSET(DB_READ_UNCOMMITTED) ||
378	    (txn != NULL && F_ISSET(txn, TXN_READ_UNCOMMITTED)))
379		F_SET(dbc, DBC_READ_UNCOMMITTED);
380
381	if (LF_ISSET(DB_READ_COMMITTED) ||
382	    (txn != NULL && F_ISSET(txn, TXN_READ_COMMITTED)))
383		F_SET(dbc, DBC_READ_COMMITTED);
384
385	*dbcp = dbc;
386	return (0);
387
388err:	(void)__dbc_close(dbc);
389	return (ret);
390}
391
392/*
393 * __db_cursor_arg --
394 *	Check DB->cursor arguments.
395 */
396static int
397__db_cursor_arg(dbp, flags)
398	DB *dbp;
399	u_int32_t flags;
400{
401	ENV *env;
402
403	env = dbp->env;
404
405	/*
406	 * DB_READ_COMMITTED and DB_READ_UNCOMMITTED require locking.
407	 */
408	if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED)) {
409		if (!LOCKING_ON(env))
410			return (__db_fnl(env, "DB->cursor"));
411	}
412
413	LF_CLR(DB_CURSOR_BULK |
414	    DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_TXN_SNAPSHOT);
415
416	/* Check for invalid function flags. */
417	if (LF_ISSET(DB_WRITECURSOR)) {
418		if (DB_IS_READONLY(dbp))
419			return (__db_rdonly(env, "DB->cursor"));
420		if (!CDB_LOCKING(env))
421			return (__db_ferr(env, "DB->cursor", 0));
422		LF_CLR(DB_WRITECURSOR);
423	} else if (LF_ISSET(DB_WRITELOCK)) {
424		if (DB_IS_READONLY(dbp))
425			return (__db_rdonly(env, "DB->cursor"));
426		LF_CLR(DB_WRITELOCK);
427	}
428
429	if (flags != 0)
430		return (__db_ferr(env, "DB->cursor", 0));
431
432	return (0);
433}
434
435/*
436 * __db_del_pp --
437 *	DB->del pre/post processing.
438 *
439 * PUBLIC: int __db_del_pp __P((DB *, DB_TXN *, DBT *, u_int32_t));
440 */
441int
442__db_del_pp(dbp, txn, key, flags)
443	DB *dbp;
444	DB_TXN *txn;
445	DBT *key;
446	u_int32_t flags;
447{
448	DB_THREAD_INFO *ip;
449	ENV *env;
450	int handle_check, ret, t_ret, txn_local;
451
452	env = dbp->env;
453	txn_local = 0;
454
455	STRIP_AUTO_COMMIT(flags);
456	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del");
457
458#ifdef CONFIG_TEST
459	if (IS_REP_MASTER(env))
460		DB_TEST_WAIT(env, env->test_check);
461#endif
462	ENV_ENTER(env, ip);
463
464	/* Check for replication block. */
465	handle_check = IS_ENV_REPLICATED(env);
466	if (handle_check &&
467	     (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
468			handle_check = 0;
469			goto err;
470	}
471
472	if ((ret = __db_del_arg(dbp, key, flags)) != 0)
473		goto err;
474
475	/* Create local transaction as necessary. */
476	if (IS_DB_AUTO_COMMIT(dbp, txn)) {
477		if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0)
478			goto err;
479		txn_local = 1;
480	}
481
482	/* Check for consistent transaction usage. */
483	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
484		goto err;
485
486	ret = __db_del(dbp, ip, txn, key, flags);
487
488err:	if (txn_local &&
489	    (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0)
490		ret = t_ret;
491
492	/* Release replication block. */
493	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
494		ret = t_ret;
495	ENV_LEAVE(env, ip);
496	__dbt_userfree(env, key, NULL, NULL);
497	return (ret);
498}
499
500/*
501 * __db_del_arg --
502 *	Check DB->delete arguments.
503 */
504static int
505__db_del_arg(dbp, key, flags)
506	DB *dbp;
507	DBT *key;
508	u_int32_t flags;
509{
510	ENV *env;
511	int ret;
512
513	env = dbp->env;
514
515	/* Check for changes to a read-only tree. */
516	if (DB_IS_READONLY(dbp))
517		return (__db_rdonly(env, "DB->del"));
518
519	/* Check for invalid function flags. */
520	switch (flags) {
521	case DB_CONSUME:
522		if (dbp->type != DB_QUEUE)
523			return (__db_ferr(env, "DB->del", 0));
524		goto copy;
525	case DB_MULTIPLE:
526	case DB_MULTIPLE_KEY:
527		if (!F_ISSET(key, DB_DBT_BULK)) {
528			__db_errx(env,
529		"DB->del with DB_MULTIPLE(_KEY) requires multiple key records");
530			return (EINVAL);
531		}
532		/* FALL THROUGH */
533	case 0:
534copy:		if ((ret = __dbt_usercopy(env, key)) != 0)
535			return (ret);
536		break;
537	default:
538		return (__db_ferr(env, "DB->del", 0));
539	}
540
541	return (0);
542}
543
544/*
545 * __db_exists --
546 *	DB->exists implementation.
547 *
548 * PUBLIC: int __db_exists __P((DB *, DB_TXN *, DBT *, u_int32_t));
549 */
550int
551__db_exists(dbp, txn, key, flags)
552	DB *dbp;
553	DB_TXN *txn;
554	DBT *key;
555	u_int32_t flags;
556{
557	DBT data;
558	int ret;
559
560	/*
561	 * Most flag checking is done in the DB->get call, we only check for
562	 * specific incompatibilities here.  This saves making __get_arg
563	 * aware of the exist method's API constraints.
564	 */
565	STRIP_AUTO_COMMIT(flags);
566	if ((ret = __db_fchk(dbp->env, "DB->exists", flags,
567	    DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) != 0)
568		return (ret);
569
570	/*
571	 * Configure a data DBT that returns no bytes so there's no copy
572	 * of the data.
573	 */
574	memset(&data, 0, sizeof(data));
575	data.dlen = 0;
576	data.flags = DB_DBT_PARTIAL | DB_DBT_USERMEM;
577
578	return (dbp->get(dbp, txn, key, &data, flags));
579}
580
581/*
582 * db_fd_pp --
583 *	DB->fd pre/post processing.
584 *
585 * PUBLIC: int __db_fd_pp __P((DB *, int *));
586 */
587int
588__db_fd_pp(dbp, fdp)
589	DB *dbp;
590	int *fdp;
591{
592	DB_FH *fhp;
593	DB_THREAD_INFO *ip;
594	ENV *env;
595	int handle_check, ret, t_ret;
596
597	env = dbp->env;
598
599	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd");
600
601	ENV_ENTER(env, ip);
602
603	/* Check for replication block. */
604	handle_check = IS_ENV_REPLICATED(env);
605	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0)
606		goto err;
607
608	/*
609	 * !!!
610	 * There's no argument checking to be done.
611	 *
612	 * !!!
613	 * The actual method call is simple, do it inline.
614	 *
615	 * XXX
616	 * Truly spectacular layering violation.
617	 */
618	if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) == 0) {
619		if (fhp == NULL) {
620			*fdp = -1;
621			__db_errx(env,
622			    "Database does not have a valid file handle");
623			ret = ENOENT;
624		} else
625			*fdp = fhp->fd;
626	}
627
628	/* Release replication block. */
629	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
630		ret = t_ret;
631
632err:	ENV_LEAVE(env, ip);
633	return (ret);
634}
635
636/*
637 * __db_get_pp --
638 *	DB->get pre/post processing.
639 *
640 * PUBLIC: int __db_get_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
641 */
642int
643__db_get_pp(dbp, txn, key, data, flags)
644	DB *dbp;
645	DB_TXN *txn;
646	DBT *key, *data;
647	u_int32_t flags;
648{
649	DB_THREAD_INFO *ip;
650	ENV *env;
651	u_int32_t mode;
652	int handle_check, ignore_lease, ret, t_ret, txn_local;
653
654	env = dbp->env;
655	mode = 0;
656	txn_local = 0;
657
658	STRIP_AUTO_COMMIT(flags);
659	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get");
660
661	ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0;
662	LF_CLR(DB_IGNORE_LEASE);
663
664	if ((ret = __db_get_arg(dbp, key, data, flags)) != 0)
665		return (ret);
666
667	ENV_ENTER(env, ip);
668
669	/* Check for replication block. */
670	handle_check = IS_ENV_REPLICATED(env);
671	if (handle_check &&
672	     (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
673			handle_check = 0;
674			goto err;
675	}
676
677	if (LF_ISSET(DB_READ_UNCOMMITTED))
678		mode = DB_READ_UNCOMMITTED;
679	else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME ||
680	    (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT) {
681		mode = DB_WRITELOCK;
682		if (IS_DB_AUTO_COMMIT(dbp, txn)) {
683			if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0)
684				goto err;
685			txn_local = 1;
686		}
687	}
688
689	/* Check for consistent transaction usage. */
690	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID,
691	    mode == DB_WRITELOCK || LF_ISSET(DB_RMW) ? 0 : 1)) != 0)
692		goto err;
693
694	ret = __db_get(dbp, ip, txn, key, data, flags);
695	/*
696	 * Check for master leases.
697	 */
698	if (ret == 0 &&
699	    IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease)
700		ret = __rep_lease_check(env, 1);
701
702err:	if (txn_local &&
703	    (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0)
704		ret = t_ret;
705
706	/* Release replication block. */
707	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
708		ret = t_ret;
709
710	ENV_LEAVE(env, ip);
711	__dbt_userfree(env, key, NULL, data);
712	return (ret);
713}
714
715/*
716 * __db_get --
717 *	DB->get.
718 *
719 * PUBLIC: int __db_get __P((DB *,
720 * PUBLIC:     DB_THREAD_INFO *, DB_TXN *, DBT *, DBT *, u_int32_t));
721 */
722int
723__db_get(dbp, ip, txn, key, data, flags)
724	DB *dbp;
725	DB_THREAD_INFO *ip;
726	DB_TXN *txn;
727	DBT *key, *data;
728	u_int32_t flags;
729{
730	DBC *dbc;
731	u_int32_t mode;
732	int ret, t_ret;
733
734	/*
735	 * The DB_CURSOR_TRANSIENT flag indicates that we're just doing a single
736	 * operation with this cursor, and that in case of error we don't need
737	 * to restore it to its old position.  Thus, we can perform the get
738	 * without duplicating the cursor, saving some cycles in this common
739	 * case.
740	 */
741	mode = DB_CURSOR_TRANSIENT;
742	if (LF_ISSET(DB_READ_UNCOMMITTED)) {
743		mode |= DB_READ_UNCOMMITTED;
744		LF_CLR(DB_READ_UNCOMMITTED);
745	} else if (LF_ISSET(DB_READ_COMMITTED)) {
746		mode |= DB_READ_COMMITTED;
747		LF_CLR(DB_READ_COMMITTED);
748	} else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME ||
749	    (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT)
750		mode |= DB_WRITELOCK;
751
752	if ((ret = __db_cursor(dbp, ip, txn, &dbc, mode)) != 0)
753		return (ret);
754
755	DEBUG_LREAD(dbc, txn, "DB->get", key, NULL, flags);
756
757	/*
758	 * The semantics of bulk gets are different for DB->get vs DBC->get.
759	 * Mark the cursor so the low-level bulk get routines know which
760	 * behavior we want.
761	 */
762	F_SET(dbc, DBC_FROM_DB_GET);
763
764	/*
765	 * SET_RET_MEM indicates that if key and/or data have no DBT
766	 * flags set and DB manages the returned-data memory, that memory
767	 * will belong to this handle, not to the underlying cursor.
768	 */
769	SET_RET_MEM(dbc, dbp);
770
771	if (LF_ISSET(~(DB_RMW | DB_MULTIPLE)) == 0)
772		LF_SET(DB_SET);
773
774#ifdef HAVE_PARTITION
775	if (F_ISSET(dbc, DBC_PARTITIONED))
776		ret = __partc_get(dbc, key, data, flags);
777	else
778#endif
779		ret = __dbc_get(dbc, key, data, flags);
780
781	if (dbc != NULL && (t_ret = __dbc_close(dbc)) != 0 && ret == 0)
782		ret = t_ret;
783
784	return (ret);
785}
786
787/*
788 * __db_get_arg --
789 *	DB->get argument checking, used by both DB->get and DB->pget.
790 */
791static int
792__db_get_arg(dbp, key, data, flags)
793	const DB *dbp;
794	DBT *key, *data;
795	u_int32_t flags;
796{
797	ENV *env;
798	int dirty, multi, ret;
799
800	env = dbp->env;
801
802	/*
803	 * Check for read-modify-write validity.  DB_RMW doesn't make sense
804	 * with CDB cursors since if you're going to write the cursor, you
805	 * had to create it with DB_WRITECURSOR.  Regardless, we check for
806	 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
807	 * If this changes, confirm that DB does not itself set the DB_RMW
808	 * flag in a path where CDB may have been configured.
809	 */
810	dirty = 0;
811	if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) {
812		if (!LOCKING_ON(env))
813			return (__db_fnl(env, "DB->get"));
814		if ((ret = __db_fcchk(env, "DB->get",
815		    flags, DB_READ_UNCOMMITTED, DB_READ_COMMITTED)) != 0)
816			return (ret);
817		if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED))
818			dirty = 1;
819		LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW);
820	}
821
822	multi = 0;
823	if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
824		if (LF_ISSET(DB_MULTIPLE_KEY))
825			goto multi_err;
826		multi = LF_ISSET(DB_MULTIPLE) ? 1 : 0;
827		LF_CLR(DB_MULTIPLE);
828	}
829
830	/* Check for invalid function flags. */
831	switch (flags) {
832	case DB_GET_BOTH:
833		if ((ret = __dbt_usercopy(env, data)) != 0)
834			return (ret);
835		/* FALLTHROUGH */
836	case 0:
837		if ((ret = __dbt_usercopy(env, key)) != 0) {
838			__dbt_userfree(env, key, NULL, data);
839			return (ret);
840		}
841		break;
842	case DB_SET_RECNO:
843		if (!F_ISSET(dbp, DB_AM_RECNUM))
844			goto err;
845		if ((ret = __dbt_usercopy(env, key)) != 0)
846			return (ret);
847		break;
848	case DB_CONSUME:
849	case DB_CONSUME_WAIT:
850		if (dirty) {
851			__db_errx(env,
852		    "%s is not supported with DB_CONSUME or DB_CONSUME_WAIT",
853			     LF_ISSET(DB_READ_UNCOMMITTED) ?
854			     "DB_READ_UNCOMMITTED" : "DB_READ_COMMITTED");
855			return (EINVAL);
856		}
857		if (multi)
858multi_err:		return (__db_ferr(env, "DB->get", 1));
859		if (dbp->type == DB_QUEUE)
860			break;
861		/* FALLTHROUGH */
862	default:
863err:		return (__db_ferr(env, "DB->get", 0));
864	}
865
866	/*
867	 * Check for invalid key/data flags.
868	 */
869	if ((ret =
870	    __dbt_ferr(dbp, "key", key, DB_RETURNS_A_KEY(dbp, flags))) != 0)
871		return (ret);
872	if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0)
873		return (ret);
874
875	if (multi) {
876		if (!F_ISSET(data, DB_DBT_USERMEM)) {
877			__db_errx(env,
878			    "DB_MULTIPLE requires DB_DBT_USERMEM be set");
879			return (EINVAL);
880		}
881		if (F_ISSET(key, DB_DBT_PARTIAL) ||
882		    F_ISSET(data, DB_DBT_PARTIAL)) {
883			__db_errx(env,
884			    "DB_MULTIPLE does not support DB_DBT_PARTIAL");
885			return (EINVAL);
886		}
887		if (data->ulen < 1024 ||
888		    data->ulen < dbp->pgsize || data->ulen % 1024 != 0) {
889			__db_errx(env, "%s%s",
890			    "DB_MULTIPLE buffers must be ",
891			    "aligned, at least page size and multiples of 1KB");
892			return (EINVAL);
893		}
894	}
895
896	return (0);
897}
898
899/*
900 * __db_join_pp --
901 *	DB->join pre/post processing.
902 *
903 * PUBLIC: int __db_join_pp __P((DB *, DBC **, DBC **, u_int32_t));
904 */
905int
906__db_join_pp(primary, curslist, dbcp, flags)
907	DB *primary;
908	DBC **curslist, **dbcp;
909	u_int32_t flags;
910{
911	DB_THREAD_INFO *ip;
912	ENV *env;
913	int handle_check, ret, t_ret;
914
915	env = primary->env;
916
917	ENV_ENTER(env, ip);
918
919	/* Check for replication block. */
920	handle_check = IS_ENV_REPLICATED(env);
921	if (handle_check && (ret =
922	    __db_rep_enter(primary, 1, 0, curslist[0]->txn != NULL)) != 0) {
923		handle_check = 0;
924		goto err;
925	}
926
927	if ((ret = __db_join_arg(primary, curslist, flags)) == 0)
928		ret = __db_join(primary, curslist, dbcp, flags);
929
930	/* Release replication block. */
931	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
932		ret = t_ret;
933
934err:	ENV_LEAVE(env, ip);
935	return (ret);
936}
937
938/*
939 * __db_join_arg --
940 *	Check DB->join arguments.
941 */
942static int
943__db_join_arg(primary, curslist, flags)
944	DB *primary;
945	DBC **curslist;
946	u_int32_t flags;
947{
948	DB_TXN *txn;
949	ENV *env;
950	int i;
951
952	env = primary->env;
953
954	switch (flags) {
955	case 0:
956	case DB_JOIN_NOSORT:
957		break;
958	default:
959		return (__db_ferr(env, "DB->join", 0));
960	}
961
962	if (curslist == NULL || curslist[0] == NULL) {
963		__db_errx(env,
964	    "At least one secondary cursor must be specified to DB->join");
965		return (EINVAL);
966	}
967
968	txn = curslist[0]->txn;
969	for (i = 1; curslist[i] != NULL; i++)
970		if (curslist[i]->txn != txn) {
971			__db_errx(env,
972		    "All secondary cursors must share the same transaction");
973			return (EINVAL);
974		}
975
976	return (0);
977}
978
979/*
980 * __db_key_range_pp --
981 *	DB->key_range pre/post processing.
982 *
983 * PUBLIC: int __db_key_range_pp
984 * PUBLIC:     __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
985 */
986int
987__db_key_range_pp(dbp, txn, key, kr, flags)
988	DB *dbp;
989	DB_TXN *txn;
990	DBT *key;
991	DB_KEY_RANGE *kr;
992	u_int32_t flags;
993{
994	DBC *dbc;
995	DB_THREAD_INFO *ip;
996	ENV *env;
997	int handle_check, ret, t_ret;
998
999	env = dbp->env;
1000
1001	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range");
1002
1003	/*
1004	 * !!!
1005	 * The actual argument checking is simple, do it inline, outside of
1006	 * the replication block.
1007	 */
1008	if (flags != 0)
1009		return (__db_ferr(env, "DB->key_range", 0));
1010
1011	ENV_ENTER(env, ip);
1012
1013	/* Check for replication block. */
1014	handle_check = IS_ENV_REPLICATED(env);
1015	if (handle_check &&
1016	     (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
1017		handle_check = 0;
1018		goto err;
1019	}
1020
1021	/* Check for consistent transaction usage. */
1022	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
1023		goto err;
1024
1025	/*
1026	 * !!!
1027	 * The actual method call is simple, do it inline.
1028	 */
1029	switch (dbp->type) {
1030	case DB_BTREE:
1031#ifndef HAVE_BREW
1032		if ((ret = __dbt_usercopy(env, key)) != 0)
1033			goto err;
1034
1035		/* Acquire a cursor. */
1036		if ((ret = __db_cursor(dbp, ip, txn, &dbc, 0)) != 0)
1037			break;
1038
1039		DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0);
1040#ifdef HAVE_PARTITION
1041		if (DB_IS_PARTITIONED(dbp))
1042			ret = __part_key_range(dbc, key, kr, flags);
1043		else
1044#endif
1045			ret = __bam_key_range(dbc, key, kr, flags);
1046
1047		if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
1048			ret = t_ret;
1049		__dbt_userfree(env, key, NULL, NULL);
1050		break;
1051#else
1052		COMPQUIET(dbc, NULL);
1053		COMPQUIET(key, NULL);
1054		COMPQUIET(kr, NULL);
1055		/* FALLTHROUGH */
1056#endif
1057	case DB_HASH:
1058	case DB_QUEUE:
1059	case DB_RECNO:
1060		ret = __dbh_am_chk(dbp, DB_OK_BTREE);
1061		break;
1062	case DB_UNKNOWN:
1063	default:
1064		ret = __db_unknown_type(env, "DB->key_range", dbp->type);
1065		break;
1066	}
1067
1068err:	/* Release replication block. */
1069	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1070		ret = t_ret;
1071
1072	ENV_LEAVE(env, ip);
1073	return (ret);
1074}
1075
1076/*
1077 * __db_open_pp --
1078 *	DB->open pre/post processing.
1079 *
1080 * PUBLIC: int __db_open_pp __P((DB *, DB_TXN *,
1081 * PUBLIC:     const char *, const char *, DBTYPE, u_int32_t, int));
1082 */
1083int
1084__db_open_pp(dbp, txn, fname, dname, type, flags, mode)
1085	DB *dbp;
1086	DB_TXN *txn;
1087	const char *fname, *dname;
1088	DBTYPE type;
1089	u_int32_t flags;
1090	int mode;
1091{
1092	DB_THREAD_INFO *ip;
1093	ENV *env;
1094	int handle_check, nosync, remove_me, ret, t_ret, txn_local;
1095
1096	env = dbp->env;
1097	nosync = 1;
1098	handle_check = remove_me = txn_local = 0;
1099
1100	ENV_ENTER(env, ip);
1101
1102	/*
1103	 * Save the file and database names and flags.  We do this here
1104	 * because we don't pass all of the flags down into the actual
1105	 * DB->open method call, we strip DB_AUTO_COMMIT at this layer.
1106	 */
1107	if ((fname != NULL &&
1108	    (ret = __os_strdup(env, fname, &dbp->fname)) != 0))
1109		goto err;
1110	if ((dname != NULL &&
1111	    (ret = __os_strdup(env, dname, &dbp->dname)) != 0))
1112		goto err;
1113	dbp->open_flags = flags;
1114
1115	/* Save the current DB handle flags for refresh. */
1116	dbp->orig_flags = dbp->flags;
1117
1118	/* Check for replication block. */
1119	handle_check = IS_ENV_REPLICATED(env);
1120	if (handle_check &&
1121	    (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
1122		handle_check = 0;
1123		goto err;
1124	}
1125
1126	/*
1127	 * Create local transaction as necessary, check for consistent
1128	 * transaction usage.
1129	 */
1130	if (IS_ENV_AUTO_COMMIT(env, txn, flags)) {
1131		if ((ret = __db_txn_auto_init(env, ip, &txn)) != 0)
1132			goto err;
1133		txn_local = 1;
1134	} else if (txn != NULL && !TXN_ON(env) &&
1135	    (!CDB_LOCKING(env) || !F_ISSET(txn, TXN_CDSGROUP))) {
1136		ret = __db_not_txn_env(env);
1137		goto err;
1138	}
1139	LF_CLR(DB_AUTO_COMMIT);
1140
1141	/*
1142	 * We check arguments after possibly creating a local transaction,
1143	 * which is unusual -- the reason is some flags are illegal if any
1144	 * kind of transaction is in effect.
1145	 */
1146	if ((ret = __db_open_arg(dbp, txn, fname, dname, type, flags)) == 0)
1147		if ((ret = __db_open(dbp, ip, txn, fname, dname, type,
1148		    flags, mode, PGNO_BASE_MD)) != 0)
1149			goto txnerr;
1150
1151	/*
1152	 * You can open the database that describes the subdatabases in the
1153	 * rest of the file read-only.  The content of each key's data is
1154	 * unspecified and applications should never be adding new records
1155	 * or updating existing records.  However, during recovery, we need
1156	 * to open these databases R/W so we can redo/undo changes in them.
1157	 * Likewise, we need to open master databases read/write during
1158	 * rename and remove so we can be sure they're fully sync'ed, so
1159	 * we provide an override flag for the purpose.
1160	 */
1161	if (dname == NULL && !IS_RECOVERING(env) && !LF_ISSET(DB_RDONLY) &&
1162	    !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
1163		__db_errx(env,
1164    "files containing multiple databases may only be opened read-only");
1165		ret = EINVAL;
1166		goto txnerr;
1167	}
1168
1169	/*
1170	 * Success: file creations have to be synchronous, otherwise we don't
1171	 * care.
1172	 */
1173	if (F_ISSET(dbp, DB_AM_CREATED | DB_AM_CREATED_MSTR))
1174		nosync = 0;
1175
1176	/* Success: don't discard the file on close. */
1177	F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR);
1178
1179	/*
1180	 * If not transactional, remove the databases/subdatabases if it is
1181	 * persistent.  If we're transactional, the child transaction abort
1182	 * cleans up.
1183	 */
1184txnerr:	if (ret != 0 && !IS_REAL_TXN(txn)) {
1185		remove_me = (F_ISSET(dbp, DB_AM_CREATED) &&
1186			(fname != NULL || dname != NULL)) ? 1 : 0;
1187		if (F_ISSET(dbp, DB_AM_CREATED_MSTR) ||
1188		    (dname == NULL && remove_me))
1189			/* Remove file. */
1190			(void)__db_remove_int(dbp,
1191			    ip, txn, fname, NULL, DB_FORCE);
1192		else if (remove_me)
1193			/* Remove subdatabase. */
1194			(void)__db_remove_int(dbp,
1195			    ip, txn, fname, dname, DB_FORCE);
1196	}
1197
1198	if (txn_local && (t_ret =
1199	     __db_txn_auto_resolve(env, txn, nosync, ret)) && ret == 0)
1200		ret = t_ret;
1201
1202err:	/* Release replication block. */
1203	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1204		ret = t_ret;
1205
1206	ENV_LEAVE(env, ip);
1207	return (ret);
1208}
1209
1210/*
1211 * __db_open_arg --
1212 *	Check DB->open arguments.
1213 */
1214static int
1215__db_open_arg(dbp, txn, fname, dname, type, flags)
1216	DB *dbp;
1217	DB_TXN *txn;
1218	const char *fname, *dname;
1219	DBTYPE type;
1220	u_int32_t flags;
1221{
1222	ENV *env;
1223	u_int32_t ok_flags;
1224	int ret;
1225
1226	env = dbp->env;
1227
1228	/* Validate arguments. */
1229#undef	OKFLAGS
1230#define	OKFLAGS								\
1231	(DB_AUTO_COMMIT | DB_CREATE | DB_EXCL | DB_FCNTL_LOCKING |	\
1232	DB_MULTIVERSION | DB_NOMMAP | DB_NO_AUTO_COMMIT | DB_RDONLY |	\
1233	DB_RDWRMASTER | DB_READ_UNCOMMITTED | DB_THREAD | DB_TRUNCATE)
1234	if ((ret = __db_fchk(env, "DB->open", flags, OKFLAGS)) != 0)
1235		return (ret);
1236	if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
1237		return (__db_ferr(env, "DB->open", 1));
1238	if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
1239		return (__db_ferr(env, "DB->open", 1));
1240
1241#ifdef	HAVE_VXWORKS
1242	if (LF_ISSET(DB_TRUNCATE)) {
1243		__db_errx(env, "DB_TRUNCATE not supported on VxWorks");
1244		return (DB_OPNOTSUP);
1245	}
1246#endif
1247	switch (type) {
1248	case DB_UNKNOWN:
1249		if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) {
1250			__db_errx(env,
1251	    "DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE");
1252			return (EINVAL);
1253		}
1254		ok_flags = 0;
1255		break;
1256	case DB_BTREE:
1257		ok_flags = DB_OK_BTREE;
1258		break;
1259	case DB_HASH:
1260#ifndef HAVE_HASH
1261		return (__db_no_hash_am(env));
1262#endif
1263		ok_flags = DB_OK_HASH;
1264		break;
1265	case DB_QUEUE:
1266#ifndef HAVE_QUEUE
1267		return (__db_no_queue_am(env));
1268#endif
1269		ok_flags = DB_OK_QUEUE;
1270		break;
1271	case DB_RECNO:
1272		ok_flags = DB_OK_RECNO;
1273		break;
1274	default:
1275		__db_errx(env, "unknown type: %lu", (u_long)type);
1276		return (EINVAL);
1277	}
1278	if (ok_flags)
1279		DB_ILLEGAL_METHOD(dbp, ok_flags);
1280
1281	/* The environment may have been created, but never opened. */
1282	if (!F_ISSET(env, ENV_DBLOCAL | ENV_OPEN_CALLED)) {
1283		__db_errx(env, "database environment not yet opened");
1284		return (EINVAL);
1285	}
1286
1287	/*
1288	 * Historically, you could pass in an environment that didn't have a
1289	 * mpool, and DB would create a private one behind the scenes.  This
1290	 * no longer works.
1291	 */
1292	if (!F_ISSET(env, ENV_DBLOCAL) && !MPOOL_ON(env)) {
1293		__db_errx(env, "environment did not include a memory pool");
1294		return (EINVAL);
1295	}
1296
1297	/*
1298	 * You can't specify threads during DB->open if subsystems in the
1299	 * environment weren't configured with them.
1300	 */
1301	if (LF_ISSET(DB_THREAD) && !F_ISSET(env, ENV_DBLOCAL | ENV_THREAD)) {
1302		__db_errx(env, "environment not created using DB_THREAD");
1303		return (EINVAL);
1304	}
1305
1306	/* DB_MULTIVERSION requires a database configured for transactions. */
1307	if (LF_ISSET(DB_MULTIVERSION) && !IS_REAL_TXN(txn)) {
1308		__db_errx(env,
1309		    "DB_MULTIVERSION illegal without a transaction specified");
1310		return (EINVAL);
1311	}
1312
1313	if (LF_ISSET(DB_MULTIVERSION) && type == DB_QUEUE) {
1314		__db_errx(env,
1315		    "DB_MULTIVERSION illegal with queue databases");
1316		return (EINVAL);
1317	}
1318
1319	/* DB_TRUNCATE is neither transaction recoverable nor lockable. */
1320	if (LF_ISSET(DB_TRUNCATE) && (LOCKING_ON(env) || txn != NULL)) {
1321		__db_errx(env,
1322		    "DB_TRUNCATE illegal with %s specified",
1323		    LOCKING_ON(env) ? "locking" : "transactions");
1324		return (EINVAL);
1325	}
1326
1327	/* Subdatabase checks. */
1328	if (dname != NULL) {
1329		/* QAM can only be done on in-memory subdatabases. */
1330		if (type == DB_QUEUE && fname != NULL) {
1331			__db_errx(
1332			    env, "Queue databases must be one-per-file");
1333			return (EINVAL);
1334		}
1335
1336		/*
1337		 * Named in-memory databases can't support certain flags,
1338		 * so check here.
1339		 */
1340		if (fname == NULL)
1341			F_CLR(dbp, DB_AM_CHKSUM | DB_AM_ENCRYPT);
1342	}
1343
1344	return (0);
1345}
1346
1347/*
1348 * __db_pget_pp --
1349 *	DB->pget pre/post processing.
1350 *
1351 * PUBLIC: int __db_pget_pp
1352 * PUBLIC:     __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t));
1353 */
1354int
1355__db_pget_pp(dbp, txn, skey, pkey, data, flags)
1356	DB *dbp;
1357	DB_TXN *txn;
1358	DBT *skey, *pkey, *data;
1359	u_int32_t flags;
1360{
1361	DB_THREAD_INFO *ip;
1362	ENV *env;
1363	int handle_check, ignore_lease, ret, t_ret;
1364
1365	env = dbp->env;
1366
1367	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->pget");
1368
1369	ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0;
1370	LF_CLR(DB_IGNORE_LEASE);
1371
1372	if ((ret = __db_pget_arg(dbp, pkey, flags)) != 0 ||
1373	    (ret = __db_get_arg(dbp, skey, data, flags)) != 0) {
1374		__dbt_userfree(env, skey, pkey, data);
1375		return (ret);
1376	}
1377
1378	ENV_ENTER(env, ip);
1379
1380	/* Check for replication block. */
1381	handle_check = IS_ENV_REPLICATED(env);
1382	if (handle_check &&
1383	    (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
1384		handle_check = 0;
1385		goto err;
1386	}
1387
1388	ret = __db_pget(dbp, ip, txn, skey, pkey, data, flags);
1389	/*
1390	 * Check for master leases.
1391	 */
1392	if (ret == 0 &&
1393	    IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease)
1394		ret = __rep_lease_check(env, 1);
1395
1396err:	/* Release replication block. */
1397	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1398		ret = t_ret;
1399
1400	ENV_LEAVE(env, ip);
1401	__dbt_userfree(env, skey, pkey, data);
1402	return (ret);
1403}
1404
1405/*
1406 * __db_pget --
1407 *	DB->pget.
1408 *
1409 * PUBLIC: int __db_pget __P((DB *,
1410 * PUBLIC:     DB_THREAD_INFO *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t));
1411 */
1412int
1413__db_pget(dbp, ip, txn, skey, pkey, data, flags)
1414	DB *dbp;
1415	DB_THREAD_INFO *ip;
1416	DB_TXN *txn;
1417	DBT *skey, *pkey, *data;
1418	u_int32_t flags;
1419{
1420	DBC *dbc;
1421	u_int32_t mode;
1422	int ret, t_ret;
1423
1424	mode = DB_CURSOR_TRANSIENT;
1425	if (LF_ISSET(DB_READ_UNCOMMITTED)) {
1426		mode |= DB_READ_UNCOMMITTED;
1427		LF_CLR(DB_READ_UNCOMMITTED);
1428	} else if (LF_ISSET(DB_READ_COMMITTED)) {
1429		mode |= DB_READ_COMMITTED;
1430		LF_CLR(DB_READ_COMMITTED);
1431	}
1432
1433	if ((ret = __db_cursor(dbp, ip, txn, &dbc, mode)) != 0)
1434		return (ret);
1435
1436	SET_RET_MEM(dbc, dbp);
1437
1438	DEBUG_LREAD(dbc, txn, "__db_pget", skey, NULL, flags);
1439
1440	/*
1441	 * !!!
1442	 * The actual method call is simple, do it inline.
1443	 *
1444	 * The underlying cursor pget will fill in a default DBT for null
1445	 * pkeys, and use the cursor's returned-key memory internally to
1446	 * store any intermediate primary keys.  However, we've just set
1447	 * the returned-key memory to the DB handle's key memory, which
1448	 * is unsafe to use if the DB handle is threaded.  If the pkey
1449	 * argument is NULL, use the DBC-owned returned-key memory
1450	 * instead;  it'll go away when we close the cursor before we
1451	 * return, but in this case that's just fine, as we're not
1452	 * returning the primary key.
1453	 */
1454	if (pkey == NULL)
1455		dbc->rkey = &dbc->my_rkey;
1456
1457	/*
1458	 * The cursor is just a perfectly ordinary secondary database cursor.
1459	 * Call its c_pget() method to do the dirty work.
1460	 */
1461	if (flags == 0 || flags == DB_RMW)
1462		flags |= DB_SET;
1463
1464	ret = __dbc_pget(dbc, skey, pkey, data, flags);
1465
1466	if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
1467		ret = t_ret;
1468
1469	return (ret);
1470}
1471
1472/*
1473 * __db_pget_arg --
1474 *	Check DB->pget arguments.
1475 */
1476static int
1477__db_pget_arg(dbp, pkey, flags)
1478	DB *dbp;
1479	DBT *pkey;
1480	u_int32_t flags;
1481{
1482	ENV *env;
1483	int ret;
1484
1485	env = dbp->env;
1486
1487	if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
1488		__db_errx(env,
1489		    "DB->pget may only be used on secondary indices");
1490		return (EINVAL);
1491	}
1492
1493	if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
1494		__db_errx(env,
1495	"DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
1496		return (EINVAL);
1497	}
1498
1499	/* DB_CONSUME makes no sense on a secondary index. */
1500	LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW);
1501	switch (flags) {
1502	case DB_CONSUME:
1503	case DB_CONSUME_WAIT:
1504		return (__db_ferr(env, "DB->pget", 0));
1505	default:
1506		/* __db_get_arg will catch the rest. */
1507		break;
1508	}
1509
1510	/*
1511	 * We allow the pkey field to be NULL, so that we can make the
1512	 * two-DBT get calls into wrappers for the three-DBT ones.
1513	 */
1514	if (pkey != NULL &&
1515	    (ret = __dbt_ferr(dbp, "primary key", pkey, 1)) != 0)
1516		return (ret);
1517
1518	if (flags == DB_GET_BOTH) {
1519		/* The pkey field can't be NULL if we're doing a DB_GET_BOTH. */
1520		if (pkey == NULL) {
1521			__db_errx(env,
1522		    "DB_GET_BOTH on a secondary index requires a primary key");
1523			return (EINVAL);
1524		}
1525		if ((ret = __dbt_usercopy(env, pkey)) != 0)
1526			return (ret);
1527	}
1528
1529	return (0);
1530}
1531
1532/*
1533 * __db_put_pp --
1534 *	DB->put pre/post processing.
1535 *
1536 * PUBLIC: int __db_put_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
1537 */
1538int
1539__db_put_pp(dbp, txn, key, data, flags)
1540	DB *dbp;
1541	DB_TXN *txn;
1542	DBT *key, *data;
1543	u_int32_t flags;
1544{
1545	DB_THREAD_INFO *ip;
1546	ENV *env;
1547	int handle_check, ret, txn_local, t_ret;
1548
1549	env = dbp->env;
1550	txn_local = 0;
1551
1552	STRIP_AUTO_COMMIT(flags);
1553	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put");
1554
1555	if ((ret = __db_put_arg(dbp, key, data, flags)) != 0)
1556		return (ret);
1557
1558	ENV_ENTER(env, ip);
1559
1560	/* Check for replication block. */
1561	handle_check = IS_ENV_REPLICATED(env);
1562	if (handle_check &&
1563	    (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
1564		handle_check = 0;
1565		goto err;
1566	}
1567
1568	/* Create local transaction as necessary. */
1569	if (IS_DB_AUTO_COMMIT(dbp, txn)) {
1570		if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0)
1571			goto err;
1572		txn_local = 1;
1573	}
1574
1575	/* Check for consistent transaction usage. */
1576	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
1577		goto err;
1578
1579	ret = __db_put(dbp, ip, txn, key, data, flags);
1580
1581err:	if (txn_local &&
1582	    (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0)
1583		ret = t_ret;
1584
1585	/* Release replication block. */
1586	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1587		ret = t_ret;
1588
1589	ENV_LEAVE(env, ip);
1590	__dbt_userfree(env, key, NULL, data);
1591	return (ret);
1592}
1593
1594/*
1595 * __db_put_arg --
1596 *	Check DB->put arguments.
1597 */
1598static int
1599__db_put_arg(dbp, key, data, flags)
1600	DB *dbp;
1601	DBT *key, *data;
1602	u_int32_t flags;
1603{
1604	ENV *env;
1605	int ret, returnkey;
1606
1607	env = dbp->env;
1608	returnkey = 0;
1609
1610	/* Check for changes to a read-only tree. */
1611	if (DB_IS_READONLY(dbp))
1612		return (__db_rdonly(env, "DB->put"));
1613
1614	/* Check for puts on a secondary. */
1615	if (F_ISSET(dbp, DB_AM_SECONDARY)) {
1616		__db_errx(env, "DB->put forbidden on secondary indices");
1617		return (EINVAL);
1618	}
1619
1620	if (LF_ISSET(DB_MULTIPLE_KEY | DB_MULTIPLE)) {
1621		if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY))
1622			goto err;
1623
1624		switch (LF_ISSET(DB_OPFLAGS_MASK)) {
1625		case 0:
1626		case DB_OVERWRITE_DUP:
1627			break;
1628		default:
1629			__db_errx(env,
1630       "DB->put: DB_MULTIPLE(_KEY) can only be combined with DB_OVERWRITE_DUP");
1631			return (EINVAL);
1632		}
1633
1634		if (!F_ISSET(key, DB_DBT_BULK)) {
1635			__db_errx(env,
1636		   "DB->put with DB_MULTIPLE(_KEY) requires a bulk key buffer");
1637			return (EINVAL);
1638		}
1639	}
1640	if (LF_ISSET(DB_MULTIPLE)) {
1641		if (!F_ISSET(data, DB_DBT_BULK)) {
1642			__db_errx(env,
1643			"DB->put with DB_MULTIPLE requires a bulk data buffer");
1644			return (EINVAL);
1645		}
1646	}
1647
1648	/* Check for invalid function flags. */
1649	switch (LF_ISSET(DB_OPFLAGS_MASK)) {
1650	case 0:
1651	case DB_NOOVERWRITE:
1652	case DB_OVERWRITE_DUP:
1653		break;
1654	case DB_APPEND:
1655		if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE)
1656			goto err;
1657		returnkey = 1;
1658		break;
1659	case DB_NODUPDATA:
1660		if (F_ISSET(dbp, DB_AM_DUPSORT))
1661			break;
1662		/* FALLTHROUGH */
1663	default:
1664err:		return (__db_ferr(env, "DB->put", 0));
1665	}
1666
1667	/*
1668	 * Check for invalid key/data flags.  The key may reasonably be NULL
1669	 * if DB_APPEND is set and the application doesn't care about the
1670	 * returned key.
1671	 */
1672	if (((returnkey && key != NULL) || !returnkey) &&
1673	    (ret = __dbt_ferr(dbp, "key", key, returnkey)) != 0)
1674		return (ret);
1675	if (!LF_ISSET(DB_MULTIPLE_KEY) &&
1676	    (ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
1677		return (ret);
1678
1679	/*
1680	 * The key parameter should not be NULL or have the "partial" flag set
1681	 * in a put call unless the user doesn't care about a key value we'd
1682	 * return.  The user tells us they don't care about the returned key by
1683	 * setting the key parameter to NULL or configuring the key DBT to not
1684	 * return any information.  (Returned keys from a put are always record
1685	 * numbers, and returning part of a record number  doesn't make sense:
1686	 * only accept a partial return if the length returned is 0.)
1687	 */
1688	if ((returnkey &&
1689	    key != NULL && F_ISSET(key, DB_DBT_PARTIAL) && key->dlen != 0) ||
1690	    (!returnkey && F_ISSET(key, DB_DBT_PARTIAL)))
1691		return (__db_ferr(env, "key DBT", 0));
1692
1693	/* Check for partial puts in the presence of duplicates. */
1694	if (data != NULL && F_ISSET(data, DB_DBT_PARTIAL) &&
1695	    (F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) {
1696		__db_errx(env,
1697"a partial put in the presence of duplicates requires a cursor operation");
1698		return (EINVAL);
1699	}
1700
1701	if ((flags != DB_APPEND && (ret = __dbt_usercopy(env, key)) != 0) ||
1702	    (!LF_ISSET(DB_MULTIPLE_KEY) &&
1703	    (ret = __dbt_usercopy(env, data)) != 0))
1704		return (ret);
1705
1706	return (0);
1707}
1708
1709/*
1710 * __db_compact_pp --
1711 *	DB->compact pre/post processing.
1712 *
1713 * PUBLIC: int __db_compact_pp __P((DB *, DB_TXN *,
1714 * PUBLIC:       DBT *, DBT *, DB_COMPACT *, u_int32_t, DBT *));
1715 */
1716int
1717__db_compact_pp(dbp, txn, start, stop, c_data, flags, end)
1718	DB *dbp;
1719	DB_TXN *txn;
1720	DBT *start, *stop;
1721	DB_COMPACT *c_data;
1722	u_int32_t flags;
1723	DBT *end;
1724{
1725	DB_COMPACT *dp, l_data;
1726	DB_THREAD_INFO *ip;
1727	ENV *env;
1728	int handle_check, ret, t_ret;
1729
1730	env = dbp->env;
1731
1732	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->compact");
1733
1734	/*
1735	 * !!!
1736	 * The actual argument checking is simple, do it inline, outside of
1737	 * the replication block.
1738	 */
1739	if ((ret = __db_fchk(
1740	    env, "DB->compact", flags, DB_FREELIST_ONLY | DB_FREE_SPACE)) != 0)
1741		return (ret);
1742
1743	/* Check for changes to a read-only database. */
1744	if (DB_IS_READONLY(dbp))
1745		return (__db_rdonly(env, "DB->compact"));
1746
1747	if (start != NULL && (ret = __dbt_usercopy(env, start)) != 0)
1748		return (ret);
1749	if (stop != NULL && (ret = __dbt_usercopy(env, stop)) != 0)
1750		return (ret);
1751
1752	ENV_ENTER(env, ip);
1753
1754	/* Check for replication block. */
1755	handle_check = IS_ENV_REPLICATED(env);
1756	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0,
1757	    txn != NULL)) != 0) {
1758		handle_check = 0;
1759		goto err;
1760	}
1761
1762	if (c_data == NULL) {
1763		dp = &l_data;
1764		memset(dp, 0, sizeof(*dp));
1765	} else
1766		dp = c_data;
1767#ifdef HAVE_PARTITION
1768	if (DB_IS_PARTITIONED(dbp))
1769		ret = __part_compact(dbp, ip, txn, start, stop, dp, flags, end);
1770	else
1771#endif
1772	switch (dbp->type) {
1773	case DB_HASH:
1774		if (!LF_ISSET(DB_FREELIST_ONLY))
1775			goto err;
1776		/* FALLTHROUGH */
1777	case DB_BTREE:
1778	case DB_RECNO:
1779		ret = __bam_compact(dbp, ip, txn, start, stop, dp, flags, end);
1780		break;
1781
1782	default:
1783err:		ret = __dbh_am_chk(dbp, DB_OK_BTREE);
1784		break;
1785	}
1786
1787	/* Release replication block. */
1788	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1789		ret = t_ret;
1790
1791	ENV_LEAVE(env, ip);
1792	__dbt_userfree(env, start, stop, NULL);
1793	return (ret);
1794}
1795
1796/*
1797 * __db_associate_foreign_pp --
1798 *	DB->associate_foreign pre/post processing.
1799 *
1800 * PUBLIC: int __db_associate_foreign_pp __P((DB *, DB *,
1801 * PUBLIC:     int (*)(DB *, const DBT *, DBT *, const DBT *, int *),
1802 * PUBLIC:     u_int32_t));
1803 */
1804int
1805__db_associate_foreign_pp(fdbp, dbp, callback, flags)
1806	DB *dbp, *fdbp;
1807	int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *));
1808	u_int32_t flags;
1809{
1810	/* Most of this is based on the implementation of associate */
1811	DB_THREAD_INFO *ip;
1812	ENV *env;
1813	int handle_check, ret, t_ret;
1814
1815	env = dbp->env;
1816
1817	PANIC_CHECK(env);
1818	STRIP_AUTO_COMMIT(flags);
1819
1820	ENV_ENTER(env, ip);
1821
1822	/* Check for replication block. */
1823	handle_check = IS_ENV_REPLICATED(env);
1824	if (handle_check &&
1825	    (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
1826		handle_check = 0;
1827		goto err;
1828	}
1829
1830	if ((ret = __db_associate_foreign_arg(fdbp, dbp, callback, flags)) != 0)
1831		goto err;
1832
1833	ret = __db_associate_foreign(fdbp, dbp, callback, flags);
1834
1835err:	/* Release replication block. */
1836	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1837		ret = t_ret;
1838	ENV_LEAVE(env, ip);
1839	return (ret);
1840}
1841
1842/*
1843 * __db_associate_foreign_arg --
1844 *	DB->associate_foreign argument checking.
1845 */
1846static int
1847__db_associate_foreign_arg(fdbp, dbp, callback, flags)
1848	DB *dbp, *fdbp;
1849	int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *));
1850	u_int32_t flags;
1851{
1852	ENV *env;
1853
1854	env = fdbp->env;
1855
1856	if (F_ISSET(fdbp, DB_AM_SECONDARY)) {
1857		__db_errx(env,
1858		    "Secondary indices may not be used as foreign databases");
1859		return (EINVAL);
1860	}
1861	if (F_ISSET(fdbp, DB_AM_DUP)) {
1862		__db_errx(env,
1863		    "Foreign databases may not be configured with duplicates");
1864		return (EINVAL);
1865	}
1866	if (F_ISSET(fdbp, DB_AM_RENUMBER)) {
1867		__db_errx(env,
1868	    "Renumbering recno databases may not be used as foreign databases");
1869		return (EINVAL);
1870	}
1871	if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
1872		__db_errx(env,
1873		    "The associating database must be a secondary index.");
1874		return (EINVAL);
1875	}
1876	if (LF_ISSET(DB_FOREIGN_NULLIFY) && callback == NULL) {
1877		__db_errx(env,
1878		    "When specifying a delete action of nullify, a callback%s",
1879		    " function needs to be configured");
1880		return (EINVAL);
1881	} else if (!LF_ISSET(DB_FOREIGN_NULLIFY) && callback != NULL) {
1882		__db_errx(env,
1883		    "When not specifying a delete action of nullify, a%s",
1884		    " callback function cannot be configured");
1885		return (EINVAL);
1886	}
1887
1888	return (0);
1889}
1890
1891/*
1892 * __db_sync_pp --
1893 *	DB->sync pre/post processing.
1894 *
1895 * PUBLIC: int __db_sync_pp __P((DB *, u_int32_t));
1896 */
1897int
1898__db_sync_pp(dbp, flags)
1899	DB *dbp;
1900	u_int32_t flags;
1901{
1902	DB_THREAD_INFO *ip;
1903	ENV *env;
1904	int handle_check, ret, t_ret;
1905
1906	env = dbp->env;
1907
1908	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
1909
1910	/*
1911	 * !!!
1912	 * The actual argument checking is simple, do it inline, outside of
1913	 * the replication block.
1914	 */
1915	if (flags != 0)
1916		return (__db_ferr(env, "DB->sync", 0));
1917
1918	ENV_ENTER(env, ip);
1919
1920	/* Check for replication block. */
1921	handle_check = IS_ENV_REPLICATED(env);
1922	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
1923		handle_check = 0;
1924		goto err;
1925	}
1926
1927	ret = __db_sync(dbp);
1928
1929	/* Release replication block. */
1930	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
1931		ret = t_ret;
1932
1933err:	ENV_LEAVE(env, ip);
1934	return (ret);
1935}
1936
1937/*
1938 * __dbc_close_pp --
1939 *	DBC->close pre/post processing.
1940 *
1941 * PUBLIC: int __dbc_close_pp __P((DBC *));
1942 */
1943int
1944__dbc_close_pp(dbc)
1945	DBC *dbc;
1946{
1947	DB *dbp;
1948	DB_THREAD_INFO *ip;
1949	ENV *env;
1950	int handle_check, ret, t_ret;
1951
1952	dbp = dbc->dbp;
1953	env = dbp->env;
1954
1955	/*
1956	 * If the cursor is already closed we have a serious problem, and we
1957	 * assume that the cursor isn't on the active queue.  Don't do any of
1958	 * the remaining cursor close processing.
1959	 */
1960	if (!F_ISSET(dbc, DBC_ACTIVE)) {
1961		__db_errx(env, "Closing already-closed cursor");
1962		return (EINVAL);
1963	}
1964
1965	ENV_ENTER(env, ip);
1966
1967	/* Check for replication block. */
1968	handle_check = dbc->txn == NULL && IS_ENV_REPLICATED(env);
1969	ret = __dbc_close(dbc);
1970
1971	/* Release replication block. */
1972	if (handle_check &&
1973	    (t_ret = __op_rep_exit(env)) != 0 && ret == 0)
1974		ret = t_ret;
1975
1976	ENV_LEAVE(env, ip);
1977	return (ret);
1978}
1979
1980/*
1981 * __dbc_cmp_pp --
1982 *	DBC->cmp pre/post processing.
1983 *
1984 * PUBLIC: int __dbc_cmp_pp __P((DBC *, DBC *, int*, u_int32_t));
1985 */
1986int
1987__dbc_cmp_pp(dbc, other_cursor, result, flags)
1988	DBC *dbc, *other_cursor;
1989	int *result;
1990	u_int32_t flags;
1991{
1992	DB *dbp, *odbp;
1993	DB_THREAD_INFO *ip;
1994	ENV *env;
1995	int ret;
1996
1997	dbp = dbc->dbp;
1998	odbp = other_cursor->dbp;
1999	env = dbp->env;
2000
2001	if (flags != 0)
2002		return (__db_ferr(env, "DBcursor->cmp", 0));
2003
2004	if (other_cursor == NULL) {
2005		__db_errx(env, "DBcursor->cmp dbc pointer must not be null");
2006		return (EINVAL);
2007	}
2008
2009	if (dbp != odbp) {
2010		__db_errx(env,
2011"DBcursor->cmp both cursors must refer to the same database.");
2012		return (EINVAL);
2013	}
2014
2015	ENV_ENTER(env, ip);
2016	ret = __dbc_cmp(dbc, other_cursor, result);
2017	ENV_LEAVE(env, ip);
2018	return (ret);
2019}
2020
2021/*
2022 * __dbc_count_pp --
2023 *	DBC->count pre/post processing.
2024 *
2025 * PUBLIC: int __dbc_count_pp __P((DBC *, db_recno_t *, u_int32_t));
2026 */
2027int
2028__dbc_count_pp(dbc, recnop, flags)
2029	DBC *dbc;
2030	db_recno_t *recnop;
2031	u_int32_t flags;
2032{
2033	DB *dbp;
2034	DB_THREAD_INFO *ip;
2035	ENV *env;
2036	int ret;
2037
2038	dbp = dbc->dbp;
2039	env = dbp->env;
2040
2041	/*
2042	 * !!!
2043	 * The actual argument checking is simple, do it inline, outside of
2044	 * the replication block.
2045	 *
2046	 * The cursor must be initialized, return EINVAL for an invalid cursor.
2047	 */
2048	if (flags != 0)
2049		return (__db_ferr(env, "DBcursor->count", 0));
2050
2051	if (!IS_INITIALIZED(dbc))
2052		return (__db_curinval(env));
2053
2054	ENV_ENTER(env, ip);
2055	ret = __dbc_count(dbc, recnop);
2056	ENV_LEAVE(env, ip);
2057	return (ret);
2058}
2059
2060/*
2061 * __dbc_del_pp --
2062 *	DBC->del pre/post processing.
2063 *
2064 * PUBLIC: int __dbc_del_pp __P((DBC *, u_int32_t));
2065 */
2066int
2067__dbc_del_pp(dbc, flags)
2068	DBC *dbc;
2069	u_int32_t flags;
2070{
2071	DB *dbp;
2072	DB_THREAD_INFO *ip;
2073	ENV *env;
2074	int ret;
2075
2076	dbp = dbc->dbp;
2077	env = dbp->env;
2078
2079	if ((ret = __dbc_del_arg(dbc, flags)) != 0)
2080		return (ret);
2081
2082	ENV_ENTER(env, ip);
2083
2084	/* Check for consistent transaction usage. */
2085	if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
2086		goto err;
2087
2088	DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->del", NULL, NULL, flags);
2089	ret = __dbc_del(dbc, flags);
2090
2091err:	ENV_LEAVE(env, ip);
2092	return (ret);
2093}
2094
2095/*
2096 * __dbc_del_arg --
2097 *	Check DBC->del arguments.
2098 */
2099static int
2100__dbc_del_arg(dbc, flags)
2101	DBC *dbc;
2102	u_int32_t flags;
2103{
2104	DB *dbp;
2105	ENV *env;
2106
2107	dbp = dbc->dbp;
2108	env = dbp->env;
2109
2110	/* Check for changes to a read-only tree. */
2111	if (DB_IS_READONLY(dbp))
2112		return (__db_rdonly(env, "DBcursor->del"));
2113
2114	/* Check for invalid function flags. */
2115	switch (flags) {
2116	case 0:
2117		break;
2118	case DB_CONSUME:
2119		if (dbp->type != DB_QUEUE)
2120			return (__db_ferr(env, "DBC->del", 0));
2121		break;
2122	case DB_UPDATE_SECONDARY:
2123		DB_ASSERT(env, F_ISSET(dbp, DB_AM_SECONDARY));
2124		break;
2125	default:
2126		return (__db_ferr(env, "DBcursor->del", 0));
2127	}
2128
2129	/*
2130	 * The cursor must be initialized, return EINVAL for an invalid cursor,
2131	 * otherwise 0.
2132	 */
2133	if (!IS_INITIALIZED(dbc))
2134		return (__db_curinval(env));
2135
2136	return (0);
2137}
2138
2139/*
2140 * __dbc_dup_pp --
2141 *	DBC->dup pre/post processing.
2142 *
2143 * PUBLIC: int __dbc_dup_pp __P((DBC *, DBC **, u_int32_t));
2144 */
2145int
2146__dbc_dup_pp(dbc, dbcp, flags)
2147	DBC *dbc, **dbcp;
2148	u_int32_t flags;
2149{
2150	DB *dbp;
2151	DB_THREAD_INFO *ip;
2152	ENV *env;
2153	int ret;
2154
2155	dbp = dbc->dbp;
2156	env = dbp->env;
2157
2158	/*
2159	 * !!!
2160	 * The actual argument checking is simple, do it inline, outside of
2161	 * the replication block.
2162	 */
2163	if (flags != 0 && flags != DB_POSITION)
2164		return (__db_ferr(env, "DBcursor->dup", 0));
2165
2166	ENV_ENTER(env, ip);
2167	ret = __dbc_dup(dbc, dbcp, flags);
2168	ENV_LEAVE(env, ip);
2169	return (ret);
2170}
2171
2172/*
2173 * __dbc_get_pp --
2174 *	DBC->get pre/post processing.
2175 *
2176 * PUBLIC: int __dbc_get_pp __P((DBC *, DBT *, DBT *, u_int32_t));
2177 */
2178int
2179__dbc_get_pp(dbc, key, data, flags)
2180	DBC *dbc;
2181	DBT *key, *data;
2182	u_int32_t flags;
2183{
2184	DB *dbp;
2185	DB_THREAD_INFO *ip;
2186	ENV *env;
2187	int ignore_lease, ret;
2188
2189	dbp = dbc->dbp;
2190	env = dbp->env;
2191
2192	ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0;
2193	LF_CLR(DB_IGNORE_LEASE);
2194	if ((ret = __dbc_get_arg(dbc, key, data, flags)) != 0)
2195		return (ret);
2196
2197	ENV_ENTER(env, ip);
2198
2199	DEBUG_LREAD(dbc, dbc->txn, "DBcursor->get",
2200	    flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags);
2201	ret = __dbc_get(dbc, key, data, flags);
2202
2203	/*
2204	 * Check for master leases.
2205	 */
2206	if (ret == 0 &&
2207	    IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease)
2208		ret = __rep_lease_check(env, 1);
2209
2210	ENV_LEAVE(env, ip);
2211	__dbt_userfree(env, key, NULL, data);
2212	return (ret);
2213}
2214
2215/*
2216 * __dbc_get_arg --
2217 *	Common DBC->get argument checking, used by both DBC->get and DBC->pget.
2218 * PUBLIC: int __dbc_get_arg __P((DBC *, DBT *, DBT *, u_int32_t));
2219 */
2220int
2221__dbc_get_arg(dbc, key, data, flags)
2222	DBC *dbc;
2223	DBT *key, *data;
2224	u_int32_t flags;
2225{
2226	DB *dbp;
2227	ENV *env;
2228	int dirty, multi, ret;
2229
2230	dbp = dbc->dbp;
2231	env = dbp->env;
2232
2233	/*
2234	 * Typically in checking routines that modify the flags, we have
2235	 * to save them and restore them, because the checking routine
2236	 * calls the work routine.  However, this is a pure-checking
2237	 * routine which returns to a function that calls the work routine,
2238	 * so it's OK that we do not save and restore the flags, even though
2239	 * we modify them.
2240	 *
2241	 * Check for read-modify-write validity.  DB_RMW doesn't make sense
2242	 * with CDB cursors since if you're going to write the cursor, you
2243	 * had to create it with DB_WRITECURSOR.  Regardless, we check for
2244	 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
2245	 * If this changes, confirm that DB does not itself set the DB_RMW
2246	 * flag in a path where CDB may have been configured.
2247	 */
2248	dirty = 0;
2249	if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) {
2250		if (!LOCKING_ON(env))
2251			return (__db_fnl(env, "DBcursor->get"));
2252		if (LF_ISSET(DB_READ_UNCOMMITTED))
2253			dirty = 1;
2254		LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW);
2255	}
2256
2257	multi = 0;
2258	if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
2259		multi = 1;
2260		if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY))
2261			goto multi_err;
2262		LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY);
2263	}
2264
2265	/* Check for invalid function flags. */
2266	switch (flags) {
2267	case DB_CONSUME:
2268	case DB_CONSUME_WAIT:
2269		if (dirty) {
2270			__db_errx(env,
2271    "DB_READ_UNCOMMITTED is not supported with DB_CONSUME or DB_CONSUME_WAIT");
2272			return (EINVAL);
2273		}
2274		if (dbp->type != DB_QUEUE)
2275			goto err;
2276		break;
2277	case DB_CURRENT:
2278	case DB_FIRST:
2279	case DB_NEXT:
2280	case DB_NEXT_DUP:
2281	case DB_NEXT_NODUP:
2282		break;
2283	case DB_LAST:
2284	case DB_PREV:
2285	case DB_PREV_DUP:
2286	case DB_PREV_NODUP:
2287		if (multi)
2288multi_err:		return (__db_ferr(env, "DBcursor->get", 1));
2289		break;
2290	case DB_GET_BOTHC:
2291		if (dbp->type == DB_QUEUE)
2292			goto err;
2293		/* FALLTHROUGH */
2294	case DB_GET_BOTH:
2295	case DB_GET_BOTH_RANGE:
2296		if ((ret = __dbt_usercopy(env, data)) != 0)
2297			goto err;
2298		/* FALLTHROUGH */
2299	case DB_SET:
2300	case DB_SET_RANGE:
2301		if ((ret = __dbt_usercopy(env, key)) != 0)
2302			goto err;
2303		break;
2304	case DB_GET_RECNO:
2305		/*
2306		 * The one situation in which this might be legal with a
2307		 * non-RECNUM dbp is if dbp is a secondary and its primary is
2308		 * DB_AM_RECNUM.
2309		 */
2310		if (!F_ISSET(dbp, DB_AM_RECNUM) &&
2311		    (!F_ISSET(dbp, DB_AM_SECONDARY) ||
2312		    !F_ISSET(dbp->s_primary, DB_AM_RECNUM)))
2313			goto err;
2314		break;
2315	case DB_SET_RECNO:
2316		if (!F_ISSET(dbp, DB_AM_RECNUM))
2317			goto err;
2318		if ((ret = __dbt_usercopy(env, key)) != 0)
2319			goto err;
2320		break;
2321	default:
2322err:		__dbt_userfree(env, key, NULL, data);
2323		return (__db_ferr(env, "DBcursor->get", 0));
2324	}
2325
2326	/* Check for invalid key/data flags. */
2327	if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
2328		return (ret);
2329	if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
2330		return (ret);
2331
2332	if (multi) {
2333		if (!F_ISSET(data, DB_DBT_USERMEM)) {
2334			__db_errx(env,
2335	    "DB_MULTIPLE/DB_MULTIPLE_KEY require DB_DBT_USERMEM be set");
2336			return (EINVAL);
2337		}
2338		if (F_ISSET(key, DB_DBT_PARTIAL) ||
2339		    F_ISSET(data, DB_DBT_PARTIAL)) {
2340			__db_errx(env,
2341	    "DB_MULTIPLE/DB_MULTIPLE_KEY do not support DB_DBT_PARTIAL");
2342			return (EINVAL);
2343		}
2344		if (data->ulen < 1024 ||
2345		    data->ulen < dbp->pgsize || data->ulen % 1024 != 0) {
2346			__db_errx(env, "%s%s",
2347			    "DB_MULTIPLE/DB_MULTIPLE_KEY buffers must be ",
2348			    "aligned, at least page size and multiples of 1KB");
2349			return (EINVAL);
2350		}
2351	}
2352
2353	/*
2354	 * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO,
2355	 * DB_PREV_DUP and DB_NEXT_DUP.  Return EINVAL for an invalid
2356	 * cursor, otherwise 0.
2357	 */
2358	if (!IS_INITIALIZED(dbc) && (flags == DB_CURRENT ||
2359	    flags == DB_GET_RECNO ||
2360	    flags == DB_NEXT_DUP || flags == DB_PREV_DUP))
2361		return (__db_curinval(env));
2362
2363	/* Check for consistent transaction usage. */
2364	if (LF_ISSET(DB_RMW) &&
2365	    (ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
2366		return (ret);
2367
2368	return (0);
2369}
2370
2371/*
2372 * __db_secondary_close_pp --
2373 *	DB->close for secondaries
2374 *
2375 * PUBLIC: int __db_secondary_close_pp __P((DB *, u_int32_t));
2376 */
2377int
2378__db_secondary_close_pp(dbp, flags)
2379	DB *dbp;
2380	u_int32_t flags;
2381{
2382	DB_THREAD_INFO *ip;
2383	ENV *env;
2384	int handle_check, ret, t_ret;
2385
2386	env = dbp->env;
2387	ret = 0;
2388
2389	/*
2390	 * As a DB handle destructor, we can't fail.
2391	 *
2392	 * !!!
2393	 * The actual argument checking is simple, do it inline, outside of
2394	 * the replication block.
2395	 */
2396	if (flags != 0 && flags != DB_NOSYNC)
2397		ret = __db_ferr(env, "DB->close", 0);
2398
2399	ENV_ENTER(env, ip);
2400
2401	/* Check for replication block. */
2402	handle_check = IS_ENV_REPLICATED(env);
2403	if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) {
2404		handle_check = 0;
2405		if (ret == 0)
2406			ret = t_ret;
2407	}
2408
2409	if ((t_ret = __db_secondary_close(dbp, flags)) != 0 && ret == 0)
2410		ret = t_ret;
2411
2412	/* Release replication block. */
2413	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
2414		ret = t_ret;
2415
2416	ENV_LEAVE(env, ip);
2417	return (ret);
2418}
2419
2420/*
2421 * __dbc_pget_pp --
2422 *	DBC->pget pre/post processing.
2423 *
2424 * PUBLIC: int __dbc_pget_pp __P((DBC *, DBT *, DBT *, DBT *, u_int32_t));
2425 */
2426int
2427__dbc_pget_pp(dbc, skey, pkey, data, flags)
2428	DBC *dbc;
2429	DBT *skey, *pkey, *data;
2430	u_int32_t flags;
2431{
2432	DB *dbp;
2433	DB_THREAD_INFO *ip;
2434	ENV *env;
2435	int ignore_lease, ret;
2436
2437	dbp = dbc->dbp;
2438	env = dbp->env;
2439
2440	ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0;
2441	LF_CLR(DB_IGNORE_LEASE);
2442	if ((ret = __dbc_pget_arg(dbc, pkey, flags)) != 0 ||
2443	    (ret = __dbc_get_arg(dbc, skey, data, flags)) != 0)
2444		return (ret);
2445
2446	ENV_ENTER(env, ip);
2447	ret = __dbc_pget(dbc, skey, pkey, data, flags);
2448	/*
2449	 * Check for master leases.
2450	 */
2451	if (ret == 0 &&
2452	    IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease)
2453		ret = __rep_lease_check(env, 1);
2454
2455	ENV_LEAVE(env, ip);
2456
2457	__dbt_userfree(env, skey, pkey, data);
2458	return (ret);
2459}
2460
2461/*
2462 * __dbc_pget_arg --
2463 *	Check DBC->pget arguments.
2464 */
2465static int
2466__dbc_pget_arg(dbc, pkey, flags)
2467	DBC *dbc;
2468	DBT *pkey;
2469	u_int32_t flags;
2470{
2471	DB *dbp;
2472	ENV *env;
2473	int ret;
2474
2475	dbp = dbc->dbp;
2476	env = dbp->env;
2477
2478	if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
2479		__db_errx(env,
2480		    "DBcursor->pget may only be used on secondary indices");
2481		return (EINVAL);
2482	}
2483
2484	if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
2485		__db_errx(env,
2486	"DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
2487		return (EINVAL);
2488	}
2489
2490	switch (LF_ISSET(DB_OPFLAGS_MASK)) {
2491	case DB_CONSUME:
2492	case DB_CONSUME_WAIT:
2493		/* These flags make no sense on a secondary index. */
2494		return (__db_ferr(env, "DBcursor->pget", 0));
2495	case DB_GET_BOTH:
2496	case DB_GET_BOTH_RANGE:
2497		/* BOTH is "get both the primary and the secondary". */
2498		if (pkey == NULL) {
2499			__db_errx(env,
2500			    "%s requires both a secondary and a primary key",
2501			     LF_ISSET(DB_GET_BOTH) ?
2502			     "DB_GET_BOTH" : "DB_GET_BOTH_RANGE");
2503			return (EINVAL);
2504		}
2505		if ((ret = __dbt_usercopy(env, pkey)) != 0)
2506			return (ret);
2507		break;
2508	default:
2509		/* __dbc_get_arg will catch the rest. */
2510		break;
2511	}
2512
2513	/*
2514	 * We allow the pkey field to be NULL, so that we can make the
2515	 * two-DBT get calls into wrappers for the three-DBT ones.
2516	 */
2517	if (pkey != NULL &&
2518	    (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0)
2519		return (ret);
2520
2521	/* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */
2522	if (pkey == NULL && (flags & DB_OPFLAGS_MASK) == DB_GET_BOTH) {
2523		__db_errx(env,
2524		    "DB_GET_BOTH on a secondary index requires a primary key");
2525		return (EINVAL);
2526	}
2527	return (0);
2528}
2529
2530/*
2531 * __dbc_put_pp --
2532 *	DBC->put pre/post processing.
2533 *
2534 * PUBLIC: int __dbc_put_pp __P((DBC *, DBT *, DBT *, u_int32_t));
2535 */
2536int
2537__dbc_put_pp(dbc, key, data, flags)
2538	DBC *dbc;
2539	DBT *key, *data;
2540	u_int32_t flags;
2541{
2542	DB *dbp;
2543	DB_THREAD_INFO *ip;
2544	ENV *env;
2545	int ret;
2546
2547	dbp = dbc->dbp;
2548	env = dbp->env;
2549
2550	if ((ret = __dbc_put_arg(dbc, key, data, flags)) != 0)
2551		return (ret);
2552
2553	ENV_ENTER(env, ip);
2554
2555	/* Check for consistent transaction usage. */
2556	if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
2557		goto err;
2558
2559	DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->put",
2560	    flags == DB_KEYFIRST || flags == DB_KEYLAST ||
2561	    flags == DB_NODUPDATA || flags == DB_UPDATE_SECONDARY ?
2562	    key : NULL, data, flags);
2563	ret = __dbc_put(dbc, key, data, flags);
2564
2565err:	ENV_LEAVE(env, ip);
2566	__dbt_userfree(env, key, NULL, data);
2567	return (ret);
2568}
2569
2570/*
2571 * __dbc_put_arg --
2572 *	Check DBC->put arguments.
2573 */
2574static int
2575__dbc_put_arg(dbc, key, data, flags)
2576	DBC *dbc;
2577	DBT *key, *data;
2578	u_int32_t flags;
2579{
2580	DB *dbp;
2581	ENV *env;
2582	int key_flags, ret;
2583
2584	dbp = dbc->dbp;
2585	env = dbp->env;
2586	key_flags = 0;
2587
2588	/* Check for changes to a read-only tree. */
2589	if (DB_IS_READONLY(dbp))
2590		return (__db_rdonly(env, "DBcursor->put"));
2591
2592	/* Check for puts on a secondary. */
2593	if (F_ISSET(dbp, DB_AM_SECONDARY)) {
2594		if (flags == DB_UPDATE_SECONDARY)
2595			flags = 0;
2596		else {
2597			__db_errx(env,
2598			    "DBcursor->put forbidden on secondary indices");
2599			return (EINVAL);
2600		}
2601	}
2602
2603	if ((ret = __dbt_usercopy(env, data)) != 0)
2604		return (ret);
2605
2606	/* Check for invalid function flags. */
2607	switch (flags) {
2608	case DB_AFTER:
2609	case DB_BEFORE:
2610		switch (dbp->type) {
2611		case DB_BTREE:
2612		case DB_HASH:		/* Only with unsorted duplicates. */
2613			if (!F_ISSET(dbp, DB_AM_DUP))
2614				goto err;
2615			if (dbp->dup_compare != NULL)
2616				goto err;
2617			break;
2618		case DB_QUEUE:		/* Not permitted. */
2619			goto err;
2620		case DB_RECNO:		/* Only with mutable record numbers. */
2621			if (!F_ISSET(dbp, DB_AM_RENUMBER))
2622				goto err;
2623			key_flags = key == NULL ? 0 : 1;
2624			break;
2625		case DB_UNKNOWN:
2626		default:
2627			goto err;
2628		}
2629		break;
2630	case DB_CURRENT:
2631		/*
2632		 * If there is a comparison function, doing a DB_CURRENT
2633		 * must not change the part of the data item that is used
2634		 * for the comparison.
2635		 */
2636		break;
2637	case DB_NODUPDATA:
2638		if (!F_ISSET(dbp, DB_AM_DUPSORT))
2639			goto err;
2640		/* FALLTHROUGH */
2641	case DB_KEYFIRST:
2642	case DB_KEYLAST:
2643	case DB_OVERWRITE_DUP:
2644		key_flags = 1;
2645		if ((ret = __dbt_usercopy(env, key)) != 0)
2646			return (ret);
2647		break;
2648	default:
2649err:		return (__db_ferr(env, "DBcursor->put", 0));
2650	}
2651
2652	/*
2653	 * Check for invalid key/data flags.  The key may reasonably be NULL
2654	 * if DB_AFTER or DB_BEFORE is set and the application doesn't care
2655	 * about the returned key, or if the DB_CURRENT flag is set.
2656	 */
2657	if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
2658		return (ret);
2659	if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
2660		return (ret);
2661
2662	/*
2663	 * The key parameter should not be NULL or have the "partial" flag set
2664	 * in a put call unless the user doesn't care about a key value we'd
2665	 * return.  The user tells us they don't care about the returned key by
2666	 * setting the key parameter to NULL or configuring the key DBT to not
2667	 * return any information.  (Returned keys from a put are always record
2668	 * numbers, and returning part of a record number  doesn't make sense:
2669	 * only accept a partial return if the length returned is 0.)
2670	 */
2671	if (key_flags && F_ISSET(key, DB_DBT_PARTIAL) && key->dlen != 0)
2672		return (__db_ferr(env, "key DBT", 0));
2673
2674	/*
2675	 * The cursor must be initialized for anything other than DB_KEYFIRST,
2676	 * DB_KEYLAST or zero: return EINVAL for an invalid cursor, otherwise 0.
2677	 */
2678	if (!IS_INITIALIZED(dbc) && flags != 0 && flags != DB_KEYFIRST &&
2679	    flags != DB_KEYLAST && flags != DB_NODUPDATA &&
2680	    flags != DB_OVERWRITE_DUP)
2681		return (__db_curinval(env));
2682
2683	return (0);
2684}
2685
2686/*
2687 * __dbt_ferr --
2688 *	Check a DBT for flag errors.
2689 */
2690static int
2691__dbt_ferr(dbp, name, dbt, check_thread)
2692	const DB *dbp;
2693	const char *name;
2694	const DBT *dbt;
2695	int check_thread;
2696{
2697	ENV *env;
2698	int ret;
2699
2700	env = dbp->env;
2701
2702	/*
2703	 * Check for invalid DBT flags.  We allow any of the flags to be
2704	 * specified to any DB or DBcursor call so that applications can
2705	 * set DB_DBT_MALLOC when retrieving a data item from a secondary
2706	 * database and then specify that same DBT as a key to a primary
2707	 * database, without having to clear flags.
2708	 */
2709	if ((ret = __db_fchk(env, name, dbt->flags, DB_DBT_APPMALLOC |
2710	    DB_DBT_BULK | DB_DBT_DUPOK | DB_DBT_MALLOC | DB_DBT_REALLOC |
2711	    DB_DBT_USERCOPY | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0)
2712		return (ret);
2713	switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC |
2714	    DB_DBT_USERCOPY | DB_DBT_USERMEM)) {
2715	case 0:
2716	case DB_DBT_MALLOC:
2717	case DB_DBT_REALLOC:
2718	case DB_DBT_USERCOPY:
2719	case DB_DBT_USERMEM:
2720		break;
2721	default:
2722		return (__db_ferr(env, name, 1));
2723	}
2724
2725	if (F_ISSET(dbt, DB_DBT_BULK) && F_ISSET(dbt, DB_DBT_PARTIAL)) {
2726		__db_errx(env,
2727	      "Bulk and partial operations cannot be combined on %s DBT", name);
2728		return (EINVAL);
2729	}
2730
2731	if (check_thread && DB_IS_THREADED(dbp) &&
2732	    !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC |
2733		DB_DBT_USERCOPY | DB_DBT_USERMEM)) {
2734		__db_errx(env,
2735		    "DB_THREAD mandates memory allocation flag on %s DBT",
2736		    name);
2737		return (EINVAL);
2738	}
2739	return (0);
2740}
2741
2742/*
2743 * __db_curinval
2744 *	Report that a cursor is in an invalid state.
2745 */
2746static int
2747__db_curinval(env)
2748	const ENV *env;
2749{
2750	__db_errx(env,
2751	    "Cursor position must be set before performing this operation");
2752	return (EINVAL);
2753}
2754
2755/*
2756 * __db_txn_auto_init --
2757 *	Handle DB_AUTO_COMMIT initialization.
2758 *
2759 * PUBLIC: int __db_txn_auto_init __P((ENV *, DB_THREAD_INFO *, DB_TXN **));
2760 */
2761int
2762__db_txn_auto_init(env, ip, txnidp)
2763	ENV *env;
2764	DB_THREAD_INFO *ip;
2765	DB_TXN **txnidp;
2766{
2767	/*
2768	 * Method calls where applications explicitly specify DB_AUTO_COMMIT
2769	 * require additional validation: the DB_AUTO_COMMIT flag cannot be
2770	 * specified if a transaction cookie is also specified, nor can the
2771	 * flag be specified in a non-transactional environment.
2772	 */
2773	if (*txnidp != NULL) {
2774		__db_errx(env,
2775    "DB_AUTO_COMMIT may not be specified along with a transaction handle");
2776		return (EINVAL);
2777	}
2778
2779	if (!TXN_ON(env)) {
2780		__db_errx(env,
2781    "DB_AUTO_COMMIT may not be specified in non-transactional environment");
2782		return (EINVAL);
2783	}
2784
2785	/*
2786	 * Our caller checked to see if replication is making a state change.
2787	 * Don't call the user-level API (which would repeat that check).
2788	 */
2789	return (__txn_begin(env, ip, NULL, txnidp, 0));
2790}
2791
2792/*
2793 * __db_txn_auto_resolve --
2794 *	Resolve local transactions.
2795 *
2796 * PUBLIC: int __db_txn_auto_resolve __P((ENV *, DB_TXN *, int, int));
2797 */
2798int
2799__db_txn_auto_resolve(env, txn, nosync, ret)
2800	ENV *env;
2801	DB_TXN *txn;
2802	int nosync, ret;
2803{
2804	int t_ret;
2805
2806	/*
2807	 * We're resolving a transaction for the user, and must decrement the
2808	 * replication handle count.  Call the user-level API.
2809	 */
2810	if (ret == 0)
2811		return (__txn_commit(txn, nosync ? DB_TXN_NOSYNC : 0));
2812
2813	if ((t_ret = __txn_abort(txn)) != 0)
2814		return (__env_panic(env, t_ret));
2815
2816	return (ret);
2817}
2818