mongodb-mongo_ext 0.1.1 → 0.3
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/Rakefile +10 -5
- data/ext/cbson/cbson.c +93 -44
- data/ext/cbson/extconf.rb +2 -0
- data/mongo-extensions.gemspec +1 -1
- metadata +2 -2
data/Rakefile
CHANGED
@@ -11,6 +11,9 @@ end
|
|
11
11
|
require 'rbconfig'
|
12
12
|
include Config
|
13
13
|
|
14
|
+
gem_command = "gem"
|
15
|
+
gem_command = "gem1.9" if CONFIG["MAJOR"] == "1" && CONFIG["MINOR"] == "9"
|
16
|
+
|
14
17
|
# NOTE: some of the tests assume Mongo is running
|
15
18
|
Rake::TestTask.new do |t|
|
16
19
|
t.test_files = FileList['tests/test*.rb']
|
@@ -18,8 +21,10 @@ end
|
|
18
21
|
|
19
22
|
desc "Generate documentation"
|
20
23
|
task :rdoc do
|
24
|
+
version = eval(File.read("mongo-ruby-driver.gemspec")).version
|
25
|
+
out = File.join('html', version.to_s)
|
21
26
|
FileUtils.rm_rf('html')
|
22
|
-
system "rdoc --main README.rdoc --op
|
27
|
+
system "rdoc --main README.rdoc --op #{out} --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
|
23
28
|
end
|
24
29
|
|
25
30
|
desc "Publish documentation to mongo.rubyforge.org"
|
@@ -33,8 +38,8 @@ namespace :gem do
|
|
33
38
|
desc "Install the gem locally"
|
34
39
|
task :install do
|
35
40
|
sh <<EOS
|
36
|
-
|
37
|
-
sudo
|
41
|
+
#{gem_command} build mongo-ruby-driver.gemspec &&
|
42
|
+
sudo #{gem_command} install mongo-*.gem &&
|
38
43
|
rm mongo-*.gem
|
39
44
|
EOS
|
40
45
|
end
|
@@ -42,8 +47,8 @@ EOS
|
|
42
47
|
desc "Install the optional c extensions"
|
43
48
|
task :install_extensions do
|
44
49
|
sh <<EOS
|
45
|
-
|
46
|
-
sudo
|
50
|
+
#{gem_command} build mongo-extensions.gemspec &&
|
51
|
+
sudo #{gem_command} install mongo_ext-*.gem &&
|
47
52
|
rm mongo_ext-*.gem
|
48
53
|
EOS
|
49
54
|
end
|
data/ext/cbson/cbson.c
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
#include "st.h"
|
25
25
|
#include "regex.h"
|
26
26
|
#include <assert.h>
|
27
|
+
#include <math.h>
|
27
28
|
|
28
29
|
#define INITIAL_BUFFER_SIZE 256
|
29
30
|
|
@@ -36,6 +37,23 @@ static VALUE Code;
|
|
36
37
|
static VALUE RegexpOfHolding;
|
37
38
|
static VALUE OrderedHash;
|
38
39
|
|
40
|
+
// this sucks. but for some reason these moved around between 1.8 and 1.9
|
41
|
+
#ifdef ONIGURUMA_H
|
42
|
+
#define IGNORECASE ONIG_OPTION_IGNORECASE
|
43
|
+
#define MULTILINE ONIG_OPTION_MULTILINE
|
44
|
+
#define EXTENDED ONIG_OPTION_EXTEND
|
45
|
+
#else
|
46
|
+
#define IGNORECASE RE_OPTION_IGNORECASE
|
47
|
+
#define MULTILINE RE_OPTION_MULTILINE
|
48
|
+
#define EXTENDED RE_OPTION_EXTENDED
|
49
|
+
#endif
|
50
|
+
|
51
|
+
// this sucks too.
|
52
|
+
#ifndef RREGEXP_SRC_PTR
|
53
|
+
#define RREGEXP_SRC_PTR(r) RREGEXP(r)->str
|
54
|
+
#define RREGEXP_SRC_LEN(r) RREGEXP(r)->len
|
55
|
+
#endif
|
56
|
+
|
39
57
|
typedef struct {
|
40
58
|
char* buffer;
|
41
59
|
int size;
|
@@ -49,7 +67,7 @@ static int cmp_char(const void* a, const void* b) {
|
|
49
67
|
return *(char*)a - *(char*)b;
|
50
68
|
}
|
51
69
|
|
52
|
-
static void write_doc(bson_buffer* buffer, VALUE hash);
|
70
|
+
static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys);
|
53
71
|
static int write_element(VALUE key, VALUE value, VALUE extra);
|
54
72
|
static VALUE elements_to_hash(const char* buffer, int max);
|
55
73
|
|
@@ -109,14 +127,19 @@ static void buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size)
|
|
109
127
|
buffer->position += size;
|
110
128
|
}
|
111
129
|
|
130
|
+
static VALUE pack_extra(bson_buffer* buffer, VALUE check_keys) {
|
131
|
+
return rb_ary_new3(2, INT2NUM((int)buffer), check_keys);
|
132
|
+
}
|
133
|
+
|
112
134
|
static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) {
|
113
135
|
buffer_write_bytes(buffer, &type, 1);
|
114
|
-
buffer_write_bytes(buffer,
|
136
|
+
buffer_write_bytes(buffer, RSTRING_PTR(name), RSTRING_LEN(name));
|
115
137
|
buffer_write_bytes(buffer, &zero, 1);
|
116
138
|
}
|
117
139
|
|
118
140
|
static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow_id) {
|
119
|
-
bson_buffer* buffer = (bson_buffer*)extra;
|
141
|
+
bson_buffer* buffer = (bson_buffer*)NUM2INT(rb_ary_entry(extra, 0));
|
142
|
+
VALUE check_keys = rb_ary_entry(extra, 1);
|
120
143
|
|
121
144
|
if (TYPE(key) == T_SYMBOL) {
|
122
145
|
// TODO better way to do this... ?
|
@@ -127,13 +150,29 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
127
150
|
rb_raise(rb_eTypeError, "keys must be strings or symbols");
|
128
151
|
}
|
129
152
|
|
130
|
-
if (!allow_id && strcmp("_id",
|
153
|
+
if (!allow_id && strcmp("_id", RSTRING_PTR(key)) == 0) {
|
131
154
|
return ST_CONTINUE;
|
132
155
|
}
|
133
156
|
|
157
|
+
if (check_keys == Qtrue) {
|
158
|
+
if (RSTRING_LEN(key) > 0 && RSTRING_PTR(key)[0] == '$') {
|
159
|
+
rb_raise(rb_eRuntimeError, "key must not start with '$'");
|
160
|
+
}
|
161
|
+
int i;
|
162
|
+
for (i = 0; i < RSTRING_LEN(key); i++) {
|
163
|
+
if (RSTRING_PTR(key)[i] == '.') {
|
164
|
+
rb_raise(rb_eRuntimeError, "key must not contain '.'");
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
134
169
|
switch(TYPE(value)) {
|
135
170
|
case T_BIGNUM:
|
136
171
|
{
|
172
|
+
if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647)) == Qtrue ||
|
173
|
+
rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648)) == Qtrue) {
|
174
|
+
rb_raise(rb_eRangeError, "MongoDB can only handle 4-byte ints - try converting to a double before saving");
|
175
|
+
}
|
137
176
|
write_name_and_type(buffer, key, 0x10);
|
138
177
|
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
|
139
178
|
int int_value = NUM2LL(as_f);
|
@@ -174,7 +213,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
174
213
|
case T_HASH:
|
175
214
|
{
|
176
215
|
write_name_and_type(buffer, key, 0x03);
|
177
|
-
write_doc(buffer, value);
|
216
|
+
write_doc(buffer, value, check_keys);
|
178
217
|
break;
|
179
218
|
}
|
180
219
|
case T_ARRAY:
|
@@ -192,7 +231,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
192
231
|
char* name;
|
193
232
|
asprintf(&name, "%d", i);
|
194
233
|
VALUE key = rb_str_new2(name);
|
195
|
-
write_element(key, values[i], (
|
234
|
+
write_element(key, values[i], pack_extra(buffer, check_keys));
|
196
235
|
free(name);
|
197
236
|
}
|
198
237
|
|
@@ -211,11 +250,11 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
211
250
|
int start_position = buffer->position;
|
212
251
|
int length_location = buffer_save_bytes(buffer, 4);
|
213
252
|
|
214
|
-
int length =
|
253
|
+
int length = RSTRING_LEN(value) + 1;
|
215
254
|
buffer_write_bytes(buffer, (char*)&length, 4);
|
216
|
-
buffer_write_bytes(buffer,
|
255
|
+
buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
|
217
256
|
buffer_write_bytes(buffer, &zero, 1);
|
218
|
-
write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0));
|
257
|
+
write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0), Qfalse);
|
219
258
|
|
220
259
|
int total_length = buffer->position - start_position;
|
221
260
|
memcpy(buffer->buffer + length_location, &total_length, 4);
|
@@ -223,9 +262,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
223
262
|
break;
|
224
263
|
} else {
|
225
264
|
write_name_and_type(buffer, key, 0x02);
|
226
|
-
int length =
|
265
|
+
int length = RSTRING_LEN(value) + 1;
|
227
266
|
buffer_write_bytes(buffer, (char*)&length, 4);
|
228
|
-
buffer_write_bytes(buffer,
|
267
|
+
buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
|
229
268
|
buffer_write_bytes(buffer, &zero, 1);
|
230
269
|
break;
|
231
270
|
}
|
@@ -249,7 +288,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
249
288
|
const char subtype = strcmp(cls, "ByteBuffer") ?
|
250
289
|
(const char)FIX2INT(rb_funcall(value, rb_intern("subtype"), 0)) : 2;
|
251
290
|
VALUE string_data = rb_funcall(value, rb_intern("to_s"), 0);
|
252
|
-
int length =
|
291
|
+
int length = RSTRING_LEN(string_data);
|
253
292
|
if (subtype == 2) {
|
254
293
|
const int other_length = length + 4;
|
255
294
|
buffer_write_bytes(buffer, (const char*)&other_length, 4);
|
@@ -259,7 +298,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
259
298
|
if (subtype != 2) {
|
260
299
|
buffer_write_bytes(buffer, &subtype, 1);
|
261
300
|
}
|
262
|
-
buffer_write_bytes(buffer,
|
301
|
+
buffer_write_bytes(buffer, RSTRING_PTR(string_data), length);
|
263
302
|
break;
|
264
303
|
}
|
265
304
|
if (strcmp(cls, "XGen::Mongo::Driver::ObjectID") == 0) {
|
@@ -267,7 +306,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
267
306
|
VALUE as_array = rb_funcall(value, rb_intern("to_a"), 0);
|
268
307
|
int i;
|
269
308
|
for (i = 0; i < 12; i++) {
|
270
|
-
char byte = (char)FIX2INT(
|
309
|
+
char byte = (char)FIX2INT(RARRAY_PTR(as_array)[i]);
|
271
310
|
buffer_write_bytes(buffer, &byte, 1);
|
272
311
|
}
|
273
312
|
break;
|
@@ -281,9 +320,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
281
320
|
int length_location = buffer_save_bytes(buffer, 4);
|
282
321
|
|
283
322
|
VALUE ns = rb_funcall(value, rb_intern("namespace"), 0);
|
284
|
-
write_element(rb_str_new2("$ref"), ns, (
|
323
|
+
write_element(rb_str_new2("$ref"), ns, pack_extra(buffer, Qfalse));
|
285
324
|
VALUE oid = rb_funcall(value, rb_intern("object_id"), 0);
|
286
|
-
write_element(rb_str_new2("$id"), oid, (
|
325
|
+
write_element(rb_str_new2("$id"), oid, pack_extra(buffer, Qfalse));
|
287
326
|
|
288
327
|
// write null byte and fill in length
|
289
328
|
buffer_write_bytes(buffer, &zero, 1);
|
@@ -303,7 +342,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
303
342
|
if (strcmp(cls, "Time") == 0) {
|
304
343
|
write_name_and_type(buffer, key, 0x09);
|
305
344
|
double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0));
|
306
|
-
long long time_since_epoch = (long long)(t * 1000);
|
345
|
+
long long time_since_epoch = (long long)round(t * 1000);
|
307
346
|
buffer_write_bytes(buffer, (const char*)&time_since_epoch, 8);
|
308
347
|
break;
|
309
348
|
}
|
@@ -312,21 +351,21 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
312
351
|
{
|
313
352
|
write_name_and_type(buffer, key, 0x0B);
|
314
353
|
|
315
|
-
int length =
|
316
|
-
char* pattern =
|
354
|
+
int length = RREGEXP_SRC_LEN(value);
|
355
|
+
char* pattern = (char*)RREGEXP_SRC_PTR(value);
|
317
356
|
buffer_write_bytes(buffer, pattern, length);
|
318
357
|
buffer_write_bytes(buffer, &zero, 1);
|
319
358
|
|
320
359
|
long flags = RREGEXP(value)->ptr->options;
|
321
|
-
if (flags &
|
360
|
+
if (flags & IGNORECASE) {
|
322
361
|
char ignorecase = 'i';
|
323
362
|
buffer_write_bytes(buffer, &ignorecase, 1);
|
324
363
|
}
|
325
|
-
if (flags &
|
364
|
+
if (flags & MULTILINE) {
|
326
365
|
char multiline = 'm';
|
327
366
|
buffer_write_bytes(buffer, &multiline, 1);
|
328
367
|
}
|
329
|
-
if (flags &
|
368
|
+
if (flags & EXTENDED) {
|
330
369
|
char extended = 'x';
|
331
370
|
buffer_write_bytes(buffer, &extended, 1);
|
332
371
|
}
|
@@ -335,8 +374,8 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
335
374
|
if (TYPE(has_extra) == T_TRUE) {
|
336
375
|
VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
|
337
376
|
int old_position = buffer->position;
|
338
|
-
buffer_write_bytes(buffer,
|
339
|
-
qsort(buffer->buffer + old_position,
|
377
|
+
buffer_write_bytes(buffer, RSTRING_PTR(extra), RSTRING_LEN(extra));
|
378
|
+
qsort(buffer->buffer + old_position, RSTRING_LEN(extra), sizeof(char), cmp_char);
|
340
379
|
}
|
341
380
|
buffer_write_bytes(buffer, &zero, 1);
|
342
381
|
|
@@ -355,33 +394,33 @@ static int write_element(VALUE key, VALUE value, VALUE extra) {
|
|
355
394
|
return write_element_allow_id(key, value, extra, 0);
|
356
395
|
}
|
357
396
|
|
358
|
-
static void write_doc(bson_buffer* buffer, VALUE hash) {
|
397
|
+
static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys) {
|
359
398
|
int start_position = buffer->position;
|
360
399
|
int length_location = buffer_save_bytes(buffer, 4);
|
361
400
|
|
362
401
|
VALUE key = rb_str_new2("_id");
|
363
|
-
|
364
|
-
|
365
|
-
write_element_allow_id(key, id, (
|
402
|
+
if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
|
403
|
+
VALUE id = rb_hash_aref(hash, key);
|
404
|
+
write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
|
366
405
|
}
|
367
406
|
key = ID2SYM(rb_intern("_id"));
|
368
|
-
|
369
|
-
|
370
|
-
write_element_allow_id(key, id, (
|
407
|
+
if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
|
408
|
+
VALUE id = rb_hash_aref(hash, key);
|
409
|
+
write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
|
371
410
|
}
|
372
411
|
|
373
|
-
|
374
412
|
// we have to check for an OrderedHash and handle that specially
|
375
413
|
if (strcmp(rb_class2name(RBASIC(hash)->klass), "OrderedHash") == 0) {
|
376
414
|
VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
|
377
415
|
int i;
|
378
|
-
for(i = 0; i <
|
379
|
-
VALUE key =
|
416
|
+
for(i = 0; i < RARRAY_LEN(keys); i++) {
|
417
|
+
VALUE key = RARRAY_PTR(keys)[i];
|
380
418
|
VALUE value = rb_hash_aref(hash, key);
|
381
|
-
|
419
|
+
|
420
|
+
write_element(key, value, pack_extra(buffer, check_keys));
|
382
421
|
}
|
383
422
|
} else {
|
384
|
-
rb_hash_foreach(hash, write_element, (
|
423
|
+
rb_hash_foreach(hash, write_element, pack_extra(buffer, check_keys));
|
385
424
|
}
|
386
425
|
|
387
426
|
// write null byte and fill in length
|
@@ -390,11 +429,11 @@ static void write_doc(bson_buffer* buffer, VALUE hash) {
|
|
390
429
|
memcpy(buffer->buffer + length_location, &length, 4);
|
391
430
|
}
|
392
431
|
|
393
|
-
static VALUE method_serialize(VALUE self, VALUE doc) {
|
432
|
+
static VALUE method_serialize(VALUE self, VALUE doc, VALUE check_keys) {
|
394
433
|
bson_buffer* buffer = buffer_new();
|
395
434
|
assert(buffer);
|
396
435
|
|
397
|
-
write_doc(buffer, doc);
|
436
|
+
write_doc(buffer, doc, check_keys);
|
398
437
|
|
399
438
|
VALUE result = rb_str_new(buffer->buffer, buffer->position);
|
400
439
|
buffer_free(buffer);
|
@@ -525,13 +564,13 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|
525
564
|
for (i = 0; i < flags_length; i++) {
|
526
565
|
char flag = buffer[*position + i];
|
527
566
|
if (flag == 'i') {
|
528
|
-
flags |=
|
567
|
+
flags |= IGNORECASE;
|
529
568
|
}
|
530
569
|
else if (flag == 'm') {
|
531
|
-
flags |=
|
570
|
+
flags |= MULTILINE;
|
532
571
|
}
|
533
572
|
else if (flag == 'x') {
|
534
|
-
flags |=
|
573
|
+
flags |= EXTENDED;
|
535
574
|
}
|
536
575
|
else if (strlen(extra) < 9) {
|
537
576
|
strncat(extra, &flag, 1);
|
@@ -594,6 +633,16 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|
594
633
|
*position += 4;
|
595
634
|
break;
|
596
635
|
}
|
636
|
+
case 17:
|
637
|
+
{
|
638
|
+
int i;
|
639
|
+
int j;
|
640
|
+
memcpy(&i, buffer + *position, 4);
|
641
|
+
memcpy(&j, buffer + *position + 4, 4);
|
642
|
+
value = rb_ary_new3(2, LL2NUM(i), LL2NUM(j));
|
643
|
+
*position += 8;
|
644
|
+
break;
|
645
|
+
}
|
597
646
|
default:
|
598
647
|
{
|
599
648
|
rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type);
|
@@ -618,8 +667,8 @@ static VALUE elements_to_hash(const char* buffer, int max) {
|
|
618
667
|
}
|
619
668
|
|
620
669
|
static VALUE method_deserialize(VALUE self, VALUE bson) {
|
621
|
-
const char* buffer =
|
622
|
-
int remaining =
|
670
|
+
const char* buffer = RSTRING_PTR(bson);
|
671
|
+
int remaining = RSTRING_LEN(bson);
|
623
672
|
|
624
673
|
// NOTE we just swallow the size and end byte here
|
625
674
|
buffer += 4;
|
@@ -651,6 +700,6 @@ void Init_cbson() {
|
|
651
700
|
OrderedHash = rb_const_get(rb_cObject, rb_intern("OrderedHash"));
|
652
701
|
|
653
702
|
VALUE CBson = rb_define_module("CBson");
|
654
|
-
rb_define_module_function(CBson, "serialize", method_serialize,
|
703
|
+
rb_define_module_function(CBson, "serialize", method_serialize, 2);
|
655
704
|
rb_define_module_function(CBson, "deserialize", method_deserialize, 1);
|
656
705
|
}
|
data/ext/cbson/extconf.rb
CHANGED
data/mongo-extensions.gemspec
CHANGED
@@ -7,7 +7,7 @@ TEST_FILES = []
|
|
7
7
|
|
8
8
|
Gem::Specification.new do |s|
|
9
9
|
s.name = 'mongo_ext'
|
10
|
-
s.version = '0.
|
10
|
+
s.version = '0.3'
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
12
|
s.summary = 'C extensions for the MongoDB Ruby driver'
|
13
13
|
s.description = 'C extensions to accelerate the MondoDB Ruby driver. For more information about Mongo, see http://www.mongodb.org.'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongodb-mongo_ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Dirolf
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|