sqlite3 1.5.0.rc1-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/API_CHANGES.md +49 -0
  4. data/CHANGELOG.md +419 -0
  5. data/CONTRIBUTING.md +24 -0
  6. data/ChangeLog.cvs +88 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +27 -0
  9. data/LICENSE-DEPENDENCIES +20 -0
  10. data/README.md +233 -0
  11. data/ext/sqlite3/aggregator.c +273 -0
  12. data/ext/sqlite3/aggregator.h +12 -0
  13. data/ext/sqlite3/backup.c +168 -0
  14. data/ext/sqlite3/backup.h +15 -0
  15. data/ext/sqlite3/database.c +853 -0
  16. data/ext/sqlite3/database.h +17 -0
  17. data/ext/sqlite3/exception.c +98 -0
  18. data/ext/sqlite3/exception.h +8 -0
  19. data/ext/sqlite3/extconf.rb +159 -0
  20. data/ext/sqlite3/sqlite3.c +163 -0
  21. data/ext/sqlite3/sqlite3_ruby.h +45 -0
  22. data/ext/sqlite3/statement.c +442 -0
  23. data/ext/sqlite3/statement.h +16 -0
  24. data/faq/faq.md +431 -0
  25. data/faq/faq.rb +145 -0
  26. data/faq/faq.yml +426 -0
  27. data/lib/sqlite3/2.6/sqlite3_native.bundle +0 -0
  28. data/lib/sqlite3/2.7/sqlite3_native.bundle +0 -0
  29. data/lib/sqlite3/3.0/sqlite3_native.bundle +0 -0
  30. data/lib/sqlite3/3.1/sqlite3_native.bundle +0 -0
  31. data/lib/sqlite3/constants.rb +50 -0
  32. data/lib/sqlite3/database.rb +741 -0
  33. data/lib/sqlite3/errors.rb +35 -0
  34. data/lib/sqlite3/pragmas.rb +595 -0
  35. data/lib/sqlite3/resultset.rb +187 -0
  36. data/lib/sqlite3/statement.rb +145 -0
  37. data/lib/sqlite3/translator.rb +118 -0
  38. data/lib/sqlite3/value.rb +57 -0
  39. data/lib/sqlite3/version.rb +25 -0
  40. data/lib/sqlite3.rb +15 -0
  41. data/test/helper.rb +27 -0
  42. data/test/test_backup.rb +33 -0
  43. data/test/test_collation.rb +82 -0
  44. data/test/test_database.rb +538 -0
  45. data/test/test_database_flags.rb +95 -0
  46. data/test/test_database_readonly.rb +36 -0
  47. data/test/test_database_readwrite.rb +41 -0
  48. data/test/test_deprecated.rb +44 -0
  49. data/test/test_encoding.rb +155 -0
  50. data/test/test_integration.rb +507 -0
  51. data/test/test_integration_aggregate.rb +336 -0
  52. data/test/test_integration_open_close.rb +30 -0
  53. data/test/test_integration_pending.rb +115 -0
  54. data/test/test_integration_resultset.rb +142 -0
  55. data/test/test_integration_statement.rb +194 -0
  56. data/test/test_result_set.rb +37 -0
  57. data/test/test_sqlite3.rb +25 -0
  58. data/test/test_statement.rb +263 -0
  59. data/test/test_statement_execute.rb +35 -0
  60. metadata +190 -0
