bdb1 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/examples/zeroc.rb ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby -I../src
2
+
3
+ require 'bdb1'
4
+ module ZeroC
5
+ def bdb1_fetch_value(a)
6
+ a.sub(/\0$/, '')
7
+ end
8
+ def bdb1_store_value(a)
9
+ a + "\0"
10
+ end
11
+ alias bdb1_fetch_key bdb1_fetch_value
12
+ alias bdb1_store_key bdb1_store_value
13
+ end
14
+
15
+ module BDB1
16
+ class A < Btree
17
+ include ZeroC
18
+ end
19
+ end
20
+
21
+ $option = {"set_pagesize" => 1024, "set_cachesize" => 32 * 1024}
22
+
23
+ db = BDB1::A.open "basic", "w", $option
24
+ File.foreach("wordtest") do |line|
25
+ line.chomp!
26
+ db[line] = line.reverse
27
+ end
28
+ db.each do |k, v|
29
+ if k != v.reverse || /\0/ =~ k || /\0/ =~ v
30
+ print "ERROR : #{k.inspect} -- #{v.inspect}\n"
31
+ end
32
+ end
33
+ db.close
34
+
35
+ db = BDB1::Btree.open "basic", $option
36
+ db.each do |k, v|
37
+ if k[-1].to_i != 0 || v[-1].to_i != 0
38
+ print "ERROR : #{k.inspect} -- #{v.inspect}\n"
39
+ end
40
+ end
data/ext/bdb1/bdb1.c ADDED
@@ -0,0 +1,1868 @@
1
+ #include "bdb1.h"
2
+
3
+ VALUE bdb1_eFatal;
4
+ VALUE bdb1_mDb, bdb1_mMarshal, bdb1_cCommon, bdb1_cRecnum;
5
+ static ID id_dump, id_load;
6
+
7
+ ID bdb1_id_current_db;
8
+
9
+ static VALUE bdb1_cBtree, bdb1_cHash, bdb1_cUnknown;
10
+
11
+ static ID id_bt_compare, id_bt_prefix, id_h_hash, bdb1_id_call;
12
+
13
+ static VALUE bdb1_errstr;
14
+ static int bdb1_errcall = 0;
15
+
16
+ static char *
17
+ db_strerror(int err)
18
+ {
19
+ if (err == 0)
20
+ return "" ;
21
+
22
+ if (err > 0)
23
+ return strerror(err) ;
24
+
25
+ return "Unknown Error" ;
26
+ }
27
+
28
+ int
29
+ bdb1_test_error(comm)
30
+ int comm;
31
+ {
32
+ VALUE error;
33
+
34
+ switch (comm) {
35
+ case 0:
36
+ case 1:
37
+ break;
38
+ default:
39
+ error = bdb1_eFatal;
40
+ if (bdb1_errcall) {
41
+ bdb1_errcall = 0;
42
+ rb_raise(error, "%s -- %s", StringValuePtr(bdb1_errstr), db_strerror(comm));
43
+ }
44
+ else
45
+ rb_raise(error, "%s", db_strerror(errno));
46
+ }
47
+ return comm;
48
+ }
49
+
50
+ static VALUE
51
+ test_dump(obj, key, a, type_kv)
52
+ VALUE obj;
53
+ DBT *key;
54
+ VALUE a;
55
+ int type_kv;
56
+ {
57
+ bdb1_DB *dbst;
58
+ int is_nil = 0;
59
+ VALUE tmp = a;
60
+
61
+ Data_Get_Struct(obj, bdb1_DB, dbst);
62
+ if (dbst->filter[type_kv]) {
63
+ if (FIXNUM_P(dbst->filter[type_kv])) {
64
+ tmp = rb_funcall(obj, NUM2INT(dbst->filter[type_kv]), 1, a);
65
+ }
66
+ else {
67
+ tmp = rb_funcall(dbst->filter[type_kv], bdb1_id_call, 1, a);
68
+ }
69
+ }
70
+ if (dbst->marshal) {
71
+ if (rb_obj_is_kind_of(a, bdb1_cDelegate)) {
72
+ tmp = bdb1_deleg_to_orig(tmp);
73
+ }
74
+ tmp = rb_funcall(dbst->marshal, id_dump, 1, tmp);
75
+ if (TYPE(tmp) != T_STRING) {
76
+ rb_raise(rb_eTypeError, "dump() must return String");
77
+ }
78
+ }
79
+ else {
80
+ tmp = rb_obj_as_string(tmp);
81
+ if (a == Qnil)
82
+ is_nil = 1;
83
+ }
84
+ key->data = StringValuePtr(tmp);
85
+ key->size = RSTRING_LEN(tmp) + is_nil;
86
+ return tmp;
87
+ }
88
+
89
+ static VALUE
90
+ test_ret(obj, tmp, a, type_kv)
91
+ VALUE obj, tmp, a;
92
+ int type_kv;
93
+ {
94
+ bdb1_DB *dbst;
95
+ Data_Get_Struct(obj, bdb1_DB, dbst);
96
+ if (dbst->marshal || a == Qnil) {
97
+ return a;
98
+ }
99
+ if (dbst->filter[type_kv]) {
100
+ return rb_obj_as_string(a);
101
+ }
102
+ return tmp;
103
+ }
104
+
105
+ static VALUE
106
+ test_recno(obj, key, recno, a)
107
+ VALUE obj;
108
+ DBT *key;
109
+ db_recno_t *recno;
110
+ VALUE a;
111
+ {
112
+ bdb1_DB *dbst;
113
+ Data_Get_Struct(obj, bdb1_DB, dbst);
114
+ if (dbst->type == DB_RECNO) {
115
+ *recno = NUM2INT(a) + dbst->array_base;
116
+ key->data = recno;
117
+ key->size = sizeof(db_recno_t);
118
+ return a;
119
+ }
120
+ return test_dump(obj, key, a, FILTER_KEY);
121
+ }
122
+
123
+ VALUE
124
+ bdb1_test_load(obj, a, type_kv)
125
+ VALUE obj;
126
+ DBT *a;
127
+ int type_kv;
128
+ {
129
+ VALUE res;
130
+ int i;
131
+ bdb1_DB *dbst;
132
+
133
+ Data_Get_Struct(obj, bdb1_DB, dbst);
134
+ if (dbst->marshal) {
135
+ res = rb_str_new(a->data, a->size);
136
+ if (dbst->filter[2 + type_kv]) {
137
+ if (FIXNUM_P(dbst->filter[2 + type_kv])) {
138
+ res = rb_funcall(obj,
139
+ NUM2INT(dbst->filter[2 + type_kv]), 1, res);
140
+ }
141
+ else {
142
+ res = rb_funcall(dbst->filter[2 + type_kv],
143
+ bdb1_id_call, 1, res);
144
+ }
145
+ }
146
+ res = rb_funcall(dbst->marshal, id_load, 1, res);
147
+ }
148
+ else {
149
+ if (a->size == 1 && ((char *)a->data)[0] == '\000') {
150
+ res = Qnil;
151
+ }
152
+ else {
153
+ res = rb_tainted_str_new(a->data, a->size);
154
+ if (dbst->filter[2 + type_kv]) {
155
+ if (FIXNUM_P(dbst->filter[2 + type_kv])) {
156
+ res = rb_funcall(obj,
157
+ NUM2INT(dbst->filter[2 + type_kv]),
158
+ 1, res);
159
+ }
160
+ else {
161
+ res = rb_funcall(dbst->filter[2 + type_kv],
162
+ bdb1_id_call, 1, res);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ return res;
168
+ }
169
+
170
+ static VALUE
171
+ test_load_dyna(obj, key, val)
172
+ VALUE obj;
173
+ DBT *key, *val;
174
+ {
175
+ bdb1_DB *dbst;
176
+ VALUE del, res, tmp;
177
+ struct deleg_class *delegst;
178
+
179
+ Data_Get_Struct(obj, bdb1_DB, dbst);
180
+ res = bdb1_test_load(obj, val, FILTER_VALUE);
181
+ if (dbst->marshal && !SPECIAL_CONST_P(res)) {
182
+ del = Data_Make_Struct(bdb1_cDelegate, struct deleg_class,
183
+ bdb1_deleg_mark, bdb1_deleg_free, delegst);
184
+ delegst->db = obj;
185
+ if (dbst->type == DB_RECNO) {
186
+ tmp = INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
187
+ }
188
+ else {
189
+ tmp = rb_str_new(key->data, key->size);
190
+ }
191
+ delegst->key = rb_funcall(dbst->marshal, id_load, 1, tmp);
192
+ delegst->obj = res;
193
+ res = del;
194
+ }
195
+ return res;
196
+ }
197
+
198
+
199
+ static int
200
+ bdb1_bt_compare(a, b)
201
+ DBT *a, *b;
202
+ {
203
+ VALUE obj, av, bv, res;
204
+ bdb1_DB *dbst;
205
+
206
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
207
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
208
+ }
209
+ Data_Get_Struct(obj, bdb1_DB, dbst);
210
+ av = bdb1_test_load(obj, a, FILTER_VALUE);
211
+ bv = bdb1_test_load(obj, b, FILTER_VALUE);
212
+ if (dbst->bt_compare == 0)
213
+ res = rb_funcall(obj, id_bt_compare, 2, av, bv);
214
+ else
215
+ res = rb_funcall(dbst->bt_compare, bdb1_id_call, 2, av, bv);
216
+ return NUM2INT(res);
217
+ }
218
+
219
+ static size_t
220
+ bdb1_bt_prefix(a, b)
221
+ DBT *a, *b;
222
+ {
223
+ VALUE obj, av, bv, res;
224
+ bdb1_DB *dbst;
225
+
226
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
227
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
228
+ }
229
+ Data_Get_Struct(obj, bdb1_DB, dbst);
230
+ av = bdb1_test_load(obj, a, FILTER_VALUE);
231
+ bv = bdb1_test_load(obj, b, FILTER_VALUE);
232
+ if (dbst->bt_prefix == 0)
233
+ res = rb_funcall(obj, id_bt_prefix, 2, av, bv);
234
+ else
235
+ res = rb_funcall(dbst->bt_prefix, bdb1_id_call, 2, av, bv);
236
+ return NUM2INT(res);
237
+ }
238
+
239
+ static u_int32_t
240
+ bdb1_h_hash(bytes, length)
241
+ void *bytes;
242
+ u_int32_t length;
243
+ {
244
+ VALUE obj, st, res;
245
+ bdb1_DB *dbst;
246
+
247
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
248
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
249
+ }
250
+ Data_Get_Struct(obj, bdb1_DB, dbst);
251
+ st = rb_tainted_str_new((char *)bytes, length);
252
+ if (dbst->h_hash == 0)
253
+ res = rb_funcall(obj, id_h_hash, 1, st);
254
+ else
255
+ res = rb_funcall(dbst->h_hash, bdb1_id_call, 1, st);
256
+ return NUM2UINT(res);
257
+ }
258
+
259
+ static void
260
+ bdb1_i_close(dbst)
261
+ bdb1_DB *dbst;
262
+ {
263
+ if (dbst->dbp != NULL && !(dbst->options & BDB1_NOT_OPEN)) {
264
+ dbst->options |= BDB1_NOT_OPEN;
265
+ bdb1_test_error(dbst->dbp->close(dbst->dbp));
266
+ }
267
+ dbst->dbp = NULL;
268
+ }
269
+
270
+ static void
271
+ bdb1_free(dbst)
272
+ bdb1_DB *dbst;
273
+ {
274
+ bdb1_i_close(dbst);
275
+ free(dbst);
276
+ }
277
+
278
+ static void
279
+ bdb1_mark(dbst)
280
+ bdb1_DB *dbst;
281
+ {
282
+ int i;
283
+
284
+ rb_gc_mark(dbst->marshal);
285
+ rb_gc_mark(dbst->bt_compare);
286
+ rb_gc_mark(dbst->bt_prefix);
287
+ rb_gc_mark(dbst->h_hash);
288
+ for (i = 0; i < 4; i++) {
289
+ rb_gc_mark(dbst->filter[i]);
290
+ }
291
+ }
292
+
293
+ static VALUE
294
+ bdb1_i185_btree(obj, dbstobj)
295
+ VALUE obj, dbstobj;
296
+ {
297
+ VALUE key, value;
298
+ bdb1_DB *dbst;
299
+ char *options;
300
+
301
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
302
+ key = rb_ary_entry(obj, 0);
303
+ value = rb_ary_entry(obj, 1);
304
+ key = rb_obj_as_string(key);
305
+ options = StringValuePtr(key);
306
+ if (strcmp(options, "set_flags") == 0) {
307
+ dbst->has_info = Qtrue;
308
+ dbst->info.bi.flags = NUM2INT(value);
309
+ }
310
+ else if (strcmp(options, "set_cachesize") == 0) {
311
+ dbst->has_info = Qtrue;
312
+ dbst->info.bi.cachesize = NUM2INT(value);
313
+ }
314
+ else if (strcmp(options, "set_bt_minkey") == 0) {
315
+ dbst->has_info = Qtrue;
316
+ dbst->info.bi.minkeypage = NUM2INT(value);
317
+ }
318
+ else if (strcmp(options, "set_pagesize") == 0) {
319
+ dbst->has_info = Qtrue;
320
+ dbst->info.bi.psize = NUM2INT(value);
321
+ }
322
+ else if (strcmp(options, "set_bt_compare") == 0) {
323
+ if (!rb_respond_to(value, bdb1_id_call)) {
324
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
325
+ }
326
+ dbst->has_info = Qtrue;
327
+ dbst->options |= BDB1_BT_COMPARE;
328
+ dbst->bt_compare = value;
329
+ dbst->info.bi.compare = bdb1_bt_compare;
330
+ }
331
+ else if (strcmp(options, "set_bt_prefix") == 0) {
332
+ if (!rb_respond_to(value, bdb1_id_call)) {
333
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
334
+ }
335
+ dbst->has_info = Qtrue;
336
+ dbst->options |= BDB1_BT_PREFIX;
337
+ dbst->bt_prefix = value;
338
+ dbst->info.bi.prefix = bdb1_bt_prefix;
339
+ }
340
+ else if (strcmp(options, "set_lorder") == 0) {
341
+ dbst->has_info = Qtrue;
342
+ dbst->info.bi.lorder = NUM2INT(value);
343
+ }
344
+ return Qnil;
345
+ }
346
+
347
+ static VALUE
348
+ bdb1_i185_hash(obj, dbstobj)
349
+ VALUE obj, dbstobj;
350
+ {
351
+ VALUE key, value;
352
+ bdb1_DB *dbst;
353
+ char *options;
354
+
355
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
356
+ key = rb_ary_entry(obj, 0);
357
+ value = rb_ary_entry(obj, 1);
358
+ key = rb_obj_as_string(key);
359
+ options = StringValuePtr(key);
360
+ if (strcmp(options, "set_h_ffactor") == 0) {
361
+ dbst->has_info = Qtrue;
362
+ dbst->info.hi.ffactor = NUM2INT(value);
363
+ }
364
+ else if (strcmp(options, "set_h_nelem") == 0) {
365
+ dbst->has_info = Qtrue;
366
+ dbst->info.hi.nelem = NUM2INT(value);
367
+ }
368
+ else if (strcmp(options, "set_cachesize") == 0) {
369
+ dbst->has_info = Qtrue;
370
+ dbst->info.hi.cachesize = NUM2INT(value);
371
+ }
372
+ else if (strcmp(options, "set_h_hash") == 0) {
373
+ if (!rb_respond_to(value, bdb1_id_call)) {
374
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
375
+ }
376
+ dbst->has_info = Qtrue;
377
+ dbst->options |= BDB1_H_HASH;
378
+ dbst->h_hash = value;
379
+ dbst->info.hi.hash = bdb1_h_hash;
380
+ }
381
+ else if (strcmp(options, "set_lorder") == 0) {
382
+ dbst->has_info = Qtrue;
383
+ dbst->info.hi.lorder = NUM2INT(value);
384
+ }
385
+ return Qnil;
386
+ }
387
+
388
+ static VALUE
389
+ bdb1_i185_recno(obj, dbstobj)
390
+ VALUE obj, dbstobj;
391
+ {
392
+ VALUE key, value;
393
+ bdb1_DB *dbst;
394
+ char *options, *str;
395
+
396
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
397
+ key = rb_ary_entry(obj, 0);
398
+ value = rb_ary_entry(obj, 1);
399
+ key = rb_obj_as_string(key);
400
+ options = StringValuePtr(key);
401
+ if (strcmp(options, "set_flags") == 0) {
402
+ dbst->has_info = Qtrue;
403
+ dbst->info.ri.flags = NUM2INT(value);
404
+ }
405
+ else if (strcmp(options, "set_re_delim") == 0) {
406
+ int ch;
407
+ if (TYPE(value) == T_STRING) {
408
+ str = StringValuePtr(value);
409
+ dbst->info.ri.bval = str[0];
410
+ }
411
+ else {
412
+ dbst->info.ri.bval = NUM2INT(value);
413
+ }
414
+ dbst->has_info = Qtrue;
415
+ dbst->info.ri.flags |= R_FIXEDLEN;
416
+ }
417
+ else if (strcmp(options, "set_re_len") == 0) {
418
+ dbst->has_info = Qtrue;
419
+ dbst->info.ri.reclen = NUM2INT(value);
420
+ dbst->info.ri.flags |= R_FIXEDLEN;
421
+ }
422
+ else if (strcmp(options, "set_re_pad") == 0) {
423
+ int ch;
424
+ if (TYPE(value) == T_STRING) {
425
+ str = StringValuePtr(value);
426
+ dbst->info.ri.bval = str[0];
427
+ }
428
+ else {
429
+ dbst->info.ri.bval = NUM2INT(value);
430
+ }
431
+ dbst->has_info = Qtrue;
432
+ dbst->info.ri.flags |= R_FIXEDLEN;
433
+ }
434
+ else if (strcmp(options, "set_cachesize") == 0) {
435
+ dbst->has_info = Qtrue;
436
+ dbst->info.ri.cachesize = NUM2INT(value);
437
+ }
438
+ else if (strcmp(options, "set_pagesize") == 0) {
439
+ dbst->has_info = Qtrue;
440
+ dbst->info.ri.psize = NUM2INT(value);
441
+ }
442
+ else if (strcmp(options, "set_lorder") == 0) {
443
+ dbst->has_info = Qtrue;
444
+ dbst->info.ri.lorder = NUM2INT(value);
445
+ }
446
+ else if (strcmp(options, "set_array_base") == 0 ||
447
+ strcmp(options, "array_base") == 0) {
448
+ int ary_base = NUM2INT(value);
449
+ switch (ary_base) {
450
+ case 0: dbst->array_base = 1; break;
451
+ case 1: dbst->array_base = 0; break;
452
+ default: rb_raise(bdb1_eFatal, "array base must be 0 or 1");
453
+ }
454
+ }
455
+ return Qnil;
456
+ }
457
+
458
+ static VALUE
459
+ bdb1_load_dump(obj)
460
+ VALUE obj;
461
+ {
462
+ VALUE res;
463
+
464
+ res = rb_funcall(obj, rb_intern("respond_to?"), 2, ID2SYM(id_load), Qtrue);
465
+ if (RTEST(res)) {
466
+ res = rb_funcall(obj, rb_intern("respond_to?"), 2, ID2SYM(id_dump), Qtrue);
467
+ }
468
+ return res;
469
+ }
470
+
471
+ static VALUE
472
+ bdb1_i185_common(obj, dbstobj)
473
+ VALUE obj, dbstobj;
474
+ {
475
+ VALUE key, value;
476
+ bdb1_DB *dbst;
477
+ char *options;
478
+
479
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
480
+ key = rb_ary_entry(obj, 0);
481
+ value = rb_ary_entry(obj, 1);
482
+ key = rb_obj_as_string(key);
483
+ options = StringValuePtr(key);
484
+ if (strcmp(options, "marshal") == 0) {
485
+ switch (value) {
486
+ case Qtrue:
487
+ dbst->marshal = bdb1_mMarshal;
488
+ dbst->options |= BDB1_MARSHAL;
489
+ break;
490
+ case Qfalse:
491
+ dbst->marshal = Qfalse;
492
+ dbst->options &= ~BDB1_MARSHAL;
493
+ break;
494
+ default:
495
+ if (!RTEST(bdb1_load_dump(value))) {
496
+ rb_raise(bdb1_eFatal, "marshal value must be true or false");
497
+ }
498
+ dbst->marshal = value;
499
+ dbst->options |= BDB1_MARSHAL;
500
+ break;
501
+ }
502
+ }
503
+ else if (strcmp(options, "set_store_key") == 0) {
504
+ if (!rb_respond_to(value, bdb1_id_call)) {
505
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
506
+ }
507
+ dbst->filter[FILTER_KEY] = value;
508
+ }
509
+ else if (strcmp(options, "set_fetch_key") == 0) {
510
+ if (!rb_respond_to(value, bdb1_id_call)) {
511
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
512
+ }
513
+ dbst->filter[2 + FILTER_KEY] = value;
514
+ }
515
+ else if (strcmp(options, "set_store_value") == 0) {
516
+ if (!rb_respond_to(value, bdb1_id_call)) {
517
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
518
+ }
519
+ dbst->filter[FILTER_VALUE] = value;
520
+ }
521
+ else if (strcmp(options, "set_fetch_value") == 0) {
522
+ if (!rb_respond_to(value, bdb1_id_call)) {
523
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
524
+ }
525
+ dbst->filter[2 + FILTER_VALUE] = value;
526
+ }
527
+ return Qnil;
528
+ }
529
+
530
+ static int
531
+ bdb1_hard_count(dbp)
532
+ DB *dbp;
533
+ {
534
+ DBT key, data;
535
+ db_recno_t recno;
536
+ long count = 0;
537
+
538
+ DATA_ZERO(key);
539
+ key.data = &recno;
540
+ key.size = sizeof(db_recno_t);
541
+ DATA_ZERO(data);
542
+ if (bdb1_test_error(dbp->seq(dbp, &key, &data, DB_LAST)) == 0) {
543
+ count = *(db_recno_t *)key.data;
544
+ }
545
+ return count;
546
+ }
547
+
548
+ /*
549
+ * call-seq:
550
+ *
551
+ * BDB1::Btree.new(name = nil, flags = "r", mode = 0, options = {})
552
+ * BDB1::Hash.new(name = nil, flags = "r", mode = 0, options = {})
553
+ * BDB1::Recnum.new(name = nil, flags = "r", mode = 0, options = {})
554
+ *
555
+ * Open the database.
556
+ *
557
+ * * +name+
558
+ * The argument name is used as the name of a single physical
559
+ * file on disk that will be used to back the database.
560
+ *
561
+ * If +nil+ is given, an on-memory database is created.
562
+ *
563
+ * * +flags+
564
+ * The flags must be the string "r", "r+", "w", "w+", "a", "a+" or
565
+ * and integer value.
566
+ *
567
+ * The flags value must be set to 0 or by bitwise inclusively
568
+ * OR'ing together one or more of the following values
569
+ *
570
+ * * +BDB1::CREATE+
571
+ * Create any underlying files, as necessary. If the files
572
+ * do not already exist and the DB_CREATE flag is not
573
+ * specified, the call will fail.
574
+ *
575
+ * * +BDB1::RDONLY+
576
+ * Open the database for reading only. Any attempt to
577
+ * modify items in the database will fail regardless of the
578
+ * actual permissions of any underlying files.
579
+ *
580
+ * * +BDB1::TRUNCATE+
581
+ * Physically truncate the underlying database file,
582
+ * discarding all previous subdatabases or databases.
583
+ * Underlying filesystem primitives are used to implement
584
+ * this flag. For this reason it is only applicable to the
585
+ * physical database file and cannot be used to discard
586
+ * subdatabases.
587
+ *
588
+ * The DB_TRUNCATE flag cannot be transaction protected,
589
+ * and it is an error to specify it in a transaction
590
+ * protected environment.
591
+ *
592
+ * * +BDB1::WRITE+
593
+ * Open the database for writing. Without this flag, any
594
+ * attempt to modify items in the database will fail.
595
+ *
596
+ * * +mode+
597
+ * mode to create the file
598
+ *
599
+ * * +options+
600
+ * Hash, Possible options are (see the documentation of Berkeley DB
601
+ * for more informations)
602
+ *
603
+ * * +set_flags+: general database configuration
604
+ * * +set_cachesize+: set the database cache size
605
+ * * +set_pagesize+: set the underlying database page size
606
+ * * +set_lorder+: set the database byte order
607
+ * * +set_store_key+: specify a Proc called before a key is stored
608
+ * * +set_fetch_key+: specify a Proc called after a key is read
609
+ * * +set_store_value+: specify a Proc called before a value is stored
610
+ * * +set_fetch_value+: specify a Proc called after a value is read
611
+ *
612
+ * * +options specific to BDB1::Btree+
613
+ *
614
+ * * +set_bt_compare+: specify a Btree comparison function
615
+ * * +set_bt_minkey+: set the minimum number of keys per Btree page
616
+ * * +set_bt_prefix+: specify a Btree prefix comparison function
617
+ *
618
+ * * +options specific to BDB1::Hash+
619
+ *
620
+ * * +set_h_ffactor+: set the Hash table density
621
+ * * +set_h_hash+: specify a hashing function
622
+ * * +set_h_nelem+: set the Hash table size
623
+ *
624
+ * * +options specific to BDB1::Recnum+
625
+ *
626
+ * * +set_re_delim+: set the variable-length record delimiter
627
+ * * +set_re_len+: set the fixed-length record length
628
+ * * +set_re_pad+: set the fixed-length record pad byte
629
+ *
630
+ * Proc given to +set_bt_compare+, +set_bt_prefix+,
631
+ * +set_h_hash+, +set_store_key+, +set_fetch_key+,
632
+ * +set_store_value+ and +set_fetch_value+ can be also
633
+ * specified as a method (replace the prefix +set_+ with
634
+ * +bdb1_+)
635
+ *
636
+ * For example:
637
+ *
638
+ * module BDB1
639
+ * class Btreesort < Btree
640
+ * def bdb1_bt_compare(a, b)
641
+ * b.downcase <=> a.downcase
642
+ * end
643
+ * end
644
+ * end
645
+ */
646
+ VALUE
647
+ bdb1_init(argc, argv, obj)
648
+ int argc;
649
+ VALUE *argv;
650
+ VALUE obj;
651
+ {
652
+ VALUE b, c, d, f;
653
+ int mode, oflags;
654
+ char *name;
655
+ bdb1_DB *dbst;
656
+ void *openinfo = NULL;
657
+
658
+ f = Qnil; name = NULL;
659
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
660
+ oflags = DB_RDONLY;
661
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
662
+ f = argv[argc - 1];
663
+ argc--;
664
+ }
665
+ switch(rb_scan_args(argc, argv, "03", &b, &c, &d)) {
666
+ case 3:
667
+ mode = NUM2INT(d);
668
+ /* ... */
669
+ case 2:
670
+ if (TYPE(c) == T_STRING) {
671
+ char *m = StringValuePtr(c);
672
+ if (strcmp(m, "r") == 0) {
673
+ oflags = DB_RDONLY;
674
+ }
675
+ else if (strcmp(m, "r+") == 0) {
676
+ oflags = DB_WRITE;
677
+ }
678
+ else if (strcmp(m, "w") == 0 || strcmp(m, "w+") == 0) {
679
+ oflags = DB_CREATE | DB_TRUNCATE | DB_WRITE;
680
+ }
681
+ else if (strcmp(m, "a") == 0 || strcmp(m, "a+") == 0) {
682
+ oflags = DB_CREATE | DB_WRITE;
683
+ }
684
+ else {
685
+ rb_raise(bdb1_eFatal, "flags must be r, r+, w, w+, a or a+");
686
+ }
687
+ }
688
+ else if (c == Qnil) {
689
+ oflags = DB_RDONLY;
690
+ }
691
+ else {
692
+ oflags = NUM2INT(c);
693
+ }
694
+ /* ... */
695
+ case 1:
696
+ if (!NIL_P(b)) {
697
+ SafeStringValue(b);
698
+ name = StringValuePtr(b);
699
+ }
700
+ else {
701
+ name = NULL;
702
+ }
703
+ /* ... */
704
+ }
705
+ Data_Get_Struct(obj, bdb1_DB, dbst);
706
+ if (dbst->type < DB_BTREE || dbst->type > DB_RECNO) {
707
+ rb_raise(bdb1_eFatal, "Unknown db185 type %d", dbst->type);
708
+ }
709
+ if (!NIL_P(f)) {
710
+ if (TYPE(f) != T_HASH) {
711
+ rb_raise(bdb1_eFatal, "options must be an hash");
712
+ }
713
+ switch(dbst->type) {
714
+ case 0:
715
+ rb_iterate(rb_each, f, bdb1_i185_btree, obj);
716
+ if (dbst->bt_compare == 0 && rb_respond_to(obj, id_bt_compare)) {
717
+ dbst->has_info = Qtrue;
718
+ dbst->options |= BDB1_BT_COMPARE;
719
+ dbst->info.bi.compare = bdb1_bt_compare;
720
+ }
721
+ if (dbst->bt_prefix == 0 && rb_respond_to(obj, id_bt_prefix)) {
722
+ dbst->has_info = Qtrue;
723
+ dbst->options |= BDB1_BT_PREFIX;
724
+ dbst->info.bi.prefix = bdb1_bt_prefix;
725
+ }
726
+ break;
727
+ case 1:
728
+ rb_iterate(rb_each, f, bdb1_i185_hash, obj);
729
+ if (dbst->h_hash == 0 && rb_respond_to(obj, id_h_hash)) {
730
+ dbst->has_info = Qtrue;
731
+ dbst->options |= BDB1_H_HASH;
732
+ dbst->info.hi.hash = bdb1_h_hash;
733
+ }
734
+ break;
735
+ case 2:
736
+ rb_iterate(rb_each, f, bdb1_i185_recno, obj);
737
+ break;
738
+ }
739
+ rb_iterate(rb_each, f, bdb1_i185_common, obj);
740
+ }
741
+ if (name == NULL) oflags = O_CREAT | O_RDWR;
742
+ if (dbst->has_info) openinfo = &dbst->info;
743
+ dbst->dbp = dbopen(name, oflags, mode, dbst->type, openinfo);
744
+ if (dbst->dbp == NULL) {
745
+ rb_raise(bdb1_eFatal, "Failed `%s'", db_strerror(errno));
746
+ }
747
+ dbst->options &= ~BDB1_NOT_OPEN;
748
+ if (dbst->type == 2) {
749
+ dbst->len = bdb1_hard_count(dbst->dbp);
750
+ }
751
+ return obj;
752
+ }
753
+
754
+ /*
755
+ * call-seq:
756
+ * db.close(flags = 0)
757
+ *
758
+ * Closes the file.
759
+ */
760
+ static VALUE
761
+ bdb1_close(obj)
762
+ VALUE obj;
763
+ {
764
+ VALUE opt;
765
+ bdb1_DB *dbst;
766
+
767
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
768
+ rb_raise(rb_eSecurityError, "Insecure: can't close the database");
769
+ }
770
+ Data_Get_Struct(obj, bdb1_DB, dbst);
771
+ bdb1_i_close(dbst);
772
+ return Qnil;
773
+ }
774
+
775
+ VALUE
776
+ bdb1_s_alloc(obj)
777
+ VALUE obj;
778
+ {
779
+ bdb1_DB *dbst;
780
+ VALUE res, cl;
781
+
782
+ res = Data_Make_Struct(obj, bdb1_DB, bdb1_mark, bdb1_free, dbst);
783
+ dbst->options |= BDB1_NOT_OPEN;
784
+ cl = obj;
785
+ while (cl) {
786
+ if (cl == bdb1_cBtree || RCLASS(cl)->m_tbl == RCLASS(bdb1_cBtree)->m_tbl) {
787
+ dbst->type = DB_BTREE;
788
+ break;
789
+ }
790
+ else if (cl == bdb1_cHash || RCLASS(cl)->m_tbl == RCLASS(bdb1_cHash)->m_tbl) {
791
+ dbst->type = DB_HASH;
792
+ break;
793
+ }
794
+ else if (cl == bdb1_cRecnum || RCLASS(cl)->m_tbl == RCLASS(bdb1_cRecnum)->m_tbl) {
795
+ dbst->type = DB_RECNO;
796
+ break;
797
+ }
798
+ cl = RCLASS(cl)->super;
799
+ }
800
+ if (!cl) {
801
+ rb_raise(bdb1_eFatal, "unknown database type");
802
+ }
803
+ if (RTEST(bdb1_load_dump(obj))) {
804
+ dbst->marshal = obj;
805
+ dbst->options |= BDB1_MARSHAL;
806
+ }
807
+ if (rb_method_boundp(obj, rb_intern("bdb1_store_key"), 0) == Qtrue) {
808
+ dbst->filter[FILTER_KEY] = INT2FIX(rb_intern("bdb1_store_key"));
809
+ }
810
+ if (rb_method_boundp(obj, rb_intern("bdb1_fetch_key"), 0) == Qtrue) {
811
+ dbst->filter[2 + FILTER_KEY] = INT2FIX(rb_intern("bdb1_fetch_key"));
812
+ }
813
+ if (rb_method_boundp(obj, rb_intern("bdb1_store_value"), 0) == Qtrue) {
814
+ dbst->filter[FILTER_VALUE] = INT2FIX(rb_intern("bdb1_store_value"));
815
+ }
816
+ if (rb_method_boundp(obj, rb_intern("bdb1_fetch_value"), 0) == Qtrue) {
817
+ dbst->filter[2 + FILTER_VALUE] = INT2FIX(rb_intern("bdb1_fetch_value"));
818
+ }
819
+ return res;
820
+ }
821
+
822
+ /*
823
+ * Same as +new+.
824
+ */
825
+ static VALUE
826
+ bdb1_s_create(argc, argv, obj)
827
+ int argc;
828
+ VALUE *argv;
829
+ VALUE obj;
830
+ {
831
+ VALUE st, res;
832
+
833
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
834
+ rb_obj_call_init(res, argc, argv);
835
+ return res;
836
+ }
837
+
838
+ static VALUE
839
+ bdb1_i_create(obj, db)
840
+ VALUE obj, db;
841
+ {
842
+ VALUE tmp[2];
843
+ tmp[0] = rb_ary_entry(obj, 0);
844
+ tmp[1] = rb_ary_entry(obj, 1);
845
+ bdb1_put(2, tmp, db);
846
+ return Qnil;
847
+ }
848
+
849
+ /*
850
+ * call-seq:
851
+ * BDB1::Btree[hash]
852
+ * BDB1::Btree[key1, value1, key2, value2, ...]
853
+ * BDB1::Hash[hash]
854
+ * BDB1::Hash[key1, value1, key2, value2, ...]
855
+ * BDB1::Recnum[hash]
856
+ * BDB1::Recnum[key1, value1, key2, value2, ...]
857
+ *
858
+ * Creates a new temporary on-memory database, populated with the
859
+ * given hash or pairs of objects.
860
+ */
861
+ static VALUE
862
+ bdb1_s_aref(argc, argv, obj)
863
+ int argc;
864
+ VALUE *argv;
865
+ VALUE obj;
866
+ {
867
+ VALUE res, tmp[2];
868
+ int i;
869
+
870
+ res = rb_funcall2(obj, rb_intern("new"), 0, 0);
871
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
872
+ rb_iterate(rb_each, argv[0], bdb1_i_create, res);
873
+ return res;
874
+ }
875
+ if (argc % 2 != 0) {
876
+ rb_raise(rb_eArgError, "odd number args for %s", rb_class2name(obj));
877
+ }
878
+ for (i = 0; i < argc; i += 2) {
879
+ bdb1_put(2, argv + i, res);
880
+ }
881
+ return res;
882
+ }
883
+
884
+ /*
885
+ * Same as +new+ except that if a block is given it is called with an
886
+ * initialized object which is automatically closed when done.
887
+ */
888
+ static VALUE
889
+ bdb1_s_open(argc, argv, obj)
890
+ int argc;
891
+ VALUE *argv;
892
+ VALUE obj;
893
+ {
894
+ VALUE res = rb_funcall2(obj, rb_intern("new"), argc, argv);
895
+ if (rb_block_given_p()) {
896
+ return rb_ensure(rb_yield, res, bdb1_close, res);
897
+ }
898
+ return res;
899
+ }
900
+
901
+ /*
902
+ * call-seq:
903
+ * db.put(key, value, flags = 0)
904
+ *
905
+ * Stores the +value+ associating with +key+ and returns the value
906
+ * stored.
907
+ *
908
+ * +flags+ can have the value +DBD::NOOVERWRITE+, in this case it will
909
+ * return +nil+ if the specified key exist, otherwise +true+.
910
+ */
911
+ VALUE
912
+ bdb1_put(argc, argv, obj)
913
+ int argc;
914
+ VALUE *argv;
915
+ VALUE obj;
916
+ {
917
+ volatile VALUE a0 = Qnil;
918
+ volatile VALUE b0 = Qnil;
919
+ VALUE a, b, c;
920
+ bdb1_DB *dbst;
921
+ DBT key, data;
922
+ int ret, flags;
923
+ db_recno_t recno;
924
+
925
+ rb_secure(4);
926
+ GetDB(obj, dbst);
927
+ flags = 0;
928
+ a = b = c = Qnil;
929
+ if (rb_scan_args(argc, argv, "21", &a, &b, &c) == 3) {
930
+ flags = NUM2INT(c);
931
+ }
932
+ DATA_ZERO(key);
933
+ DATA_ZERO(data);
934
+ a0 = test_recno(obj, &key, &recno, a);
935
+ b0 = test_dump(obj, &data, b, FILTER_VALUE);
936
+ ret = bdb1_test_error(dbst->dbp->put(dbst->dbp, &key, &data, flags));
937
+ if (ret == DB_KEYEXIST)
938
+ return Qfalse;
939
+ else {
940
+ return test_ret(obj, b0, b, FILTER_VALUE);
941
+ }
942
+ }
943
+
944
+ static VALUE
945
+ bdb1_assign(obj, a, b)
946
+ VALUE obj, a, b;
947
+ {
948
+ VALUE tmp[2];
949
+ tmp[0] = a;
950
+ tmp[1] = b;
951
+ bdb1_put(2, tmp, obj);
952
+ return b;
953
+ }
954
+
955
+ static VALUE
956
+ test_load_key(obj, key)
957
+ VALUE obj;
958
+ DBT *key;
959
+ {
960
+ bdb1_DB *dbst;
961
+ Data_Get_Struct(obj, bdb1_DB, dbst);
962
+ if (dbst->type == DB_RECNO)
963
+ return INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
964
+ return bdb1_test_load(obj, key, FILTER_KEY);
965
+ }
966
+
967
+ static VALUE
968
+ bdb1_assoc(obj, key, data)
969
+ VALUE obj;
970
+ DBT *key, *data;
971
+ {
972
+ return rb_assoc_new(test_load_key(obj, key),
973
+ bdb1_test_load(obj, data, FILTER_VALUE));
974
+ }
975
+
976
+ static VALUE
977
+ bdb1_assoc_dyna(obj, key, data)
978
+ VALUE obj;
979
+ DBT *key, *data;
980
+ {
981
+ return rb_assoc_new(test_load_key(obj, key),
982
+ test_load_dyna(obj, key, data));
983
+ }
984
+
985
+ static VALUE
986
+ bdb1_get_internal(argc, argv, obj, notfound, dyna)
987
+ int argc;
988
+ VALUE *argv;
989
+ VALUE obj;
990
+ VALUE notfound;
991
+ int dyna;
992
+ {
993
+ volatile VALUE a = Qnil;
994
+ VALUE b, c;
995
+ bdb1_DB *dbst;
996
+ DBT key, data;
997
+ DBT datas;
998
+ int flagss;
999
+ int ret, flags;
1000
+ db_recno_t recno;
1001
+
1002
+ flagss = flags = 0;
1003
+ GetDB(obj, dbst);
1004
+ DATA_ZERO(key);
1005
+ DATA_ZERO(data);
1006
+ switch(rb_scan_args(argc, argv, "12", &a, &b, &c)) {
1007
+ case 3:
1008
+ flags = NUM2INT(c);
1009
+ break;
1010
+ case 2:
1011
+ flagss = flags = NUM2INT(b);
1012
+ break;
1013
+ }
1014
+ a = test_recno(obj, &key, &recno, a);
1015
+ ret = bdb1_test_error(dbst->dbp->get(dbst->dbp, &key, &data, flags));
1016
+ if (ret == DB_NOTFOUND)
1017
+ return notfound;
1018
+ if (dyna) {
1019
+ return test_load_dyna(obj, &key, &data);
1020
+ }
1021
+ else {
1022
+ return bdb1_test_load(obj, &data, FILTER_VALUE);
1023
+ }
1024
+ }
1025
+
1026
+ VALUE
1027
+ bdb1_get(argc, argv, obj)
1028
+ int argc;
1029
+ VALUE *argv;
1030
+ VALUE obj;
1031
+ {
1032
+ return bdb1_get_internal(argc, argv, obj, Qnil, 0);
1033
+ }
1034
+
1035
+ /*
1036
+ * call-seq:
1037
+ * db[key]
1038
+ * db[key, flags = 0]
1039
+ *
1040
+ * Returns the value corresponding to +key+.
1041
+ */
1042
+ static VALUE
1043
+ bdb1_get_dyna(argc, argv, obj)
1044
+ int argc;
1045
+ VALUE *argv;
1046
+ VALUE obj;
1047
+ {
1048
+ return bdb1_get_internal(argc, argv, obj, Qnil, 1);
1049
+ }
1050
+
1051
+ static VALUE
1052
+ bdb1_fetch(argc, argv, obj)
1053
+ int argc;
1054
+ VALUE *argv, obj;
1055
+ {
1056
+ VALUE key, if_none;
1057
+ VALUE val;
1058
+
1059
+ rb_scan_args(argc, argv, "11", &key, &if_none);
1060
+ val = bdb1_get_internal(1, argv, obj, Qundef, 1);
1061
+ if (val == Qundef) {
1062
+ if (rb_block_given_p()) {
1063
+ if (argc > 1) {
1064
+ rb_raise(rb_eArgError, "wrong # of arguments", argc);
1065
+ }
1066
+ return rb_yield(key);
1067
+ }
1068
+ if (argc == 1) {
1069
+ rb_raise(rb_eIndexError, "key not found");
1070
+ }
1071
+ return if_none;
1072
+ }
1073
+ return val;
1074
+ }
1075
+
1076
+ static VALUE
1077
+ bdb1_has_key(obj, key)
1078
+ VALUE obj, key;
1079
+ {
1080
+ return bdb1_get_internal(1, &key, obj, Qfalse);
1081
+ }
1082
+
1083
+ /*
1084
+ * call-seq:
1085
+ * db.has_both?(key, value)
1086
+ *
1087
+ * Returns +true+ if the association from +key+ is +value+.
1088
+ */
1089
+ static VALUE
1090
+ bdb1_has_both(obj, a, b)
1091
+ VALUE obj, a, b;
1092
+ {
1093
+ bdb1_DB *dbst;
1094
+ DBT key, data;
1095
+ DBT keys, datas;
1096
+ int ret, flags;
1097
+ db_recno_t recno;
1098
+ volatile VALUE c = Qnil;
1099
+ volatile VALUE d = Qnil;
1100
+
1101
+ GetDB(obj, dbst);
1102
+ DATA_ZERO(key);
1103
+ DATA_ZERO(data);
1104
+ c = test_recno(obj, &key, &recno, a);
1105
+ d = test_dump(obj, &data, b, FILTER_VALUE);
1106
+ MEMCPY(&keys, &key, DBT, 1);
1107
+ MEMCPY(&datas, &data, DBT, 1);
1108
+ flags = (dbst->type == DB_HASH)?DB_FIRST:R_CURSOR;
1109
+ while (1) {
1110
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1111
+ if (ret == DB_NOTFOUND) {
1112
+ return Qfalse;
1113
+ }
1114
+ if (key.size == keys.size &&
1115
+ memcmp(keys.data, key.data, key.size) == 0 &&
1116
+ data.size == datas.size &&
1117
+ memcmp(datas.data, data.data, data.size) == 0) {
1118
+ return Qtrue;
1119
+ }
1120
+ flags = DB_NEXT;
1121
+ }
1122
+ return Qnil;
1123
+ }
1124
+
1125
+ /*
1126
+ * call-seq:
1127
+ * db.delete(key)
1128
+ *
1129
+ * Removes the association from the +key+.
1130
+ *
1131
+ * It returns the object deleted or +nil+ if the specified key doesn't
1132
+ * exist.
1133
+ */
1134
+ VALUE
1135
+ bdb1_del(obj, a)
1136
+ VALUE a, obj;
1137
+ {
1138
+ bdb1_DB *dbst;
1139
+ DBT key;
1140
+ int ret;
1141
+ db_recno_t recno;
1142
+ volatile VALUE c = Qnil;
1143
+
1144
+ rb_secure(4);
1145
+ GetDB(obj, dbst);
1146
+ if (dbst->type == DB_HASH) {
1147
+ rb_warning("delete can give strange result with DB_HASH");
1148
+ }
1149
+ DATA_ZERO(key);
1150
+ c = test_recno(obj, &key, &recno, a);
1151
+ ret = bdb1_test_error(dbst->dbp->del(dbst->dbp, &key, 0));
1152
+ if (ret == DB_NOTFOUND)
1153
+ return Qnil;
1154
+ else
1155
+ return obj;
1156
+ }
1157
+
1158
+ static VALUE
1159
+ bdb1_empty(obj)
1160
+ VALUE obj;
1161
+ {
1162
+ bdb1_DB *dbst;
1163
+ DBT key, data;
1164
+ int ret, flags;
1165
+ db_recno_t recno;
1166
+
1167
+ GetDB(obj, dbst);
1168
+ INIT_RECNO(dbst, key, recno);
1169
+ DATA_ZERO(data);
1170
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, DB_FIRST));
1171
+ if (ret == DB_NOTFOUND) {
1172
+ return Qtrue;
1173
+ }
1174
+ FREE_KEY(dbst, key);
1175
+ return Qfalse;
1176
+ }
1177
+
1178
+ static VALUE
1179
+ bdb1_delete_if(obj)
1180
+ VALUE obj;
1181
+ {
1182
+ bdb1_DB *dbst;
1183
+ DBT key, data, save;
1184
+ int ret, ret1, flags;
1185
+ db_recno_t recno;
1186
+
1187
+ rb_secure(4);
1188
+ GetDB(obj, dbst);
1189
+ INIT_RECNO(dbst, key, recno);
1190
+ DATA_ZERO(data);
1191
+ flags = DB_FIRST;
1192
+ do {
1193
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1194
+ if (ret == DB_NOTFOUND) {
1195
+ return Qnil;
1196
+ }
1197
+ flags = DB_NEXT;
1198
+ if (RTEST(rb_yield(bdb1_assoc(obj, &key, &data)))) {
1199
+ bdb1_test_error(dbst->dbp->del(dbst->dbp, 0, R_CURSOR));
1200
+ }
1201
+ } while (1);
1202
+ return obj;
1203
+ }
1204
+
1205
+ VALUE
1206
+ bdb1_clear(obj)
1207
+ VALUE obj;
1208
+ {
1209
+ bdb1_DB *dbst;
1210
+ DBT key, data, save;
1211
+ int ret, value, flags;
1212
+ db_recno_t recno;
1213
+
1214
+ rb_secure(4);
1215
+ GetDB(obj, dbst);
1216
+ INIT_RECNO(dbst, key, recno);
1217
+ DATA_ZERO(data);
1218
+ flags = DB_FIRST;
1219
+ value = 0;
1220
+ do {
1221
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1222
+ if (ret == DB_NOTFOUND) {
1223
+ return INT2NUM(value);
1224
+ }
1225
+ value++;
1226
+ bdb1_test_error(dbst->dbp->del(dbst->dbp, 0, R_CURSOR));
1227
+ } while (1);
1228
+ return INT2NUM(-1);
1229
+ }
1230
+
1231
+ static VALUE
1232
+ bdb1_length(obj)
1233
+ VALUE obj;
1234
+ {
1235
+ bdb1_DB *dbst;
1236
+ DBT key, data;
1237
+ int ret, value, flags;
1238
+ db_recno_t recno;
1239
+
1240
+ GetDB(obj, dbst);
1241
+ if (dbst->type == DB_RECNO) {
1242
+ return INT2NUM(bdb1_hard_count(dbst->dbp));
1243
+ }
1244
+ INIT_RECNO(dbst, key, recno);
1245
+ DATA_ZERO(data);
1246
+ value = 0;
1247
+ flags = DB_FIRST;
1248
+ do {
1249
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1250
+ if (ret == DB_NOTFOUND) {
1251
+ return INT2NUM(value);
1252
+ }
1253
+ flags = DB_NEXT;
1254
+ FREE_KEY(dbst, key);
1255
+ value++;
1256
+ } while (1);
1257
+ return INT2NUM(value);
1258
+ }
1259
+
1260
+ static VALUE
1261
+ bdb1_each_valuec(obj, sens, result)
1262
+ VALUE obj, result;
1263
+ int sens;
1264
+ {
1265
+ bdb1_DB *dbst;
1266
+ DBT key, data;
1267
+ int ret, flags;
1268
+ db_recno_t recno;
1269
+ VALUE interm, rest;
1270
+
1271
+ GetDB(obj, dbst);
1272
+ INIT_RECNO(dbst, key, recno);
1273
+ DATA_ZERO(data);
1274
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1275
+ do {
1276
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1277
+ if (ret == DB_NOTFOUND) {
1278
+ return result;
1279
+ }
1280
+ flags = sens;
1281
+ FREE_KEY(dbst, key);
1282
+ interm = bdb1_test_load(obj, &data, FILTER_VALUE);
1283
+ rest = rb_yield(interm);
1284
+ if (result != Qnil && RTEST(rest)) {
1285
+ rb_ary_push(result, interm);
1286
+ }
1287
+ } while (1);
1288
+ }
1289
+
1290
+ VALUE bdb1_each_value(obj) VALUE obj;{ return bdb1_each_valuec(obj, DB_NEXT, Qnil); }
1291
+ VALUE bdb1_each_eulav(obj) VALUE obj;{ return bdb1_each_valuec(obj, DB_PREV, Qnil); }
1292
+
1293
+ static VALUE
1294
+ bdb1_each_keyc(obj, sens)
1295
+ VALUE obj;
1296
+ int sens;
1297
+ {
1298
+ bdb1_DB *dbst;
1299
+ DBT key, data;
1300
+ int ret, flags;
1301
+ db_recno_t recno;
1302
+
1303
+ GetDB(obj, dbst);
1304
+ INIT_RECNO(dbst, key, recno);
1305
+ DATA_ZERO(data);
1306
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1307
+ do {
1308
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1309
+ if (ret == DB_NOTFOUND) {
1310
+ return Qnil;
1311
+ }
1312
+ rb_yield(test_load_key(obj, &key));
1313
+ flags = sens;
1314
+ } while (1);
1315
+ return obj;
1316
+ }
1317
+
1318
+ VALUE bdb1_each_key(obj) VALUE obj;{ return bdb1_each_keyc(obj, DB_NEXT); }
1319
+ static VALUE bdb1_each_yek(obj) VALUE obj;{ return bdb1_each_keyc(obj, DB_PREV); }
1320
+
1321
+ static VALUE
1322
+ bdb1_each_common(obj, sens)
1323
+ VALUE obj;
1324
+ int sens;
1325
+ {
1326
+ bdb1_DB *dbst;
1327
+ DBT key, data;
1328
+ int ret, flags;
1329
+ db_recno_t recno;
1330
+
1331
+ GetDB(obj, dbst);
1332
+ INIT_RECNO(dbst, key, recno);
1333
+ DATA_ZERO(data);
1334
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1335
+ do {
1336
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1337
+ if (ret == DB_NOTFOUND) {
1338
+ return Qnil;
1339
+ }
1340
+ rb_yield(bdb1_assoc(obj, &key, &data));
1341
+ flags = sens;
1342
+ } while (1);
1343
+ return obj;
1344
+ }
1345
+
1346
+ static VALUE bdb1_each_pair(obj) VALUE obj;{ return bdb1_each_common(obj, DB_NEXT); }
1347
+ static VALUE bdb1_each_riap(obj) VALUE obj;{ return bdb1_each_common(obj, DB_PREV); }
1348
+
1349
+ VALUE
1350
+ bdb1_to_type(obj, result, flag)
1351
+ VALUE obj, result, flag;
1352
+ {
1353
+ bdb1_DB *dbst;
1354
+ DBT key, data;
1355
+ int ret, flags;
1356
+ db_recno_t recno;
1357
+
1358
+ GetDB(obj, dbst);
1359
+ INIT_RECNO(dbst, key, recno);
1360
+ DATA_ZERO(data);
1361
+ flags = (flag == Qnil)?DB_LAST:DB_FIRST;
1362
+ do {
1363
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1364
+ if (ret == DB_NOTFOUND) {
1365
+ return result;
1366
+ }
1367
+ switch (TYPE(result)) {
1368
+ case T_ARRAY:
1369
+ if (flag == Qtrue) {
1370
+ rb_ary_push(result, bdb1_assoc(obj, &key, &data));
1371
+ }
1372
+ else {
1373
+ rb_ary_push(result, bdb1_test_load(obj, &data, FILTER_VALUE));
1374
+ }
1375
+ break;
1376
+ case T_HASH:
1377
+ if (flag == Qtrue) {
1378
+ rb_hash_aset(result, test_load_key(obj, &key),
1379
+ bdb1_test_load(obj, &data, FILTER_VALUE));
1380
+ }
1381
+ else {
1382
+ rb_hash_aset(result, bdb1_test_load(obj, &data, FILTER_VALUE),
1383
+ test_load_key(obj, &key));
1384
+ }
1385
+ }
1386
+ flags = (flag == Qnil)?DB_PREV:DB_NEXT;
1387
+ } while (1);
1388
+ return result;
1389
+ }
1390
+
1391
+ static VALUE
1392
+ bdb1_to_a(obj)
1393
+ VALUE obj;
1394
+ {
1395
+ return bdb1_to_type(obj, rb_ary_new(), Qtrue);
1396
+ }
1397
+
1398
+ static VALUE
1399
+ bdb1_invert(obj)
1400
+ VALUE obj;
1401
+ {
1402
+ return bdb1_to_type(obj, rb_hash_new(), Qfalse);
1403
+ }
1404
+
1405
+ static VALUE
1406
+ bdb1_to_hash(obj)
1407
+ VALUE obj;
1408
+ {
1409
+ return bdb1_to_type(obj, rb_hash_new(), Qtrue);
1410
+ }
1411
+
1412
+ static VALUE
1413
+ bdb1_each_kv(obj, a, result, flag)
1414
+ VALUE obj, a, result, flag;
1415
+ {
1416
+ bdb1_DB *dbst;
1417
+ DBT keys, key, data;
1418
+ int ret, flags;
1419
+ db_recno_t recno;
1420
+ VALUE k;
1421
+ volatile VALUE b = Qnil;
1422
+
1423
+ GetDB(obj, dbst);
1424
+ b = test_recno(obj, &key, &recno, a);
1425
+ MEMCPY(&keys, &key, DBT, 1);
1426
+ DATA_ZERO(data);
1427
+ flags = R_CURSOR;
1428
+ while (1) {
1429
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1430
+ if (ret == DB_NOTFOUND || keys.size != key.size ||
1431
+ memcmp(keys.data, key.data, key.size) != 0) {
1432
+ return (result == Qnil)?obj:result;
1433
+ }
1434
+ k = bdb1_test_load(obj, &data, FILTER_VALUE);
1435
+ if (RTEST(flag)) {
1436
+ k = rb_assoc_new(test_load_key(obj, &key), k);
1437
+ }
1438
+ if (NIL_P(result)) {
1439
+ rb_yield(k);
1440
+ }
1441
+ else {
1442
+ rb_ary_push(result, k);
1443
+ }
1444
+ flags = DB_NEXT;
1445
+ }
1446
+ return Qnil;
1447
+ }
1448
+
1449
+ /*
1450
+ * call-seq:
1451
+ * db.duplicates(key, assoc = true)
1452
+ *
1453
+ * Returns an array of all duplicate associations for the +key+.
1454
+ *
1455
+ * If +assoc+ is +false+ return only the values.
1456
+ */
1457
+ static VALUE
1458
+ bdb1_bt_duplicates(argc, argv, obj)
1459
+ int argc;
1460
+ VALUE *argv, obj;
1461
+ {
1462
+ VALUE a, b;
1463
+
1464
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 1) {
1465
+ b = Qtrue;
1466
+ }
1467
+ return bdb1_each_kv(obj, a, rb_ary_new(), b);
1468
+ }
1469
+
1470
+ /*
1471
+ * call-seq:
1472
+ * db.each_dup(key)
1473
+ *
1474
+ * Iterates over duplicate associations for the +key+.
1475
+ */
1476
+ static VALUE
1477
+ bdb1_bt_dup(obj, a)
1478
+ VALUE a, obj;
1479
+ {
1480
+ return bdb1_each_kv(obj, a, Qnil, Qtrue);
1481
+ }
1482
+
1483
+ /*
1484
+ * call-seq:
1485
+ * db.each_dup_value(key)
1486
+ *
1487
+ * Iterates over duplicate values for the +key+.
1488
+ */
1489
+ static VALUE
1490
+ bdb1_bt_dupval(obj, a)
1491
+ VALUE a, obj;
1492
+ {
1493
+ return bdb1_each_kv(obj, a, Qnil, Qfalse);
1494
+ }
1495
+
1496
+ static VALUE
1497
+ bdb1_reject(obj)
1498
+ VALUE obj;
1499
+ {
1500
+ return rb_hash_delete_if(bdb1_to_hash(obj));
1501
+ }
1502
+
1503
+ static VALUE
1504
+ bdb1_values(obj)
1505
+ VALUE obj;
1506
+ {
1507
+ bdb1_DB *dbst;
1508
+ DBT key, data;
1509
+ int ret, flags;
1510
+ db_recno_t recno;
1511
+ VALUE ary;
1512
+
1513
+ GetDB(obj, dbst);
1514
+ ary = rb_ary_new();
1515
+ INIT_RECNO(dbst, key, recno);
1516
+ DATA_ZERO(data);
1517
+ flags = DB_FIRST;
1518
+ do {
1519
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1520
+ if (ret == DB_NOTFOUND) {
1521
+ return ary;
1522
+ }
1523
+ flags = DB_NEXT;
1524
+ FREE_KEY(dbst, key);
1525
+ rb_ary_push(ary, bdb1_test_load(obj, &data, FILTER_VALUE));
1526
+ } while (1);
1527
+ return ary;
1528
+ }
1529
+
1530
+ VALUE
1531
+ bdb1_internal_value(obj, a, b, sens)
1532
+ VALUE obj, a, b;
1533
+ int sens;
1534
+ {
1535
+ bdb1_DB *dbst;
1536
+ DBT key, data;
1537
+ int ret, flags;
1538
+ db_recno_t recno;
1539
+
1540
+ GetDB(obj, dbst);
1541
+ INIT_RECNO(dbst, key, recno);
1542
+ DATA_ZERO(data);
1543
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1544
+ do {
1545
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1546
+ if (ret == DB_NOTFOUND) {
1547
+ return (b == Qfalse)?Qfalse:Qnil;
1548
+ }
1549
+ flags = sens;
1550
+ if (rb_equal(a, bdb1_test_load(obj, &data, FILTER_VALUE)) == Qtrue) {
1551
+ VALUE d;
1552
+
1553
+ d = (b == Qfalse)?Qtrue:test_load_key(obj, &key);
1554
+ FREE_KEY(dbst, key);
1555
+ return d;
1556
+ }
1557
+ FREE_KEY(dbst, key);
1558
+ } while (1);
1559
+ return (b == Qfalse)?Qfalse:Qnil;
1560
+ }
1561
+
1562
+ VALUE
1563
+ bdb1_index(obj, a)
1564
+ VALUE obj, a;
1565
+ {
1566
+ return bdb1_internal_value(obj, a, Qtrue, DB_NEXT);
1567
+ }
1568
+
1569
+ static VALUE
1570
+ bdb1_indexes(argc, argv, obj)
1571
+ int argc;
1572
+ VALUE obj, *argv;
1573
+ {
1574
+ VALUE indexes;
1575
+ int i;
1576
+
1577
+ #if HAVE_RB_ARY_VALUES_AT
1578
+ rb_warn("BDB1#%s is deprecated; use BDB1#values_at",
1579
+ #if HAVE_RB_FRAME_THIS_FUNC
1580
+ rb_id2name(rb_frame_this_func()));
1581
+ #else
1582
+ rb_id2name(rb_frame_last_func()));
1583
+ #endif
1584
+ #endif
1585
+ indexes = rb_ary_new2(argc);
1586
+ for (i = 0; i < argc; i++) {
1587
+ rb_ary_push(indexes, bdb1_get(1, argv + i, obj));
1588
+ }
1589
+ return indexes;
1590
+ }
1591
+
1592
+ VALUE
1593
+ bdb1_has_value(obj, a)
1594
+ VALUE obj, a;
1595
+ {
1596
+ return bdb1_internal_value(obj, a, Qfalse, DB_NEXT);
1597
+ }
1598
+
1599
+ static VALUE
1600
+ bdb1_keys(obj)
1601
+ VALUE obj;
1602
+ {
1603
+ bdb1_DB *dbst;
1604
+ DBT key, data;
1605
+ int ret, flags;
1606
+ db_recno_t recno;
1607
+ VALUE ary;
1608
+
1609
+ GetDB(obj, dbst);
1610
+ ary = rb_ary_new();
1611
+ INIT_RECNO(dbst, key, recno);
1612
+ DATA_ZERO(data);
1613
+ flags = DB_FIRST;
1614
+ do {
1615
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1616
+ if (ret == DB_NOTFOUND) {
1617
+ return ary;
1618
+ }
1619
+ rb_ary_push(ary, test_load_key(obj, &key));
1620
+ FREE_KEY(dbst, key);
1621
+ flags = DB_NEXT;
1622
+ } while (1);
1623
+ return ary;
1624
+ }
1625
+
1626
+ static VALUE
1627
+ bdb1_sync(obj)
1628
+ VALUE obj;
1629
+ {
1630
+ bdb1_DB *dbst;
1631
+
1632
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
1633
+ rb_raise(rb_eSecurityError, "Insecure: can't sync the database");
1634
+ GetDB(obj, dbst);
1635
+ bdb1_test_error(dbst->dbp->sync(dbst->dbp, 0));
1636
+ return Qtrue;
1637
+ }
1638
+
1639
+ #if HAVE_RB_ARY_VALUES_AT
1640
+
1641
+ static VALUE
1642
+ bdb1_values_at(argc, argv, obj)
1643
+ int argc;
1644
+ VALUE *argv, obj;
1645
+ {
1646
+ VALUE result = rb_ary_new2(argc);
1647
+ long i;
1648
+
1649
+ for (i = 0; i < argc; i++) {
1650
+ rb_ary_push(result, bdb1_get(1, argv + i, obj));
1651
+ }
1652
+ return result;
1653
+ }
1654
+
1655
+ #endif
1656
+
1657
+ #if HAVE_RB_ARY_SELECT
1658
+
1659
+ static VALUE
1660
+ bdb1_select(argc, argv, obj)
1661
+ int argc;
1662
+ VALUE *argv, obj;
1663
+ {
1664
+ VALUE result = rb_ary_new();
1665
+ long i;
1666
+
1667
+ if (rb_block_given_p()) {
1668
+ if (argc > 0) {
1669
+ rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
1670
+ }
1671
+ return bdb1_each_valuec(obj, DB_NEXT, result);
1672
+ }
1673
+ rb_warn("Common#select(index..) is deprecated; use Common#values_at");
1674
+ return bdb1_values_at(argc, argv, obj);
1675
+ }
1676
+
1677
+ #endif
1678
+
1679
+ VALUE
1680
+ bdb1_each_vc(obj, replace, rtest)
1681
+ VALUE obj;
1682
+ int replace, rtest;
1683
+ {
1684
+ bdb1_DB *dbst;
1685
+ DBT key, data;
1686
+ int ret, flags;
1687
+ db_recno_t recno;
1688
+ VALUE res, result, val;
1689
+
1690
+ GetDB(obj, dbst);
1691
+ INIT_RECNO(dbst, key, recno);
1692
+ DATA_ZERO(data);
1693
+ flags = DB_FIRST;
1694
+ result = rb_ary_new();
1695
+ do {
1696
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1697
+ if (ret == DB_NOTFOUND) {
1698
+ return result;
1699
+ }
1700
+ flags = DB_NEXT;
1701
+ FREE_KEY(dbst, key);
1702
+ val = bdb1_test_load(obj, &data, FILTER_VALUE);
1703
+ res = rb_yield(val);
1704
+ if (rtest) {
1705
+ if (RTEST(res)) {
1706
+ rb_ary_push(result, val);
1707
+ }
1708
+ }
1709
+ else {
1710
+ rb_ary_push(result, res);
1711
+ }
1712
+ if (replace == Qtrue) {
1713
+ DATA_ZERO(data);
1714
+ res = test_dump(obj, &data, res, FILTER_VALUE);
1715
+ bdb1_test_error(dbst->dbp->put(dbst->dbp, &key, &data, 0));
1716
+ }
1717
+ } while (1);
1718
+ return Qnil;
1719
+ }
1720
+
1721
+ /*
1722
+ * This interface if for the version 1.85 and 1.86 of Berkeley DB (for
1723
+ * Berkeley version >= 2 see bdb)
1724
+ *
1725
+ * Developers may choose to store data in any of several different
1726
+ * storage structures to satisfy the requirements of a particular
1727
+ * application. In database terminology, these storage structures and
1728
+ * the code that operates on them are called access methods.
1729
+ *
1730
+ * The library includes support for the following access methods:
1731
+ *
1732
+ * * BDB1::Btree
1733
+ *
1734
+ * B+tree: Stores keys in sorted order, using a default function
1735
+ * that does lexicographical ordering of keys.
1736
+ *
1737
+ * * BDB1::Hash
1738
+ *
1739
+ * Hashing: Stores records in a hash table for fast searches based
1740
+ * on strict equality, using a default that hashes on the key as a
1741
+ * bit string. Extended Linear Hashing modifies the hash function
1742
+ * used by the table as new records are inserted, in order to keep
1743
+ * buckets underfull in the steady state.
1744
+ *
1745
+ * * BDB1::Recnum
1746
+ *
1747
+ * Fixed and Variable-Length Records. Stores fixed- or
1748
+ * variable-length records in sequential order.
1749
+ *
1750
+ */
1751
+ void
1752
+ Init_bdb1()
1753
+ {
1754
+ bdb1_mMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
1755
+ id_dump = rb_intern("dump");
1756
+ id_load = rb_intern("load");
1757
+ bdb1_id_current_db = rb_intern("bdb1_current_db");
1758
+ id_bt_compare = rb_intern("bdb1_bt_compare");
1759
+ id_bt_prefix = rb_intern("bdb1_bt_prefix");
1760
+ id_h_hash = rb_intern("bdb1_h_hash");
1761
+ bdb1_id_call = rb_intern("call");
1762
+ if (rb_const_defined_at(rb_cObject, rb_intern("BDB1"))) {
1763
+ rb_raise(rb_eNameError, "class already defined");
1764
+ }
1765
+ bdb1_mDb = rb_define_module("BDB1");
1766
+ bdb1_eFatal = rb_define_class_under(bdb1_mDb, "Fatal", rb_eStandardError);
1767
+ /* CONSTANT */
1768
+ rb_define_const(bdb1_mDb, "VERSION_MAJOR", INT2FIX(DB_VERSION_MAJOR));
1769
+ rb_define_const(bdb1_mDb, "VERSION_MINOR", INT2FIX(DB_VERSION_MINOR));
1770
+ rb_define_const(bdb1_mDb, "RELEASE_PATCH", INT2FIX(DB_RELEASE_PATCH));
1771
+ rb_define_const(bdb1_mDb, "VERSION", rb_str_new2("1.x.x"));
1772
+ rb_define_const(bdb1_mDb, "BTREE", INT2FIX(DB_BTREE));
1773
+ rb_define_const(bdb1_mDb, "HASH", INT2FIX(DB_HASH));
1774
+ rb_define_const(bdb1_mDb, "RECNO", INT2FIX(DB_RECNO));
1775
+ rb_define_const(bdb1_mDb, "AFTER", INT2FIX(DB_AFTER));
1776
+ rb_define_const(bdb1_mDb, "BEFORE", INT2FIX(DB_BEFORE));
1777
+ rb_define_const(bdb1_mDb, "CREATE", INT2FIX(DB_CREATE));
1778
+ rb_define_const(bdb1_mDb, "DUP", INT2FIX(DB_DUP));
1779
+ rb_define_const(bdb1_mDb, "FIRST", INT2FIX(DB_FIRST));
1780
+ rb_define_const(bdb1_mDb, "LAST", INT2FIX(DB_LAST));
1781
+ rb_define_const(bdb1_mDb, "NEXT", INT2FIX(DB_NEXT));
1782
+ rb_define_const(bdb1_mDb, "PREV", INT2FIX(DB_PREV));
1783
+ rb_define_const(bdb1_mDb, "RDONLY", INT2FIX(DB_RDONLY));
1784
+ rb_define_const(bdb1_mDb, "SET_RANGE", INT2FIX(DB_SET_RANGE));
1785
+ rb_define_const(bdb1_mDb, "TRUNCATE", INT2FIX(DB_TRUNCATE));
1786
+ rb_define_const(bdb1_mDb, "WRITE", INT2FIX(DB_WRITE));
1787
+ rb_define_const(bdb1_mDb, "NOOVERWRITE", INT2FIX(DB_NOOVERWRITE));
1788
+ /* DATABASE */
1789
+ bdb1_cCommon = rb_define_class_under(bdb1_mDb, "Common", rb_cObject);
1790
+ rb_define_method(bdb1_cCommon, "initialize", bdb1_init, -1);
1791
+ rb_include_module(bdb1_cCommon, rb_mEnumerable);
1792
+ #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
1793
+ rb_define_alloc_func(bdb1_cCommon, bdb1_s_alloc);
1794
+ #else
1795
+ rb_define_singleton_method(bdb1_cCommon, "allocate", bdb1_s_alloc, 0);
1796
+ #endif
1797
+ rb_define_singleton_method(bdb1_cCommon, "create", bdb1_s_create, -1);
1798
+ rb_define_singleton_method(bdb1_cCommon, "open", bdb1_s_open, -1);
1799
+ rb_define_singleton_method(bdb1_cCommon, "[]", bdb1_s_aref, -1);
1800
+ rb_define_method(bdb1_cCommon, "close", bdb1_close, 0);
1801
+ rb_define_method(bdb1_cCommon, "db_close", bdb1_close, 0);
1802
+ rb_define_method(bdb1_cCommon, "put", bdb1_put, -1);
1803
+ rb_define_method(bdb1_cCommon, "db_put", bdb1_put, -1);
1804
+ rb_define_method(bdb1_cCommon, "[]=", bdb1_assign, 2);
1805
+ rb_define_method(bdb1_cCommon, "store", bdb1_put, -1);
1806
+ rb_define_method(bdb1_cCommon, "get", bdb1_get_dyna, -1);
1807
+ rb_define_method(bdb1_cCommon, "db_get", bdb1_get_dyna, -1);
1808
+ rb_define_method(bdb1_cCommon, "[]", bdb1_get_dyna, -1);
1809
+ rb_define_method(bdb1_cCommon, "fetch", bdb1_fetch, -1);
1810
+ rb_define_method(bdb1_cCommon, "delete", bdb1_del, 1);
1811
+ rb_define_method(bdb1_cCommon, "del", bdb1_del, 1);
1812
+ rb_define_method(bdb1_cCommon, "db_del", bdb1_del, 1);
1813
+ rb_define_method(bdb1_cCommon, "sync", bdb1_sync, 0);
1814
+ rb_define_method(bdb1_cCommon, "db_sync", bdb1_sync, 0);
1815
+ rb_define_method(bdb1_cCommon, "flush", bdb1_sync, 0);
1816
+ rb_define_method(bdb1_cCommon, "each", bdb1_each_pair, 0);
1817
+ rb_define_method(bdb1_cCommon, "each_value", bdb1_each_value, 0);
1818
+ rb_define_method(bdb1_cCommon, "reverse_each_value", bdb1_each_eulav, 0);
1819
+ rb_define_method(bdb1_cCommon, "each_key", bdb1_each_key, 0);
1820
+ rb_define_method(bdb1_cCommon, "reverse_each_key", bdb1_each_yek, 0);
1821
+ rb_define_method(bdb1_cCommon, "each_pair", bdb1_each_pair, 0);
1822
+ rb_define_method(bdb1_cCommon, "reverse_each", bdb1_each_riap, 0);
1823
+ rb_define_method(bdb1_cCommon, "reverse_each_pair", bdb1_each_riap, 0);
1824
+ rb_define_method(bdb1_cCommon, "keys", bdb1_keys, 0);
1825
+ rb_define_method(bdb1_cCommon, "values", bdb1_values, 0);
1826
+ rb_define_method(bdb1_cCommon, "delete_if", bdb1_delete_if, 0);
1827
+ rb_define_method(bdb1_cCommon, "reject!", bdb1_delete_if, 0);
1828
+ rb_define_method(bdb1_cCommon, "reject", bdb1_reject, 0);
1829
+ rb_define_method(bdb1_cCommon, "clear", bdb1_clear, 0);
1830
+ rb_define_method(bdb1_cCommon, "include?", bdb1_has_key, 1);
1831
+ rb_define_method(bdb1_cCommon, "has_key?", bdb1_has_key, 1);
1832
+ rb_define_method(bdb1_cCommon, "key?", bdb1_has_key, 1);
1833
+ rb_define_method(bdb1_cCommon, "member?", bdb1_has_key, 1);
1834
+ rb_define_method(bdb1_cCommon, "has_value?", bdb1_has_value, 1);
1835
+ rb_define_method(bdb1_cCommon, "value?", bdb1_has_value, 1);
1836
+ rb_define_method(bdb1_cCommon, "has_both?", bdb1_has_both, 2);
1837
+ rb_define_method(bdb1_cCommon, "both?", bdb1_has_both, 2);
1838
+ rb_define_method(bdb1_cCommon, "to_a", bdb1_to_a, 0);
1839
+ rb_define_method(bdb1_cCommon, "to_hash", bdb1_to_hash, 0);
1840
+ rb_define_method(bdb1_cCommon, "invert", bdb1_invert, 0);
1841
+ rb_define_method(bdb1_cCommon, "empty?", bdb1_empty, 0);
1842
+ rb_define_method(bdb1_cCommon, "length", bdb1_length, 0);
1843
+ rb_define_alias(bdb1_cCommon, "size", "length");
1844
+ rb_define_method(bdb1_cCommon, "index", bdb1_index, 1);
1845
+ rb_define_method(bdb1_cCommon, "indexes", bdb1_indexes, -1);
1846
+ rb_define_method(bdb1_cCommon, "indices", bdb1_indexes, -1);
1847
+ #if HAVE_RB_ARY_SELECT
1848
+ rb_define_method(bdb1_cCommon, "select", bdb1_select, -1);
1849
+ #endif
1850
+ #if HAVE_RB_ARY_VALUES_AT
1851
+ rb_define_method(bdb1_cCommon, "values_at", bdb1_values_at, -1);
1852
+ #endif
1853
+ bdb1_cBtree = rb_define_class_under(bdb1_mDb, "Btree", bdb1_cCommon);
1854
+ rb_define_method(bdb1_cBtree, "duplicates", bdb1_bt_duplicates, -1);
1855
+ rb_define_method(bdb1_cBtree, "each_dup", bdb1_bt_dup, 1);
1856
+ rb_define_method(bdb1_cBtree, "each_dup_value", bdb1_bt_dupval, 1);
1857
+ bdb1_cHash = rb_define_class_under(bdb1_mDb, "Hash", bdb1_cCommon);
1858
+ rb_undef_method(bdb1_cHash, "delete_if");
1859
+ rb_undef_method(bdb1_cHash, "reverse_each_value");
1860
+ rb_undef_method(bdb1_cHash, "reverse_each_key");
1861
+ rb_undef_method(bdb1_cHash, "reverse_each_pair");
1862
+ rb_undef_method(bdb1_cHash, "reverse_each");
1863
+ bdb1_cUnknown = rb_define_class_under(bdb1_mDb, "Unknown", bdb1_cCommon);
1864
+ bdb1_errstr = rb_tainted_str_new(0, 0);
1865
+ rb_global_variable(&bdb1_errstr);
1866
+ bdb1_init_delegator();
1867
+ bdb1_init_recnum();
1868
+ }