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/.document +5 -0
- data/Changes +51 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +21 -0
- data/LICENSE.txt +3 -0
- data/README.md +27 -0
- data/Rakefile +65 -0
- data/VERSION +1 -0
- data/bdb1.gemspec +75 -0
- data/examples/basic.rb +15 -0
- data/examples/func.rb +29 -0
- data/examples/recno.rb +19 -0
- data/examples/record.rb +43 -0
- data/examples/wordtest +10000 -0
- data/examples/zeroc.rb +40 -0
- data/ext/bdb1/bdb1.c +1868 -0
- data/ext/bdb1/bdb1.h +160 -0
- data/ext/bdb1/delegate.c +196 -0
- data/ext/bdb1/extconf.rb +33 -0
- data/ext/bdb1/recnum.c +1093 -0
- data/test/helper.rb +39 -0
- data/test/test_btree.rb +360 -0
- data/test/test_hash.rb +293 -0
- data/test/test_marshal.rb +181 -0
- data/test/test_recnum.rb +440 -0
- data/test/tmp/.keep_me +0 -0
- metadata +153 -0
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
|
+
}
|