sqlite3-ruby 1.3.0.beta.2-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/API_CHANGES.rdoc +48 -0
  2. data/CHANGELOG.rdoc +108 -0
  3. data/ChangeLog.cvs +88 -0
  4. data/LICENSE +27 -0
  5. data/Manifest.txt +44 -0
  6. data/README.rdoc +54 -0
  7. data/Rakefile +10 -0
  8. data/ext/sqlite3/database.c +693 -0
  9. data/ext/sqlite3/database.h +15 -0
  10. data/ext/sqlite3/exception.c +94 -0
  11. data/ext/sqlite3/exception.h +8 -0
  12. data/ext/sqlite3/extconf.rb +39 -0
  13. data/ext/sqlite3/sqlite3.c +33 -0
  14. data/ext/sqlite3/sqlite3_ruby.h +43 -0
  15. data/ext/sqlite3/statement.c +419 -0
  16. data/ext/sqlite3/statement.h +16 -0
  17. data/faq/faq.rb +145 -0
  18. data/faq/faq.yml +426 -0
  19. data/lib/sqlite3.rb +10 -0
  20. data/lib/sqlite3/1.8/sqlite3_native.so +0 -0
  21. data/lib/sqlite3/1.9/sqlite3_native.so +0 -0
  22. data/lib/sqlite3/constants.rb +49 -0
  23. data/lib/sqlite3/database.rb +568 -0
  24. data/lib/sqlite3/errors.rb +44 -0
  25. data/lib/sqlite3/pragmas.rb +280 -0
  26. data/lib/sqlite3/resultset.rb +126 -0
  27. data/lib/sqlite3/statement.rb +146 -0
  28. data/lib/sqlite3/translator.rb +114 -0
  29. data/lib/sqlite3/value.rb +57 -0
  30. data/lib/sqlite3/version.rb +16 -0
  31. data/setup.rb +1333 -0
  32. data/tasks/faq.rake +9 -0
  33. data/tasks/gem.rake +31 -0
  34. data/tasks/native.rake +31 -0
  35. data/tasks/vendor_sqlite3.rake +107 -0
  36. data/test/helper.rb +3 -0
  37. data/test/test_database.rb +291 -0
  38. data/test/test_deprecated.rb +25 -0
  39. data/test/test_encoding.rb +115 -0
  40. data/test/test_integration.rb +545 -0
  41. data/test/test_integration_open_close.rb +30 -0
  42. data/test/test_integration_pending.rb +113 -0
  43. data/test/test_integration_resultset.rb +183 -0
  44. data/test/test_integration_statement.rb +194 -0
  45. data/test/test_sqlite3.rb +9 -0
  46. data/test/test_statement.rb +207 -0
  47. metadata +181 -0
