sqlite3 1.7.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +182 -1
  3. data/CONTRIBUTING.md +23 -1
  4. data/FAQ.md +0 -43
  5. data/INSTALLATION.md +15 -5
  6. data/LICENSE +18 -22
  7. data/README.md +75 -4
  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 +535 -482
  14. data/ext/sqlite3/database.h +7 -4
  15. data/ext/sqlite3/exception.c +111 -92
  16. data/ext/sqlite3/exception.h +3 -1
  17. data/ext/sqlite3/extconf.rb +21 -22
  18. data/ext/sqlite3/sqlite3.c +159 -115
  19. data/ext/sqlite3/sqlite3_ruby.h +2 -2
  20. data/ext/sqlite3/statement.c +516 -300
  21. data/ext/sqlite3/statement.h +3 -3
  22. data/ext/sqlite3/timespec.h +20 -0
  23. data/lib/sqlite3/constants.rb +171 -47
  24. data/lib/sqlite3/database.rb +106 -166
  25. data/lib/sqlite3/errors.rb +26 -1
  26. data/lib/sqlite3/pragmas.rb +126 -136
  27. data/lib/sqlite3/resultset.rb +14 -97
  28. data/lib/sqlite3/statement.rb +58 -13
  29. data/lib/sqlite3/value.rb +17 -20
  30. data/lib/sqlite3/version.rb +1 -21
  31. data/lib/sqlite3.rb +6 -4
  32. data/ports/archives/sqlite-autoconf-3460000.tar.gz +0 -0
  33. metadata +10 -35
  34. data/API_CHANGES.md +0 -49
  35. data/ChangeLog.cvs +0 -88
  36. data/Gemfile +0 -10
  37. data/LICENSE-DEPENDENCIES +0 -20
  38. data/lib/sqlite3/translator.rb +0 -117
  39. data/ports/archives/sqlite-autoconf-3450000.tar.gz +0 -0
  40. data/test/helper.rb +0 -27
  41. data/test/test_backup.rb +0 -33
  42. data/test/test_collation.rb +0 -82
  43. data/test/test_database.rb +0 -668
  44. data/test/test_database_flags.rb +0 -95
  45. data/test/test_database_readonly.rb +0 -36
  46. data/test/test_database_readwrite.rb +0 -41
  47. data/test/test_deprecated.rb +0 -49
  48. data/test/test_encoding.rb +0 -165
  49. data/test/test_integration.rb +0 -507
  50. data/test/test_integration_aggregate.rb +0 -336
  51. data/test/test_integration_open_close.rb +0 -30
  52. data/test/test_integration_pending.rb +0 -115
  53. data/test/test_integration_resultset.rb +0 -142
  54. data/test/test_integration_statement.rb +0 -194
  55. data/test/test_pragmas.rb +0 -22
  56. data/test/test_result_set.rb +0 -47
  57. data/test/test_sqlite3.rb +0 -30
  58. data/test/test_statement.rb +0 -290
  59. data/test/test_statement_execute.rb +0 -39
@@ -1,12 +1,10 @@
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
+ require "sqlite3/constants"
2
+ require "sqlite3/errors"
3
+ require "sqlite3/pragmas"
4
+ require "sqlite3/statement"
5
+ require "sqlite3/value"
7
6
 
8
7
  module SQLite3
9
-
10
8
  # The Database class encapsulates a single connection to a SQLite3 database.
11
9
  # Its usage is very straightforward:
12
10
  #
@@ -32,17 +30,24 @@ module SQLite3
32
30
  # ArrayFields module from Ara Howard. If you require the ArrayFields
33
31
  # module before performing a query, and if you have not enabled results as
34
32
  # hashes, then the results will all be indexible by field name.
33
+ #
34
+ # Thread safety:
35
+ #
36
+ # When `SQLite3.threadsafe?` returns true, it is safe to share instances of
37
+ # the database class among threads without adding specific locking. Other
38
+ # object instances may require applications to provide their own locks if
39
+ # they are to be shared among threads. Please see the README.md for more
40
+ # information.
35
41
  class Database
36
42
  attr_reader :collations
