sqlite3-ruby 1.2.3-x86-mingw32
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.
Potentially problematic release.
This version of sqlite3-ruby might be problematic. Click here for more details.
- data/README.rdoc +51 -0
- data/doc/faq/faq.html +408 -0
- data/doc/faq/faq.rb +145 -0
- data/doc/faq/faq.yml +426 -0
- data/ext/sqlite3_api/MANIFEST +4 -0
- data/ext/sqlite3_api/Makefile +142 -0
- data/ext/sqlite3_api/extconf.rb +16 -0
- data/ext/sqlite3_api/mkmf.log +66 -0
- data/ext/sqlite3_api/sqlite3_api.i +358 -0
- data/ext/sqlite3_api/sqlite3_api.so +0 -0
- data/ext/sqlite3_api/sqlite3_api_wrap.c +3094 -0
- data/ext/sqlite3_api/sqlite3_api_wrap.o +0 -0
- data/ext/sqlite3_api/win32/build.bat +7 -0
- data/lib/sqlite3.rb +1 -0
- data/lib/sqlite3/constants.rb +49 -0
- data/lib/sqlite3/database.rb +715 -0
- data/lib/sqlite3/driver/dl/api.rb +152 -0
- data/lib/sqlite3/driver/dl/driver.rb +307 -0
- data/lib/sqlite3/driver/native/driver.rb +211 -0
- data/lib/sqlite3/errors.rb +68 -0
- data/lib/sqlite3/pragmas.rb +271 -0
- data/lib/sqlite3/resultset.rb +176 -0
- data/lib/sqlite3/statement.rb +230 -0
- data/lib/sqlite3/translator.rb +109 -0
- data/lib/sqlite3/value.rb +57 -0
- data/lib/sqlite3/version.rb +14 -0
- data/test/bm.rb +140 -0
- data/test/driver/dl/tc_driver.rb +292 -0
- data/test/mocks.rb +45 -0
- data/test/native-vs-dl.rb +126 -0
- data/test/tc_database.rb +198 -0
- data/test/tc_errors.rb +21 -0
- data/test/tc_integration.rb +1044 -0
- data/test/tests.rb +6 -0
- metadata +96 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'sqlite3_api'
|
2
|
+
|
3
|
+
module SQLite3 ; module Driver ; module Native
|
4
|
+
|
5
|
+
class Driver
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@callback_data = Hash.new
|
9
|
+
@authorizer = Hash.new
|
10
|
+
@busy_handler = Hash.new
|
11
|
+
@trace = Hash.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def complete?( sql, utf16=false )
|
15
|
+
API.send( utf16 ? :sqlite3_complete16 : :sqlite3_complete, sql ) != 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def busy_handler( db, data=nil, &block )
|
19
|
+
if block
|
20
|
+
cb = API::CallbackData.new
|
21
|
+
cb.proc = block
|
22
|
+
cb.data = data
|
23
|
+
result = API.sqlite3_busy_handler( db, API::Sqlite3_ruby_busy_handler, cb )
|
24
|
+
# Reference the Callback object so that
|
25
|
+
# it is not deleted by the GC
|
26
|
+
@busy_handler[db] = cb
|
27
|
+
else
|
28
|
+
# Unreference the callback *after* having removed it
|
29
|
+
# from sqlite
|
30
|
+
result = API.sqlite3_busy_handler( db, nil, nil )
|
31
|
+
@busy_handler.delete(db)
|
32
|
+
end
|
33
|
+
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_authorizer( db, data=nil, &block )
|
38
|
+
if block
|
39
|
+
cb = API::CallbackData.new
|
40
|
+
cb.proc = block
|
41
|
+
cb.data = data
|
42
|
+
result = API.sqlite3_set_authorizer( db, API::Sqlite3_ruby_authorizer, cb )
|
43
|
+
@authorizer[db] = cb # see comments in busy_handler
|
44
|
+
else
|
45
|
+
result = API.sqlite3_set_authorizer( db, nil, nil )
|
46
|
+
@authorizer.delete(db) # see comments in busy_handler
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
def trace( db, data=nil, &block )
|
53
|
+
if block
|
54
|
+
cb = API::CallbackData.new
|
55
|
+
cb.proc = block
|
56
|
+
cb.data = data
|
57
|
+
result = API.sqlite3_trace( db, API::Sqlite3_ruby_trace, cb )
|
58
|
+
@trace[db] = cb # see comments in busy_handler
|
59
|
+
else
|
60
|
+
result = API.sqlite3_trace( db, nil, nil )
|
61
|
+
@trace.delete(db) # see comments in busy_handler
|
62
|
+
end
|
63
|
+
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def open( filename, utf16=false )
|
68
|
+
API.send( utf16 ? :sqlite3_open16 : :sqlite3_open, filename )
|
69
|
+
end
|
70
|
+
|
71
|
+
def errmsg( db, utf16=false )
|
72
|
+
API.send( utf16 ? :sqlite3_errmsg16 : :sqlite3_errmsg, db )
|
73
|
+
end
|
74
|
+
|
75
|
+
def prepare( db, sql, utf16=false )
|
76
|
+
API.send( ( utf16 ? :sqlite3_prepare16 : :sqlite3_prepare ),
|
77
|
+
db, sql )
|
78
|
+
end
|
79
|
+
|
80
|
+
def bind_text( stmt, index, value, utf16=false )
|
81
|
+
API.send( ( utf16 ? :sqlite3_bind_text16 : :sqlite3_bind_text ),
|
82
|
+
stmt, index, value.to_s )
|
83
|
+
end
|
84
|
+
|
85
|
+
def column_name( stmt, index, utf16=false )
|
86
|
+
API.send( ( utf16 ? :sqlite3_column_name16 : :sqlite3_column_name ),
|
87
|
+
stmt, index )
|
88
|
+
end
|
89
|
+
|
90
|
+
def column_decltype( stmt, index, utf16=false )
|
91
|
+
API.send(
|
92
|
+
( utf16 ? :sqlite3_column_decltype16 : :sqlite3_column_decltype ),
|
93
|
+
stmt, index )
|
94
|
+
end
|
95
|
+
|
96
|
+
def column_text( stmt, index, utf16=false )
|
97
|
+
API.send( ( utf16 ? :sqlite3_column_text16 : :sqlite3_column_text ),
|
98
|
+
stmt, index )
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_function( db, name, args, text, cookie, func, step, final )
|
102
|
+
if func || ( step && final )
|
103
|
+
cb = API::CallbackData.new
|
104
|
+
cb.proc = cb.proc2 = nil
|
105
|
+
cb.data = cookie
|
106
|
+
end
|
107
|
+
|
108
|
+
if func
|
109
|
+
cb.proc = func
|
110
|
+
|
111
|
+
func = API::Sqlite3_ruby_function_step
|
112
|
+
step = final = nil
|
113
|
+
elsif step && final
|
114
|
+
cb.proc = step
|
115
|
+
cb.proc2 = final
|
116
|
+
|
117
|
+
func = nil
|
118
|
+
step = API::Sqlite3_ruby_function_step
|
119
|
+
final = API::Sqlite3_ruby_function_final
|
120
|
+
end
|
121
|
+
|
122
|
+
result = API.sqlite3_create_function( db, name, args, text, cb, func, step, final )
|
123
|
+
|
124
|
+
# see comments in busy_handler
|
125
|
+
if cb
|
126
|
+
@callback_data[ name ] = cb
|
127
|
+
else
|
128
|
+
@callback_data.delete( name )
|
129
|
+
end
|
130
|
+
|
131
|
+
return result
|
132
|
+
end
|
133
|
+
|
134
|
+
def value_text( value, utf16=false )
|
135
|
+
method = case utf16
|
136
|
+
when nil, false then :sqlite3_value_text
|
137
|
+
when :le then :sqlite3_value_text16le
|
138
|
+
when :be then :sqlite3_value_text16be
|
139
|
+
else :sqlite3_value_text16
|
140
|
+
end
|
141
|
+
|
142
|
+
API.send( method, value )
|
143
|
+
end
|
144
|
+
|
145
|
+
def result_text( context, result, utf16=false )
|
146
|
+
method = case utf16
|
147
|
+
when nil, false then :sqlite3_result_text
|
148
|
+
when :le then :sqlite3_result_text16le
|
149
|
+
when :be then :sqlite3_result_text16be
|
150
|
+
else :sqlite3_result_text16
|
151
|
+
end
|
152
|
+
|
153
|
+
API.send( method, context, result.to_s )
|
154
|
+
end
|
155
|
+
|
156
|
+
def result_error( context, value, utf16=false )
|
157
|
+
API.send( ( utf16 ? :sqlite3_result_error16 : :sqlite3_result_error ),
|
158
|
+
context, value )
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.api_delegate( name )
|
162
|
+
eval "def #{name} (*args) API.sqlite3_#{name}( *args ) ; end"
|
163
|
+
end
|
164
|
+
|
165
|
+
api_delegate :libversion
|
166
|
+
api_delegate :close
|
167
|
+
api_delegate :last_insert_rowid
|
168
|
+
api_delegate :changes
|
169
|
+
api_delegate :total_changes
|
170
|
+
api_delegate :interrupt
|
171
|
+
api_delegate :busy_timeout
|
172
|
+
api_delegate :errcode
|
173
|
+
api_delegate :bind_blob
|
174
|
+
api_delegate :bind_double
|
175
|
+
api_delegate :bind_int
|
176
|
+
api_delegate :bind_int64
|
177
|
+
api_delegate :bind_null
|
178
|
+
api_delegate :bind_parameter_count
|
179
|
+
api_delegate :bind_parameter_name
|
180
|
+
api_delegate :bind_parameter_index
|
181
|
+
api_delegate :column_count
|
182
|
+
api_delegate :step
|
183
|
+
api_delegate :data_count
|
184
|
+
api_delegate :column_blob
|
185
|
+
api_delegate :column_bytes
|
186
|
+
api_delegate :column_bytes16
|
187
|
+
api_delegate :column_double
|
188
|
+
api_delegate :column_int
|
189
|
+
api_delegate :column_int64
|
190
|
+
api_delegate :column_type
|
191
|
+
api_delegate :finalize
|
192
|
+
api_delegate :reset
|
193
|
+
api_delegate :aggregate_count
|
194
|
+
api_delegate :value_blob
|
195
|
+
api_delegate :value_bytes
|
196
|
+
api_delegate :value_bytes16
|
197
|
+
api_delegate :value_double
|
198
|
+
api_delegate :value_int
|
199
|
+
api_delegate :value_int64
|
200
|
+
api_delegate :value_type
|
201
|
+
api_delegate :result_blob
|
202
|
+
api_delegate :result_double
|
203
|
+
api_delegate :result_int
|
204
|
+
api_delegate :result_int64
|
205
|
+
api_delegate :result_null
|
206
|
+
api_delegate :result_value
|
207
|
+
api_delegate :aggregate_context
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end ; end ; end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'sqlite3/constants'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
|
5
|
+
class Exception < ::StandardError
|
6
|
+
@code = 0
|
7
|
+
|
8
|
+
# The numeric error code that this exception represents.
|
9
|
+
def self.code
|
10
|
+
@code
|
11
|
+
end
|
12
|
+
|
13
|
+
# A convenience for accessing the error code for this exception.
|
14
|
+
def code
|
15
|
+
self.class.code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class SQLException < Exception; end
|
20
|
+
class InternalException < Exception; end
|
21
|
+
class PermissionException < Exception; end
|
22
|
+
class AbortException < Exception; end
|
23
|
+
class BusyException < Exception; end
|
24
|
+
class LockedException < Exception; end
|
25
|
+
class MemoryException < Exception; end
|
26
|
+
class ReadOnlyException < Exception; end
|
27
|
+
class InterruptException < Exception; end
|
28
|
+
class IOException < Exception; end
|
29
|
+
class CorruptException < Exception; end
|
30
|
+
class NotFoundException < Exception; end
|
31
|
+
class FullException < Exception; end
|
32
|
+
class CantOpenException < Exception; end
|
33
|
+
class ProtocolException < Exception; end
|
34
|
+
class EmptyException < Exception; end
|
35
|
+
class SchemaChangedException < Exception; end
|
36
|
+
class TooBigException < Exception; end
|
37
|
+
class ConstraintException < Exception; end
|
38
|
+
class MismatchException < Exception; end
|
39
|
+
class MisuseException < Exception; end
|
40
|
+
class UnsupportedException < Exception; end
|
41
|
+
class AuthorizationException < Exception; end
|
42
|
+
class FormatException < Exception; end
|
43
|
+
class RangeException < Exception; end
|
44
|
+
class NotADatabaseException < Exception; end
|
45
|
+
|
46
|
+
EXCEPTIONS = [
|
47
|
+
nil,
|
48
|
+
SQLException, InternalException, PermissionException,
|
49
|
+
AbortException, BusyException, LockedException, MemoryException,
|
50
|
+
ReadOnlyException, InterruptException, IOException, CorruptException,
|
51
|
+
NotFoundException, FullException, CantOpenException, ProtocolException,
|
52
|
+
EmptyException, SchemaChangedException, TooBigException,
|
53
|
+
ConstraintException, MismatchException, MisuseException,
|
54
|
+
UnsupportedException, AuthorizationException, FormatException,
|
55
|
+
RangeException, NotADatabaseException
|
56
|
+
].each_with_index { |e,i| e.instance_variable_set( :@code, i ) if e }
|
57
|
+
|
58
|
+
module Error
|
59
|
+
def check( result, db=nil, msg=nil )
|
60
|
+
unless result == Constants::ErrorCode::OK
|
61
|
+
msg = ( msg ? msg + ": " : "" ) + db.errmsg if db
|
62
|
+
raise(( EXCEPTIONS[result] || SQLite3::Exception ), msg)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
module_function :check
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'sqlite3/errors'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
|
5
|
+
# This module is intended for inclusion solely by the Database class. It
|
6
|
+
# defines convenience methods for the various pragmas supported by SQLite3.
|
7
|
+
#
|
8
|
+
# For a detailed description of these pragmas, see the SQLite3 documentation
|
9
|
+
# at http://sqlite.org/pragma.html.
|
10
|
+
module Pragmas
|
11
|
+
|
12
|
+
# Returns +true+ or +false+ depending on the value of the named pragma.
|
13
|
+
def get_boolean_pragma( name )
|
14
|
+
get_first_value( "PRAGMA #{name}" ) != "0"
|
15
|
+
end
|
16
|
+
private :get_boolean_pragma
|
17
|
+
|
18
|
+
# Sets the given pragma to the given boolean value. The value itself
|
19
|
+
# may be +true+ or +false+, or any other commonly used string or
|
20
|
+
# integer that represents truth.
|
21
|
+
def set_boolean_pragma( name, mode )
|
22
|
+
case mode
|
23
|
+
when String
|
24
|
+
case mode.downcase
|
25
|
+
when "on", "yes", "true", "y", "t"; mode = "'ON'"
|
26
|
+
when "off", "no", "false", "n", "f"; mode = "'OFF'"
|
27
|
+
else
|
28
|
+
raise Exception,
|
29
|
+
"unrecognized pragma parameter #{mode.inspect}"
|
30
|
+
end
|
31
|
+
when true, 1
|
32
|
+
mode = "ON"
|
33
|
+
when false, 0, nil
|
34
|
+
mode = "OFF"
|
35
|
+
else
|
36
|
+
raise Exception,
|
37
|
+
"unrecognized pragma parameter #{mode.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
execute( "PRAGMA #{name}=#{mode}" )
|
41
|
+
end
|
42
|
+
private :set_boolean_pragma
|
43
|
+
|
44
|
+
# Requests the given pragma (and parameters), and if the block is given,
|
45
|
+
# each row of the result set will be yielded to it. Otherwise, the results
|
46
|
+
# are returned as an array.
|
47
|
+
def get_query_pragma( name, *parms, &block ) # :yields: row
|
48
|
+
if parms.empty?
|
49
|
+
execute( "PRAGMA #{name}", &block )
|
50
|
+
else
|
51
|
+
args = "'" + parms.join("','") + "'"
|
52
|
+
execute( "PRAGMA #{name}( #{args} )", &block )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
private :get_query_pragma
|
56
|
+
|
57
|
+
# Return the value of the given pragma.
|
58
|
+
def get_enum_pragma( name )
|
59
|
+
get_first_value( "PRAGMA #{name}" )
|
60
|
+
end
|
61
|
+
private :get_enum_pragma
|
62
|
+
|
63
|
+
# Set the value of the given pragma to +mode+. The +mode+ parameter must
|
64
|
+
# conform to one of the values in the given +enum+ array. Each entry in
|
65
|
+
# the array is another array comprised of elements in the enumeration that
|
66
|
+
# have duplicate values. See #synchronous, #default_synchronous,
|
67
|
+
# #temp_store, and #default_temp_store for usage examples.
|
68
|
+
def set_enum_pragma( name, mode, enums )
|
69
|
+
match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
|
70
|
+
raise Exception,
|
71
|
+
"unrecognized #{name} #{mode.inspect}" unless match
|
72
|
+
execute( "PRAGMA #{name}='#{match.first.upcase}'" )
|
73
|
+
end
|
74
|
+
private :set_enum_pragma
|
75
|
+
|
76
|
+
# Returns the value of the given pragma as an integer.
|
77
|
+
def get_int_pragma( name )
|
78
|
+
get_first_value( "PRAGMA #{name}" ).to_i
|
79
|
+
end
|
80
|
+
private :get_int_pragma
|
81
|
+
|
82
|
+
# Set the value of the given pragma to the integer value of the +value+
|
83
|
+
# parameter.
|
84
|
+
def set_int_pragma( name, value )
|
85
|
+
execute( "PRAGMA #{name}=#{value.to_i}" )
|
86
|
+
end
|
87
|
+
private :set_int_pragma
|
88
|
+
|
89
|
+
# The enumeration of valid synchronous modes.
|
90
|
+
SYNCHRONOUS_MODES = [ [ 'full', 2 ], [ 'normal', 1 ], [ 'off', 0 ] ]
|
91
|
+
|
92
|
+
# The enumeration of valid temp store modes.
|
93
|
+
TEMP_STORE_MODES = [ [ 'default', 0 ], [ 'file', 1 ], [ 'memory', 2 ] ]
|
94
|
+
|
95
|
+
# Does an integrity check on the database. If the check fails, a
|
96
|
+
# SQLite3::Exception will be raised. Otherwise it
|
97
|
+
# returns silently.
|
98
|
+
def integrity_check
|
99
|
+
execute( "PRAGMA integrity_check" ) do |row|
|
100
|
+
raise Exception, row[0] if row[0] != "ok"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def auto_vacuum
|
105
|
+
get_boolean_pragma "auto_vacuum"
|
106
|
+
end
|
107
|
+
|
108
|
+
def auto_vacuum=( mode )
|
109
|
+
set_boolean_pragma "auto_vacuum", mode
|
110
|
+
end
|
111
|
+
|
112
|
+
def schema_cookie
|
113
|
+
get_int_pragma "schema_cookie"
|
114
|
+
end
|
115
|
+
|
116
|
+
def schema_cookie=( cookie )
|
117
|
+
set_int_pragma "schema_cookie", cookie
|
118
|
+
end
|
119
|
+
|
120
|
+
def user_cookie
|
121
|
+
get_int_pragma "user_cookie"
|
122
|
+
end
|
123
|
+
|
124
|
+
def user_cookie=( cookie )
|
125
|
+
set_int_pragma "user_cookie", cookie
|
126
|
+
end
|
127
|
+
|
128
|
+
def cache_size
|
129
|
+
get_int_pragma "cache_size"
|
130
|
+
end
|
131
|
+
|
132
|
+
def cache_size=( size )
|
133
|
+
set_int_pragma "cache_size", size
|
134
|
+
end
|
135
|
+
|
136
|
+
def default_cache_size
|
137
|
+
get_int_pragma "default_cache_size"
|
138
|
+
end
|
139
|
+
|
140
|
+
def default_cache_size=( size )
|
141
|
+
set_int_pragma "default_cache_size", size
|
142
|
+
end
|
143
|
+
|
144
|
+
def default_synchronous
|
145
|
+
get_enum_pragma "default_synchronous"
|
146
|
+
end
|
147
|
+
|
148
|
+
def default_synchronous=( mode )
|
149
|
+
set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
|
150
|
+
end
|
151
|
+
|
152
|
+
def synchronous
|
153
|
+
get_enum_pragma "synchronous"
|
154
|
+
end
|
155
|
+
|
156
|
+
def synchronous=( mode )
|
157
|
+
set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
|
158
|
+
end
|
159
|
+
|
160
|
+
def default_temp_store
|
161
|
+
get_enum_pragma "default_temp_store"
|
162
|
+
end
|
163
|
+
|
164
|
+
def default_temp_store=( mode )
|
165
|
+
set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
|
166
|
+
end
|
167
|
+
|
168
|
+
def temp_store
|
169
|
+
get_enum_pragma "temp_store"
|
170
|
+
end
|
171
|
+
|
172
|
+
def temp_store=( mode )
|
173
|
+
set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
|
174
|
+
end
|
175
|
+
|
176
|
+
def full_column_names
|
177
|
+
get_boolean_pragma "full_column_names"
|
178
|
+
end
|
179
|
+
|
180
|
+
def full_column_names=( mode )
|
181
|
+
set_boolean_pragma "full_column_names", mode
|
182
|
+
end
|
183
|
+
|
184
|
+
def parser_trace
|
185
|
+
get_boolean_pragma "parser_trace"
|
186
|
+
end
|
187
|
+
|
188
|
+
def parser_trace=( mode )
|
189
|
+
set_boolean_pragma "parser_trace", mode
|
190
|
+
end
|
191
|
+
|
192
|
+
def vdbe_trace
|
193
|
+
get_boolean_pragma "vdbe_trace"
|
194
|
+
end
|
195
|
+
|
196
|
+
def vdbe_trace=( mode )
|
197
|
+
set_boolean_pragma "vdbe_trace", mode
|
198
|
+
end
|
199
|
+
|
200
|
+
def database_list( &block ) # :yields: row
|
201
|
+
get_query_pragma "database_list", &block
|
202
|
+
end
|
203
|
+
|
204
|
+
def foreign_key_list( table, &block ) # :yields: row
|
205
|
+
get_query_pragma "foreign_key_list", table, &block
|
206
|
+
end
|
207
|
+
|
208
|
+
def index_info( index, &block ) # :yields: row
|
209
|
+
get_query_pragma "index_info", index, &block
|
210
|
+
end
|
211
|
+
|
212
|
+
def index_list( table, &block ) # :yields: row
|
213
|
+
get_query_pragma "index_list", table, &block
|
214
|
+
end
|
215
|
+
|
216
|
+
def table_info( table, &block ) # :yields: row
|
217
|
+
columns, *rows = execute2("PRAGMA table_info(#{table})")
|
218
|
+
|
219
|
+
needs_tweak_default = version_compare(driver.libversion, "3.3.7") > 0
|
220
|
+
|
221
|
+
result = [] unless block_given?
|
222
|
+
rows.each do |row|
|
223
|
+
new_row = {}
|
224
|
+
columns.each_with_index do |name, index|
|
225
|
+
new_row[name] = row[index]
|
226
|
+
end
|
227
|
+
|
228
|
+
tweak_default(new_row) if needs_tweak_default
|
229
|
+
|
230
|
+
if block_given?
|
231
|
+
yield new_row
|
232
|
+
else
|
233
|
+
result << new_row
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
result
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Compares two version strings
|
243
|
+
def version_compare(v1, v2)
|
244
|
+
v1 = v1.split(".").map { |i| i.to_i }
|
245
|
+
v2 = v2.split(".").map { |i| i.to_i }
|
246
|
+
parts = [v1.length, v2.length].max
|
247
|
+
v1.push 0 while v1.length < parts
|
248
|
+
v2.push 0 while v2.length < parts
|
249
|
+
v1.zip(v2).each do |a,b|
|
250
|
+
return -1 if a < b
|
251
|
+
return 1 if a > b
|
252
|
+
end
|
253
|
+
return 0
|
254
|
+
end
|
255
|
+
|
256
|
+
# Since SQLite 3.3.8, the table_info pragma has returned the default
|
257
|
+
# value of the row as a quoted SQL value. This method essentially
|
258
|
+
# unquotes those values.
|
259
|
+
def tweak_default(hash)
|
260
|
+
case hash["dflt_value"]
|
261
|
+
when /^null$/i
|
262
|
+
hash["dflt_value"] = nil
|
263
|
+
when /^'(.*)'$/
|
264
|
+
hash["dflt_value"] = $1.gsub(/''/, "'")
|
265
|
+
when /^"(.*)"$/
|
266
|
+
hash["dflt_value"] = $1.gsub(/""/, '"')
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|