oinky 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +141 -0
  3. data/ext/extconf.rb +79 -0
  4. data/ext/include/oinky.h +424 -0
  5. data/ext/include/oinky.hpp +63 -0
  6. data/ext/include/oinky/nky_base.hpp +1116 -0
  7. data/ext/include/oinky/nky_core.hpp +1603 -0
  8. data/ext/include/oinky/nky_cursor.hpp +665 -0
  9. data/ext/include/oinky/nky_dialect.hpp +107 -0
  10. data/ext/include/oinky/nky_error.hpp +164 -0
  11. data/ext/include/oinky/nky_fixed_table.hpp +710 -0
  12. data/ext/include/oinky/nky_handle.hpp +334 -0
  13. data/ext/include/oinky/nky_index.hpp +1038 -0
  14. data/ext/include/oinky/nky_log.hpp +15 -0
  15. data/ext/include/oinky/nky_merge_itr.hpp +403 -0
  16. data/ext/include/oinky/nky_model.hpp +110 -0
  17. data/ext/include/oinky/nky_pool.hpp +760 -0
  18. data/ext/include/oinky/nky_public.hpp +808 -0
  19. data/ext/include/oinky/nky_serializer.hpp +1625 -0
  20. data/ext/include/oinky/nky_strtable.hpp +504 -0
  21. data/ext/include/oinky/nky_table.hpp +1996 -0
  22. data/ext/nky_lib.cpp +390 -0
  23. data/ext/nky_lib_core.hpp +212 -0
  24. data/ext/nky_lib_index.cpp +158 -0
  25. data/ext/nky_lib_table.cpp +224 -0
  26. data/lib/oinky.rb +1284 -0
  27. data/lib/oinky/compiler.rb +106 -0
  28. data/lib/oinky/cpp_emitter.rb +311 -0
  29. data/lib/oinky/dsl.rb +167 -0
  30. data/lib/oinky/error.rb +19 -0
  31. data/lib/oinky/modelbase.rb +12 -0
  32. data/lib/oinky/nbuffer.rb +152 -0
  33. data/lib/oinky/normalize.rb +132 -0
  34. data/lib/oinky/oc_builder.rb +44 -0
  35. data/lib/oinky/query.rb +193 -0
  36. data/lib/oinky/rb_emitter.rb +147 -0
  37. data/lib/oinky/shard.rb +40 -0
  38. data/lib/oinky/testsup.rb +104 -0
  39. data/lib/oinky/version.rb +9 -0
  40. data/oinky.gemspec +36 -0
  41. metadata +120 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ This project is distributed under the MIT License
