source: vendor/FreeBSD-libc/current/db/test/dbtest.c

Last change on this file was 961, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.4 KB
Line 
1/*-
2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1992, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#if defined(LIBC_SCCS) && !defined(lint)
41static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
42#endif /* LIBC_SCCS and not lint */
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: src/lib/libc/db/test/dbtest.c,v 1.10 2002/05/28 16:59:38 alfred Exp $");
45
46#include <sys/param.h>
47#include <sys/stat.h>
48
49#include <ctype.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include <db.h>
59
60enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
61
62void compare(DBT *, DBT *);
63DBTYPE dbtype(char *);
64void dump(DB *, int);
65void err(const char *, ...) __printflike(1, 2);
66void get(DB *, DBT *);
67void getdata(DB *, DBT *, DBT *);
68void put(DB *, DBT *, DBT *);
69void rem(DB *, DBT *);
70char *sflags(int);
71void synk(DB *);
72void *rfile(char *, size_t *);
73void seq(DB *, DBT *);
74u_int setflags(char *);
75void *setinfo(DBTYPE, char *);
76void usage(void);
77void *xmalloc(char *, size_t);
78
79DBTYPE type; /* Database type. */
80void *infop; /* Iflags. */
81u_long lineno; /* Current line in test script. */
82u_int flags; /* Current DB flags. */
83int ofd = STDOUT_FILENO; /* Standard output fd. */
84
85DB *XXdbp; /* Global for gdb. */
86int XXlineno; /* Fast breakpoint for gdb. */
87
88int
89main(argc, argv)
90 int argc;
91 char *argv[];
92{
93 extern int optind;
94 extern char *optarg;
95 enum S command, state;
96 DB *dbp;
97 DBT data, key, keydata;
98 size_t len;
99 int ch, oflags, sflag;
100 char *fname, *infoarg, *p, *t, buf[8 * 1024];
101
102 infoarg = NULL;
103 fname = NULL;
104 oflags = O_CREAT | O_RDWR;
105 sflag = 0;
106 while ((ch = getopt(argc, argv, "f:i:lo:s")) != EOF)
107 switch (ch) {
108 case 'f':
109 fname = optarg;
110 break;
111 case 'i':
112 infoarg = optarg;
113 break;
114 case 'l':
115 oflags |= DB_LOCK;
116 break;
117 case 'o':
118 if ((ofd = open(optarg,
119 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
120 err("%s: %s", optarg, strerror(errno));
121 break;
122 case 's':
123 sflag = 1;
124 break;
125 case '?':
126 default:
127 usage();
128 }
129 argc -= optind;
130 argv += optind;
131
132 if (argc != 2)
133 usage();
134
135 /* Set the type. */
136 type = dbtype(*argv++);
137
138 /* Open the descriptor file. */
139 if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
140 err("%s: %s", *argv, strerror(errno));
141
142 /* Set up the db structure as necessary. */
143 if (infoarg == NULL)
144 infop = NULL;
145 else
146 for (p = strtok(infoarg, ",\t "); p != NULL;
147 p = strtok(0, ",\t "))
148 if (*p != '\0')
149 infop = setinfo(type, p);
150
151 /*
152 * Open the DB. Delete any preexisting copy, you almost never
153 * want it around, and it often screws up tests.
154 */
155 if (fname == NULL) {
156 p = getenv("TMPDIR");
157 if (p == NULL)
158 p = "/var/tmp";
159 (void)snprintf(buf, sizeof(buf), "%s/__dbtest", p);
160 fname = buf;
161 (void)unlink(buf);
162 } else if (!sflag)
163 (void)unlink(fname);
164
165 if ((dbp = dbopen(fname,
166 oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
167 err("dbopen: %s", strerror(errno));
168 XXdbp = dbp;
169
170 state = COMMAND;
171 for (lineno = 1;
172 (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
173 /* Delete the newline, displaying the key/data is easier. */
174 if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
175 *t = '\0';
176 if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
177 continue;
178
179 /* Convenient gdb break point. */
180 if (XXlineno == lineno)
181 XXlineno = 1;
182 switch (*p) {
183 case 'c': /* compare */
184 if (state != COMMAND)
185 err("line %lu: not expecting command", lineno);
186 state = KEY;
187 command = COMPARE;
188 break;
189 case 'e': /* echo */
190 if (state != COMMAND)
191 err("line %lu: not expecting command", lineno);
192 /* Don't display the newline, if CR at EOL. */
193 if (p[len - 2] == '\r')
194 --len;
195 if (write(ofd, p + 1, len - 1) != len - 1 ||
196 write(ofd, "\n", 1) != 1)
197 err("write: %s", strerror(errno));
198 break;
199 case 'g': /* get */
200 if (state != COMMAND)
201 err("line %lu: not expecting command", lineno);
202 state = KEY;
203 command = GET;
204 break;
205 case 'p': /* put */
206 if (state != COMMAND)
207 err("line %lu: not expecting command", lineno);
208 state = KEY;
209 command = PUT;
210 break;
211 case 'r': /* remove */
212 if (state != COMMAND)
213 err("line %lu: not expecting command", lineno);
214 if (flags == R_CURSOR) {
215 rem(dbp, &key);
216 state = COMMAND;
217 } else {
218 state = KEY;
219 command = REMOVE;
220 }
221 break;
222 case 'S': /* sync */
223 if (state != COMMAND)
224 err("line %lu: not expecting command", lineno);
225 synk(dbp);
226 state = COMMAND;
227 break;
228 case 's': /* seq */
229 if (state != COMMAND)
230 err("line %lu: not expecting command", lineno);
231 if (flags == R_CURSOR) {
232 state = KEY;
233 command = SEQ;
234 } else
235 seq(dbp, &key);
236 break;
237 case 'f':
238 flags = setflags(p + 1);
239 break;
240 case 'D': /* data file */
241 if (state != DATA)
242 err("line %lu: not expecting data", lineno);
243 data.data = rfile(p + 1, &data.size);
244 goto ldata;
245 case 'd': /* data */
246 if (state != DATA)
247 err("line %lu: not expecting data", lineno);
248 data.data = xmalloc(p + 1, len - 1);
249 data.size = len - 1;
250ldata: switch (command) {
251 case COMPARE:
252 compare(&keydata, &data);
253 break;
254 case PUT:
255 put(dbp, &key, &data);
256 break;
257 default:
258 err("line %lu: command doesn't take data",
259 lineno);
260 }
261 if (type != DB_RECNO)
262 free(key.data);
263 free(data.data);
264 state = COMMAND;
265 break;
266 case 'K': /* key file */
267 if (state != KEY)
268 err("line %lu: not expecting a key", lineno);
269 if (type == DB_RECNO)
270 err("line %lu: 'K' not available for recno",
271 lineno);
272 key.data = rfile(p + 1, &key.size);
273 goto lkey;
274 case 'k': /* key */
275 if (state != KEY)
276 err("line %lu: not expecting a key", lineno);
277 if (type == DB_RECNO) {
278 static recno_t recno;
279 recno = atoi(p + 1);
280 key.data = &recno;
281 key.size = sizeof(recno);
282 } else {
283 key.data = xmalloc(p + 1, len - 1);
284 key.size = len - 1;
285 }
286lkey: switch (command) {
287 case COMPARE:
288 getdata(dbp, &key, &keydata);
289 state = DATA;
290 break;
291 case GET:
292 get(dbp, &key);
293 if (type != DB_RECNO)
294 free(key.data);
295 state = COMMAND;
296 break;
297 case PUT:
298 state = DATA;
299 break;
300 case REMOVE:
301 rem(dbp, &key);
302 if ((type != DB_RECNO) && (flags != R_CURSOR))
303 free(key.data);
304 state = COMMAND;
305 break;
306 case SEQ:
307 seq(dbp, &key);
308 if ((type != DB_RECNO) && (flags != R_CURSOR))
309 free(key.data);
310 state = COMMAND;
311 break;
312 default:
313 err("line %lu: command doesn't take a key",
314 lineno);
315 }
316 break;
317 case 'o':
318 dump(dbp, p[1] == 'r');
319 break;
320 default:
321 err("line %lu: %s: unknown command character",
322 lineno, p);
323 }
324 }
325#ifdef STATISTICS
326 /*
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.
329 */
330 if (type == DB_BTREE && oflags & DB_LOCK)
331 __bt_stat(dbp);
332#endif
333 if (dbp->close(dbp))
334 err("db->close: %s", strerror(errno));
335 (void)close(ofd);
336 exit(0);
337}
338
339#define NOOVERWRITE "put failed, would overwrite key\n"
340
341void
342compare(db1, db2)
343 DBT *db1, *db2;
344{
345 size_t len;
346 u_char *p1, *p2;
347
348 if (db1->size != db2->size)
349 printf("compare failed: key->data len %lu != data len %lu\n",
350 db1->size, db2->size);
351
352 len = MIN(db1->size, db2->size);
353 for (p1 = db1->data, p2 = db2->data; len--;)
354 if (*p1++ != *p2++) {
355 printf("compare failed at offset %d\n",
356 p1 - (u_char *)db1->data);
357 break;
358 }
359}
360
361void
362get(dbp, kp)
363 DB *dbp;
364 DBT *kp;
365{
366 DBT data;
367
368 switch (dbp->get(dbp, kp, &data, flags)) {
369 case 0:
370 (void)write(ofd, data.data, data.size);
371 if (ofd == STDOUT_FILENO)
372 (void)write(ofd, "\n", 1);
373 break;
374 case -1:
375 err("line %lu: get: %s", lineno, strerror(errno));
376 /* NOTREACHED */
377 case 1:
378#define NOSUCHKEY "get failed, no such key\n"
379 if (ofd != STDOUT_FILENO)
380 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
381 else
382 (void)fprintf(stderr, "%d: %.*s: %s",
383 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
384#undef NOSUCHKEY
385 break;
386 }
387}
388
389void
390getdata(dbp, kp, dp)
391 DB *dbp;
392 DBT *kp, *dp;
393{
394 switch (dbp->get(dbp, kp, dp, flags)) {
395 case 0:
396 return;
397 case -1:
398 err("line %lu: getdata: %s", lineno, strerror(errno));
399 /* NOTREACHED */
400 case 1:
401 err("line %lu: getdata failed, no such key", lineno);
402 /* NOTREACHED */
403 }
404}
405
406void
407put(dbp, kp, dp)
408 DB *dbp;
409 DBT *kp, *dp;
410{
411 switch (dbp->put(dbp, kp, dp, flags)) {
412 case 0:
413 break;
414 case -1:
415 err("line %lu: put: %s", lineno, strerror(errno));
416 /* NOTREACHED */
417 case 1:
418 (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
419 break;
420 }
421}
422
423void
424rem(dbp, kp)
425 DB *dbp;
426 DBT *kp;
427{
428 switch (dbp->del(dbp, kp, flags)) {
429 case 0:
430 break;
431 case -1:
432 err("line %lu: rem: %s", lineno, strerror(errno));
433 /* NOTREACHED */
434 case 1:
435#define NOSUCHKEY "rem failed, no such key\n"
436 if (ofd != STDOUT_FILENO)
437 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
438 else if (flags != R_CURSOR)
439 (void)fprintf(stderr, "%d: %.*s: %s",
440 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
441 else
442 (void)fprintf(stderr,
443 "%d: rem of cursor failed\n", lineno);
444#undef NOSUCHKEY
445 break;
446 }
447}
448
449void
450synk(dbp)
451 DB *dbp;
452{
453 switch (dbp->sync(dbp, flags)) {
454 case 0:
455 break;
456 case -1:
457 err("line %lu: synk: %s", lineno, strerror(errno));
458 /* NOTREACHED */
459 }
460}
461
462void
463seq(dbp, kp)
464 DB *dbp;
465 DBT *kp;
466{
467 DBT data;
468
469 switch (dbp->seq(dbp, kp, &data, flags)) {
470 case 0:
471 (void)write(ofd, data.data, data.size);
472 if (ofd == STDOUT_FILENO)
473 (void)write(ofd, "\n", 1);
474 break;
475 case -1:
476 err("line %lu: seq: %s", lineno, strerror(errno));
477 /* NOTREACHED */
478 case 1:
479#define NOSUCHKEY "seq failed, no such key\n"
480 if (ofd != STDOUT_FILENO)
481 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
482 else if (flags == R_CURSOR)
483 (void)fprintf(stderr, "%d: %.*s: %s",
484 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
485 else
486 (void)fprintf(stderr,
487 "%d: seq (%s) failed\n", lineno, sflags(flags));
488#undef NOSUCHKEY
489 break;
490 }
491}
492
493void
494dump(dbp, rev)
495 DB *dbp;
496 int rev;
497{
498 DBT key, data;
499 int flags, nflags;
500
501 if (rev) {
502 flags = R_LAST;
503 nflags = R_PREV;
504 } else {
505 flags = R_FIRST;
506 nflags = R_NEXT;
507 }
508 for (;; flags = nflags)
509 switch (dbp->seq(dbp, &key, &data, flags)) {
510 case 0:
511 (void)write(ofd, data.data, data.size);
512 if (ofd == STDOUT_FILENO)
513 (void)write(ofd, "\n", 1);
514 break;
515 case 1:
516 goto done;
517 case -1:
518 err("line %lu: (dump) seq: %s",
519 lineno, strerror(errno));
520 /* NOTREACHED */
521 }
522done: return;
523}
524
525u_int
526setflags(s)
527 char *s;
528{
529 char *p, *index();
530
531 for (; isspace(*s); ++s);
532 if (*s == '\n' || *s == '\0')
533 return (0);
534 if ((p = index(s, '\n')) != NULL)
535 *p = '\0';
536 if (!strcmp(s, "R_CURSOR")) return (R_CURSOR);
537 if (!strcmp(s, "R_FIRST")) return (R_FIRST);
538 if (!strcmp(s, "R_IAFTER")) return (R_IAFTER);
539 if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE);
540 if (!strcmp(s, "R_LAST")) return (R_LAST);
541 if (!strcmp(s, "R_NEXT")) return (R_NEXT);
542 if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE);
543 if (!strcmp(s, "R_PREV")) return (R_PREV);
544 if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR);
545
546 err("line %lu: %s: unknown flag", lineno, s);
547 /* NOTREACHED */
548}
549
550char *
551sflags(flags)
552 int flags;
553{
554 switch (flags) {
555 case R_CURSOR: return ("R_CURSOR");
556 case R_FIRST: return ("R_FIRST");
557 case R_IAFTER: return ("R_IAFTER");
558 case R_IBEFORE: return ("R_IBEFORE");
559 case R_LAST: return ("R_LAST");
560 case R_NEXT: return ("R_NEXT");
561 case R_NOOVERWRITE: return ("R_NOOVERWRITE");
562 case R_PREV: return ("R_PREV");
563 case R_SETCURSOR: return ("R_SETCURSOR");
564 }
565
566 return ("UNKNOWN!");
567}
568
569DBTYPE
570dbtype(s)
571 char *s;
572{
573 if (!strcmp(s, "btree"))
574 return (DB_BTREE);
575 if (!strcmp(s, "hash"))
576 return (DB_HASH);
577 if (!strcmp(s, "recno"))
578 return (DB_RECNO);
579 err("%s: unknown type (use btree, hash or recno)", s);
580 /* NOTREACHED */
581}
582
583void *
584setinfo(type, s)
585 DBTYPE type;
586 char *s;
587{
588 static BTREEINFO ib;
589 static HASHINFO ih;
590 static RECNOINFO rh;
591 char *eq, *index();
592
593 if ((eq = index(s, '=')) == NULL)
594 err("%s: illegal structure set statement", s);
595 *eq++ = '\0';
596 if (!isdigit(*eq))
597 err("%s: structure set statement must be a number", s);
598
599 switch (type) {
600 case DB_BTREE:
601 if (!strcmp("flags", s)) {
602 ib.flags = atoi(eq);
603 return (&ib);
604 }
605 if (!strcmp("cachesize", s)) {
606 ib.cachesize = atoi(eq);
607 return (&ib);
608 }
609 if (!strcmp("maxkeypage", s)) {
610 ib.maxkeypage = atoi(eq);
611 return (&ib);
612 }
613 if (!strcmp("minkeypage", s)) {
614 ib.minkeypage = atoi(eq);
615 return (&ib);
616 }
617 if (!strcmp("lorder", s)) {
618 ib.lorder = atoi(eq);
619 return (&ib);
620 }
621 if (!strcmp("psize", s)) {
622 ib.psize = atoi(eq);
623 return (&ib);
624 }
625 break;
626 case DB_HASH:
627 if (!strcmp("bsize", s)) {
628 ih.bsize = atoi(eq);
629 return (&ih);
630 }
631 if (!strcmp("ffactor", s)) {
632 ih.ffactor = atoi(eq);
633 return (&ih);
634 }
635 if (!strcmp("nelem", s)) {
636 ih.nelem = atoi(eq);
637 return (&ih);
638 }
639 if (!strcmp("cachesize", s)) {
640 ih.cachesize = atoi(eq);
641 return (&ih);
642 }
643 if (!strcmp("lorder", s)) {
644 ih.lorder = atoi(eq);
645 return (&ih);
646 }
647 break;
648 case DB_RECNO:
649 if (!strcmp("flags", s)) {
650 rh.flags = atoi(eq);
651 return (&rh);
652 }
653 if (!strcmp("cachesize", s)) {
654 rh.cachesize = atoi(eq);
655 return (&rh);
656 }
657 if (!strcmp("lorder", s)) {
658 rh.lorder = atoi(eq);
659 return (&rh);
660 }
661 if (!strcmp("reclen", s)) {
662 rh.reclen = atoi(eq);
663 return (&rh);
664 }
665 if (!strcmp("bval", s)) {
666 rh.bval = atoi(eq);
667 return (&rh);
668 }
669 if (!strcmp("psize", s)) {
670 rh.psize = atoi(eq);
671 return (&rh);
672 }
673 break;
674 }
675 err("%s: unknown structure value", s);
676 /* NOTREACHED */
677}
678
679void *
680rfile(name, lenp)
681 char *name;
682 size_t *lenp;
683{
684 struct stat sb;
685 void *p;
686 int fd;
687 char *np, *index();
688
689 for (; isspace(*name); ++name);
690 if ((np = index(name, '\n')) != NULL)
691 *np = '\0';
692 if ((fd = open(name, O_RDONLY, 0)) < 0 ||
693 fstat(fd, &sb))
694 err("%s: %s\n", name, strerror(errno));
695#ifdef NOT_PORTABLE
696 if (sb.st_size > (off_t)SIZE_T_MAX)
697 err("%s: %s\n", name, strerror(E2BIG));
698#endif
699 if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
700 err("%s", strerror(errno));
701 (void)read(fd, p, (int)sb.st_size);
702 *lenp = sb.st_size;
703 (void)close(fd);
704 return (p);
705}
706
707void *
708xmalloc(text, len)
709 char *text;
710 size_t len;
711{
712 void *p;
713
714 if ((p = (void *)malloc(len)) == NULL)
715 err("%s", strerror(errno));
716 memmove(p, text, len);
717 return (p);
718}
719
720void
721usage()
722{
723 (void)fprintf(stderr,
724 "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
725 exit(1);
726}
727
728#include <stdarg.h>
729
730void
731err(const char *fmt, ...)
732{
733 va_list ap;
734
735 va_start(ap, fmt);
736 (void)fprintf(stderr, "dbtest: ");
737 (void)vfprintf(stderr, fmt, ap);
738 va_end(ap);
739 (void)fprintf(stderr, "\n");
740 exit(1);
741 /* NOTREACHED */
742}
Note: See TracBrowser for help on using the repository browser.