rod 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.travis.yml +1 -1
  2. data/README.rdoc +38 -10
  3. data/Rakefile +20 -9
  4. data/changelog.txt +25 -0
  5. data/contributors.txt +1 -0
  6. data/data/backward/0.7.0/_join_element.dat +0 -0
  7. data/data/backward/0.7.0/_polymorphic_join_element.dat +0 -0
  8. data/data/backward/0.7.0/char.dat +0 -0
  9. data/data/backward/0.7.0/database.yml +58 -0
  10. data/data/backward/0.7.0/rod_test__automobile.dat +0 -0
  11. data/data/backward/0.7.0/rod_test__caveman.dat +0 -0
  12. data/data/backward/0.7.0/rod_test__dog.dat +0 -0
  13. data/data/backward/0.7.0/rod_test__test_model.dat +0 -0
  14. data/data/portability/_join_element.dat +0 -0
  15. data/data/portability/_polymorphic_join_element.dat +0 -0
  16. data/data/portability/char.dat +0 -0
  17. data/data/portability/database.yml +49 -0
  18. data/data/portability/rod_test__automobile.dat +0 -0
  19. data/data/portability/rod_test__caveman.dat +0 -0
  20. data/data/portability/rod_test__dog.dat +0 -0
  21. data/data/portability/rod_test__test_model.dat +0 -0
  22. data/features/backward.feature +33 -0
  23. data/features/basic.feature +3 -0
  24. data/features/collection_proxy.feature +95 -0
  25. data/features/flat_indexing.feature +44 -2
  26. data/features/hash_indexing.feature +63 -9
  27. data/features/portability.feature +72 -0
  28. data/features/segmented_indexing.feature +45 -2
  29. data/features/steps/collection_proxy.rb +1 -1
  30. data/features/steps/model.rb +48 -5
  31. data/features/steps/rod.rb +15 -16
  32. data/lib/rod.rb +11 -1
  33. data/lib/rod/abstract_database.rb +52 -42
  34. data/lib/rod/berkeley/collection_proxy.rb +96 -0
  35. data/lib/rod/berkeley/database.rb +337 -0
  36. data/lib/rod/berkeley/environment.rb +209 -0
  37. data/lib/rod/berkeley/sequence.rb +222 -0
  38. data/lib/rod/berkeley/transaction.rb +233 -0
  39. data/lib/rod/collection_proxy.rb +76 -1
  40. data/lib/rod/constants.rb +3 -2
  41. data/lib/rod/database.rb +127 -14
  42. data/lib/rod/index/base.rb +12 -3
  43. data/lib/rod/index/hash_index.rb +295 -70
  44. data/lib/rod/index/segmented_index.rb +3 -0
  45. data/lib/rod/model.rb +154 -531
  46. data/lib/rod/property/base.rb +190 -0
  47. data/lib/rod/property/field.rb +258 -0
  48. data/lib/rod/property/plural_association.rb +145 -0
  49. data/lib/rod/property/singular_association.rb +139 -0
  50. data/rod.gemspec +6 -4
  51. data/spec/berkeley/database.rb +83 -0
  52. data/spec/berkeley/environment.rb +58 -0
  53. data/spec/berkeley/sequence.rb +101 -0
  54. data/spec/berkeley/transaction.rb +92 -0
  55. data/spec/collection_proxy.rb +38 -0
  56. data/spec/database.rb +36 -0
  57. data/spec/model.rb +26 -0
  58. data/spec/property/base.rb +73 -0
  59. data/spec/property/field.rb +244 -0
  60. data/spec/property/plural_association.rb +67 -0
  61. data/spec/property/singular_association.rb +65 -0
  62. data/tests/class_compatibility_create.rb +2 -2
  63. data/tests/eff1_test.rb +1 -1
  64. data/tests/eff2_test.rb +1 -1
  65. data/tests/full_runs.rb +1 -1
  66. data/tests/generate_classes_create.rb +14 -14
  67. data/tests/migration_create.rb +47 -47
  68. data/tests/migration_verify.rb +1 -1
  69. data/tests/missing_class_create.rb +6 -6
  70. data/tests/properties_order_create.rb +4 -4
  71. data/tests/read_on_create.rb +33 -34
  72. data/tests/save_struct.rb +40 -39
  73. data/tests/unit/database.rb +1 -1
  74. data/tests/unit/model_tests.rb +73 -65
  75. metadata +71 -15
  76. data/tests/unit/model.rb +0 -36
