sqlite3-ffi 0.1.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.
@@ -0,0 +1,797 @@
1
+ # frozen_string_literal: true
2
+
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
+
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:
15
+ #
16
+ # require 'sqlite3'
17
+ #
18
+ # SQLite3::Database.new( "data.db" ) do |db|
19
+ # db.execute( "select * from table" ) do |row|
20
+ # p row
21
+ # end
22
+ # end
23
+ #
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.
26
+ #
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
30
+ # the database--insertions and updates are all still typeless.
31
+ #
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
+ #
86
+ class Database
87
+ attr_reader :collations
88
+
89
+ include Pragmas
90
+
91
+ class << self
92
+ # Without block works exactly as new.
93
+ # With block, like new closes the database at the end, but unlike new
94
+ # returns the result of the block instead of the database instance.
95
+ def open(*args)
96
+ database = new(*args)
97
+
98
+ if block_given?
99
+ begin
100
+ yield database
101
+ ensure
102
+ database.close
103
+ end
104
+ else
105
+ database
106
+ end
107
+ end
108
+
109
+ # Quotes the given string, making it safe to use in an SQL statement.
110
+ # It replaces all instances of the single-quote character with two
111
+ # single-quote characters. The modified string is returned.
112
+ def quote(string)
113
+ string.gsub("'", "''")
114
+ end
115
+ end
116
+
117
+ # A boolean that indicates whether rows in result sets should be returned
118
+ # as hashes or not. By default, rows are returned as arrays.
119
+ attr_accessor :results_as_hash
120
+
121
+ # call-seq:
122
+ # SQLite3::Database.new(file, options = {})
123
+ #
124
+ # Create a new Database object that opens the given file.
125
+ #
126
+ # Supported permissions +options+:
127
+ # - the default mode is <tt>READWRITE | CREATE</tt>
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.
131
+ #
132
+ # Supported encoding +options+:
133
+ # - +utf16:+ +boolish+ (default false), is the filename's encoding UTF-16 (only needed if the filename encoding is not UTF_16LE or BE)
134
+ #
135
+ # Other supported +options+:
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.
140
+ #
141
+ def initialize file, options = {}, zvfs = nil
142
+ mode = Constants::Open::READWRITE | Constants::Open::CREATE
143
+
144
+ file = file.to_path if file.respond_to? :to_path
145
+ if file.encoding == ::Encoding::UTF_16LE || file.encoding == ::Encoding::UTF_16BE || options[:utf16]
146
+ open16 file
147
+ else
148
+ # The three primary flag values for sqlite3_open_v2 are:
149
+ # SQLITE_OPEN_READONLY
150
+ # SQLITE_OPEN_READWRITE
151
+ # SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -- always used for sqlite3_open and sqlite3_open16
152
+ mode = Constants::Open::READONLY if options[:readonly]
153
+
154
+ if options[:readwrite]
155
+ raise "conflicting options: readonly and readwrite" if options[:readonly]
156
+ mode = Constants::Open::READWRITE
157
+ end
158
+
159
+ if options[:flags]
160
+ if options[:readonly] || options[:readwrite]
161
+ raise "conflicting options: flags with readonly and/or readwrite"
162
+ end
163
+ mode = options[:flags]
164
+ end
165
+
166
+ open_v2 file.encode("utf-8"), mode, zvfs
167
+
168
+ if options[:strict]
169
+ disable_quirk_mode
170
+ end
171
+ end
172
+
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
180
+ @default_transaction_mode = options[:default_transaction_mode] || :deferred
181
+
182
+ initialize_extensions(options[:extensions])
183
+
184
+ ForkSafety.track(self)
185
+
186
+ if block_given?
187
+ begin
188
+ yield self
189
+ ensure
190
+ close
191
+ end
192
+ end
193
+ end
194
+
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) }
200
+ end
201
+
202
+ # Installs (or removes) a block that will be invoked for every access
203
+ # to the database. If the block returns 0 (or +nil+), the statement
204
+ # is allowed to proceed. Returning 1 causes an authorization error to
205
+ # occur, and returning 2 causes the access to be silently denied.
206
+ def authorizer(&block)
207
+ self.authorizer = block
208
+ end
209
+
210
+ # Returns a Statement object representing the given SQL. This does not
211
+ # execute the statement; it merely prepares the statement for execution.
212
+ #
213
+ # The Statement can then be executed using Statement#execute.
214
+ #
215
+ def prepare sql
216
+ stmt = SQLite3::Statement.new(self, sql)
217
+ return stmt unless block_given?
218
+
219
+ begin
220
+ yield stmt
221
+ ensure
222
+ stmt.close unless stmt.closed?
223
+ end
224
+ end
225
+
226
+ # Returns the filename for the database named +db_name+. +db_name+ defaults
227
+ # to "main". Main return `nil` or an empty string if the database is
228
+ # temporary or in-memory.
229
+ def filename db_name = "main"
230
+ db_filename db_name
231
+ end
232
+
233
+ # Executes the given SQL statement. If additional parameters are given,
234
+ # they are treated as bind variables, and are bound to the placeholders in
235
+ # the query.
236
+ #
237
+ # Note that if any of the values passed to this are hashes, then the
238
+ # key/value pairs are each bound separately, with the key being used as
239
+ # the name of the placeholder to bind the value to.
240
+ #
241
+ # The block is optional. If given, it will be invoked for each row returned
242
+ # by the query. Otherwise, any results are accumulated into an array and
243
+ # returned wholesale.
244
+ #
245
+ # See also #execute2, #query, and #execute_batch for additional ways of
246
+ # executing statements.
247
+ def execute sql, bind_vars = [], &block
248
+ prepare(sql) do |stmt|
249
+ stmt.bind_params(bind_vars)
250
+ stmt = build_result_set stmt
251
+
252
+ if block
253
+ stmt.each do |row|
254
+ yield row
255
+ end
256
+ else
257
+ stmt.to_a.freeze
258
+ end
259
+ end
260
+ end
261
+
262
+ # Executes the given SQL statement, exactly as with #execute. However, the
263
+ # first row returned (either via the block, or in the returned array) is
264
+ # always the names of the columns. Subsequent rows correspond to the data
265
+ # from the result set.
266
+ #
267
+ # Thus, even if the query itself returns no rows, this method will always
268
+ # return at least one row--the names of the columns.
269
+ #
270
+ # See also #execute, #query, and #execute_batch for additional ways of
271
+ # executing statements.
272
+ def execute2(sql, *bind_vars)
273
+ prepare(sql) do |stmt|
274
+ result = stmt.execute(*bind_vars)
275
+ if block_given?
276
+ yield stmt.columns
277
+ result.each { |row| yield row }
278
+ else
279
+ return result.each_with_object([stmt.columns]) { |row, arr|
280
+ arr << row
281
+ }
282
+ end
283
+ end
284
+ end
285
+
286
+ # Executes all SQL statements in the given string. By contrast, the other
287
+ # means of executing queries will only execute the first statement in the
288
+ # string, ignoring all subsequent statements. This will execute each one
289
+ # in turn. The same bind parameters, if given, will be applied to each
290
+ # statement.
291
+ #
292
+ # This always returns the result of the last statement.
293
+ #
294
+ # See also #execute_batch2 for additional ways of
295
+ # executing statements.
296
+ def execute_batch(sql, bind_vars = [])
297
+ sql = sql.strip
298
+ result = nil
299
+ until sql.empty?
300
+ prepare(sql) do |stmt|
301
+ unless stmt.closed?
302
+ # FIXME: this should probably use sqlite3's api for batch execution
303
+ # This implementation requires stepping over the results.
304
+ if bind_vars.length == stmt.bind_parameter_count
305
+ stmt.bind_params(bind_vars)
306
+ end
307
+ result = stmt.step
308
+ end
309
+ sql = stmt.remainder.strip
310
+ end
311
+ end
312
+
313
+ result
314
+ end
315
+
316
+ # Executes all SQL statements in the given string. By contrast, the other
317
+ # means of executing queries will only execute the first statement in the
318
+ # string, ignoring all subsequent statements. This will execute each one
319
+ # in turn. Bind parameters cannot be passed to #execute_batch2.
320
+ #
321
+ # If a query is made, all values will be returned as strings.
322
+ # If no query is made, an empty array will be returned.
323
+ #
324
+ # Because all values except for 'NULL' are returned as strings,
325
+ # a block can be passed to parse the values accordingly.
326
+ #
327
+ # See also #execute_batch for additional ways of
328
+ # executing statements.
329
+ def execute_batch2(sql, &block)
330
+ if block
331
+ result = exec_batch(sql, @results_as_hash)
332
+ result.map do |val|
333
+ yield val
334
+ end
335
+ else
336
+ exec_batch(sql, @results_as_hash)
337
+ end
338
+ end
339
+
340
+ # This is a convenience method for creating a statement, binding
341
+ # parameters to it, and calling execute:
342
+ #
343
+ # result = db.query( "select * from foo where a=?", [5])
344
+ # # is the same as
345
+ # result = db.prepare( "select * from foo where a=?" ).execute( 5 )
346
+ #
347
+ # You must be sure to call +close+ on the ResultSet instance that is
348
+ # returned, or you could have problems with locks on the table. If called
349
+ # with a block, +close+ will be invoked implicitly when the block
350
+ # terminates.
351
+ def query(sql, bind_vars = [])
352
+ result = prepare(sql).execute(bind_vars)
353
+ if block_given?
354
+ begin
355
+ yield result
356
+ ensure
357
+ result.close
358
+ end
359
+ else
360
+ result
361
+ end
362
+ end
363
+
364
+ # A convenience method for obtaining the first row of a result set, and
365
+ # discarding all others. It is otherwise identical to #execute.
366
+ #
367
+ # See also #get_first_value.
368
+ def get_first_row(sql, *bind_vars)
369
+ execute(sql, *bind_vars).first
370
+ end
371
+
372
+ # A convenience method for obtaining the first value of the first row of a
373
+ # result set, and discarding all other values and rows. It is otherwise
374
+ # identical to #execute.
375
+ #
376
+ # See also #get_first_row.
377
+ def get_first_value(sql, *bind_vars)
378
+ query(sql, bind_vars) do |rs|
379
+ if (row = rs.next)
380
+ return @results_as_hash ? row[rs.columns[0]] : row[0]
381
+ end
382
+ end
383
+ nil
384
+ end
385
+
386
+ alias_method :busy_timeout, :busy_timeout=
387
+
388
+ # Creates a new function for use in SQL statements. It will be added as
389
+ # +name+, with the given +arity+. (For variable arity functions, use
390
+ # -1 for the arity.)
391
+ #
392
+ # The block should accept at least one parameter--the FunctionProxy
393
+ # instance that wraps this function invocation--and any other
394
+ # arguments it needs (up to its arity).
395
+ #
396
+ # The block does not return a value directly. Instead, it will invoke
397
+ # the FunctionProxy#result= method on the +func+ parameter and
398
+ # indicate the return value that way.
399
+ #
400
+ # Example:
401
+ #
402
+ # db.create_function( "maim", 1 ) do |func, value|
403
+ # if value.nil?
404
+ # func.result = nil
405
+ # else
406
+ # func.result = value.split(//).sort.join
407
+ # end
408
+ # end
409
+ #
410
+ # puts db.get_first_value( "select maim(name) from table" )
411
+ def create_function name, arity, text_rep = Constants::TextRep::UTF8, &block
412
+ define_function_with_flags(name, text_rep) do |*args|
413
+ fp = FunctionProxy.new
414
+ block.call(fp, *args)
415
+ fp.result
416
+ end
417
+ self
418
+ end
419
+
420
+ # Creates a new aggregate function for use in SQL statements. Aggregate
421
+ # functions are functions that apply over every row in the result set,
422
+ # instead of over just a single row. (A very common aggregate function
423
+ # is the "count" function, for determining the number of rows that match
424
+ # a query.)
425
+ #
426
+ # The new function will be added as +name+, with the given +arity+. (For
427
+ # variable arity functions, use -1 for the arity.)
428
+ #
429
+ # The +step+ parameter must be a proc object that accepts as its first
430
+ # parameter a FunctionProxy instance (representing the function
431
+ # invocation), with any subsequent parameters (up to the function's arity).
432
+ # The +step+ callback will be invoked once for each row of the result set.
433
+ #
434
+ # The +finalize+ parameter must be a +proc+ object that accepts only a
435
+ # single parameter, the FunctionProxy instance representing the current
436
+ # function invocation. It should invoke FunctionProxy#result= to
437
+ # store the result of the function.
438
+ #
439
+ # Example:
440
+ #
441
+ # db.create_aggregate( "lengths", 1 ) do
442
+ # step do |func, value|
443
+ # func[ :total ] ||= 0
444
+ # func[ :total ] += ( value ? value.length : 0 )
445
+ # end
446
+ #
447
+ # finalize do |func|
448
+ # func.result = func[ :total ] || 0
449
+ # end
450
+ # end
451
+ #
452
+ # puts db.get_first_value( "select lengths(name) from table" )
453
+ #
454
+ # See also #create_aggregate_handler for a more object-oriented approach to
455
+ # aggregate functions.
456
+ def create_aggregate(name, arity, step = nil, finalize = nil,
457
+ text_rep = Constants::TextRep::ANY, &block)
458
+
459
+ proxy = Class.new do
460
+ def self.step(&block)
461
+ define_method(:step_with_ctx, &block)
462
+ end
463
+
464
+ def self.finalize(&block)
465
+ define_method(:finalize_with_ctx, &block)
466
+ end
467
+ end
468
+
469
+ if block
470
+ proxy.instance_eval(&block)
471
+ else
472
+ proxy.class_eval do
473
+ define_method(:step_with_ctx, step)
474
+ define_method(:finalize_with_ctx, finalize)
475
+ end
476
+ end
477
+
478
+ proxy.class_eval do
479
+ # class instance variables
480
+ @name = name
481
+ @arity = arity
482
+
483
+ def self.name
484
+ @name
485
+ end
486
+
487
+ def self.arity
488
+ @arity
489
+ end
490
+
491
+ def initialize
492
+ @ctx = FunctionProxy.new
493
+ end
494
+
495
+ def step(*args)
496
+ step_with_ctx(@ctx, *args)
497
+ end
498
+
499
+ def finalize
500
+ finalize_with_ctx(@ctx)
501
+ @ctx.result
502
+ end
503
+ end
504
+ define_aggregator2(proxy, name)
505
+ end
506
+
507
+ # This is another approach to creating an aggregate function (see
508
+ # #create_aggregate). Instead of explicitly specifying the name,
509
+ # callbacks, arity, and type, you specify a factory object
510
+ # (the "handler") that knows how to obtain all of that information. The
511
+ # handler should respond to the following messages:
512
+ #
513
+ # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
514
+ # message is optional, and if the handler does not respond to it,
515
+ # the function will have an arity of -1.
516
+ # +name+:: this is the name of the function. The handler _must_ implement
517
+ # this message.
518
+ # +new+:: this must be implemented by the handler. It should return a new
519
+ # instance of the object that will handle a specific invocation of
520
+ # the function.
521
+ #
522
+ # The handler instance (the object returned by the +new+ message, described
523
+ # above), must respond to the following messages:
524
+ #
525
+ # +step+:: this is the method that will be called for each step of the
526
+ # aggregate function's evaluation. It should implement the same
527
+ # signature as the +step+ callback for #create_aggregate.
528
+ # +finalize+:: this is the method that will be called to finalize the
529
+ # aggregate function's evaluation. It should implement the
530
+ # same signature as the +finalize+ callback for
531
+ # #create_aggregate.
532
+ #
533
+ # Example:
534
+ #
535
+ # class LengthsAggregateHandler
536
+ # def self.arity; 1; end
537
+ # def self.name; 'lengths'; end
538
+ #
539
+ # def initialize
540
+ # @total = 0
541
+ # end
542
+ #
543
+ # def step( ctx, name )
544
+ # @total += ( name ? name.length : 0 )
545
+ # end
546
+ #
547
+ # def finalize( ctx )
548
+ # ctx.result = @total
549
+ # end
550
+ # end
551
+ #
552
+ # db.create_aggregate_handler( LengthsAggregateHandler )
553
+ # puts db.get_first_value( "select lengths(name) from A" )
554
+ def create_aggregate_handler(handler)
555
+ # This is a compatibility shim so the (basically pointless) FunctionProxy
556
+ # "ctx" object is passed as first argument to both step() and finalize().
557
+ # Now its up to the library user whether he prefers to store his
558
+ # temporaries as instance variables or fields in the FunctionProxy.
559
+ # The library user still must set the result value with
560
+ # FunctionProxy.result= as there is no backwards compatible way to
561
+ # change this.
562
+ proxy = Class.new(handler) do
563
+ def initialize
564
+ super
565
+ @fp = FunctionProxy.new
566
+ end
567
+
568
+ def step(*args)
569
+ super(@fp, *args)
570
+ end
571
+
572
+ def finalize
573
+ super(@fp)
574
+ @fp.result
575
+ end
576
+ end
577
+ define_aggregator2(proxy, proxy.name)
578
+ self
579
+ end
580
+
581
+ # Define an aggregate function named +name+ using a object template
582
+ # object +aggregator+. +aggregator+ must respond to +step+ and +finalize+.
583
+ # +step+ will be called with row information and +finalize+ must return the
584
+ # return value for the aggregator function.
585
+ #
586
+ # _API Change:_ +aggregator+ must also implement +clone+. The provided
587
+ # +aggregator+ object will serve as template that is cloned to provide the
588
+ # individual instances of the aggregate function. Regular ruby objects
589
+ # already provide a suitable +clone+.
590
+ # The functions arity is the arity of the +step+ method.
591
+ def define_aggregator(name, aggregator)
592
+ # Previously, this has been implemented in C. Now this is just yet
593
+ # another compatibility shim
594
+ proxy = Class.new do
595
+ @template = aggregator
596
+ @name = name
597
+
598
+ def self.template
599
+ @template
600
+ end
601
+
602
+ def self.name
603
+ @name
604
+ end
605
+
606
+ def self.arity
607
+ # this is what sqlite3_obj_method_arity did before
608
+ @template.method(:step).arity
609
+ end
610
+
611
+ def initialize
612
+ @klass = self.class.template.clone
613
+ end
614
+
615
+ def step(*args)
616
+ @klass.step(*args)
617
+ end
618
+
619
+ def finalize
620
+ @klass.finalize
621
+ end
622
+ end
623
+ define_aggregator2(proxy, name)
624
+ self
625
+ end
626
+
627
+ # Begins a new transaction. Note that nested transactions are not allowed
628
+ # by SQLite, so attempting to nest a transaction will result in a runtime
629
+ # exception.
630
+ #
631
+ # The +mode+ parameter may be either <tt>:deferred</tt>,
632
+ # <tt>:immediate</tt>, or <tt>:exclusive</tt>.
633
+ # If `nil` is specified, the default transaction mode, which was
634
+ # passed to #initialize, is used.
635
+ #
636
+ # If a block is given, the database instance is yielded to it, and the
637
+ # transaction is committed when the block terminates. If the block
638
+ # raises an exception, a rollback will be performed instead. Note that if
639
+ # a block is given, #commit and #rollback should never be called
640
+ # explicitly or you'll get an error when the block terminates.
641
+ #
642
+ # If a block is not given, it is the caller's responsibility to end the
643
+ # transaction explicitly, either by calling #commit, or by calling
644
+ # #rollback.
645
+ def transaction(mode = nil)
646
+ mode = @default_transaction_mode if mode.nil?
647
+ execute "begin #{mode} transaction"
648
+
649
+ if block_given?
650
+ abort = false
651
+ begin
652
+ yield self
653
+ rescue
654
+ abort = true
655
+ raise
656
+ ensure
657
+ abort and rollback or commit
658
+ end
659
+ else
660
+ true
661
+ end
662
+ end
663
+
664
+ # Commits the current transaction. If there is no current transaction,
665
+ # this will cause an error to be raised. This returns +true+, in order
666
+ # to allow it to be used in idioms like
667
+ # <tt>abort? and rollback or commit</tt>.
668
+ def commit
669
+ execute "commit transaction"
670
+ true
671
+ end
672
+
673
+ # Rolls the current transaction back. If there is no current transaction,
674
+ # this will cause an error to be raised. This returns +true+, in order
675
+ # to allow it to be used in idioms like
676
+ # <tt>abort? and rollback or commit</tt>.
677
+ def rollback
678
+ execute "rollback transaction"
679
+ true
680
+ end
681
+
682
+ # Returns +true+ if the database has been open in readonly mode
683
+ # A helper to check before performing any operation
684
+ def readonly?
685
+ @readonly
686
+ end
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
+
753
+ # A helper class for dealing with custom functions (see #create_function,
754
+ # #create_aggregate, and #create_aggregate_handler). It encapsulates the
755
+ # opaque function object that represents the current invocation. It also
756
+ # provides more convenient access to the API functions that operate on
757
+ # the function object.
758
+ #
759
+ # This class will almost _always_ be instantiated indirectly, by working
760
+ # with the create methods mentioned above.
761
+ class FunctionProxy
762
+ attr_accessor :result
763
+
764
+ # Create a new FunctionProxy that encapsulates the given +func+ object.
765
+ # If context is non-nil, the functions context will be set to that. If
766
+ # it is non-nil, it must quack like a Hash. If it is nil, then none of
767
+ # the context functions will be available.
768
+ def initialize
769
+ @result = nil
770
+ @context = {}
771
+ end
772
+
773
+ # Returns the value with the given key from the context. This is only
774
+ # available to aggregate functions.
775
+ def [](key)
776
+ @context[key]
777
+ end
778
+
779
+ # Sets the value with the given key in the context. This is only
780
+ # available to aggregate functions.
781
+ def []=(key, value)
782
+ @context[key] = value
783
+ end
784
+ end
785
+
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)
792
+ else
793
+ ResultSet.new(self, stmt)
794
+ end
795
+ end
796
+ end
797
+ end