37
43
 
38
44
  include Pragmas
39
45
 
40
46
  class << self
41
-
42
47
  # Without block works exactly as new.
43
48
  # With block, like new closes the database at the end, but unlike new
44
49
  # returns the result of the block instead of the database instance.
45
- def open( *args )
50
+ def open(*args)
46
51
  database = new(*args)
47
52
 
48
53
  if block_given?
@@ -59,10 +64,9 @@ module SQLite3
59
64
  # Quotes the given string, making it safe to use in an SQL statement.
60
65
  # It replaces all instances of the single-quote character with two
61
66
  # single-quote characters. The modified string is returned.
62
- def quote( string )
63
- string.gsub( /'/, "''" )
67
+ def quote(string)
68
+ string.gsub("'", "''")
64
69
  end
65
-
66
70
  end
67
71
 
68
72
  # A boolean that indicates whether rows in result sets should be returned
@@ -85,7 +89,6 @@ module SQLite3
85
89
  # Other supported +options+:
86
90
  # - +: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
91
  # - +:results_as_hash+: boolean (default false), return rows as hashes instead of arrays
88
- # - +:type_translation+: boolean (default false), enable type translation
89
92
  # - +: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.
90
93
  #
91
94
  def initialize file, options = {}, zvfs = nil
@@ -120,16 +123,14 @@ module SQLite3
120
123
  end
121
124
  end
122
125
 
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
126
+ @tracefunc = nil
127
+ @authorizer = nil
128
+ @busy_handler = nil
129
+ @progress_handler = nil
130
+ @collations = {}
131
+ @functions = {}
132
+ @results_as_hash = options[:results_as_hash]
133
+ @readonly = mode & Constants::Open::READONLY != 0
133
134
  @default_transaction_mode = options[:default_transaction_mode] || :deferred
134
135
 
135
136
  if block_given?
@@ -141,30 +142,18 @@ module SQLite3
141
142
  end
142
143
  end
143
144
 
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
145
+ # call-seq: db.encoding
146
+ #
147
+ # Fetch the encoding set on this database
148
+ def encoding
149
+ prepare("PRAGMA encoding") { |stmt| Encoding.find(stmt.first.first) }
161
150
  end
162
151
 
163
152
  # Installs (or removes) a block that will be invoked for every access
164
153
  # to the database. If the block returns 0 (or +nil+), the statement
165
154
  # is allowed to proceed. Returning 1 causes an authorization error to
166
155
  # occur, and returning 2 causes the access to be silently denied.
167
- def authorizer( &block )
156
+ def authorizer(&block)
168
157
  self.authorizer = block
169
158
  end
170
159
 
@@ -174,7 +163,7 @@ module SQLite3
174
163
  # The Statement can then be executed using Statement#execute.
175
164
  #
176
165
  def prepare sql
177
- stmt = SQLite3::Statement.new( self, sql )
166
+ stmt = SQLite3::Statement.new(self, sql)
178
167
  return stmt unless block_given?
179
168
 
180
169
  begin
@@ -187,7 +176,7 @@ module SQLite3
187
176
  # Returns the filename for the database named +db_name+. +db_name+ defaults
188
177
  # to "main". Main return `nil` or an empty string if the database is
189
178
  # temporary or in-memory.
190
- def filename db_name = 'main'
179
+ def filename db_name = "main"
191
180
  db_filename db_name
192
181
  end
193
182
 
@@ -205,29 +194,17 @@ module SQLite3
205
194
  #
206
195
  # See also #execute2, #query, and #execute_batch for additional ways of
207
196
  # 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|
197
+ def execute sql, bind_vars = [], &block
198
+ prepare(sql) do |stmt|
222
199
  stmt.bind_params(bind_vars)
223
- stmt = ResultSet.new self, stmt
200
+ stmt = build_result_set stmt
224
201
 
225
- if block_given?
202
+ if block
226
203
  stmt.each do |row|
227
204
  yield row
228
205
  end
229
206
  else
230
- stmt.to_a
207
+ stmt.to_a.freeze
231
208
  end
232
209
  end
233
210
  end
@@ -242,15 +219,16 @@ module SQLite3
242
219
  #
243
220
  # See also #execute, #query, and #execute_batch for additional ways of
244
221
  # executing statements.
245
- def execute2( sql, *bind_vars )
246
- prepare( sql ) do |stmt|
247
- result = stmt.execute( *bind_vars )
222
+ def execute2(sql, *bind_vars)
223
+ prepare(sql) do |stmt|
224
+ result = stmt.execute(*bind_vars)
248
225
  if block_given?
249
226
  yield stmt.columns
250
227
  result.each { |row| yield row }
251
228
  else
252
- return result.inject( [ stmt.columns ] ) { |arr,row|
253
- arr << row; arr }
229
+ return result.each_with_object([stmt.columns]) { |row, arr|
230
+ arr << row
231
+ }
254
232
  end
255
233
  end
256
234
  end
@@ -261,49 +239,28 @@ module SQLite3
261
239
  # in turn. The same bind parameters, if given, will be applied to each
262
240
  # statement.
263
241
  #
264
- # This always returns +nil+, making it unsuitable for queries that return
265
- # rows.
242
+ # This always returns the result of the last statement.
266
243
  #
267
244
  # See also #execute_batch2 for additional ways of
268
245
  # 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
-
246
+ def execute_batch(sql, bind_vars = [])
291
247
  sql = sql.strip
292
- until sql.empty? do
293
- prepare( sql ) do |stmt|
248
+ result = nil
249
+ until sql.empty?
250
+ prepare(sql) do |stmt|
294
251
  unless stmt.closed?
295
252
  # FIXME: this should probably use sqlite3's api for batch execution
296
253
  # This implementation requires stepping over the results.
297
254
  if bind_vars.length == stmt.bind_parameter_count
298
255
  stmt.bind_params(bind_vars)
299
256
  end
300
- stmt.step
257
+ result = stmt.step
301
258
  end
302
259
  sql = stmt.remainder.strip
303
260
  end
304
261
  end
305
- # FIXME: we should not return `nil` as a success return value
306
- nil
262
+
263
+ result
307
264
  end
308
265
 
309
266
  # Executes all SQL statements in the given string. By contrast, the other
@@ -320,7 +277,7 @@ module SQLite3
320
277
  # See also #execute_batch for additional ways of
321
278
  # executing statements.
322
279
  def execute_batch2(sql, &block)
323
- if block_given?
280
+ if block
324
281
  result = exec_batch(sql, @results_as_hash)
325
282
  result.map do |val|
326
283
  yield val
@@ -341,21 +298,8 @@ module SQLite3
341
298
  # returned, or you could have problems with locks on the table. If called
342
299
  # with a block, +close+ will be invoked implicitly when the block
343
300
  # 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 )
301
+ def query(sql, bind_vars = [])
302
+ result = prepare(sql).execute(bind_vars)
359
303
  if block_given?
360
304
  begin
361
305
  yield result
@@ -363,7 +307,7 @@ module SQLite3
363
307
  result.close
364
308
  end
365
309
  else
366
- return result
310
+ result
367
311
  end
368
312
  end
369
313
 
@@ -371,8 +315,8 @@ module SQLite3
371
315
  # discarding all others. It is otherwise identical to #execute.
372
316
  #
373
317
  # See also #get_first_value.
374
- def get_first_row( sql, *bind_vars )
375
- execute( sql, *bind_vars ).first
318
+ def get_first_row(sql, *bind_vars)
319
+ execute(sql, *bind_vars).first
376
320
  end
377
321
 
378
322
  # A convenience method for obtaining the first value of the first row of a
@@ -380,8 +324,8 @@ module SQLite3
380
324
  # identical to #execute.
381
325
  #
382
326
  # See also #get_first_row.
383
- def get_first_value( sql, *bind_vars )
384
- query( sql, bind_vars ) do |rs|
327
+ def get_first_value(sql, *bind_vars)
328
+ query(sql, bind_vars) do |rs|
385
329
  if (row = rs.next)
386
330
  return @results_as_hash ? row[rs.columns[0]] : row[0]
387
331
  end
@@ -389,7 +333,7 @@ module SQLite3
389
333
  nil
390
334
  end
391
335
 
392
- alias :busy_timeout :busy_timeout=
336
+ alias_method :busy_timeout, :busy_timeout=
393
337
 
394
338
  # Creates a new function for use in SQL statements. It will be added as
395
339
  # +name+, with the given +arity+. (For variable arity functions, use
@@ -414,7 +358,7 @@ module SQLite3
414
358
  # end
415
359
  #
416
360
  # puts db.get_first_value( "select maim(name) from table" )
417
- def create_function name, arity, text_rep=Constants::TextRep::UTF8, &block
361
+ def create_function name, arity, text_rep = Constants::TextRep::UTF8, &block
418
362
  define_function_with_flags(name, text_rep) do |*args|
419
363
  fp = FunctionProxy.new
420
364
  block.call(fp, *args)
@@ -459,20 +403,20 @@ module SQLite3
459
403
  #
460
404
  # See also #create_aggregate_handler for a more object-oriented approach to
461
405
  # aggregate functions.
462
- def create_aggregate( name, arity, step=nil, finalize=nil,
463
- text_rep=Constants::TextRep::ANY, &block )
406
+ def create_aggregate(name, arity, step = nil, finalize = nil,
407
+ text_rep = Constants::TextRep::ANY, &block)
464
408
 
465
409
  proxy = Class.new do
466
- def self.step( &block )
410
+ def self.step(&block)
467
411
  define_method(:step_with_ctx, &block)
468
412
  end
469
413
 
470
- def self.finalize( &block )
414
+ def self.finalize(&block)
471
415
  define_method(:finalize_with_ctx, &block)
472
416
  end
473
417
  end
474
418
 
475
- if block_given?
419
+ if block
476
420
  proxy.instance_eval(&block)
477
421
  else
478
422
  proxy.class_eval do
@@ -498,7 +442,7 @@ module SQLite3
498
442
  @ctx = FunctionProxy.new
499
443
  end
500
444
 
501
- def step( *args )
445
+ def step(*args)
502
446
  step_with_ctx(@ctx, *args)
503
447
  end
504
448
 
@@ -557,7 +501,7 @@ module SQLite3
557
501
  #
558
502
  # db.create_aggregate_handler( LengthsAggregateHandler )
559
503
  # puts db.get_first_value( "select lengths(name) from A" )
560
- def create_aggregate_handler( handler )
504
+ def create_aggregate_handler(handler)
561
505
  # This is a compatibility shim so the (basically pointless) FunctionProxy
562
506
  # "ctx" object is passed as first argument to both step() and finalize().
563
507
  # Now its up to the library user whether he prefers to store his
@@ -571,7 +515,7 @@ module SQLite3
571
515
  @fp = FunctionProxy.new
572
516
  end
573
517
 
574
- def step( *args )
518
+ def step(*args)
575
519
  super(@fp, *args)
576
520
  end
577
521
 
@@ -594,7 +538,7 @@ module SQLite3
594
538
  # individual instances of the aggregate function. Regular ruby objects
595
539
  # already provide a suitable +clone+.
596
540
  # The functions arity is the arity of the +step+ method.
597
- def define_aggregator( name, aggregator )
541
+ def define_aggregator(name, aggregator)
598
542
  # Previously, this has been implemented in C. Now this is just yet
599
543
  # another compatibility shim
600
544
  proxy = Class.new do
@@ -648,9 +592,9 @@ module SQLite3
648
592
  # If a block is not given, it is the caller's responsibility to end the
649
593
  # transaction explicitly, either by calling #commit, or by calling
650
594
  # #rollback.
651
- def transaction( mode = nil )
595
+ def transaction(mode = nil)
652
596
  mode = @default_transaction_mode if mode.nil?
653
- execute "begin #{mode.to_s} transaction"
597
+ execute "begin #{mode} transaction"
654
598
 
655
599
  if block_given?
656
600
  abort = false
@@ -662,9 +606,9 @@ module SQLite3
662
606
  ensure
663
607
  abort and rollback or commit
664
608
  end
609
+ else
610
+ true
665
611
  end
666
-
667
- true
668
612
  end
669
613
 
670
614
  # Commits the current transaction. If there is no current transaction,
@@ -691,6 +635,25 @@ module SQLite3
691
635
  @readonly
692
636
  end
693
637
 
638
+ # Sets a #busy_handler that releases the GVL between retries,
639
+ # but only retries up to the indicated number of +milliseconds+.
640
+ # This is an alternative to #busy_timeout, which holds the GVL
641
+ # while SQLite sleeps and retries.
642
+ def busy_handler_timeout=(milliseconds)
643
+ timeout_seconds = milliseconds.fdiv(1000)
644
+
645
+ busy_handler do |count|
646
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
647
+ if count.zero?
648
+ @timeout_deadline = now + timeout_seconds
649
+ elsif now > @timeout_deadline
650
+ next false
651
+ else
652
+ sleep(0.001)
653
+ end
654
+ end
655
+ end
656
+
694
657
  # A helper class for dealing with custom functions (see #create_function,
695
658
  # #create_aggregate, and #create_aggregate_handler). It encapsulates the
696
659
  # opaque function object that represents the current invocation. It also
@@ -707,54 +670,31 @@ module SQLite3
707
670
  # it is non-nil, it must quack like a Hash. If it is nil, then none of
708
671
  # the context functions will be available.
709
672
  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 )