@@ -6,16 +6,14 @@ Given /^the library works in development mode$/ do
6
6
  Rod::Database.development_mode = true
7
7
  end
8
8
 
9
- Given /^(the )?(\w+) is created( in (\w+))?$/ do |ignore,db_name,location,location_name|
9
+ Given /^(?:the )?(\w+) is created(?: in (\S+))?$/ do |db_name,location|
10
10
  get_db(db_name).instance.close_database if get_db(db_name).instance.opened?
11
- if File.exist?("tmp")
12
- if location
13
- db_location = location_name
14
- else
15
- db_location = db_name
16
- end
11
+ if location
12
+ db_location = location
13
+ else
14
+ db_location = "tmp/#{db_name}"
17
15
  end
18
- get_db(db_name).instance.create_database("tmp/#{db_location}")
16
+ get_db(db_name).instance.create_database(db_location)
19
17
  @instances = {}
20
18
  end
21
19
 
@@ -42,27 +40,28 @@ Given /^the class space is cleared$/ do
42
40
  end
43
41
 
44
42
  # Should be split
45
- When /^I reopen (?:the )?(\w+)( for reading)?( in (\w+))?$/ do |db_name,reading,location,location_name|
43
+ # I reopen the database for reading in tmp/location1
44
+ When /^I reopen (?:the )?(\w+)( for reading)?(?: in (\S+))?$/ do |db_name,reading,location|
46
45
  if location
47
- db_location = location_name
46
+ db_location = location
48
47
  else
49
- db_location = db_name
48
+ db_location = "tmp/#{db_name}"
50
49
  end
51
50
  get_db(db_name).instance.close_database
52
51
  get_db(db_name).instance.clear_cache
53
52
  readonly = reading.nil? ? false : true
54
- get_db(db_name).instance.open_database("tmp/#{db_location}",readonly)
53
+ get_db(db_name).instance.open_database(db_location,readonly)
55
54
  end
56
55
 
57
- When /^I open (\w+)( for reading)?( in (\w+))?$/ do |db_name,reading,location,location_name|
56
+ When /^I open (?:the )?(\w+)( for reading)?(?: in (\S+))?$/ do |db_name,reading,location|
58
57
  if location
59
- db_location = location_name
58
+ db_location = location
60
59
  else
61
- db_location = db_name
60
+ db_location = "tmp/#{db_name}"
62
61
  end
63
62
  get_db(db_name).instance.clear_cache
64
63
  readonly = reading.nil? ? false : true
65
- get_db(db_name).instance.open_database("tmp/#{db_location}",readonly)
64
+ get_db(db_name).instance.open_database(db_location,readonly)
66
65
  end
67
66
 
68
67
  Then /^database should be opened for reading$/ do
data/lib/rod.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'inline'
2
2
  require 'english/inflect'
3
- require 'active_model/deprecated_error_methods'
3
+ require 'active_support/deprecation'
4
4
  require 'active_model/validator'
5
5
  require 'active_model/naming'
6
6
  require 'active_model/translation'
@@ -31,3 +31,13 @@ require 'rod/index/base'
31
31
  require 'rod/index/flat_index'
32
32
  require 'rod/index/hash_index'
33
33
  require 'rod/index/segmented_index'
34
+ require 'rod/property/base'
35
+ require 'rod/property/field'
36
+ require 'rod/property/singular_association'
37
+ require 'rod/property/plural_association'
38
+
39
+ require 'rod/berkeley/collection_proxy'
40
+ require 'rod/berkeley/environment'
41
+ require 'rod/berkeley/database'
42
+ require 'rod/berkeley/transaction'
43
+ require 'rod/berkeley/sequence'
@@ -66,31 +66,47 @@ module Rod
66
66
  #
67
67
  # WARNING: all files in the DB directory are removed during DB creation!
68
68
  def create_database(path)