@@ -0,0 +1,741 @@
1
+ require 'sqlite3/constants'
2
+ require 'sqlite3/errors'
3
+ require 'sqlite3/pragmas'
4
+ require 'sqlite3/statement'
5
+ require 'sqlite3/translator'
6
+ require 'sqlite3/value'
7
+
8
+ module SQLite3
9
+
10
+ # The Database class encapsulates a single connection to a SQLite3 database.
11
+ # Its usage is very straightforward:
12
+ #
13
+ # require 'sqlite3'
14
+ #
15
+ # SQLite3::Database.new( "data.db" ) do |db|
16
+ # db.execute( "select * from table" ) do |row|
17
+ # p row
18
+ # end
19
+ # end
20
+ #
21
+ # It wraps the lower-level methods provides by the selected driver, and
22
+ # includes the Pragmas module for access to various pragma convenience
23
+ # methods.
24
+ #
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
29
+ # the database--insertions and updates are all still typeless.
30
+ #
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.
35
+ class Database
36
+ attr_reader :collations
37
+
38
+ include Pragmas
39
+
40
+ class << self
41
+
42
+ alias :open :new
43
+
44
+ # Quotes the given string, making it safe to use in an SQL statement.
45
+ # It replaces all instances of the single-quote character with two
46
+ # single-quote characters. The modified string is returned.
47
+ def quote( string )
48
+ string.gsub( /'/, "''" )
49
+ end
50
+
51
+ end
52
+
53
+ # A boolean that indicates whether rows in result sets should be returned
54
+ # as hashes or not. By default, rows are returned as arrays.
55
+ attr_accessor :results_as_hash
56
+
57
+ # call-seq: SQLite3::Database.new(file, options = {})
58
+ #
59
+ # Create a new Database object that opens the given file. If utf16
60
+ # is +true+, the filename is interpreted as a UTF-16 encoded string.
61
+ #
62
+ # By default, the new database will return result rows as arrays
63
+ # (#results_as_hash) and has type translation disabled (#type_translation=).
64
+
65
+ def initialize file, options = {}, zvfs = nil
66
+ mode = Constants::Open::READWRITE | Constants::Open::CREATE
67
+
68
+ file = file.to_path if file.respond_to? :to_path
69
+ if file.encoding == ::Encoding::UTF_16LE || file.encoding == ::Encoding::UTF_16BE || options[:utf16]
70
+ open16 file
71
+ else
72
+ # The three primary flag values for sqlite3_open_v2 are:
73
+ # SQLITE_OPEN_READONLY
74
+ # SQLITE_OPEN_READWRITE
75
+ # SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -- always used for sqlite3_open and sqlite3_open16
76
+ mode = Constants::Open::READONLY if options[:readonly]
77
+
78
+ if options[:readwrite]
79
+ raise "conflicting options: readonly and readwrite" if options[:readonly]
80
+ mode = Constants::Open::READWRITE
81
+ end
82
+
83
+ if options[:flags]
84
+ if options[:readonly] || options[:readwrite]
85
+ raise "conflicting options: flags with readonly and/or readwrite"
86
+ end
87
+ mode = options[:flags]
88
+ end
89
+
90
+ open_v2 file.encode("utf-8"), mode, zvfs
91
+
92
+ if options[:strict]
93
+ disable_quirk_mode
94
+ end
95
+ end
96
+
97
+ @tracefunc = nil
98
+ @authorizer = nil
99
+ @encoding = nil
100
+ @busy_handler = nil
101
+ @collations = {}
102
+ @functions = {}
103
+ @results_as_hash = options[:results_as_hash]
104
+ @type_translation = options[:type_translation]
105
+ @type_translator = make_type_translator @type_translation
106
+ @readonly = mode & Constants::Open::READONLY != 0
107
+
108
+ if block_given?
109
+ begin
110
+ yield self
111
+ ensure
112
+ close
113
+ end
114
+ end
115
+ end
116
+
117
+ def type_translation= value # :nodoc:
118
+ warn(<<-eowarn) if $VERBOSE
119
+ #{caller[0]} is calling SQLite3::Database#type_translation=
120
+ SQLite3::Database#type_translation= is deprecated and will be removed
121
+ in version 2.0.0.
122
+ eowarn
123
+ @type_translator = make_type_translator value
124
+ @type_translation = value
125
+ end
126
+ attr_reader :type_translation # :nodoc:
127
+
128
+ # Return the type translator employed by this database instance. Each
129
+ # database instance has its own type translator; this allows for different
130
+ # type handlers to be installed in each instance without affecting other
131
+ # instances. Furthermore, the translators are instantiated lazily, so that
132
+ # if a database does not use type translation, it will not be burdened by
133
+ # the overhead of a useless type translator. (See the Translator class.)
134
+ def translator
135
+ @translator ||= Translator.new
136
+ end
137
+
138
+ # Installs (or removes) a block that will be invoked for every access
139
+ # to the database. If the block returns 0 (or +nil+), the statement
140
+ # is allowed to proceed. Returning 1 causes an authorization error to
141
+ # occur, and returning 2 causes the access to be silently denied.
142
+ def authorizer( &block )
143
+ self.authorizer = block
144
+ end
145
+
146
+ # Returns a Statement object representing the given SQL. This does not
147
+ # execute the statement; it merely prepares the statement for execution.
148
+ #
149
+ # The Statement can then be executed using Statement#execute.
150
+ #
151
+ def prepare sql
152
+ stmt = SQLite3::Statement.new( self, sql )
153
+ return stmt unless block_given?
154
+
155
+ begin
156
+ yield stmt
157
+ ensure
158
+ stmt.close unless stmt.closed?
159
+ end
160
+ end
161
+
162
+ # Returns the filename for the database named +db_name+. +db_name+ defaults
163
+ # to "main". Main return `nil` or an empty string if the database is
164
+ # temporary or in-memory.
165
+ def filename db_name = 'main'
166
+ db_filename db_name
167
+ end
168
+
169
+ # Executes the given SQL statement. If additional parameters are given,
170
+ # they are treated as bind variables, and are bound to the placeholders in
171
+ # the query.
172
+ #
173
+ # Note that if any of the values passed to this are hashes, then the
174
+ # key/value pairs are each bound separately, with the key being used as
175
+ # the name of the placeholder to bind the value to.
176
+ #
177
+ # The block is optional. If given, it will be invoked for each row returned
178
+ # by the query. Otherwise, any results are accumulated into an array and
179
+ # returned wholesale.
180
+ #
181
+ # See also #execute2, #query, and #execute_batch for additional ways of
182
+ # executing statements.
183
+ def execute sql, bind_vars = [], *args, &block
184
+ if bind_vars.nil? || !args.empty?
185
+ if args.empty?
186
+ bind_vars = []
187
+ else
188
+ bind_vars = [bind_vars] + args
189
+ end
190
+
191
+ warn(<<-eowarn) if $VERBOSE
192
+ #{caller[0]} is calling SQLite3::Database#execute with nil or multiple bind params
193
+ without using an array. Please switch to passing bind parameters as an array.
194
+ Support for bind parameters as *args will be removed in 2.0.0.
195
+ eowarn
196
+ end
197
+
198
+ prepare( sql ) do |stmt|
199
+ stmt.bind_params(bind_vars)
200
+ stmt = ResultSet.new self, stmt
201
+
202
+ if block_given?
203
+ stmt.each do |row|
204
+ yield row
205
+ end
206
+ else
207
+ stmt.to_a
208
+ end
209
+ end
210
+ end
211
+
212
+ # Executes the given SQL statement, exactly as with #execute. However, the
213
+ # first row returned (either via the block, or in the returned array) is
214
+ # always the names of the columns. Subsequent rows correspond to the data
215
+ # from the result set.
216
+ #
217
+ # Thus, even if the query itself returns no rows, this method will always
218
+ # return at least one row--the names of the columns.
219
+ #
220
+ # See also #execute, #query, and #execute_batch for additional ways of
221
+ # executing statements.
222
+ def execute2( sql, *bind_vars )
223
+ prepare( sql ) do |stmt|
224
+ result = stmt.execute( *bind_vars )
225
+ if block_given?
226
+ yield stmt.columns
227
+ result.each { |row| yield row }
228
+ else
229
+ return result.inject( [ stmt.columns ] ) { |arr,row|
230
+ arr << row; arr }
231
+ end
232
+ end
233
+ end
234
+
235
+ # Executes all SQL statements in the given string. By contrast, the other
236
+ # means of executing queries will only execute the first statement in the
237
+ # string, ignoring all subsequent statements. This will execute each one
238
+ # in turn. The same bind parameters, if given, will be applied to each
239
+ # statement.
240
+ #
241
+ # This always returns +nil+, making it unsuitable for queries that return
242
+ # rows.
243
+ #
244
+ # See also #execute_batch2 for additional ways of
245
+ # executing statements.
246
+ def execute_batch( sql, bind_vars = [], *args )
247
+ # FIXME: remove this stuff later
248
+ unless [Array, Hash].include?(bind_vars.class)
249
+ bind_vars = [bind_vars]
250
+ warn(<<-eowarn) if $VERBOSE
251
+ #{caller[0]} is calling SQLite3::Database#execute_batch with bind parameters
252
+ that are not a list of a hash. Please switch to passing bind parameters as an
253
+ array or hash. Support for this behavior will be removed in version 2.0.0.
254
+ eowarn
255
+ end
256
+
257
+ # FIXME: remove this stuff later
258
+ if bind_vars.nil? || !args.empty?
259
+ if args.empty?
260
+ bind_vars = []
261
+ else
262
+ bind_vars = [nil] + args
263
+ end
264
+
265
+ warn(<<-eowarn) if $VERBOSE
266
+ #{caller[0]} is calling SQLite3::Database#execute_batch with nil or multiple bind params
267
+ without using an array. Please switch to passing bind parameters as an array.
268
+ Support for this behavior will be removed in version 2.0.0.
269
+ eowarn
270
+ end
271
+
272
+ sql = sql.strip
273
+ until sql.empty? do
274
+ prepare( sql ) do |stmt|
275
+ unless stmt.closed?
276
+ # FIXME: this should probably use sqlite3's api for batch execution
277
+ # This implementation requires stepping over the results.
278
+ if bind_vars.length == stmt.bind_parameter_count
279
+ stmt.bind_params(bind_vars)
280
+ end
281
+ stmt.step
282
+ end
283
+ sql = stmt.remainder.strip
284
+ end
285
+ end
286
+ # FIXME: we should not return `nil` as a success return value
287
+ nil
288
+ end
289
+
290
+ # Executes all SQL statements in the given string. By contrast, the other
291
+ # means of executing queries will only execute the first statement in the
292
+ # string, ignoring all subsequent statements. This will execute each one
293
+ # in turn. Bind parameters cannot be passed to #execute_batch2.
294
+ #
295
+ # If a query is made, all values will be returned as strings.
296
+ # If no query is made, an empty array will be returned.
297
+ #
298
+ # Because all values except for 'NULL' are returned as strings,
299
+ # a block can be passed to parse the values accordingly.
300
+ #
301
+ # See also #execute_batch for additional ways of
302
+ # executing statements.
303
+ def execute_batch2(sql, &block)
304
+ if block_given?
305
+ result = exec_batch(sql, @results_as_hash)
306
+ result.map do |val|
307
+ yield val
308
+ end
309
+ else
310
+ exec_batch(sql, @results_as_hash)
311
+ end
312
+ end
313
+
314
+ # This is a convenience method for creating a statement, binding
315
+ # parameters to it, and calling execute:
316
+ #
317
+ # result = db.query( "select * from foo where a=?", [5])
318
+ # # is the same as
319
+ # result = db.prepare( "select * from foo where a=?" ).execute( 5 )
320
+ #
321
+ # You must be sure to call +close+ on the ResultSet instance that is
322
+ # returned, or you could have problems with locks on the table. If called
323
+ # with a block, +close+ will be invoked implicitly when the block
324
+ # terminates.
325
+ def query( sql, bind_vars = [], *args )
326
+
327
+ if bind_vars.nil? || !args.empty?
328
+ if args.empty?
329
+ bind_vars = []
330
+ else
331
+ bind_vars = [bind_vars] + args
332
+ end
333
+
334
+ warn(<<-eowarn) if $VERBOSE
335
+ #{caller[0]} is calling SQLite3::Database#query with nil or multiple bind params
336
+ without using an array. Please switch to passing bind parameters as an array.
337
+ Support for this will be removed in version 2.0.0.
338
+ eowarn
339
+ end
340
+
341
+ result = prepare( sql ).execute( bind_vars )
342
+ if block_given?
343
+ begin
344
+ yield result
345
+ ensure
346
+ result.close
347
+ end
348
+ else
349
+ return result
350
+ end
351
+ end
352
+
353
+ # A convenience method for obtaining the first row of a result set, and
354
+ # discarding all others. It is otherwise identical to #execute.
355
+ #
356
+ # See also #get_first_value.
357
+ def get_first_row( sql, *bind_vars )
358
+ execute( sql, *bind_vars ).first
359
+ end
360
+
361
+ # A convenience method for obtaining the first value of the first row of a
362
+ # result set, and discarding all other values and rows. It is otherwise
363
+ # identical to #execute.
364
+ #
365
+ # See also #get_first_row.
366
+ def get_first_value( sql, *bind_vars )
367
+ query( sql, bind_vars ) do |rs|
368
+ if (row = rs.next)
369
+ return @results_as_hash ? row[rs.columns[0]] : row[0]
370
+ end
371
+ end
372
+ nil
373
+ end
374
+
375
+ alias :busy_timeout :busy_timeout=
376
+
377
+ # Creates a new function for use in SQL statements. It will be added as
378
+ # +name+, with the given +arity+. (For variable arity functions, use
379
+ # -1 for the arity.)
380
+ #
381
+ # The block should accept at least one parameter--the FunctionProxy
382
+ # instance that wraps this function invocation--and any other
383
+ # arguments it needs (up to its arity).
384
+ #
385
+ # The block does not return a value directly. Instead, it will invoke
386
+ # the FunctionProxy#result= method on the +func+ parameter and
387
+ # indicate the return value that way.
388
+ #
389
+ # Example:
390
+ #
391
+ # db.create_function( "maim", 1 ) do |func, value|
392
+ # if value.nil?
393
+ # func.result = nil
394
+ # else
395
+ # func.result = value.split(//).sort.join
396
+ # end
397
+ # end
398
+ #
399
+ # puts db.get_first_value( "select maim(name) from table" )
400
+ def create_function name, arity, text_rep=Constants::TextRep::UTF8, &block
401
+ define_function_with_flags(name, text_rep) do |*args|
402
+ fp = FunctionProxy.new
403
+ block.call(fp, *args)
404
+ fp.result
405
+ end
406
+ self
407
+ end
408
+
409
+ # Creates a new aggregate function for use in SQL statements. Aggregate
410
+ # functions are functions that apply over every row in the result set,
411
+ # instead of over just a single row. (A very common aggregate function
412
+ # is the "count" function, for determining the number of rows that match
413
+ # a query.)
414
+ #
415
+ # The new function will be added as +name+, with the given +arity+. (For
416
+ # variable arity functions, use -1 for the arity.)
417
+ #
418
+ # The +step+ parameter must be a proc object that accepts as its first
419
+ # parameter a FunctionProxy instance (representing the function
420
+ # invocation), with any subsequent parameters (up to the function's arity).
421
+ # The +step+ callback will be invoked once for each row of the result set.
422
+ #
423
+ # The +finalize+ parameter must be a +proc+ object that accepts only a
424
+ # single parameter, the FunctionProxy instance representing the current
425
+ # function invocation. It should invoke FunctionProxy#result= to
426
+ # store the result of the function.
427
+ #
428
+ # Example:
429
+ #
430
+ # db.create_aggregate( "lengths", 1 ) do
431
+ # step do |func, value|
432
+ # func[ :total ] ||= 0
433
+ # func[ :total ] += ( value ? value.length : 0 )
434
+ # end
435
+ #
436
+ # finalize do |func|
437
+ # func.result = func[ :total ] || 0
438
+ # end
439
+ # end
440
+ #
441
+ # puts db.get_first_value( "select lengths(name) from table" )
442
+ #
443
+ # See also #create_aggregate_handler for a more object-oriented approach to
444
+ # aggregate functions.
445
+ def create_aggregate( name, arity, step=nil, finalize=nil,
446
+ text_rep=Constants::TextRep::ANY, &block )
447
+
448
+ proxy = Class.new do
449
+ def self.step( &block )
450
+ define_method(:step_with_ctx, &block)
451
+ end
452
+
453
+ def self.finalize( &block )
454
+ define_method(:finalize_with_ctx, &block)
455
+ end
456
+ end
457
+
458
+ if block_given?
459
+ proxy.instance_eval(&block)
460
+ else
461
+ proxy.class_eval do
462
+ define_method(:step_with_ctx, step)
463
+ define_method(:finalize_with_ctx, finalize)
464
+ end
465
+ end
466
+
467
+ proxy.class_eval do
468
+ # class instance variables
469
+ @name = name
470
+ @arity = arity
471
+
472
+ def self.name
473
+ @name
474
+ end
475
+
476
+ def self.arity
477
+ @arity
478
+ end
479
+
480
+ def initialize
481
+ @ctx = FunctionProxy.new
482
+ end
483
+
484
+ def step( *args )
485
+ step_with_ctx(@ctx, *args)
486
+ end
487
+
488
+ def finalize
489
+ finalize_with_ctx(@ctx)
490
+ @ctx.result
491
+ end
492
+ end
493
+ define_aggregator2(proxy, name)
494
+ end
495
+
496
+ # This is another approach to creating an aggregate function (see
497
+ # #create_aggregate). Instead of explicitly specifying the name,
498
+ # callbacks, arity, and type, you specify a factory object
499
+ # (the "handler") that knows how to obtain all of that information. The
500
+ # handler should respond to the following messages:
501
+ #
502
+ # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
503
+ # message is optional, and if the handler does not respond to it,
504
+ # the function will have an arity of -1.
505
+ # +name+:: this is the name of the function. The handler _must_ implement
506
+ # this message.
507
+ # +new+:: this must be implemented by the handler. It should return a new
508
+ # instance of the object that will handle a specific invocation of
509
+ # the function.
510
+ #
511
+ # The handler instance (the object returned by the +new+ message, described
512
+ # above), must respond to the following messages:
513
+ #
514
+ # +step+:: this is the method that will be called for each step of the
515
+ # aggregate function's evaluation. It should implement the same
516
+ # signature as the +step+ callback for #create_aggregate.
517
+ # +finalize+:: this is the method that will be called to finalize the
518
+ # aggregate function's evaluation. It should implement the
519
+ # same signature as the +finalize+ callback for
520
+ # #create_aggregate.
521
+ #
522
+ # Example:
523
+ #
524
+ # class LengthsAggregateHandler
525
+ # def self.arity; 1; end
526
+ # def self.name; 'lengths'; end
527
+ #
528
+ # def initialize
529
+ # @total = 0
530
+ # end
531
+ #
532
+ # def step( ctx, name )
533
+ # @total += ( name ? name.length : 0 )
534
+ # end
535
+ #
536
+ # def finalize( ctx )
537
+ # ctx.result = @total
538
+ # end
539
+ # end
540
+ #
541
+ # db.create_aggregate_handler( LengthsAggregateHandler )
542
+ # puts db.get_first_value( "select lengths(name) from A" )
543
+ def create_aggregate_handler( handler )
544
+ # This is a compatibility shim so the (basically pointless) FunctionProxy
545
+ # "ctx" object is passed as first argument to both step() and finalize().
546
+ # Now its up to the library user whether he prefers to store his
547
+ # temporaries as instance variables or fields in the FunctionProxy.
548
+ # The library user still must set the result value with
549
+ # FunctionProxy.result= as there is no backwards compatible way to
550
+ # change this.
551
+ proxy = Class.new(handler) do
552
+ def initialize
553
+ super
554
+ @fp = FunctionProxy.new
555
+ end
556
+
557
+ def step( *args )
558
+ super(@fp, *args)
559
+ end
560
+
561
+ def finalize
562
+ super(@fp)
563
+ @fp.result
564
+ end
565
+ end
566
+ define_aggregator2(proxy, proxy.name)
567
+ self
568
+ end
569
+
570
+ # Define an aggregate function named +name+ using a object template
571
+ # object +aggregator+. +aggregator+ must respond to +step+ and +finalize+.
572
+ # +step+ will be called with row information and +finalize+ must return the
573
+ # return value for the aggregator function.
574
+ #
575
+ # _API Change:_ +aggregator+ must also implement +clone+. The provided
576
+ # +aggregator+ object will serve as template that is cloned to provide the
577
+ # individual instances of the aggregate function. Regular ruby objects
578
+ # already provide a suitable +clone+.
579
+ # The functions arity is the arity of the +step+ method.
580
+ def define_aggregator( name, aggregator )
581
+ # Previously, this has been implemented in C. Now this is just yet
582
+ # another compatibility shim
583
+ proxy = Class.new do
584
+ @template = aggregator
585
+ @name = name
586
+
587
+ def self.template
588
+ @template
589
+ end
590
+
591
+ def self.name
592
+ @name
593
+ end
594
+
595
+ def self.arity
596
+ # this is what sqlite3_obj_method_arity did before
597
+ @template.method(:step).arity
598
+ end
599
+
600
+ def initialize
601
+ @klass = self.class.template.clone
602
+ end
603
+
604
+ def step(*args)
605
+ @klass.step(*args)
606
+ end
607
+
608
+ def finalize
609
+ @klass.finalize
610
+ end
611
+ end
612
+ define_aggregator2(proxy, name)
613
+ self
614
+ end
615
+
616
+ # Begins a new transaction. Note that nested transactions are not allowed
617
+ # by SQLite, so attempting to nest a transaction will result in a runtime
618
+ # exception.
619
+ #
620
+ # The +mode+ parameter may be either <tt>:deferred</tt> (the default),
621
+ # <tt>:immediate</tt>, or <tt>:exclusive</tt>.
622
+ #
623
+ # If a block is given, the database instance is yielded to it, and the
624
+ # transaction is committed when the block terminates. If the block
625
+ # raises an exception, a rollback will be performed instead. Note that if
626
+ # a block is given, #commit and #rollback should never be called
627
+ # explicitly or you'll get an error when the block terminates.
628
+ #
629
+ # If a block is not given, it is the caller's responsibility to end the
630
+ # transaction explicitly, either by calling #commit, or by calling
631
+ # #rollback.
632
+ def transaction( mode = :deferred )
633
+ execute "begin #{mode.to_s} transaction"
634
+
635
+ if block_given?
636
+ abort = false
637
+ begin
638
+ yield self
639
+ rescue
640
+ abort = true
641
+ raise
642
+ ensure
643
+ abort and rollback or commit
644
+ end
645
+ end
646
+
647
+ true
648
+ end
649
+
650
+ # Commits the current transaction. If there is no current transaction,
651
+ # this will cause an error to be raised. This returns +true+, in order
652
+ # to allow it to be used in idioms like
653
+ # <tt>abort? and rollback or commit</tt>.
654
+ def commit
655
+ execute "commit transaction"
656
+ true
657
+ end
658
+
659
+ # Rolls the current transaction back. If there is no current transaction,
660
+ # this will cause an error to be raised. This returns +true+, in order
661
+ # to allow it to be used in idioms like
662
+ # <tt>abort? and rollback or commit</tt>.
663
+ def rollback
664
+ execute "rollback transaction"
665
+ true
666
+ end
667
+
668
+ # Returns +true+ if the database has been open in readonly mode
669
+ # A helper to check before performing any operation
670
+ def readonly?
671
+ @readonly
672
+ end
673
+
674
+ # A helper class for dealing with custom functions (see #create_function,
675
+ # #create_aggregate, and #create_aggregate_handler). It encapsulates the
676
+ # opaque function object that represents the current invocation. It also
677
+ # provides more convenient access to the API functions that operate on
678
+ # the function object.
679
+ #
680
+ # This class will almost _always_ be instantiated indirectly, by working
681
+ # with the create methods mentioned above.
682
+ class FunctionProxy
683
+ attr_accessor :result
684
+
685
+ # Create a new FunctionProxy that encapsulates the given +func+ object.
686
+ # If context is non-nil, the functions context will be set to that. If
687
+ # it is non-nil, it must quack like a Hash. If it is nil, then none of
688
+ # the context functions will be available.
689
+ def initialize
690
+ @result = nil
691
+ @context = {}
692
+ end
693
+
694
+ # Set the result of the function to the given error message.
695
+ # The function will then return that error.
696
+ def set_error( error )
697
+ @driver.result_error( @func, error.to_s, -1 )
698
+ end
699
+
700
+ # (Only available to aggregate functions.) Returns the number of rows
701
+ # that the aggregate has processed so far. This will include the current
702
+ # row, and so will always return at least 1.
703
+ def count
704
+ @driver.aggregate_count( @func )
705
+ end
706
+
707
+ # Returns the value with the given key from the context. This is only
708
+ # available to aggregate functions.
709
+ def []( key )
710
+ @context[ key ]
711
+ end
712
+
713
+ # Sets the value with the given key in the context. This is only
714
+ # available to aggregate functions.
715
+ def []=( key, value )
716
+ @context[ key ] = value
717
+ end
718
+ end
719
+
720
+ # Translates a +row+ of data from the database with the given +types+
721
+ def translate_from_db types, row
722
+ @type_translator.call types, row
723
+ end
724
+
725
+ private
726
+
727
+ NULL_TRANSLATOR = lambda { |_, row| row }
728
+
729
+ def make_type_translator should_translate
730
+ if should_translate
731
+ lambda { |types, row|
732
+ types.zip(row).map do |type, value|
733
+ translator.translate( type, value )
734
+ end
735
+ }
736
+ else
737
+ NULL_TRANSLATOR
738
+ end
739
+ end
740
+ end
741
+ end