sqlite3 2.0.0-x86_64-linux-musl

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2004-2024, Jamis Buck, Luis Lavena, Aaron Patterson, Mike Dalessio, et al.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted
4
+ provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions
7
+ and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of
10
+ conditions and the following disclaimer in the documentation and/or other materials provided with
11
+ the distribution.
12
+
13
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to
14
+ endorse or promote products derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
23
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,181 @@
1
+ # Ruby Interface for SQLite3
2
+
3
+ ## Overview
4
+
5
+ This library allows Ruby programs to use the SQLite3 database engine (http://www.sqlite.org).
6
+
7
+ Note that this module is only compatible with SQLite 3.6.16 or newer.
8
+
9
+ * Source code: https://github.com/sparklemotion/sqlite3-ruby
10
+ * Mailing list: http://groups.google.com/group/sqlite3-ruby
11
+ * Download: http://rubygems.org/gems/sqlite3
12
+ * Documentation: http://www.rubydoc.info/gems/sqlite3
13
+
14
+ [![Test suite](https://github.com/sparklemotion/sqlite3-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/sparklemotion/sqlite3-ruby/actions/workflows/ci.yml)
15
+
16
+
17
+ ## Quick start
18
+
19
+ For help understanding the SQLite3 Ruby API, please read the [FAQ](./FAQ.md) and the [full API documentation](https://rubydoc.info/gems/sqlite3).
20
+
21
+ A few key classes whose APIs are often-used are:
22
+
23
+ - SQLite3::Database ([rdoc](https://rubydoc.info/gems/sqlite3/SQLite3/Database))
24
+ - SQLite3::Statement ([rdoc](https://rubydoc.info/gems/sqlite3/SQLite3/Statement))
25
+ - SQLite3::ResultSet ([rdoc](https://rubydoc.info/gems/sqlite3/SQLite3/ResultSet))
26
+
27
+ If you have any questions that you feel should be addressed in the FAQ, please send them to [the mailing list](http://groups.google.com/group/sqlite3-ruby) or open a [discussion thread](https://github.com/sparklemotion/sqlite3-ruby/discussions/categories/q-a).
28
+
29
+
30
+ ``` ruby
31
+ require "sqlite3"
32
+
33
+ # Open a database
34
+ db = SQLite3::Database.new "test.db"
35
+
36
+ # Create a table
37
+ rows = db.execute <<-SQL
38
+ create table numbers (
39
+ name varchar(30),
40
+ val int
41
+ );
42
+ SQL
43
+
44
+ # Execute a few inserts
45
+ {
46
+ "one" => 1,
47
+ "two" => 2,
48
+ }.each do |pair|
49
+ db.execute "insert into numbers values ( ?, ? )", pair
50
+ end
51
+
52
+ # Find a few rows
53
+ db.execute( "select * from numbers" ) do |row|
54
+ p row
55
+ end
56
+ # => ["one", 1]
57
+ # ["two", 2]
58
+
59
+ # Create another table with multiple columns
60
+ db.execute <<-SQL
61
+ create table students (
62
+ name varchar(50),
63
+ email varchar(50),
64
+ grade varchar(5),
65
+ blog varchar(50)
66
+ );
67
+ SQL
68
+
69
+ # Execute inserts with parameter markers
70
+ db.execute("INSERT INTO students (name, email, grade, blog)
71
+ VALUES (?, ?, ?, ?)", ["Jane", "me@janedoe.com", "A", "http://blog.janedoe.com"])
72
+
73
+ db.execute( "select * from students" ) do |row|
74
+ p row
75
+ end
76
+ # => ["Jane", "me@janedoe.com", "A", "http://blog.janedoe.com"]
77
+ ```
78
+
79
+ ## Thread Safety
80
+
81
+ When `SQLite3.threadsafe?` returns `true`, then SQLite3 has been compiled to
82
+ support running in a multithreaded environment. However, this doesn't mean
83
+ that all classes in the SQLite3 gem can be considered "thread safe".
84
+
85
+ When `SQLite3.threadsafe?` returns `true`, it is safe to share only
86
+ `SQLite3::Database` instances among threads without providing your own locking
87
+ mechanism. For example, the following code is fine because only the database
88
+ instance is shared among threads:
89
+
90
+ ```ruby
91
+ require 'sqlite3'
92
+
93
+ db = SQLite3::Database.new ":memory:"
94
+
95
+ latch = Queue.new
96
+
97
+ ts = 10.times.map {
98
+ Thread.new {
99
+ latch.pop
100
+ db.execute "SELECT '#{Thread.current.inspect}'"
101
+ }
102
+ }
103
+ 10.times { latch << nil }
104
+
105
+ p ts.map(&:value)
106
+ ```
107
+
108
+ Other instances can be shared among threads, but they require that you provide
109
+ your own locking for thread safety. For example, `SQLite3::Statement` objects
110
+ (prepared statements) are mutable, so applications must take care to add
111
+ appropriate locks to avoid data race conditions when sharing these objects
112
+ among threads.
113
+
114
+ Lets rewrite the above example but use a prepared statement and safely share
115
+ the prepared statement among threads:
116
+
117
+ ```ruby
118
+ db = SQLite3::Database.new ":memory:"
119
+
120
+ # Prepare a statement
121
+ stmt = db.prepare "SELECT :inspect"
122
+ stmt_lock = Mutex.new
123
+
124
+ latch = Queue.new
125
+
126
+ ts = 10.times.map {
127
+ Thread.new {
128
+ latch.pop
129
+
130
+ # Add a lock when using the prepared statement.
131
+ # Binding values, and walking over results will mutate the statement, so
132
+ # in order to prevent other threads from "seeing" this thread's data, we
133
+ # must lock when using the statement object
134
+ stmt_lock.synchronize do
135
+ stmt.execute(Thread.current.inspect).to_a
136
+ end
137
+ }
138
+ }
139
+
140
+ 10.times { latch << nil }
141
+
142
+ p ts.map(&:value)
143
+
144
+ stmt.close
145
+ ```
146
+
147
+ It is generally recommended that if applications want to share a database among
148
+ threads, they _only_ share the database instance object. Other objects are
149
+ fine to share, but may require manual locking for thread safety.
150
+
151
+ ## Support
152
+
153
+ ### Installation or database extensions
154
+
155
+ If you're having trouble with installation, please first read [`INSTALLATION.md`](./INSTALLATION.md).
156
+
157
+ ### General help requests
158
+
159
+ You can ask for help or support:
160
+
161
+ * by emailing the [sqlite3-ruby mailing list](http://groups.google.com/group/sqlite3-ruby)
162
+ * by opening a [discussion thread](https://github.com/sparklemotion/sqlite3-ruby/discussions/categories/q-a) on Github
163
+
164
+ ### Bug reports
165
+
166
+ You can file the bug at the [github issues page](https://github.com/sparklemotion/sqlite3-ruby/issues).
167
+
168
+
169
+ ## Contributing
170
+
171
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
172
+
173
+
174
+ ## License
175
+
176
+ This library is licensed under `BSD-3-Clause`, see [`LICENSE`](./LICENSE).
177
+
178
+ ### Dependencies
179
+
180
+ The source code of `sqlite` is distributed in the "ruby platform" gem. This code is public domain,
181
+ see https://www.sqlite.org/copyright.html for details.
data/dependencies.yml ADDED
@@ -0,0 +1,13 @@
1
+ sqlite3:
2
+ # checksum verified by first checking the published sha3(256) checksum against https://sqlite.org/download.html:
3
+ # cc1050780e0266de4d91b31c8deaf4638336908c12c21898e9f1fcae1e2ac303
4
+ #
5
+ # $ sha3sum -a 256 ports/archives/sqlite-autoconf-3450300.tar.gz
6
+ # cc1050780e0266de4d91b31c8deaf4638336908c12c21898e9f1fcae1e2ac303 ports/archives/sqlite-autoconf-3450300.tar.gz
7
+ #
8
+ # $ sha256sum ports/archives/sqlite-autoconf-3450300.tar.gz
9
+ # b2809ca53124c19c60f42bf627736eae011afdcc205bb48270a5ee9a38191531 ports/archives/sqlite-autoconf-3450300.tar.gz
10
+ version: "3.45.3"
11
+ files:
12
+ - url: "https://sqlite.org/2024/sqlite-autoconf-3450300.tar.gz"
13
+ sha256: "b2809ca53124c19c60f42bf627736eae011afdcc205bb48270a5ee9a38191531"
@@ -0,0 +1,270 @@
1
+ #include <aggregator.h>
2
+ #include <database.h>
3
+
4
+ /* wraps a factory "handler" class. The "-aggregators" instance variable of
5
+ * the SQLite3::Database holds an array of all AggrogatorWrappers.
6
+ *
7
+ * An AggregatorWrapper holds the following instance variables:
8
+ * -handler_klass: the handler that creates the instances.
9
+ * -instances: array of all the cAggregatorInstance objects currently
10
+ * in-flight for this aggregator. */
11
+ static VALUE cAggregatorWrapper;
12
+
13
+ /* wraps a instance of the "handler" class. Loses its reference at the end of
14
+ * the xFinal callback.
15
+ *
16
+ * An AggregatorInstance holds the following instance variables:
17
+ * -handler_instance: the instance to call `step` and `finalize` on.
18
+ * -exc_status: status returned by rb_protect.
19
+ * != 0 if an exception occurred. If an exception occurred
20
+ * `step` and `finalize` won't be called any more. */
21
+ static VALUE cAggregatorInstance;
22
+
23
+ typedef struct rb_sqlite3_protected_funcall_args {
24
+ VALUE self;
25
+ ID method;
26
+ int argc;
27
+ VALUE *params;
28
+ } protected_funcall_args_t;
29
+
30
+ /* why isn't there something like this in the ruby API? */
31
+ static VALUE
32
+ rb_sqlite3_protected_funcall_body(VALUE protected_funcall_args_ptr)
33
+ {
34
+ protected_funcall_args_t *args =
35
+ (protected_funcall_args_t *)protected_funcall_args_ptr;
36
+
37
+ return rb_funcall2(args->self, args->method, args->argc, args->params);
38
+ }
39
+
40
+ static VALUE
41
+ rb_sqlite3_protected_funcall(VALUE self, ID method, int argc, VALUE *params,
42
+ int *exc_status)
43
+ {
44
+ protected_funcall_args_t args = {
45
+ .self = self, .method = method, .argc = argc, .params = params
46
+ };
47
+ return rb_protect(rb_sqlite3_protected_funcall_body, (VALUE)(&args), exc_status);
48
+ }
49
+
50
+ /* called in rb_sqlite3_aggregator_step and rb_sqlite3_aggregator_final. It
51
+ * checks if the execution context already has an associated instance. If it
52
+ * has one, it returns it. If there is no instance yet, it creates one and
53
+ * associates it with the context. */
54
+ static VALUE
55
+ rb_sqlite3_aggregate_instance(sqlite3_context *ctx)
56
+ {
57
+ VALUE aw = (VALUE) sqlite3_user_data(ctx);
58
+ VALUE handler_klass = rb_iv_get(aw, "-handler_klass");
59
+ VALUE inst;
60
+ VALUE *inst_ptr = sqlite3_aggregate_context(ctx, (int)sizeof(VALUE));
61
+
62
+ if (!inst_ptr) {
63
+ rb_fatal("SQLite is out-of-merory");
64
+ }
65
+
66
+ inst = *inst_ptr;
67
+
68
+ if (inst == Qfalse) { /* Qfalse == 0 */
69
+ VALUE instances = rb_iv_get(aw, "-instances");
70
+ int exc_status;
71
+
72
+ inst = rb_class_new_instance(0, NULL, cAggregatorInstance);
73
+ rb_iv_set(inst, "-handler_instance", rb_sqlite3_protected_funcall(
74
+ handler_klass, rb_intern("new"), 0, NULL, &exc_status));
75
+ rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));
76
+
77
+ rb_ary_push(instances, inst);
78
+
79
+ *inst_ptr = inst;
80
+ }
81
+
82
+ if (inst == Qnil) {
83
+ rb_fatal("SQLite called us back on an already destroyed aggregate instance");
84
+ }
85
+
86
+ return inst;
87
+ }
88
+
89
+ /* called by rb_sqlite3_aggregator_final. Unlinks and frees the
90
+ * aggregator_instance_t, so the handler_instance won't be marked any more
91
+ * and Ruby's GC may free it. */
92
+ static void
93
+ rb_sqlite3_aggregate_instance_destroy(sqlite3_context *ctx)
94
+ {
95
+ VALUE aw = (VALUE) sqlite3_user_data(ctx);
96
+ VALUE instances = rb_iv_get(aw, "-instances");
97
+ VALUE *inst_ptr = sqlite3_aggregate_context(ctx, 0);
98
+ VALUE inst;
99
+
100
+ if (!inst_ptr || (inst = *inst_ptr)) {
101
+ return;
102
+ }
103
+
104
+ if (inst == Qnil) {
105
+ rb_fatal("attempt to destroy aggregate instance twice");
106
+ }
107
+
108
+ rb_iv_set(inst, "-handler_instance", Qnil); // may catch use-after-free
109
+ if (rb_ary_delete(instances, inst) == Qnil) {
110
+ rb_fatal("must be in instances at that point");
111
+ }
112
+
113
+ *inst_ptr = Qnil;
114
+ }
115
+
116
+ static void
117
+ rb_sqlite3_aggregator_step(sqlite3_context *ctx, int argc, sqlite3_value **argv)
118
+ {
119
+ VALUE inst = rb_sqlite3_aggregate_instance(ctx);
120
+ VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
121
+ VALUE *params = NULL;
122
+ VALUE one_param;
123
+ int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
124
+ int i;
125
+
126
+ if (exc_status) {
127
+ return;
128
+ }
129
+
130
+ if (argc == 1) {
131
+ one_param = sqlite3val2rb(argv[0]);
132
+ params = &one_param;
133
+ }
134
+ if (argc > 1) {
135
+ params = xcalloc((size_t)argc, sizeof(VALUE));
136
+ for (i = 0; i < argc; i++) {
137
+ params[i] = sqlite3val2rb(argv[i]);
138
+ }
139
+ }
140
+ rb_sqlite3_protected_funcall(
141
+ handler_instance, rb_intern("step"), argc, params, &exc_status);
142
+ if (argc > 1) {
143
+ xfree(params);
144
+ }
145
+
146
+ rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));
147
+ }
148
+
149
+ /* we assume that this function is only called once per execution context */
150
+ static void
151
+ rb_sqlite3_aggregator_final(sqlite3_context *ctx)
152
+ {
153
+ VALUE inst = rb_sqlite3_aggregate_instance(ctx);
154
+ VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
155
+ int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
156
+
157
+ if (!exc_status) {
158
+ VALUE result = rb_sqlite3_protected_funcall(
159
+ handler_instance, rb_intern("finalize"), 0, NULL, &exc_status);
160
+ if (!exc_status) {
161
+ set_sqlite3_func_result(ctx, result);
162
+ }
163
+ }
164
+
165
+ if (exc_status) {
166
+ /* the user should never see this, as Statement.step() will pick up the
167
+ * outstanding exception and raise it instead of generating a new one
168
+ * for SQLITE_ERROR with message "Ruby Exception occurred" */
169
+ sqlite3_result_error(ctx, "Ruby Exception occurred", -1);
170
+ }
171
+
172
+ rb_sqlite3_aggregate_instance_destroy(ctx);
173
+ }
174
+
175
+ /* call-seq: define_aggregator2(aggregator)
176
+ *
177
+ * Define an aggregrate function according to a factory object (the "handler")
178
+ * that knows how to obtain to all the information. The handler must provide
179
+ * the following class methods:
180
+ *
181
+ * +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
182
+ * message is optional, and if the handler does not respond to it,
183
+ * the function will have an arity of -1.
184
+ * +name+:: this is the name of the function. The handler _must_ implement
185
+ * this message.
186
+ * +new+:: this must be implemented by the handler. It should return a new
187
+ * instance of the object that will handle a specific invocation of
188
+ * the function.
189
+ *
190
+ * The handler instance (the object returned by the +new+ message, described
191
+ * above), must respond to the following messages:
192
+ *
193
+ * +step+:: this is the method that will be called for each step of the
194
+ * aggregate function's evaluation. It should take parameters according
195
+ * to the *arity* definition.
196
+ * +finalize+:: this is the method that will be called to finalize the
197
+ * aggregate function's evaluation. It should not take arguments.
198
+ *
199
+ * Note the difference between this function and #create_aggregate_handler
200
+ * is that no FunctionProxy ("ctx") object is involved. This manifests in two
201
+ * ways: The return value of the aggregate function is the return value of
202
+ * +finalize+ and neither +step+ nor +finalize+ take an additional "ctx"
203
+ * parameter.
204
+ */
205
+ VALUE
206
+ rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name)
207
+ {
208
+ /* define_aggregator is added as a method to SQLite3::Database in database.c */
209
+ sqlite3RubyPtr ctx = sqlite3_database_unwrap(self);
210
+ int arity, status;
211
+ VALUE aw;
212
+ VALUE aggregators;
213
+
214
+ if (!ctx->db) {
215
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
216
+ }
217
+
218
+ if (rb_respond_to(aggregator, rb_intern("arity"))) {
219
+ VALUE ruby_arity = rb_funcall(aggregator, rb_intern("arity"), 0);
220
+ arity = NUM2INT(ruby_arity);
221
+ } else {
222
+ arity = -1;
223
+ }
224
+
225
+ if (arity < -1 || arity > 127) {
226
+ #ifdef PRIsVALUE
227
+ rb_raise(rb_eArgError, "%"PRIsVALUE" arity=%d out of range -1..127",
228
+ self, arity);
229
+ #else
230
+ rb_raise(rb_eArgError, "Aggregator arity=%d out of range -1..127", arity);
231
+ #endif
232
+ }
233
+
234
+ if (!rb_ivar_defined(self, rb_intern("-aggregators"))) {
235
+ rb_iv_set(self, "-aggregators", rb_ary_new());
236
+ }
237
+ aggregators = rb_iv_get(self, "-aggregators");
238
+
239
+ aw = rb_class_new_instance(0, NULL, cAggregatorWrapper);
240
+ rb_iv_set(aw, "-handler_klass", aggregator);
241
+ rb_iv_set(aw, "-instances", rb_ary_new());
242
+
243
+ status = sqlite3_create_function(
244
+ ctx->db,
245
+ StringValueCStr(ruby_name),
246
+ arity,
247
+ SQLITE_UTF8,
248
+ (void *)aw,
249
+ NULL,
250
+ rb_sqlite3_aggregator_step,
251
+ rb_sqlite3_aggregator_final
252
+ );
253
+
254
+ CHECK(ctx->db, status);
255
+
256
+ rb_ary_push(aggregators, aw);
257
+
258
+ return self;
259
+ }
260
+
261
+ void
262
+ rb_sqlite3_aggregator_init(void)
263
+ {
264
+ /* rb_class_new generatos class with undefined allocator in ruby 1.9 */
265
+ cAggregatorWrapper = rb_funcall(rb_cClass, rb_intern("new"), 0);
266
+ rb_gc_register_mark_object(cAggregatorWrapper);
267
+
268
+ cAggregatorInstance = rb_funcall(rb_cClass, rb_intern("new"), 0);
269
+ rb_gc_register_mark_object(cAggregatorInstance);
270
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef SQLITE3_AGGREGATOR_RUBY
2
+ #define SQLITE3_AGGREGATOR_RUBY
3
+
4
+ #include <sqlite3_ruby.h>
5
+
6
+ VALUE rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name);
7
+
8
+ void rb_sqlite3_aggregator_init(void);
9
+
10
+ #endif
@@ -0,0 +1,190 @@
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 size_t
12
+ backup_memsize(const void *data)
13
+ {
14
+ sqlite3BackupRubyPtr ctx = (sqlite3BackupRubyPtr)data;
15
+ // NB: can't account for ctx->p because the type is incomplete.
16
+ return sizeof(*ctx);
17
+ }
18
+
19
+ static const rb_data_type_t backup_type = {
20
+ "SQLite3::Backup",
21
+ {
22
+ NULL,
23
+ RUBY_TYPED_DEFAULT_FREE,
24
+ backup_memsize,
25
+ },
26
+ 0,
27
+ 0,
28
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
29
+ };
30
+
31
+ static VALUE
32
+ allocate(VALUE klass)
33
+ {
34
+ sqlite3BackupRubyPtr ctx;
35
+ return TypedData_Make_Struct(klass, sqlite3BackupRuby, &backup_type, ctx);
36
+ }
37
+
38
+ /* call-seq: SQLite3::Backup.new(dstdb, dstname, srcdb, srcname)
39
+ *
40
+ * Initialize backup the backup.
41
+ *
42
+ * dstdb:
43
+ * the destination SQLite3::Database object.
44
+ * dstname:
45
+ * the destination's database name.
46
+ * srcdb:
47
+ * the source SQLite3::Database object.
48
+ * srcname:
49
+ * the source's database name.
50
+ *
51
+ * The database name is "main", "temp", or the name specified in an
52
+ * ATTACH statement.
53
+ *
54
+ * This feature requires SQLite 3.6.11 or later.
55
+ *
56
+ * require 'sqlite3'
57
+ * sdb = SQLite3::Database.new('src.sqlite3')
58
+ *
59
+ * ddb = SQLite3::Database.new(':memory:')
60
+ * b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
61
+ * p [b.remaining, b.pagecount] # invalid value; for example [0, 0]
62
+ * begin
63
+ * p b.step(1) #=> OK or DONE
64
+ * p [b.remaining, b.pagecount]
65
+ * end while b.remaining > 0
66
+ * b.finish
67
+ *
68
+ * ddb = SQLite3::Database.new(':memory:')
69
+ * b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
70
+ * b.step(-1) #=> DONE
71
+ * b.finish
72
+ *
73
+ */
74
+ static VALUE
75
+ initialize(VALUE self, VALUE dstdb, VALUE dstname, VALUE srcdb, VALUE srcname)
76
+ {
77
+ sqlite3BackupRubyPtr ctx;
78
+ sqlite3RubyPtr ddb_ctx, sdb_ctx;
79
+ sqlite3_backup *pBackup;
80
+
81
+ TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
82
+ ddb_ctx = sqlite3_database_unwrap(dstdb);
83
+ sdb_ctx = sqlite3_database_unwrap(srcdb);
84
+
85
+ if (!sdb_ctx->db) {
86
+ rb_raise(rb_eArgError, "cannot backup from a closed database");
87
+ }
88
+ if (!ddb_ctx->db) {
89
+ rb_raise(rb_eArgError, "cannot backup to a closed database");
90
+ }
91
+
92
+ pBackup = sqlite3_backup_init(ddb_ctx->db, StringValuePtr(dstname),
93
+ sdb_ctx->db, StringValuePtr(srcname));
94
+ if (pBackup) {
95
+ ctx->p = pBackup;
96
+ } else {
97
+ CHECK(ddb_ctx->db, sqlite3_errcode(ddb_ctx->db));
98
+ }
99
+
100
+ return self;
101
+ }
102
+
103
+ /* call-seq: SQLite3::Backup#step(nPage)
104
+ *
105
+ * Copy database pages up to +nPage+.
106
+ * If negative, copy all remaining source pages.
107
+ *
108
+ * If all pages are copied, it returns SQLite3::Constants::ErrorCode::DONE.
109
+ * When coping is not done, it returns SQLite3::Constants::ErrorCode::OK.
110
+ * When some errors occur, it returns the error code.
111
+ */
112
+ static VALUE
113
+ step(VALUE self, VALUE nPage)
114
+ {
115
+ sqlite3BackupRubyPtr ctx;
116
+ int status;
117
+
118
+ TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
119
+ REQUIRE_OPEN_BACKUP(ctx);
120
+ status = sqlite3_backup_step(ctx->p, NUM2INT(nPage));
121
+ return INT2NUM(status);
122
+ }
123
+
124
+ /* call-seq: SQLite3::Backup#finish
125
+ *
126
+ * Destroy the backup object.
127
+ */
128
+ static VALUE
129
+ finish(VALUE self)
130
+ {
131
+ sqlite3BackupRubyPtr ctx;
132
+
133
+ TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
134
+ REQUIRE_OPEN_BACKUP(ctx);
135
+ (void)sqlite3_backup_finish(ctx->p);
136
+ ctx->p = NULL;
137
+ return Qnil;
138
+ }
139
+
140
+ /* call-seq: SQLite3::Backup#remaining
141
+ *
142
+ * Returns the number of pages still to be backed up.
143
+ *
144
+ * Note that the value is only updated after step() is called,
145
+ * so before calling step() returned value is invalid.
146
+ */
147
+ static VALUE
148
+ remaining(VALUE self)
149
+ {
150
+ sqlite3BackupRubyPtr ctx;
151
+
152
+ TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
153
+ REQUIRE_OPEN_BACKUP(ctx);
154
+ return INT2NUM(sqlite3_backup_remaining(ctx->p));
155
+ }
156
+
157
+ /* call-seq: SQLite3::Backup#pagecount
158
+ *
159
+ * Returns the total number of pages in the source database file.
160
+ *
161
+ * Note that the value is only updated after step() is called,
162
+ * so before calling step() returned value is invalid.
163
+ */
164
+ static VALUE
165
+ pagecount(VALUE self)
166
+ {
167
+ sqlite3BackupRubyPtr ctx;
168
+
169
+ TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
170
+ REQUIRE_OPEN_BACKUP(ctx);
171
+ return INT2NUM(sqlite3_backup_pagecount(ctx->p));
172
+ }
173
+
174
+ void
175
+ init_sqlite3_backup(void)
176
+ {
177
+ #if 0
178
+ VALUE mSqlite3 = rb_define_module("SQLite3");
179
+ #endif
180
+ cSqlite3Backup = rb_define_class_under(mSqlite3, "Backup", rb_cObject);
181
+
182
+ rb_define_alloc_func(cSqlite3Backup, allocate);
183
+ rb_define_method(cSqlite3Backup, "initialize", initialize, 4);
184
+ rb_define_method(cSqlite3Backup, "step", step, 1);
185
+ rb_define_method(cSqlite3Backup, "finish", finish, 0);
186
+ rb_define_method(cSqlite3Backup, "remaining", remaining, 0);
187
+ rb_define_method(cSqlite3Backup, "pagecount", pagecount, 0);
188
+ }
189
+
190
+ #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