sqlite3 1.7.2 → 2.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +323 -1
- data/CONTRIBUTING.md +33 -7
- data/FAQ.md +43 -77
- data/INSTALLATION.md +14 -6
- data/LICENSE +18 -22
- data/README.md +97 -9
- data/dependencies.yml +10 -11
- data/ext/sqlite3/aggregator.c +142 -145
- data/ext/sqlite3/aggregator.h +2 -4
- data/ext/sqlite3/backup.c +74 -65
- data/ext/sqlite3/backup.h +2 -2
- data/ext/sqlite3/database.c +623 -495
- data/ext/sqlite3/database.h +13 -4
- data/ext/sqlite3/exception.c +116 -92
- data/ext/sqlite3/exception.h +5 -1
- data/ext/sqlite3/extconf.rb +32 -24
- data/ext/sqlite3/sqlite3.c +176 -115
- data/ext/sqlite3/sqlite3_ruby.h +2 -2
- data/ext/sqlite3/statement.c +553 -300
- data/ext/sqlite3/statement.h +4 -3
- data/ext/sqlite3/timespec.h +20 -0
- data/lib/sqlite3/constants.rb +195 -47
- data/lib/sqlite3/database.rb +224 -187
- data/lib/sqlite3/errors.rb +54 -1
- data/lib/sqlite3/fork_safety.rb +66 -0
- data/lib/sqlite3/pragmas.rb +194 -141
- data/lib/sqlite3/resultset.rb +14 -97
- data/lib/sqlite3/statement.rb +58 -13
- data/lib/sqlite3/value.rb +17 -20
- data/lib/sqlite3/version.rb +2 -21
- data/lib/sqlite3/version_info.rb +17 -0
- data/lib/sqlite3.rb +8 -4
- data/ports/archives/sqlite-autoconf-3500100.tar.gz +0 -0
- metadata +9 -37
- data/API_CHANGES.md +0 -49
- data/ChangeLog.cvs +0 -88
- data/Gemfile +0 -10
- data/LICENSE-DEPENDENCIES +0 -20
- data/lib/sqlite3/translator.rb +0 -117
- data/ports/archives/sqlite-autoconf-3450100.tar.gz +0 -0
- data/test/helper.rb +0 -27
- data/test/test_backup.rb +0 -33
- data/test/test_collation.rb +0 -82
- data/test/test_database.rb +0 -668
- data/test/test_database_flags.rb +0 -95
- data/test/test_database_readonly.rb +0 -36
- data/test/test_database_readwrite.rb +0 -41
- data/test/test_deprecated.rb +0 -49
- data/test/test_encoding.rb +0 -165
- data/test/test_integration.rb +0 -507
- data/test/test_integration_aggregate.rb +0 -336
- data/test/test_integration_open_close.rb +0 -30
- data/test/test_integration_pending.rb +0 -115
- data/test/test_integration_resultset.rb +0 -142
- data/test/test_integration_statement.rb +0 -194
- data/test/test_pragmas.rb +0 -22
- data/test/test_result_set.rb +0 -47
- data/test/test_sqlite3.rb +0 -30
- data/test/test_statement.rb +0 -290
- data/test/test_statement_execute.rb +0 -39
data/lib/sqlite3/database.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
|
2
|
-
require 'sqlite3/errors'
|
3
|
-
require 'sqlite3/pragmas'
|
4
|
-
require 'sqlite3/statement'
|
5
|
-
require 'sqlite3/translator'
|
6
|
-
require 'sqlite3/value'
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
3
|
+
require "sqlite3/constants"
|
4
|
+
require "sqlite3/errors"
|
5
|
+
require "sqlite3/pragmas"
|
6
|
+
require "sqlite3/statement"
|
7
|
+
require "sqlite3/value"
|
8
|
+
require "sqlite3/fork_safety"
|
9
9
|
|
10
|
-
|
11
|
-
#
|
10
|
+
module SQLite3
|
11
|
+
# == Overview
|
12
|
+
#
|
13
|
+
# The Database class encapsulates a single connection to a SQLite3 database. Here's a
|
14
|
+
# straightforward example of usage:
|
12
15
|
#
|
13
16
|
# require 'sqlite3'
|
14
17
|
#
|
@@ -18,31 +21,79 @@ module SQLite3
|
|
18
21
|
# end
|
19
22
|
# end
|
20
23
|
#
|
21
|
-
# It wraps the lower-level methods provided by the selected driver, and
|
22
|
-
#
|
23
|
-
# methods.
|
24
|
+
# It wraps the lower-level methods provided by the selected driver, and includes the Pragmas
|
25
|
+
# module for access to various pragma convenience methods.
|
24
26
|
#
|
25
|
-
# The Database class provides type translation services as well, by which
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# for their tables). This translation only occurs when querying data from
|
27
|
+
# The Database class provides type translation services as well, by which the SQLite3 data types
|
28
|
+
# (which are all represented as strings) may be converted into their corresponding types (as
|
29
|
+
# defined in the schemas for their tables). This translation only occurs when querying data from
|
29
30
|
# the database--insertions and updates are all still typeless.
|
30
31
|
#
|
31
|
-
# Furthermore, the Database class has been designed to work well with the
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
32
|
+
# Furthermore, the Database class has been designed to work well with the ArrayFields module from
|
33
|
+
# Ara Howard. If you require the ArrayFields module before performing a query, and if you have not
|
34
|
+
# enabled results as hashes, then the results will all be indexible by field name.
|
35
|
+
#
|
36
|
+
# == Thread safety
|
37
|
+
#
|
38
|
+
# When SQLite3.threadsafe? returns true, it is safe to share instances of the database class
|
39
|
+
# among threads without adding specific locking. Other object instances may require applications
|
40
|
+
# to provide their own locks if they are to be shared among threads. Please see the README.md for
|
41
|
+
# more information.
|
42
|
+
#
|
43
|
+
# == SQLite Extensions
|
44
|
+
#
|
45
|
+
# SQLite3::Database supports the universe of {sqlite
|
46
|
+
# extensions}[https://www.sqlite.org/loadext.html]. It's possible to load an extension into an
|
47
|
+
# existing Database object using the #load_extension method and passing a filesystem path:
|
48
|
+
#
|
49
|
+
# db = SQLite3::Database.new(":memory:")
|
50
|
+
# db.enable_load_extension(true)
|
51
|
+
# db.load_extension("/path/to/extension")
|
52
|
+
#
|
53
|
+
# As of v2.4.0, it's also possible to pass an object that responds to +#to_path+. This
|
54
|
+
# documentation will refer to the supported interface as +_ExtensionSpecifier+, which can be
|
55
|
+
# expressed in RBS syntax as:
|
56
|
+
#
|
57
|
+
# interface _ExtensionSpecifier
|
58
|
+
# def to_path: () → String
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# So, for example, if you are using the {sqlean gem}[https://github.com/flavorjones/sqlean-ruby]
|
62
|
+
# which provides modules that implement this interface, you can pass the module directly:
|
63
|
+
#
|
64
|
+
# db = SQLite3::Database.new(":memory:")
|
65
|
+
# db.enable_load_extension(true)
|
66
|
+
# db.load_extension(SQLean::Crypto)
|
67
|
+
#
|
68
|
+
# It's also possible in v2.4.0+ to load extensions via the SQLite3::Database constructor by using
|
69
|
+
# the +extensions:+ keyword argument to pass an array of String paths or extension specifiers:
|
70
|
+
#
|
71
|
+
# db = SQLite3::Database.new(":memory:", extensions: ["/path/to/extension", SQLean::Crypto])
|
72
|
+
#
|
73
|
+
# Note that when loading extensions via the constructor, there is no need to call
|
74
|
+
# #enable_load_extension; however it is still necessary to call #enable_load_extensions before any
|
75
|
+
# subsequently invocations of #load_extension on the initialized Database object.
|
76
|
+
#
|
77
|
+
# You can load extensions in a Rails application by using the +extensions:+ configuration option:
|
78
|
+
#
|
79
|
+
# # config/database.yml
|
80
|
+
# development:
|
81
|
+
# adapter: sqlite3
|
82
|
+
# extensions:
|
83
|
+
# - .sqlpkg/nalgeon/crypto/crypto.so # a filesystem path
|
84
|
+
# - <%= SQLean::UUID.to_path %> # or ruby code returning a path
|
85
|
+
# - SQLean::Crypto # Rails 8.1+ accepts the name of a constant that responds to `to_path`
|
86
|
+
#
|
35
87
|
class Database
|
36
88
|
attr_reader :collations
|
37
89
|
|
38
90
|
include Pragmas
|
39
91
|
|
40
92
|
class << self
|
41
|
-
|
42
93
|
# Without block works exactly as new.
|
43
94
|
# With block, like new closes the database at the end, but unlike new
|
44
95
|
# returns the result of the block instead of the database instance.
|
45
|
-
def open(
|
96
|
+
def open(*args)
|
46
97
|
database = new(*args)
|
47
98
|
|
48
99
|
if block_given?
|
@@ -59,34 +110,34 @@ module SQLite3
|
|
59
110
|
# Quotes the given string, making it safe to use in an SQL statement.
|
60
111
|
# It replaces all instances of the single-quote character with two
|
61
112
|
# single-quote characters. The modified string is returned.
|
62
|
-
def quote(
|
63
|
-
string.gsub(
|
113
|
+
def quote(string)
|
114
|
+
string.gsub("'", "''")
|
64
115
|
end
|
65
|
-
|
66
116
|
end
|
67
117
|
|
68
118
|
# A boolean that indicates whether rows in result sets should be returned
|
69
119
|
# as hashes or not. By default, rows are returned as arrays.
|
70
120
|
attr_accessor :results_as_hash
|
71
121
|
|
72
|
-
# call-seq:
|
122
|
+
# call-seq:
|
123
|
+
# SQLite3::Database.new(file, options = {})
|
73
124
|
#
|
74
125
|
# Create a new Database object that opens the given file.
|
75
126
|
#
|
76
127
|
# Supported permissions +options+:
|
77
128
|
# - the default mode is <tt>READWRITE | CREATE</tt>
|
78
|
-
# -
|
79
|
-
# -
|
80
|
-
# -
|
129
|
+
# - +readonly:+ boolean (default false), true to set the mode to +READONLY+
|
130
|
+
# - +readwrite:+ boolean (default false), true to set the mode to +READWRITE+
|
131
|
+
# - +flags:+ set the mode to a combination of SQLite3::Constants::Open flags.
|
81
132
|
#
|
82
133
|
# Supported encoding +options+:
|
83
|
-
# -
|
134
|
+
# - +utf16:+ +boolish+ (default false), is the filename's encoding UTF-16 (only needed if the filename encoding is not UTF_16LE or BE)
|
84
135
|
#
|
85
136
|
# Other supported +options+:
|
86
|
-
# -
|
87
|
-
# -
|
88
|
-
# - +:
|
89
|
-
# -
|
137
|
+
# - +strict:+ +boolish+ (default false), disallow the use of double-quoted string literals (see https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted)
|
138
|
+
# - +results_as_hash:+ +boolish+ (default false), return rows as hashes instead of arrays
|
139
|
+
# - +default_transaction_mode:+ one of +:deferred+ (default), +:immediate+, or +:exclusive+. If a mode is not specified in a call to #transaction, this will be the default transaction mode.
|
140
|
+
# - +extensions:+ <tt>Array[String | _ExtensionSpecifier]</tt> SQLite extensions to load into the database. See Database@SQLite+Extensions for more information.
|
90
141
|
#
|
91
142
|
def initialize file, options = {}, zvfs = nil
|
92
143
|
mode = Constants::Open::READWRITE | Constants::Open::CREATE
|
@@ -120,18 +171,19 @@ module SQLite3
|
|
120
171
|
end
|
121
172
|
end
|
122
173
|
|
123
|
-
@tracefunc
|
124
|
-
@authorizer
|
125
|
-
@
|
126
|
-
@
|
127
|
-
@
|
128
|
-
@
|
129
|
-
@
|
130
|
-
@type_translation = options[:type_translation]
|
131
|
-
@type_translator = make_type_translator @type_translation
|
132
|
-
@readonly = mode & Constants::Open::READONLY != 0
|
174
|
+
@tracefunc = nil
|
175
|
+
@authorizer = nil
|
176
|
+
@progress_handler = nil
|
177
|
+
@collations = {}
|
178
|
+
@functions = {}
|
179
|
+
@results_as_hash = options[:results_as_hash]
|
180
|
+
@readonly = mode & Constants::Open::READONLY != 0
|
133
181
|
@default_transaction_mode = options[:default_transaction_mode] || :deferred
|
134
182
|
|
183
|
+
initialize_extensions(options[:extensions])
|
184
|
+
|
185
|
+
ForkSafety.track(self)
|
186
|
+
|
135
187
|
if block_given?
|
136
188
|
begin
|
137
189
|
yield self
|
@@ -141,30 +193,18 @@ module SQLite3
|
|
141
193
|
end
|
142
194
|
end
|
143
195
|
|
144
|
-
|
145
|
-
|
146
|
-
#
|
147
|
-
|
148
|
-
|
149
|
-
@type_translation = value
|
150
|
-
end
|
151
|
-
attr_reader :type_translation # :nodoc:
|
152
|
-
|
153
|
-
# Return the type translator employed by this database instance. Each
|
154
|
-
# database instance has its own type translator; this allows for different
|
155
|
-
# type handlers to be installed in each instance without affecting other
|
156
|
-
# instances. Furthermore, the translators are instantiated lazily, so that
|
157
|
-
# if a database does not use type translation, it will not be burdened by
|
158
|
-
# the overhead of a useless type translator. (See the Translator class.)
|
159
|
-
def translator
|
160
|
-
@translator ||= Translator.new
|
196
|
+
# call-seq: db.encoding
|
197
|
+
#
|
198
|
+
# Fetch the encoding set on this database
|
199
|
+
def encoding
|
200
|
+
Encoding.find super
|
161
201
|
end
|
162
202
|
|
163
203
|
# Installs (or removes) a block that will be invoked for every access
|
164
204
|
# to the database. If the block returns 0 (or +nil+), the statement
|
165
205
|
# is allowed to proceed. Returning 1 causes an authorization error to
|
166
206
|
# occur, and returning 2 causes the access to be silently denied.
|
167
|
-
def authorizer(
|
207
|
+
def authorizer(&block)
|
168
208
|
self.authorizer = block
|
169
209
|
end
|
170
210
|
|
@@ -174,7 +214,7 @@ module SQLite3
|
|
174
214
|
# The Statement can then be executed using Statement#execute.
|
175
215
|
#
|
176
216
|
def prepare sql
|
177
|
-
stmt = SQLite3::Statement.new(
|
217
|
+
stmt = SQLite3::Statement.new(self, sql)
|
178
218
|
return stmt unless block_given?
|
179
219
|
|
180
220
|
begin
|
@@ -187,7 +227,7 @@ module SQLite3
|
|
187
227
|
# Returns the filename for the database named +db_name+. +db_name+ defaults
|
188
228
|
# to "main". Main return `nil` or an empty string if the database is
|
189
229
|
# temporary or in-memory.
|
190
|
-
def filename db_name =
|
230
|
+
def filename db_name = "main"
|
191
231
|
db_filename db_name
|
192
232
|
end
|
193
233
|
|
@@ -205,29 +245,17 @@ module SQLite3
|
|
205
245
|
#
|
206
246
|
# See also #execute2, #query, and #execute_batch for additional ways of
|
207
247
|
# executing statements.
|
208
|
-
def execute sql, bind_vars = [],
|
209
|
-
|
210
|
-
if args.empty?
|
211
|
-
bind_vars = []
|
212
|
-
else
|
213
|
-
bind_vars = [bind_vars] + args
|
214
|
-
end
|
215
|
-
|
216
|
-
warn(<<-eowarn) if $VERBOSE
|
217
|
-
#{caller[0]} is calling `SQLite3::Database#execute` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for bind parameters as *args will be removed in 2.0.0.
|
218
|
-
eowarn
|
219
|
-
end
|
220
|
-
|
221
|
-
prepare( sql ) do |stmt|
|
248
|
+
def execute sql, bind_vars = [], &block
|
249
|
+
prepare(sql) do |stmt|
|
222
250
|
stmt.bind_params(bind_vars)
|
223
|
-
stmt
|
251
|
+
stmt = build_result_set stmt
|
224
252
|
|
225
|
-
if
|
253
|
+
if block
|
226
254
|
stmt.each do |row|
|
227
255
|
yield row
|
228
256
|
end
|
229
257
|
else
|
230
|
-
stmt.to_a
|
258
|
+
stmt.to_a.freeze
|
231
259
|
end
|
232
260
|
end
|
233
261
|
end
|
@@ -242,15 +270,16 @@ module SQLite3
|
|
242
270
|
#
|
243
271
|
# See also #execute, #query, and #execute_batch for additional ways of
|
244
272
|
# executing statements.
|
245
|
-
def execute2(
|
246
|
-
prepare(
|
247
|
-
result = stmt.execute(
|
273
|
+
def execute2(sql, *bind_vars)
|
274
|
+
prepare(sql) do |stmt|
|
275
|
+
result = stmt.execute(*bind_vars)
|
248
276
|
if block_given?
|
249
277
|
yield stmt.columns
|
250
278
|
result.each { |row| yield row }
|
251
279
|
else
|
252
|
-
return result.
|
253
|
-
|
280
|
+
return result.each_with_object([stmt.columns]) { |row, arr|
|
281
|
+
arr << row
|
282
|
+
}
|
254
283
|
end
|
255
284
|
end
|
256
285
|
end
|
@@ -261,49 +290,28 @@ module SQLite3
|
|
261
290
|
# in turn. The same bind parameters, if given, will be applied to each
|
262
291
|
# statement.
|
263
292
|
#
|
264
|
-
# This always returns
|
265
|
-
# rows.
|
293
|
+
# This always returns the result of the last statement.
|
266
294
|
#
|
267
295
|
# See also #execute_batch2 for additional ways of
|
268
296
|
# executing statements.
|
269
|
-
def execute_batch(
|
270
|
-
# FIXME: remove this stuff later
|
271
|
-
unless [Array, Hash].include?(bind_vars.class)
|
272
|
-
bind_vars = [bind_vars]
|
273
|
-
warn(<<-eowarn) if $VERBOSE
|
274
|
-
#{caller[0]} is calling `SQLite3::Database#execute_batch` with bind parameters that are not a list of a hash. Please switch to passing bind parameters as an array or hash. Support for this behavior will be removed in version 2.0.0.
|
275
|
-
eowarn
|
276
|
-
end
|
277
|
-
|
278
|
-
# FIXME: remove this stuff later
|
279
|
-
if bind_vars.nil? || !args.empty?
|
280
|
-
if args.empty?
|
281
|
-
bind_vars = []
|
282
|
-
else
|
283
|
-
bind_vars = [nil] + args
|
284
|
-
end
|
285
|
-
|
286
|
-
warn(<<-eowarn) if $VERBOSE
|
287
|
-
#{caller[0]} is calling `SQLite3::Database#execute_batch` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for this behavior will be removed in version 2.0.0.
|
288
|
-
eowarn
|
289
|
-
end
|
290
|
-
|
297
|
+
def execute_batch(sql, bind_vars = [])
|
291
298
|
sql = sql.strip
|
292
|
-
|
293
|
-
|
299
|
+
result = nil
|
300
|
+
until sql.empty?
|
301
|
+
prepare(sql) do |stmt|
|
294
302
|
unless stmt.closed?
|
295
303
|
# FIXME: this should probably use sqlite3's api for batch execution
|
296
304
|
# This implementation requires stepping over the results.
|
297
305
|
if bind_vars.length == stmt.bind_parameter_count
|
298
306
|
stmt.bind_params(bind_vars)
|
299
307
|
end
|
300
|
-
stmt.step
|
308
|
+
result = stmt.step
|
301
309
|
end
|
302
310
|
sql = stmt.remainder.strip
|
303
311
|
end
|
304
312
|
end
|
305
|
-
|
306
|
-
|
313
|
+
|
314
|
+
result
|
307
315
|
end
|
308
316
|
|
309
317
|
# Executes all SQL statements in the given string. By contrast, the other
|
@@ -320,7 +328,7 @@ module SQLite3
|
|
320
328
|
# See also #execute_batch for additional ways of
|
321
329
|
# executing statements.
|
322
330
|
def execute_batch2(sql, &block)
|
323
|
-
if
|
331
|
+
if block
|
324
332
|
result = exec_batch(sql, @results_as_hash)
|
325
333
|
result.map do |val|
|
326
334
|
yield val
|
@@ -341,21 +349,8 @@ module SQLite3
|
|
341
349
|
# returned, or you could have problems with locks on the table. If called
|
342
350
|
# with a block, +close+ will be invoked implicitly when the block
|
343
351
|
# terminates.
|
344
|
-
def query(
|
345
|
-
|
346
|
-
if bind_vars.nil? || !args.empty?
|
347
|
-
if args.empty?
|
348
|
-
bind_vars = []
|
349
|
-
else
|
350
|
-
bind_vars = [bind_vars] + args
|
351
|
-
end
|
352
|
-
|
353
|
-
warn(<<-eowarn) if $VERBOSE
|
354
|
-
#{caller[0]} is calling `SQLite3::Database#query` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for this will be removed in version 2.0.0.
|
355
|
-
eowarn
|
356
|
-
end
|
357
|
-
|
358
|
-
result = prepare( sql ).execute( bind_vars )
|
352
|
+
def query(sql, bind_vars = [])
|
353
|
+
result = prepare(sql).execute(bind_vars)
|
359
354
|
if block_given?
|
360
355
|
begin
|
361
356
|
yield result
|
@@ -363,7 +358,7 @@ module SQLite3
|
|
363
358
|
result.close
|
364
359
|
end
|
365
360
|
else
|
366
|
-
|
361
|
+
result
|
367
362
|
end
|
368
363
|
end
|
369
364
|
|
@@ -371,8 +366,8 @@ module SQLite3
|
|
371
366
|
# discarding all others. It is otherwise identical to #execute.
|
372
367
|
#
|
373
368
|
# See also #get_first_value.
|
374
|
-
def get_first_row(
|
375
|
-
execute(
|
369
|
+
def get_first_row(sql, *bind_vars)
|
370
|
+
execute(sql, *bind_vars).first
|
376
371
|
end
|
377
372
|
|
378
373
|
# A convenience method for obtaining the first value of the first row of a
|
@@ -380,8 +375,8 @@ module SQLite3
|
|
380
375
|
# identical to #execute.
|
381
376
|
#
|
382
377
|
# See also #get_first_row.
|
383
|
-
def get_first_value(
|
384
|
-
query(
|
378
|
+
def get_first_value(sql, *bind_vars)
|
379
|
+
query(sql, bind_vars) do |rs|
|
385
380
|
if (row = rs.next)
|
386
381
|
return @results_as_hash ? row[rs.columns[0]] : row[0]
|
387
382
|
end
|
@@ -389,7 +384,7 @@ module SQLite3
|
|
389
384
|
nil
|
390
385
|
end
|
391
386
|
|
392
|
-
|
387
|
+
alias_method :busy_timeout, :busy_timeout=
|
393
388
|
|
394
389
|
# Creates a new function for use in SQL statements. It will be added as
|
395
390
|
# +name+, with the given +arity+. (For variable arity functions, use
|
@@ -414,7 +409,7 @@ module SQLite3
|
|
414
409
|
# end
|
415
410
|
#
|
416
411
|
# puts db.get_first_value( "select maim(name) from table" )
|
417
|
-
def create_function name, arity, text_rep=Constants::TextRep::UTF8, &block
|
412
|
+
def create_function name, arity, text_rep = Constants::TextRep::UTF8, &block
|
418
413
|
define_function_with_flags(name, text_rep) do |*args|
|
419
414
|
fp = FunctionProxy.new
|
420
415
|
block.call(fp, *args)
|
@@ -459,20 +454,20 @@ module SQLite3
|
|
459
454
|
#
|
460
455
|
# See also #create_aggregate_handler for a more object-oriented approach to
|
461
456
|
# aggregate functions.
|
462
|
-
def create_aggregate(
|
463
|
-
text_rep=Constants::TextRep::ANY, &block
|
457
|
+
def create_aggregate(name, arity, step = nil, finalize = nil,
|
458
|
+
text_rep = Constants::TextRep::ANY, &block)
|
464
459
|
|
465
460
|
proxy = Class.new do
|
466
|
-
def self.step(
|
461
|
+
def self.step(&block)
|
467
462
|
define_method(:step_with_ctx, &block)
|
468
463
|
end
|
469
464
|
|
470
|
-
def self.finalize(
|
465
|
+
def self.finalize(&block)
|
471
466
|
define_method(:finalize_with_ctx, &block)
|
472
467
|
end
|
473
468
|
end
|
474
469
|
|
475
|
-
if
|
470
|
+
if block
|
476
471
|
proxy.instance_eval(&block)
|
477
472
|
else
|
478
473
|
proxy.class_eval do
|
@@ -498,7 +493,7 @@ module SQLite3
|
|
498
493
|
@ctx = FunctionProxy.new
|
499
494
|
end
|
500
495
|
|
501
|
-
def step(
|
496
|
+
def step(*args)
|
502
497
|
step_with_ctx(@ctx, *args)
|
503
498
|
end
|
504
499
|
|
@@ -557,7 +552,7 @@ module SQLite3
|
|
557
552
|
#
|
558
553
|
# db.create_aggregate_handler( LengthsAggregateHandler )
|
559
554
|
# puts db.get_first_value( "select lengths(name) from A" )
|
560
|
-
def create_aggregate_handler(
|
555
|
+
def create_aggregate_handler(handler)
|
561
556
|
# This is a compatibility shim so the (basically pointless) FunctionProxy
|
562
557
|
# "ctx" object is passed as first argument to both step() and finalize().
|
563
558
|
# Now its up to the library user whether he prefers to store his
|
@@ -571,7 +566,7 @@ module SQLite3
|
|
571
566
|
@fp = FunctionProxy.new
|
572
567
|
end
|
573
568
|
|
574
|
-
def step(
|
569
|
+
def step(*args)
|
575
570
|
super(@fp, *args)
|
576
571
|
end
|
577
572
|
|
@@ -594,7 +589,7 @@ module SQLite3
|
|
594
589
|
# individual instances of the aggregate function. Regular ruby objects
|
595
590
|
# already provide a suitable +clone+.
|
596
591
|
# The functions arity is the arity of the +step+ method.
|
597
|
-
def define_aggregator(
|
592
|
+
def define_aggregator(name, aggregator)
|
598
593
|
# Previously, this has been implemented in C. Now this is just yet
|
599
594
|
# another compatibility shim
|
600
595
|
proxy = Class.new do
|
@@ -648,9 +643,9 @@ module SQLite3
|
|
648
643
|
# If a block is not given, it is the caller's responsibility to end the
|
649
644
|
# transaction explicitly, either by calling #commit, or by calling
|
650
645
|
# #rollback.
|
651
|
-
def transaction(
|
646
|
+
def transaction(mode = nil)
|
652
647
|
mode = @default_transaction_mode if mode.nil?
|
653
|
-
execute "begin #{mode
|
648
|
+
execute "begin #{mode} transaction"
|
654
649
|
|
655
650
|
if block_given?
|
656
651
|
abort = false
|
@@ -662,9 +657,9 @@ module SQLite3
|
|
662
657
|
ensure
|
663
658
|
abort and rollback or commit
|
664
659
|
end
|
660
|
+
else
|
661
|
+
true
|
665
662
|
end
|
666
|
-
|
667
|
-
true
|
668
663
|
end
|
669
664
|
|
670
665
|
# Commits the current transaction. If there is no current transaction,
|
@@ -691,6 +686,71 @@ module SQLite3
|
|
691
686
|
@readonly
|
692
687
|
end
|
693
688
|
|
689
|
+
# Sets a #busy_handler that releases the GVL between retries,
|
690
|
+
# but only retries up to the indicated number of +milliseconds+.
|
691
|
+
# This is an alternative to #busy_timeout, which holds the GVL
|
692
|
+
# while SQLite sleeps and retries.
|
693
|
+
def busy_handler_timeout=(milliseconds)
|
694
|
+
timeout_seconds = milliseconds.fdiv(1000)
|
695
|
+
|
696
|
+
busy_handler do |count|
|
697
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
698
|
+
if count.zero?
|
699
|
+
@timeout_deadline = now + timeout_seconds
|
700
|
+
elsif now > @timeout_deadline
|
701
|
+
next false
|
702
|
+
else
|
703
|
+
sleep(0.001)
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
# call-seq:
|
709
|
+
# load_extension(extension_specifier) -> self
|
710
|
+
#
|
711
|
+
# Loads an SQLite extension library from the named file. Extension loading must be enabled using
|
712
|
+
# #enable_load_extension prior to using this method.
|
713
|
+
#
|
714
|
+
# See also: Database@SQLite+Extensions
|
715
|
+
#
|
716
|
+
# [Parameters]
|
717
|
+
# - +extension_specifier+: (String | +_ExtensionSpecifier+) If a String, it is the filesystem path
|
718
|
+
# to the sqlite extension file. If an object that responds to #to_path, the
|
719
|
+
# return value of that method is used as the filesystem path to the sqlite extension file.
|
720
|
+
#
|
721
|
+
# [Example] Using a filesystem path:
|
722
|
+
#
|
723
|
+
# db.load_extension("/path/to/my_extension.so")
|
724
|
+
#
|
725
|
+
# [Example] Using the {sqlean gem}[https://github.com/flavorjones/sqlean-ruby]:
|
726
|
+
#
|
727
|
+
# db.load_extension(SQLean::VSV)
|
728
|
+
#
|
729
|
+
def load_extension(extension_specifier)
|
730
|
+
if extension_specifier.respond_to?(:to_path)
|
731
|
+
extension_specifier = extension_specifier.to_path
|
732
|
+
elsif !extension_specifier.is_a?(String)
|
733
|
+
raise TypeError, "extension_specifier #{extension_specifier.inspect} is not a String or a valid extension specifier object"
|
734
|
+
end
|
735
|
+
load_extension_internal(extension_specifier)
|
736
|
+
end
|
737
|
+
|
738
|
+
def initialize_extensions(extensions) # :nodoc:
|
739
|
+
return if extensions.nil?
|
740
|
+
raise TypeError, "extensions must be an Array" unless extensions.is_a?(Array)
|
741
|
+
return if extensions.empty?
|
742
|
+
|
743
|
+
begin
|
744
|
+
enable_load_extension(true)
|
745
|
+
|
746
|
+
extensions.each do |extension|
|
747
|
+
load_extension(extension)
|
748
|
+
end
|
749
|
+
ensure
|
750
|
+
enable_load_extension(false)
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
694
754
|
# A helper class for dealing with custom functions (see #create_function,
|
695
755
|
# #create_aggregate, and #create_aggregate_handler). It encapsulates the
|
696
756
|
# opaque function object that represents the current invocation. It also
|
@@ -707,54 +767,31 @@ module SQLite3
|
|
707
767
|
# it is non-nil, it must quack like a Hash. If it is nil, then none of
|
708
768
|
# the context functions will be available.
|
709
769
|
def initialize
|
710
|
-
@result
|
711
|
-
@context
|
712
|
-
end
|
713
|
-
|
714
|
-
# Set the result of the function to the given error message.
|
715
|
-
# The function will then return that error.
|
716
|
-
def set_error( error )
|
717
|
-
@driver.result_error( @func, error.to_s, -1 )
|
718
|
-
end
|
719
|
-
|
720
|
-
# (Only available to aggregate functions.) Returns the number of rows
|
721
|
-
# that the aggregate has processed so far. This will include the current
|
722
|
-
# row, and so will always return at least 1.
|
723
|
-
def count
|
724
|
-
@driver.aggregate_count( @func )
|
770
|
+
@result = nil
|
771
|
+
@context = {}
|
725
772
|
end
|
726
773
|
|
727
774
|
# Returns the value with the given key from the context. This is only
|
728
775
|
# available to aggregate functions.
|
729
|
-
def [](
|
730
|
-
@context[
|
776
|
+
def [](key)
|
777
|
+
@context[key]
|
731
778
|
end
|
732
779
|
|
733
780
|
# Sets the value with the given key in the context. This is only
|
734
781
|
# available to aggregate functions.
|
735
|
-
def []=(
|
736
|
-
@context[
|
782
|
+
def []=(key, value)
|
783
|
+
@context[key] = value
|
737
784
|
end
|
738
785
|
end
|
739
786
|
|
740
|
-
#
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
NULL_TRANSLATOR = lambda { |_, row| row }
|
748
|
-
|
749
|
-
def make_type_translator should_translate
|
750
|
-
if should_translate
|
751
|
-
lambda { |types, row|
|
752
|
-
types.zip(row).map do |type, value|
|
753
|
-
translator.translate( type, value )
|
754
|
-
end
|
755
|
-
}
|
787
|
+
# Given a statement, return a result set.
|
788
|
+
# This is not intended for general consumption
|
789
|
+
# :nodoc:
|
790
|
+
def build_result_set stmt
|
791
|
+
if results_as_hash
|
792
|
+
HashResultSet.new(self, stmt)
|
756
793
|
else
|
757
|
-
|
794
|
+
ResultSet.new(self, stmt)
|
758
795
|
end
|
759
796
|
end
|
760
797
|
end
|