-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspex-ja.html
4348 lines (3198 loc) · 330 KB
/
spex-ja.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="author" content="Mikio Hirabayashi" />
<meta name="keywords" content="QDBM, DBM, database, hash, B+ tree" />
<meta name="description" content="fundamental specifications of QDBM" />
<link rel="contents" href="./" />
<link rel="alternate" href="spex.html" hreflang="en" title="the English version" />
<link rev="made" href="mailto:[email protected]" />
<title>Specifications of QDBM Version 1 (Japanese)</title>
<style type="text/css">html { margin: 0em 0em; padding: 0em 0em; background: #eeeeee none; }
body { margin: 2em 2em; padding: 0em 0em;
background: #eeeeee none; color: #111111;
font-style: normal; font-weight: normal; }
h1 { margin-top: 1.8em; margin-bottom: 1.3em; font-weight: bold; }
h2 { margin-top: 1.8em; margin-bottom: 1.1em; font-weight: bold;
border-left: solid 0.6em #445555; border-bottom: solid 1pt #bbbbbb;
padding: 0.5em 0.5em; width: 60%; }
h3 { margin-top: 1.8em; margin-bottom: 0.8em; font-weight: bold; }
hr { margin-top: 2.5em; margin-bottom: 1.5em; height: 1pt;
color: #999999; background-color: #999999; border: none; }
div.note,div.navi { text-align: right; }
div.logo { text-align: center; margin: 3em 0em; }
div.logo img { border: inset 2pt #ccccdd; }
p { margin: 0.8em 0em; line-height: 140%; }
p,dd { text-indent: 0.8em; }
div,pre { margin-left: 1.7em; margin-right: 1.7em; }
pre { background-color: #ddddee; padding: 0.2em; border: 1pt solid #bbbbcc; font-size: smaller; }
kbd { color: #111111; font-style: normal; font-weight: bold; }
a { color: #0022aa; text-decoration: none; }
a:hover,a:focus { color: #0033ee; text-decoration: underline; }
a.head { color: #111111; text-decoration: none; }
table { padding: 1pt 2pt 1pt 2pt; border: none; margin-left: 1.7em; border-collapse: collapse; }
th { padding: 1pt 4pt 1pt 4pt; border-style: none;
text-align: left; vertical-align: bottom; }
td { padding: 1pt 4pt 1pt 4pt; border: 1pt solid #333333;
text-align: left; vertical-align: top; }
ul,ol,dl { line-height: 140%; }
dt { margin-left: 1.2em; }
dd { margin-left: 2.0em; }
ul.lines { list-style-type: none; }
@media print {
html,body { margin: 0em 0em; background-color: #ffffff; color: #000000; }
h1 { padding: 8em 0em 0.5em 0em; text-align: center; }
h2 { page-break-before: always; }
div.note { text-align: center; }
div.navi,div.logo { display: none }
hr { display: none; }
pre { margin: 0.8em 0.8em; background-color: #ffffff;
border: 1pt solid #aaaaaa; font-size: smaller; }
a,kbd { color: #000000; text-decoration: none; }
h1,h2,h3 { font-family: sans-serif; }
p,div,li,dt,dd { font-family: serif; }
pre,kbd { font-family: monospace; }
dd { font-size: smaller; }
}
</style>
</head>
<body>
<h1>QDBMバージョン1基本仕様書</h1>
<div class="note">Copyright (C) 2000-2007 Mikio Hirabayashi</div>
<div class="note">Last Update: Thu, 26 Oct 2006 15:00:20 +0900</div>
<div class="navi">[<a href="spex.html" hreflang="en">English</a>] [<a href="http://qdbm.sourceforge.net/">Home</a>]</div>
<hr />
<h2>目次</h2>
<ol>
<li><a href="#overview">概要</a></li>
<li><a href="#features">特徴</a></li>
<li><a href="#installation">インストール</a></li>
<li><a href="#depotapi">Depot: 基本API</a></li>
<li><a href="#depotcli">Depot用コマンド</a></li>
<li><a href="#curiaapi">Curia: 拡張API</a></li>
<li><a href="#curiacli">Curia用コマンド</a></li>
<li><a href="#relicapi">Relic: NDBM互換API</a></li>
<li><a href="#reliccli">Relic用コマンド</a></li>
<li><a href="#hovelapi">Hovel: GDBM互換API</a></li>
<li><a href="#hovelcli">Hovel用コマンド</a></li>
<li><a href="#cabinapi">Cabin: ユーティリティAPI</a></li>
<li><a href="#cabincli">Cabin用コマンド</a></li>
<li><a href="#villaapi">Villa: 上級API</a></li>
<li><a href="#villacli">Villa用コマンド</a></li>
<li><a href="#odeumapi">Odeum: 転置API</a></li>
<li><a href="#odeumcli">Odeum用コマンド</a></li>
<li><a href="#fileformat">ファイルフォーマット</a></li>
<li><a href="#porting">移植方法</a></li>
<li><a href="#bugs">バグ</a></li>
<li><a href="#faq">よく聞かれる質問</a></li>
<li><a href="#copying">ライセンス</a></li>
</ol>
<hr />
<h2><a name="overview" id="overview" class="head">概要</a></h2>
<p>QDBMはデータベースを扱うルーチン群のライブラリである。データベースといっても単純なものであり、キーと値のペアからなるレコード群を格納したデータファイルである。キーと値は任意の長さを持つ一連のバイト列であり、文字列でもバイナリでも扱うことができる。テーブルやデータ型の概念はない。レコードはハッシュ表またはB+木で編成される。</p>
<p>ハッシュ表のデータベースでは、キーはデータベース内で一意であり、キーが重複する複数のレコードを格納することはできない。このデータベースに対しては、キーと値を指定してレコードを格納したり、キーを指定して対応するレコードを削除したり、キーを指定して対応するレコードを検索したりすることができる。また、データベースに格納してある全てのキーを順不同に一つずつ取り出すこともできる。このような操作は、UNIX標準で定義されているDBMライブラリおよびその追従であるNDBMやGDBMに類するものである。QDBMはDBMのより良い代替として利用することができる。</p>
<p>B+木のデータベースでは、キーが重複する複数のレコードを格納することができる。このデータベースに対しては、ハッシュ表のデータベースと同様に、キーを指定してレコードを格納したり取り出したり削除したりすることができる。レコードはユーザが指示した比較関数に基づいて整列されて格納される。カーソルを用いて各レコードを昇順または降順で参照することができる。この機構によって、文字列の前方一致検索や数値の範囲検索が可能になる。また、B+木のデータベースではトランザクションが利用できる。</p>
<p>QDBMはCで記述され、C、C++、Java、PerlおよびRubyのAPIとして提供される。QDBMはPOSIX準拠のAPIを備えるプラットフォームで利用できる。QDBMはGNU Lesser General Public Licenseに基づくフリーソフトウェアである。</p>
<hr />
<h2><a name="features" id="features" class="head">特徴</a></h2>
<h3>効率的なハッシュデータベースの実装</h3>
<p>QDBMはGDBMを参考に次の三点を目標として開発された。処理がより高速であること、データベースファイルがより小さいこと、APIがより単純であること。これらの目標は達成されている。また、GDBMと同様に、伝統的なDBMが抱える三つの制限事項を回避している。すなわち、プロセス内で複数のデータベースを扱うことができ、キーと値のサイズに制限がなく、データベースファイルがスパースではない。</p>
<p>QDBMはレコードの探索にハッシュアルゴリズムを用いる。バケット配列に十分な要素数があれば、レコードの探索にかかる時間計算量は O(1) である。すなわち、レコードの探索に必要な時間はデータベースの規模に関わらず一定である。追加や削除に関しても同様である。ハッシュ値の衝突はセパレートチェーン法で管理する。チェーンのデータ構造は二分探索木である。バケット配列の要素数が著しく少ない場合でも、探索等の時間計算量は O(log n) に抑えられる。</p>
<p>QDBMはバケット配列を全てRAM上に保持することによって、処理の高速化を図る。バケット配列がRAM上にあれば、ほぼ1パスのファイル操作でレコードに該当するファイル上の領域を参照することができる。ファイルに記録されたバケット配列は `read' コールでRAM上に読み込むのではなく、`mmap' コールでRAMに直接マッピングされる。したがって、データベースに接続する際の準備時間が極めて短く、また、複数のプロセスでメモリマップを共有することができる。</p>
<p>バケット配列の要素数が格納するレコード数の半分ほどであれば、データの性質によって多少前後するが、ハッシュ値の衝突率は56.7%ほどである(等倍だと36.8%、2倍だと21.3%、4倍だと11.5%、8倍だと6.0%ほど)。そのような場合、平均2パス以下のファイル操作でレコードを探索することができる。これを性能指標とするならば、例えば100万個のレコードを格納するためには50万要素のバケット配列が求められる。バケット配列の各要素は4バイトである。すなわち、2MバイトのRAMが利用できれば100万レコードのデータベースが構築できる。</p>
<p>QDBMにはデータベースに接続するモードとして、「リーダ」と「ライタ」の二種類がある。リーダは読み込み専用であり、ライタは読み書き両用である。データベースにはファイルロックによってプロセス間での排他制御が行われる。ライタが接続している間は、他のプロセスはリーダとしてもライタとしても接続できない。リーダが接続している間は、他のプロセスのリーダは接続できるが、ライタは接続できない。この機構によって、マルチタスク環境での同時接続に伴うデータの整合性が保証される。</p>
<p>伝統的なDBMにはレコードの追加操作に関して「挿入」モードと「置換」モードがある。前者では、キーが既存のレコードと重複する際に既存の値を残す。後者では、キーが既存のレコードと重複した際に新しい値に置き換える。QDBMはその2つに加えて「連結」モードがある。既存の値の末尾に指定された値を連結して格納する操作である。レコードの値を配列として扱う場合、要素を追加するには連結モードが役に立つ。また、DBMではレコードの値を取り出す際にはその全ての領域を処理対象にするしか方法がないが、QDBMでは値の領域の一部のみを選択して取り出すことができる。レコードの値を配列として扱う場合にはこの機能も役に立つ。</p>
<p>一般的に、データベースの更新処理を続けるとファイル内の利用可能領域の断片化が起き、ファイルのサイズが肥大化してしまう。QDBMは隣接する不要領域を連結して再利用し、またデータベースの最適化機能を備えることによってこの問題に対処する。既存のレコードの値をより大きなサイズの値に上書きする場合、そのレコードの領域をファイル中の別の位置に移動させる必要がある。この処理の時間計算量はレコードのサイズに依存するので、値を拡張していく場合には効率が悪い。しかし、QDBMはアラインメントによってこの問題に対処する。増分がパディングに収まれば領域を移動させる必要はない。</p>
<p>多くのファイルシステムでは、2GBを越えるサイズのファイルを扱うことができない。この問題に対処するために、QDBMは複数のデータベースファイルを含むディレクトリからなるデータベースを扱う機能を提供する。レコードをどのファイルに格納するかはキーに別のハッシュ関数を適用することによって決められる。この機能によって、理論的にはレコードの合計サイズが1TBまでのデータベースを構築することができる。また、データベースファイルを複数のディスクに振り分けることができるため、RAID-0(ストライピング)に見られるような更新操作の高速化が期待できる。NFS等を利用すれば複数のファイルサーバにデータベースを分散させることもできる。</p>
<h3>便利なB+木データベースの実装</h3>
<p>B+木データベースはハッシュデータベースより遅いが、ユーザが定義した順序に基づいて各レコードを参照できることが特長である。B+木は複数のレコードを整列させた状態で論理的なページにまとめて管理する。各ページに対してはB木すなわち多進平衡木によって階層化された疎インデックスが維持される。したがって、各レコードの探索等にかかる時間計算量は O(log n) である。各レコードを順番に参照するためにカーソルが提供される。カーソルの場所はキーを指定して飛ばすことができ、また現在の場所から次のレコードに進めたり前のレコードに戻したりすることができる。各ページは双方向リンクリストで編成されるので、カーソルを前後に移動させる時間計算量は O(1) である。</p>
<p>B+木データベースは上述のハッシュデータベースを基盤として実装される。B+木の各ページはハッシュデータベースのレコードとして記録されるので、ハッシュデータベースの記憶管理の効率性を継承している。B+木では各レコードのヘッダが小さく、各ページのアラインメントはページサイズに応じて調整されるので、ほとんどの場合、ハッシュデータベースに較べてデータベースファイルのサイズが半減する。B+木を更新する際には多くのページを操作する必要があるが、QDBMはページをキャッシュすることによってファイル操作を減らして処理を効率化する。ほとんどの場合、疎インデックス全体がメモリ上にキャッシュされるので、各レコードを参照するのに必要なファイル操作は平均1パス以下である。</p>
<p>B+木データベースはトランザクション機構を提供する。トランザクションを開始してから終了するまでの一連の操作を一括してデータベースにコミットしたり、一連の更新操作を破棄してデータベースの状態をトランザクションの開始前の状態にロールバックしたりすることができる。トランザクションの間にアプリケーションのプロセスがクラッシュしてもデータベースファイルは破壊されない。</p>
<p>可逆データ圧縮ライブラリであるZLIBかLZOかBZIP2を有効化してQDBMをビルドすると、B+木の各ページの内容は圧縮されてファイルに書き込まれる。同一ページ内の各レコードは似たようなパターンを持つため、Lempel-Zivなどのアルゴリズムを適用すると高い圧縮効率が期待できる。テキストデータを扱う場合、データベースのサイズが元の25%程度になる。データベースの規模が大きくディスクI/Oがボトルネックとなる場合は、圧縮機能を有効化すると処理速度が大幅に改善される。</p>
<h3>単純だが多様なインタフェース群</h3>
<p>QDBMのAPIは非常に単純である。ANSI Cで定義された `FILE' ポインタを用いた通常のファイル入出力と同じようにデータベースファイルに対する入出力を行うことができる。QDBMの基本APIでは、データベースの実体は単一のファイルに記録される。拡張APIでは、データベースの実体は単一のディレクトリに含まれる複数のファイルに記録される。二つのAPIは互いに酷似しているので、アプリケーションを一方から他方に移植することはたやすい。</p>
<p>NDBMおよびGDBMに互換するAPIも提供される。NDBMやGDBMのアプリケーションは市場に数多く存在するが、それらをQDBMに移植するのはたやすい。ほとんどの場合、ヘッダファイルの取り込み(#include)を書き換えてコンパイルしなおせばよい。ただし、オリジナルのNDBMやGDBMで作成したデータベースファイルをQDBMで扱うことはできない。</p>
<p>メモリ上でレコードを簡単に扱うために、ユーティリティAPIが提供される。メモリ確保関数とソート関数と拡張可能なデータと配列リストとハッシュマップ等の実装である。それらを用いると、C言語でもPerlやRuby等のスクリプト言語のような手軽さでレコードを扱うことができる。</p>
<p>B+木データベースは上級APIを介して利用する。上級APIは基本APIとユーティリティAPIを利用して実装される。上級APIも基本APIや拡張APIに類似した書式を持つので、使い方を覚えるのは容易である。</p>
<p>全文検索システムで利用される転置インデックスを扱うために、転置APIが提供される。文書群の転置インデックスを容易に扱うことができれば、アプリケーションはテキスト処理や自然言語処理に注力できる。このAPIは文字コードや言語に依存しないので、ユーザの多様な要求に応える全文検索システムを実装することが可能となる。</p>
<p>QDBMはC言語の他にも、C++、Java、PerlおよびRubyのAPIを提供する。C言語のAPIには、基本API、拡張API、NDBM互換API、GDBM互換API、ユーティリティAPI、上級APIおよび転置APIの七種類がある。各APIに対応したコマンドラインインタフェースも用意されている。それらはプロトタイピングやテストやデバッグなどで活躍する。C++用APIは基本APIと拡張APIと上級APIのデータベース操作関数群をC++のクラス機構でカプセル化したものである。Java用APIはJava Native Interfaceを用いて基本APIと拡張APIと上級APIを呼び出すものである。Perl用APIはXS言語を用いて基本APIと拡張APIと上級APIを呼び出すものである。Ruby用APIはRubyのモジュールとして基本APIと拡張APIと上級APIを呼び出すものである。データベースの管理とファイルアップロードと全文検索のためのCGIスクリプトも提供される。</p>
<h3>幅広い移植性</h3>
<p>QDBMはANSI C(C89)の記法に従い、ANSI CまたはPOSIXで定義されたAPIのみを用いて実装される。したがって、ほとんどのUNIXおよびその互換をうたうOSで動作させることができる。C言語のAPIに関しては、少なくとも以下のプラットフォームで動作確認されている。</p>
<ul>
<li>Linux (2.2, 2.4, 2.6) (IA32, IA64, AMD64, PA-RISC, Alpha, PowerPC, M68000, ARM)</li>
<li>FreeBSD (4.9, 5.0, 5.1, 5.2, 5.3) (IA32, IA64, SPARC, Alpha)</li>
<li>NetBSD (1.6) (IA32)</li>
<li>OpenBSD (3.4) (IA32)</li>
<li>SunOS (5.6, 5.7, 5.8, 5.9, 5.10) (IA32, SPARC)</li>
<li>HP-UX (11.11, 11.23) (IA64, PA-RISC)</li>
<li>AIX (5.2) (POWER)</li>
<li>Windows (2000, XP) (IA32, IA64, AMD64) (Cygwin, MinGW, Visual C++)</li>
<li>Mac OS X (10.2, 10.3, 10.4) (IA32, PowerPC)</li>
<li>Tru64 (5.1) (Alpha)</li>
<li>RISC OS (5.03) (ARM)</li>
</ul>
<p>QDBMが作成したデータベースファイルは処理系のバイトオーダに依存するが、その対策として、バイトオーダに依存しない形式のデータをダンプするユーティリティが提供される。</p>
<hr />
<h2><a name="installation" id="installation" class="head">インストール</a></h2>
<h3>準備</h3>
<p>ソースパッケージを用いてQDBMをインストールするには、GCCのバージョン2.8以降と `make' が必要である。</p>
<p>QDBMの配布用アーカイブファイルを展開したら、生成されたディレクトリに入ってインストール作業を行う。</p>
<h3>普通の手順</h3>
<p>LinuxとBSDとSunOSでは以下の手順に従う。</p>
<p>ビルド環境を設定する。</p>
<pre>./configure
</pre>
<p>プログラムをビルドする。</p>
<pre>make
</pre>
<p>プログラムの自己診断テストを行う。</p>
<pre>make check
</pre>
<p>プログラムをインストールする。作業は `root' ユーザで行う。</p>
<pre>make install
</pre>
<h3>GNU Libtoolを使う場合</h3>
<p>上記の方法でうまくいかない場合、以下の手順に従う。この手順には、GNU Libtoolのバージョン1.5以降が必要である。</p>
<p>ビルド環境を設定する。</p>
<pre>./configure
</pre>
<p>プログラムをビルドする。</p>
<pre>make -f LTmakefile
</pre>
<p>プログラムの自己診断テストを行う。</p>
<pre>make -f LTmakefile check
</pre>
<p>プログラムをインストールする。作業は `root' ユーザで行う。</p>
<pre>make -f LTmakefile install
</pre>
<h3>結果</h3>
<p>一連の作業が終ると、以下のファイルがインストールされる。その他にも、マニュアルが `/usr/local/man/man1' と `/usr/local/man/man3' に、それ以外の文書が `/usr/local/share/qdbm' に、`pkg-config' 用の設定ファイルが `/usr/local/lib/pkgconfig' にインストールされる。</p>
<pre>/usr/local/include/depot.h
/usr/local/include/curia.h
/usr/local/include/relic.h
/usr/local/include/hovel.h
/usr/local/include/cabin.h
/usr/local/include/villa.h
/usr/local/include/vista.h
/usr/local/include/odeum.h
/usr/local/lib/libqdbm.a
/usr/local/lib/libqdbm.so.14.13.0
/usr/local/lib/libqdbm.so.14
/usr/local/lib/libqdbm.so
/usr/local/bin/dpmgr
/usr/local/bin/dptest
/usr/local/bin/dptsv
/usr/local/bin/crmgr
/usr/local/bin/crtest
/usr/local/bin/crtsv
/usr/local/bin/rlmgr
/usr/local/bin/rltest
/usr/local/bin/hvmgr
/usr/local/bin/hvtest
/usr/local/bin/cbtest
/usr/local/bin/cbcodec
/usr/local/bin/vlmgr
/usr/local/bin/vltest
/usr/local/bin/vltsv
/usr/local/bin/odmgr
/usr/local/bin/odtest
/usr/local/bin/odidx
/usr/local/bin/qmttest
</pre>
<p>`libqdbm.so' と動的にリンクしたプログラムを実行する際には、ライブラリの検索パスに `/usr/local/lib' を含めるべきである。環境変数 `LD_LIBRARY_PATH' でライブラリの検索パスを設定することができる。</p>
<p>QDBMをアンインストールするには、`./configure' をした後の状態で以下のコマンドを実行する。作業は `root' ユーザで行う。</p>
<pre>make uninstall
</pre>
<p>QDBMの古いバージョンがインストールされている場合、それをアンインストールしてからインストール作業を行うべきである。</p>
<p>C言語以外のAPIとCGIスクリプトはデフォルトではインストールされない。C++用APIのインストール方法については、サブディレクトリ `plus' にある `xspex-ja.html' を参照すること。JAVA用APIのインストール方法については、サブディレクトリ `java' にある `jspex-ja.html' を参照すること。Perl用APIのインストール方法については、サブディレクトリ `perl' にある `plspex-ja.html' を参照すること。Ruby用APIのインストール方法については、サブディレクトリ `ruby' にある `rbspex-ja.html' を参照すること。CGIスクリプトのインストール方法については、サブディレクトリ `cgi' にある `cgispex.html' を参照すること。</p>
<p>RPM等のバイナリパッケージを用いてインストールを行う場合は、それぞれのパッケージマネージャのマニュアルを参照すること。例えば、RPMを用いる場合、以下のようなコマンドを `root' ユーザで実行する。</p>
<pre>rpm -ivh qdbm-1.x.x-x.i386.rpm
</pre>
<h3>Windowsの場合</h3>
<p>Windows(Cygwin)にインストールする場合、以下の手順に従う。</p>
<p>ビルド環境を設定する。</p>
<pre>./configure
</pre>
<p>プログラムをビルドする。</p>
<pre>make win
</pre>
<p>プログラムの自己診断テストを行う。</p>
<pre>make check-win
</pre>
<p>プログラムをインストールする。なお、アンインストールする場合は `make uninstall-win' とする。</p>
<pre>make install-win
</pre>
<p>Windowsでは、静的ライブラリ `libqdbm.a' に加えてインポートライブラリ `libqdbm.dll.a' が生成され、動的ライブラリ `libqdbm.so' 等の代わりにダイナミックリンクライブラリ `qdbm.dll' が生成される。`qdbm.dll' は `/usr/local/bin' にインストールされる。</p>
<p>Cygwin環境でMinGWを用いてビルドするには、`make win' の代わりに `make mingw' を用いる。CygwinのUNIXエミュレーション層を用いる場合、生成されるプログラムは `cygwin1.dll' に依存したものになる(GNU GPLの影響を受ける)。MinGWによってWin32のネイティブDLLとリンクさせればこの問題を回避できる。</p>
<p>Visual C++を用いてビルドするには、`VCmakefile' を編集してヘッダとライブラリの検索パスを設定した上で、`nmake /f VCMakefile' とすればよい。生成された `qdbm.dll' とリンクするアプリケーションは、コンパイラの `/MD' または `/MDd' オプションを用いて `msvcrt.dll' とリンクさせる必要がある。詳細設定に関しては `VCmakefile' を参照のこと。</p>
<h3>Mac OS Xの場合</h3>
<p>Mac OS X(Darwin)にインストールする場合、以下の手順に従う。</p>
<p>ビルド環境を設定する。</p>
<pre>./configure
</pre>
<p>プログラムをビルドする。</p>
<pre>make mac
</pre>
<p>プログラムの自己診断テストを行う。</p>
<pre>make check-mac
</pre>
<p>プログラムをインストールする。なお、アンインストールする場合は `make uninstall-mac' とする。</p>
<pre>make install-mac
</pre>
<p>Mac OS Xでは、`libqdbm.so' 等の代わりに `libqdbm.dylib' 等が生成される。ライブラリの検索パスの指定は環境変数 `DYLD_LIBRARY_PATH' で行うことができる。</p>
<h3>HP-UXの場合</h3>
<p>HP-UXにインストールする場合、以下の手順に従う。</p>
<p>ビルド環境を設定する。</p>
<pre>./configure
</pre>
<p>プログラムをビルドする。</p>
<pre>make hpux
</pre>
<p>プログラムの自己診断テストを行う。</p>
<pre>make check-hpux
</pre>
<p>プログラムをインストールする。なお、アンインストールする場合は `make uninstall-hpux' とする。</p>
<pre>make install-hpux
</pre>
<p>HP-UXでは、`libqdbm.so' 等の代わりに `libqdbm.sl' が生成される。ライブラリの検索パスの指定は環境変数 `SHLIB_PATH' で行うことができる。</p>
<h3>RISC OSの場合</h3>
<p>RISC OSにインストールする場合、以下の手順に従う。</p>
<p>プログラムをビルドする。デフォルトではコンパイラに `cc' を用いるようになっているが、`gcc' を用いたければ `CC=gcc' という引数を加えればよい。</p>
<pre>make -f RISCmakefile
</pre>
<p>一連の作業が終ると、`libqdbm' というライブラリファイルと `dpmgr' 等のコマンドが生成される。それらのインストール方法は定義されていないので、手動で任意の場所にコピーしてインストールすること。`depot.h' 等のヘッダファイルも同様に手動でインストールすること。</p>
<h3>詳細設定</h3>
<p>`./configure' を実行する際に以下のオプション引数を指定することで、ビルド方法の詳細な設定を行うことができる。</p>
<ul class="lines">
<li><kbd>--enable-debug</kbd> : デバッグ用にビルドする。デバッグシンボルを有効化し、最適化を行わず、静的にリンクする。</li>
<li><kbd>--enable-devel</kbd> : 開発用にビルドする。デバッグシンボルを有効化し、最適化を行い、動的にリンクする。</li>
<li><kbd>--enable-stable</kbd> : 安定版のリリース用にビルドする。保守的な最適化を行い、動的にリンクする。</li>
<li><kbd>--enable-pthread</kbd> : POSIXスレッドを用い、グローバル変数をスレッド固有データとして扱う。</li>
<li><kbd>--disable-lock</kbd> : ファイルロッキングが実装されていない環境用にビルドする。</li>
<li><kbd>--disable-mmap</kbd> : メモリマッピングが実装されていない環境用にビルドする。</li>
<li><kbd>--enable-zlib</kbd> : ZLIBによるB+木と転置インデックスのレコード圧縮を機能させる。</li>
<li><kbd>--enable-lzo</kbd> : LZOによるB+木と転置インデックスのレコード圧縮を機能させる。</li>
<li><kbd>--enable-bzip</kbd> : BZIP2によるB+木と転置インデックスのレコード圧縮を機能させる。</li>
<li><kbd>--enable-iconv</kbd> : ICONVによる文字コード変換ユーティリティを機能させる。</li>
</ul>
<p>通常、QDBMとそのアプリケーションは `libqdbm.*' 以外の非標準のライブラリには依存しないでビルドすることができる。ただし、POSIXスレッドを有効にした場合は `libpthread.*' に依存し、ZLIBを有効にした場合は `libz.*' に依存し、LZOを有効にした場合は `liblzo2.*' に依存し、BZIP2を有効にした場合は `libbz2.*' に依存し、ICONVを有効にした場合は `libiconv.*' に依存するようになる。</p>
<p>LZOのライセンスはGNU GPLなので、`liblzo2.*' とリンクしたアプリケーションはGNU GPLの制約を受けることに注意すること。</p>
<hr />
<h2><a name="depotapi" id="depotapi" class="head">Depot: 基本API</a></h2>
<h3>概要</h3>
<p>DepotはQDBMの基本APIである。QDBMが提供するデータベース管理機能のほぼ全てがDepotによって実装される。その他のAPIはDepotのラッパーにすぎない。したがって、QDBMのAPIの中でDepotが最も高速に動作する。</p>
<p>Depotを使うためには、`depot.h' と `stdlib.h' をインクルードすべきである。通常、ソースファイルの冒頭付近で以下の記述を行う。</p>
<dl>
<dt><kbd>#include <depot.h></kbd></dt>
<dt><kbd>#include <stdlib.h></kbd></dt>
</dl>
<p>Depotでデータベースを扱う際には、`DEPOT' 型へのポインタをハンドルとして用いる。これは、`stdio.h' の各種ルーチンがファイル入出力に `FILE' 型へのポインタを用いるのに似ている。ハンドルは、関数 `dpopen' で開き、関数 `dpclose' で閉じる。ハンドルのメンバを直接参照することは推奨されない。データベースに致命的なエラーが起きた場合は、以後そのハンドルに対する `dpclose' を除く全ての操作は何もせずにエラーを返す。ひとつのプロセスで複数のデータベースファイルを同時に利用することは可能であるが、同じデータベースファイルの複数のハンドルを利用してはならない。</p>
<h3>API</h3>
<p>外部変数 `dpversion' はバージョン情報の文字列である。</p>
<dl>
<dt><kbd>extern const char *dpversion;</kbd></dt>
<dd>この変数の指す領域は書き込み禁止である。</dd>
</dl>
<p>外部変数 `dpecode' には直前のエラーコードが記録される。エラーコードの詳細については `depot.h' を参照すること。</p>
<dl>
<dt><kbd>extern int dpecode;</kbd></dt>
<dd>この変数の初期値は `DP_ENOERR' である。その他の値として、`DP_EFATAL'、`DP_EMODE'、`DP_EBROKEN'、`DP_EKEEP'、`DP_ENOITEM'、`DP_EALLOC'、`DP_EMAP'、`DP_EOPEN'、`DP_ECLOSE'、`DP_ETRUNC'、`DP_ESYNC'、`DP_ESTAT'、`DP_ESEEK'、`DP_EREAD'、`DP_EWRITE'、`DP_ELOCK'、`DP_EUNLINK'、`DP_EMKDIR'、`DP_ERMDIR' および `DP_EMISC' がある。</dd>
</dl>
<p>エラーコードに対応するメッセージ文字列を得るには、関数 `dperrmsg' を用いる。</p>
<dl>
<dt><kbd>const char *dperrmsg(int <var>ecode</var>);</kbd></dt>
<dd>`ecode' はエラーコードを指定する。戻り値はエラーメッセージの文字列であり、その領域は書き込み禁止である。</dd>
</dl>
<p>データベースのハンドルを作成するには、関数 `dpopen' を用いる。</p>
<dl>
<dt><kbd>DEPOT *dpopen(const char *<var>name</var>, int <var>omode</var>, int <var>bnum</var>);</kbd></dt>
<dd>`name' はデータベースファイルの名前を指定する。`omode' は接続モードを指定し、`DP_OREADER' ならリーダ、`DP_OWRITER' ならライタとなる。`DP_OWRITER' の場合、`DP_OCREAT' または `DP_OTRUNC' とのビット論理和にすることができる。`DP_OCREAT' はファイルが無い場合に新規作成することを指示し、`DP_OTRUNC' はファイルが存在しても作り直すことを指示する。`DP_OREADER' と `DP_OWRITER' の両方で `DP_ONOLCK' または `DP_OLCKNB' とのビット論理和にすることができるが、前者はファイルロックをかけずにデータベースを開くことを指示し、後者はブロックせずにロックをかけることを指示する。`DP_OCREAT' は `DP_OSPARSE' とのビット論理和にすることができるが、それは生成されるファイルをスパースにすることを指示する。`bnum' はバケット配列の要素数の目安を指定するが、0 以下ならデフォルト値が使われる。バケット配列の要素数はデータベースを作成する時に決められ、最適化以外の手段で変更することはできない。バケット配列の要素数は、格納するレコード数の半分から4倍程度にするのがよい。戻り値はデータベースハンドルであるか、エラーなら `NULL' である。ライタ(読み書き両用モード)でデータベースファイルを開く際にはそのファイルに対して排他ロックがかけられ、リーダ(読み込み専用モード)で開く際には共有ロックがかけられる。その際には該当のロックがかけられるまで制御がブロックする。`DP_ONOLCK' を使う場合、アプリケーションが排他制御の責任を負う。</dd>
</dl>
<p>データベースとの接続を閉じてハンドルを破棄するには、関数 `dpclose' を用いる。</p>
<dl>
<dt><kbd>int dpclose(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。データベースの更新内容は、接続を閉じた時点で初めてファイルと同期される。ライタでデータベースを開いた場合、適切に接続を閉じないとデータベースが破壊される。閉じたハンドルの領域は解放されるので、以後は利用できなくなる。</dd>
</dl>
<p>レコードを追加するには、関数 `dpput' を用いる。</p>
<dl>
<dt><kbd>int dpput(DEPOT *<var>depot</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, const char *<var>vbuf</var>, int <var>vsiz</var>, int <var>dmode</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`vbuf' は値のデータ領域へのポインタを指定する。`vsiz' は値のデータ領域のサイズを指定するか、負数なら `strlen(vbuf)' の値となる。`dmode' はキーが既存レコードと重複した際の制御を指定する。`DP_DOVER' は既存のレコードの値を上書きし、`DP_DKEEP' は既存のレコードを残してエラーを返し、`DP_DCAT' は指定された値を既存の値の末尾に加える。戻り値は正常なら真であり、エラーなら偽である。</dd>
</dl>
<p>レコードを削除するには、関数 `dpout' を用いる。</p>
<dl>
<dt><kbd>int dpout(DEPOT *<var>depot</var>, const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値は正常なら真であり、エラーなら偽である。該当のレコードがない場合も偽を返す。</dd>
</dl>
<p>レコードを取得するには、関数 `dpget' を用いる。</p>
<dl>
<dt><kbd>char *dpget(DEPOT *<var>depot</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, int <var>start</var>, int <var>max</var>, int *<var>sp</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`start' は値の領域から抽出する最初のバイトのオフセットを指定する。`max' は値の領域から抽出するサイズを指定するか、負数なら無制限となる。`sp' が `NULL' でなければ、その参照先に抽出した領域のサイズを格納する。戻り値は正常なら値を格納した領域へのポインタであり、エラーなら `NULL' である。該当のレコードがない場合も `NULL' を返す。取り出そうとした値のサイズが `start' より小さかった場合には該当とみなさない。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。</dd>
</dl>
<p>レコードを取得してバッファに書き込むには、関数 `dpgetwb' を用いる。</p>
<dl>
<dt><kbd>int dpgetwb(DEPOT *<var>depot</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, int <var>start</var>, int <var>max</var>, char *<var>vbuf</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`start' は値の領域から抽出する最初のバイトのオフセットを指定する。`max' は値の領域から抽出するサイズを指定する。それは書き込み用のバッファのサイズ以下である必要がある。`vbuf' は抽出したデータを書き込むバッファへのポインタを指定する。戻り値は正常ならバッファに書き込まれたデータのサイズであり、エラーなら -1 である。該当のレコードがない場合も -1 を返す。取り出そうとした値のサイズが `start' より小さかった場合には該当とみなさない。書き込み用バッファの末尾に終端文字が追加されないことに注意すべきである。</dd>
</dl>
<p>レコードの値のサイズを取得するには、関数 `dpvsiz' を用いる。</p>
<dl>
<dt><kbd>int dpvsiz(DEPOT *<var>depot</var>, const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値は該当レコードの値のサイズであるが、該当がない場合やエラーの場合は -1 である。この関数はレコードの有無を調べるのにも便利である。`dpget' と違って実データを読み込まないので効率がよい。</dd>
</dl>
<p>データベースのイテレータを初期化するには、関数 `dpiterinit' を用いる。</p>
<dl>
<dt><kbd>int dpiterinit(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。イテレータは、データベースに格納された全てのレコードを参照するために用いられる。</dd>
</dl>
<p>データベースのイテレータから次のレコードのキーを取り出すには、関数 `dpiternext' を用いる。</p>
<dl>
<dt><kbd>char *dpiternext(DEPOT *<var>depot</var>, int *<var>sp</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。`sp' が `NULL' でなければ、その参照先に抽出した領域のサイズを格納する。戻り値は正常ならキーを格納した領域へのポインタであり、エラーなら `NULL' である。イテレータが最後まできて該当のレコードがない場合も `NULL' を返す。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。この関数を繰り返して呼ぶことによって全てのレコードを一度ずつ参照することができる。ただし、繰り返しの間にデータベースの更新があった場合はその限りではない。なお、取り出すレコードの順序は制御できず、格納した順番でレコードを取り出せるとは限らない。</dd>
</dl>
<p>データベースのアラインメントを設定するには、関数 `dpsetalign' を用いる。</p>
<dl>
<dt><kbd>int dpsetalign(DEPOT *<var>depot</var>, int <var>align</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。`align' はアラインメントのサイズを指定する。戻り値は正常なら真であり、エラーなら偽である。アラインメントを設定しておくと、レコードの上書きを頻繁にする場合の処理効率が良くなる。アラインメントには、一連の更新操作をした後の状態での標準的な値のサイズを指定するのがよい。アラインメントが正数の場合、レコードの領域のサイズがアラインメントの倍数になるようにパディングがとられる。アラインメントが負数の場合、`vsiz' を値のサイズとして、パディングのサイズは `(vsiz / pow(2, abs(align) - 1))' として算出される。アラインメントの設定はデータベースに保存されないので、データベースを開く度に指定する必要がある。</dd>
</dl>
<p>データベースのフリーブロックプールのサイズ設定するには、関数 `dpsetfbpsiz' を用いる。</p>
<dl>
<dt><kbd>int dpsetfbpsiz(DEPOT *<var>depot</var>, int <var>size</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。`size' はフリーブロックプールのサイズを指定する。戻り値は正常なら真であり、エラーなら偽である。フリーブロックプールのデフォルトのサイズは16である。サイズをより大きくすると、レコードの上書きを繰り返す際の空間効率は上がるが、時間効率が下がる。</dd>
</dl>
<p>データベースを更新した内容をファイルとデバイスに同期させるには、関数 `dpsync' を用いる。</p>
<dl>
<dt><kbd>int dpsync(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。この関数はデータベースを閉じないうちに別プロセスにデータベースファイルを利用させる場合に役立つ。</dd>
</dl>
<p>データベースを最適化するには、関数 `dpoptimize' を用いる。</p>
<dl>
<dt><kbd>int dpoptimize(DEPOT *<var>depot</var>, int <var>bnum</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。`bnum' は新たなバケット配列の要素数を指定するが、0 以下なら現在のレコード数に最適な値が指定される。戻り値は正常なら真であり、エラーなら偽である。レコードを削除したり、置換モードや連結モードで書き込みを繰り返したりする場合は、データベース内に不要な領域が蓄積するが、この関数はそれを解消するのに役立つ。</dd>
</dl>
<p>データベースの名前を得るには、関数 `dpname' を用いる。</p>
<dl>
<dt><kbd>char *dpname(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常なら名前を格納した領域へのポインタであり、エラーなら `NULL' である。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。</dd>
</dl>
<p>データベースファイルのサイズを得るには、関数 `dpfsiz' を用いる。</p>
<dl>
<dt><kbd>int dpfsiz(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常ならデータベースファイルのサイズであり、エラーなら -1 である。</dd>
</dl>
<p>データベースのバケット配列の要素数を得るには、関数 `dpbnum' を用いる。</p>
<dl>
<dt><kbd>int dpbnum(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常ならデータベースのバケット配列の要素数であり、エラーなら -1 である。</dd>
</dl>
<p>データベースのバケット配列の利用済みの要素数を得るには、関数 `dpbusenum' を用いる。</p>
<dl>
<dt><kbd>int dpbusenum(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常ならバケット配列の利用済みの要素数であり、エラーなら -1 である。この関数はバケット配列の全ての要素を参照するので、効率が悪い。</dd>
</dl>
<p>データベースのレコード数を得るには、関数 `dprnum' を用いる。</p>
<dl>
<dt><kbd>int dprnum(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は正常ならデータベースのレコード数であり、エラーなら -1 である。</dd>
</dl>
<p>データベースハンドルがライタかどうかを調べるには、関数 `dpwritable' を用いる。</p>
<dl>
<dt><kbd>int dpwritable(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値はライタなら真であり、そうでなければ偽である。</dd>
</dl>
<p>データベースに致命的エラーが起きたかどうかを調べるには、関数 `dpfatalerror' を用いる。</p>
<dl>
<dt><kbd>int dpfatalerror(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値は致命的エラーがあれば真であり、そうでなければ偽である。</dd>
</dl>
<p>データベースファイルのinode番号を得るには、関数 `dpinode' を用いる。</p>
<dl>
<dt><kbd>int dpinode(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値はデータベースファイルのinode番号である。</dd>
</dl>
<p>データベースの最終更新時刻を得るには、関数 `dpmtime' を用いる。</p>
<dl>
<dt><kbd>time_t dpmtime(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値はデータベースの最終更新時刻である。</dd>
</dl>
<p>データベースファイルのファイルディスクリプタを得るには、関数 `dpfdesc' を用いる。</p>
<dl>
<dt><kbd>int dpfdesc(DEPOT *<var>depot</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。戻り値はデータベースファイルのファイルディスクリプタである。データベースのファイルディスクリプタを直接操ることは推奨されない。</dd>
</dl>
<p>データベースファイルを削除するには、関数 `dpremove' を用いる。</p>
<dl>
<dt><kbd>int dpremove(const char *<var>name</var>);</kbd></dt>
<dd>`name' はデータベースファイルの名前を指定する。戻り値は正常なら真であり、エラーなら偽である。</dd>
</dl>
<p>壊れたデータベースファイルを修復するには、関数 `dprepair' を用いる。</p>
<dl>
<dt><kbd>int dprepair(const char *<var>name</var>);</kbd></dt>
<dd>`name' はデータベースファイルの名前を指定する。戻り値は正常なら真であり、エラーなら偽である。修復されたデータベースの全レコードが元来もしくは期待される状態に戻る保証はない。</dd>
</dl>
<p>全てのレコードをエンディアン非依存のデータとしてダンプするには、関数 `dpexportdb' を用いる。</p>
<dl>
<dt><kbd>int dpexportdb(DEPOT *<var>depot</var>, const char *<var>name</var>);</kbd></dt>
<dd>`depot' はデータベースハンドルを指定する。`name' は出力ファイルの名前を指定する。戻り値は正常なら真であり、エラーなら偽である。</dd>
</dl>
<p>エンディアン非依存データから全てのレコードをロードするには、関数 `dpimportdb' を用いる。</p>
<dl>
<dt><kbd>int dpimportdb(DEPOT *<var>depot</var>, const char *<var>name</var>);</kbd></dt>
<dd>`depot' はライタで接続したデータベースハンドルを指定する。データベースは空でなければならない。`name' は入力ファイルの名前を指定する。戻り値は正常なら真であり、エラーなら偽である。</dd>
</dl>
<p>データベースファイルからレコードを直接取得するには、関数 `dpsnaffle' を用いる。</p>
<dl>
<dt><kbd>char *dpsnaffle(const char *<var>name</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, int *<var>sp</var>);</kbd></dt>
<dd>`name' はデータベースファイルの名前を指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`start' は値の領域から抽出する最初のバイトのオフセットを指定する。`max' は値の領域から抽出するサイズを指定するか、負数なら無制限となる。`sp' が `NULL' でなければ、その参照先に抽出した領域のサイズを格納する。戻り値は正常なら値を格納した領域へのポインタであり、エラーなら `NULL' である。該当のレコードがない場合も `NULL' を返す。取り出そうとした値のサイズが `start' より小さかった場合には該当とみなさない。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。この関数はデータベースファイルが別のプロセスにロックされていても利用できるが、最新の更新が反映されている保証はない。</dd>
</dl>
<p>データベースの内部で用いるハッシュ関数として、関数 `dpinnerhash' がある。</p>
<dl>
<dt><kbd>int dpinnerhash(const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値はキーから31ビット長のハッシュ値を算出した値である。この関数はアプリケーションがバケット配列の状態を予測する際に役立つ。</dd>
</dl>
<p>データベースの内部で用いるハッシュ関数と独立したハッシュ関数として、関数 `dpouterhash' がある。</p>
<dl>
<dt><kbd>int dpouterhash(const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値はキーから31ビット長のハッシュ値を算出した値である。この関数はアプリケーションがデータベースの更に上でハッシュアルゴリズムを利用する際に役立つ。</dd>
</dl>
<p>ある数以上の自然数の素数を得るには、関数 `dpprimenum' を用いる。</p>
<dl>
<dt><kbd>int dpprimenum(int <var>num</var>);</kbd></dt>
<dd>`num' は適当な自然数を指定する。戻り値は、指定した数と同じかより大きくかつなるべく小さい自然数の素数である。この関数はアプリケーションが利用するバケット配列のサイズを決める場合に役立つ。</dd>
</dl>
<h3>サンプルコード</h3>
<p>名前と対応させて電話番号を格納し、それを検索するアプリケーションのサンプルコードを以下に示す。</p>
<pre>#include <depot.h>
#include <stdlib.h>
#include <stdio.h>
#define NAME "mikio"
#define NUMBER "000-1234-5678"
#define DBNAME "book"
int main(int argc, char **argv){
DEPOT *depot;
char *val;
/* データベースを開く */
if(!(depot = dpopen(DBNAME, DP_OWRITER | DP_OCREAT, -1))){
fprintf(stderr, "dpopen: %s\n", dperrmsg(dpecode));
return 1;
}
/* レコードを格納する */
if(!dpput(depot, NAME, -1, NUMBER, -1, DP_DOVER)){
fprintf(stderr, "dpput: %s\n", dperrmsg(dpecode));
}
/* レコードを取得する */
if(!(val = dpget(depot, NAME, -1, 0, -1, NULL))){
fprintf(stderr, "dpget: %s\n", dperrmsg(dpecode));
} else {
printf("Name: %s\n", NAME);
printf("Number: %s\n", val);
free(val);
}
/* データベースを閉じる */
if(!dpclose(depot)){
fprintf(stderr, "dpclose: %s\n", dperrmsg(dpecode));
return 1;
}
return 0;
}
</pre>
<p>データベースの全てのレコードを表示するアプリケーションのサンプルコードを以下に示す。</p>
<pre>#include <depot.h>
#include <stdlib.h>
#include <stdio.h>
#define DBNAME "book"
int main(int argc, char **argv){
DEPOT *depot;
char *key, *val;
/* データベースを開く */
if(!(depot = dpopen(DBNAME, DP_OREADER, -1))){
fprintf(stderr, "dpopen: %s\n", dperrmsg(dpecode));
return 1;
}
/* イテレータを初期化する */
if(!dpiterinit(depot)){
fprintf(stderr, "dpiterinit: %s\n", dperrmsg(dpecode));
}
/* イテレータを走査する */
while((key = dpiternext(depot, NULL)) != NULL){
if(!(val = dpget(depot, key, -1, 0, -1, NULL))){
fprintf(stderr, "dpget: %s\n", dperrmsg(dpecode));
free(key);
break;
}
printf("%s: %s\n", key, val);
free(val);
free(key);
}
/* データベースを閉じる */
if(!dpclose(depot)){
fprintf(stderr, "dpclose: %s\n", dperrmsg(dpecode));
return 1;
}
return 0;
}
</pre>
<h3>注記</h3>
<p>Depotを利用したプログラムをビルドするには、ライブラリ `libqdbm.a' または `libqdbm.so' をリンク対象に加える必要がある。例えば、`sample.c' から `sample' を作るには、以下のようにビルドを行う。</p>
<pre>gcc -I/usr/local/include -o sample sample.c -L/usr/local/lib -lqdbm
</pre>
<p>POSIXスレッドを有効にしてQDBMをビルドした場合、外部変数 `dpecode' はスレッド固有データへの参照として扱われ、Depotの各関数はリエントラントになる。その場合、スレッド間で同時に同じハンドルにアクセスしない限りは、各関数はスレッドセーフである。ただし、`errno' や `malloc' 等がスレッドセーフな処理系であることが前提となる。</p>
<hr />
<h2><a name="depotcli" id="depotcli" class="head">Depot用コマンド</a></h2>
<p>Depotに対応するコマンドラインインタフェースは以下のものである。</p>
<p>コマンド `dpmgr' はDepotやそのアプリケーションのデバッグに役立つツールである。データベースを更新したり、データベースの状態を調べたりする機能を持つ。シェルスクリプトでデータベースアプリケーションを作るのにも利用できる。以下の書式で用いる。`name' はデータベース名、`key' はレコードのキー、`val' はレコードの値を指定する。</p>
<dl>
<dt><kbd>dpmgr create [-s] [-bnum <var>num</var>] <var>name</var></kbd></dt>
<dd>データベースファイルを作成する。</dd>
<dt><kbd>dpmgr put [-kx|-ki] [-vx|-vi|-vf] [-keep|-cat] [-na] <var>name</var> <var>key</var> <var>val</var></kbd></dt>
<dd>キーと値に対応するレコードを追加する。</dd>
<dt><kbd>dpmgr out [-kx|-ki] <var>name</var> <var>key</var></kbd></dt>
<dd>キーに対応するレコードを削除する。</dd>
<dt><kbd>dpmgr get [-nl] [-kx|-ki] [-start <var>num</var>] [-max <var>num</var>] [-ox] [-n] <var>name</var> <var>key</var></kbd></dt>
<dd>キーに対応するレコードの値を取得して標準出力する。</dd>
<dt><kbd>dpmgr list [-nl] [-k|-v] [-ox] <var>name</var></kbd></dt>
<dd>データベース内の全てのレコードのキーと値をタブと改行で区切って標準出力する。</dd>
<dt><kbd>dpmgr optimize [-bnum <var>num</var>] [-na] <var>name</var></kbd></dt>
<dd>データベースを最適化する。</dd>
<dt><kbd>dpmgr inform [-nl] <var>name</var></kbd></dt>
<dd>データベースの雑多な情報を出力する。</dd>
<dt><kbd>dpmgr remove <var>name</var></kbd></dt>
<dd>データベースファイルを削除する。</dd>
<dt><kbd>dpmgr repair <var>name</var></kbd></dt>
<dd>壊れたデータベースファイルを修復する。</dd>
<dt><kbd>dpmgr exportdb <var>name</var> <var>file</var></kbd></dt>
<dd>全てのレコードをエンディアン非依存のデータとしてダンプする。</dd>
<dt><kbd>dpmgr importdb [-bnum <var>num</var>] <var>name</var> <var>file</var></kbd></dt>
<dd>エンディアン非依存データから全てのレコードをロードする。</dd>
<dt><kbd>dpmgr snaffle [-kx|-ki] [-ox] [-n] <var>name</var> <var>key</var></kbd></dt>
<dd>ロックされたデータベースからキーに対応するレコードの値を取得して標準出力する。</dd>
<dt><kbd>dpmgr version</kbd></dt>
<dd>QDBMのバージョン情報を標準出力する。</dd>
</dl>
<p>各オプションは以下の機能を持つ。</p>
<ul class="lines">
<li><kbd>-s</kbd> : ファイルをスパースにする。</li>
<li><kbd>-bnum <var>num</var></kbd> : バケット配列の要素数を `num' に指定する。</li>
<li><kbd>-kx</kbd> : 2桁単位の16進数によるバイナリ表現として `key' を扱う。</li>
<li><kbd>-ki</kbd> : 10進数による数値表現として `key' を扱う。</li>
<li><kbd>-vx</kbd> : 2桁単位の16進数によるバイナリ表現として `val' を扱う。</li>
<li><kbd>-vi</kbd> : 10進数による数値表現として `val' を扱う。</li>
<li><kbd>-vf</kbd> : 名前が `val' のファイルのデータを値として読み込む。</li>
<li><kbd>-keep</kbd> : 既存のレコードとキーが重複時に上書きせずにエラーにする。</li>
<li><kbd>-cat</kbd> : 既存のレコードとキーが重複時に値を末尾に追加する。</li>
<li><kbd>-na</kbd> : アラインメントを設定しない。</li>
<li><kbd>-nl</kbd> : ファイルロックをかけずにデータベースを開く。</li>
<li><kbd>-start</kbd> : 値から取り出すデータの開始オフセットを指定する。</li>
<li><kbd>-max</kbd> : 値から取り出すデータの最大の長さを指定する。</li>
<li><kbd>-ox</kbd> : 2桁単位の16進数によるバイナリ表現として標準出力を行う。</li>
<li><kbd>-n</kbd> : 標準出力の末尾に付加される改行文字の出力を抑制する。</li>
<li><kbd>-k</kbd> : キーのみを出力する。</li>
<li><kbd>-v</kbd> : 値のみを出力する。</li>
</ul>
<p>このコマンドは処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。環境変数 `QDBMDBGFD' の値として、変数 `dpecode' の変更履歴を出力するファイルディスクリプタを指定ことができる。</p>
<p>コマンド `dptest' はDepotの機能テストや性能テストに用いるツールである。このコマンドによって生成されたデータベースファイルを `dpmgr' によって解析したり、`time' コマンドによってこのコマンドの実行時間を計ったりするとよい。以下の書式で用いる。`name' はデータベース名、`rnum' はレコード数、`bnum' はバケット配列の要素数、`pnum' はキーのパターン数、`align' はアラインメントの基本サイズ、`fbpsiz' はフリーブロックプールのサイズを指定する。</p>
<dl>
<dt><kbd>dptest write [-s] <var>name</var> <var>rnum</var> <var>bnum</var></kbd></dt>
<dd>`00000001'、`00000002' のように変化する8バイトのキーと適当な8バイトの値を連続してデータベースに追加する。</dd>
<dt><kbd>dptest read [-wb] <var>name</var></kbd></dt>
<dd>上記で生成したデータベースの全レコードを検索する。</dd>
<dt><kbd>dptest rcat [-c] <var>name</var> <var>rnum</var> <var>bnum</var> <var>pnum</var> <var>align</var> <var>fbpsiz</var></kbd></dt>
<dd>キーがある程度重複するようにレコードの追加を行い、連結モードで処理する。</dd>
<dt><kbd>dptest combo <var>name</var></kbd></dt>
<dd>各種操作の組み合わせテストを行う。</dd>
<dt><kbd>dptest wicked [-c] <var>name</var> <var>rnum</var></kbd></dt>
<dd>各種更新操作を無作為に選択して実行する。</dd>
</dl>
<p>各オプションは以下の機能を持つ。</p>
<ul class="lines">
<li><kbd>-s</kbd> : ファイルをスパースにする。</li>
<li><kbd>-wb</kbd> : 関数 `dpget' の代わりに関数 `dpgetwb' を用いる。</li>
<li><kbd>-c</kbd> : Cabinのマップを使って比較テストを行う。</li>
</ul>
<p>このコマンドは処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。環境変数 `QDBMDBGFD' の値として、変数 `dpecode' の変更履歴を出力するファイルディスクリプタを指定ことができる。</p>
<p>コマンド `dptsv' はタブ区切りでキーと値を表現した行からなるTSVファイルとDepotのデータベースを相互変換する。このコマンドは、QDBMの他のバージョンや他のDBMとの間でデータの交換を行う際に役立つ。また、バイトオーダの違うシステムの間でデータを交換する際にも役立つ。以下の書式で用いる。`name' はデータベース名を指定する。`export' サブコマンドではTSVのデータは標準入力から読み込む。キーが重複するレコードは後者を優先する。`-bnum' オプションの引数 `num' はバケット配列の要素数を指定する。`import' サブコマンドではTSVのデータが標準出力に書き出される。</p>
<dl>
<dt><kbd>dptsv import [-bnum <var>num</var>] [-bin] <var>name</var></kbd></dt>
<dd>TSVファイルを読み込んでデータベースを作成する。</dd>
<dt><kbd>dptsv export [-bin] <var>name</var></kbd></dt>
<dd>データベースの全てのレコードをTSVファイルとして出力する。</dd>
</dl>
<p>各オプションは以下の機能を持つ。</p>
<ul class="lines">
<li><kbd>-bnum <var>num</var></kbd> : バケット配列の要素数を `num' に指定する。</li>
<li><kbd>-bin</kbd> : Base64形式でレコードを扱う。</li>
</ul>
<p>このコマンドは処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。</p>
<p>Depotのコマンド群を駆使すると、簡単なデータベースシステムが構築できる。例えば `/etc/password' をユーザ名で検索するためのデータベースを作成するには、以下のようにする。</p>
<pre>cat /etc/passwd | tr ':' '\t' | dptsv import casket
</pre>
<p>そして、`mikio' というユーザの情報を取り出すには、以下のようにする。</p>
<pre>dpmgr get casket mikio
</pre>
<p>これらのコマンドと同等の機能をDepotのAPIを用いて実装することも容易である。</p>
<hr />
<h2><a name="curiaapi" id="curiaapi" class="head">Curia: 拡張API</a></h2>
<h3>概要</h3>
<p>CuriaはQDBMの拡張APIであり、複数のデータベースファイルをディレクトリで一括して扱う機能を提供する。データベースを複数のファイルに分割することで、ファイルシステムによるファイルサイズの制限を回避することができる。複数のデバイスにファイルを分散させれば、スケーラビリティを向上させることができる。</p>
<p>Depotではファイル名を指定してデータベースを構築するが、Curiaではディレクトリ名を指定してデータベースを構築する。指定したディレクトリの直下には、`depot' という名前のデータベースファイルが生成される。これはディレクトリの属性を保持するものであり、レコードの実データは格納されない。それとは別に、データベースを分割した個数だけ、4桁の10進数値の名前を持つサブディレクトリが生成され、各々のサブディレクトリの中には `depot' という名前でデータベースファイルが生成される。レコードの実データはそれらに格納される。例えば、`casket' という名前のデータベースを作成し、分割数を3にする場合、`casket/depot'、`casket/0001/depot'、`casket/0002/depot'、`casket/0003/depot' が生成される。データベースを作成する際にすでにディレクトリが存在していてもエラーとはならない。したがって、予めサブディレクトリを生成しておいて、各々に異なるデバイスのファイルシステムをマウントしておけば、データベースファイルを複数のデバイスに分散させることができる。</p>
<p>Curiaにはラージオブジェクトを扱う機能がある。通常のレコードのデータはデータベースファイルに格納されるが、ラージオブジェクトのレコードのデータは個別のファイルに格納される。ラージオブジェクトのファイルはハッシュ値を元にディレクトリに分けて格納されるので、通常のレコードには劣るが、それなりの速度で参照できる。サイズが大きく参照頻度が低いデータは、ラージオブジェクトとしてデータベースファイルから分離すべきである。そうすれば、通常のレコードに対する処理速度が向上する。ラージオブジェクトのディレクトリ階層はデータベースファイルが格納されるサブディレクトリの中の `lob' という名前のディレクトリの中に作られる。通常のデータベースとラージオブジェクトのデータベースはキー空間が異なり、互いに干渉することはない。</p>
<p>Curiaを使うためには、`depot.h' と `curia.h' と `stdlib.h' をインクルードすべきである。通常、ソースファイルの冒頭付近で以下の記述を行う。</p>
<dl>
<dt><kbd>#include <depot.h></kbd></dt>
<dt><kbd>#include <curia.h></kbd></dt>
<dt><kbd>#include <stdlib.h></kbd></dt>
</dl>
<p>Curiaでデータベースを扱う際には、`CURIA' 型へのポインタをハンドルとして用いる。これは、`stdio.h' の各種ルーチンがファイル入出力に `FILE' 型へのポインタを用いるのに似ている。ハンドルは、関数 `cropen' で開き、関数 `crclose' で閉じる。ハンドルのメンバを直接参照することは推奨されない。データベースに致命的なエラーが起きた場合は、以後そのハンドルに対する `crclose' を除く全ての操作は何もせずにエラーを返す。ひとつのプロセスで複数のデータベースディレクトリを同時に利用することは可能であるが、同じデータベースディレクトリの複数のハンドルを利用してはならない。</p>
<p>CuriaでもDepotと同じく外部変数 `dpecode' に直前のエラーコードが記録される。エラーコードに対応するメッセージ文字列を得るには、関数 `dperrmsg' を用いる。</p>
<h3>API</h3>
<p>データベースのハンドルを作成するには、関数 `cropen' を用いる。</p>
<dl>
<dt><kbd>CURIA *cropen(const char *<var>name</var>, int <var>omode</var>, int <var>bnum</var>, int <var>dnum</var>);</kbd></dt>
<dd>`name' はデータベースディレクトリの名前を指定する。`omode' は接続モードを指定し、`CR_OREADER' ならリーダ、`CR_OWRITER' ならライタとなる。`CR_OWRITER' の場合、`CR_OCREAT' または `CR_OTRUNC' とのビット論理和にすることができる。`CR_OCREAT' はファイルが無い場合に新規作成することを指示し、`CR_OTRUNC' はファイルが存在しても作り直すことを指示する。`CR_OREADER' と `CR_OWRITER' の両方で `CR_ONOLCK' または `CR_OLCKNB' とのビット論理和にすることができるが、前者はファイルロックをかけずにデータベースを開くことを指示し、後者はブロックせずにロックをかけることを指示する。`CR_OCREAT' は `CR_OSPARSE' とのビット論理和にすることができるが、それは生成されるファイルをスパースにすることを指示する。`bnum' はバケット配列の要素数の目安を指定するが、0 以下ならデフォルト値が使われる。バケット配列の要素数はデータベースを作成する時に決められ、最適化以外の手段で変更することはできない。バケット配列の要素数は、格納するレコード数の半分から4倍程度にするのがよい。`dnum' は要素データベースの数を指定するが、0 以下ならデフォルト値が使われる。データベースファイルの分割数はデータベースを作成する時に指定したものから変更することはできない。データベースファイルの分割数の最大値は 512 個である。戻り値はデータベースハンドルであるか、エラーなら `NULL' である。ライタ(読み書き両用モード)でデータベースファイルを開く際にはそのファイルに対して排他ロックがかけられ、リーダ(読み込み専用モード)で開く際には共有ロックがかけられる。その際には該当のロックがかけられるまで制御がブロックする。`CR_ONOLCK' を使う場合、アプリケーションが排他制御の責任を負う。</dd>
</dl>
<p>データベースとの接続を閉じてハンドルを破棄するには、関数 `crclose' を用いる。</p>
<dl>
<dt><kbd>int crclose(CURIA *<var>curia</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。データベースの更新内容は、接続を閉じた時点で初めてファイルと同期される。ライタでデータベースを開いた場合、適切に接続を閉じないとデータベースが破壊される。閉じたハンドルの領域は解放されるので、以後は利用できなくなる。</dd>
</dl>
<p>レコードを追加するには、関数 `crput' を用いる。</p>
<dl>
<dt><kbd>int crput(CURIA *<var>curia</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, const char *<var>vbuf</var>, int <var>vsiz</var>, int <var>dmode</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`vbuf' は値のデータ領域へのポインタを指定する。`vsiz' は値のデータ領域のサイズを指定するか、負数なら `strlen(vbuf)' の値となる。`dmode' はキーが既存レコードと重複した際の制御を指定する。`CR_DOVER' は既存のレコードの値を上書きし、`CR_DKEEP' は既存のレコードを残してエラーを返し、`DP_DCAT' は指定された値を既存の値の末尾に加える。戻り値は正常なら真であり、エラーなら偽である。</dd>
</dl>
<p>レコードを削除するには、関数 `crout' を用いる。</p>
<dl>
<dt><kbd>int crout(CURIA *<var>curia</var>, const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値は正常なら真であり、エラーなら偽である。該当のレコードがない場合も偽を返す。</dd>
</dl>
<p>レコードを取得するには、関数 `crget' を用いる。</p>
<dl>
<dt><kbd>char *crget(CURIA *<var>curia</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, int <var>start</var>, int <var>max</var>, int *<var>sp</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`start' は値の領域から抽出する最初のバイトのオフセットを指定する。`max' は値の領域から抽出するサイズを指定するか、負数なら無制限となる。`sp' が `NULL' でなければ、その参照先に抽出した領域のサイズを格納する。戻り値は正常なら値を格納した領域へのポインタであり、エラーなら `NULL' である。該当のレコードがない場合も `NULL' を返す。取り出そうとした値のサイズが `start' より小さかった場合には該当とみなさない。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。</dd>
</dl>
<p>レコードを取得してバッファに書き込むには、関数 `crgetwb' を用いる。</p>
<dl>
<dt><kbd>int crgetwb(CURIA *<var>curia</var>, const char *<var>kbuf</var>, int <var>ksiz</var>, int <var>start</var>, int <var>max</var>, char *<var>vbuf</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。`start' は値の領域から抽出する最初のバイトのオフセットを指定する。`max' は値の領域から抽出するサイズを指定する。それは書き込み用のバッファのサイズ以下である必要がある。`vbuf' は抽出したデータを書き込むバッファへのポインタを指定する。戻り値は正常ならバッファに書き込まれたデータのサイズであり、エラーなら -1 である。該当のレコードがない場合も -1 を返す。取り出そうとした値のサイズが `start' より小さかった場合には該当とみなさない。書き込み用バッファの末尾に終端文字が追加されないことに注意すべきである。</dd>
</dl>
<p>レコードの値のサイズを取得するには、関数 `crvsiz' を用いる。</p>
<dl>
<dt><kbd>int crvsiz(CURIA *<var>curia</var>, const char *<var>kbuf</var>, int <var>ksiz</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。`kbuf' はキーのデータ領域へのポインタを指定する。`ksiz' はキーのデータ領域のサイズを指定するか、負数なら `strlen(kbuf)' の値となる。戻り値は該当レコードの値のサイズであるが、該当がない場合やエラーの場合は -1 である。この関数はレコードの有無を調べるのにも便利である。`crget' と違って実データを読み込まないので効率がよい。</dd>
</dl>
<p>データベースのイテレータを初期化するには、関数 `criterinit' を用いる。</p>
<dl>
<dt><kbd>int criterinit(CURIA *<var>curia</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。イテレータは、データベースに格納された全てのレコードを参照するために用いられる。</dd>
</dl>
<p>データベースのイテレータから次のレコードのキーを取り出すには、関数 `criternext' を用いる。</p>
<dl>
<dt><kbd>char *criternext(CURIA *<var>curia</var>, int *<var>sp</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。`sp' が `NULL' でなければ、その参照先に抽出した領域のサイズを格納する。戻り値は正常ならキーを格納した領域へのポインタであり、エラーなら `NULL' である。イテレータが最後まできて該当のレコードがない場合も `NULL' を返す。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。この関数を繰り返して呼ぶことによって全てのレコードを一度ずつ参照することができる。ただし、繰り返しの間にデータベースの更新があった場合はその限りではない。なお、取り出すレコードの順序は制御できず、格納した順番でレコードを取り出せるとは限らない。</dd>
</dl>
<p>データベースのアラインメントを設定するには、関数 `crsetalign' を用いる。</p>
<dl>
<dt><kbd>int crsetalign(CURIA *<var>curia</var>, int <var>align</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。`align' はアラインメントのサイズを指定する。戻り値は正常なら真であり、エラーなら偽である。アラインメントを設定しておくと、レコードの上書きを頻繁にする場合の処理効率が良くなる。アラインメントには、一連の更新操作をした後の状態での標準的な値のサイズを指定するのがよい。アラインメントが正数の場合、レコードの領域のサイズがアラインメントの倍数になるようにパディングがとられる。アラインメントが負数の場合、`vsiz' を値のサイズとして、パディングのサイズは `(vsiz / pow(2, abs(align) - 1))' として算出される。アラインメントの設定はデータベースに保存されないので、データベースを開く度に指定する必要がある。</dd>
</dl>
<p>データベースのフリーブロックプールのサイズ設定するには、関数 `crsetfbpsiz' を用いる。</p>
<dl>
<dt><kbd>int crsetfbpsiz(CURIA *<var>curia</var>, int <var>size</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。`size' はフリーブロックプールのサイズを指定する。戻り値は正常なら真であり、エラーなら偽である。フリーブロックプールのデフォルトのサイズは16である。サイズをより大きくすると、レコードの上書きを繰り返す際の空間効率は上がるが、時間効率が下がる。</dd>
</dl>
<p>データベースを更新した内容をファイルとデバイスに同期させるには、関数 `crsync' を用いる。</p>
<dl>
<dt><kbd>int crsync(CURIA *<var>curia</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。この関数はデータベースを閉じないうちに別プロセスにデータベースファイルを利用させる場合に役立つ。</dd>
</dl>
<p>データベースを最適化するには、関数 `croptimize' を用いる。</p>
<dl>
<dt><kbd>int croptimize(CURIA *<var>curia</var>, int <var>bnum</var>);</kbd></dt>
<dd>`curia' はライタで接続したデータベースハンドルを指定する。`bnum' は新たなバケット配列の要素数を指定するが、0 以下なら現在のレコード数に最適な値が指定される。戻り値は正常なら真であり、エラーなら偽である。レコードを削除したり、置換モードや連結モードで書き込みを繰り返したりする場合は、データベース内に不要な領域が蓄積するが、この関数はそれを解消するのに役立つ。</dd>
</dl>
<p>データベースの名前を得るには、関数 `crname' を用いる。</p>
<dl>
<dt><kbd>char *crname(CURIA *<var>curia</var>);</kbd></dt>
<dd>`curia' はデータベースハンドルを指定する。戻り値は正常なら名前を格納した領域へのポインタであり、エラーなら `NULL' である。戻り値の領域は `malloc' で確保されるので、不要になったら `free' で解放するべきである。</dd>