sqlite3 1.3.8-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gemtest +0 -0
  2. data/API_CHANGES.rdoc +50 -0
  3. data/CHANGELOG.rdoc +265 -0
  4. data/ChangeLog.cvs +88 -0
  5. data/Gemfile +15 -0
  6. data/LICENSE +27 -0
  7. data/Manifest.txt +52 -0
  8. data/README.rdoc +95 -0
  9. data/Rakefile +10 -0
  10. data/ext/sqlite3/backup.c +168 -0
  11. data/ext/sqlite3/backup.h +15 -0
  12. data/ext/sqlite3/database.c +822 -0
  13. data/ext/sqlite3/database.h +15 -0
  14. data/ext/sqlite3/exception.c +94 -0
  15. data/ext/sqlite3/exception.h +8 -0
  16. data/ext/sqlite3/extconf.rb +51 -0
  17. data/ext/sqlite3/sqlite3.c +40 -0
  18. data/ext/sqlite3/sqlite3_ruby.h +53 -0
  19. data/ext/sqlite3/statement.c +439 -0
  20. data/ext/sqlite3/statement.h +16 -0
  21. data/faq/faq.rb +145 -0
  22. data/faq/faq.yml +426 -0
  23. data/lib/sqlite3.rb +10 -0
  24. data/lib/sqlite3/2.0/sqlite3_native.so +0 -0
  25. data/lib/sqlite3/constants.rb +49 -0
  26. data/lib/sqlite3/database.rb +579 -0
  27. data/lib/sqlite3/errors.rb +44 -0
  28. data/lib/sqlite3/pragmas.rb +280 -0
  29. data/lib/sqlite3/resultset.rb +195 -0
  30. data/lib/sqlite3/statement.rb +144 -0
  31. data/lib/sqlite3/translator.rb +118 -0
  32. data/lib/sqlite3/value.rb +57 -0
  33. data/lib/sqlite3/version.rb +25 -0
  34. data/setup.rb +1333 -0
  35. data/tasks/faq.rake +9 -0
  36. data/tasks/gem.rake +37 -0
  37. data/tasks/native.rake +45 -0
  38. data/tasks/vendor_sqlite3.rake +87 -0
  39. data/test/helper.rb +18 -0
  40. data/test/test_backup.rb +33 -0
  41. data/test/test_collation.rb +82 -0
  42. data/test/test_database.rb +350 -0
  43. data/test/test_database_readonly.rb +29 -0
  44. data/test/test_deprecated.rb +44 -0
  45. data/test/test_encoding.rb +121 -0
  46. data/test/test_integration.rb +555 -0
  47. data/test/test_integration_open_close.rb +30 -0
  48. data/test/test_integration_pending.rb +115 -0
  49. data/test/test_integration_resultset.rb +159 -0
  50. data/test/test_integration_statement.rb +194 -0
  51. data/test/test_result_set.rb +37 -0
  52. data/test/test_sqlite3.rb +9 -0
  53. data/test/test_statement.rb +256 -0
  54. data/test/test_statement_execute.rb +35 -0
  55. metadata +246 -0
