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