673
+ @result = nil
674
+ @context = {}
725
675
  end
726
676
 
727
677
  # Returns the value with the given key from the context. This is only
728
678
  # available to aggregate functions.
729
- def []( key )
730
- @context[ key ]
679
+ def [](key)
680
+ @context[key]
731
681
  end
732
682
 
733
683
  # Sets the value with the given key in the context. This is only
734
684
  # available to aggregate functions.
735
- def []=( key, value )
736
- @context[ key ] = value
685
+ def []=(key, value)
686
+ @context[key] = value
737
687
  end
738
688
  end
739
689
 
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
- }
690
+ # Given a statement, return a result set.
691
+ # This is not intended for general consumption
692
+ # :nodoc:
693
+ def build_result_set stmt
694
+ if results_as_hash
695
+ HashResultSet.new(self, stmt)
756
696
  else
757
- NULL_TRANSLATOR
697
+ ResultSet.new(self, stmt)
758
698
  end
759
699
  end
760
700
  end
@@ -1,4 +1,4 @@
1
- require 'sqlite3/constants'
1
+ require "sqlite3/constants"
2
2
 
3
3
  module SQLite3
4
4
  class Exception < ::StandardError
@@ -7,29 +7,54 @@ module SQLite3
7
7
  end
8
8
 