@@ -0,0 +1,52 @@
1
+ API_CHANGES.rdoc
2
+ CHANGELOG.rdoc
3
+ ChangeLog.cvs
4
+ Gemfile
5
+ LICENSE
6
+ Manifest.txt
7
+ README.rdoc
8
+ Rakefile
9
+ ext/sqlite3/backup.c
10
+ ext/sqlite3/backup.h
11
+ ext/sqlite3/database.c
12
+ ext/sqlite3/database.h
13
+ ext/sqlite3/exception.c
14
+ ext/sqlite3/exception.h
15
+ ext/sqlite3/extconf.rb
16
+ ext/sqlite3/sqlite3.c
17
+ ext/sqlite3/sqlite3_ruby.h
18
+ ext/sqlite3/statement.c
19
+ ext/sqlite3/statement.h
20
+ faq/faq.rb
21
+ faq/faq.yml
22
+ lib/sqlite3.rb
23
+ lib/sqlite3/constants.rb
24
+ lib/sqlite3/database.rb
25
+ lib/sqlite3/errors.rb
26
+ lib/sqlite3/pragmas.rb
27
+ lib/sqlite3/resultset.rb
28
+ lib/sqlite3/statement.rb
29
+ lib/sqlite3/translator.rb
30
+ lib/sqlite3/value.rb
31
+ lib/sqlite3/version.rb
32
+ setup.rb
33
+ tasks/faq.rake
34
+ tasks/gem.rake
35
+ tasks/native.rake
36
+ tasks/vendor_sqlite3.rake
37
+ test/helper.rb
38
+ test/test_backup.rb
39
+ test/test_collation.rb
40
+ test/test_database.rb
41
+ test/test_database_readonly.rb
42
+ test/test_deprecated.rb
43
+ test/test_encoding.rb
44
+ test/test_integration.rb
45
+ test/test_integration_open_close.rb
46
+ test/test_integration_pending.rb
47
+ test/test_integration_resultset.rb
48
+ test/test_integration_statement.rb
49
+ test/test_result_set.rb
50
+ test/test_sqlite3.rb
51
+ test/test_statement.rb
52
+ test/test_statement_execute.rb
@@ -0,0 +1,95 @@
1
+ = SQLite3/Ruby Interface
2
+
3
+ * http://github.com/luislavena/sqlite3-ruby
4
+ * http://groups.google.com/group/sqlite3-ruby
5
+
6
+ == DESCRIPTION
7
+
8
+ This module allows Ruby programs to interface with the SQLite3
9
+ database engine (http://www.sqlite.org). You must have the
10
+ SQLite engine installed in order to build this module.
11
+
12
+ Note that this module is only compatible with SQLite 3.6.16 or newer.
13
+
14
+ == SYNOPSIS
15
+
16
+ require "sqlite3"
17
+
18
+ # Open a database
19
+ db = SQLite3::Database.new "test.db"
20
+
21
+ # Create a database
22
+ rows = db.execute <<-SQL
23
+ create table numbers (
24
+ name varchar(30),
25
+ val int
26
+ );
27
+ SQL
28
+
29
+ # Execute a few inserts
30
+ {
31
+ "one" => 1,
32
+ "two" => 2,
33
+ }.each do |pair|
34
+ db.execute "insert into numbers values ( ?, ? )", pair
35
+ end
36
+
37
+ # Find a few rows
38
+ db.execute( "select * from numbers" ) do |row|
39
+ p row
40
+ end
41
+
42
+
43
+ == Compilation and Installation
44
+
45
+ Install SQLite3, enabling the option SQLITE_ENABLE_COLUMN_METADATA (see
46
+ www.sqlite.org/compile.html for details).
47
+
48
+ Then do the following:
49
+
50
+ ruby setup.rb config
51
+ ruby setup.rb setup
52
+ ruby setup.rb install
53
+
54
+ Alternatively, you can download and install the RubyGem package for
55
+ SQLite3/Ruby (you must have RubyGems and SQLite3 installed, first):
56
+
57
+ gem install sqlite3
58
+
59
+ If you have sqlite3 installed in a non-standard location, you can specify the location of the include and lib files by doing:
60
+
61
+ gem install sqlite3 -- --with-sqlite3-include=/opt/local/include \
62
+ --with-sqlite3-lib=/opt/local/lib
63
+
64
+ = SUPPORT!!!
65
+
66
+ == OMG! Something has gone wrong! Where do I get help?
67
+
68
+ The best place to get help is from the
69
+ {sqlite3-ruby mailing list}[http://groups.google.com/group/sqlite3-ruby] which
70
+ can be found here:
71
+
72
+ * http://groups.google.com/group/sqlite3-ruby
73
+
74
+ == I've found a bug! Where do I file it?
75
+
76
+ Uh oh. After contacting the mailing list, you've found that you've actually
77
+ discovered a bug. You can file the bug at the
78
+ {github issues page}[http://github.com/luislavena/sqlite3-ruby/issues]
79
+ which can be found here:
80
+
81
+ * http://github.com/luislavena/sqlite3-ruby/issues
82
+
83
+ == Usage
84
+
85
+ For help figuring out the SQLite3/Ruby interface, check out the
86
+ SYNOPSIS as well as the RDoc. It includes examples of
87
+ usage. If you have any questions that you feel should be address in the
88
+ FAQ, please send them to {the mailing list}[http://groups.google.com/group/sqlite3-ruby]
89
+
90
+ == Source Code
91
+
92
+ The source repository is accessible via git:
93
+
94
+ git clone git://github.com/luislavena/sqlite3-ruby.git
95
+
@@ -0,0 +1,10 @@
1
+ #
2
+ # NOTE: Keep this file clean.
3
+ # Add your customizations inside tasks directory.
4
+ # Thank You.
5
+ #
6
+
7
+ # load rakefile extensions (tasks)
8
+ Dir['tasks/*.rake'].sort.each { |f| load f }
9
+
10
+ # vim: syntax=ruby
@@ -0,0 +1,168 @@
1
+ #ifdef HAVE_SQLITE3_BACKUP_INIT
2
+
3
+ #include <sqlite3_ruby.h>
4
+
5
+ #define REQUIRE_OPEN_BACKUP(_ctxt) \
6
+ if(!_ctxt->p) \
7
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed backup");
8
+
9
+ VALUE cSqlite3Backup;
10
+
11
+ static void deallocate(void * ctx)
12
+ {
13
+ sqlite3BackupRubyPtr c = (sqlite3BackupRubyPtr)ctx;
14
+ xfree(c);
15
+ }
16
+
17
+ static VALUE allocate(VALUE klass)
18
+ {
19
+ sqlite3BackupRubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3BackupRuby));
20
+ return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
21
+ }
22
+
23
+ /* call-seq: SQLite3::Backup.new(dstdb, dstname, srcdb, srcname)
24
+ *
25
+ * Initialize backup the backup.
26
+ *
27
+ * dstdb:
28
+ * the destination SQLite3::Database object.
29
+ * dstname:
30
+ * the destination's database name.
31
+ * srcdb:
32
+ * the source SQLite3::Database object.
33
+ * srcname:
34
+ * the source's database name.
35
+ *
36
+ * The database name is "main", "temp", or the name specified in an
37
+ * ATTACH statement.
38
+ *
39
+ * This feature requires SQLite 3.6.11 or later.
40
+ *
41
+ * require 'sqlite3'
42
+ * sdb = SQLite3::Database.new('src.sqlite3')
43
+ *
44
+ * ddb = SQLite3::Database.new(':memory:')
45
+ * b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
46
+ * p [b.remaining, b.pagecount] # invalid value; for example [0, 0]
47
+ * begin
48
+ * p b.step(1) #=> OK or DONE
49
+ * p [b.remaining, b.pagecount]
50
+ * end while b.remaining > 0
51
+ * b.finish
52
+ *
53
+ * ddb = SQLite3::Database.new(':memory:')
54
+ * b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
55
+ * b.step(-1) #=> DONE
56
+ * b.finish
57
+ *
58
+ */
59
+ static VALUE initialize(VALUE self, VALUE dstdb, VALUE dstname, VALUE srcdb, VALUE srcname)
60
+ {
61
+ sqlite3BackupRubyPtr ctx;
62
+ sqlite3RubyPtr ddb_ctx, sdb_ctx;
63
+ sqlite3_backup *pBackup;
64
+
65
+ Data_Get_Struct(self, sqlite3BackupRuby, ctx);
66
+ Data_Get_Struct(dstdb, sqlite3Ruby, ddb_ctx);
67
+ Data_Get_Struct(srcdb, sqlite3Ruby, sdb_ctx);
68
+
69
+ if(!sdb_ctx->db)
70
+ rb_raise(rb_eArgError, "cannot backup from a closed database");
71
+ if(!ddb_ctx->db)
72
+ rb_raise(rb_eArgError, "cannot backup to a closed database");
73
+
74
+ pBackup = sqlite3_backup_init(ddb_ctx->db, StringValuePtr(dstname),
75
+ sdb_ctx->db, StringValuePtr(srcname));
76
+ if( pBackup ){
77
+ ctx->p = pBackup;
78
+ }
79
+ else {
80
+ CHECK(ddb_ctx->db, sqlite3_errcode(ddb_ctx->db));
81
+ }
82
+
83
+ return self;
84
+ }
85
+
86
+ /* call-seq: SQLite3::Backup#step(nPage)
87
+ *
88
+ * Copy database pages up to +nPage+.
89
+ * If negative, copy all remaining source pages.
90
+ *
91
+ * If all pages are copied, it returns SQLite3::Constants::ErrorCode::DONE.
92
+ * When coping is not done, it returns SQLite3::Constants::ErrorCode::OK.
93
+ * When some errors occur, it returns the error code.
94
+ */
95
+ static VALUE step(VALUE self, VALUE nPage)
96
+ {
97
+ sqlite3BackupRubyPtr ctx;
98
+ int status;
99
+
100
+ Data_Get_Struct(self, sqlite3BackupRuby, ctx);
101
+ REQUIRE_OPEN_BACKUP(ctx);
102
+ status = sqlite3_backup_step(ctx->p, NUM2INT(nPage));
103
+ return INT2NUM(status);
104
+ }
105
+
106
+ /* call-seq: SQLite3::Backup#finish
107
+ *
108
+ * Destroy the backup object.
109
+ */
110
+ static VALUE finish(VALUE self)
111
+ {
112
+ sqlite3BackupRubyPtr ctx;
113
+
114
+ Data_Get_Struct(self, sqlite3BackupRuby, ctx);
115
+ REQUIRE_OPEN_BACKUP(ctx);
116
+ (void)sqlite3_backup_finish(ctx->p);
117
+ ctx->p = NULL;
118
+ return Qnil;
119
+ }
120
+
121
+ /* call-seq: SQLite3::Backup#remaining
122
+ *
123
+ * Returns the number of pages still to be backed up.
124
+ *
125
+ * Note that the value is only updated after step() is called,
126
+ * so before calling step() returned value is invalid.
127
+ */
128
+ static VALUE remaining(VALUE self)
129
+ {
130
+ sqlite3BackupRubyPtr ctx;
131
+
132
+ Data_Get_Struct(self, sqlite3BackupRuby, ctx);
133
+ REQUIRE_OPEN_BACKUP(ctx);
134
+ return INT2NUM(sqlite3_backup_remaining(ctx->p));
135
+ }
136
+
137
+ /* call-seq: SQLite3::Backup#pagecount
138
+ *
139
+ * Returns the total number of pages in the source database file.
140
+ *
141
+ * Note that the value is only updated after step() is called,
142
+ * so before calling step() returned value is invalid.
143
+ */
144
+ static VALUE pagecount(VALUE self)
145
+ {
146
+ sqlite3BackupRubyPtr ctx;
147
+
148
+ Data_Get_Struct(self, sqlite3BackupRuby, ctx);
149
+ REQUIRE_OPEN_BACKUP(ctx);
150
+ return INT2NUM(sqlite3_backup_pagecount(ctx->p));
151
+ }
152
+
153
+ void init_sqlite3_backup()
154
+ {
155
+ #if 0
156
+ VALUE mSqlite3 = rb_define_module("SQLite3");
157
+ #endif
158
+ cSqlite3Backup = rb_define_class_under(mSqlite3, "Backup", rb_cObject);
159
+
160
+ rb_define_alloc_func(cSqlite3Backup, allocate);
161
+ rb_define_method(cSqlite3Backup, "initialize", initialize, 4);
162
+ rb_define_method(cSqlite3Backup, "step", step, 1);
163
+ rb_define_method(cSqlite3Backup, "finish", finish, 0);
164
+ rb_define_method(cSqlite3Backup, "remaining", remaining, 0);
165
+ rb_define_method(cSqlite3Backup, "pagecount", pagecount, 0);
166
+ }
167
+
168
+ #endif
@@ -0,0 +1,15 @@
1
+ #if !defined(SQLITE3_BACKUP_RUBY) && defined(HAVE_SQLITE3_BACKUP_INIT)
2
+ #define SQLITE3_BACKUP_RUBY
3
+
4
+ #include <sqlite3_ruby.h>
5
+
6
+ struct _sqlite3BackupRuby {
7
+ sqlite3_backup *p;
8
+ };
9
+
10
+ typedef struct _sqlite3BackupRuby sqlite3BackupRuby;
11
+ typedef sqlite3BackupRuby * sqlite3BackupRubyPtr;
12
+
13
+ void init_sqlite3_backup();
14
+
15
+ #endif
@@ -0,0 +1,822 @@
1
+ #include <sqlite3_ruby.h>
2
+
3
+ #define REQUIRE_OPEN_DB(_ctxt) \
4
+ if(!_ctxt->db) \
5
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
6
+
7
+ VALUE cSqlite3Database;
8
+ static VALUE sym_utf16, sym_results_as_hash, sym_type_translation;
9
+
10
+ static void deallocate(void * ctx)
11
+ {
12
+ sqlite3RubyPtr c = (sqlite3RubyPtr)ctx;
13
+ sqlite3 * db = c->db;
14
+
15
+ if(db) sqlite3_close(db);
16
+ xfree(c);
17
+ }
18
+
19
+ static VALUE allocate(VALUE klass)
20
+ {
21
+ sqlite3RubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3Ruby));
22
+ return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
23
+ }
24
+
25
+ static char *
26
+ utf16_string_value_ptr(VALUE str)
27
+ {
28
+ StringValue(str);
29
+ rb_str_buf_cat(str, "\x00", 1L);
30
+ return RSTRING_PTR(str);
31
+ }
32
+
33
+ /* call-seq: SQLite3::Database.new(file, options = {})
34
+ *
35
+ * Create a new Database object that opens the given file. If utf16
36
+ * is +true+, the filename is interpreted as a UTF-16 encoded string.
37
+ *
38
+ * By default, the new database will return result rows as arrays
39
+ * (#results_as_hash) and has type translation disabled (#type_translation=).
40
+ */
41
+ static VALUE initialize(int argc, VALUE *argv, VALUE self)
42
+ {
43
+ sqlite3RubyPtr ctx;
44
+ VALUE file;
45
+ VALUE opts;
46
+ VALUE zvfs;
47
+ #ifdef HAVE_SQLITE3_OPEN_V2
48
+ int mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
49
+ #endif
50
+ int status;
51
+
52
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
53
+
54
+ rb_scan_args(argc, argv, "12", &file, &opts, &zvfs);
55
+ #if defined StringValueCStr
56
+ StringValuePtr(file);
57
+ rb_check_safe_obj(file);
58
+ #else
59
+ Check_SafeStr(file);
60
+ #endif
61
+ if(NIL_P(opts)) opts = rb_hash_new();
62
+ else Check_Type(opts, T_HASH);
63
+
64
+ #ifdef HAVE_RUBY_ENCODING_H
65
+ if(UTF16_LE_P(file) || UTF16_BE_P(file)) {
66
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
67
+ } else {
68
+ #endif
69
+
70
+ if(Qtrue == rb_hash_aref(opts, sym_utf16)) {
71
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
72
+ } else {
73
+
74
+ #ifdef HAVE_RUBY_ENCODING_H
75
+ if(!UTF8_P(file)) {
76
+ file = rb_str_export_to_enc(file, rb_utf8_encoding());
77
+ }
78
+ #endif
79
+
80
+ if (Qtrue == rb_hash_aref(opts, ID2SYM(rb_intern("readonly")))) {
81
+ #ifdef HAVE_SQLITE3_OPEN_V2
82
+ mode = SQLITE_OPEN_READONLY;
83
+ #else
84
+ rb_raise(rb_eNotImpError, "sqlite3-ruby was compiled against a version of sqlite that does not support readonly databases");
85
+ #endif
86
+ }
87
+ #ifdef HAVE_SQLITE3_OPEN_V2
88
+ status = sqlite3_open_v2(
89
+ StringValuePtr(file),
90
+ &ctx->db,
91
+ mode,
92
+ NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
93
+ );
94
+ #else
95
+ status = sqlite3_open(
96
+ StringValuePtr(file),
97
+ &ctx->db
98
+ );
99
+ #endif
100
+ }
101
+
102
+ #ifdef HAVE_RUBY_ENCODING_H
103
+ }
104
+ #endif
105
+
106
+ CHECK(ctx->db, status)
107
+
108
+ rb_iv_set(self, "@tracefunc", Qnil);
109
+ rb_iv_set(self, "@authorizer", Qnil);
110
+ rb_iv_set(self, "@encoding", Qnil);
111
+ rb_iv_set(self, "@busy_handler", Qnil);
112
+ rb_iv_set(self, "@collations", rb_hash_new());
113
+ rb_iv_set(self, "@functions", rb_hash_new());
114
+ rb_iv_set(self, "@results_as_hash", rb_hash_aref(opts, sym_results_as_hash));
115
+ rb_iv_set(self, "@type_translation", rb_hash_aref(opts, sym_type_translation));
116
+ #ifdef HAVE_SQLITE3_OPEN_V2
117
+ rb_iv_set(self, "@readonly", mode == SQLITE_OPEN_READONLY ? Qtrue : Qfalse);
118
+ #else
119
+ rb_iv_set(self, "@readonly", Qfalse);
120
+ #endif
121
+
122
+ if(rb_block_given_p()) {
123
+ rb_yield(self);
124
+ rb_funcall(self, rb_intern("close"), 0);
125
+ }
126
+
127
+ return self;
128
+ }
129
+
130
+ /* call-seq: db.close
131
+ *
132
+ * Closes this database.
133
+ */
134
+ static VALUE sqlite3_rb_close(VALUE self)
135
+ {
136
+ sqlite3RubyPtr ctx;
137
+ sqlite3 * db;
138
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
139
+
140
+ db = ctx->db;
141
+ CHECK(db, sqlite3_close(ctx->db));
142
+
143
+ ctx->db = NULL;
144
+
145
+ return self;
146
+ }
147
+
148
+ /* call-seq: db.closed?
149
+ *
150
+ * Returns +true+ if this database instance has been closed (see #close).
151
+ */
152
+ static VALUE closed_p(VALUE self)
153
+ {
154
+ sqlite3RubyPtr ctx;
155
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
156
+
157
+ if(!ctx->db) return Qtrue;
158
+
159
+ return Qfalse;
160
+ }
161
+
162
+ /* call-seq: total_changes
163
+ *
164
+ * Returns the total number of changes made to this database instance
165
+ * since it was opened.
166
+ */
167
+ static VALUE total_changes(VALUE self)
168
+ {
169
+ sqlite3RubyPtr ctx;
170
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
171
+ REQUIRE_OPEN_DB(ctx);
172
+
173
+ return INT2NUM((long)sqlite3_total_changes(ctx->db));
174
+ }
175
+
176
+ static void tracefunc(void * data, const char *sql)
177
+ {
178
+ VALUE self = (VALUE)data;
179
+ VALUE thing = rb_iv_get(self, "@tracefunc");
180
+ rb_funcall(thing, rb_intern("call"), 1, rb_str_new2(sql));
181
+ }
182
+
183
+ /* call-seq:
184
+ * trace { |sql| ... }
185
+ * trace(Class.new { def call sql; end }.new)
186
+ *
187
+ * Installs (or removes) a block that will be invoked for every SQL
188
+ * statement executed. The block receives one parameter: the SQL statement
189
+ * executed. If the block is +nil+, any existing tracer will be uninstalled.
190
+ */
191
+ static VALUE trace(int argc, VALUE *argv, VALUE self)
192
+ {
193
+ sqlite3RubyPtr ctx;
194
+ VALUE block;
195
+
196
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
197
+ REQUIRE_OPEN_DB(ctx);
198
+
199
+ rb_scan_args(argc, argv, "01", &block);
200
+
201
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
202
+
203
+ rb_iv_set(self, "@tracefunc", block);
204
+
205
+ sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);
206
+
207
+ return self;
208
+ }
209
+
210
+ static int rb_sqlite3_busy_handler(void * ctx, int count)
211
+ {
212
+ VALUE self = (VALUE)(ctx);
213
+ VALUE handle = rb_iv_get(self, "@busy_handler");
214
+ VALUE result = rb_funcall(handle, rb_intern("call"), 1, INT2NUM((long)count));
215
+
216
+ if(Qfalse == result) return 0;
217
+
218
+ return 1;
219
+ }
220
+
221
+ /* call-seq:
222
+ * busy_handler { |count| ... }
223
+ * busy_handler(Class.new { def call count; end }.new)
224
+ *
225
+ * Register a busy handler with this database instance. When a requested
226
+ * resource is busy, this handler will be invoked. If the handler returns
227
+ * +false+, the operation will be aborted; otherwise, the resource will
228
+ * be requested again.
229
+ *
230
+ * The handler will be invoked with the name of the resource that was
231
+ * busy, and the number of times it has been retried.
232
+ *
233
+ * See also the mutually exclusive #busy_timeout.
234
+ */
235
+ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
236
+ {
237
+ sqlite3RubyPtr ctx;
238
+ VALUE block;
239
+ int status;
240
+
241
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
242
+ REQUIRE_OPEN_DB(ctx);
243
+
244
+ rb_scan_args(argc, argv, "01", &block);
245
+
246
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
247
+
248
+ rb_iv_set(self, "@busy_handler", block);
249
+
250
+ status = sqlite3_busy_handler(
251
+ ctx->db, NIL_P(block) ? NULL : rb_sqlite3_busy_handler, (void *)self);
252
+
253
+ CHECK(ctx->db, status);
254
+
255
+ return self;
256
+ }
257
+
258
+ /* call-seq: last_insert_row_id
259
+ *
260
+ * Obtains the unique row ID of the last row to be inserted by this Database
261
+ * instance.
262
+ */
263
+ static VALUE last_insert_row_id(VALUE self)
264
+ {
265
+ sqlite3RubyPtr ctx;
266
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
267
+ REQUIRE_OPEN_DB(ctx);
268
+
269
+ return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
270
+ }
271
+
272
+ static VALUE sqlite3val2rb(sqlite3_value * val)
273
+ {
274
+ switch(sqlite3_value_type(val)) {
275
+ case SQLITE_INTEGER:
276
+ return LL2NUM(sqlite3_value_int64(val));
277
+ break;
278
+ case SQLITE_FLOAT:
279
+ return rb_float_new(sqlite3_value_double(val));
280
+ break;
281
+ case SQLITE_TEXT:
282
+ return rb_tainted_str_new2((const char *)sqlite3_value_text(val));
283
+ break;
284
+ case SQLITE_BLOB: {
285
+ /* Sqlite warns calling sqlite3_value_bytes may invalidate pointer from sqlite3_value_blob,
286
+ so we explicitly get the length before getting blob pointer.
287
+ Note that rb_str_new and rb_tainted_str_new apparently create string with ASCII-8BIT (BINARY) encoding,
288
+ which is what we want, as blobs are binary
289
+ */
290
+ int len = sqlite3_value_bytes(val);
291
+ return rb_tainted_str_new((const char *)sqlite3_value_blob(val), len);
292
+ break;
293
+ }
294
+ case SQLITE_NULL:
295
+ return Qnil;
296
+ break;
297
+ default:
298
+ rb_raise(rb_eRuntimeError, "bad type"); /* FIXME */
299
+ }
300
+ }
301
+
302
+ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
303
+ {
304
+ switch(TYPE(result)) {
305
+ case T_NIL:
306
+ sqlite3_result_null(ctx);
307
+ break;
308
+ case T_FIXNUM:
309
+ sqlite3_result_int64(ctx, (sqlite3_int64)FIX2LONG(result));
310
+ break;
311
+ case T_BIGNUM:
312
+ #if SIZEOF_LONG < 8
313
+ if (RBIGNUM_LEN(result) * SIZEOF_BDIGITS <= 8) {
314
+ sqlite3_result_int64(ctx, NUM2LL(result));
315
+ break;
316
+ }
317
+ #endif
318
+ case T_FLOAT:
319
+ sqlite3_result_double(ctx, NUM2DBL(result));
320
+ break;
321
+ case T_STRING:
322
+ sqlite3_result_text(
323
+ ctx,
324
+ (const char *)StringValuePtr(result),
325
+ (int)RSTRING_LEN(result),
326
+ SQLITE_TRANSIENT
327
+ );
328
+ break;
329
+ default:
330
+ rb_raise(rb_eRuntimeError, "can't return %s",
331
+ rb_class2name(CLASS_OF(result)));
332
+ }
333
+ }
334
+
335
+ static void rb_sqlite3_func(sqlite3_context * ctx, int argc, sqlite3_value **argv)
336
+ {
337
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
338
+ VALUE * params = NULL;
339
+ VALUE result;
340
+ int i;
341
+
342
+ if (argc > 0) {
343
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
344
+
345
+ for(i = 0; i < argc; i++) {
346
+ VALUE param = sqlite3val2rb(argv[i]);
347
+ RB_GC_GUARD(param);
348
+ params[i] = param;
349
+ }
350
+ }
351
+
352
+ result = rb_funcall2(callable, rb_intern("call"), argc, params);
353
+ xfree(params);
354
+
355
+ set_sqlite3_func_result(ctx, result);
356
+ }
357
+
358
+ #ifndef HAVE_RB_PROC_ARITY
359
+ int rb_proc_arity(VALUE self)
360
+ {
361
+ return (int)NUM2INT(rb_funcall(self, rb_intern("arity"), 0));
362
+ }
363
+ #endif
364
+
365
+ /* call-seq: define_function(name) { |args,...| }
366
+ *
367
+ * Define a function named +name+ with +args+. The arity of the block
368
+ * will be used as the arity for the function defined.
369
+ */
370
+ static VALUE define_function(VALUE self, VALUE name)
371
+ {
372
+ sqlite3RubyPtr ctx;
373
+ VALUE block;
374
+ int status;
375
+
376
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
377
+ REQUIRE_OPEN_DB(ctx);
378
+
379
+ block = rb_block_proc();
380
+
381
+ status = sqlite3_create_function(
382
+ ctx->db,
383
+ StringValuePtr(name),
384
+ rb_proc_arity(block),
385
+ SQLITE_UTF8,
386
+ (void *)block,
387
+ rb_sqlite3_func,
388
+ NULL,
389
+ NULL
390
+ );
391
+
392
+ CHECK(ctx->db, status);
393
+
394
+ rb_hash_aset(rb_iv_get(self, "@functions"), name, block);
395
+
396
+ return self;
397
+ }
398
+
399
+ static int sqlite3_obj_method_arity(VALUE obj, ID id)
400
+ {
401
+ VALUE method = rb_funcall(obj, rb_intern("method"), 1, ID2SYM(id));
402
+ VALUE arity = rb_funcall(method, rb_intern("arity"), 0);
403
+
404
+ return (int)NUM2INT(arity);
405
+ }
406
+
407
+ static void rb_sqlite3_step(sqlite3_context * ctx, int argc, sqlite3_value **argv)
408
+ {
409
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
410
+ VALUE * params = NULL;
411
+ int i;
412
+
413
+ if (argc > 0) {
414
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
415
+ for(i = 0; i < argc; i++) {
416
+ params[i] = sqlite3val2rb(argv[i]);
417
+ }
418
+ }
419
+ rb_funcall2(callable, rb_intern("step"), argc, params);
420
+ xfree(params);
421
+ }
422
+
423
+ static void rb_sqlite3_final(sqlite3_context * ctx)
424
+ {
425
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
426
+ VALUE result = rb_funcall(callable, rb_intern("finalize"), 0);
427
+ set_sqlite3_func_result(ctx, result);
428
+ }
429
+
430
+ /* call-seq: define_aggregator(name, aggregator)
431
+ *
432
+ * Define an aggregate function named +name+ using the object +aggregator+.
433
+ * +aggregator+ must respond to +step+ and +finalize+. +step+ will be called
434
+ * with row information and +finalize+ must return the return value for the
435
+ * aggregator function.
436
+ */
437
+ static VALUE define_aggregator(VALUE self, VALUE name, VALUE aggregator)
438
+ {
439
+ sqlite3RubyPtr ctx;
440
+ int arity, status;
441
+
442
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
443
+ REQUIRE_OPEN_DB(ctx);
444
+
445
+ arity = sqlite3_obj_method_arity(aggregator, rb_intern("step"));
446
+
447
+ status = sqlite3_create_function(
448
+ ctx->db,
449
+ StringValuePtr(name),
450
+ arity,
451
+ SQLITE_UTF8,
452
+ (void *)aggregator,
453
+ NULL,
454
+ rb_sqlite3_step,
455
+ rb_sqlite3_final
456
+ );
457
+
458
+ rb_iv_set(self, "@agregator", aggregator);
459
+
460
+ CHECK(ctx->db, status);
461
+
462
+ return self;
463
+ }
464
+
465
+ /* call-seq: interrupt
466
+ *
467
+ * Interrupts the currently executing operation, causing it to abort.
468
+ */
469
+ static VALUE interrupt(VALUE self)
470
+ {
471
+ sqlite3RubyPtr ctx;
472
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
473
+ REQUIRE_OPEN_DB(ctx);
474
+
475
+ sqlite3_interrupt(ctx->db);
476
+
477
+ return self;
478
+ }
479
+
480
+ /* call-seq: errmsg
481
+ *
482
+ * Return a string describing the last error to have occurred with this
483
+ * database.
484
+ */
485
+ static VALUE errmsg(VALUE self)
486
+ {
487
+ sqlite3RubyPtr ctx;
488
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
489
+ REQUIRE_OPEN_DB(ctx);
490
+
491
+ return rb_str_new2(sqlite3_errmsg(ctx->db));
492
+ }
493
+
494
+ /* call-seq: errcode
495
+ *
496
+ * Return an integer representing the last error to have occurred with this
497
+ * database.
498
+ */
499
+ static VALUE errcode_(VALUE self)
500
+ {
501
+ sqlite3RubyPtr ctx;
502
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
503
+ REQUIRE_OPEN_DB(ctx);
504
+
505
+ return INT2NUM((long)sqlite3_errcode(ctx->db));
506
+ }
507
+
508
+ /* call-seq: complete?(sql)
509
+ *
510
+ * Return +true+ if the string is a valid (ie, parsable) SQL statement, and
511
+ * +false+ otherwise.
512
+ */
513
+ static VALUE complete_p(VALUE UNUSED(self), VALUE sql)
514
+ {
515
+ if(sqlite3_complete(StringValuePtr(sql)))
516
+ return Qtrue;
517
+
518
+ return Qfalse;
519
+ }
520
+
521
+ /* call-seq: changes
522
+ *
523
+ * Returns the number of changes made to this database instance by the last
524
+ * operation performed. Note that a "delete from table" without a where
525
+ * clause will not affect this value.
526
+ */
527
+ static VALUE changes(VALUE self)
528
+ {
529
+ sqlite3RubyPtr ctx;
530
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
531
+ REQUIRE_OPEN_DB(ctx);
532
+
533
+ return INT2NUM(sqlite3_changes(ctx->db));
534
+ }
535
+
536
+ static int rb_sqlite3_auth(
537
+ void *ctx,
538
+ int _action,
539
+ const char * _a,
540
+ const char * _b,
541
+ const char * _c,
542
+ const char * _d)
543
+ {
544
+ VALUE self = (VALUE)ctx;
545
+ VALUE action = INT2NUM(_action);
546
+ VALUE a = _a ? rb_str_new2(_a) : Qnil;
547
+ VALUE b = _b ? rb_str_new2(_b) : Qnil;
548
+ VALUE c = _c ? rb_str_new2(_c) : Qnil;
549
+ VALUE d = _d ? rb_str_new2(_d) : Qnil;
550
+ VALUE callback = rb_iv_get(self, "@authorizer");
551
+ VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
552
+
553
+ if(T_FIXNUM == TYPE(result)) return (int)NUM2INT(result);
554
+ if(Qtrue == result) return SQLITE_OK;
555
+ if(Qfalse == result) return SQLITE_DENY;
556
+
557
+ return SQLITE_IGNORE;
558
+ }
559
+
560
+ /* call-seq: set_authorizer = auth
561
+ *
562
+ * Set the authorizer for this database. +auth+ must respond to +call+, and
563
+ * +call+ must take 5 arguments.
564
+ *
565
+ * Installs (or removes) a block that will be invoked for every access
566
+ * to the database. If the block returns 0 (or +true+), the statement
567
+ * is allowed to proceed. Returning 1 or false causes an authorization error to
568
+ * occur, and returning 2 or nil causes the access to be silently denied.
569
+ */
570
+ static VALUE set_authorizer(VALUE self, VALUE authorizer)
571
+ {
572
+ sqlite3RubyPtr ctx;
573
+ int status;
574
+
575
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
576
+ REQUIRE_OPEN_DB(ctx);
577
+
578
+ status = sqlite3_set_authorizer(
579
+ ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
580
+ );
581
+
582
+ CHECK(ctx->db, status);
583
+
584
+ rb_iv_set(self, "@authorizer", authorizer);
585
+
586
+ return self;
587
+ }
588
+
589
+ /* call-seq: db.busy_timeout = ms
590
+ *
591
+ * Indicates that if a request for a resource terminates because that
592
+ * resource is busy, SQLite should sleep and retry for up to the indicated
593
+ * number of milliseconds. By default, SQLite does not retry
594
+ * busy resources. To restore the default behavior, send 0 as the
595
+ * +ms+ parameter.
596
+ *
597
+ * See also the mutually exclusive #busy_handler.
598
+ */
599
+ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
600
+ {
601
+ sqlite3RubyPtr ctx;
602
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
603
+ REQUIRE_OPEN_DB(ctx);
604
+
605
+ CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));
606
+
607
+ return self;
608
+ }
609
+
610
+ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const void * b)
611
+ {
612
+ VALUE comparator;
613
+ VALUE a_str;
614
+ VALUE b_str;
615
+ VALUE comparison;
616
+ #ifdef HAVE_RUBY_ENCODING_H
617
+ rb_encoding * internal_encoding;
618
+
619
+ internal_encoding = rb_default_internal_encoding();
620
+ #endif
621
+
622
+ comparator = (VALUE)ctx;
623
+ a_str = rb_str_new((const char *)a, a_len);
624
+ b_str = rb_str_new((const char *)b, b_len);
625
+
626
+ #ifdef HAVE_RUBY_ENCODING_H
627
+ rb_enc_associate_index(a_str, rb_utf8_encindex());
628
+ rb_enc_associate_index(b_str, rb_utf8_encindex());
629
+
630
+ if(internal_encoding) {
631
+ a_str = rb_str_export_to_enc(a_str, internal_encoding);
632
+ b_str = rb_str_export_to_enc(b_str, internal_encoding);
633
+ }
634
+ #endif
635
+
636
+ comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
637
+
638
+ return NUM2INT(comparison);
639
+ }
640
+
641
+ /* call-seq: db.collation(name, comparator)
642
+ *
643
+ * Add a collation with name +name+, and a +comparator+ object. The
644
+ * +comparator+ object should implement a method called "compare" that takes
645
+ * two parameters and returns an integer less than, equal to, or greater than
646
+ * 0.
647
+ */
648
+ static VALUE collation(VALUE self, VALUE name, VALUE comparator)
649
+ {
650
+ sqlite3RubyPtr ctx;
651
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
652
+ REQUIRE_OPEN_DB(ctx);
653
+
654
+ CHECK(ctx->db, sqlite3_create_collation(
655
+ ctx->db,
656
+ StringValuePtr(name),
657
+ SQLITE_UTF8,
658
+ (void *)comparator,
659
+ NIL_P(comparator) ? NULL : rb_comparator_func));
660
+
661
+ /* Make sure our comparator doesn't get garbage collected. */
662
+ rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);
663
+
664
+ return self;
665
+ }
666
+
667
+ #ifdef HAVE_SQLITE3_LOAD_EXTENSION
668
+ /* call-seq: db.load_extension(file)
669
+ *
670
+ * Loads an SQLite extension library from the named file. Extension
671
+ * loading must be enabled using db.enable_load_extension(true) prior
672
+ * to calling this API.
673
+ */
674
+ static VALUE load_extension(VALUE self, VALUE file)
675
+ {
676
+ sqlite3RubyPtr ctx;
677
+ int status;
678
+ char *errMsg;
679
+ VALUE errexp;
680
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
681
+ REQUIRE_OPEN_DB(ctx);
682
+
683
+ status = sqlite3_load_extension(ctx->db, RSTRING_PTR(file), 0, &errMsg);
684
+ if (status != SQLITE_OK)
685
+ {
686
+ errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
687
+ sqlite3_free(errMsg);
688
+ rb_exc_raise(errexp);
689
+ }
690
+
691
+ return self;
692
+ }
693
+ #endif
694
+
695
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
696
+ /* call-seq: db.enable_load_extension(onoff)
697
+ *
698
+ * Enable or disable extension loading.
699
+ */
700
+ static VALUE enable_load_extension(VALUE self, VALUE onoff)
701
+ {
702
+ sqlite3RubyPtr ctx;
703
+ int onoffparam;
704
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
705
+ REQUIRE_OPEN_DB(ctx);
706
+
707
+ if (Qtrue == onoff) {
708
+ onoffparam = 1;
709
+ } else if (Qfalse == onoff) {
710
+ onoffparam = 0;
711
+ } else {
712
+ onoffparam = (int)NUM2INT(onoff);
713
+ }
714
+
715
+ CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, onoffparam));
716
+
717
+ return self;
718
+ }
719
+ #endif
720
+
721
+ #ifdef HAVE_RUBY_ENCODING_H
722
+ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
723
+ {
724
+ VALUE self = (VALUE)_self;
725
+
726
+ int index = rb_enc_find_index(data[0]);
727
+ rb_encoding * e = rb_enc_from_index(index);
728
+ rb_iv_set(self, "@encoding", rb_enc_from_encoding(e));
729
+
730
+ return 0;
731
+ }
732
+ #else
733
+ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
734
+ {
735
+ VALUE self = (VALUE)_self;
736
+
737
+ rb_iv_set(self, "@encoding", rb_str_new2(data[0]));
738
+
739
+ return 0;
740
+ }
741
+ #endif
742
+
743
+ /* call-seq: db.encoding
744
+ *
745
+ * Fetch the encoding set on this database
746
+ */
747
+ static VALUE db_encoding(VALUE self)
748
+ {
749
+ sqlite3RubyPtr ctx;
750
+ VALUE enc;
751
+
752
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
753
+ REQUIRE_OPEN_DB(ctx);
754
+
755
+ enc = rb_iv_get(self, "@encoding");
756
+
757
+ if(NIL_P(enc)) {
758
+ sqlite3_exec(ctx->db, "PRAGMA encoding", enc_cb, (void *)self, NULL);
759
+ }
760
+
761
+ return rb_iv_get(self, "@encoding");
762
+ }
763
+
764
+ /* call-seq: db.transaction_active?
765
+ *
766
+ * Returns +true+ if there is a transaction active, and +false+ otherwise.
767
+ *
768
+ */
769
+ static VALUE transaction_active_p(VALUE self)
770
+ {
771
+ sqlite3RubyPtr ctx;
772
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
773
+ REQUIRE_OPEN_DB(ctx);
774
+
775
+ return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
776
+ }
777
+
778
+ void init_sqlite3_database()
779
+ {
780
+ ID id_utf16, id_results_as_hash, id_type_translation;
781
+ #if 0
782
+ VALUE mSqlite3 = rb_define_module("SQLite3");
783
+ #endif
784
+ cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
785
+
786
+ rb_define_alloc_func(cSqlite3Database, allocate);
787
+ rb_define_method(cSqlite3Database, "initialize", initialize, -1);
788
+ rb_define_method(cSqlite3Database, "collation", collation, 2);
789
+ rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
790
+ rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
791
+ rb_define_method(cSqlite3Database, "total_changes", total_changes, 0);
792
+ rb_define_method(cSqlite3Database, "trace", trace, -1);
793
+ rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
794
+ rb_define_method(cSqlite3Database, "define_function", define_function, 1);
795
+ rb_define_method(cSqlite3Database, "define_aggregator", define_aggregator, 2);
796
+ rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
797
+ rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
798
+ rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
799
+ rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
800
+ rb_define_method(cSqlite3Database, "changes", changes, 0);
801
+ rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
802
+ rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
803
+ rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
804
+ rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
805
+
806
+ #ifdef HAVE_SQLITE3_LOAD_EXTENSION
807
+ rb_define_method(cSqlite3Database, "load_extension", load_extension, 1);
808
+ #endif
809
+
810
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
811
+ rb_define_method(cSqlite3Database, "enable_load_extension", enable_load_extension, 1);
812
+ #endif
813
+
814
+ rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
815
+
816
+ id_utf16 = rb_intern("utf16");
817
+ sym_utf16 = ID2SYM(id_utf16);
818
+ id_results_as_hash = rb_intern("results_as_hash");
819
+ sym_results_as_hash = ID2SYM(id_results_as_hash);
820
+ id_type_translation = rb_intern("type_translation");
821
+ sym_type_translation = ID2SYM(id_type_translation);
822
+ }