xref: /dragonfly/lib/libc/db/test/btree.tests/main.c (revision f746689a)
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.8 2008/07/10 18:29:51 swildner 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(int argc, char **argv)
115 {
116 	int c;
117 	DB *db;
118 	BTREEINFO b;
119 
120 	progname = *argv;
121 
122 	b.flags = 0;
123 	b.cachesize = 0;
124 	b.maxkeypage = 0;
125 	b.minkeypage = 0;
126 	b.psize = 0;
127 	b.compare = NULL;
128 	b.prefix = NULL;
129 	b.lorder = 0;
130 
131 	while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) {
132 		switch (c) {
133 		case 'b':
134 			b.lorder = BIG_ENDIAN;
135 			break;
136 		case 'c':
137 			b.cachesize = atoi(optarg);
138 			break;
139 		case 'd':
140 			b.flags |= R_DUP;
141 			break;
142 		case 'i':
143 			dict = optarg;
144 			break;
145 		case 'l':
146 			b.lorder = LITTLE_ENDIAN;
147 			break;
148 		case 'p':
149 			b.psize = atoi(optarg);
150 			break;
151 		case 'r':
152 			recno = 1;
153 			break;
154 		case 'u':
155 			b.flags = 0;
156 			break;
157 		default:
158 			usage();
159 		}
160 	}
161 	argc -= optind;
162 	argv += optind;
163 
164 	if (recno)
165 		db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
166 		    0, DB_RECNO, NULL);
167 	else
168 		db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
169 		    0600, DB_BTREE, &b);
170 
171 	if (db == NULL) {
172 		fprintf(stderr, "dbopen: %s\n", strerror(errno));
173 		exit(1);
174 	}
175 	globaldb = db;
176 	user(db);
177 	exit(0);
178 	/* NOTREACHED */
179 }
180 
181 void
182 user(DB *db)
183 {
184 	FILE *ifp;
185 	int argc, i, last;
186 	char *lbuf, *argv[4], buf[512];
187 
188 	if ((ifp = fopen("/dev/tty", "r")) == NULL) {
189 		fprintf(stderr,
190 		    "/dev/tty: %s\n", strerror(errno));
191 		exit(1);
192 	}
193 	for (last = 0;;) {
194 		printf("> ");
195 		fflush(stdout);
196 		if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
197 			break;
198 		if (lbuf[0] == '\n') {
199 			i = last;
200 			goto uselast;
201 		}
202 		lbuf[strlen(lbuf) - 1] = '\0';
203 
204 		if (lbuf[0] == 'q')
205 			break;
206 
207 		argc = parse(lbuf, &argv[0], 3);
208 		if (argc == 0)
209 			continue;
210 
211 		for (i = 0; commands[i].cmd != NULL; i++)
212 			if (strncmp(commands[i].cmd, argv[0],
213 			    strlen(commands[i].cmd)) == 0)
214 				break;
215 
216 		if (commands[i].cmd == NULL) {
217 			fprintf(stderr,
218 			    "%s: command unknown ('help' for help)\n", lbuf);
219 			continue;
220 		}
221 
222 		if (commands[i].nargs != argc - 1) {
223 			fprintf(stderr, "usage: %s\n", commands[i].usage);
224 			continue;
225 		}
226 
227 		if (recno && commands[i].rconv) {
228 			static recno_t nlong;
229 			nlong = atoi(argv[1]);
230 			argv[1] = (char *)&nlong;
231 		}
232 uselast:	last = i;
233 		(*commands[i].func)(db, argv);
234 	}
235 	if ((db->sync)(db) == RET_ERROR)
236 		perror("dbsync");
237 	else if ((db->close)(db) == RET_ERROR)
238 		perror("dbclose");
239 }
240 
241 int
242 parse(char *lbuf, char **argv, int maxargc)
243 {
244 	int argc = 0;
245 	char *c;
246 
247 	c = lbuf;
248 	while (isspace(*c))
249 		c++;
250 	while (*c != '\0' && argc < maxargc) {
251 		*argv++ = c;
252 		argc++;
253 		while (!isspace(*c) && *c != '\0') {
254 			c++;
255 		}
256 		while (isspace(*c))
257 			*c++ = '\0';
258 	}
259 	return (argc);
260 }
261 
262 void
263 append(DB *db, char **argv)
264 {
265 	DBT key, data;
266 	int status;
267 
268 	if (!recno) {
269 		fprintf(stderr,
270 		    "append only available for recno db's.\n");
271 		return;
272 	}
273 	key.data = argv[1];
274 	key.size = sizeof(recno_t);
275 	data.data = argv[2];
276 	data.size = strlen(data.data);
277 	status = (db->put)(db, &key, &data, R_APPEND);
278 	switch (status) {
279 	case RET_ERROR:
280 		perror("append/put");
281 		break;
282 	case RET_SPECIAL:
283 		printf("%s (duplicate key)\n", argv[1]);
284 		break;
285 	case RET_SUCCESS:
286 		break;
287 	}
288 }
289 
290 void
291 cursor(DB *db, char **argv)
292 {
293 	DBT data, key;
294 	int status;
295 
296 	key.data = argv[1];
297 	if (recno)
298 		key.size = sizeof(recno_t);
299 	else
300 		key.size = strlen(argv[1]) + 1;
301 	status = (*db->seq)(db, &key, &data, R_CURSOR);
302 	switch (status) {
303 	case RET_ERROR:
304 		perror("cursor/seq");
305 		break;
306 	case RET_SPECIAL:
307 		printf("key not found\n");
308 		break;
309 	case RET_SUCCESS:
310 		keydata(&key, &data);
311 		break;
312 	}
313 }
314 
315 void
316 delcur(DB *db, char **argv)
317 {
318 	int status;
319 
320 	status = (*db->del)(db, NULL, R_CURSOR);
321 
322 	if (status == RET_ERROR)
323 		perror("delcur/del");
324 }
325 
326 void
327 delete(DB *db, char **argv)
328 {
329 	DBT key;
330 	int status;
331 
332 	key.data = argv[1];
333 	if (recno)
334 		key.size = sizeof(recno_t);
335 	else
336 		key.size = strlen(argv[1]) + 1;
337 
338 	status = (*db->del)(db, &key, 0);
339 	switch (status) {
340 	case RET_ERROR:
341 		perror("delete/del");
342 		break;
343 	case RET_SPECIAL:
344 		printf("key not found\n");
345 		break;
346 	case RET_SUCCESS:
347 		break;
348 	}
349 }
350 
351 void
352 dump(DB *db, char **argv)
353 {
354 	__bt_dump(db);
355 }
356 
357 void
358 first(DB *db, char **argv)
359 {
360 	DBT data, key;
361 	int status;
362 
363 	status = (*db->seq)(db, &key, &data, R_FIRST);
364 
365 	switch (status) {
366 	case RET_ERROR:
367 		perror("first/seq");
368 		break;
369 	case RET_SPECIAL:
370 		printf("no more keys\n");
371 		break;
372 	case RET_SUCCESS:
373 		keydata(&key, &data);
374 		break;
375 	}
376 }
377 
378 void
379 get(DB *db, char **argv)
380 {
381 	DBT data, key;
382 	int status;
383 
384 	key.data = argv[1];
385 	if (recno)
386 		key.size = sizeof(recno_t);
387 	else
388 		key.size = strlen(argv[1]) + 1;
389 
390 	status = (*db->get)(db, &key, &data, 0);
391 
392 	switch (status) {
393 	case RET_ERROR:
394 		perror("get/get");
395 		break;
396 	case RET_SPECIAL:
397 		printf("key not found\n");
398 		break;
399 	case RET_SUCCESS:
400 		keydata(&key, &data);
401 		break;
402 	}
403 }
404 
405 void
406 help(DB *db, char **argv)
407 {
408 	int i;
409 
410 	for (i = 0; commands[i].cmd; i++)
411 		if (commands[i].descrip)
412 			printf("%s: %s\n",
413 			    commands[i].usage, commands[i].descrip);
414 }
415 
416 void
417 iafter(DB *db, char **argv)
418 {
419 	DBT key, data;
420 	int status;
421 
422 	if (!recno) {
423 		fprintf(stderr,
424 		    "iafter only available for recno db's.\n");
425 		return;
426 	}
427 	key.data = argv[1];
428 	key.size = sizeof(recno_t);
429 	data.data = argv[2];
430 	data.size = strlen(data.data);
431 	status = (db->put)(db, &key, &data, R_IAFTER);
432 	switch (status) {
433 	case RET_ERROR:
434 		perror("iafter/put");
435 		break;
436 	case RET_SPECIAL:
437 		printf("%s (duplicate key)\n", argv[1]);
438 		break;
439 	case RET_SUCCESS:
440 		break;
441 	}
442 }
443 
444 void
445 ibefore(DB *db, char **argv)
446 {
447 	DBT key, data;
448 	int status;
449 
450 	if (!recno) {
451 		fprintf(stderr,
452 		    "ibefore only available for recno db's.\n");
453 		return;
454 	}
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_IBEFORE);
460 	switch (status) {
461 	case RET_ERROR:
462 		perror("ibefore/put");
463 		break;
464 	case RET_SPECIAL:
465 		printf("%s (duplicate key)\n", argv[1]);
466 		break;
467 	case RET_SUCCESS:
468 		break;
469 	}
470 }
471 
472 void
473 icursor(DB *db, char **argv)
474 {
475 	int status;
476 	DBT data, key;
477 
478 	key.data = argv[1];
479 	if (recno)
480 		key.size = sizeof(recno_t);
481 	else
482 		key.size = strlen(argv[1]) + 1;
483 	data.data = argv[2];
484 	data.size = strlen(argv[2]) + 1;
485 
486 	status = (*db->put)(db, &key, &data, R_CURSOR);
487 	switch (status) {
488 	case RET_ERROR:
489 		perror("icursor/put");
490 		break;
491 	case RET_SPECIAL:
492 		printf("%s (duplicate key)\n", argv[1]);
493 		break;
494 	case RET_SUCCESS:
495 		break;
496 	}
497 }
498 
499 void
500 insert(DB *db, 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_NOOVERWRITE);
514 	switch (status) {
515 	case RET_ERROR:
516 		perror("insert/put");
517 		break;
518 	case RET_SPECIAL:
519 		printf("%s (duplicate key)\n", argv[1]);
520 		break;
521 	case RET_SUCCESS:
522 		break;
523 	}
524 }
525 
526 void
527 last(DB *db, char **argv)
528 {
529 	DBT data, key;
530 	int status;
531 
532 	status = (*db->seq)(db, &key, &data, R_LAST);
533 
534 	switch (status) {
535 	case RET_ERROR:
536 		perror("last/seq");
537 		break;
538 	case RET_SPECIAL:
539 		printf("no more keys\n");
540 		break;
541 	case RET_SUCCESS:
542 		keydata(&key, &data);
543 		break;
544 	}
545 }
546 
547 void
548 list(DB *db, char **argv)
549 {
550 	DBT data, key;
551 	FILE *fp;
552 	int status;
553 
554 	if ((fp = fopen(argv[1], "w")) == NULL) {
555 		fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
556 		return;
557 	}
558 	status = (*db->seq)(db, &key, &data, R_FIRST);
559 	while (status == RET_SUCCESS) {
560 		fprintf(fp, "%s\n", key.data);
561 		status = (*db->seq)(db, &key, &data, R_NEXT);
562 	}
563 	if (status == RET_ERROR)
564 		perror("list/seq");
565 }
566 
567 DB *BUGdb;
568 void
569 load(DB *db, char **argv)
570 {
571 	char *p, *t;
572 	FILE *fp;
573 	DBT data, key;
574 	recno_t cnt;
575 	size_t len;
576 	int status;
577 	char *lp, buf[16 * 1024];
578 
579 	BUGdb = db;
580 	if ((fp = fopen(argv[1], "r")) == NULL) {
581 		fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
582 		return;
583 	}
584 	printf("loading %s...\n", argv[1]);
585 
586 	for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
587 		if (recno) {
588 			key.data = &cnt;
589 			key.size = sizeof(recno_t);
590 			data.data = lp;
591 			data.size = len + 1;
592 		} else {
593 			key.data = lp;
594 			key.size = len + 1;
595 			for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
596 			*t = '\0';
597 			data.data = buf;
598 			data.size = len + 1;
599 		}
600 
601 		status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
602 		switch (status) {
603 		case RET_ERROR:
604 			perror("load/put");
605 			exit(1);
606 		case RET_SPECIAL:
607 			if (recno)
608 				fprintf(stderr,
609 				    "duplicate: %ld {%s}\n", cnt, data.data);
610 			else
611 				fprintf(stderr,
612 				    "duplicate: %ld {%s}\n", cnt, key.data);
613 			exit(1);
614 		case RET_SUCCESS:
615 			break;
616 		}
617 	}
618 	fclose(fp);
619 }
620 
621 void
622 next(DB *db, char **argv)
623 {
624 	DBT data, key;
625 	int status;
626 
627 	status = (*db->seq)(db, &key, &data, R_NEXT);
628 
629 	switch (status) {
630 	case RET_ERROR:
631 		perror("next/seq");
632 		break;
633 	case RET_SPECIAL:
634 		printf("no more keys\n");
635 		break;
636 	case RET_SUCCESS:
637 		keydata(&key, &data);
638 		break;
639 	}
640 }
641 
642 void
643 previous(DB *db, char **argv)
644 {
645 	DBT data, key;
646 	int status;
647 
648 	status = (*db->seq)(db, &key, &data, R_PREV);
649 
650 	switch (status) {
651 	case RET_ERROR:
652 		perror("previous/seq");
653 		break;
654 	case RET_SPECIAL:
655 		printf("no more keys\n");
656 		break;
657 	case RET_SUCCESS:
658 		keydata(&key, &data);
659 		break;
660 	}
661 }
662 
663 void
664 show(DB *db, char **argv)
665 {
666 	BTREE *t;
667 	PAGE *h;
668 	pgno_t pg;
669 
670 	pg = atoi(argv[1]);
671 	t = db->internal;
672 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
673 		printf("getpage of %ld failed\n", pg);
674 		return;
675 	}
676 	if (pg == 0)
677 		__bt_dmpage(h);
678 	else
679 		__bt_dpage(h);
680 	mpool_put(t->bt_mp, h, 0);
681 }
682 
683 void
684 bstat(DB *db, char **argv)
685 {
686 	printf("BTREE\n");
687 	__bt_stat(db);
688 }
689 
690 void
691 mstat(DB *db, char **argv)
692 {
693 	printf("MPOOL\n");
694 	mpool_stat(((BTREE *)db->internal)->bt_mp);
695 }
696 
697 void
698 keydata(DBT *key, DBT *data)
699 {
700 	if (!recno && key->size > 0)
701 		printf("%s/", key->data);
702 	if (data->size > 0)
703 		printf("%s", data->data);
704 	printf("\n");
705 }
706 
707 void
708 usage(void)
709 {
710 	fprintf(stderr,
711 	    "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
712 	    progname);
713 	exit (1);
714 }
715