9
9
  class SQLException < Exception; end
10
+
10
11
  class InternalException < Exception; end
12
+
11
13
  class PermissionException < Exception; end
14
+
12
15
  class AbortException < Exception; end
16
+
13
17
  class BusyException < Exception; end
18
+
14
19
  class LockedException < Exception; end
20
+
15
21
  class MemoryException < Exception; end
22
+
16
23
  class ReadOnlyException < Exception; end
24
+
17
25
  class InterruptException < Exception; end
26
+
18
27
  class IOException < Exception; end
28
+
19
29
  class CorruptException < Exception; end
30
+
20
31
  class NotFoundException < Exception; end
32
+
21
33
  class FullException < Exception; end
34
+
22
35
  class CantOpenException < Exception; end
36
+
23
37
  class ProtocolException < Exception; end
38
+
24
39
  class EmptyException < Exception; end
40
+
25
41
  class SchemaChangedException < Exception; end
42
+
26
43
  class TooBigException < Exception; end
44
+
27
45
  class ConstraintException < Exception; end
46
+
28
47
  class MismatchException < Exception; end
48
+
29
49
  class MisuseException < Exception; end
50
+
30
51
  class UnsupportedException < Exception; end
52
+
31
53
  class AuthorizationException < Exception; end
54
+
32
55
  class FormatException < Exception; end
56
+
33
57
  class RangeException < Exception; end
58
+
34
59
  class NotADatabaseException < Exception; end
35
60
  end