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