rod 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +7 -0
  2. data/{README → README.rdoc} +33 -2
  3. data/Rakefile +7 -2
  4. data/changelog.txt +13 -0
  5. data/contributors.txt +2 -0
  6. data/features/append.feature +221 -0
  7. data/features/assoc_indexing.feature +66 -0
  8. data/features/basic.feature +199 -0
  9. data/features/collection.feature +171 -0
  10. data/features/flat_indexing.feature +140 -0
  11. data/features/fred.feature +49 -0
  12. data/features/inheritence.feature +211 -0
  13. data/features/muliple_db.feature +113 -0
  14. data/features/relationships.feature +195 -0
  15. data/features/segmented_indexing.feature +172 -0
  16. data/features/steps/model.rb +386 -0
  17. data/features/steps/rod.rb +71 -0
  18. data/features/steps/test_helper.rb +5 -0
  19. data/lib/rod/abstract_database.rb +17 -5
  20. data/lib/rod/constants.rb +1 -1
  21. data/lib/rod/database.rb +95 -74
  22. data/lib/rod/join_element.rb +6 -2
  23. data/lib/rod/model.rb +37 -9
  24. data/rod.gemspec +15 -12
  25. data/tests/check_strings.rb +10 -0
  26. data/tests/class_compatibility_create.rb +14 -0
  27. data/tests/class_compatibility_verify.rb +18 -0
  28. data/tests/eff1_test.rb +60 -0
  29. data/tests/eff2_test.rb +61 -0
  30. data/tests/full_runs.rb +68 -0
  31. data/tests/generate_classes_create.rb +25 -0
  32. data/tests/generate_classes_model.rb +23 -0
  33. data/tests/generate_classes_rewrite.rb +7 -0
  34. data/tests/generate_classes_verify.rb +46 -0
  35. data/tests/load_struct.rb +24 -0
  36. data/tests/migration_create.rb +25 -0
  37. data/tests/migration_migrate.rb +22 -0
  38. data/tests/migration_model1.rb +23 -0
  39. data/tests/migration_model2.rb +27 -0
  40. data/tests/migration_verify.rb +56 -0
  41. data/tests/mock_tests.rb +128 -0
  42. data/tests/read_on_create.rb +45 -0
  43. data/tests/save_struct.rb +49 -0
  44. data/tests/structures.rb +52 -0
  45. data/tests/unit/database.rb +60 -0
  46. data/tests/unit/model.rb +36 -0
  47. data/tests/unit/model_tests.rb +116 -0
  48. data/tests/validate_read_on_create.rb +12 -0
  49. data/utils/convert_index.rb +31 -0
  50. metadata +77 -28
@@ -0,0 +1,5 @@
1
+ $:.unshift "lib"
2
+ require 'rod'
3
+ module RodTest
4
+ end
5
+
@@ -52,7 +52,7 @@ module Rod
52
52
  if File.exist?(@path)
53
53
  remove_file("#{@path}database.yml")
54
54
  else
55
- Dir.mkdir(@path)
55
+ FileUtils.mkdir_p(@path)
56
56
  end
57
57
  self.classes.each do |klass|
58
58
  klass.send(:build_structure)
@@ -68,6 +68,7 @@ module Rod
68
68
  next if special_class?(klass)
69
69
  remove_files_but(klass.inline_library)
70
70
  end
71
+ remove_files(self.inline_library)
71
72
  generate_c_code(@path, classes)
72
73
  remove_files_but(self.inline_library)
73
74
  @metadata = {}
@@ -104,6 +105,7 @@ module Rod
104
105
  elsif options[:migrate]
105
106
  create_legacy_classes
106
107
  FileUtils.cp(@path + DATABASE_FILE, @path + DATABASE_FILE + LEGACY_DATA_SUFFIX)
108
+ remove_files(self.inline_library)
107
109
  end
108
110
  self.classes.each do |klass|
109
111
  klass.send(:build_structure)
@@ -266,16 +268,26 @@ module Rod
266
268
  end
267
269
 
268
270
  # Returns the string of given +length+ starting at given +offset+.