69
- raise DatabaseError.new("Database already opened.") if opened?
70
- @readonly = false
71
- @path = canonicalize_path(path)
72
- if File.exist?(@path)
73
- remove_file("#{@path}database.yml")
69
+
70
+ if block_given?
71
+
72
+ create_database(path)
73
+
74
+ begin
75
+ yield
76
+ ensure
77
+ close_database
78
+ end
79
+
74
80
  else
75
- FileUtils.mkdir_p(@path)
76
- end
77
- self.classes.each do |klass|
78
- klass.send(:build_structure)
79
- remove_file(klass.path_for_data(@path))
80
- klass.indexed_properties.each do |property,options|
81
- klass.index_for(property,options).destroy
81
+
82
+ raise DatabaseError.new("Database already opened.") if opened?
83
+ @readonly = false
84
+ @path = canonicalize_path(path)
85
+ if File.exist?(@path)
86
+ remove_file("#{@path}database.yml")
87
+ else
88
+ FileUtils.mkdir_p(@path)
82
89
  end
83
- next if special_class?(klass)
84
- remove_files_but(klass.inline_library)
90
+ self.classes.each do |klass|
91
+ klass.send(:build_structure)
92
+ remove_file(klass.path_for_data(@path))
93
+ klass.indexed_properties.each do |property|
94
+ property.index.destroy
95
+ end
96
+ next if special_class?(klass)
97
+ remove_files_but(klass.inline_library)
98
+ end
99
+ remove_files(self.inline_library)
100
+ generate_c_code(@path, classes)
101
+ remove_files_but(self.inline_library)
102
+ @metadata = {}
103
+ @metadata["Rod"] = {}
104
+ @metadata["Rod"][:created_at] = Time.now
105
+ @handler = _init_handler(@path)
106
+ _create(@handler)
107
+
85
108
  end
86
- remove_files(self.inline_library)
87
- generate_c_code(@path, classes)
88
- remove_files_but(self.inline_library)
89
- @metadata = {}
90
- @metadata["Rod"] = {}
91
- @metadata["Rod"][:created_at] = Time.now
92
- @handler = _init_handler(@path)
93
- _create(@handler)
109
+
94
110
  end
95
111
 
96
112
  # Opens the database at +path+ with +options+. This allows
@@ -223,8 +239,8 @@ module Rod
223
239
  end
224
240
  unless skip_indices
225
241
  self.classes.each do |klass|
226
- klass.indexed_properties.each do |property,options|
227
- klass.index_for(property,options).save
242
+ klass.indexed_properties.each do |property|
243
+ property.index.save
228
244
  end
229
245
  end
230
246
  end
@@ -325,26 +341,20 @@ module Rod
325
341
  _allocate_join_elements(size,@handler)
326
342
  end
327
343
 
344
+ # Computes fast intersection for sorted join elements.
345
+ def fast_intersection_size(first_offset,first_length,second_offset,second_length)
346
+ _fast_intersection_size(first_offset,first_length,second_offset,
347
+ second_length,@handler)
348
+ end
349
+
328
350
  # Returns the string of given +length+ starting at given +offset+.
329
- # Options:
330
- # * +:skip_encoding+ - if set to +true+, the string is left as ASCII-8BIT
331
- def read_string(length, offset,options={})
332
- # TODO the encoding should be stored in the DB
333
- # or configured globally
351
+ def read_string(length, offset)
334
352
  value = _read_string(length, offset, @handler)
335
- if options[:skip_encoding]
336
- value.force_encoding("ascii-8bit")
337
- else
338
- value.force_encoding("utf-8")
339
- end
340
353
  end
341
354
 
342
- # Stores the string in the DB encoding it to utf-8.
343
- # Options:
344
- # * +:skip_encoding+ - if set to +true+, the string is not encoded
345
- def set_string(value,options={})
355
+ # Stores the string in the DB.
356
+ def set_string(value)
346
357
  raise DatabaseError.new("Readonly database.") if readonly_data?
347
- value = value.encode("utf-8") unless options[:skip_encoding]
348
358
  _set_string(value,@handler)
349
359
  end
350
360
 
@@ -476,9 +486,9 @@ module Rod
476
486
  [:fields,:has_one,:has_many].each do |property_type|
477
487
  next if metadata[property_type].nil?
478
488
  metadata[property_type].each do |property,options|