2
+
3
+ Copyright (c) 2012, Jacob Lacouture
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a
6
+ copy of this software and associated documentation files (the "Software"),
7
+ to deal in the Software without restriction, including without limitation
8
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ and/or sell copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ DEALINGS IN THE SOFTWARE.
22
+
@@ -0,0 +1,141 @@
1
+ ## What is Oinky?
2
+
3
+ Oinky is an in-memory relational database library that supports fast serialization and deserialization. It is a tool for transforming the representation of data between the application (as a database) and network or storage (as a string of bytes). It is a database (like sqlite), but also an encoder (like Protocol Buffers).
4
+
5
+ The implementation is C++, and currently includes bindings for C and Ruby.
6
+
7
+ ## Applications
8
+
9
+ Oinky is a general purpose serialization library. It has tons of potential applications. Many excellent serialization libraries exist, but complex data structures like graphs can be cumbersome to encode with the best of them. Oinky's relational facility makes it well suited to such tasks, as relational schemas can naturally and efficiently represent data of arbitrary topology.
10
+
11
+ ### Microsharding
12
+
13
+ Microsharding is a scheme for deploying quasi-relational databases over distributed key-value storage platforms. Oinky provides the relational adapter. The rationale behind microsharding is described in more detail in a [blog post][blog].
14
+
15
+ [blog]: http://jkub.github.com/2012/03/21/microsharding/
16
+
17
+ ## Sample
18
+
19
+ The following sample is inspired by the Sequel sample at [http://sequel.rubyforge.org][sequel]
20
+
21
+ [sequel]: http://sequel.rubyforge.org "The Sequel Database Library"
22
+
23
+ require 'oinky'
24
+
25
+ db = Oinky::DB.new
26
+
27
+ db.atomic {
28
+ db.create_table(:items) { |tbl|
29
+ tbl.add_column(:id, :int32, 0)
30
+ tbl.add_column(:name, :string, '')
31
+ tbl.add_column(:price, :int32, 0)
32
+
33
+ tbl.add_index(:name=>'by_name', :unique=>true, :columns=>[:name])
34
+ }
35
+ }
36
+
37
+ items = db[:items]
38
+
39
+ items.insert_row(:name => 'abc', :price => (rand * 100).to_i)
40
+ items.insert_row(:name => 'def', :price => (rand * 100).to_i)
41
+ items.insert_row(:name => 'ghi', :price => (rand * 100).to_i)
42
+
43
+ # print out the number of records
44
+ puts "Item count: #{items.row_count}"
45
+
46
+ puts "Items table contains:"
47
+ items.each{ |row|
48
+ # row is a hash of colname=>value
49
+ puts row.inspect
50
+ }
51
+
52
+ # print out the average over a specific column
53
+ avg = items.each.average(:price)
54
+ puts "The average price is: #{avg}"
55
+
56
+ # Using a lambda explicitly to compute something more complex
57
+ # (and ideally less useless).
58
+ db[:items].each.average(lambda {|r| r[:price] + r[:name].size} )
59
+
60
+ # Serialize
61
+ str = db.serialize
62
+ puts "The serialized database consumes #{str.length} bytes"
63
+
64
+ # Create a clone
65
+ db2 = Oinky::DB.mount(str)
66
+
67
+ db2.alter_table(:items) { |tbl|
68
+ tbl.add_index(:name=>'by_price', :unique=>false, :columns=>[:price])
69
+ }
70
+
71
+ puts "Items by price:"
72
+ db2[:items].indices[:by_price].each {|row|
73
+ puts row.inspect
74
+ }
75
+
76
+ str2 = db2.serialize
77
+ puts "With the price index, the serialized database consumes #{str2.length} bytes"
78
+
79
+
80
+ ## Implementation
81
+
82
+ See the [design][design] document for an overview of behavior and implementation.
83
+
84
+ [design]: http://github.com/oinky/oinky/blob/master/doc/design.md "Design"
85
+
86
+
87
+ ### Performance
88
+
89
+ Oinky is designed to perform very well in specific scenarios. Design tradeoffs and performance properties are covered in the [performance document][perf].
90
+
91
+ [perf]: http://github.com/oinky/oinky/blob/master/doc/performance.md "Performance"
92
+
93
+ ### Status
94
+
95
+ Oinky is fast and stable, but very new. The interface is raw, and the library is unsupported by the tools and ORMs that help make relational schemas so compelling in the first place.
96
+
97
+ Nevertheless, Oinky is highly functional as it is, and offers open-ended opportunities for improvement.
98
+
99
+ ## Installation
100
+
101
+ Oinky is configured with autoconf and depends on the [boost C++ libraries][boost]. First you'll need to make sure boost and autotools are installed. Then you can generate the configure script as follows.
102
+
103
+ ./boostrap.sh
104
+
105
+ If boost is installed in a nonstandard location, you'll need to provide that location to the *configure* script. Additionally, building the ruby gem is optional, as it depends on ruby and rake. The following command illustrates the available options.
106
+
107
+ ./configure --with-boost-include-path=/usr/local/boost_1_47_0 \
108
+ --with-boost-lib-path=/usr/local/boost_1_47_0/stage/lib \
109
+ --enable-rubygem=yes --with-asserts=yes
110
+
111
+ Once you've configured, *make* will build the C library. *make install* will install the headers and C library. *make check* will build and run some sanity tests.
112
+
113
+ ### Ruby
114
+
115
+ Before installing the gem, you'll need to build it in (project_root)/lib/rubygem
116
+
117
+ The gem installer accepts the boost arguments in the same format as the *configure* script.
118
+
119
+ gem install oinky-0.1.0.gem -- --with-boost-include-path=/usr/local/boost_1_47_0 \
120
+ --with-boost-lib-path=/usr/local/boost_1_47_0/stage/lib
121
+
122
+ [boost]: http://www.boost.org/ "The Boost C++ Libraries"
123
+
124
+ The gem requires Ruby 1.9.x. Though the gem is built with FFI and is theoretically portable, only MRI currently works, due to differences in the FFI interface under JRuby and RBX.
125
+
126
+ ### Platforms
127
+
128
+ Oinky has been successfully built and tested on 64 bit OSX and 32/64 bit Linux with clang++(2.1) and g++(4.4 and 4.6) and boost versions 1.46 and 1.47. Various older compilers and boost versions have caused issues, though many may work. Oinky implements architecture-dependent byte-order conversion, but it's only been minimally tested.
129
+
130
+ ## Support
131
+
132
+ There is a [mailing list][group] where discussion may occur.
133
+
134
+ [group]: http://groups.google.com/group/oinky "The oinky mailing list"
135
+
136
+ ## License
137
+
138
+ Oinky is published under the terms of the MIT license. See the LICENSE file.
139
+
140
+
141
+
@@ -0,0 +1,79 @@
1
+ require 'mkmf'
2
+
3
+ # We may need to be told where the boost headers/libs are
4
+ dir_config('boost')
5
+ # The above assumes that the final dir component of all include dirs is
6
+ # 'include' which is not always the case, so we have to do this:
7
+
8
+ boostinc = nil
9
+ boostlib = nil
10
+
11
+ iprefix = '--with-boost-include-path='
12
+ lprefix = '--with-boost-lib-path='
13
+ withasserts = '--with-asserts=yes'
14
+
15
+ ARGV.each { |s|
16
+ if s[0..iprefix.size-1] == iprefix
17
+ boostinc = s[iprefix.size..-1]
18
+ newflags = " -I" + File.join(boostinc,'boost/tr1/tr1') + " -I" + boostinc + ' '
19
+ # Give the specified boost include path precedence over any default.
20
+ $INCFLAGS = newflags + $INCFLAGS
21
+ elsif s[0..lprefix.size-1] == lprefix
22
+ boostlib = s[lprefix.size..-1]
23
+ newflags = " -L" + boostlib + ' '
24
+ $LDFLAGS = newflags + $LDFLAGS
25
+ elsif s == withasserts
26
+ $CFLAGS += ' -DDEBUG'
27
+ end
28
+ }
29
+
30
+ $LDFLAGS += " -lboost_system"
31
+
32
+ # -flat_namespace causes HORRIBLE THINGS, so we have to remove it.
33
+ $DLDFLAGS = $DLDFLAGS.split(/\s/).select{ |str| /flat_namespace/ !~ str } * ' '
34
+
35
+ if boostinc
36
+ puts "Using #{boostinc} as boost header path."
37
+ end
38
+ if boostlib
39
+ puts "Using #{boostlib} as boost lib path."
40
+ end
41
+
42
+ unless boostinc or boostlib
43
+ puts "
44
+ Specify #{iprefix}<ipath> or #{lprefix}<lpath> to set
45
+ boost include and lib paths respectively, or use --with-boost-dir=<path>
46
+ to set include and lib paths to <path>/include and <path>/lib.
47
+
48
+ If you're doing a gem install, try:
49
+ gem install oinky -- --with-boost-include-path=<boostinc> --with-boost-lib-path=<boostlib>
50
+ "
51
+ end
52
+
53
+ puts "You may enable asserts in the C extension as follows:
54
+ gem install oinky -- --with-asserts=yes
55
+ "
56
+
57
+ =begin
58
+ #Is this bug 4924, which has been open 9 months?
59
+ #http://www.ruby-forum.com/topic/1994312#1007218
60
+
61
+ # This is the one boost lib we link to (for now)
62
+ #have_library('boost_system', 'boost::datetime::now')
63
+ # This is a TR1 library. Oinky will actually use the compiler's tr1 library if
64
+ # it's available, but this will be available as a backup if that's not available.
65
+ if boostinc
66
+ find_header('boost/tr1/tr1/unordered_map', [boostinc])
67
+ find_header('boost/type_traits.hpp', [boostinc])
68
+ else
69
+ have_header('boost/tr1/tr1/unordered_map')
70
+ have_header('boost/type_traits.hpp')
71
+ end
72
+ =end
73
+
74
+
75
+ # Give the gem-local Oinky implementation preference over any default installed version.
76
+ $INCFLAGS = ' -I./include ' + $INCFLAGS
77
+
78
+ create_makefile("liboinky_c")
79
+
@@ -0,0 +1,424 @@
1
+ // This source is distributed under the terms of the MIT License. Refer
2
+ // to the 'LICENSE' file for details.
3
+ //
4
+ // Copyright (c) Jacob Lacouture, 2012
5
+
6
+ #ifndef OINKY_H_INCLUDED
7
+ #define OINKY_H_INCLUDED
8
+
9
+ #include <stdint.h>
10
+ #include <string.h>
11
+
12
+ #ifdef __cplusplus
13
+ extern "C" {
14
+ #endif
15
+
16
+ // This is the C header for Oinky. To use this header, you must bind to the
17
+ // appropriate Oinky library. The C++ header requires no library.
18
+ //
19
+ // I don't expect anyone to use the C library directly. The only reason this
20
+ // exists is to provide simpler bindings for scripting languages (eg: Ruby FFI)
21
+
22
+ typedef struct _oinky_db_handle_t oinky_db_handle_t;
23
+ typedef struct _oinky_table_handle_t oinky_table_handle_t;
24
+ typedef struct _oinky_index_handle_t oinky_index_handle_t;
25
+ typedef struct _oinky_column_handle_t oinky_column_handle_t;
26
+ typedef struct _oinky_column_selector_t oinky_column_selector_t;
27
+ typedef struct _oinky_index_row_cursor_t oinky_index_row_cursor_t;
28
+ typedef struct _oinky_table_row_cursor_t oinky_table_row_cursor_t;
29
+
30
+ typedef struct _oinky_datetime_t {
31
+ uint64_t value;
32
+ } oinky_datetime_t;
33
+
34
+ typedef uint64_t oinky_savepoint_t;
35
+
36
+ typedef struct _oinky_db_string {
37
+ size_t length;
38
+ const char *bytes;
39
+ } oinky_db_string;
40
+
41
+ typedef enum _oinky_column_type_code_t
42
+ {
43
+ nky_Variant = 0,
44
+
45
+ // The rest are identical to value_type_code
46
+ nky_Bit = 1,
47
+ nky_Int8 = 2,
48
+ nky_Int16 = 3,
49
+ nky_Int32 = 4,
50
+ nky_Int64 = 5,
51
+ nky_Datetime = 6,
52
+ nky_String = 7,
53
+ // more inline types
54
+ nky_Uint8 = 8,
55
+ nky_Uint16 = 9,
56
+ nky_Uint32 = 10,
57
+ nky_Uint64 = 11,
58
+ nky_Float32 = 12,
59
+ nky_Float64 = 13
60
+ } oinky_column_type_code_t;
61
+
62
+ // conditioning on platform may become necessary.
63
+ typedef double float64_t;
64
+ typedef float float32_t;
65
+
66
+ typedef struct _oinky_db_variant {
67
+ union {
68
+ oinky_db_string string_value;
69
+ int64_t int_value;
70
+ uint64_t uint_value;
71
+ float64_t f64_value;
72
+ float32_t f32_value;
73
+ oinky_datetime_t dt_value;
74
+ } value;
75
+ oinky_column_type_code_t type;
76
+ } oinky_db_variant;
77
+
78
+ inline oinky_db_string nky_string_from_immediate(const char *str) {
79
+ oinky_db_string s = {strlen(str), str};
80
+ return s;
81
+ }
82
+ inline oinky_db_variant nky_variant_from_immediate_s(const char *str) {
83
+ oinky_db_variant v;
84
+ v.value.string_value = nky_string_from_immediate(str);
85
+ v.type = nky_String;
86
+ return v;
87
+ }
88
+ inline oinky_db_variant nky_variant_from_immediate_dbs(oinky_db_string str) {
89
+ oinky_db_variant v;
90
+ v.value.string_value = str;
91
+ v.type = nky_String;
92
+ return v;
93
+ }
94
+ inline oinky_db_variant nky_variant_from_immediate_dt(oinky_datetime_t dt) {
95
+ oinky_db_variant v;
96
+ v.value.dt_value = dt;
97
+ v.type = nky_Datetime;
98
+ return v;
99
+ }
100
+ //int
101
+ inline oinky_db_variant nky_variant_from_immediate_i64(int64_t x) {
102
+ oinky_db_variant v;
103
+ v.value.int_value = x;
104
+ v.type = nky_Int64;
105
+ return v;
106
+ }
107
+ inline oinky_db_variant nky_variant_from_immediate_i32(int32_t x) {
108
+ oinky_db_variant v;
109
+ v.value.int_value = x;
110
+ v.type = nky_Int32;
111
+ return v;
112
+ }
113
+ inline oinky_db_variant nky_variant_from_immediate_i16(int16_t x) {
114
+ oinky_db_variant v;
115
+ v.value.int_value = x;
116
+ v.type = nky_Int16;
117
+ return v;
118
+ }
119
+ inline oinky_db_variant nky_variant_from_immediate_i8(int8_t x) {
120
+ oinky_db_variant v;
121
+ v.value.int_value = x;
122
+ v.type = nky_Int8;
123
+ return v;
124
+ }
125
+ //uint
126
+ inline oinky_db_variant nky_variant_from_immediate_ui64(uint64_t x) {
127
+ oinky_db_variant v;
128
+ v.value.uint_value = x;
129
+ v.type = nky_Uint64;
130
+ return v;
131
+ }
132
+ inline oinky_db_variant nky_variant_from_immediate_ui32(uint32_t x) {
133
+ oinky_db_variant v;
134
+ v.value.uint_value = x;
135
+ v.type = nky_Uint32;
136
+ return v;
137
+ }
138
+ inline oinky_db_variant nky_variant_from_immediate_ui16(uint16_t x) {
139
+ oinky_db_variant v;
140
+ v.value.uint_value = x;
141
+ v.type = nky_Uint16;
142
+ return v;
143
+ }
144
+ inline oinky_db_variant nky_variant_from_immediate_ui8(uint8_t x) {
145
+ oinky_db_variant v;
146
+ v.value.uint_value = x;
147
+ v.type = nky_Uint8;
148
+ return v;
149
+ }
150
+
151
+ inline oinky_db_variant nky_variant_from_immediate_bit(int x) {
152
+ oinky_db_variant v;
153
+ v.value.int_value = x ? 1 : 0;
154
+ v.type = nky_Bit;
155
+ return v;
156
+ }
157
+
158
+ //float
159
+ inline oinky_db_variant nky_variant_from_immediate_f64(float64_t x) {
160
+ oinky_db_variant v;
161
+ v.value.f64_value = x;
162
+ v.type = nky_Float64;
163
+ return v;
164
+ }
165
+ inline oinky_db_variant nky_variant_from_immediate_f32(float32_t x) {
166
+ oinky_db_variant v;
167
+ v.value.f32_value = x;
168
+ v.type = nky_Float32;
169
+ return v;
170
+ }
171
+
172
+ // We still want to export these.
173
+ oinky_db_variant _nky_variant_from_immediate_s(const char *str);
174
+ oinky_db_variant _nky_variant_from_immediate_dt(oinky_datetime_t dt);
175
+ oinky_db_variant _nky_variant_from_immediate_i64(int64_t x);
176
+ oinky_db_variant _nky_variant_from_immediate_i32(int32_t x);
177
+ oinky_db_variant _nky_variant_from_immediate_i16(int16_t x);
178
+ oinky_db_variant _nky_variant_from_immediate_i8(int8_t x);
179
+ oinky_db_variant _nky_variant_from_immediate_ui64(uint64_t x);
180
+ oinky_db_variant _nky_variant_from_immediate_ui32(uint32_t x);
181
+ oinky_db_variant _nky_variant_from_immediate_ui16(uint16_t x);
182
+ oinky_db_variant _nky_variant_from_immediate_ui8(uint8_t x);
183
+ oinky_db_variant _nky_variant_from_immediate_f64(float64_t x);
184
+ oinky_db_variant _nky_variant_from_immediate_f32(float32_t x);
185
+ oinky_db_variant _nky_variant_from_immediate_bit(int x);
186
+
187
+ typedef struct _oinky_column_def {
188
+ oinky_db_string column_name;
189
+ oinky_column_type_code_t column_type;
190
+ oinky_db_variant default_value;
191
+ } oinky_column_def;
192
+
193
+ typedef struct _oinky_index_column_def {
194
+ oinky_db_string column_name;
195
+ char sort_ascending;
196
+ } oinky_index_column_def;
197
+
198
+ typedef enum
199
+ {
200
+ nky_success = 0,
201
+
202
+ nky_implementation_bug = -1,
203
+ nky_no_resources = -2,
204
+ nky_invalid_argument = -5,
205
+ nky_unknown_exception = -6,
206
+ nky_row_format_mismatch = -8,
207
+ nky_column_type_mismatch = -9,
208
+ nky_object_deleted = -10,
209
+ nky_object_exists = -11,
210
+ nky_index_entry_not_unique = -12,
211
+ nky_version_mismatch = -13,
212
+ nky_unsupported_operation = -14,
213
+ nky_object_still_referenced = -15,
214
+ nky_incomparable_value_types = -16,
215
+ nky_column_not_indexable = -17,
216
+ nky_object_not_found = -18,
217
+ nky_buffer_overflow = -19,
218
+ nky_buffer_underflow = -20,
219
+ nky_bad_encoding = -21,
220
+ nky_cursor_out_of_range = -22,
221
+ nky_limit_exceeded = -23
222
+ } oinky_error;
223
+
224
+ const char *convert_oinky_error(oinky_error err);
225
+
226
+ // This is the structure that represents the datetime in a way the client can
227
+ // understand it, as opposed to the opaque int64 type with which we represent
228
+ // it in storage.
229
+ struct nky_datetime_unpacked {
230
+ int32_t years_since_1900;
231
+ uint8_t months_since_january;
232
+ uint8_t days_since_first_of_month;
233
+ uint8_t hours_since_midnight;
234
+ uint8_t minutes_since_hour;
235
+ uint8_t seconds_since_minute;
236
+ uint32_t microseconds_since_second;
237
+ };
238
+
239
+ oinky_error nky_pack_datetime(oinky_datetime_t *dt, nky_datetime_unpacked unpacked);
240
+ oinky_error nky_unpack_datetime(oinky_datetime_t dt, nky_datetime_unpacked *unpacked);
241
+
242
+ //##############
243
+ // Managing DB instances
244
+
245
+ // Allocate a new, empty DB instance. This must be freed with oinky_db_free.
246
+ // Returns NULL on error.
247
+ oinky_db_handle_t *oinky_db_new();
248
+
249
+ // Create a new DB instance from serialized bytes. The new handle will
250
+ // continue to access the given buffer until it is destroyed and the caller
251
+ // should manage the lifetimes of both the DB handle and bytestring appropriately.
252
+ oinky_error oinky_db_mount(oinky_db_handle_t **handle, size_t bufferlen, const char *bytes);
253
+
254
+ // Destroy and deallocate an oinky DB instance.
255
+ void oinky_db_free(oinky_db_handle_t *db);
256
+
257
+ // Compute the number of bytes required to serialize the given database.
258
+ oinky_error oinky_db_prepare_pack(oinky_db_handle_t *db, size_t *required_bytes);
259
+ // Serialize the database to the given buffer.
260
+ oinky_error oinky_db_complete_pack(oinky_db_handle_t *db, size_t bufferlen, char *buffer);
261
+
262
+ // Create a savepoint and save the marker at the given address.
263
+ oinky_error oinky_db_create_savepoint(oinky_db_handle_t *db, oinky_savepoint_t *sp);
264
+ oinky_error oinky_db_savepoint_rollback(oinky_db_handle_t *db, oinky_savepoint_t sp);
265
+
266
+ //##############
267
+ // Stats/Properties
268
+
269
+ int oinky_db_is_modified_since(oinky_db_handle_t *db, oinky_savepoint_t sp);
270
+ size_t oinky_table_count(oinky_db_handle_t *db);
271
+ size_t oinky_tbl_column_count(oinky_table_handle_t *table);
272
+ size_t oinky_idx_column_count(oinky_index_handle_t *index);
273
+ size_t oinky_tbl_index_count(oinky_table_handle_t *table);
274
+ size_t oinky_tbl_row_count(oinky_table_handle_t *table);
275
+ size_t oinky_idx_row_count(oinky_index_handle_t *index);
276
+ oinky_db_string oinky_table_name(oinky_table_handle_t *table);
277
+ oinky_db_string oinky_index_name(oinky_index_handle_t *index);
278
+
279
+
280
+ //##############
281
+ // Navigating the DB hierarchy
282
+ //
283
+ // These really shouldn't be necessary. Unlike the C++ API, which is designed
284
+ // for usability, this interface should be minimal.
285
+ //
286
+ //oinky_db_handle_t *oinky_db_from_table_handle(oinky_table_handle_t *table);
287
+ //oinky_table_handle_t *oinky_table_from_index_handle(oinky_index_handle_t *index);
288
+ //oinky_table_handle_t *oinky_table_from_column_handle(oinky_column_handle_t *column);
289
+ //oinky_index_handle_t *oinky_index_from_cursor(oinky_index_row_cursor_t *cursor);
290
+
291
+
292
+
293
+ //##############
294
+ // Enumerating objects
295
+
296
+ // These methods do not allocate. The caller should invoke one of the counting
297
+ // routines above to determine how many handles there are, and then allocate
298
+ // an array to receive the handles, and then pass it to one of these routines
299
+ // which will fill the array with pointers.
300
+ //
301
+ // Both routines return the number of handles saved. If the array is not big
302
+ // enough to receive all the handles, only the first <array_size> handles
303
+ // are returned. Enumeration always starts at the first handle. To retrieve
304
+ // the last handle, an array must be supplied which is large enough to receive
305
+ // all handles.
306
+ //
307
+ // Tables and indices are enumerated in order by name.
308
+ size_t oinky_db_get_table_handles(oinky_db_handle_t *db, oinky_table_handle_t **handle_array, size_t array_size);
309
+ size_t oinky_table_get_index_handles(oinky_table_handle_t *table, oinky_index_handle_t **handle_array, size_t array_size);
310
+ size_t oinky_table_get_column_defs(oinky_table_handle_t *table, oinky_column_def *def_array, size_t array_size);
311
+ oinky_error oinky_index_get_definition(oinky_index_handle_t *index, oinky_db_string *name, char *is_unique, oinky_index_column_def *def_array, size_t array_size);
312
+
313
+ //##############
314
+ // Schema Modification
315
+ oinky_error oinky_db_create_table(oinky_db_handle_t *db, const char *name, oinky_table_handle_t **handle);
316
+ oinky_error oinky_db_drop_table(oinky_db_handle_t *db, oinky_db_string tblname);
317
+ oinky_error oinky_table_add_column(oinky_table_handle_t *table, oinky_column_def defn);
318
+ oinky_error oinky_table_drop_column(oinky_table_handle_t *table, oinky_db_string colname);
319
+ oinky_error oinky_table_drop_index(oinky_table_handle_t *table, oinky_db_string idxname);
320
+
321
+ oinky_error oinky_table_add_index(
322
+ oinky_table_handle_t *table,
323
+ const char *idxname,
324
+ char unique,
325
+ size_t col_count,
326
+ const oinky_index_column_def *coldefs,
327
+ oinky_index_handle_t **ih);
328
+
329
+ //##############
330
+ // Data Access
331
+
332
+ oinky_error oinky_table_make_column_selector(oinky_table_handle_t *table, size_t col_count, char **colnames, oinky_column_selector_t **selector);
333
+ oinky_error oinky_table_delete_column_selector(oinky_table_handle_t *table, oinky_column_selector_t *selector);
334
+
335
+ // Update the columns (identified by column_selector) at the row (identified by cursor) with the given values.
336
+ oinky_error oinky_table_update_row_at_index_cursor(oinky_table_handle_t *table, oinky_index_row_cursor_t *cursor, oinky_column_selector_t *selector, size_t col_count, const oinky_db_variant *values);
337
+ oinky_error oinky_table_update_row_at_table_cursor(oinky_table_handle_t *table, oinky_table_row_cursor_t *cursor, oinky_column_selector_t *selector, size_t col_count, const oinky_db_variant *values);
338
+
339
+ // Delete the row identified by the cursor.
340
+ oinky_error oinky_table_delete_row_at_index_cursor(oinky_table_handle_t *table, oinky_index_row_cursor_t *cursor);
341
+ oinky_error oinky_table_delete_row_at_table_cursor(oinky_table_handle_t *table, oinky_table_row_cursor_t *cursor);
342
+
343
+ oinky_error oinky_table_insert_row(oinky_table_handle_t *table, oinky_column_selector_t *selector, size_t col_count, const oinky_db_variant *values);
344
+
345
+ //##############
346
+ // Index cursors
347
+
348
+ // Create a cursor at the beginning of the index.
349
+ oinky_error oinky_index_cursor_new(oinky_index_handle_t *index, oinky_index_row_cursor_t **crs);
350
+ oinky_error oinky_index_cursor_clone(oinky_index_handle_t *index, oinky_index_row_cursor_t *src, oinky_index_row_cursor_t **newcrs);
351
+ void oinky_index_cursor_free(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
352
+ oinky_error oinky_index_cursor_get_values(oinky_index_row_cursor_t *crs, oinky_column_selector_t *selector, size_t vcount, oinky_db_variant *out_values, size_t *out_value_count);
353
+
354
+ oinky_error oinky_index_cursor_seek_last(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
355
+ oinky_error oinky_index_cursor_seek_first(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
356
+
357
+ // Moves the given cursor to a position in the index defined by the given set of values.
358
+ // lower_bound and upper_bound are equivalent to their STL meanings.
359
+ oinky_error oinky_index_cursor_seek_lower_bound(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs, size_t seq_len, const oinky_db_variant *value_seq);
360
+ oinky_error oinky_index_cursor_seek_upper_bound(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs, size_t seq_len, const oinky_db_variant *value_seq);
361
+ // If found, returns success and sets cursor to element. If not found,
362
+ // return ObjectNotFound and sets cursor to end (state == 1). Analogous
363
+ // to STL find.
364
+ oinky_error oinky_index_cursor_seek_exact(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs, size_t seq_len, const oinky_db_variant *value_seq);
365
+ // increment/decrement
366
+ oinky_error oinky_index_cursor_seek_next(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
367
+ oinky_error oinky_index_cursor_seek_prev(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
368
+
369
+ // Returns -1 if cursor is before beginning of sequence,
370
+ // 0 if it is on a valid element,
371
+ // and 1 if it is beyond the end of the sequence.
372
+ int8_t oinky_index_cursor_state(oinky_index_handle_t *index, oinky_index_row_cursor_t *crs);
373
+
374
+ //##############
375
+ // Table cursors
376
+
377
+ // Create a cursor at the beginning of the table.
378
+ oinky_error oinky_table_cursor_new(oinky_table_handle_t *table, oinky_table_row_cursor_t **crs);
379
+ oinky_error oinky_table_cursor_clone(oinky_table_handle_t *table, oinky_table_row_cursor_t *src, oinky_table_row_cursor_t **newcrs);
380
+ void oinky_table_cursor_free(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
381
+ oinky_error oinky_table_cursor_get_values(oinky_table_row_cursor_t *crs, oinky_column_selector_t *selector, size_t vcount, oinky_db_variant *out_values, size_t *out_value_count);
382
+
383
+ oinky_error oinky_table_cursor_seek_last(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
384
+ oinky_error oinky_table_cursor_seek_first(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
385
+
386
+ // increment/decrement
387
+ oinky_error oinky_table_cursor_seek_next(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
388
+ oinky_error oinky_table_cursor_seek_prev(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
389
+
390
+ // Returns -1 if cursor is before beginning of sequence,
391
+ // 0 if it is on a valid element,
392
+ // and 1 if it is beyond the end of the sequence.
393
+ int8_t oinky_table_cursor_state(oinky_table_handle_t *table, oinky_table_row_cursor_t *crs);
394
+
395
+
396
+ //uint32 oinky_get_column_handles(oinky_table_handle_t **handle_array, unsigned array_size);
397
+ /*
398
+ // Invoke the callback with a handle for each table. Enumeration stops when
399
+ // the callback returns false, or the set of tables is exhausted.
400
+ // Tables are enumerated in order by name.
401
+ typedef bool (oinky_each_table_cb*)(oinky_db_handle_t *db, oinky_table_handle_t *table, void *cb_ctx);
402
+ void oinky_enum_tables(oinky_db_handle_t *db, oinky_each_table_cb cb, void *cb_ctx);
403
+
404
+ // Invoke the callback with a handle for each index. Same semantics as
405
+ // table enumeration
406
+ typedef bool (oinky_each_index_cb*)(oinky_table_handle_t *db, oinky_index_handle_t *index, void *cb_ctx);
407
+ void oinky_enum_indices(oinky_table_handle_t *db, oinky_each_index_cb cb, void *cb_ctx);
408
+
409
+ // Invoke the callback with a handle for each column. Same semantics as
410
+ // table enumeration
411
+ typedef bool (oinky_each_column_cb*)(oinky_table_handle_t *db, oinky_column_handle_t *column, void *cb_ctx);
412
+ void oinky_enum_columns(oinky_table_handle_t *db, oinky_each_column_cb cb, void *cb_ctx);
413
+ */
414
+
415
+ // Test support
416
+ void oinky_debug_break();
417
+
418
+ #ifdef __cplusplus
419
+ } //extern "C" {
420
+ #endif
421
+
422
+ //#ifndef OINKY_H_INCLUDED
423
+ #endif
424
+