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 * $FreeBSD: head/lib/libc/db/test/btree.tests/main.c 176380 2008-02-18 03:19:25Z kevlo $
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
main(int argc,char ** argv)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
user(DB * db)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
parse(char * lbuf,char ** argv,int maxargc)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
append(DB * db,char ** argv)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
cursor(DB * db,char ** argv)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
delcur(DB * db,char ** argv)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
delete(DB * db,char ** argv)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
dump(DB * db,char ** argv)352 dump(DB *db, char **argv)
353 {
354 __bt_dump(db);
355 }
356
357 void
first(DB * db,char ** argv)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
get(DB * db,char ** argv)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
help(DB * db,char ** argv)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
iafter(DB * db,char ** argv)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
ibefore(DB * db,char ** argv)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
icursor(DB * db,char ** argv)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
insert(DB * db,char ** argv)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
last(DB * db,char ** argv)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
list(DB * db,char ** argv)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 fclose(fp);
567 }
568
569 DB *BUGdb;
570 void
load(DB * db,char ** argv)571 load(DB *db, char **argv)
572 {
573 char *p, *t;
574 FILE *fp;
575 DBT data, key;
576 recno_t cnt;
577 size_t len;
578 int status;
579 char *lp, buf[16 * 1024];
580
581 BUGdb = db;
582 if ((fp = fopen(argv[1], "r")) == NULL) {
583 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
584 return;
585 }
586 printf("loading %s...\n", argv[1]);
587
588 for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
589 if (recno) {
590 key.data = &cnt;
591 key.size = sizeof(recno_t);
592 data.data = lp;
593 data.size = len + 1;
594 } else {
595 key.data = lp;
596 key.size = len + 1;
597 for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
598 *t = '\0';
599 data.data = buf;
600 data.size = len + 1;
601 }
602
603 status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
604 switch (status) {
605 case RET_ERROR:
606 perror("load/put");
607 exit(1);
608 case RET_SPECIAL:
609 if (recno)
610 fprintf(stderr,
611 "duplicate: %ld {%s}\n", cnt, data.data);
612 else
613 fprintf(stderr,
614 "duplicate: %ld {%s}\n", cnt, key.data);
615 exit(1);
616 case RET_SUCCESS:
617 break;
618 }
619 }
620 fclose(fp);
621 }
622
623 void
next(DB * db,char ** argv)624 next(DB *db, char **argv)
625 {
626 DBT data, key;
627 int status;
628
629 status = (*db->seq)(db, &key, &data, R_NEXT);
630
631 switch (status) {
632 case RET_ERROR:
633 perror("next/seq");
634 break;
635 case RET_SPECIAL:
636 printf("no more keys\n");
637 break;
638 case RET_SUCCESS:
639 keydata(&key, &data);
640 break;
641 }
642 }
643
644 void
previous(DB * db,char ** argv)645 previous(DB *db, char **argv)
646 {
647 DBT data, key;
648 int status;
649
650 status = (*db->seq)(db, &key, &data, R_PREV);
651
652 switch (status) {
653 case RET_ERROR:
654 perror("previous/seq");
655 break;
656 case RET_SPECIAL:
657 printf("no more keys\n");
658 break;
659 case RET_SUCCESS:
660 keydata(&key, &data);
661 break;
662 }
663 }
664
665 void
show(DB * db,char ** argv)666 show(DB *db, char **argv)
667 {
668 BTREE *t;
669 PAGE *h;
670 pgno_t pg;
671
672 pg = atoi(argv[1]);
673 t = db->internal;
674 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
675 printf("getpage of %ld failed\n", pg);
676 return;
677 }
678 if (pg == 0)
679 __bt_dmpage(h);
680 else
681 __bt_dpage(h);
682 mpool_put(t->bt_mp, h, 0);
683 }
684
685 void
bstat(DB * db,char ** argv)686 bstat(DB *db, char **argv)
687 {
688 printf("BTREE\n");
689 __bt_stat(db);
690 }
691
692 void
mstat(DB * db,char ** argv)693 mstat(DB *db, char **argv)
694 {
695 printf("MPOOL\n");
696 mpool_stat(((BTREE *)db->internal)->bt_mp);
697 }
698
699 void
keydata(DBT * key,DBT * data)700 keydata(DBT *key, DBT *data)
701 {
702 if (!recno && key->size > 0)
703 printf("%s/", key->data);
704 if (data->size > 0)
705 printf("%s", data->data);
706 printf("\n");
707 }
708
709 void
usage(void)710 usage(void)
711 {
712 fprintf(stderr,
713 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
714 progname);
715 exit (1);
716 }
717