data/API_CHANGES.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = API Changes
2
+
3
+ * SQLite3::ResultSet used to query the database for the first row, regardless
4
+ of whether the user asked for it or not. I have removed that so that rows
5
+ will not be returned until the user asks for them. This is a subtle but
6
+ sometimes important change in behavior.
7
+
8
+ 83882d2208ed189361617d5ab8532a325aaf729d
9
+
10
+ * SQLite3::Database#trace now takes either a block or an object that responds
11
+ to "call". The previous implementation passed around a VALUE that was cast
12
+ to a void *. This is dangerous because the value could get garbage collected
13
+ before the proc was called. If the user wants data passed around with the
14
+ block, they should use variables available to the closure or create an
15
+ object.
16
+
17
+ * SQLite3::Statement#step automatically converts to ruby types, where before
18
+ all values were automatically yielded as strings. This will only be a
19
+ problem for people who were accessing information about the database that
20
+ wasn't previously passed through the pure ruby conversion code.
21
+
22
+ * SQLite3::Database#errmsg no longer takes a parameter to return error
23
+ messages as UTF-16. Do people even use that? I opt for staying UTF-8 when
24
+ possible. See test_integration.rb test_errmsg_utf16
25
+
26
+ * SQLite3::Database#authorize same changes as trace
27
+
28
+ * test/test_tc_database.rb was removed because we no longer use the Driver
29
+ design pattern.
30
+
31
+ = Garbage Collection Strategy
32
+
33
+ All statements keep pointers back to their respective database connections.
34
+ The @connection instance variable on the Statement handle keeps the database
35
+ connection alive. Memory allocated for a statement handler will be freed in
36
+ two cases:
37
+
38
+ * close is called on the statement
39
+ * The SQLite3::Database object gets garbage collected
40
+
41
+ We can't free the memory for the statement in the garbage collection function
42
+ for the statement handler. The reason is because there exists a race
43
+ condition. We cannot guarantee the order in which objects will be garbage
44
+ collected. So, it is possible that a connection and a statement are up for
45
+ garbage collection. If the database connection were to be free'd before the
46
+ statement, then boom. Instead we'll be conservative and free unclosed
47
+ statements when the connection is terminated.
48
+
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,108 @@
1
+ === 1.3.0.beta.2 / 2010-05-15
2
+
3
+ * Enhancements
4
+ * Added support for type translations [tenderlove]
5
+
6
+ @db.translator.add_translator('sometime') do |type, thing|
7
+ 'output' # this will be returned as value for that column
8
+ end
9
+
10
+ * Bugfixes
11
+ * Allow extension compilation search for common lib paths [kashif]
12
+ (lookup /usr/local, /opt/local and /usr)
13
+ * Corrected extension compilation under MSVC [romuloceccon]
14
+ * Define load_extension functionality based on availability [tenderlove]
15
+ * Deprecation notices for Database#query. Fixes RF #28192
16
+
17
+ === 1.3.0.beta.1 / 2010-05-10
18
+
19
+ * Enhancements
20
+ * Complete rewrite of C-based adapter from SWIG to hand-crafted one [tenderlove]
21
+ See API_CHANGES document for details.
22
+ This closes: Bug #27300, Bug #27241, Patch #16020
23
+ * Improved UTF, Unicode, M17N, all that handling and proper BLOB handling [tenderlove, nurse]
24
+
25
+ * Experimental
26
+ * Added API to access and load extensions. [kashif]
27
+ These functions maps directly into SQLite3 own enable_load_extension()
28
+ and load_extension() C-API functions. See SQLite3::Database API documentation for details.
29
+ This closes: Patches #9178
30
+
31
+ * Bugfixes
32
+ * Corrected gem dependencies (runtime and development)
33
+ * Fixed threaded tests [Alexey Borzenkov]
34
+ * Removed GitHub gemspec
35
+ * Fixed "No definition for" warnings from RDoc
36
+ * Generate zip and tgz files for releases
37
+ * Added Luis Lavena as gem Author (maintainer)
38
+ * Prevent mkmf interfere with Mighty Snow Leopard
39
+
40
+ === 1.2.5 / 25 Jul 2009
41
+
42
+ * Check for illegal nil before executing SQL [Erik Veenstra]
43
+ * Switch to Hoe for gem task management and packaging.
44
+ * Advertise rake-compiler as development dependency.
45
+ * Build gem binaries for Windows.
46
+ * Improved Ruby 1.9 support compatibility.
47
+ * Taint returned values. Patch #20325.
48
+ * Database.open and Database.new now take an optional block [Gerrit Kaiser]
49
+
50
+
51
+ === 1.2.4.1 (internal) / 5 Jul 2009
52
+
53
+ * Check for illegal nil before executing SQL [Erik Veenstra]
54
+ * Switch to Hoe for gem task management and packaging.
55
+ * Advertise rake-compiler as development dependency.
56
+ * Build gem binaries for Windows.
57
+ * Improved Ruby 1.9 support compatibility.
58
+
59
+
60
+ === 1.2.4 / 27 Aug 2008
61
+
62
+ * Package the updated C file for source builds. [Jamis Buck]
63
+
64
+
65
+ === 1.2.3 / 26 Aug 2008
66
+
67
+ * Fix incorrect permissions on database.rb and translator.rb [Various]
68
+
69
+ * Avoid using Object#extend for greater speedups [Erik Veenstra]
70
+
71
+ * Ruby 1.9 compatibility tweaks for Array#zip [jimmy88@gmail.com]
72
+
73
+ * Fix linking against Ruby 1.8.5 [Rob Holland <rob@inversepath.com>]
74
+
75
+
76
+ === 1.2.2 / 31 May 2008
77
+
78
+ * Make the table_info method adjust the returned default value for the rows
79
+ so that the sqlite3 change in 3.3.8 and greater can be handled
80
+ transparently [Jamis Buck <jamis@37signals.com>]
81
+
82
+ * Ruby 1.9 compatibility tweaks [Roman Le Negrate <roman2k@free.fr>]
83
+
84
+ * Various performance enhancements [thanks Erik Veenstra]
85
+
86
+ * Correct busy_handler documentation [Rob Holland <rob@inversepath.com>]
87
+
88
+ * Use int_bind64 on Fixnum values larger than a 32bit C int can take. [Rob Holland <rob@inversepath.com>]
89
+
90
+ * Work around a quirk in SQLite's error reporting by calling sqlite3_reset
91
+ to produce a more informative error code upon a failure from
92
+ sqlite3_step. [Rob Holland <rob@inversepath.com>]
93
+
94
+ * Various documentation, test, and style tweaks [Rob Holland <rob@inversepath.com>]
95
+
96
+ * Be more granular with time/data translation [Rob Holland <rob@inversepath.com>]
97
+
98
+ * Use Date directly for parsing rather than going via Time [Rob Holland <rob@inversepath.com>]
99
+
100
+ * Check for the rt library and fdatasync so we link against that when
101
+ needed [Rob Holland <rob@inversepath.com>]
102
+
103
+ * Rename data structures to avoid collision on win32. based on patch
104
+ by: Luis Lavena [Rob Holland <rob@inversepath.com>]
105
+
106
+ * Add test for defaults [Daniel Rodríguez Troitiño]
107
+
108
+ * Correctly unquote double-quoted pragma defaults [Łukasz Dargiewicz <lukasz.dargiewicz@gmail.com>]
data/ChangeLog.cvs ADDED
@@ -0,0 +1,88 @@
1
+ 2005-01-05 09:40 minam
2
+
3
+ * Rakefile, sqlite3-ruby-win32.gemspec, sqlite3-ruby.gemspec: Added
4
+ win32 gem.
5
+
6
+ 2005-01-05 07:31 minam
7
+
8
+ * Rakefile, test/tc_integration.rb, test/tests.rb: Added
9
+ native-vs-dl benchmark to Rakefile. Added SQLITE3_DRIVERS
10
+ environment variable to integration test to specify which
11
+ driver(s) should be tested (defaults to "Native").
12
+
13
+ 2005-01-04 14:26 minam
14
+
15
+ * ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
16
+ lib/sqlite3/driver/native/driver.rb, test/tc_database.rb,
17
+ test/tc_integration.rb, test/tests.rb: Unit tests: done. Bugs:
18
+ fixed.
19
+
20
+ 2005-01-03 23:13 minam
21
+
22
+ * ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
23
+ lib/sqlite3/driver/dl/driver.rb,
24
+ lib/sqlite3/driver/native/driver.rb, test/tc_integration.rb:
25
+ Custom functions (aggregate and otherwise) are supported by the
26
+ native driver now. Test cases for the same.
27
+
28
+ 2005-01-03 13:51 minam
29
+
30
+ * ext/sqlite3_api/MANIFEST, ext/sqlite3_api/extconf.rb,
31
+ ext/sqlite3_api/post-clean.rb, ext/sqlite3_api/post-distclean.rb,
32
+ ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
33
+ lib/sqlite3/resultset.rb, lib/sqlite3/version.rb,
34
+ lib/sqlite3/driver/dl/driver.rb,
35
+ lib/sqlite3/driver/native/driver.rb, test/native-vs-dl.rb,
36
+ test/tc_integration.rb: Added preliminary implementation of
37
+ native driver (swig-based), and integration tests.
38
+
39
+ 2004-12-29 19:37 minam
40
+
41
+ * lib/sqlite3/driver/dl/driver.rb: Some fixes to allow the DL
42
+ driver to work with Ruby 1.8.1.
43
+
44
+ 2004-12-29 14:52 minam
45
+
46
+ * lib/sqlite3/: database.rb, version.rb: Made #quote a class method
47
+ (again). Bumped version to 0.6.
48
+
49
+ 2004-12-25 22:59 minam
50
+
51
+ * lib/sqlite3/driver/dl/api.rb: Added check for darwin in supported
52
+ platforms (thanks to bitsweat).
53
+
54
+ 2004-12-22 12:38 minam
55
+
56
+ * Rakefile: Rakefile wasn't packaging the README file.
57
+
58
+ 2004-12-21 22:28 minam
59
+
60
+ * Rakefile, sqlite3-ruby.gemspec, test/bm.rb: Packaging now works.
61
+ Added benchmarks.
62
+
63
+ 2004-12-21 21:45 minam
64
+
65
+ * LICENSE, README, Rakefile, setup.rb, sqlite3-ruby.gemspec,
66
+ doc/faq/faq.rb, doc/faq/faq.yml, lib/sqlite3.rb,
67
+ lib/sqlite3/statement.rb, lib/sqlite3/constants.rb,
68
+ lib/sqlite3/database.rb, lib/sqlite3/resultset.rb,
69
+ lib/sqlite3/translator.rb, lib/sqlite3/value.rb,
70
+ lib/sqlite3/version.rb, lib/sqlite3/errors.rb,
71
+ lib/sqlite3/pragmas.rb, lib/sqlite3/driver/dl/api.rb,
72
+ lib/sqlite3/driver/dl/driver.rb, test/mocks.rb,
73
+ test/tc_database.rb, test/tests.rb, test/driver/dl/tc_driver.rb:
74
+ Initial import
75
+
76
+ 2004-12-21 21:45 minam
77
+
78
+ * LICENSE, README, Rakefile, setup.rb, sqlite3-ruby.gemspec,
79
+ doc/faq/faq.rb, doc/faq/faq.yml, lib/sqlite3.rb,
80
+ lib/sqlite3/statement.rb, lib/sqlite3/constants.rb,
81
+ lib/sqlite3/database.rb, lib/sqlite3/resultset.rb,
82
+ lib/sqlite3/translator.rb, lib/sqlite3/value.rb,
83
+ lib/sqlite3/version.rb, lib/sqlite3/errors.rb,
84
+ lib/sqlite3/pragmas.rb, lib/sqlite3/driver/dl/api.rb,
85
+ lib/sqlite3/driver/dl/driver.rb, test/mocks.rb,
86
+ test/tc_database.rb, test/tests.rb, test/driver/dl/tc_driver.rb:
87
+ Initial revision
88
+
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2004, Jamis Buck (jamis@jamisbuck.org)
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ * The names of its contributors may not be used to endorse or promote
15
+ products derived from this software without specific prior written
16
+ permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Manifest.txt ADDED
@@ -0,0 +1,44 @@
1
+ API_CHANGES.rdoc
2
+ CHANGELOG.rdoc
3
+ ChangeLog.cvs
4
+ LICENSE
5
+ Manifest.txt
6
+ README.rdoc
7
+ Rakefile
8
+ ext/sqlite3/database.c
9
+ ext/sqlite3/database.h
10
+ ext/sqlite3/exception.c
11
+ ext/sqlite3/exception.h
12
+ ext/sqlite3/extconf.rb
13
+ ext/sqlite3/sqlite3.c
14
+ ext/sqlite3/sqlite3_ruby.h
15
+ ext/sqlite3/statement.c
16
+ ext/sqlite3/statement.h
17
+ faq/faq.rb
18
+ faq/faq.yml
19
+ lib/sqlite3.rb
20
+ lib/sqlite3/constants.rb
21
+ lib/sqlite3/database.rb
22
+ lib/sqlite3/errors.rb
23
+ lib/sqlite3/pragmas.rb
24
+ lib/sqlite3/resultset.rb
25
+ lib/sqlite3/statement.rb
26
+ lib/sqlite3/translator.rb
27
+ lib/sqlite3/value.rb
28
+ lib/sqlite3/version.rb
29
+ setup.rb
30
+ tasks/faq.rake
31
+ tasks/gem.rake
32
+ tasks/native.rake
33
+ tasks/vendor_sqlite3.rake
34
+ test/helper.rb
35
+ test/test_database.rb
36
+ test/test_deprecated.rb
37
+ test/test_encoding.rb
38
+ test/test_integration.rb
39
+ test/test_integration_open_close.rb
40
+ test/test_integration_pending.rb
41
+ test/test_integration_resultset.rb
42
+ test/test_integration_statement.rb
43
+ test/test_sqlite3.rb
44
+ test/test_statement.rb
data/README.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ = SQLite3/Ruby Interface
2
+
3
+ * http://github.com/luislavena/sqlite3-ruby
4
+ * http://rubyforge.org/projects/sqlite-ruby
5
+ * http://sqlite-ruby.rubyforge.org
6
+
7
+ == DESCRIPTION
8
+
9
+ This module allows Ruby programs to interface with the SQLite3
10
+ database engine (http://www.sqlite.org). You must have the
11
+ SQLite engine installed in order to build this module.
12
+
13
+ Note that this module is NOT compatible with SQLite 2.x.
14
+
15
+ == Compilation and Installation
16
+
17
+ Install SQLite3, enabling option SQLITE_ENABLE_COLUMN_METADATA (see
18
+ www.sqlite.org/compile.html for details).
19
+
20
+ Then do the following:
21
+
22
+ ruby setup.rb config
23
+ ruby setup.rb setup
24
+ ruby setup.rb install
25
+
26
+ Alternatively, you can download and install the RubyGem package for
27
+ SQLite3/Ruby (you must have RubyGems and SQLite3 installed, first):
28
+
29
+ gem install sqlite3-ruby
30
+
31
+ If you have sqlite3 installed in a non-standard location, you can specify the location of the include and lib files by doing:
32
+
33
+ gem install sqlite3-ruby -- --with-sqlite3-include=/opt/local/include \
34
+ --with-sqlite3-lib=/opt/local/lib
35
+
36
+ == Usage
37
+
38
+ For help figuring out the SQLite3/Ruby interface, check out the
39
+ FAQ[http://sqlite-ruby.rubyforge.org/sqlite3/faq.html]. It includes examples of
40
+ usage. If you have any questions that you feel should be address in the
41
+ FAQ, please send them to jamis@37signals.com
42
+
43
+ == Source Code
44
+
45
+ The source repository is accessible via git:
46
+
47
+ git clone git://github.com/luislavena/sqlite3-ruby.git
48
+
49
+ == Contact Information
50
+
51
+ The project page is http://rubyforge.org/projects/sqlite-ruby. There, you can
52
+ find links to mailing lists and forums that you can use to discuss this
53
+ library. Additionally, there are trackers for submitting bugs and feature
54
+ requests. Feel free to use them!
data/Rakefile ADDED
@@ -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,693 @@
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
+ sqlite3_stmt * stmt;
15
+
16
+ if(db) {
17
+ while((stmt = sqlite3_next_stmt(db, NULL)) != NULL) {
18
+ sqlite3_finalize(stmt);
19
+ }
20
+ sqlite3_close(db);
21
+ }
22
+ xfree(c);
23
+ }
24
+
25
+ static VALUE allocate(VALUE klass)
26
+ {
27
+ sqlite3RubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3Ruby));
28
+ return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
29
+ }
30
+
31
+ static char *
32
+ utf16_string_value_ptr(VALUE str)
33
+ {
34
+ StringValue(str);
35
+ rb_str_buf_cat(str, "\x00", 1L);
36
+ return RSTRING_PTR(str);
37
+ }
38
+
39
+ /* call-seq: SQLite3::Database.new(file, options = {})
40
+ *
41
+ * Create a new Database object that opens the given file. If utf16
42
+ * is +true+, the filename is interpreted as a UTF-16 encoded string.
43
+ *
44
+ * By default, the new database will return result rows as arrays
45
+ * (#results_as_hash) and has type translation disabled (#type_translation=).
46
+ */
47
+ static VALUE initialize(int argc, VALUE *argv, VALUE self)
48
+ {
49
+ sqlite3RubyPtr ctx;
50
+ VALUE file;
51
+ VALUE opts;
52
+ VALUE zvfs;
53
+ int status;
54
+
55
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
56
+
57
+ rb_scan_args(argc, argv, "12", &file, &opts, &zvfs);
58
+ if(NIL_P(opts)) opts = rb_hash_new();
59
+
60
+ #ifdef HAVE_RUBY_ENCODING_H
61
+ if(UTF16_LE_P(file)) {
62
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
63
+ } else {
64
+ #endif
65
+
66
+ if(Qtrue == rb_hash_aref(opts, sym_utf16)) {
67
+ status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
68
+ } else {
69
+
70
+ #ifdef HAVE_RUBY_ENCODING_H
71
+ if(!UTF8_P(file)) {
72
+ file = rb_str_export_to_enc(file, rb_utf8_encoding());
73
+ }
74
+ #endif
75
+
76
+ status = sqlite3_open_v2(
77
+ StringValuePtr(file),
78
+ &ctx->db,
79
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
80
+ NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
81
+ );
82
+ }
83
+
84
+ #ifdef HAVE_RUBY_ENCODING_H
85
+ }
86
+ #endif
87
+
88
+ CHECK(ctx->db, status)
89
+
90
+ rb_iv_set(self, "@tracefunc", Qnil);
91
+ rb_iv_set(self, "@authorizer", Qnil);
92
+ rb_iv_set(self, "@encoding", Qnil);
93
+ rb_iv_set(self, "@busy_handler", Qnil);
94
+ rb_iv_set(self, "@results_as_hash", rb_hash_aref(opts, sym_results_as_hash));
95
+ rb_iv_set(self, "@type_translation", rb_hash_aref(opts, sym_type_translation));
96
+
97
+ if(rb_block_given_p()) {
98
+ rb_yield(self);
99
+ rb_funcall(self, rb_intern("close"), 0);
100
+ }
101
+
102
+ return self;
103
+ }
104
+
105
+ /* call-seq: db.close
106
+ *
107
+ * Closes this database.
108
+ */
109
+ static VALUE sqlite3_rb_close(VALUE self)
110
+ {
111
+ sqlite3RubyPtr ctx;
112
+ sqlite3 * db;
113
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
114
+
115
+ db = ctx->db;
116
+ CHECK(db, sqlite3_close(ctx->db));
117
+
118
+ ctx->db = NULL;
119
+
120
+ return self;
121
+ }
122
+
123
+ /* call-seq: db.closed?
124
+ *
125
+ * Returns +true+ if this database instance has been closed (see #close).
126
+ */
127
+ static VALUE closed_p(VALUE self)
128
+ {
129
+ sqlite3RubyPtr ctx;
130
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
131
+
132
+ if(!ctx->db) return Qtrue;
133
+
134
+ return Qfalse;
135
+ }
136
+
137
+ /* call-seq: total_changes
138
+ *
139
+ * Returns the total number of changes made to this database instance
140
+ * since it was opened.
141
+ */
142
+ static VALUE total_changes(VALUE self)
143
+ {
144
+ sqlite3RubyPtr ctx;
145
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
146
+ REQUIRE_OPEN_DB(ctx);
147
+
148
+ return INT2NUM((long)sqlite3_total_changes(ctx->db));
149
+ }
150
+
151
+ static void tracefunc(void * data, const char *sql)
152
+ {
153
+ VALUE self = (VALUE)data;
154
+ VALUE thing = rb_iv_get(self, "@tracefunc");
155
+ rb_funcall(thing, rb_intern("call"), 1, rb_str_new2(sql));
156
+ }
157
+
158
+ /* call-seq:
159
+ * trace { |sql| ... }
160
+ * trace(Class.new { def call sql; end }.new)
161
+ *
162
+ * Installs (or removes) a block that will be invoked for every SQL
163
+ * statement executed. The block receives one parameter: the SQL statement
164
+ * executed. If the block is +nil+, any existing tracer will be uninstalled.
165
+ */
166
+ static VALUE trace(int argc, VALUE *argv, VALUE self)
167
+ {
168
+ sqlite3RubyPtr ctx;
169
+ VALUE block;
170
+
171
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
172
+ REQUIRE_OPEN_DB(ctx);
173
+
174
+ rb_scan_args(argc, argv, "01", &block);
175
+
176
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
177
+
178
+ rb_iv_set(self, "@tracefunc", block);
179
+
180
+ sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);
181
+
182
+ return self;
183
+ }
184
+
185
+ static int rb_sqlite3_busy_handler(void * ctx, int count)
186
+ {
187
+ VALUE self = (VALUE)(ctx);
188
+ VALUE handle = rb_iv_get(self, "@busy_handler");
189
+ VALUE result = rb_funcall(handle, rb_intern("call"), 1, INT2NUM((long)count));
190
+
191
+ if(Qfalse == result) return 0;
192
+
193
+ return 1;
194
+ }
195
+
196
+ /* call-seq:
197
+ * busy_handler { |count| ... }
198
+ * busy_handler(Class.new { def call count; end }.new)
199
+ *
200
+ * Register a busy handler with this database instance. When a requested
201
+ * resource is busy, this handler will be invoked. If the handler returns
202
+ * +false+, the operation will be aborted; otherwise, the resource will
203
+ * be requested again.
204
+ *
205
+ * The handler will be invoked with the name of the resource that was
206
+ * busy, and the number of times it has been retried.
207
+ *
208
+ * See also the mutually exclusive #busy_timeout.
209
+ */
210
+ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
211
+ {
212
+ sqlite3RubyPtr ctx;
213
+ VALUE block;
214
+ int status;
215
+
216
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
217
+ REQUIRE_OPEN_DB(ctx);
218
+
219
+ rb_scan_args(argc, argv, "01", &block);
220
+
221
+ if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();
222
+
223
+ rb_iv_set(self, "@busy_handler", block);
224
+
225
+ status = sqlite3_busy_handler(
226
+ ctx->db, NIL_P(block) ? NULL : rb_sqlite3_busy_handler, (void *)self);
227
+
228
+ CHECK(ctx->db, status);
229
+
230
+ return self;
231
+ }
232
+
233
+ /* call-seq: last_insert_row_id
234
+ *
235
+ * Obtains the unique row ID of the last row to be inserted by this Database
236
+ * instance.
237
+ */
238
+ static VALUE last_insert_row_id(VALUE self)
239
+ {
240
+ sqlite3RubyPtr ctx;
241
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
242
+ REQUIRE_OPEN_DB(ctx);
243
+
244
+ return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
245
+ }
246
+
247
+ static VALUE sqlite3val2rb(sqlite3_value * val)
248
+ {
249
+ switch(sqlite3_value_type(val)) {
250
+ case SQLITE_INTEGER:
251
+ return LL2NUM(sqlite3_value_int64(val));
252
+ break;
253
+ case SQLITE_FLOAT:
254
+ return rb_float_new(sqlite3_value_double(val));
255
+ break;
256
+ case SQLITE_TEXT:
257
+ return rb_tainted_str_new2((const char *)sqlite3_value_text(val));
258
+ break;
259
+ case SQLITE_BLOB:
260
+ return rb_tainted_str_new2((const char *)sqlite3_value_blob(val));
261
+ break;
262
+ case SQLITE_NULL:
263
+ return Qnil;
264
+ break;
265
+ default:
266
+ rb_raise(rb_eRuntimeError, "bad type"); /* FIXME */
267
+ }
268
+ }
269
+
270
+ static void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result)
271
+ {
272
+ switch(TYPE(result)) {
273
+ case T_NIL:
274
+ sqlite3_result_null(ctx);
275
+ break;
276
+ case T_FIXNUM:
277
+ sqlite3_result_int64(ctx, (sqlite3_int64)FIX2LONG(result));
278
+ break;
279
+ case T_BIGNUM:
280
+ #if SIZEOF_LONG < 8
281
+ if (RBIGNUM_LEN(result) * SIZEOF_BDIGITS <= 8) {
282
+ sqlite3_result_int64(ctx, NUM2LL(result));
283
+ break;
284
+ }
285
+ #endif
286
+ case T_FLOAT:
287
+ sqlite3_result_double(ctx, NUM2DBL(result));
288
+ break;
289
+ case T_STRING:
290
+ sqlite3_result_text(
291
+ ctx,
292
+ (const char *)StringValuePtr(result),
293
+ (int)RSTRING_LEN(result),
294
+ SQLITE_TRANSIENT
295
+ );
296
+ break;
297
+ default:
298
+ rb_raise(rb_eRuntimeError, "can't return %s",
299
+ rb_class2name(CLASS_OF(result)));
300
+ }
301
+ }
302
+
303
+ static void rb_sqlite3_func(sqlite3_context * ctx, int argc, sqlite3_value **argv)
304
+ {
305
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
306
+ VALUE * params = NULL;
307
+ VALUE result;
308
+ int i;
309
+
310
+ if (argc > 0) {
311
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
312
+
313
+ for(i = 0; i < argc; i++) {
314
+ params[i] = sqlite3val2rb(argv[i]);
315
+ }
316
+ }
317
+
318
+ result = rb_funcall2(callable, rb_intern("call"), argc, params);
319
+ xfree(params);
320
+
321
+ set_sqlite3_func_result(ctx, result);
322
+ }
323
+
324
+ #ifndef HAVE_RB_PROC_ARITY
325
+ int rb_proc_arity(VALUE self)
326
+ {
327
+ return (int)NUM2INT(rb_funcall(self, rb_intern("arity"), 0));
328
+ }
329
+ #endif
330
+
331
+ /* call-seq: define_function(name) { |args,...| }
332
+ *
333
+ * Define a function named +name+ with +args+. The arity of the block
334
+ * will be used as the arity for the function defined.
335
+ */
336
+ static VALUE define_function(VALUE self, VALUE name)
337
+ {
338
+ sqlite3RubyPtr ctx;
339
+ VALUE block;
340
+ int status;
341
+
342
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
343
+ REQUIRE_OPEN_DB(ctx);
344
+
345
+ block = rb_block_proc();
346
+
347
+ status = sqlite3_create_function(
348
+ ctx->db,
349
+ StringValuePtr(name),
350
+ rb_proc_arity(block),
351
+ SQLITE_UTF8,
352
+ (void *)block,
353
+ rb_sqlite3_func,
354
+ NULL,
355
+ NULL
356
+ );
357
+
358
+ CHECK(ctx->db, status);
359
+
360
+ return self;
361
+ }
362
+
363
+ static int sqlite3_obj_method_arity(VALUE obj, ID id)
364
+ {
365
+ VALUE method = rb_funcall(obj, rb_intern("method"), 1, ID2SYM(id));
366
+ VALUE arity = rb_funcall(method, rb_intern("arity"), 0);
367
+
368
+ return (int)NUM2INT(arity);
369
+ }
370
+
371
+ static void rb_sqlite3_step(sqlite3_context * ctx, int argc, sqlite3_value **argv)
372
+ {
373
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
374
+ VALUE * params = NULL;
375
+ int i;
376
+
377
+ if (argc > 0) {
378
+ params = xcalloc((size_t)argc, sizeof(VALUE *));
379
+ for(i = 0; i < argc; i++) {
380
+ params[i] = sqlite3val2rb(argv[i]);
381
+ }
382
+ }
383
+ rb_funcall2(callable, rb_intern("step"), argc, params);
384
+ xfree(params);
385
+ }
386
+
387
+ static void rb_sqlite3_final(sqlite3_context * ctx)
388
+ {
389
+ VALUE callable = (VALUE)sqlite3_user_data(ctx);
390
+ VALUE result = rb_funcall(callable, rb_intern("finalize"), 0);
391
+ set_sqlite3_func_result(ctx, result);
392
+ }
393
+
394
+ /* call-seq: define_aggregator(name, aggregator)
395
+ *
396
+ * Define an aggregate function named +name+ using the object +aggregator+.
397
+ * +aggregator+ must respond to +step+ and +finalize+. +step+ will be called
398
+ * with row information and +finalize+ must return the return value for the
399
+ * aggregator function.
400
+ */
401
+ static VALUE define_aggregator(VALUE self, VALUE name, VALUE aggregator)
402
+ {
403
+ sqlite3RubyPtr ctx;
404
+ int arity, status;
405
+
406
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
407
+ REQUIRE_OPEN_DB(ctx);
408
+
409
+ arity = sqlite3_obj_method_arity(aggregator, rb_intern("step"));
410
+
411
+ status = sqlite3_create_function(
412
+ ctx->db,
413
+ StringValuePtr(name),
414
+ arity,
415
+ SQLITE_UTF8,
416
+ (void *)aggregator,
417
+ NULL,
418
+ rb_sqlite3_step,
419
+ rb_sqlite3_final
420
+ );
421
+
422
+ rb_iv_set(self, "@agregator", aggregator);
423
+
424
+ CHECK(ctx->db, status);
425
+
426
+ return self;
427
+ }
428
+
429
+ /* call-seq: interrupt
430
+ *
431
+ * Interrupts the currently executing operation, causing it to abort.
432
+ */
433
+ static VALUE interrupt(VALUE self)
434
+ {
435
+ sqlite3RubyPtr ctx;
436
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
437
+ REQUIRE_OPEN_DB(ctx);
438
+
439
+ sqlite3_interrupt(ctx->db);
440
+
441
+ return self;
442
+ }
443
+
444
+ /* call-seq: errmsg
445
+ *
446
+ * Return a string describing the last error to have occurred with this
447
+ * database.
448
+ */
449
+ static VALUE errmsg(VALUE self)
450
+ {
451
+ sqlite3RubyPtr ctx;
452
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
453
+ REQUIRE_OPEN_DB(ctx);
454
+
455
+ return rb_str_new2(sqlite3_errmsg(ctx->db));
456
+ }
457
+
458
+ /* call-seq: errcode
459
+ *
460
+ * Return an integer representing the last error to have occurred with this
461
+ * database.
462
+ */
463
+ static VALUE errcode_(VALUE self)
464
+ {
465
+ sqlite3RubyPtr ctx;
466
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
467
+ REQUIRE_OPEN_DB(ctx);
468
+
469
+ return INT2NUM((long)sqlite3_errcode(ctx->db));
470
+ }
471
+
472
+ /* call-seq: complete?(sql)
473
+ *
474
+ * Return +true+ if the string is a valid (ie, parsable) SQL statement, and
475
+ * +false+ otherwise.
476
+ */
477
+ static VALUE complete_p(VALUE UNUSED(self), VALUE sql)
478
+ {
479
+ if(sqlite3_complete(StringValuePtr(sql)))
480
+ return Qtrue;
481
+
482
+ return Qfalse;
483
+ }
484
+
485
+ /* call-seq: changes
486
+ *
487
+ * Returns the number of changes made to this database instance by the last
488
+ * operation performed. Note that a "delete from table" without a where
489
+ * clause will not affect this value.
490
+ */
491
+ static VALUE changes(VALUE self)
492
+ {
493
+ sqlite3RubyPtr ctx;
494
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
495
+ REQUIRE_OPEN_DB(ctx);
496
+
497
+ return INT2NUM(sqlite3_changes(ctx->db));
498
+ }
499
+
500
+ static int rb_sqlite3_auth(
501
+ void *ctx,
502
+ int _action,
503
+ const char * _a,
504
+ const char * _b,
505
+ const char * _c,
506
+ const char * _d)
507
+ {
508
+ VALUE self = (VALUE)ctx;
509
+ VALUE action = INT2NUM(_action);
510
+ VALUE a = _a ? rb_str_new2(_a) : Qnil;
511
+ VALUE b = _b ? rb_str_new2(_b) : Qnil;
512
+ VALUE c = _c ? rb_str_new2(_c) : Qnil;
513
+ VALUE d = _d ? rb_str_new2(_d) : Qnil;
514
+ VALUE callback = rb_iv_get(self, "@authorizer");
515
+ VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
516
+
517
+ if(T_FIXNUM == TYPE(result)) return (int)NUM2INT(result);
518
+ if(Qtrue == result) return SQLITE_OK;
519
+ if(Qfalse == result) return SQLITE_DENY;
520
+
521
+ return SQLITE_IGNORE;
522
+ }
523
+
524
+ /* call-seq: set_authorizer = auth
525
+ *
526
+ * Set the authorizer for this database. +auth+ must respond to +call+, and
527
+ * +call+ must take 5 arguments.
528
+ *
529
+ * Installs (or removes) a block that will be invoked for every access
530
+ * to the database. If the block returns 0 (or +true+), the statement
531
+ * is allowed to proceed. Returning 1 or false causes an authorization error to
532
+ * occur, and returning 2 or nil causes the access to be silently denied.
533
+ */
534
+ static VALUE set_authorizer(VALUE self, VALUE authorizer)
535
+ {
536
+ sqlite3RubyPtr ctx;
537
+ int status;
538
+
539
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
540
+ REQUIRE_OPEN_DB(ctx);
541
+
542
+ status = sqlite3_set_authorizer(
543
+ ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
544
+ );
545
+
546
+ CHECK(ctx->db, status);
547
+
548
+ rb_iv_set(self, "@authorizer", authorizer);
549
+
550
+ return self;
551
+ }
552
+
553
+ /* call-seq: db.busy_timeout = ms
554
+ *
555
+ * Indicates that if a request for a resource terminates because that
556
+ * resource is busy, SQLite should sleep and retry for up to the indicated
557
+ * number of milliseconds. By default, SQLite does not retry
558
+ * busy resources. To restore the default behavior, send 0 as the
559
+ * +ms+ parameter.
560
+ *
561
+ * See also the mutually exclusive #busy_handler.
562
+ */
563
+ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
564
+ {
565
+ sqlite3RubyPtr ctx;
566
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
567
+ REQUIRE_OPEN_DB(ctx);
568
+
569
+ CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));
570
+
571
+ return self;
572
+ }
573
+
574
+ /* call-seq: db.load_extension(file)
575
+ *
576
+ * Loads an SQLite extension library from the named file. Extension
577
+ * loading must be enabled using db.enable_load_extension(1) prior
578
+ * to calling this API.
579
+ */
580
+ static VALUE load_extension(VALUE self, VALUE file)
581
+ {
582
+ sqlite3RubyPtr ctx;
583
+ int status;
584
+ char *errMsg;
585
+ VALUE errexp;
586
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
587
+ REQUIRE_OPEN_DB(ctx);
588
+
589
+ status = sqlite3_load_extension(ctx->db, RSTRING_PTR(file), 0, &errMsg);
590
+ if (status != SQLITE_OK)
591
+ {
592
+ errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
593
+ sqlite3_free(errMsg);
594
+ rb_exc_raise(errexp);
595
+ }
596
+
597
+ return self;
598
+ }
599
+
600
+ /* call-seq: db.enable_load_extension(onoff)
601
+ *
602
+ * Enable or disable extension loading.
603
+ */
604
+ static VALUE enable_load_extension(VALUE self, VALUE onoff)
605
+ {
606
+ sqlite3RubyPtr ctx;
607
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
608
+ REQUIRE_OPEN_DB(ctx);
609
+
610
+ CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, (int)NUM2INT(onoff)));
611
+
612
+ return self;
613
+ }
614
+
615
+ #ifdef HAVE_RUBY_ENCODING_H
616
+ static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
617
+ {
618
+ VALUE self = (VALUE)_self;
619
+
620
+ int index = rb_enc_find_index(data[0]);
621
+ rb_encoding * e = rb_enc_from_index(index);
622
+ rb_iv_set(self, "@encoding", rb_enc_from_encoding(e));
623
+
624
+ return 0;
625
+ }
626
+
627
+ /* call-seq: db.encoding
628
+ *
629
+ * Fetch the encoding set on this database
630
+ */
631
+ static VALUE db_encoding(VALUE self)
632
+ {
633
+ sqlite3RubyPtr ctx;
634
+ VALUE enc;
635
+
636
+ Data_Get_Struct(self, sqlite3Ruby, ctx);
637
+ REQUIRE_OPEN_DB(ctx);
638
+
639
+ enc = rb_iv_get(self, "@encoding");
640
+
641
+ if(NIL_P(enc)) {
642
+ sqlite3_exec(ctx->db, "PRAGMA encoding", enc_cb, (void *)self, NULL);
643
+ }
644
+
645
+ return rb_iv_get(self, "@encoding");
646
+ }
647
+ #endif
648
+
649
+ void init_sqlite3_database()
650
+ {
651
+ ID id_utf16, id_results_as_hash, id_type_translation;
652
+ #if 0
653
+ VALUE mSqlite3 = rb_define_module("SQLite3");
654
+ #endif
655
+ cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
656
+
657
+ rb_define_alloc_func(cSqlite3Database, allocate);
658
+ rb_define_method(cSqlite3Database, "initialize", initialize, -1);
659
+ rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
660
+ rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
661
+ rb_define_method(cSqlite3Database, "total_changes", total_changes, 0);
662
+ rb_define_method(cSqlite3Database, "trace", trace, -1);
663
+ rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
664
+ rb_define_method(cSqlite3Database, "define_function", define_function, 1);
665
+ rb_define_method(cSqlite3Database, "define_aggregator", define_aggregator, 2);
666
+ rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
667
+ rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
668
+ rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
669
+ rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
670
+ rb_define_method(cSqlite3Database, "changes", changes, 0);
671
+ rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
672
+ rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
673
+ rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
674
+
675
+ #ifdef HAVE_SQLITE3_LOAD_EXTENSION
676
+ rb_define_method(cSqlite3Database, "load_extension", load_extension, 1);
677
+ #endif
678
+
679
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
680
+ rb_define_method(cSqlite3Database, "enable_load_extension", enable_load_extension, 1);
681
+ #endif
682
+
683
+ #ifdef HAVE_RUBY_ENCODING_H
684
+ rb_define_method(cSqlite3Database, "encoding", db_encoding, 0);
685
+ #endif
686
+
687
+ id_utf16 = rb_intern("utf16");
688
+ sym_utf16 = ID2SYM(id_utf16);
689
+ id_results_as_hash = rb_intern("results_as_hash");
690
+ sym_results_as_hash = ID2SYM(id_results_as_hash);
691
+ id_type_translation = rb_intern("type_translation");
692
+ sym_type_translation = ID2SYM(id_type_translation);
693
+ }