xref: /dragonfly/lib/libc/db/test/btree.tests/main.c (revision 2cd2d2b5)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Olson.
7  *
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.
23  *
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.
35  *
36  * @(#)main.c	8.1 (Berkeley) 6/4/93
37  * $DragonFly: src/lib/libc/db/test/btree.tests/main.c,v 1.4 2003/11/12 20:21:23 eirikn Exp $
38  */
39 
40 #include <sys/param.h>
41 #include <fcntl.h>
42 #include <db.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "btree.h"
49 
50 typedef struct cmd_table {
51 	char *cmd;
52 	int nargs;
53 	int rconv;
54 	void (*func) (DB *, char **);
55 	char *usage, *descrip;
56 } cmd_table;
57 
58 int stopstop;
59 DB *globaldb;
60 
61 void append	(DB *, char **);
62 void bstat	(DB *, char **);
63 void cursor	(DB *, char **);
64 void delcur	(DB *, char **);
65 void delete	(DB *, char **);
66 void dump	(DB *, char **);
67 void first	(DB *, char **);
68 void get	(DB *, char **);
69 void help	(DB *, char **);
70 void iafter	(DB *, char **);
71 void ibefore	(DB *, char **);
72 void icursor	(DB *, char **);
73 void insert	(DB *, char **);
74 void keydata	(DBT *, DBT *);
75 void last	(DB *, char **);
76 void list	(DB *, char **);
77 void load	(DB *, char **);
78 void mstat	(DB *, char **);
79 void next	(DB *, char **);
80 int  parse	(char *, char **, int);
81 void previous	(DB *, char **);
82 void show	(DB *, char **);
83 void usage	(void);
84 void user	(DB *);
85 
86 cmd_table commands[] = {
87 	"?",	0, 0, help, "help", NULL,
88 	"a",	2, 1, append, "append key def", "append key with data def",
89 	"b",	0, 0, bstat, "bstat", "stat btree",
90 	"c",	1, 1, cursor,  "cursor word", "move cursor to word",
91 	"delc",	0, 0, delcur, "delcur", "delete key the cursor references",
92 	"dele",	1, 1, delete, "delete word", "delete word",
93 	"d",	0, 0, dump, "dump", "dump database",
94 	"f",	0, 0, first, "first", "move cursor to first record",
95 	"g",	1, 1, get, "get key", "locate key",
96 	"h",	0, 0, help, "help", "print command summary",
97 	"ia",	2, 1, iafter, "iafter key data", "insert data after key",
98 	"ib",	2, 1, ibefore, "ibefore key data", "insert data before key",
99 	"ic",	2, 1, icursor, "icursor key data", "replace cursor",
100 	"in",	2, 1, insert, "insert key def", "insert key with data def",
101 	"la",	0, 0, last, "last", "move cursor to last record",
102 	"li",	1, 1, list, "list file", "list to a file",
103 	"loa",	1, 0, load, "load file", NULL,
104 	"loc",	1, 1, get, "get key", NULL,
105 	"m",	0, 0, mstat, "mstat", "stat memory pool",
106 	"n",	0, 0, next, "next", "move cursor forward one record",
107 	"p",	0, 0, previous, "previous", "move cursor back one record",
108 	"q",	0, 0, NULL, "quit", "quit",
109 	"sh",	1, 0, show, "show page", "dump a page",
110 	{ NULL },
111 };
112 
113 int recno;					/* use record numbers */
114 char *dict = "words";				/* default dictionary */
115 char *progname;
116 
117 int
118 main(argc, argv)
119 	int argc;
120 	char **argv;
121 {
122 	int c;
123 	DB *db;
124 	BTREEINFO b;
125 
126 	progname = *argv;
127 
128 	b.flags = 0;
129 	b.cachesize = 0;
130 	b.maxkeypage = 0;
131 	b.minkeypage = 0;
132 	b.psize = 0;
133 	b.compare = NULL;
134 	b.prefix = NULL;
135 	b.lorder = 0;
136 
137 	while ((c = getopt(argc, argv, "bc:di:lp:ru")) != EOF) {
138 		switch (c) {
139 		case 'b':
140 			b.lorder = BIG_ENDIAN;
141 			break;
142 		case 'c':
143 			b.cachesize = atoi(optarg);
144 			break;
145 		case 'd':
146 			b.flags |= R_DUP;
147 			break;
148 		case 'i':
149 			dict = optarg;
150 			break;
151 		case 'l':
152 			b.lorder = LITTLE_ENDIAN;
153 			break;
154 		case 'p':
155 			b.psize = atoi(optarg);
156 			break;
157 		case 'r':
158 			recno = 1;
159 			break;
160 		case 'u':
161 			b.flags = 0;
162 			break;
163 		default:
164 			usage();
165 		}
166 	}
167 	argc -= optind;
168 	argv += optind;
169 
170 	if (recno)
171 		db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
172 		    0, DB_RECNO, NULL);
173 	else
174 		db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
175 		    0600, DB_BTREE, &b);
176 
177 	if (db == NULL) {
178 		(void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
179 		exit(1);
180 	}
181 	globaldb = db;
182 	user(db);
183 	exit(0);
184 	/* NOTREACHED */
185 }
186 
187 void
188 user(db)
189 	DB *db;
190 {
191 	FILE *ifp;
192 	int argc, i, last;
193 	char *lbuf, *argv[4], buf[512];
194 
195 	if ((ifp = fopen("/dev/tty", "r")) == NULL) {
196 		(void)fprintf(stderr,
197 		    "/dev/tty: %s\n", strerror(errno));
198 		exit(1);
199 	}
200 	for (last = 0;;) {
201 		(void)printf("> ");
202 		(void)fflush(stdout);
203 		if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
204 			break;
205 		if (lbuf[0] == '\n') {
206 			i = last;
207 			goto uselast;
208 		}
209 		lbuf[strlen(lbuf) - 1] = '\0';
210 
211 		if (lbuf[0] == 'q')
212 			break;
213 
214 		argc = parse(lbuf, &argv[0], 3);
215 		if (argc == 0)
216 			continue;
217 
218 		for (i = 0; commands[i].cmd != NULL; i++)
219 			if (strncmp(commands[i].cmd, argv[0],
220 			    strlen(commands[i].cmd)) == 0)
221 				break;
222 
223 		if (commands[i].cmd == NULL) {
224 			(void)fprintf(stderr,
225 			    "%s: command unknown ('help' for help)\n", lbuf);
226 			continue;
227 		}
228 
229 		if (commands[i].nargs != argc - 1) {
230 			(void)fprintf(stderr, "usage: %s\n", commands[i].usage);
231 			continue;
232 		}
233 
234 		if (recno && commands[i].rconv) {
235 			static recno_t nlong;
236 			nlong = atoi(argv[1]);
237 			argv[1] = (char *)&nlong;
238 		}
239 uselast:	last = i;
240 		(*commands[i].func)(db, argv);
241 	}
242 	if ((db->sync)(db) == RET_ERROR)
243 		perror("dbsync");
244 	else if ((db->close)(db) == RET_ERROR)
245 		perror("dbclose");
246 }
247 
248 int
249 parse(lbuf, argv, maxargc)
250 	char *lbuf, **argv;
251 	int maxargc;
252 {
253 	int argc = 0;
254 	char *c;
255 
256 	c = lbuf;
257 	while (isspace(*c))
258 		c++;
259 	while (*c != '\0' && argc < maxargc) {
260 		*argv++ = c;
261 		argc++;
262 		while (!isspace(*c) && *c != '\0') {
263 			c++;
264 		}
265 		while (isspace(*c))
266 			*c++ = '\0';
267 	}
268 	return (argc);
269 }
270 
271 void
272 append(db, argv)
273 	DB *db;
274 	char **argv;
275 {
276 	DBT key, data;
277 	int status;
278 
279 	if (!recno) {
280 		(void)fprintf(stderr,
281 		    "append only available for recno db's.\n");
282 		return;
283 	}
284 	key.data = argv[1];
285 	key.size = sizeof(recno_t);
286 	data.data = argv[2];
287 	data.size = strlen(data.data);
288 	status = (db->put)(db, &key, &data, R_APPEND);
289 	switch (status) {
290 	case RET_ERROR:
291 		perror("append/put");
292 		break;
293 	case RET_SPECIAL:
294 		(void)printf("%s (duplicate key)\n", argv[1]);
295 		break;
296 	case RET_SUCCESS:
297 		break;
298 	}
299 }
300 
301 void
302 cursor(db, argv)
303 	DB *db;
304 	char **argv;
305 {
306 	DBT data, key;
307 	int status;
308 
309 	key.data = argv[1];
310 	if (recno)
311 		key.size = sizeof(recno_t);
312 	else
313 		key.size = strlen(argv[1]) + 1;
314 	status = (*db->seq)(db, &key, &data, R_CURSOR);
315 	switch (status) {
316 	case RET_ERROR:
317 		perror("cursor/seq");
318 		break;
319 	case RET_SPECIAL:
320 		(void)printf("key not found\n");
321 		break;
322 	case RET_SUCCESS:
323 		keydata(&key, &data);
324 		break;
325 	}
326 }
327 
328 void
329 delcur(db, argv)
330 	DB *db;
331 	char **argv;
332 {
333 	int status;
334 
335 	status = (*db->del)(db, NULL, R_CURSOR);
336 
337 	if (status == RET_ERROR)
338 		perror("delcur/del");
339 }
340 
341 void
342 delete(db, argv)
343 	DB *db;
344 	char **argv;
345 {
346 	DBT key;
347 	int status;
348 
349 	key.data = argv[1];
350 	if (recno)
351 		key.size = sizeof(recno_t);
352 	else
353 		key.size = strlen(argv[1]) + 1;
354 
355 	status = (*db->del)(db, &key, 0);
356 	switch (status) {
357 	case RET_ERROR:
358 		perror("delete/del");
359 		break;
360 	case RET_SPECIAL:
361 		(void)printf("key not found\n");
362 		break;
363 	case RET_SUCCESS:
364 		break;
365 	}
366 }
367 
368 void
369 dump(db, argv)
370 	DB *db;
371 	char **argv;
372 {
373 	__bt_dump(db);
374 }
375 
376 void
377 first(db, argv)
378 	DB *db;
379 	char **argv;
380 {
381 	DBT data, key;
382 	int status;
383 
384 	status = (*db->seq)(db, &key, &data, R_FIRST);
385 
386 	switch (status) {
387 	case RET_ERROR:
388 		perror("first/seq");
389 		break;
390 	case RET_SPECIAL:
391 		(void)printf("no more keys\n");
392 		break;
393 	case RET_SUCCESS:
394 		keydata(&key, &data);
395 		break;
396 	}
397 }
398 
399 void
400 get(db, argv)
401 	DB *db;
402 	char **argv;
403 {
404 	DBT data, key;
405 	int status;
406 
407 	key.data = argv[1];
408 	if (recno)
409 		key.size = sizeof(recno_t);
410 	else
411 		key.size = strlen(argv[1]) + 1;
412 
413 	status = (*db->get)(db, &key, &data, 0);
414 
415 	switch (status) {
416 	case RET_ERROR:
417 		perror("get/get");
418 		break;
419 	case RET_SPECIAL:
420 		(void)printf("key not found\n");
421 		break;
422 	case RET_SUCCESS:
423 		keydata(&key, &data);
424 		break;
425 	}
426 }
427 
428 void
429 help(db, argv)
430 	DB *db;
431 	char **argv;
432 {
433 	int i;
434 
435 	for (i = 0; commands[i].cmd; i++)
436 		if (commands[i].descrip)
437 			(void)printf("%s: %s\n",
438 			    commands[i].usage, commands[i].descrip);
439 }
440 
441 void
442 iafter(db, argv)
443 	DB *db;
444 	char **argv;
445 {
446 	DBT key, data;
447 	int status;
448 
449 	if (!recno) {
450 		(void)fprintf(stderr,
451 		    "iafter only available for recno db's.\n");
452 		return;
453 	}
454 	key.data = argv[1];
455 	key.size = sizeof(recno_t);
456 	data.data = argv[2];
457 	data.size = strlen(data.data);
458 	status = (db->put)(db, &key, &data, R_IAFTER);
459 	switch (status) {
460 	case RET_ERROR:
461 		perror("iafter/put");
462 		break;
463 	case RET_SPECIAL:
464 		(void)printf("%s (duplicate key)\n", argv[1]);
465 		break;
466 	case RET_SUCCESS:
467 		break;
468 	}
469 }
470 
471 void
472 ibefore(db, argv)
473 	DB *db;
474 	char **argv;
475 {
476 	DBT key, data;
477 	int status;
478 
479 	if (!recno) {
480 		(void)fprintf(stderr,
481 		    "ibefore only available for recno db's.\n");
482 		return;
483 	}
484 	key.data = argv[1];
485 	key.size = sizeof(recno_t);
486 	data.data = argv[2];
487 	data.size = strlen(data.data);
488 	status = (db->put)(db, &key, &data, R_IBEFORE);
489 	switch (status) {
490 	case RET_ERROR:
491 		perror("ibefore/put");
492 		break;
493 	case RET_SPECIAL:
494 		(void)printf("%s (duplicate key)\n", argv[1]);
495 		break;
496 	case RET_SUCCESS:
497 		break;
498 	}
499 }
500 
501 void
502 icursor(db, argv)
503 	DB *db;
504 	char **argv;
505 {
506 	int status;
507 	DBT data, key;
508 
509 	key.data = argv[1];
510 	if (recno)
511 		key.size = sizeof(recno_t);
512 	else
513 		key.size = strlen(argv[1]) + 1;
514 	data.data = argv[2];
515 	data.size = strlen(argv[2]) + 1;
516 
517 	status = (*db->put)(db, &key, &data, R_CURSOR);
518 	switch (status) {
519 	case RET_ERROR:
520 		perror("icursor/put");
521 		break;
522 	case RET_SPECIAL:
523 		(void)printf("%s (duplicate key)\n", argv[1]);
524 		break;
525 	case RET_SUCCESS:
526 		break;
527 	}
528 }
529 
530 void
531 insert(db, argv)
532 	DB *db;
533 	char **argv;
534 {
535 	int status;
536 	DBT data, key;
537 
538 	key.data = argv[1];
539 	if (recno)
540 		key.size = sizeof(recno_t);
541 	else
542 		key.size = strlen(argv[1]) + 1;
543 	data.data = argv[2];
544 	data.size = strlen(argv[2]) + 1;
545 
546 	status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
547 	switch (status) {
548 	case RET_ERROR:
549 		perror("insert/put");
550 		break;
551 	case RET_SPECIAL:
552 		(void)printf("%s (duplicate key)\n", argv[1]);
553 		break;
554 	case RET_SUCCESS:
555 		break;
556 	}
557 }
558 
559 void
560 last(db, argv)
561 	DB *db;
562 	char **argv;
563 {
564 	DBT data, key;
565 	int status;
566 
567 	status = (*db->seq)(db, &key, &data, R_LAST);
568 
569 	switch (status) {
570 	case RET_ERROR:
571 		perror("last/seq");
572 		break;
573 	case RET_SPECIAL:
574 		(void)printf("no more keys\n");
575 		break;
576 	case RET_SUCCESS:
577 		keydata(&key, &data);
578 		break;
579 	}
580 }
581 
582 void
583 list(db, argv)
584 	DB *db;
585 	char **argv;
586 {
587 	DBT data, key;
588 	FILE *fp;
589 	int status;
590 
591 	if ((fp = fopen(argv[1], "w")) == NULL) {
592 		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
593 		return;
594 	}
595 	status = (*db->seq)(db, &key, &data, R_FIRST);
596 	while (status == RET_SUCCESS) {
597 		(void)fprintf(fp, "%s\n", key.data);
598 		status = (*db->seq)(db, &key, &data, R_NEXT);
599 	}
600 	if (status == RET_ERROR)
601 		perror("list/seq");
602 }
603 
604 DB *BUGdb;
605 void
606 load(db, argv)
607 	DB *db;
608 	char **argv;
609 {
610 	register char *p, *t;
611 	FILE *fp;
612 	DBT data, key;
613 	recno_t cnt;
614 	size_t len;
615 	int status;
616 	char *lp, buf[16 * 1024];
617 
618 	BUGdb = db;
619 	if ((fp = fopen(argv[1], "r")) == NULL) {
620 		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
621 		return;
622 	}
623 	(void)printf("loading %s...\n", argv[1]);
624 
625 	for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
626 		if (recno) {
627 			key.data = &cnt;
628 			key.size = sizeof(recno_t);
629 			data.data = lp;
630 			data.size = len + 1;
631 		} else {
632 			key.data = lp;
633 			key.size = len + 1;
634 			for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
635 			*t = '\0';
636 			data.data = buf;
637 			data.size = len + 1;
638 		}
639 
640 		status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
641 		switch (status) {
642 		case RET_ERROR:
643 			perror("load/put");
644 			exit(1);
645 		case RET_SPECIAL:
646 			if (recno)
647 				(void)fprintf(stderr,
648 				    "duplicate: %ld {%s}\n", cnt, data.data);
649 			else
650 				(void)fprintf(stderr,
651 				    "duplicate: %ld {%s}\n", cnt, key.data);
652 			exit(1);
653 		case RET_SUCCESS:
654 			break;
655 		}
656 	}
657 	(void)fclose(fp);
658 }
659 
660 void
661 next(db, argv)
662 	DB *db;
663 	char **argv;
664 {
665 	DBT data, key;
666 	int status;
667 
668 	status = (*db->seq)(db, &key, &data, R_NEXT);
669 
670 	switch (status) {
671 	case RET_ERROR:
672 		perror("next/seq");
673 		break;
674 	case RET_SPECIAL:
675 		(void)printf("no more keys\n");
676 		break;
677 	case RET_SUCCESS:
678 		keydata(&key, &data);
679 		break;
680 	}
681 }
682 
683 void
684 previous(db, argv)
685 	DB *db;
686 	char **argv;
687 {
688 	DBT data, key;
689 	int status;
690 
691 	status = (*db->seq)(db, &key, &data, R_PREV);
692 
693 	switch (status) {
694 	case RET_ERROR:
695 		perror("previous/seq");
696 		break;
697 	case RET_SPECIAL:
698 		(void)printf("no more keys\n");
699 		break;
700 	case RET_SUCCESS:
701 		keydata(&key, &data);
702 		break;
703 	}
704 }
705 
706 void
707 show(db, argv)
708 	DB *db;
709 	char **argv;
710 {
711 	BTREE *t;
712 	PAGE *h;
713 	pgno_t pg;
714 
715 	pg = atoi(argv[1]);
716 	t = db->internal;
717 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
718 		(void)printf("getpage of %ld failed\n", pg);
719 		return;
720 	}
721 	if (pg == 0)
722 		__bt_dmpage(h);
723 	else
724 		__bt_dpage(h);
725 	mpool_put(t->bt_mp, h, 0);
726 }
727 
728 void
729 bstat(db, argv)
730 	DB *db;
731 	char **argv;
732 {
733 	(void)printf("BTREE\n");
734 	__bt_stat(db);
735 }
736 
737 void
738 mstat(db, argv)
739 	DB *db;
740 	char **argv;
741 {
742 	(void)printf("MPOOL\n");
743 	mpool_stat(((BTREE *)db->internal)->bt_mp);
744 }
745 
746 void
747 keydata(key, data)
748 	DBT *key, *data;
749 {
750 	if (!recno && key->size > 0)
751 		(void)printf("%s/", key->data);
752 	if (data->size > 0)
753 		(void)printf("%s", data->data);
754 	(void)printf("\n");
755 }
756 
757 void
758 usage()
759 {
760 	(void)fprintf(stderr,
761 	    "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
762 	    progname);
763 	exit (1);
764 }
765