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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#) Copyright (c) 1992, 1993, 1994 The Regents of the University of California. All rights reserved.
30 * @(#)dbtest.c 8.17 (Berkeley) 9/1/94
31 * $FreeBSD: src/lib/libc/db/test/dbtest.c,v 1.3.8.1 2000/08/21 22:44:47 jhb Exp $
32 * $DragonFly: src/lib/libc/db/test/dbtest.c,v 1.8 2008/07/10 18:29:51 swildner Exp $
35 #include <sys/param.h>
49 enum S
{ COMMAND
, COMPARE
, GET
, PUT
, REMOVE
, SEQ
, SEQFLAG
, KEY
, DATA
};
51 void compare (DBT
*, DBT
*);
52 DBTYPE
dbtype (char *);
53 void dump (DB
*, int);
54 void err (const char *, ...);
55 void get (DB
*, DBT
*);
56 void getdata (DB
*, DBT
*, DBT
*);
57 void put (DB
*, DBT
*, DBT
*);
58 void rem (DB
*, DBT
*);
61 void *rfile (char *, size_t *);
62 void seq (DB
*, DBT
*);
63 u_int
setflags (char *);
64 void *setinfo (DBTYPE
, char *);
66 void *xmalloc (char *, size_t);
68 DBTYPE type
; /* Database type. */
69 void *infop
; /* Iflags. */
70 u_long lineno
; /* Current line in test script. */
71 u_int flags
; /* Current DB flags. */
72 int ofd
= STDOUT_FILENO
; /* Standard output fd. */
74 DB
*XXdbp
; /* Global for gdb. */
75 int XXlineno
; /* Fast breakpoint for gdb. */
78 main(int argc
, char *argv
[])
82 enum S command
, state
;
84 DBT data
, key
, keydata
;
86 int ch
, oflags
, sflag
;
87 char *fname
, *infoarg
, *p
, *t
, buf
[8 * 1024];
91 oflags
= O_CREAT
| O_RDWR
;
93 while ((ch
= getopt(argc
, argv
, "f:i:lo:s")) != -1)
105 if ((ofd
= open(optarg
,
106 O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
107 err("%s: %s", optarg
, strerror(errno
));
123 type
= dbtype(*argv
++);
125 /* Open the descriptor file. */
126 if (strcmp(*argv
, "-") && freopen(*argv
, "r", stdin
) == NULL
)
127 err("%s: %s", *argv
, strerror(errno
));
129 /* Set up the db structure as necessary. */
133 for (p
= strtok(infoarg
, ",\t "); p
!= NULL
;
134 p
= strtok(0, ",\t "))
136 infop
= setinfo(type
, p
);
139 * Open the DB. Delete any preexisting copy, you almost never
140 * want it around, and it often screws up tests.
143 p
= getenv("TMPDIR");
146 snprintf(buf
, sizeof(buf
), "%s/__dbtest", p
);
152 if ((dbp
= dbopen(fname
,
153 oflags
, S_IRUSR
| S_IWUSR
, type
, infop
)) == NULL
)
154 err("dbopen: %s", strerror(errno
));
159 (p
= fgets(buf
, sizeof(buf
), stdin
)) != NULL
; ++lineno
) {
160 /* Delete the newline, displaying the key/data is easier. */
161 if (ofd
== STDOUT_FILENO
&& (t
= strchr(p
, '\n')) != NULL
)
163 if ((len
= strlen(buf
)) == 0 || isspace(*p
) || *p
== '#')
166 /* Convenient gdb break point. */
167 if (XXlineno
== lineno
)
170 case 'c': /* compare */
171 if (state
!= COMMAND
)
172 err("line %lu: not expecting command", lineno
);
177 if (state
!= COMMAND
)
178 err("line %lu: not expecting command", lineno
);
179 /* Don't display the newline, if CR at EOL. */
180 if (p
[len
- 2] == '\r')
182 if (write(ofd
, p
+ 1, len
- 1) != len
- 1 ||
183 write(ofd
, "\n", 1) != 1)
184 err("write: %s", strerror(errno
));
187 if (state
!= COMMAND
)
188 err("line %lu: not expecting command", lineno
);
193 if (state
!= COMMAND
)
194 err("line %lu: not expecting command", lineno
);
198 case 'r': /* remove */
199 if (state
!= COMMAND
)
200 err("line %lu: not expecting command", lineno
);
201 if (flags
== R_CURSOR
) {
210 if (state
!= COMMAND
)
211 err("line %lu: not expecting command", lineno
);
216 if (state
!= COMMAND
)
217 err("line %lu: not expecting command", lineno
);
218 if (flags
== R_CURSOR
) {
225 flags
= setflags(p
+ 1);
227 case 'D': /* data file */
229 err("line %lu: not expecting data", lineno
);
230 data
.data
= rfile(p
+ 1, &data
.size
);
234 err("line %lu: not expecting data", lineno
);
235 data
.data
= xmalloc(p
+ 1, len
- 1);
237 ldata
: switch (command
) {
239 compare(&keydata
, &data
);
242 put(dbp
, &key
, &data
);
245 err("line %lu: command doesn't take data",
248 if (type
!= DB_RECNO
)
253 case 'K': /* key file */
255 err("line %lu: not expecting a key", lineno
);
256 if (type
== DB_RECNO
)
257 err("line %lu: 'K' not available for recno",
259 key
.data
= rfile(p
+ 1, &key
.size
);
263 err("line %lu: not expecting a key", lineno
);
264 if (type
== DB_RECNO
) {
265 static recno_t recno
;
268 key
.size
= sizeof(recno
);
270 key
.data
= xmalloc(p
+ 1, len
- 1);
273 lkey
: switch (command
) {
275 getdata(dbp
, &key
, &keydata
);
280 if (type
!= DB_RECNO
)
289 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
295 if ((type
!= DB_RECNO
) && (flags
!= R_CURSOR
))
300 err("line %lu: command doesn't take a key",
305 dump(dbp
, p
[1] == 'r');
308 err("line %lu: %s: unknown command character",
314 * -l must be used (DB_LOCK must be set) for this to be
315 * used, otherwise a page will be locked and it will fail.
317 if (type
== DB_BTREE
&& oflags
& DB_LOCK
)
321 err("db->close: %s", strerror(errno
));
326 #define NOOVERWRITE "put failed, would overwrite key\n"
329 compare(DBT
*db1
, DBT
*db2
)
334 if (db1
->size
!= db2
->size
)
335 printf("compare failed: key->data len %lu != data len %lu\n",
336 db1
->size
, db2
->size
);
338 len
= MIN(db1
->size
, db2
->size
);
339 for (p1
= db1
->data
, p2
= db2
->data
; len
--;)
340 if (*p1
++ != *p2
++) {
341 printf("compare failed at offset %d\n",
342 p1
- (u_char
*)db1
->data
);
348 get(DB
*dbp
, DBT
*kp
)
352 switch (dbp
->get(dbp
, kp
, &data
, flags
)) {
354 write(ofd
, data
.data
, data
.size
);
355 if (ofd
== STDOUT_FILENO
)
359 err("line %lu: get: %s", lineno
, strerror(errno
));
362 #define NOSUCHKEY "get failed, no such key\n"
363 if (ofd
!= STDOUT_FILENO
)
364 write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
366 fprintf(stderr
, "%d: %.*s: %s",
367 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
374 getdata(DB
*dbp
, DBT
*kp
, DBT
*dp
)
376 switch (dbp
->get(dbp
, kp
, dp
, flags
)) {
380 err("line %lu: getdata: %s", lineno
, strerror(errno
));
383 err("line %lu: getdata failed, no such key", lineno
);
389 put(DB
*dbp
, DBT
*kp
, DBT
*dp
)
391 switch (dbp
->put(dbp
, kp
, dp
, flags
)) {
395 err("line %lu: put: %s", lineno
, strerror(errno
));
398 write(ofd
, NOOVERWRITE
, sizeof(NOOVERWRITE
) - 1);
404 rem(DB
*dbp
, DBT
*kp
)
406 switch (dbp
->del(dbp
, kp
, flags
)) {
410 err("line %lu: rem: %s", lineno
, strerror(errno
));
413 #define NOSUCHKEY "rem failed, no such key\n"
414 if (ofd
!= STDOUT_FILENO
)
415 write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
416 else if (flags
!= R_CURSOR
)
417 fprintf(stderr
, "%d: %.*s: %s",
418 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
421 "%d: rem of cursor failed\n", lineno
);
430 switch (dbp
->sync(dbp
, flags
)) {
434 err("line %lu: synk: %s", lineno
, strerror(errno
));
440 seq(DB
*dbp
, DBT
*kp
)
444 switch (dbp
->seq(dbp
, kp
, &data
, flags
)) {
446 write(ofd
, data
.data
, data
.size
);
447 if (ofd
== STDOUT_FILENO
)
451 err("line %lu: seq: %s", lineno
, strerror(errno
));
454 #define NOSUCHKEY "seq failed, no such key\n"
455 if (ofd
!= STDOUT_FILENO
)
456 write(ofd
, NOSUCHKEY
, sizeof(NOSUCHKEY
) - 1);
457 else if (flags
== R_CURSOR
)
458 fprintf(stderr
, "%d: %.*s: %s",
459 lineno
, MIN(kp
->size
, 20), kp
->data
, NOSUCHKEY
);
462 "%d: seq (%s) failed\n", lineno
, sflags(flags
));
469 dump(DB
*dbp
, int rev
)
481 for (;; flags
= nflags
)
482 switch (dbp
->seq(dbp
, &key
, &data
, flags
)) {
484 write(ofd
, data
.data
, data
.size
);
485 if (ofd
== STDOUT_FILENO
)
491 err("line %lu: (dump) seq: %s",
492 lineno
, strerror(errno
));
503 for (; isspace(*s
); ++s
);
504 if (*s
== '\n' || *s
== '\0')
506 if ((p
= index(s
, '\n')) != NULL
)
508 if (!strcmp(s
, "R_CURSOR")) return (R_CURSOR
);
509 if (!strcmp(s
, "R_FIRST")) return (R_FIRST
);
510 if (!strcmp(s
, "R_IAFTER")) return (R_IAFTER
);
511 if (!strcmp(s
, "R_IBEFORE")) return (R_IBEFORE
);
512 if (!strcmp(s
, "R_LAST")) return (R_LAST
);
513 if (!strcmp(s
, "R_NEXT")) return (R_NEXT
);
514 if (!strcmp(s
, "R_NOOVERWRITE")) return (R_NOOVERWRITE
);
515 if (!strcmp(s
, "R_PREV")) return (R_PREV
);
516 if (!strcmp(s
, "R_SETCURSOR")) return (R_SETCURSOR
);
518 err("line %lu: %s: unknown flag", lineno
, s
);
526 case R_CURSOR
: return ("R_CURSOR");
527 case R_FIRST
: return ("R_FIRST");
528 case R_IAFTER
: return ("R_IAFTER");
529 case R_IBEFORE
: return ("R_IBEFORE");
530 case R_LAST
: return ("R_LAST");
531 case R_NEXT
: return ("R_NEXT");
532 case R_NOOVERWRITE
: return ("R_NOOVERWRITE");
533 case R_PREV
: return ("R_PREV");
534 case R_SETCURSOR
: return ("R_SETCURSOR");
543 if (!strcmp(s
, "btree"))
545 if (!strcmp(s
, "hash"))
547 if (!strcmp(s
, "recno"))
549 err("%s: unknown type (use btree, hash or recno)", s
);
554 setinfo(DBTYPE type
, char *s
)
561 if ((eq
= index(s
, '=')) == NULL
)
562 err("%s: illegal structure set statement", s
);
565 err("%s: structure set statement must be a number", s
);
569 if (!strcmp("flags", s
)) {
573 if (!strcmp("cachesize", s
)) {
574 ib
.cachesize
= atoi(eq
);
577 if (!strcmp("maxkeypage", s
)) {
578 ib
.maxkeypage
= atoi(eq
);
581 if (!strcmp("minkeypage", s
)) {
582 ib
.minkeypage
= atoi(eq
);
585 if (!strcmp("lorder", s
)) {
586 ib
.lorder
= atoi(eq
);
589 if (!strcmp("psize", s
)) {
595 if (!strcmp("bsize", s
)) {
599 if (!strcmp("ffactor", s
)) {
600 ih
.ffactor
= atoi(eq
);
603 if (!strcmp("nelem", s
)) {
607 if (!strcmp("cachesize", s
)) {
608 ih
.cachesize
= atoi(eq
);
611 if (!strcmp("lorder", s
)) {
612 ih
.lorder
= atoi(eq
);
617 if (!strcmp("flags", s
)) {
621 if (!strcmp("cachesize", s
)) {
622 rh
.cachesize
= atoi(eq
);
625 if (!strcmp("lorder", s
)) {
626 rh
.lorder
= atoi(eq
);
629 if (!strcmp("reclen", s
)) {
630 rh
.reclen
= atoi(eq
);
633 if (!strcmp("bval", s
)) {
637 if (!strcmp("psize", s
)) {
643 err("%s: unknown structure value", s
);
648 rfile(char *name
, size_t *lenp
)
655 for (; isspace(*name
); ++name
);
656 if ((np
= index(name
, '\n')) != NULL
)
658 if ((fd
= open(name
, O_RDONLY
, 0)) < 0 ||
660 err("%s: %s\n", name
, strerror(errno
));
662 if (sb
.st_size
> (off_t
)SIZE_T_MAX
)
663 err("%s: %s\n", name
, strerror(E2BIG
));
665 if ((p
= (void *)malloc((u_int
)sb
.st_size
)) == NULL
)
666 err("%s", strerror(errno
));
667 read(fd
, p
, (int)sb
.st_size
);
674 xmalloc(char *text
, size_t len
)
678 if ((p
= (void *)malloc(len
)) == NULL
)
679 err("%s", strerror(errno
));
680 memmove(p
, text
, len
);
688 "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
695 err(const char *fmt
, ...)
699 fprintf(stderr
, "dbtest: ");
700 vfprintf(stderr
, fmt
, ap
);
702 fprintf(stderr
, "\n");