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