1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: bt_method.c,v 12.10 2008/01/08 20:57:59 bostic Exp $
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/qam.h"
15
16static int __bam_set_bt_minkey __P((DB *, u_int32_t));
17static int __bam_set_bt_prefix
18	       __P((DB *, size_t(*)(DB *, const DBT *, const DBT *)));
19static int __ram_get_re_delim __P((DB *, int *));
20static int __ram_set_re_delim __P((DB *, int));
21static int __ram_set_re_len __P((DB *, u_int32_t));
22static int __ram_set_re_pad __P((DB *, int));
23static int __ram_get_re_source __P((DB *, const char **));
24static int __ram_set_re_source __P((DB *, const char *));
25
26/*
27 * __bam_db_create --
28 *	Btree specific initialization of the DB structure.
29 *
30 * PUBLIC: int __bam_db_create __P((DB *));
31 */
32int
33__bam_db_create(dbp)
34	DB *dbp;
35{
36	BTREE *t;
37	int ret;
38
39	/* Allocate and initialize the private btree structure. */
40	if ((ret = __os_calloc(dbp->env, 1, sizeof(BTREE), &t)) != 0)
41		return (ret);
42	dbp->bt_internal = t;
43
44	t->bt_minkey = DEFMINKEYPAGE;		/* Btree */
45	t->bt_compare = __bam_defcmp;
46	t->bt_prefix = __bam_defpfx;
47
48	dbp->set_bt_compare = __bam_set_bt_compare;
49	dbp->get_bt_minkey = __bam_get_bt_minkey;
50	dbp->set_bt_minkey = __bam_set_bt_minkey;
51	dbp->set_bt_prefix = __bam_set_bt_prefix;
52
53	t->re_pad = ' ';			/* Recno */
54	t->re_delim = '\n';
55	t->re_eof = 1;
56
57	dbp->get_re_delim = __ram_get_re_delim;
58	dbp->set_re_delim = __ram_set_re_delim;
59	dbp->get_re_len = __ram_get_re_len;
60	dbp->set_re_len = __ram_set_re_len;
61	dbp->get_re_pad = __ram_get_re_pad;
62	dbp->set_re_pad = __ram_set_re_pad;
63	dbp->get_re_source = __ram_get_re_source;
64	dbp->set_re_source = __ram_set_re_source;
65
66	return (0);
67}
68
69/*
70 * __bam_db_close --
71 *	Btree specific discard of the DB structure.
72 *
73 * PUBLIC: int __bam_db_close __P((DB *));
74 */
75int
76__bam_db_close(dbp)
77	DB *dbp;
78{
79	BTREE *t;
80
81	if ((t = dbp->bt_internal) == NULL)
82		return (0);
83						/* Recno */
84	/* Close any backing source file descriptor. */
85	if (t->re_fp != NULL)
86		(void)fclose(t->re_fp);
87
88	/* Free any backing source file name. */
89	if (t->re_source != NULL)
90		__os_free(dbp->env, t->re_source);
91
92	__os_free(dbp->env, t);
93	dbp->bt_internal = NULL;
94
95	return (0);
96}
97
98/*
99 * __bam_map_flags --
100 *	Map Btree specific flags from public to the internal values.
101 *
102 * PUBLIC: void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *));
103 */
104void
105__bam_map_flags(dbp, inflagsp, outflagsp)
106	DB *dbp;
107	u_int32_t *inflagsp, *outflagsp;
108{
109	COMPQUIET(dbp, NULL);
110
111	if (FLD_ISSET(*inflagsp, DB_DUP)) {
112		FLD_SET(*outflagsp, DB_AM_DUP);
113		FLD_CLR(*inflagsp, DB_DUP);
114	}
115	if (FLD_ISSET(*inflagsp, DB_DUPSORT)) {
116		FLD_SET(*outflagsp, DB_AM_DUP | DB_AM_DUPSORT);
117		FLD_CLR(*inflagsp, DB_DUPSORT);
118	}
119	if (FLD_ISSET(*inflagsp, DB_RECNUM)) {
120		FLD_SET(*outflagsp, DB_AM_RECNUM);
121		FLD_CLR(*inflagsp, DB_RECNUM);
122	}
123	if (FLD_ISSET(*inflagsp, DB_REVSPLITOFF)) {
124		FLD_SET(*outflagsp, DB_AM_REVSPLITOFF);
125		FLD_CLR(*inflagsp, DB_REVSPLITOFF);
126	}
127}
128
129/*
130 * __bam_set_flags --
131 *	Set Btree specific flags.
132 *
133 * PUBLIC: int __bam_set_flags __P((DB *, u_int32_t *flagsp));
134 */
135int
136__bam_set_flags(dbp, flagsp)
137	DB *dbp;
138	u_int32_t *flagsp;
139{
140	u_int32_t flags;
141
142	flags = *flagsp;
143	if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF))
144		DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
145
146	/*
147	 * The DB_DUP and DB_DUPSORT flags are shared by the Hash
148	 * and Btree access methods.
149	 */
150	if (LF_ISSET(DB_DUP | DB_DUPSORT))
151		DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
152
153	if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF))
154		DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
155
156	/* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */
157	if (LF_ISSET(DB_DUP | DB_DUPSORT) && F_ISSET(dbp, DB_AM_RECNUM))
158		goto incompat;
159
160	/* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */
161	if (LF_ISSET(DB_RECNUM) && F_ISSET(dbp, DB_AM_DUP))
162		goto incompat;
163
164	if (LF_ISSET(DB_DUPSORT) && dbp->dup_compare == NULL)
165		dbp->dup_compare = __bam_defcmp;
166
167	__bam_map_flags(dbp, flagsp, &dbp->flags);
168	return (0);
169
170incompat:
171	return (__db_ferr(dbp->env, "DB->set_flags", 1));
172}
173
174/*
175 * __bam_set_bt_compare --
176 *	Set the comparison function.
177 *
178 * PUBLIC: int __bam_set_bt_compare
179 * PUBLIC:         __P((DB *, int (*)(DB *, const DBT *, const DBT *)));
180 */
181int
182__bam_set_bt_compare(dbp, func)
183	DB *dbp;
184	int (*func) __P((DB *, const DBT *, const DBT *));
185{
186	BTREE *t;
187
188	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compare");
189	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
190
191	t = dbp->bt_internal;
192
193	/*
194	 * Can't default the prefix routine if the user supplies a comparison
195	 * routine; shortening the keys can break their comparison algorithm.
196	 */
197	t->bt_compare = func;
198	if (t->bt_prefix == __bam_defpfx)
199		t->bt_prefix = NULL;
200
201	return (0);
202}
203
204/*
205 * __db_get_bt_minkey --
206 *	Get the minimum keys per page.
207 *
208 * PUBLIC: int __bam_get_bt_minkey __P((DB *, u_int32_t *));
209 */
210int
211__bam_get_bt_minkey(dbp, bt_minkeyp)
212	DB *dbp;
213	u_int32_t *bt_minkeyp;
214{
215	BTREE *t;
216
217	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
218
219	t = dbp->bt_internal;
220	*bt_minkeyp = t->bt_minkey;
221	return (0);
222}
223
224/*
225 * __bam_set_bt_minkey --
226 *	Set the minimum keys per page.
227 */
228static int
229__bam_set_bt_minkey(dbp, bt_minkey)
230	DB *dbp;
231	u_int32_t bt_minkey;
232{
233	BTREE *t;
234
235	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_minkey");
236	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
237
238	t = dbp->bt_internal;
239
240	if (bt_minkey < 2) {
241		__db_errx(dbp->env, "minimum bt_minkey value is 2");
242		return (EINVAL);
243	}
244
245	t->bt_minkey = bt_minkey;
246	return (0);
247}
248
249/*
250 * __bam_set_bt_prefix --
251 *	Set the prefix function.
252 */
253static int
254__bam_set_bt_prefix(dbp, func)
255	DB *dbp;
256	size_t (*func) __P((DB *, const DBT *, const DBT *));
257{
258	BTREE *t;
259
260	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_prefix");
261	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
262
263	t = dbp->bt_internal;
264
265	t->bt_prefix = func;
266	return (0);
267}
268
269/*
270 * __ram_map_flags --
271 *	Map Recno specific flags from public to the internal values.
272 *
273 * PUBLIC: void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *));
274 */
275void
276__ram_map_flags(dbp, inflagsp, outflagsp)
277	DB *dbp;
278	u_int32_t *inflagsp, *outflagsp;
279{
280	COMPQUIET(dbp, NULL);
281
282	if (FLD_ISSET(*inflagsp, DB_RENUMBER)) {
283		FLD_SET(*outflagsp, DB_AM_RENUMBER);
284		FLD_CLR(*inflagsp, DB_RENUMBER);
285	}
286	if (FLD_ISSET(*inflagsp, DB_SNAPSHOT)) {
287		FLD_SET(*outflagsp, DB_AM_SNAPSHOT);
288		FLD_CLR(*inflagsp, DB_SNAPSHOT);
289	}
290}
291
292/*
293 * __ram_set_flags --
294 *	Set Recno specific flags.
295 *
296 * PUBLIC: int __ram_set_flags __P((DB *, u_int32_t *flagsp));
297 */
298int
299__ram_set_flags(dbp, flagsp)
300	DB *dbp;
301	u_int32_t *flagsp;
302{
303	u_int32_t flags;
304
305	flags = *flagsp;
306	if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) {
307		DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
308		DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
309	}
310
311	__ram_map_flags(dbp, flagsp, &dbp->flags);
312	return (0);
313}
314
315/*
316 * __db_get_re_delim --
317 *	Get the variable-length input record delimiter.
318 */
319static int
320__ram_get_re_delim(dbp, re_delimp)
321	DB *dbp;
322	int *re_delimp;
323{
324	BTREE *t;
325
326	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
327	t = dbp->bt_internal;
328	*re_delimp = t->re_delim;
329	return (0);
330}
331
332/*
333 * __ram_set_re_delim --
334 *	Set the variable-length input record delimiter.
335 */
336static int
337__ram_set_re_delim(dbp, re_delim)
338	DB *dbp;
339	int re_delim;
340{
341	BTREE *t;
342
343	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_delim");
344	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
345
346	t = dbp->bt_internal;
347
348	t->re_delim = re_delim;
349	F_SET(dbp, DB_AM_DELIMITER);
350
351	return (0);
352}
353
354/*
355 * __db_get_re_len --
356 *	Get the variable-length input record length.
357 *
358 * PUBLIC: int __ram_get_re_len __P((DB *, u_int32_t *));
359 */
360int
361__ram_get_re_len(dbp, re_lenp)
362	DB *dbp;
363	u_int32_t *re_lenp;
364{
365	BTREE *t;
366	QUEUE *q;
367
368	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
369
370	/*
371	 * This has to work for all access methods, before or after opening the
372	 * database.  When the record length is set with __ram_set_re_len, the
373	 * value in both the BTREE and QUEUE structs will be correct.
374	 * Otherwise, this only makes sense after the database in opened, in
375	 * which case we know the type.
376	 */
377	if (dbp->type == DB_QUEUE) {
378		q = dbp->q_internal;
379		*re_lenp = q->re_len;
380	} else {
381		t = dbp->bt_internal;
382		*re_lenp = t->re_len;
383	}
384
385	return (0);
386}
387
388/*
389 * __ram_set_re_len --
390 *	Set the variable-length input record length.
391 */
392static int
393__ram_set_re_len(dbp, re_len)
394	DB *dbp;
395	u_int32_t re_len;
396{
397	BTREE *t;
398	QUEUE *q;
399
400	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_len");
401	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
402
403	t = dbp->bt_internal;
404	t->re_len = re_len;
405
406	q = dbp->q_internal;
407	q->re_len = re_len;
408
409	F_SET(dbp, DB_AM_FIXEDLEN);
410
411	return (0);
412}
413
414/*
415 * __db_get_re_pad --
416 *	Get the fixed-length record pad character.
417 *
418 * PUBLIC: int __ram_get_re_pad __P((DB *, int *));
419 */
420int
421__ram_get_re_pad(dbp, re_padp)
422	DB *dbp;
423	int *re_padp;
424{
425	BTREE *t;
426	QUEUE *q;
427
428	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
429
430	/*
431	 * This has to work for all access methods, before or after opening the
432	 * database.  When the record length is set with __ram_set_re_pad, the
433	 * value in both the BTREE and QUEUE structs will be correct.
434	 * Otherwise, this only makes sense after the database in opened, in
435	 * which case we know the type.
436	 */
437	if (dbp->type == DB_QUEUE) {
438		q = dbp->q_internal;
439		*re_padp = q->re_pad;
440	} else {
441		t = dbp->bt_internal;
442		*re_padp = t->re_pad;
443	}
444
445	return (0);
446}
447
448/*
449 * __ram_set_re_pad --
450 *	Set the fixed-length record pad character.
451 */
452static int
453__ram_set_re_pad(dbp, re_pad)
454	DB *dbp;
455	int re_pad;
456{
457	BTREE *t;
458	QUEUE *q;
459
460	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_pad");
461	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
462
463	t = dbp->bt_internal;
464	t->re_pad = re_pad;
465
466	q = dbp->q_internal;
467	q->re_pad = re_pad;
468
469	F_SET(dbp, DB_AM_PAD);
470
471	return (0);
472}
473
474/*
475 * __db_get_re_source --
476 *	Get the backing source file name.
477 */
478static int
479__ram_get_re_source(dbp, re_sourcep)
480	DB *dbp;
481	const char **re_sourcep;
482{
483	BTREE *t;
484
485	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
486
487	t = dbp->bt_internal;
488	*re_sourcep = t->re_source;
489	return (0);
490}
491
492/*
493 * __ram_set_re_source --
494 *	Set the backing source file name.
495 */
496static int
497__ram_set_re_source(dbp, re_source)
498	DB *dbp;
499	const char *re_source;
500{
501	BTREE *t;
502
503	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_source");
504	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
505
506	t = dbp->bt_internal;
507
508	return (__os_strdup(dbp->env, re_source, &t->re_source));
509}
510