add db.1.85
[nvi.git] / db.1.85 / test / btree.tests / main.c
blobf26e193562b3d555ed29f530fe6debd86ab29009
1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Mike Olson.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/4/93";
39 #endif /* LIBC_SCCS and not lint */
41 #include <sys/param.h>
42 #include <fcntl.h>
43 #include <db.h>
44 #include <errno.h>
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "btree.h"
51 typedef struct cmd_table {
52 char *cmd;
53 int nargs;
54 int rconv;
55 void (*func) __P((DB *, char **));
56 char *usage, *descrip;
57 } cmd_table;
59 int stopstop;
60 DB *globaldb;
62 void append __P((DB *, char **));
63 void bstat __P((DB *, char **));
64 void cursor __P((DB *, char **));
65 void delcur __P((DB *, char **));
66 void delete __P((DB *, char **));
67 void dump __P((DB *, char **));
68 void first __P((DB *, char **));
69 void get __P((DB *, char **));
70 void help __P((DB *, char **));
71 void iafter __P((DB *, char **));
72 void ibefore __P((DB *, char **));
73 void icursor __P((DB *, char **));
74 void insert __P((DB *, char **));
75 void keydata __P((DBT *, DBT *));
76 void last __P((DB *, char **));
77 void list __P((DB *, char **));
78 void load __P((DB *, char **));
79 void mstat __P((DB *, char **));
80 void next __P((DB *, char **));
81 int parse __P((char *, char **, int));
82 void previous __P((DB *, char **));
83 void show __P((DB *, char **));
84 void usage __P((void));
85 void user __P((DB *));
87 cmd_table commands[] = {
88 "?", 0, 0, help, "help", NULL,
89 "a", 2, 1, append, "append key def", "append key with data def",
90 "b", 0, 0, bstat, "bstat", "stat btree",
91 "c", 1, 1, cursor, "cursor word", "move cursor to word",
92 "delc", 0, 0, delcur, "delcur", "delete key the cursor references",
93 "dele", 1, 1, delete, "delete word", "delete word",
94 "d", 0, 0, dump, "dump", "dump database",
95 "f", 0, 0, first, "first", "move cursor to first record",
96 "g", 1, 1, get, "get key", "locate key",
97 "h", 0, 0, help, "help", "print command summary",
98 "ia", 2, 1, iafter, "iafter key data", "insert data after key",
99 "ib", 2, 1, ibefore, "ibefore key data", "insert data before key",
100 "ic", 2, 1, icursor, "icursor key data", "replace cursor",
101 "in", 2, 1, insert, "insert key def", "insert key with data def",
102 "la", 0, 0, last, "last", "move cursor to last record",
103 "li", 1, 1, list, "list file", "list to a file",
104 "loa", 1, 0, load, "load file", NULL,
105 "loc", 1, 1, get, "get key", NULL,
106 "m", 0, 0, mstat, "mstat", "stat memory pool",
107 "n", 0, 0, next, "next", "move cursor forward one record",
108 "p", 0, 0, previous, "previous", "move cursor back one record",
109 "q", 0, 0, NULL, "quit", "quit",
110 "sh", 1, 0, show, "show page", "dump a page",
111 { NULL },
114 int recno; /* use record numbers */
115 char *dict = "words"; /* default dictionary */
116 char *progname;
119 main(argc, argv)
120 int argc;
121 char **argv;
123 int c;
124 DB *db;
125 BTREEINFO b;
127 progname = *argv;
129 b.flags = 0;
130 b.cachesize = 0;
131 b.maxkeypage = 0;
132 b.minkeypage = 0;
133 b.psize = 0;
134 b.compare = NULL;
135 b.prefix = NULL;
136 b.lorder = 0;
138 while ((c = getopt(argc, argv, "bc:di:lp:ru")) != EOF) {
139 switch (c) {
140 case 'b':
141 b.lorder = BIG_ENDIAN;
142 break;
143 case 'c':
144 b.cachesize = atoi(optarg);
145 break;
146 case 'd':
147 b.flags |= R_DUP;
148 break;
149 case 'i':
150 dict = optarg;
151 break;
152 case 'l':
153 b.lorder = LITTLE_ENDIAN;
154 break;
155 case 'p':
156 b.psize = atoi(optarg);
157 break;
158 case 'r':
159 recno = 1;
160 break;
161 case 'u':
162 b.flags = 0;
163 break;
164 default:
165 usage();
168 argc -= optind;
169 argv += optind;
171 if (recno)
172 db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
173 0, DB_RECNO, NULL);
174 else
175 db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
176 0600, DB_BTREE, &b);
178 if (db == NULL) {
179 (void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
180 exit(1);
182 globaldb = db;
183 user(db);
184 exit(0);
185 /* NOTREACHED */
188 void
189 user(db)
190 DB *db;
192 FILE *ifp;
193 int argc, i, last;
194 char *lbuf, *argv[4], buf[512];
196 if ((ifp = fopen("/dev/tty", "r")) == NULL) {
197 (void)fprintf(stderr,
198 "/dev/tty: %s\n", strerror(errno));
199 exit(1);
201 for (last = 0;;) {
202 (void)printf("> ");
203 (void)fflush(stdout);
204 if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
205 break;
206 if (lbuf[0] == '\n') {
207 i = last;
208 goto uselast;
210 lbuf[strlen(lbuf) - 1] = '\0';
212 if (lbuf[0] == 'q')
213 break;
215 argc = parse(lbuf, &argv[0], 3);
216 if (argc == 0)
217 continue;
219 for (i = 0; commands[i].cmd != NULL; i++)
220 if (strncmp(commands[i].cmd, argv[0],
221 strlen(commands[i].cmd)) == 0)
222 break;
224 if (commands[i].cmd == NULL) {
225 (void)fprintf(stderr,
226 "%s: command unknown ('help' for help)\n", lbuf);
227 continue;
230 if (commands[i].nargs != argc - 1) {
231 (void)fprintf(stderr, "usage: %s\n", commands[i].usage);
232 continue;
235 if (recno && commands[i].rconv) {
236 static recno_t nlong;
237 nlong = atoi(argv[1]);
238 argv[1] = (char *)&nlong;
240 uselast: last = i;
241 (*commands[i].func)(db, argv);
243 if ((db->sync)(db) == RET_ERROR)
244 perror("dbsync");
245 else if ((db->close)(db) == RET_ERROR)
246 perror("dbclose");
250 parse(lbuf, argv, maxargc)
251 char *lbuf, **argv;
252 int maxargc;
254 int argc = 0;
255 char *c;
257 c = lbuf;
258 while (isspace(*c))
259 c++;
260 while (*c != '\0' && argc < maxargc) {
261 *argv++ = c;
262 argc++;
263 while (!isspace(*c) && *c != '\0') {
264 c++;
266 while (isspace(*c))
267 *c++ = '\0';
269 return (argc);
272 void
273 append(db, argv)
274 DB *db;
275 char **argv;
277 DBT key, data;
278 int status;
280 if (!recno) {
281 (void)fprintf(stderr,
282 "append only available for recno db's.\n");
283 return;
285 key.data = argv[1];
286 key.size = sizeof(recno_t);
287 data.data = argv[2];
288 data.size = strlen(data.data);
289 status = (db->put)(db, &key, &data, R_APPEND);
290 switch (status) {
291 case RET_ERROR:
292 perror("append/put");
293 break;
294 case RET_SPECIAL:
295 (void)printf("%s (duplicate key)\n", argv[1]);
296 break;
297 case RET_SUCCESS:
298 break;
302 void
303 cursor(db, argv)
304 DB *db;
305 char **argv;
307 DBT data, key;
308 int status;
310 key.data = argv[1];
311 if (recno)
312 key.size = sizeof(recno_t);
313 else
314 key.size = strlen(argv[1]) + 1;
315 status = (*db->seq)(db, &key, &data, R_CURSOR);
316 switch (status) {
317 case RET_ERROR:
318 perror("cursor/seq");
319 break;
320 case RET_SPECIAL:
321 (void)printf("key not found\n");
322 break;
323 case RET_SUCCESS:
324 keydata(&key, &data);
325 break;
329 void
330 delcur(db, argv)
331 DB *db;
332 char **argv;
334 int status;
336 status = (*db->del)(db, NULL, R_CURSOR);
338 if (status == RET_ERROR)
339 perror("delcur/del");
342 void
343 delete(db, argv)
344 DB *db;
345 char **argv;
347 DBT key;
348 int status;
350 key.data = argv[1];
351 if (recno)
352 key.size = sizeof(recno_t);
353 else
354 key.size = strlen(argv[1]) + 1;
356 status = (*db->del)(db, &key, 0);
357 switch (status) {
358 case RET_ERROR:
359 perror("delete/del");
360 break;
361 case RET_SPECIAL:
362 (void)printf("key not found\n");
363 break;
364 case RET_SUCCESS:
365 break;
369 void
370 dump(db, argv)
371 DB *db;
372 char **argv;
374 __bt_dump(db);
377 void
378 first(db, argv)
379 DB *db;
380 char **argv;
382 DBT data, key;
383 int status;
385 status = (*db->seq)(db, &key, &data, R_FIRST);
387 switch (status) {
388 case RET_ERROR:
389 perror("first/seq");
390 break;
391 case RET_SPECIAL:
392 (void)printf("no more keys\n");
393 break;
394 case RET_SUCCESS:
395 keydata(&key, &data);
396 break;
400 void
401 get(db, argv)
402 DB *db;
403 char **argv;
405 DBT data, key;
406 int status;
408 key.data = argv[1];
409 if (recno)
410 key.size = sizeof(recno_t);
411 else
412 key.size = strlen(argv[1]) + 1;
414 status = (*db->get)(db, &key, &data, 0);
416 switch (status) {
417 case RET_ERROR:
418 perror("get/get");
419 break;
420 case RET_SPECIAL:
421 (void)printf("key not found\n");
422 break;
423 case RET_SUCCESS:
424 keydata(&key, &data);
425 break;
429 void
430 help(db, argv)
431 DB *db;
432 char **argv;
434 int i;
436 for (i = 0; commands[i].cmd; i++)
437 if (commands[i].descrip)
438 (void)printf("%s: %s\n",
439 commands[i].usage, commands[i].descrip);
442 void
443 iafter(db, argv)
444 DB *db;
445 char **argv;
447 DBT key, data;
448 int status;
450 if (!recno) {
451 (void)fprintf(stderr,
452 "iafter only available for recno db's.\n");
453 return;
455 key.data = argv[1];
456 key.size = sizeof(recno_t);
457 data.data = argv[2];
458 data.size = strlen(data.data);
459 status = (db->put)(db, &key, &data, R_IAFTER);
460 switch (status) {
461 case RET_ERROR:
462 perror("iafter/put");
463 break;
464 case RET_SPECIAL:
465 (void)printf("%s (duplicate key)\n", argv[1]);
466 break;
467 case RET_SUCCESS:
468 break;
472 void
473 ibefore(db, argv)
474 DB *db;
475 char **argv;
477 DBT key, data;
478 int status;
480 if (!recno) {
481 (void)fprintf(stderr,
482 "ibefore only available for recno db's.\n");
483 return;
485 key.data = argv[1];
486 key.size = sizeof(recno_t);
487 data.data = argv[2];
488 data.size = strlen(data.data);
489 status = (db->put)(db, &key, &data, R_IBEFORE);
490 switch (status) {
491 case RET_ERROR:
492 perror("ibefore/put");
493 break;
494 case RET_SPECIAL:
495 (void)printf("%s (duplicate key)\n", argv[1]);
496 break;
497 case RET_SUCCESS:
498 break;
502 void
503 icursor(db, argv)
504 DB *db;
505 char **argv;
507 int status;
508 DBT data, key;
510 key.data = argv[1];
511 if (recno)
512 key.size = sizeof(recno_t);
513 else
514 key.size = strlen(argv[1]) + 1;
515 data.data = argv[2];
516 data.size = strlen(argv[2]) + 1;
518 status = (*db->put)(db, &key, &data, R_CURSOR);
519 switch (status) {
520 case RET_ERROR:
521 perror("icursor/put");
522 break;
523 case RET_SPECIAL:
524 (void)printf("%s (duplicate key)\n", argv[1]);
525 break;
526 case RET_SUCCESS:
527 break;
531 void
532 insert(db, argv)
533 DB *db;
534 char **argv;
536 int status;
537 DBT data, key;
539 key.data = argv[1];
540 if (recno)
541 key.size = sizeof(recno_t);
542 else
543 key.size = strlen(argv[1]) + 1;
544 data.data = argv[2];
545 data.size = strlen(argv[2]) + 1;
547 status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
548 switch (status) {
549 case RET_ERROR:
550 perror("insert/put");
551 break;
552 case RET_SPECIAL:
553 (void)printf("%s (duplicate key)\n", argv[1]);
554 break;
555 case RET_SUCCESS:
556 break;
560 void
561 last(db, argv)
562 DB *db;
563 char **argv;
565 DBT data, key;
566 int status;
568 status = (*db->seq)(db, &key, &data, R_LAST);
570 switch (status) {
571 case RET_ERROR:
572 perror("last/seq");
573 break;
574 case RET_SPECIAL:
575 (void)printf("no more keys\n");
576 break;
577 case RET_SUCCESS:
578 keydata(&key, &data);
579 break;
583 void
584 list(db, argv)
585 DB *db;
586 char **argv;
588 DBT data, key;
589 FILE *fp;
590 int status;
592 if ((fp = fopen(argv[1], "w")) == NULL) {
593 (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
594 return;
596 status = (*db->seq)(db, &key, &data, R_FIRST);
597 while (status == RET_SUCCESS) {
598 (void)fprintf(fp, "%s\n", key.data);
599 status = (*db->seq)(db, &key, &data, R_NEXT);
601 if (status == RET_ERROR)
602 perror("list/seq");
605 DB *BUGdb;
606 void
607 load(db, argv)
608 DB *db;
609 char **argv;
611 register char *p, *t;
612 FILE *fp;
613 DBT data, key;
614 recno_t cnt;
615 size_t len;
616 int status;
617 char *lp, buf[16 * 1024];
619 BUGdb = db;
620 if ((fp = fopen(argv[1], "r")) == NULL) {
621 (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
622 return;
624 (void)printf("loading %s...\n", argv[1]);
626 for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
627 if (recno) {
628 key.data = &cnt;
629 key.size = sizeof(recno_t);
630 data.data = lp;
631 data.size = len + 1;
632 } else {
633 key.data = lp;
634 key.size = len + 1;
635 for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
636 *t = '\0';
637 data.data = buf;
638 data.size = len + 1;
641 status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
642 switch (status) {
643 case RET_ERROR:
644 perror("load/put");
645 exit(1);
646 case RET_SPECIAL:
647 if (recno)
648 (void)fprintf(stderr,
649 "duplicate: %ld {%s}\n", cnt, data.data);
650 else
651 (void)fprintf(stderr,
652 "duplicate: %ld {%s}\n", cnt, key.data);
653 exit(1);
654 case RET_SUCCESS:
655 break;
658 (void)fclose(fp);
661 void
662 next(db, argv)
663 DB *db;
664 char **argv;
666 DBT data, key;
667 int status;
669 status = (*db->seq)(db, &key, &data, R_NEXT);
671 switch (status) {
672 case RET_ERROR:
673 perror("next/seq");
674 break;
675 case RET_SPECIAL:
676 (void)printf("no more keys\n");
677 break;
678 case RET_SUCCESS:
679 keydata(&key, &data);
680 break;
684 void
685 previous(db, argv)
686 DB *db;
687 char **argv;
689 DBT data, key;
690 int status;
692 status = (*db->seq)(db, &key, &data, R_PREV);
694 switch (status) {
695 case RET_ERROR:
696 perror("previous/seq");
697 break;
698 case RET_SPECIAL:
699 (void)printf("no more keys\n");
700 break;
701 case RET_SUCCESS:
702 keydata(&key, &data);
703 break;
707 void
708 show(db, argv)
709 DB *db;
710 char **argv;
712 BTREE *t;
713 PAGE *h;
714 pgno_t pg;
716 pg = atoi(argv[1]);
717 t = db->internal;
718 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
719 (void)printf("getpage of %ld failed\n", pg);
720 return;
722 if (pg == 0)
723 __bt_dmpage(h);
724 else
725 __bt_dpage(h);
726 mpool_put(t->bt_mp, h, 0);
729 void
730 bstat(db, argv)
731 DB *db;
732 char **argv;
734 (void)printf("BTREE\n");
735 __bt_stat(db);
738 void
739 mstat(db, argv)
740 DB *db;
741 char **argv;
743 (void)printf("MPOOL\n");
744 mpool_stat(((BTREE *)db->internal)->bt_mp);
747 void
748 keydata(key, data)
749 DBT *key, *data;
751 if (!recno && key->size > 0)
752 (void)printf("%s/", key->data);
753 if (data->size > 0)
754 (void)printf("%s", data->data);
755 (void)printf("\n");
758 void
759 usage()
761 (void)fprintf(stderr,
762 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
763 progname);
764 exit (1);