1 /* $NetBSD: dbtest.c,v 1.17 2009/01/25 13:40:05 lukem Exp $ */
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
42 __RCSID("$NetBSD: dbtest.c,v 1.17 2009/01/25 13:40:05 lukem Exp $");
46 #include <sys/param.h>
61 enum S
{ COMMAND
, COMPARE
, GET
, PUT
, REMOVE
, SEQ
, SEQFLAG
, KEY
, DATA
};
63 static void compare(DBT
*, DBT
*);
64 static DBTYPE
dbtype(const char *);
65 static void dump(DB
*, int);
66 static void get(DB
*, DBT
*);
67 static void getdata(DB
*, DBT
*, DBT
*);
68 static void put(DB
*, DBT
*, DBT
*);
69 static void rem(DB
*, DBT
*);
70 static const char *sflags(int);
71 static void synk(DB
*);
72 static void *rfile(char *, size_t *);
73 static void seq(DB
*, DBT
*);
74 static u_int
setflags(char *);
75 static void *setinfo(DBTYPE
, char *);
76 static void usage(void) __attribute__((__noreturn__
));
77 static void *xcopy(void *, size_t);
78 static void chkcmd(enum S
);
79 static void chkdata(enum S
);
80 static void chkkey(enum S
);
83 extern void __bt_stat(DB
*);
86 static DBTYPE type
; /* Database type. */
87 static void *infop
; /* Iflags. */
88 static size_t lineno
; /* Current line in test script. */
89 static u_int flags
; /* Current DB flags. */
90 static int ofd
= STDOUT_FILENO
; /* Standard output fd. */
92 static DB
*XXdbp
; /* Global for gdb. */
93 static size_t XXlineno
; /* Fast breakpoint for gdb. */
96 main(int argc
, char *argv
[])
100 enum S command
= COMMAND
, state
;
102 DBT data
, key
, keydata
;
104 int ch
, oflags
, sflag
;
105 char *fname
, *infoarg
, *p
, *t
, buf
[8 * 1024];
110 unlink_dbfile
= false;
111 oflags
= O_CREAT
| O_RDWR
;
113 while ((ch
= getopt(argc
, argv
, "f:i:lo:s")) != -1)
125 if ((ofd
= open(optarg
,
126 O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
127 err(1, "Cannot create `%s'", optarg
);
143 type
= dbtype(*argv
++);
145 /* Open the descriptor file. */
146 if (strcmp(*argv
, "-") && freopen(*argv
, "r", stdin
) == NULL
)
147 err(1, "Cannot reopen `%s'", *argv
);
149 /* Set up the db structure as necessary. */
153 for (p
= strtok(infoarg
, ",\t "); p
!= NULL
;
154 p
= strtok(0, ",\t "))
156 infop
= setinfo(type
, p
);
159 * Open the DB. Delete any preexisting copy, you almost never
160 * want it around, and it often screws up tests.
163 const char *q
= getenv("TMPDIR");
166 (void)snprintf(buf
, sizeof(buf
), "%s/__dbtest", q
);
169 unlink_dbfile
= true;
173 if ((dbp
= dbopen(fname
,
174 oflags
, S_IRUSR
| S_IWUSR
, type
, infop
)) == NULL
)
175 err(1, "Cannot dbopen `%s'", fname
);
182 (p
= fgets(buf
, sizeof(buf
), stdin
)) != NULL
; ++lineno
) {
183 /* Delete the newline, displaying the key/data is easier. */
184 if (ofd
== STDOUT_FILENO
&& (t
= strchr(p
, '\n')) != NULL
)
186 if ((len
= strlen(buf
)) == 0 || isspace((unsigned char)*p
) ||
190 /* Convenient gdb break point. */
191 if (XXlineno
== lineno
)
194 case 'c': /* compare */
201 /* Don't display the newline, if CR at EOL. */
202 if (p
[len
- 2] == '\r')
204 if ((size_t)write(ofd
, p
+ 1, len
- 1) != (len
- 1) ||
205 write(ofd
, "\n", 1) != 1)
206 err(1, "write failed");
218 case 'r': /* remove */
220 if (flags
== R_CURSOR
) {
235 if (flags
== R_CURSOR
) {
242 flags
= setflags(p
+ 1);
244 case 'D': /* data file */
246 data
.data
= rfile(p
+ 1, &data
.size
);
250 data
.data
= xcopy(p
+ 1, len
- 1);
252 ldata
: switch (command
) {
254 compare(&keydata
, &data
);
257 put(dbp
, &key
, &data
);
260 errx(1, "line %zu: command doesn't take data",
263 if (type
!= DB_RECNO
)
268 case 'K': /* key file */
270 if (type
== DB_RECNO
)
271 errx(1, "line %zu: 'K' not available for recno",
273 key
.data
= rfile(p
+ 1, &key
.size
);
277 if (type
== DB_RECNO
) {
278 static recno_t recno
;
281 key
.size
= sizeof(recno
);
283 key
.data
= xcopy(p
+ 1, len
- 1);
286 lkey
: switch (command
) {
288 getdata(dbp
, &key
, &keydata
);
293 if (type
!= DB_RECNO
)
302 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
308 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
313 errx(1, "line %zu: command doesn't take a key",
318 dump(dbp
, p
[1] == 'r');
321 errx(1, "line %zu: %s: unknown command character",
327 * -l must be used (DB_LOCK must be set) for this to be
328 * used, otherwise a page will be locked and it will fail.
330 if (type
== DB_BTREE
&& oflags
& DB_LOCK
)
333 if ((*dbp
->close
)(dbp
))
334 err(1, "db->close failed");
339 #define NOOVERWRITE "put failed, would overwrite key\n"
342 compare(DBT
*db1
, DBT
*db2
)
347 if (db1
->size
!= db2
->size
)
348 printf("compare failed: key->data len %zu != data len %zu\n",
349 db1
->size
, db2
->size
);
351 len
= MIN(db1
->size
, db2
->size
);
352 for (p1
= db1
->data
, p2
= db2
->data
; len
--;)
353 if (*p1
++ != *p2
++) {
354 printf("compare failed at offset %lu\n",
355 (unsigned long)(p1
- (u_char
*)db1
->data
));
361 get(DB
*dbp
, DBT
*kp
)
365 switch ((*dbp
->get
)(dbp
, kp
, &data
, flags
)) {
367 (void)write(ofd
, data
.data
, data
.size
);
368 if (ofd
== STDOUT_FILENO
)
369 (void)write(ofd
, "\n", 1);
372 err(1, "line %zu: get failed", lineno
);
375 #define NOSUCHKEY "get failed, no such key\n"
376 if (ofd
!= STDOUT_FILENO
)
377 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
379 (void)fprintf(stderr
, "%zu: %.*s: %s",
380 lineno
, (int)MIN(kp
->size
, 20),
381 (const char *)kp
->data
,
389 getdata(DB
*dbp
, DBT
*kp
, DBT
*dp
)
391 switch ((*dbp
->get
)(dbp
, kp
, dp
, flags
)) {
395 err(1, "line %zu: getdata failed", lineno
);
398 errx(1, "line %zu: getdata failed, no such key", lineno
);
404 put(DB
*dbp
, DBT
*kp
, DBT
*dp
)
406 switch ((*dbp
->put
)(dbp
, kp
, dp
, flags
)) {
410 err(1, "line %zu: put failed", lineno
);
413 (void)write(ofd
, NOOVERWRITE
, sizeof(NOOVERWRITE
) - 1);
419 rem(DB
*dbp
, DBT
*kp
)
421 switch ((*dbp
->del
)(dbp
, kp
, flags
)) {
425 err(1, "line %zu: rem failed", lineno
);
428 #define NOSUCHKEY "rem failed, no such key\n"
429 if (ofd
!= STDOUT_FILENO
)
430 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
431 else if (flags
!= R_CURSOR
)
432 (void)fprintf(stderr
, "%zu: %.*s: %s",
433 lineno
, (int)MIN(kp
->size
, 20),
434 (const char *)kp
->data
, NOSUCHKEY
);
436 (void)fprintf(stderr
,
437 "%zu: rem of cursor failed\n", lineno
);
446 switch ((*dbp
->sync
)(dbp
, flags
)) {
450 err(1, "line %zu: synk failed", lineno
);
456 seq(DB
*dbp
, DBT
*kp
)
460 switch (dbp
->seq(dbp
, kp
, &data
, flags
)) {
462 (void)write(ofd
, data
.data
, data
.size
);
463 if (ofd
== STDOUT_FILENO
)
464 (void)write(ofd
, "\n", 1);
467 err(1, "line %zu: seq failed", lineno
);
470 #define NOSUCHKEY "seq failed, no such key\n"
471 if (ofd
!= STDOUT_FILENO
)
472 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
473 else if (flags
== R_CURSOR
)
474 (void)fprintf(stderr
, "%zu: %.*s: %s",
475 lineno
, (int)MIN(kp
->size
, 20),
476 (const char *)kp
->data
, NOSUCHKEY
);
478 (void)fprintf(stderr
,
479 "%zu: seq (%s) failed\n", lineno
, sflags(flags
));
486 dump(DB
*dbp
, int rev
)
498 for (;; xflags
= nflags
)
499 switch (dbp
->seq(dbp
, &key
, &data
, xflags
)) {
501 (void)write(ofd
, data
.data
, data
.size
);
502 if (ofd
== STDOUT_FILENO
)
503 (void)write(ofd
, "\n", 1);
508 err(1, "line %zu: (dump) seq failed", lineno
);
519 for (; isspace((unsigned char)*s
); ++s
);
520 if (*s
== '\n' || *s
== '\0')
522 if ((p
= strchr(s
, '\n')) != NULL
)
524 if (!strcmp(s
, "R_CURSOR")) return R_CURSOR
;
525 if (!strcmp(s
, "R_FIRST")) return R_FIRST
;
526 if (!strcmp(s
, "R_IAFTER")) return R_IAFTER
;
527 if (!strcmp(s
, "R_IBEFORE")) return R_IBEFORE
;
528 if (!strcmp(s
, "R_LAST")) return R_LAST
;
529 if (!strcmp(s
, "R_NEXT")) return R_NEXT
;
530 if (!strcmp(s
, "R_NOOVERWRITE")) return R_NOOVERWRITE
;
531 if (!strcmp(s
, "R_PREV")) return R_PREV
;
532 if (!strcmp(s
, "R_SETCURSOR")) return R_SETCURSOR
;
534 errx(1, "line %zu: %s: unknown flag", lineno
, s
);
542 case R_CURSOR
: return "R_CURSOR";
543 case R_FIRST
: return "R_FIRST";
544 case R_IAFTER
: return "R_IAFTER";
545 case R_IBEFORE
: return "R_IBEFORE";
546 case R_LAST
: return "R_LAST";
547 case R_NEXT
: return "R_NEXT";
548 case R_NOOVERWRITE
: return "R_NOOVERWRITE";
549 case R_PREV
: return "R_PREV";
550 case R_SETCURSOR
: return "R_SETCURSOR";
557 dbtype(const char *s
)
559 if (!strcmp(s
, "btree"))
561 if (!strcmp(s
, "hash"))
563 if (!strcmp(s
, "recno"))
565 errx(1, "%s: unknown type (use btree, hash or recno)", s
);
570 setinfo(DBTYPE dtype
, char *s
)
577 if ((eq
= strchr(s
, '=')) == NULL
)
578 errx(1, "%s: illegal structure set statement", s
);
580 if (!isdigit((unsigned char)*eq
))
581 errx(1, "%s: structure set statement must be a number", s
);
585 if (!strcmp("flags", s
)) {
589 if (!strcmp("cachesize", s
)) {
590 ib
.cachesize
= atoi(eq
);
593 if (!strcmp("maxkeypage", s
)) {
594 ib
.maxkeypage
= atoi(eq
);
597 if (!strcmp("minkeypage", s
)) {
598 ib
.minkeypage
= atoi(eq
);
601 if (!strcmp("lorder", s
)) {
602 ib
.lorder
= atoi(eq
);
605 if (!strcmp("psize", s
)) {
611 if (!strcmp("bsize", s
)) {
615 if (!strcmp("ffactor", s
)) {
616 ih
.ffactor
= atoi(eq
);
619 if (!strcmp("nelem", s
)) {
623 if (!strcmp("cachesize", s
)) {
624 ih
.cachesize
= atoi(eq
);
627 if (!strcmp("lorder", s
)) {
628 ih
.lorder
= atoi(eq
);
633 if (!strcmp("flags", s
)) {
637 if (!strcmp("cachesize", s
)) {
638 rh
.cachesize
= atoi(eq
);
641 if (!strcmp("lorder", s
)) {
642 rh
.lorder
= atoi(eq
);
645 if (!strcmp("reclen", s
)) {
646 rh
.reclen
= atoi(eq
);
649 if (!strcmp("bval", s
)) {
653 if (!strcmp("psize", s
)) {
659 errx(1, "%s: unknown structure value", s
);
664 rfile(char *name
, size_t *lenp
)
671 for (; isspace((unsigned char)*name
); ++name
)
673 if ((np
= strchr(name
, '\n')) != NULL
)
675 if ((fd
= open(name
, O_RDONLY
, 0)) == -1 || fstat(fd
, &sb
) == -1)
676 err(1, "Cannot open `%s'", name
);
678 if (sb
.st_size
> (off_t
)SIZE_T_MAX
) {
680 err("Cannot process `%s'", name
);
683 if ((p
= malloc((size_t)sb
.st_size
)) == NULL
)
684 err(1, "Cannot allocate %zu bytes", (size_t)sb
.st_size
);
685 if (read(fd
, p
, (ssize_t
)sb
.st_size
) != (ssize_t
)sb
.st_size
)
686 err(1, "read failed");
687 *lenp
= (size_t)sb
.st_size
;
693 xcopy(void *text
, size_t len
)
697 if ((p
= malloc(len
)) == NULL
)
698 err(1, "Cannot allocate %zu bytes", len
);
699 (void)memmove(p
, text
, len
);
706 if (state
!= COMMAND
)
707 errx(1, "line %zu: not expecting command", lineno
);
711 chkdata(enum S state
)
714 errx(1, "line %zu: not expecting data", lineno
);
721 errx(1, "line %zu: not expecting a key", lineno
);
727 (void)fprintf(stderr
,
728 "Usage: %s [-l] [-f file] [-i info] [-o file] type script\n",