269
- def read_string(length, offset)
271
+ # Options:
272
+ # * +:skip_encoding+ - if set to +true+, the string is left as ASCII-8BIT
273
+ def read_string(length, offset,options={})
270
274
  # TODO the encoding should be stored in the DB
271
275
  # or configured globally
272
- _read_string(length, offset, @handler).force_encoding("utf-8")
276
+ value = _read_string(length, offset, @handler)
277
+ if options[:skip_encoding]
278
+ value.force_encoding("ascii-8bit")
279
+ else
280
+ value.force_encoding("utf-8")
281
+ end
273
282
  end
274
283
 
275
284
  # Stores the string in the DB encoding it to utf-8.
276
- def set_string(value)
285
+ # Options:
286
+ # * +:skip_encoding+ - if set to +true+, the string is not encoded
287
+ def set_string(value,options={})
277
288
  raise DatabaseError.new("Readonly database.") if readonly_data?
278
- _set_string(value.encode("utf-8"),@handler)
289
+ value = value.encode("utf-8") unless options[:skip_encoding]
290
+ _set_string(value,@handler)
279
291
  end
280
292
 
281
293
  # Returns the number of objects for given +klass+.
data/lib/rod/constants.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Rod
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
 
4
4
  # The name of file containing the data base.
5
5
  DATABASE_FILE = "database.yml"
data/lib/rod/database.rb CHANGED
@@ -57,19 +57,19 @@ module Rod
57
57
  # exist.
58
58
  def open_class_file(klass)
59
59
  str =<<-END
