2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static char copyright
[] =
36 "@(#) Copyright (c) 1992, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
41 static char sccsid
[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
44 #include <sys/param.h>
58 enum S
{ COMMAND
, COMPARE
, GET
, PUT
, REMOVE
, SEQ
, SEQFLAG
, KEY
, DATA
};
60 void compare
__P((DBT
*, DBT
*));
61 DBTYPE dbtype
__P((char *));
62 void dump
__P((DB
*, int));
63 void err
__P((const char *, ...));
64 void get
__P((DB
*, DBT
*));
65 void getdata
__P((DB
*, DBT
*, DBT
*));
66 void put
__P((DB
*, DBT
*, DBT
*));
67 void rem
__P((DB
*, DBT
*));
68 char *sflags
__P((int));
69 void synk
__P((DB
*));
70 void *rfile
__P((char *, size_t *));
71 void seq
__P((DB
*, DBT
*));
72 u_int setflags
__P((char *));
73 void *setinfo
__P((DBTYPE
, char *));
74 void usage
__P((void));
75 void *xmalloc
__P((char *, size_t));
77 DBTYPE type
; /* Database type. */
78 void *infop
; /* Iflags. */
79 u_long lineno
; /* Current line in test script. */
80 u_int flags
; /* Current DB flags. */
81 int ofd
= STDOUT_FILENO
; /* Standard output fd. */
83 DB
*XXdbp
; /* Global for gdb. */
84 int XXlineno
; /* Fast breakpoint for gdb. */
93 enum S command
, state
;
95 DBT data
, key
, keydata
;
97 int ch
, oflags
, sflag
;
98 char *fname
, *infoarg
, *p
, *t
, buf
[8 * 1024];
102 oflags
= O_CREAT
| O_RDWR
;
104 while ((ch
= getopt(argc
, argv
, "f:i:lo:s")) != EOF
)
116 if ((ofd
= open(optarg
,
117 O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
118 err("%s: %s", optarg
, strerror(errno
));
134 type
= dbtype(*argv
++);
136 /* Open the descriptor file. */
137 if (strcmp(*argv
, "-") && freopen(*argv
, "r", stdin
) == NULL
)
138 err("%s: %s", *argv
, strerror(errno
));
140 /* Set up the db structure as necessary. */
144 for (p
= strtok(infoarg
, ",\t "); p
!= NULL
;
145 p
= strtok(0, ",\t "))
147 infop
= setinfo(type
, p
);
150 * Open the DB. Delete any preexisting copy, you almost never
151 * want it around, and it often screws up tests.
154 p
= getenv("TMPDIR");
157 (void)sprintf(buf
, "%s/__dbtest", p
);
163 if ((dbp
= dbopen(fname
,
164 oflags
, S_IRUSR
| S_IWUSR
, type
, infop
)) == NULL
)
165 err("dbopen: %s", strerror(errno
));
170 (p
= fgets(buf
, sizeof(buf
), stdin
)) != NULL
; ++lineno
) {
171 /* Delete the newline, displaying the key/data is easier. */
172 if (ofd
== STDOUT_FILENO
&& (t
= strchr(p
, '\n')) != NULL
)
174 if ((len
= strlen(buf
)) == 0 || isspace(*p
) || *p
== '#')
177 /* Convenient gdb break point. */
178 if (XXlineno
== lineno
)
181 case 'c': /* compare */
182 if (state
!= COMMAND
)
183 err("line %lu: not expecting command", lineno
);
188 if (state
!= COMMAND
)
189 err("line %lu: not expecting command", lineno
);
190 /* Don't display the newline, if CR at EOL. */
191 if (p
[len
- 2] == '\r')
193 if (write(ofd
, p
+ 1, len
- 1) != len
- 1 ||
194 write(ofd
, "\n", 1) != 1)
195 err("write: %s", strerror(errno
));
198 if (state
!= COMMAND
)
199 err("line %lu: not expecting command", lineno
);
204 if (state
!= COMMAND
)
205 err("line %lu: not expecting command", lineno
);
209 case 'r': /* remove */
210 if (state
!= COMMAND
)
211 err("line %lu: not expecting command", lineno
);
212 if (flags
== R_CURSOR
) {
221 if (state
!= COMMAND
)
222 err("line %lu: not expecting command", lineno
);
227 if (state
!= COMMAND
)
228 err("line %lu: not expecting command", lineno
);
229 if (flags
== R_CURSOR
) {
236 flags
= setflags(p
+ 1);
238 case 'D': /* data file */
240 err("line %lu: not expecting data", lineno
);
241 data
.data
= rfile(p
+ 1, &data
.size
);
245 err("line %lu: not expecting data", lineno
);
246 data
.data
= xmalloc(p
+ 1, len
- 1);
248 ldata
: switch (command
) {
250 compare(&keydata
, &data
);
253 put(dbp
, &key
, &data
);
256 err("line %lu: command doesn't take data",
259 if (type
!= DB_RECNO
)
264 case 'K': /* key file */
266 err("line %lu: not expecting a key", lineno
);
267 if (type
== DB_RECNO
)
268 err("line %lu: 'K' not available for recno",
270 key
.data
= rfile(p
+ 1, &key
.size
);
274 err("line %lu: not expecting a key", lineno
);
275 if (type
== DB_RECNO
) {
276 static recno_t recno
;
279 key
.size
= sizeof(recno
);
281 key
.data
= xmalloc(p
+ 1, len
- 1);
284 lkey
: switch (command
) {
286 getdata(dbp
, &key
, &keydata
);
291 if (type
!= DB_RECNO
)
300 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
306 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
311 err("line %lu: command doesn't take a key",
316 dump(dbp
, p
[1] == 'r');
319 err("line %lu: %s: unknown command character",
325 * -l must be used (DB_LOCK must be set) for this to be
326 * used, otherwise a page will be locked and it will fail.
328 if (type
== DB_BTREE
&& oflags
& DB_LOCK
)
332 err("db->close: %s", strerror(errno
));
337 #define NOOVERWRITE "put failed, would overwrite key\n"
344 register u_char
*p1
, *p2
;
346 if (db1
->size
!= db2
->size
)
347 printf("compare failed: key->data len %lu != data len %lu\n",
348 db1
->size
, db2
->size
);
350 len
= MIN(db1
->size
, db2
->size
);
351 for (p1
= db1
->data
, p2
= db2
->data
; len
--;)
352 if (*p1
++ != *p2
++) {
353 printf("compare failed at offset %d\n",
354 p1
- (u_char
*)db1
->data
);
366 switch (dbp
->get(dbp
, kp
, &data
, flags
)) {
368 (void)write(ofd
, data
.data
, data
.size
);
369 if (ofd
== STDOUT_FILENO
)
370 (void)write(ofd
, "\n", 1);
373 err("line %lu: get: %s", lineno
, strerror(errno
));
376 #define NOSUCHKEY "get failed, no such key\n"
377 if (ofd
!= STDOUT_FILENO
)
378 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
380 (void)fprintf(stderr
, "%d: %.*s: %s",
381 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
392 switch (dbp
->get(dbp
, kp
, dp
, flags
)) {
396 err("line %lu: getdata: %s", lineno
, strerror(errno
));
399 err("line %lu: getdata failed, no such key", lineno
);
409 switch (dbp
->put(dbp
, kp
, dp
, flags
)) {
413 err("line %lu: put: %s", lineno
, strerror(errno
));
416 (void)write(ofd
, NOOVERWRITE
, sizeof(NOOVERWRITE
) - 1);
426 switch (dbp
->del(dbp
, kp
, flags
)) {
430 err("line %lu: rem: %s", lineno
, strerror(errno
));
433 #define NOSUCHKEY "rem failed, no such key\n"
434 if (ofd
!= STDOUT_FILENO
)
435 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
436 else if (flags
!= R_CURSOR
)
437 (void)fprintf(stderr
, "%d: %.*s: %s",
438 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
440 (void)fprintf(stderr
,
441 "%d: rem of cursor failed\n", lineno
);
451 switch (dbp
->sync(dbp
, flags
)) {
455 err("line %lu: synk: %s", lineno
, strerror(errno
));
467 switch (dbp
->seq(dbp
, kp
, &data
, flags
)) {
469 (void)write(ofd
, data
.data
, data
.size
);
470 if (ofd
== STDOUT_FILENO
)
471 (void)write(ofd
, "\n", 1);
474 err("line %lu: seq: %s", lineno
, strerror(errno
));
477 #define NOSUCHKEY "seq failed, no such key\n"
478 if (ofd
!= STDOUT_FILENO
)
479 (void)write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
480 else if (flags
== R_CURSOR
)
481 (void)fprintf(stderr
, "%d: %.*s: %s",
482 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
484 (void)fprintf(stderr
,
485 "%d: seq (%s) failed\n", lineno
, sflags(flags
));
506 for (;; flags
= nflags
)
507 switch (dbp
->seq(dbp
, &key
, &data
, flags
)) {
509 (void)write(ofd
, data
.data
, data
.size
);
510 if (ofd
== STDOUT_FILENO
)
511 (void)write(ofd
, "\n", 1);
516 err("line %lu: (dump) seq: %s",
517 lineno
, strerror(errno
));
529 for (; isspace(*s
); ++s
);
530 if (*s
== '\n' || *s
== '\0')
532 if ((p
= index(s
, '\n')) != NULL
)
534 if (!strcmp(s
, "R_CURSOR")) return (R_CURSOR
);
535 if (!strcmp(s
, "R_FIRST")) return (R_FIRST
);
536 if (!strcmp(s
, "R_IAFTER")) return (R_IAFTER
);
537 if (!strcmp(s
, "R_IBEFORE")) return (R_IBEFORE
);
538 if (!strcmp(s
, "R_LAST")) return (R_LAST
);
539 if (!strcmp(s
, "R_NEXT")) return (R_NEXT
);
540 if (!strcmp(s
, "R_NOOVERWRITE")) return (R_NOOVERWRITE
);
541 if (!strcmp(s
, "R_PREV")) return (R_PREV
);
542 if (!strcmp(s
, "R_SETCURSOR")) return (R_SETCURSOR
);
544 err("line %lu: %s: unknown flag", lineno
, s
);
553 case R_CURSOR
: return ("R_CURSOR");
554 case R_FIRST
: return ("R_FIRST");
555 case R_IAFTER
: return ("R_IAFTER");
556 case R_IBEFORE
: return ("R_IBEFORE");
557 case R_LAST
: return ("R_LAST");
558 case R_NEXT
: return ("R_NEXT");
559 case R_NOOVERWRITE
: return ("R_NOOVERWRITE");
560 case R_PREV
: return ("R_PREV");
561 case R_SETCURSOR
: return ("R_SETCURSOR");
571 if (!strcmp(s
, "btree"))
573 if (!strcmp(s
, "hash"))
575 if (!strcmp(s
, "recno"))
577 err("%s: unknown type (use btree, hash or recno)", s
);
591 if ((eq
= index(s
, '=')) == NULL
)
592 err("%s: illegal structure set statement", s
);
595 err("%s: structure set statement must be a number", s
);
599 if (!strcmp("flags", s
)) {
603 if (!strcmp("cachesize", s
)) {
604 ib
.cachesize
= atoi(eq
);
607 if (!strcmp("maxkeypage", s
)) {
608 ib
.maxkeypage
= atoi(eq
);
611 if (!strcmp("minkeypage", s
)) {
612 ib
.minkeypage
= atoi(eq
);
615 if (!strcmp("lorder", s
)) {
616 ib
.lorder
= atoi(eq
);
619 if (!strcmp("psize", s
)) {
625 if (!strcmp("bsize", s
)) {
629 if (!strcmp("ffactor", s
)) {
630 ih
.ffactor
= atoi(eq
);
633 if (!strcmp("nelem", s
)) {
637 if (!strcmp("cachesize", s
)) {
638 ih
.cachesize
= atoi(eq
);
641 if (!strcmp("lorder", s
)) {
642 ih
.lorder
= atoi(eq
);
647 if (!strcmp("flags", s
)) {
651 if (!strcmp("cachesize", s
)) {
652 rh
.cachesize
= atoi(eq
);
655 if (!strcmp("lorder", s
)) {
656 rh
.lorder
= atoi(eq
);
659 if (!strcmp("reclen", s
)) {
660 rh
.reclen
= atoi(eq
);
663 if (!strcmp("bval", s
)) {
667 if (!strcmp("psize", s
)) {
673 err("%s: unknown structure value", s
);
687 for (; isspace(*name
); ++name
);
688 if ((np
= index(name
, '\n')) != NULL
)
690 if ((fd
= open(name
, O_RDONLY
, 0)) < 0 ||
692 err("%s: %s\n", name
, strerror(errno
));
694 if (sb
.st_size
> (off_t
)SIZE_T_MAX
)
695 err("%s: %s\n", name
, strerror(E2BIG
));
697 if ((p
= (void *)malloc((u_int
)sb
.st_size
)) == NULL
)
698 err("%s", strerror(errno
));
699 (void)read(fd
, p
, (int)sb
.st_size
);
712 if ((p
= (void *)malloc(len
)) == NULL
)
713 err("%s", strerror(errno
));
714 memmove(p
, text
, len
);
721 (void)fprintf(stderr
,
722 "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
734 err(const char *fmt
, ...)
747 (void)fprintf(stderr
, "dbtest: ");
748 (void)vfprintf(stderr
, fmt
, ap
);
750 (void)fprintf(stderr
, "\n");