sqlite3 1.5.0-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sqlite3 might be problematic. Click here for more details.

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 +425 -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 +274 -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 +252 -0
  20. data/ext/sqlite3/sqlite3.c +163 -0
  21. data/ext/sqlite3/sqlite3_ruby.h +48 -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.so +0 -0
  28. data/lib/sqlite3/2.7/sqlite3_native.so +0 -0
  29. data/lib/sqlite3/3.0/sqlite3_native.so +0 -0
  30. data/lib/sqlite3/3.1/sqlite3_native.so +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 +23 -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 +545 -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 +30 -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,187 @@
1
+ require 'sqlite3/constants'
2
+ require 'sqlite3/errors'
3
+
4
+ module SQLite3
5
+
6
+ # The ResultSet object encapsulates the enumerability of a query's output.
7
+ # It is a simple cursor over the data that the query returns. It will
8
+ # very rarely (if ever) be instantiated directly. Instead, clients should
9
+ # obtain a ResultSet instance via Statement#execute.
10
+ class ResultSet
11
+ include Enumerable
12
+
13
+ class ArrayWithTypes < Array # :nodoc:
14
+ attr_accessor :types
15
+ end
16
+
17
+ class ArrayWithTypesAndFields < Array # :nodoc:
18
+ attr_writer :types
19
+ attr_writer :fields
20
+
21
+ def types
22
+ warn(<<-eowarn) if $VERBOSE
23
+ #{caller[0]} is calling #{self.class}#types. This method will be removed in
24
+ sqlite3 version 2.0.0, please call the `types` method on the SQLite3::ResultSet
25
+ object that created this object
26
+ eowarn
27
+ @types
28
+ end
29
+
30
+ def fields
31
+ warn(<<-eowarn) if $VERBOSE
32
+ #{caller[0]} is calling #{self.class}#fields. This method will be removed in
33
+ sqlite3 version 2.0.0, please call the `columns` method on the SQLite3::ResultSet
34
+ object that created this object
35
+ eowarn
36
+ @fields
37
+ end
38
+ end
39
+
40
+ # The class of which we return an object in case we want a Hash as
41
+ # result.
42
+ class HashWithTypesAndFields < Hash # :nodoc:
43
+ attr_writer :types
44
+ attr_writer :fields
45
+
46
+ def types
47
+ warn(<<-eowarn) if $VERBOSE
48
+ #{caller[0]} is calling #{self.class}#types. This method will be removed in
49
+ sqlite3 version 2.0.0, please call the `types` method on the SQLite3::ResultSet
50
+ object that created this object
51
+ eowarn
52
+ @types
53
+ end
54
+
55
+ def fields
56
+ warn(<<-eowarn) if $VERBOSE
57
+ #{caller[0]} is calling #{self.class}#fields. This method will be removed in
58
+ sqlite3 version 2.0.0, please call the `columns` method on the SQLite3::ResultSet
59
+ object that created this object
60
+ eowarn
61
+ @fields
62
+ end
63
+
64
+ def [] key
65
+ key = fields[key] if key.is_a? Numeric
66
+ super key
67
+ end
68
+ end
69
+
70
+ # Create a new ResultSet attached to the given database, using the
71
+ # given sql text.
72
+ def initialize db, stmt
73
+ @db = db
74
+ @stmt = stmt
75
+ end
76
+
77
+ # Reset the cursor, so that a result set which has reached end-of-file
78
+ # can be rewound and reiterated.
79
+ def reset( *bind_params )
80
+ @stmt.reset!
81
+ @stmt.bind_params( *bind_params )
82
+ @eof = false
83
+ end
84
+
85
+ # Query whether the cursor has reached the end of the result set or not.
86
+ def eof?
87
+ @stmt.done?
88
+ end
89
+
90
+ # Obtain the next row from the cursor. If there are no more rows to be
91
+ # had, this will return +nil+. If type translation is active on the
92
+ # corresponding database, the values in the row will be translated
93
+ # according to their types.
94
+ #
95
+ # The returned value will be an array, unless Database#results_as_hash has
96
+ # been set to +true+, in which case the returned value will be a hash.
97
+ #
98
+ # For arrays, the column names are accessible via the +fields+ property,
99
+ # and the column types are accessible via the +types+ property.
100
+ #
101
+ # For hashes, the column names are the keys of the hash, and the column
102
+ # types are accessible via the +types+ property.
103
+ def next
104
+ if @db.results_as_hash
105
+ return next_hash
106
+ end
107
+
108
+ row = @stmt.step
109
+ return nil if @stmt.done?
110
+
111
+ row = @db.translate_from_db @stmt.types, row
112
+
113
+ if row.respond_to?(:fields)
114
+ # FIXME: this can only happen if the translator returns something
115
+ # that responds to `fields`. Since we're removing the translator
116
+ # in 2.0, we can remove this branch in 2.0.
117
+ row = ArrayWithTypes.new(row)
118
+ else
119
+ # FIXME: the `fields` and `types` methods are deprecated on this
120
+ # object for version 2.0, so we can safely remove this branch
121
+ # as well.
122
+ row = ArrayWithTypesAndFields.new(row)
123
+ end
124
+
125
+ row.fields = @stmt.columns
126
+ row.types = @stmt.types
127
+ row
128
+ end
129
+
130
+ # Required by the Enumerable mixin. Provides an internal iterator over the
131
+ # rows of the result set.
132
+ def each
133
+ while node = self.next
134
+ yield node
135
+ end
136
+ end
137
+
138
+ # Provides an internal iterator over the rows of the result set where
139
+ # each row is yielded as a hash.
140
+ def each_hash
141
+ while node = next_hash
142
+ yield node
143
+ end
144
+ end
145
+
146
+ # Closes the statement that spawned this result set.
147
+ # <em>Use with caution!</em> Closing a result set will automatically
148
+ # close any other result sets that were spawned from the same statement.
149
+ def close
150
+ @stmt.close
151
+ end
152
+
153
+ # Queries whether the underlying statement has been closed or not.
154
+ def closed?
155
+ @stmt.closed?
156
+ end
157
+
158
+ # Returns the types of the columns returned by this result set.
159
+ def types
160
+ @stmt.types
161
+ end
162
+
163
+ # Returns the names of the columns returned by this result set.
164
+ def columns
165
+ @stmt.columns
166
+ end
167
+
168
+ # Return the next row as a hash
169
+ def next_hash
170
+ row = @stmt.step
171
+ return nil if @stmt.done?
172
+
173
+ # FIXME: type translation is deprecated, so this can be removed
174
+ # in 2.0
175
+ row = @db.translate_from_db @stmt.types, row
176
+
177
+ # FIXME: this can be switched to a regular hash in 2.0
178
+ row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]
179
+
180
+ # FIXME: these methods are deprecated for version 2.0, so we can remove
181
+ # this code in 2.0
182
+ row.fields = @stmt.columns
183
+ row.types = @stmt.types
184
+ row
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,145 @@
1
+ require 'sqlite3/errors'
2
+ require 'sqlite3/resultset'
3
+
4
+ class String
5
+ def to_blob
6
+ SQLite3::Blob.new( self )
7
+ end
8
+ end
9
+
10
+ module SQLite3
11
+ # A statement represents a prepared-but-unexecuted SQL query. It will rarely
12
+ # (if ever) be instantiated directly by a client, and is most often obtained
13
+ # via the Database#prepare method.
14
+ class Statement
15
+ include Enumerable
16
+
17
+ # This is any text that followed the first valid SQL statement in the text
18
+ # with which the statement was initialized. If there was no trailing text,
19
+ # this will be the empty string.
20
+ attr_reader :remainder
21
+
22
+ # Binds the given variables to the corresponding placeholders in the SQL
23
+ # text.
24
+ #
25
+ # See Database#execute for a description of the valid placeholder
26
+ # syntaxes.
27
+ #
28
+ # Example:
29
+ #
30
+ # stmt = db.prepare( "select * from table where a=? and b=?" )
31
+ # stmt.bind_params( 15, "hello" )
32
+ #
33
+ # See also #execute, #bind_param, Statement#bind_param, and
34
+ # Statement#bind_params.
35
+ def bind_params( *bind_vars )
36
+ index = 1
37
+ bind_vars.flatten.each do |var|
38
+ if Hash === var
39
+ var.each { |key, val| bind_param key, val }
40
+ else
41
+ bind_param index, var
42
+ index += 1
43
+ end
44
+ end
45
+ end
46
+
47
+ # Execute the statement. This creates a new ResultSet object for the
48
+ # statement's virtual machine. If a block was given, the new ResultSet will
49
+ # be yielded to it; otherwise, the ResultSet will be returned.
50
+ #
51
+ # Any parameters will be bound to the statement using #bind_params.
52
+ #
53
+ # Example:
54
+ #
55
+ # stmt = db.prepare( "select * from table" )
56
+ # stmt.execute do |result|
57
+ # ...
58
+ # end
59
+ #
60
+ # See also #bind_params, #execute!.
61
+ def execute( *bind_vars )
62
+ reset! if active? || done?
63
+
64
+ bind_params(*bind_vars) unless bind_vars.empty?
65
+ @results = ResultSet.new(@connection, self)
66
+
67
+ step if 0 == column_count
68
+
69
+ yield @results if block_given?
70
+ @results
71
+ end
72
+
73
+ # Execute the statement. If no block was given, this returns an array of
74
+ # rows returned by executing the statement. Otherwise, each row will be
75
+ # yielded to the block.
76
+ #
77
+ # Any parameters will be bound to the statement using #bind_params.
78
+ #
79
+ # Example:
80
+ #
81
+ # stmt = db.prepare( "select * from table" )
82
+ # stmt.execute! do |row|
83
+ # ...
84
+ # end
85
+ #
86
+ # See also #bind_params, #execute.
87
+ def execute!( *bind_vars, &block )
88
+ execute(*bind_vars)
89
+ block_given? ? each(&block) : to_a
90
+ end
91
+
92
+ # Returns true if the statement is currently active, meaning it has an
93
+ # open result set.
94
+ def active?
95
+ !done?
96
+ end
97
+
98
+ # Return an array of the column names for this statement. Note that this
99
+ # may execute the statement in order to obtain the metadata; this makes it
100
+ # a (potentially) expensive operation.
101
+ def columns
102
+ get_metadata unless @columns
103
+ return @columns
104
+ end
105
+
106
+ def each
107
+ loop do
108
+ val = step
109
+ break self if done?
110
+ yield val
111
+ end
112
+ end
113
+
114
+ # Return an array of the data types for each column in this statement. Note
115
+ # that this may execute the statement in order to obtain the metadata; this
116
+ # makes it a (potentially) expensive operation.
117
+ def types
118
+ must_be_open!
119
+ get_metadata unless @types
120
+ @types
121
+ end
122
+
123
+ # Performs a sanity check to ensure that the statement is not
124
+ # closed. If it is, an exception is raised.
125
+ def must_be_open! # :nodoc:
126
+ if closed?
127
+ raise SQLite3::Exception, "cannot use a closed statement"
128
+ end
129
+ end
130
+
131
+ private
132
+ # A convenience method for obtaining the metadata about the query. Note
133
+ # that this will actually execute the SQL, which means it can be a
134
+ # (potentially) expensive operation.
135
+ def get_metadata
136
+ @columns = Array.new(column_count) do |column|
137
+ column_name column
138
+ end
139
+ @types = Array.new(column_count) do |column|
140
+ val = column_decltype(column)
141
+ val.nil? ? nil : val.downcase
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,118 @@
1
+ require 'time'
2
+ require 'date'
3
+
4
+ module SQLite3
5
+
6
+ # The Translator class encapsulates the logic and callbacks necessary for
7
+ # converting string data to a value of some specified type. Every Database
8
+ # instance may have a Translator instance, in order to assist in type
9
+ # translation (Database#type_translation).
10
+ #
11
+ # Further, applications may define their own custom type translation logic
12
+ # by registering translator blocks with the corresponding database's
13
+ # translator instance (Database#translator).
14
+ class Translator
15
+
16
+ # Create a new Translator instance. It will be preinitialized with default
17
+ # translators for most SQL data types.
18
+ def initialize
19
+ @translators = Hash.new( proc { |type,value| value } )
20
+ @type_name_cache = {}
21
+ register_default_translators
22
+ end
23
+
24
+ # Add a new translator block, which will be invoked to process type
25
+ # translations to the given type. The type should be an SQL datatype, and
26
+ # may include parentheses (i.e., "VARCHAR(30)"). However, any parenthetical
27
+ # information is stripped off and discarded, so type translation decisions
28
+ # are made solely on the "base" type name.
29
+ #
30
+ # The translator block itself should accept two parameters, "type" and
31
+ # "value". In this case, the "type" is the full type name (including
32
+ # parentheses), so the block itself may include logic for changing how a
33
+ # type is translated based on the additional data. The "value" parameter
34
+ # is the (string) data to convert.
35
+ #
36
+ # The block should return the translated value.
37
+ def add_translator( type, &block ) # :yields: type, value
38
+ warn(<<-eowarn) if $VERBOSE
39
+ #{caller[0]} is calling `add_translator`.
40
+ Built in translators are deprecated and will be removed in version 2.0.0
41
+ eowarn
42
+ @translators[ type_name( type ) ] = block
43
+ end
44
+
45
+ # Translate the given string value to a value of the given type. In the
46
+ # absence of an installed translator block for the given type, the value
47
+ # itself is always returned. Further, +nil+ values are never translated,
48
+ # and are always passed straight through regardless of the type parameter.
49
+ def translate( type, value )
50
+ unless value.nil?
51
+ # FIXME: this is a hack to support Sequel
52
+ if type && %w{ datetime timestamp }.include?(type.downcase)
53
+ @translators[ type_name( type ) ].call( type, value.to_s )
54
+ else
55
+ @translators[ type_name( type ) ].call( type, value )
56
+ end
57
+ end
58
+ end
59
+
60
+ # A convenience method for working with type names. This returns the "base"
61
+ # type name, without any parenthetical data.
62
+ def type_name( type )
63
+ @type_name_cache[type] ||= begin
64
+ type = "" if type.nil?
65
+ type = $1 if type =~ /^(.*?)\(/
66
+ type.upcase
67
+ end
68
+ end
69
+ private :type_name
70
+
71
+ # Register the default translators for the current Translator instance.
72
+ # This includes translators for most major SQL data types.
73
+ def register_default_translators
74
+ [ "time",
75
+ "timestamp" ].each { |type| add_translator( type ) { |t, v| Time.parse( v ) } }
76
+
77
+ add_translator( "date" ) { |t,v| Date.parse(v) }
78
+ add_translator( "datetime" ) { |t,v| DateTime.parse(v) }
79
+
80
+ [ "decimal",
81
+ "float",
82
+ "numeric",
83
+ "double",
84
+ "real",
85
+ "dec",
86
+ "fixed" ].each { |type| add_translator( type ) { |t,v| v.to_f } }
87
+
88
+ [ "integer",
89
+ "smallint",
90
+ "mediumint",
91
+ "int",
92
+ "bigint" ].each { |type| add_translator( type ) { |t,v| v.to_i } }
93
+
94
+ [ "bit",
95
+ "bool",
96
+ "boolean" ].each do |type|
97
+ add_translator( type ) do |t,v|
98
+ !( v.strip.gsub(/00+/,"0") == "0" ||
99
+ v.downcase == "false" ||
100
+ v.downcase == "f" ||
101
+ v.downcase == "no" ||
102
+ v.downcase == "n" )
103
+ end
104
+ end
105
+
106
+ add_translator( "tinyint" ) do |type, value|
107
+ if type =~ /\(\s*1\s*\)/
108
+ value.to_i == 1
109
+ else
110
+ value.to_i
111
+ end
112
+ end
113
+ end
114
+ private :register_default_translators
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,57 @@
1
+ require 'sqlite3/constants'
2
+
3
+ module SQLite3
4
+
5
+ class Value
6
+ attr_reader :handle
7
+
8
+ def initialize( db, handle )
9
+ @driver = db.driver
10
+ @handle = handle
11
+ end
12
+
13
+ def null?
14
+ type == :null
15
+ end
16
+
17
+ def to_blob
18
+ @driver.value_blob( @handle )
19
+ end
20
+
21
+ def length( utf16=false )
22
+ if utf16
23
+ @driver.value_bytes16( @handle )
24
+ else
25
+ @driver.value_bytes( @handle )
26
+ end
27
+ end
28
+
29
+ def to_f
30
+ @driver.value_double( @handle )
31
+ end
32
+
33
+ def to_i
34
+ @driver.value_int( @handle )
35
+ end
36
+
37
+ def to_int64
38
+ @driver.value_int64( @handle )
39
+ end
40
+
41
+ def to_s( utf16=false )
42
+ @driver.value_text( @handle, utf16 )
43
+ end
44
+
45
+ def type
46
+ case @driver.value_type( @handle )
47
+ when Constants::ColumnType::INTEGER then :int
48
+ when Constants::ColumnType::FLOAT then :float
49
+ when Constants::ColumnType::TEXT then :text
50
+ when Constants::ColumnType::BLOB then :blob
51
+ when Constants::ColumnType::NULL then :null
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,23 @@
1
+ module SQLite3
2
+
3
+ VERSION = "1.5.0"
4
+
5
+ module VersionProxy
6
+ MAJOR = 1
7
+ MINOR = 5
8
+ TINY = 0
9
+ BUILD = nil
10
+
11
+ STRING = [ MAJOR, MINOR, TINY, BUILD ].compact.join( "." )
12
+
13
+ VERSION = ::SQLite3::VERSION
14
+ end
15
+
16
+ def self.const_missing(name)
17
+ return super unless name == :Version
18
+ warn(<<-eowarn) if $VERBOSE
19
+ #{caller[0]}: SQLite::Version will be removed in sqlite3-ruby version 2.0.0
20
+ eowarn
21
+ VersionProxy
22
+ end
23
+ end
data/lib/sqlite3.rb ADDED
@@ -0,0 +1,15 @@
1
+ # support multiple ruby version (fat binaries under windows)
2
+ begin
3
+ RUBY_VERSION =~ /(\d+\.\d+)/
4
+ require "sqlite3/#{$1}/sqlite3_native"
5
+ rescue LoadError
6
+ require 'sqlite3/sqlite3_native'
7
+ end
8
+
9
+ require 'sqlite3/database'
10
+ require 'sqlite3/version'
11
+
12
+ module SQLite3
13
+ # Was sqlite3 compiled with thread safety on?
14
+ def self.threadsafe?; threadsafe > 0; end
15
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'sqlite3'
2
+ require 'minitest/autorun'
3
+
4
+ if ENV['GITHUB_ACTIONS'] == 'true' || ENV['CI']
5
+ $VERBOSE = nil
6
+ end
7
+
8
+ puts "info: sqlite3-ruby version: #{SQLite3::VERSION}/#{SQLite3::VersionProxy::STRING}"
9
+ puts "info: sqlite3 version: #{SQLite3::SQLITE_VERSION}/#{SQLite3::SQLITE_LOADED_VERSION}"
10
+ puts "info: sqlcipher?: #{SQLite3.sqlcipher?}"
11
+ puts "info: threadsafe?: #{SQLite3.threadsafe?}"
12
+
13
+ unless RUBY_VERSION >= "1.9"
14
+ require 'iconv'
15
+ end
16
+
17
+ module SQLite3
18
+ class TestCase < Minitest::Test
19
+ alias :assert_not_equal :refute_equal
20
+ alias :assert_not_nil :refute_nil
21
+ alias :assert_raise :assert_raises
22
+
23
+ def assert_nothing_raised
24
+ yield
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ module SQLite3
4
+ class TestBackup < SQLite3::TestCase
5
+ def setup
6
+ @sdb = SQLite3::Database.new(':memory:')
7
+ @ddb = SQLite3::Database.new(':memory:')
8
+ @sdb.execute('CREATE TABLE foo (idx, val);');
9
+ @data = ('A'..'Z').map{|x|x * 40}
10
+ @data.each_with_index do |v, i|
11
+ @sdb.execute('INSERT INTO foo (idx, val) VALUES (?, ?);', [i, v])
12
+ end
13
+ end
14
+
15
+ def test_backup_step
16
+ b = SQLite3::Backup.new(@ddb, 'main', @sdb, 'main')
17
+ while b.step(1) == SQLite3::Constants::ErrorCode::OK
18
+ assert_not_equal(0, b.remaining)
19
+ end
20
+ assert_equal(0, b.remaining)
21
+ b.finish
22
+ assert_equal(@data.length, @ddb.execute('SELECT * FROM foo;').length)
23
+ end
24
+
25
+ def test_backup_all
26
+ b = SQLite3::Backup.new(@ddb, 'main', @sdb, 'main')
27
+ assert_equal(SQLite3::Constants::ErrorCode::DONE, b.step(-1))
28
+ assert_equal(0, b.remaining)
29
+ b.finish
30
+ assert_equal(@data.length, @ddb.execute('SELECT * FROM foo;').length)
31
+ end
32
+ end if defined?(SQLite3::Backup)
33
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'helper'
4
+
5
+ module SQLite3
6
+ class TestCollation < SQLite3::TestCase
7
+ class Comparator
8
+ attr_reader :calls
9
+ def initialize
10
+ @calls = []
11
+ end
12
+
13
+ def compare left, right
14
+ @calls << [left, right]
15
+ left <=> right
16
+ end
17
+ end
18
+
19
+ def setup
20
+ @db = SQLite3::Database.new(':memory:')
21
+ @create = "create table ex(id int, data string)"
22
+ @db.execute(@create);
23
+ [ [1, 'hello'], [2, 'world'] ].each do |vals|
24
+ @db.execute('insert into ex (id, data) VALUES (?, ?)', vals)
25
+ end
26
+ end
27
+
28
+ def test_custom_collation
29
+ comparator = Comparator.new
30
+
31
+ @db.collation 'foo', comparator
32
+
33
+ assert_equal comparator, @db.collations['foo']
34
+ @db.execute('select data from ex order by 1 collate foo')
35
+ assert_equal 1, comparator.calls.length
36
+ end
37
+
38
+ def test_remove_collation
39
+ comparator = Comparator.new
40
+
41
+ @db.collation 'foo', comparator
42
+ @db.collation 'foo', nil
43
+
44
+ assert_nil @db.collations['foo']
45
+ assert_raises(SQLite3::SQLException) do
46
+ @db.execute('select data from ex order by 1 collate foo')
47
+ end
48
+ end
49
+
50
+ if RUBY_VERSION >= '1.9.1'
51
+ def test_encoding
52
+ comparator = Comparator.new
53
+ @db.collation 'foo', comparator
54
+ @db.execute('select data from ex order by 1 collate foo')
55
+
56
+ a, b = *comparator.calls.first
57
+
58
+ assert_equal Encoding.find('UTF-8'), a.encoding
59
+ assert_equal Encoding.find('UTF-8'), b.encoding
60
+ end
61
+
62
+ def test_encoding_default_internal
63
+ warn_before = $-w
64
+ $-w = false
65
+ before_enc = Encoding.default_internal
66
+
67
+ Encoding.default_internal = 'EUC-JP'
68
+ comparator = Comparator.new
69
+ @db.collation 'foo', comparator
70
+ @db.execute('select data from ex order by 1 collate foo')
71
+
72
+ a, b = *comparator.calls.first
73
+
74
+ assert_equal Encoding.find('EUC-JP'), a.encoding
75
+ assert_equal Encoding.find('EUC-JP'), b.encoding
76
+ ensure
77
+ Encoding.default_internal = before_enc
78
+ $-w = warn_before
79
+ end
80
+ end
81
+ end
82
+ end