60
- |// create the file unless it exists
61
- |if(model_p->#{klass.struct_name}_lib_file == -1){
62
- | char * path = malloc(sizeof(char) * (strlen(model_p->path) +
63
- | #{klass.path_for_data("").size} + 1));
64
- | strcpy(path,model_p->path);
65
- | strcat(path,"#{klass.path_for_data("")}");
66
- | model_p->#{klass.struct_name}_lib_file =
67
- | open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
68
- | if(model_p->#{klass.struct_name}_lib_file == -1) {
69
- | rb_raise(rodException(),"Could not open file for class #{klass} on path %s writing.",path);
60
+ | // create the file unless it exists
61
+ | if(model_p->#{klass.struct_name}_lib_file == -1){
62
+ | char * path = malloc(sizeof(char) * (strlen(model_p->path) +
63
+ | #{klass.path_for_data("").size} + 1));
64
+ | strcpy(path,model_p->path);
65
+ | strcat(path,"#{klass.path_for_data("")}");
66
+ | model_p->#{klass.struct_name}_lib_file =
67
+ | open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
68
+ | if(model_p->#{klass.struct_name}_lib_file == -1) {
69
+ | rb_raise(rodException(),"Could not open file for class #{klass} on path %s writing.",path);
70
+ | }
71
+ | free(path);
70
72
  | }
71
- | free(path);
72
- |}
73
73
  END
74
74
  str.margin
75
75
  end
@@ -109,34 +109,36 @@ module Rod
109
109
  |
110
110
  | // increase the pages count by 1
111
111
  | model_p->#{klass.struct_name}_page_count += ALLOCATED_PAGES;
112
- |
113
- | // open the file for writing
114
- | FILE * #{klass.struct_name}_file =
115
- | fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
116
- | if(#{klass.struct_name}_file == NULL){
117
- | rb_raise(rodException(),"Could not open file for #{klass.struct_name}.");
118
- | }
119
- | // seek to the end
120
- | if(fseek(#{klass.struct_name}_file,0,SEEK_END) == -1){
121
- | rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
122
- | }
123
- | // write empty data at the end
124
- | char* #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
125
- | if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
126
- | page_size() * ALLOCATED_PAGES) == -1){
127
- | rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
128
- | }
129
- | // seek to the beginning
130
- | if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
131
- | rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
132
- | }
133
- | // mmap the extended file
134
- | model_p->#{klass.struct_name}_table = mmap(NULL,
135
- | model_p->#{klass.struct_name}_page_count * page_size(),
136
- | PROT_WRITE | PROT_READ, MAP_SHARED, model_p->#{klass.struct_name}_lib_file,0);
137
- | if(model_p->#{klass.struct_name}_table == MAP_FAILED){
138
- | perror(NULL);
139
- | rb_raise(rodException(),"Could not mmap segment for #{klass.struct_name}.");
112
+ | {
113
+ | // open the file for writing
114
+ | char* #{klass.struct_name}_empty_data;
115
+ | FILE * #{klass.struct_name}_file =
116
+ | fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
117
+ | if(#{klass.struct_name}_file == NULL){
118
+ | rb_raise(rodException(),"Could not open file for #{klass.struct_name}.");
119
+ | }
120
+ | // seek to the end
121
+ | if(fseek(#{klass.struct_name}_file,0,SEEK_END) == -1){
122
+ | rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
123
+ | }
124
+ | // write empty data at the end
125
+ | #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
126
+ | if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
127
+ | page_size() * ALLOCATED_PAGES) == -1){
128
+ | rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
129
+ | }
130
+ | // seek to the beginning
131
+ | if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
132
+ | rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
133
+ | }
134
+ | // mmap the extended file
135
+ | model_p->#{klass.struct_name}_table = mmap(NULL,
136
+ | model_p->#{klass.struct_name}_page_count * page_size(),
137
+ | PROT_WRITE | PROT_READ, MAP_SHARED, model_p->#{klass.struct_name}_lib_file,0);
138
+ | if(model_p->#{klass.struct_name}_table == MAP_FAILED){
139
+ | perror(NULL);
140
+ | rb_raise(rodException(),"Could not mmap segment for #{klass.struct_name}.");
141
+ | }
140
142
  | }
141
143
  |#{update_pointer(klass) unless special_class?(klass)}
142
144
  END
@@ -153,6 +155,19 @@ module Rod
153
155
  # Implementations of abstract methods
154
156
  #########################################################################
155
157
 
158
+ # Ruby inline generated shared library name.
159
+ def inline_library
160
+ unless defined?(@inline_library)
161
+ self.class.inline(:C) do |builder|
162
+ builder.c_singleton("void __unused_method_#{rand(1000)}(){}")
163
+
164
+ self.instance_variable_set("@inline_library",builder.so_name)
165
+ end
166
+ end
167
+ @inline_library
168
+ end
169
+
170
+
156
171
  # Generates the code C responsible for management of the database.
157
172
  def generate_c_code(path, classes)
158
173
  if !@code_generated || @@rod_development_mode
@@ -177,14 +192,7 @@ module Rod
177
192
  END
178
193
  builder.prefix(str.margin)
179
194
 
180
- str =<<-END
181
- |VALUE rodException(){
182
- | VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
183
- | klass = rb_const_get(klass, rb_intern("DatabaseError"));
184
- | return klass;
185
- |}
186
- END
187
- builder.prefix(str.margin)
195
+ builder.prefix(self.class.rod_exception)
188
196
 
189
197
 
190
198
  #########################################
@@ -215,7 +223,7 @@ module Rod
215
223
  |VALUE _join_element_index(unsigned long element_offset, unsigned long element_index, VALUE handler){
216
224
  | #{model_struct} * model_p;
217
225
  | Data_Get_Struct(handler,#{model_struct},model_p);
218
- | return UINT2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
226
+ | return ULONG2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
219
227
  |}
220
228
  END
221
229
  builder.c(str.margin)
@@ -225,7 +233,7 @@ module Rod
225
233
  | unsigned long element_index, VALUE handler){
226
234
  | #{model_struct} * model_p;
227
235
  | Data_Get_Struct(handler,#{model_struct},model_p);
228
- | return UINT2NUM((model_p->_polymorphic_join_element_table +
236
+ | return ULONG2NUM((model_p->_polymorphic_join_element_table +
229
237
  | element_offset + element_index)->offset);
230
238
  |}
231
239
  END
@@ -236,7 +244,7 @@ module Rod
236
244
  | unsigned long element_index, VALUE handler){
237
245
  | #{model_struct} * model_p;
238
246
  | Data_Get_Struct(handler,#{model_struct},model_p);
239
- | return UINT2NUM((model_p->_polymorphic_join_element_table +
247
+ | return ULONG2NUM((model_p->_polymorphic_join_element_table +
240
248
  | element_offset + element_index)->class);
241
249
  |}
242
250
  END
@@ -247,12 +255,11 @@ module Rod
247
255
  | unsigned long element_index, unsigned long offset,
248
256
  | VALUE handler){
249
257
  | #{model_struct} * model_p;
250
- | Data_Get_Struct(handler,#{model_struct},model_p);
251
258
  | _join_element * element_p;
259
+ | Data_Get_Struct(handler,#{model_struct},model_p);
252
260
  | element_p = model_p->_join_element_table + element_offset + element_index;
253
261
  | if(element_p->index != element_index){
254
- | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
255
- | rb_raise(eClass, "Join element indices are inconsistent: %lu %lu!",
262
+ | rb_raise(rodException(), "Join element indices are inconsistent: %lu %lu!",
256
263
  | element_index, element_p->index);
257
264
  | }
258
265
  | element_p->offset = offset;
@@ -265,12 +272,11 @@ module Rod
265
272
  | unsigned long element_index, unsigned long offset, unsigned long class_id,
266
273
  | VALUE handler){
267
274
  | #{model_struct} * model_p;
268
- | Data_Get_Struct(handler,#{model_struct},model_p);
269
275
  | _polymorphic_join_element * element_p;
276
+ | Data_Get_Struct(handler,#{model_struct},model_p);
270
277
  | element_p = model_p->_polymorphic_join_element_table + element_offset + element_index;
271
278
  | if(element_p->index != element_index){
272
- | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
273
- | rb_raise(eClass, "Polymorphic join element indices are inconsistent: %lu %lu!",
279
+ | rb_raise(rodException(), "Polymorphic join element indices are inconsistent: %lu %lu!",
274
280
  | element_index, element_p->index);
275
281
  | }
276
282
  | element_p->offset = offset;
@@ -284,8 +290,9 @@ module Rod
284
290
  | _join_element * element;
285
291
  | unsigned long index;
286
292
  | #{model_struct} * model_p;
293
+ | unsigned long result;
287
294
  | Data_Get_Struct(handler,#{model_struct},model_p);
288
- | unsigned long result = model_p->_join_element_count;
295
+ | result = model_p->_join_element_count;
289
296
  | for(index = 0; index < size; index++){
290
297
  | if((model_p->_join_element_count + 1) * sizeof(_join_element) >=
291
298
  | page_size() * model_p->_join_element_page_count){
@@ -306,8 +313,9 @@ module Rod
306
313
  | _polymorphic_join_element * element;
307
314
  | unsigned long index;
308
315
  | #{model_struct} * model_p;
316
+ | unsigned long result;
309
317
  | Data_Get_Struct(handler,#{model_struct},model_p);
310
- | unsigned long result = model_p->_polymorphic_join_element_count;
318
+ | result = model_p->_polymorphic_join_element_count;
311
319
  | for(index = 0; index < size; index++){
312
320
  | if((model_p->_polymorphic_join_element_count + 1) *
313
321
  | sizeof(_polymorphic_join_element) >=
@@ -332,8 +340,9 @@ module Rod
332
340
  str =<<-END
333
341
  |VALUE _read_string(unsigned long length, unsigned long offset, VALUE handler){
334
342
  | #{model_struct} * model_p;
343
+ | char * str;
335
344
  | Data_Get_Struct(handler,#{model_struct},model_p);
336
- | char * str = model_p->#{StringElement.struct_name}_table + offset;
345
+ | str = model_p->#{StringElement.struct_name}_table + offset;
337
346
  | return rb_str_new(str, length);
338
347
  |}
339
348
  END
@@ -344,10 +353,9 @@ module Rod
344
353
  |// The return value is a pair: length and offset.
345
354
  |VALUE _set_string(VALUE ruby_value, VALUE handler){
346
355
  | #{model_struct} * model_p;
347
- | Data_Get_Struct(handler,#{model_struct},model_p);
348
356
  | unsigned long length = RSTRING_LEN(ruby_value);
349
357
  | char * value = RSTRING_PTR(ruby_value);
350
- | unsigned long string_offset, page_offset, current_page;
358
+ | unsigned long string_offset, page_offset, current_page, sum;
351
359
  | char * dest;
352
360
  | // table:
353
361
  | // - address of the first page
@@ -356,12 +364,17 @@ module Rod
356
364
  | // count:
357
365
  | // - total number of bytes
358
366
  | long length_left = length;
367
+ | // see the routine description above.
368
+ | VALUE result;
369
+ | // get the structure
370
+ | Data_Get_Struct(handler,#{model_struct},model_p);
359
371
  | // first free byte in current page
360
372
  | string_offset = model_p->#{StringElement.struct_name}_count % page_size();
361
373
  | page_offset = model_p->#{StringElement.struct_name}_count / page_size();
362
374
  | current_page = page_offset;
363
375
  | while(length_left > 0){
364
- | if(length_left + string_offset >= page_size()){
376
+ | sum = ((unsigned long)length_left) + string_offset;
377
+ | if(sum >= page_size()){
365
378
  | \n#{mmap_class(StringElement)}
366
379
  | }
367
380
  | dest = model_p->#{StringElement.struct_name}_table +
@@ -378,9 +391,9 @@ module Rod
378
391
  |
379
392
  | model_p->#{StringElement.struct_name}_count += length;
380
393
  |
381
- | VALUE result = rb_ary_new();
382
- | rb_ary_push(result, UINT2NUM(length));
383
- | rb_ary_push(result, UINT2NUM(string_offset + page_offset * page_size()));
394
+ | result = rb_ary_new();
395
+ | rb_ary_push(result, ULONG2NUM(length));
396
+ | rb_ary_push(result, ULONG2NUM(string_offset + page_offset * page_size()));
384
397
  | return result;
385
398
  |}
386
399
  END
@@ -410,12 +423,13 @@ module Rod
410
423
  |void _store_#{klass.struct_name}(VALUE object, VALUE handler){
411
424
  |
412
425
  | #{model_struct} * model_p;
426
+ | #{klass.struct_name} * struct_p;
413
427
  | Data_Get_Struct(handler,#{model_struct},model_p);
414
428
  | if((model_p->#{klass.struct_name}_count+1) * sizeof(#{klass.struct_name}) >=
415
429
  | model_p->#{klass.struct_name}_page_count * page_size()){
416
430
  | \n#{mmap_class(klass)}
417
431
  | }
418
- | #{klass.struct_name} * struct_p = model_p->#{klass.struct_name}_table +
432
+ | struct_p = model_p->#{klass.struct_name}_table +
419
433
  | model_p->#{klass.struct_name}_count;
420
434
  | //printf("struct assigned\\n");
421
435
  | model_p->#{klass.struct_name}_count++;
@@ -423,7 +437,7 @@ module Rod
423
437
  | //the number is incresed by 1, because 0 indicates that the
424
438
  | //(referenced) object is nil
425
439
  | struct_p->rod_id = model_p->#{klass.struct_name}_count;
426
- | rb_iv_set(object, \"@rod_id\",UINT2NUM(struct_p->rod_id));
440
+ | rb_iv_set(object, \"@rod_id\",ULONG2NUM(struct_p->rod_id));
427
441
  |}
428
442
  END
429
443
  builder.c(str.margin)
@@ -435,6 +449,7 @@ module Rod
435
449
  str = <<-END
436
450
  |VALUE _init_handler(char * dir_path){
437
451
  | #{model_struct} * model_p;
452
+ | VALUE cClass;
438
453
  | model_p = ALLOC(#{model_struct});
439
454
  |
440
455
  | #{init_structs(classes)}
@@ -444,7 +459,7 @@ module Rod
444
459
  | strcpy(model_p->path,dir_path);
445
460
  |
446
461
  | //create the wrapping object
447
- | VALUE cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
462
+ | cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
448
463
  | rb_cObject);
449
464
  | return Data_Wrap_Struct(cClass, 0, free, model_p);
450
465
  |}
@@ -569,11 +584,6 @@ module Rod
569
584
  # This has to be at the very end of builder definition!
570
585
  self.instance_variable_set("@inline_library",builder.so_name)
571
586
 
572
- # Ruby inline generated shared library.
573
- def self.inline_library
574
- @inline_library
575
- end
576
-
577
587
  end
578
588
  @code_generated = true
579
589
  end
@@ -602,5 +612,16 @@ module Rod
602
612
  END
603
613
  builder.c(str.margin)
604
614
  end
615
+
616
+ def self.rod_exception
617
+ str =<<-END
618
+ |VALUE rodException(){
619
+ | VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
620
+ | klass = rb_const_get(klass, rb_intern("DatabaseError"));
621
+ | return klass;
622
+ |}
623
+ END
624
+ str.margin
625
+ end
605
626
  end
606
627
  end
@@ -13,7 +13,9 @@ module Rod
13
13
  end
14
14
 
15
15
  def self.layout
16
- ' printf(" offset: %lu, index: %lu\n",sizeof(unsigned long), sizeof(unsigned long));' + "\n"
16
+ ' printf(" offset: %lu, index: %lu\n",' +
17
+ '(unsigned long)sizeof(unsigned long), ' +
18
+ '(unsigned long)sizeof(unsigned long));' + "\n"
17
19
  end
18
20
 
19
21
  def self.struct_name
@@ -39,7 +41,9 @@ module Rod
39
41
 
40
42
  def self.layout
41
43
  ' printf(" offset: %lu, index: %lu, class: %lu\n",' +
42
- 'sizeof(unsigned long), sizeof(unsigned long), sizeof(unsigned long));' + "\n"
44
+ '(unsigned long)sizeof(unsigned long), ' +
45
+ '(unsigned long)sizeof(unsigned long), ' +
46
+ '(unsigned long)sizeof(unsigned long));' + "\n"
43
47
  end
44
48
  end
45
49
  end
data/lib/rod/model.rb CHANGED
@@ -52,14 +52,19 @@ module Rod
52
52
  self.class == other.class && self.rod_id == other.rod_id
53
53
  end
54
54
 
55
- # Default implementation of to_s.
56
- def to_s
55
+ # Default implementation of +inspect+.
56
+ def inspect
57
57
  fields = self.class.fields.map{|n,o| "#{n}:#{self.send(n)}"}.join(",")
58
58
  singular = self.class.singular_associations.map{|n,o| "#{n}:#{self.send(n).class}"}.join(",")
59
59
  plural = self.class.plural_associations.map{|n,o| "#{n}:#{self.send(n).size}"}.join(",")
60
60
  "#{self.class}:<#{fields}><#{singular}><#{plural}>"
61
61
  end
62
62
 
63
+ # Default implementation of +to_s+.
64
+ def to_s
65
+ self.inspect
66
+ end
67
+
63
68
  # Returns the number of objects of this class stored in the
64
69
  # database.
65
70
  def self.count
@@ -228,7 +233,11 @@ module Rod
228
233
  else
229
234
  raise RodException.new("Unrecognised field type '#{self.class.fields[name][:type]}'!")
230
235
  end
231
- length, offset = database.set_string(value)
236
+ options = {}
237
+ if self.class.fields[name][:type] == :object
238
+ options[:skip_encoding] = true
239
+ end
240
+ length, offset = database.set_string(value,options)
232
241
  send("_#{name}_length=",@rod_id,length)
233
242
  send("_#{name}_offset=",@rod_id,offset)
234
243
  else
@@ -726,20 +735,23 @@ module Rod
726
735
  result = <<-END
727
736
  | \n#{self.fields.map do |field,options|
728
737
  unless string_field?(options[:type])
729
- "| printf(\" size of '#{field}': %lu\\n\",sizeof(#{TYPE_MAPPING[options[:type]]}));"
738
+ "| printf(\" size of '#{field}': %lu\\n\"," +
739
+ "(unsigned long)sizeof(#{TYPE_MAPPING[options[:type]]}));"
730
740
  else
731
741
  <<-SUBEND
732
742
  | printf(" string '#{field}' length: %lu offset: %lu page: %lu\\n",
733
- | sizeof(unsigned long), sizeof(unsigned long), sizeof(unsigned long));
743
+ | (unsigned long)sizeof(unsigned long), (unsigned long)sizeof(unsigned long),
744
+ | (unsigned long)sizeof(unsigned long));
734
745
  SUBEND
735
746
  end
736
747
  end.join("\n") }
737
748
  | \n#{singular_associations.map do |name, options|
738
- " printf(\" singular assoc '#{name}': %lu\\n\",sizeof(unsigned long));"
749
+ " printf(\" singular assoc '#{name}': %lu\\n\","+
750
+ "(unsigned long)sizeof(unsigned long));"
739
751
  end.join("\n| ")}
740
752
  | \n#{plural_associations.map do |name, options|
741
753
  "| printf(\" plural assoc '#{name}' offset: %lu, count %lu\\n\",\n"+
742
- "| sizeof(unsigned long),sizeof(unsigned long));"
754
+ "| (unsigned long)sizeof(unsigned long),(unsigned long)sizeof(unsigned long));"
743
755
  end.join("\n| \n")}
744
756
  END
745
757
  result.margin
@@ -749,6 +761,9 @@ module Rod
749
761
  def self.field_reader(name,result_type,builder)
750
762
  str =<<-END
751
763
  |#{result_type} _#{name}(unsigned long object_rod_id){
764
+ | if(object_rod_id == 0){
765
+ | rb_raise(rodException(), "Invalid object rod_id (0)");
766
+ | }
752
767
  | VALUE klass = rb_funcall(self,rb_intern("class"),0);
753
768
  | #{struct_name} * pointer = (#{struct_name} *)
754
769
  | NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
@@ -762,6 +777,9 @@ module Rod
762
777
  def self.field_writer(name,arg_type,builder)
763
778
  str =<<-END
764
779
  |void _#{name}_equals(unsigned long object_rod_id,#{arg_type} value){
780
+ | if(object_rod_id == 0){
781
+ | rb_raise(rodException(), "Invalid object rod_id (0)");
782
+ | }
765
783
  | VALUE klass = rb_funcall(self,rb_intern("class"),0);
766
784
  | #{struct_name} * pointer = (#{struct_name} *)
767
785
  | NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
@@ -786,6 +804,7 @@ module Rod
786
804
 
787
805
  inline(:C) do |builder|
788
806
  builder.prefix(typedef_struct)
807
+ builder.prefix(Database.rod_exception)
789
808
  if Database.development_mode
790
809
  # This method is created to force rebuild of the C code, since
791
810
  # it is rebuild on the basis of methods' signatures change.
@@ -883,7 +902,11 @@ module Rod
883
902
  return (options[:type] == :object ? nil : "")
884
903
  end
885
904
  offset = send("_#{field}_offset", @rod_id)
886
- value = database.read_string(length, offset)
905
+ read_options = {}
906
+ if options[:type] == :object
907
+ read_options[:skip_encoding] = true
908
+ end
909
+ value = database.read_string(length, offset, options)
887
910
  if options[:type] == :object
888
911
  value = Marshal.load(value)
889
912
  end
@@ -917,6 +940,7 @@ module Rod
917
940
  define_method(name) do
918
941
  value = instance_variable_get("@#{name}")
919
942
  if value.nil?
943
+ return nil if @rod_id == 0
920
944
  rod_id = send("_#{name}",@rod_id)
921
945
  # the indices are shifted by 1, to leave 0 for nil
922
946
  if rod_id == 0
@@ -973,7 +997,11 @@ module Rod
973
997
  if (instance_variable_get("@#{name}") != nil)
974
998
  return instance_variable_get("@#{name}").count
975
999
  else
976
- return send("_#{name}_count",@rod_id)
1000
+ if @rod_id == 0
1001
+ return 0
1002
+ else
1003
+ return send("_#{name}_count",@rod_id)
1004
+ end
977
1005
  end
978
1006
  end
979
1007