479
- if superclasses.keys.include?(options[:options][:class_name])
480
- metadata[property_type][property][:options][:class_name] =
481
- prefix + options[:options][:class_name]
489
+ if superclasses.keys.include?(options[:class_name])
490
+ metadata[property_type][property][:class_name] =
491
+ prefix + options[:class_name]
482
492
  end
483
493
  end
484
494
  end
@@ -0,0 +1,96 @@
1
+ module Rod
2
+ module Berkeley
3
+ class CollectionProxy
4
+ include Enumerable
5
+
6
+ # Initializes the proxy with given Berkeley +database+.
7
+ def initialize(database,key)
8
+ @database = database
9
+ @key = key
10
+ end
11
+
12
+ def [](object_index)
13
+ if object_index == 0
14
+ begin
15
+ return object_for(@database.get_first(@key))
16
+ rescue KeyMissing => ex
17
+ return nil
18
+ end
19
+ else
20
+ # TODO This should be optimized!
21
+ self.each.with_index do |object,index|
22
+ return object if index == object_index
23
+ end
24
+ end
25
+ nil
26
+ end
27
+
28
+ def |(other)
29
+ raise "#{self.class}##{__method__} not implemented yet."
30
+ end
31
+
32
+ def &(other)
33
+ raise "#{self.class}##{__method__} not implemented yet."
34
+ end
35
+
36
+ def <<(element)
37
+ # TODO #207 this doesn't work for not persited objects
38
+ rod_id = element.rod_id
39
+ raise "Not implemented #207" if rod_id.nil? || rod_id == 0
40
+ @database.put(@key,rod_id)
41
+ end
42
+
43
+ def insert(index,element)
44
+ raise "#{self.class}##{__method__} not implemented yet."
45
+ end
46
+
47
+ def delete(element)
48
+ begin
49
+ @database.delete(@key,element)
50
+ element
51
+ rescue KeyMissing => ex
52
+ nil
53
+ end
54
+ end
55
+
56
+ def delete_at(index)
57
+ raise "#{self.class}##{__method__} not implemented yet."
58
+ end
59
+
60
+ def clear
61
+ raise "#{self.class}##{__method__} not implemented yet."
62
+ end
63
+
64
+ def each
65
+ if block_given?
66
+ begin
67
+ @database.each_for(@key) do |rod_id|
68
+ yield object_for(rod_id)
69
+ end
70
+ rescue KeyMissing
71
+ nil
72
+ end
73
+ else
74
+ enum_for(:each)
75
+ end
76
+ end
77
+
78
+ def to_s
79
+ raise "#{self.class}##{__method__} not implemented yet."
80
+ end
81
+
82
+ def empty?
83
+ raise "#{self.class}##{__method__} not implemented yet."
84
+ end
85
+
86
+ def save
87
+ raise "#{self.class}##{__method__} not implemented yet."
88
+ end
89
+
90
+ protected
91
+ def object_for(rod_id)
92
+ @database.klass.find_by_rod_id(rod_id)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,337 @@
1
+ module Rod
2
+ module Berkeley
3
+ class Database
4
+ # The environment of the database.
5
+ attr_reader :environment
6
+
7
+ # The path of the database.
8
+ attr_reader :path
9
+
10
+ # Initializes the database as working within the given
11
+ # +environment+.
12
+ def initialize(environment)
13
+ # TODO allow standalone databases
14
+ @environment = environment
15
+ @opened = false
16
+ end
17
+
18
+ # Opens the Berkeley DB database at given +path+ with given +access_method+.
19
+ #
20
+ # The followin access methods are supported (see the Berkeley DB documentation
21
+ # for full description of the access methods):
22
+ # * +:btree+ - sorted, balanced tree
23
+ # * +:hash+ - hash table
24
+ # * +:queue+ - queue
25
+ # * +:recno+ - recno
26
+ # * +:heap+ - heap NOT SUPPORTED!
27
+ #
28
+ # The following options are supported (see the Berkeley DB documentation
29
+ # for full description of the flags):
30
+ # * +:auto_commit: - automaticaly commit each database change,
31
+ # BDB: +DB_AUTO_COMMIT+
32
+ # * +:create: - create the database if it doesn't exist, BDB: +DB_CREATE+
33
+ # * +:create_exclusive: - check if the database exists when creating it,
34
+ # if it exists - raise an error, BDB: +DB_EXCL+
35
+ # * +:multiversion: - use multiversion concurrency control to perform transaction
36
+ # snapshot isolation, BDB: +DB_MULTIVERSION+
37
+ # * +:no_mmap: - don't map this database to the process memory, BDB: +DB_NOMMAP+
38
+ # * +:readonly: - work in readonly mode - all database changes will fail,
39
+ # BDB: +DB_RDONLY+
40
+ # * +:read_uncommitted: - perform transaction degree 1 isolation,
41
+ # BDB: +DB_READ_UNCOMMITTED+
42
+ # * +:threads+ allow multiple threads within one process to access the databases,
43
+ # BDB: +DB_THREAD+
44
+ # * +:truncate: - empty the database on creation, BDB: +DB_TRUNCATE+
45
+ def open(path,access_method,options={})
46
+ # TODO check for validity of the method
47
+ # TODO check for validity of options
48
+ # TODO check for conflicting options
49
+ raise DatabaseError.new("The database is already opened at #{@path}.") if opened?
50
+ _open(path,access_method,options)
51
+ @path = path
52
+ @opened = true
53
+ end
54
+
55
+ # Closes the database.
56
+ def close
57
+ _close
58
+ @opened = false
59
+ end
60
+
61
+ # Returns true if the database is opened.
62
+ def opened?
63
+ @opened
64
+ end
65
+
66
+ # Put the +value+ to the database at the specified +key+.
67
+ # The operation might be protected by the +transaction+.
68
+ # Both the value and the key are marshaled before being stored.
69
+ def put(key,value,transaction=nil)
70
+ marshaled_key = Marshal.dump(key)
71
+ marshaled_value = Marshal.dump(value)
72
+ _put_strings(marshaled_key,marshaled_value,transaction)
73
+ end
74
+
75
+
76
+ # Return the value of the database for the specified +key+.
77
+ # The operation might be protected by the +transaction+.
78
+ # The key is marshaled before being stored looked up in the database.
79
+ def get(key,transaction=nil)
80
+ marshaled_key = Marshal.dump(key)
81
+ Marshal.load(_get_strings(marshaled_key,transaction))
82
+ end
83
+
84
+ class << self
85
+ # The C definition of the KeyMissing exception.
86
+ def key_missing_exception
87
+ str =<<-END
88
+ |VALUE keyMissingException(){
89
+ | VALUE klass;
90
+ |
91
+ | klass = rb_const_get(rb_cObject, rb_intern("Rod"));
92
+ | klass = rb_const_get(klass, rb_intern("KeyMissing"));
93
+ | return klass;
94
+ |}
95
+ END
96
+ str.margin
97
+ end
98
+ end
99
+
100
+ inline(:C) do |builder|
101
+ Rod::Berkeley::Environment.init_builder(builder)
102
+ builder.prefix(Rod::Berkeley::Environment.database_error)
103
+ builder.prefix(self.key_missing_exception)
104
+
105
+ str =<<-END
106
+ |/*
107
+ |* Closes the database causing the resources to be freed.
108
+ |*/
109
+ |void db_free(DB * db_pointer){
110
+ | int return_value;
111
+ |
112
+ | if(db_pointer != NULL){
113
+ | return_value = db_pointer->close(db_pointer,0);
114
+ | if(return_value != 0){
115
+ | rb_raise(databaseError(),"%s",db_strerror(return_value));
116
+ | }
117
+ | }
118
+ |}
119
+ END
120
+ builder.prefix(str.margin)
121
+
122
+ str =<<-END
123
+ |/*
124
+ |* Replaces default allocate with function returning wrapper for the
125
+ |* database struct.
126
+ |*/
127
+ |VALUE allocate(){
128
+ | // db_mark == NULL - no internal elements have to be marked
129
+ | // struct == NULL - there is no struct to wrap at the moment
130
+ | return Data_Wrap_Struct(self,NULL,db_free,NULL);
131
+ |}
132
+ END
133
+ builder.c_singleton(str.margin)
134
+
135
+ str =<<-END
136
+ |/*
137
+ |* Opens the database on the +path+ given with the access +method+ specified.
138
+ |* See +open+ for a list of options.
139
+ |*/
140
+ |void _open(const char * path, VALUE method, VALUE options){
141
+ | DB_ENV * env_pointer;
142
+ | DB * db_pointer;
143
+ | DBTYPE access_method;
144
+ | u_int32_t flags;
145
+ | int return_value;
146
+ | VALUE environment;
147
+ |
148
+ | environment = rb_iv_get(self,"@environment");
149
+ | if(NIL_P(environment)){
150
+ | rb_raise(databaseError(),"The environment of the database at %s is nil!",path);
151
+ | }
152
+ | Data_Get_Struct(environment,DB_ENV,env_pointer);
153
+ | if(env_pointer == NULL){
154
+ | rb_raise(databaseError(),"The environment of the database at %s is NULL!",path);
155
+ | }
156
+ | // the flags could be DB_XA_CREATE, but we don't support it so far.
157
+ | return_value = db_create(&db_pointer, env_pointer, 0);
158
+ | if(return_value != 0){
159
+ | rb_raise(databaseError(),"%s",db_strerror(return_value));
160
+ | }
161
+ |
162
+ | flags = 0;
163
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("auto_commit"))) == Qtrue){
164
+ | flags |= DB_AUTO_COMMIT;
165
+ | }
166
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("create"))) == Qtrue){
167
+ | flags |= DB_CREATE;
168
+ | }
169
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("create_exclusive"))) == Qtrue){
170
+ | flags |= DB_EXCL;
171
+ | }
172
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("multiversion"))) == Qtrue){
173
+ | flags |= DB_MULTIVERSION;
174
+ | }
175
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("no_mmap"))) == Qtrue){
176
+ | flags |= DB_NOMMAP;
177
+ | }
178
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("readonly"))) == Qtrue){
179
+ | flags |= DB_RDONLY;
180
+ | }
181
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("read_uncommitted"))) == Qtrue){
182
+ | flags |= DB_READ_UNCOMMITTED;
183
+ | }
184
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("threads"))) == Qtrue){
185
+ | flags |= DB_THREAD;
186
+ | }
187
+ | if(rb_hash_aref(options,ID2SYM(rb_intern("truncate"))) == Qtrue){
188
+ | flags |= DB_TRUNCATE;
189
+ | }
190
+ |
191
+ | // access method
192
+ | if(ID2SYM(rb_intern("btree")) == method){
193
+ | method = DB_BTREE;
194
+ | } else if(ID2SYM(rb_intern("hash")) == method){
195
+ | method = DB_BTREE;
196
+ | } else if(ID2SYM(rb_intern("heap")) == method){
197
+ | // DB_HEAP no supported in the library
198
+ | // method = DB_HEAP;
199
+ | } else if(ID2SYM(rb_intern("queue")) == method){
200
+ | method = DB_QUEUE;
201
+ | } else if(ID2SYM(rb_intern("recno")) == method){
202
+ | method = DB_RECNO;
203
+ | } else {
204
+ | // only for existing databases
205
+ | method = DB_UNKNOWN;
206
+ | }
207
+ | // 1 NULL - transaction pointer
208
+ | // 2 NULL - logical database name (for many dbs in one file)
209
+ | // 0 - default file access mode
210
+ | return_value = db_pointer->open(db_pointer,NULL,path,NULL,method,flags,0);
211
+ | if(return_value != 0){
212
+ | rb_raise(databaseError(),"%s",db_strerror(return_value));
213
+ | }
214
+ | DATA_PTR(self) = db_pointer;
215
+ |}
216
+ END
217
+ builder.c(str.margin)
218
+
219
+ str =<<-END
220
+ |/*
221
+ |* Closes the database if it is opened.
222
+ |*/
223
+ |void _close(){
224
+ | DB * db_pointer;
225
+ | int return_value;
226
+ |
227
+ | Data_Get_Struct(self,DB,db_pointer);
228
+ | db_free(db_pointer);
229
+ | DATA_PTR(self) = NULL;
230
+ |}
231
+ END
232
+ builder.c(str.margin)
233
+
234
+ str =<<-END
235
+ |void _put(VALUE self,void * key,unsigned int key_size, void * value,
236
+ | unsigned int value_size, VALUE transaction){
237
+ | DB *db_pointer;
238
+ | DB_TXN *txn_pointer;
239
+ | DBT db_key, db_value;
240
+ | int return_value;
241
+ |
242
+ | Data_Get_Struct(self,DB,db_pointer);
243
+ |
244
+ | memset(&db_key, 0, sizeof(DBT));
245
+ | db_key.data = key;
246
+ | db_key.size = key_size;
247
+ |
248
+ | memset(&db_value, 0, sizeof(DBT));
249
+ | db_value.data = value;
250
+ | db_value.size = value_size;
251
+ |
252
+ | if(db_pointer == NULL){
253
+ | rb_raise(databaseError(),"The handle for the database is NULL!");
254
+ | }
255
+ | // TODO options
256
+ | if(NIL_P(transaction)){
257
+ | return_value = db_pointer->put(db_pointer, NULL, &db_key, &db_value, 0);
258
+ | } else {
259
+ | Data_Get_Struct(transaction,DB_TXN,txn_pointer);
260
+ | return_value = db_pointer->put(db_pointer, txn_pointer, &db_key, &db_value, 0);
261
+ | }
262
+ | if(return_value != 0){
263
+ | rb_raise(databaseError(),"%s",db_strerror(return_value));
264
+ | }
265
+ |}
266
+ END
267
+ builder.prefix(str.margin)
268
+
269
+ str =<<-END
270
+ |/*
271
+ |* Put the string key-value pair to the database.
272
+ |*/
273
+ |void _put_strings(VALUE key, VALUE value, VALUE transaction){
274
+ | _put(self,RSTRING_PTR(key),RSTRING_LEN(key),RSTRING_PTR(value),
275
+ | RSTRING_LEN(value),transaction);
276
+ |}
277
+ END
278
+ builder.c(str.margin)
279
+
280
+ str =<<-END
281
+ |unsigned int _get(VALUE self, void * key, unsigned int key_size,
282
+ | void * value, unsigned int value_size, VALUE transaction){
283
+ | DB *db_pointer;
284
+ | DB_TXN *txn_pointer;
285
+ | DBT db_key, db_value;
286
+ | int return_value;
287
+ |
288
+ | Data_Get_Struct(self,DB,db_pointer);
289
+ |
290
+ | if(db_pointer == NULL){
291
+ | rb_raise(databaseError(),"The handle for the database is NULL!");
292
+ | }
293
+ |
294
+ | memset(&db_value, 0, sizeof(DBT));
295
+ | db_value.data = value;
296
+ | db_value.ulen = value_size;
297
+ | db_value.flags = DB_DBT_USERMEM;
298
+ |
299
+ | memset(&db_key, 0, sizeof(DBT));
300
+ | db_key.data = key;
301
+ | db_key.size = key_size;
302
+ |
303
+ | if(NIL_P(transaction)){
304
+ | return_value = db_pointer->get(db_pointer, NULL, &db_key, &db_value, 0);
305
+ | } else {
306
+ | Data_Get_Struct(transaction,DB_TXN,txn_pointer);
307
+ | return_value = db_pointer->get(db_pointer, txn_pointer, &db_key, &db_value, 0);
308
+ | }
309
+ | if(return_value == DB_NOTFOUND){
310
+ | rb_raise(keyMissingException(),"%s",db_strerror(return_value));
311
+ | } else if(return_value != 0){
312
+ | rb_raise(databaseError(),"%s",db_strerror(return_value));
313
+ | }
314
+ | return db_value.size;
315
+ |}
316
+ END
317
+ builder.prefix(str.margin)
318
+
319
+ str =<<-END
320
+ |/*
321
+ |* Get the value for given +key+. The key and the value
322
+ |* are supposed to be strings. The result size is limited to 1024 bytes.
323
+ |*/
324
+ |VALUE _get_strings(VALUE key, VALUE transaction){
325
+ | char buffer[1024];
326
+ | VALUE result;
327
+ | unsigned int size;
328
+ |
329
+ | size = _get(self,RSTRING_PTR(key),RSTRING_LEN(key),buffer,1024,transaction);
330
+ | return rb_str_new(buffer,size);
331
+ |}
332
+ END
333
+ builder.c(str.margin)
334
+ end
335
+ end
336
+ end
337
+ end