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

Sign up to get free protection for your applications and to get access to all the features.
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
+ }