dbd-sqlite 0.1
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.
- data/ChangeLog +3694 -0
- data/LICENSE +25 -0
- data/README +271 -0
- data/lib/dbd/SQLite.rb +97 -0
- data/lib/dbd/sqlite/database.rb +142 -0
- data/lib/dbd/sqlite/statement.rb +120 -0
- data/test/DBD_TESTS +48 -0
- data/test/dbd/general/test_database.rb +157 -0
- data/test/dbd/general/test_statement.rb +240 -0
- data/test/dbd/general/test_types.rb +253 -0
- data/test/dbd/sqlite/base.rb +33 -0
- data/test/dbd/sqlite/test_database.rb +24 -0
- data/test/dbd/sqlite/test_driver.rb +68 -0
- data/test/dbd/sqlite/test_statement.rb +97 -0
- data/test/dbd/sqlite/up.sql +23 -0
- data/test/ts_dbd.rb +118 -0
- metadata +89 -0
@@ -0,0 +1,253 @@
|
|
1
|
+
@class = Class.new(DBDConfig.testbase(DBDConfig.current_dbtype)) do
|
2
|
+
def skip_bit
|
3
|
+
# FIXME this test fails because DBI's type system blows goats.
|
4
|
+
@sth = nil
|
5
|
+
|
6
|
+
assert_nothing_raised do
|
7
|
+
@sth = @dbh.prepare("insert into bit_test (mybit) values (?)")
|
8
|
+
@sth.bind_param(1, 0, DBI::SQL_TINYINT)
|
9
|
+
@sth.execute
|
10
|
+
# if dbtype == "postgresql"
|
11
|
+
# @sth.execute("0")
|
12
|
+
# else
|
13
|
+
# @sth.execute(0)
|
14
|
+
# end
|
15
|
+
@sth.finish
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_nothing_raised do
|
19
|
+
@sth = @dbh.prepare("select * from bit_test")
|
20
|
+
@sth.execute
|
21
|
+
row = @sth.fetch
|
22
|
+
@sth.finish
|
23
|
+
|
24
|
+
assert_equal [0], row
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# FIXME
|
29
|
+
# Ideally, this test should be split across the DBI tests and DBD, but for
|
30
|
+
# now testing against the DBDs really doesn't cost us anything other than
|
31
|
+
# debugging time if something breaks.
|
32
|
+
def test_bind_coltype
|
33
|
+
# ensure type conv didn't get turned off somewhere.
|
34
|
+
assert(DBI.convert_types)
|
35
|
+
assert(@dbh.convert_types)
|
36
|
+
|
37
|
+
assert_nothing_raised do
|
38
|
+
@sth = @dbh.prepare("select name, age from names order by age")
|
39
|
+
assert(@sth.convert_types) # again
|
40
|
+
@sth.execute
|
41
|
+
@sth.bind_coltype(2, DBI::Type::Varchar)
|
42
|
+
assert_equal(
|
43
|
+
[
|
44
|
+
["Joe", "19"],
|
45
|
+
["Bob", "21"],
|
46
|
+
["Jim", "30"],
|
47
|
+
], @sth.fetch_all
|
48
|
+
)
|
49
|
+
@sth.finish
|
50
|
+
end
|
51
|
+
|
52
|
+
# just to be sure..
|
53
|
+
assert_nothing_raised do
|
54
|
+
@sth = @dbh.prepare("select name, age from names order by age")
|
55
|
+
@sth.execute
|
56
|
+
@sth.bind_coltype(2, DBI::Type::Float)
|
57
|
+
@sth.fetch_all.collect { |x| assert_kind_of(Float, x[1]) }
|
58
|
+
@sth.finish
|
59
|
+
end
|
60
|
+
|
61
|
+
# now, let's check some failure cases
|
62
|
+
@sth = @dbh.prepare("select name, age from names order by age")
|
63
|
+
|
64
|
+
# can't bind_coltype before execute
|
65
|
+
assert_raise(DBI::InterfaceError) { @sth.bind_coltype(1, DBI::Type::Float) }
|
66
|
+
# can't index < 1
|
67
|
+
assert_raise(DBI::InterfaceError) { @sth.bind_coltype(0, DBI::Type::Float) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_noconv
|
71
|
+
# XXX this test will fail the whole test suite miserably if it fails at any point.
|
72
|
+
assert(DBI.convert_types)
|
73
|
+
|
74
|
+
DBI.convert_types = false
|
75
|
+
@sth.finish rescue nil
|
76
|
+
@dbh.disconnect
|
77
|
+
set_base_dbh
|
78
|
+
|
79
|
+
assert(!@dbh.convert_types)
|
80
|
+
|
81
|
+
assert_nothing_raised do
|
82
|
+
@sth = @dbh.prepare("select * from names order by age")
|
83
|
+
assert(!@sth.convert_types)
|
84
|
+
@sth.execute
|
85
|
+
assert_equal(
|
86
|
+
[
|
87
|
+
["Joe", "19"],
|
88
|
+
["Bob", "21"],
|
89
|
+
["Jim", "30"],
|
90
|
+
], @sth.fetch_all
|
91
|
+
)
|
92
|
+
@sth.finish
|
93
|
+
end
|
94
|
+
|
95
|
+
DBI.convert_types = true
|
96
|
+
@sth.finish rescue nil
|
97
|
+
@dbh.disconnect
|
98
|
+
set_base_dbh
|
99
|
+
|
100
|
+
assert(DBI.convert_types)
|
101
|
+
assert(@dbh.convert_types)
|
102
|
+
|
103
|
+
assert_nothing_raised do
|
104
|
+
@sth = @dbh.prepare("select * from names order by age")
|
105
|
+
assert(@sth.convert_types)
|
106
|
+
@sth.execute
|
107
|
+
assert_equal(
|
108
|
+
[
|
109
|
+
["Joe", 19],
|
110
|
+
["Bob", 21],
|
111
|
+
["Jim", 30],
|
112
|
+
], @sth.fetch_all
|
113
|
+
)
|
114
|
+
@sth.finish
|
115
|
+
end
|
116
|
+
|
117
|
+
@dbh.convert_types = false
|
118
|
+
|
119
|
+
assert_nothing_raised do
|
120
|
+
@sth = @dbh.prepare("select * from names order by age")
|
121
|
+
assert(!@sth.convert_types)
|
122
|
+
@sth.execute
|
123
|
+
assert_equal(
|
124
|
+
[
|
125
|
+
["Joe", "19"],
|
126
|
+
["Bob", "21"],
|
127
|
+
["Jim", "30"],
|
128
|
+
], @sth.fetch_all
|
129
|
+
)
|
130
|
+
@sth.finish
|
131
|
+
end
|
132
|
+
|
133
|
+
@dbh.convert_types = true
|
134
|
+
|
135
|
+
assert_nothing_raised do
|
136
|
+
@sth = @dbh.prepare("select * from names order by age")
|
137
|
+
assert(@sth.convert_types)
|
138
|
+
@sth.convert_types = false
|
139
|
+
@sth.execute
|
140
|
+
assert_equal(
|
141
|
+
[
|
142
|
+
["Joe", "19"],
|
143
|
+
["Bob", "21"],
|
144
|
+
["Jim", "30"],
|
145
|
+
], @sth.fetch_all
|
146
|
+
)
|
147
|
+
@sth.finish
|
148
|
+
end
|
149
|
+
rescue Exception => e
|
150
|
+
DBI.convert_types = true
|
151
|
+
@sth.finish
|
152
|
+
@dbh.disconnect
|
153
|
+
set_base_dbh
|
154
|
+
raise e
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_null
|
158
|
+
assert_nothing_raised do
|
159
|
+
@sth = @dbh.prepare('insert into names (name, age) values (?, ?)')
|
160
|
+
@sth.execute("'NULL'", 201)
|
161
|
+
@sth.execute(nil, 202)
|
162
|
+
@sth.execute("NULL", 203)
|
163
|
+
@sth.finish
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_nothing_raised do
|
167
|
+
@sth = @dbh.prepare('select * from names where age > 200 order by age')
|
168
|
+
@sth.execute
|
169
|
+
assert_equal(["'NULL'", 201], @sth.fetch)
|
170
|
+
assert_equal([nil, 202], @sth.fetch)
|
171
|
+
assert_equal(["NULL", 203], @sth.fetch)
|
172
|
+
@sth.finish
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_time
|
177
|
+
@sth = nil
|
178
|
+
t = nil
|
179
|
+
assert_nothing_raised do
|
180
|
+
@sth = @dbh.prepare("insert into time_test (mytime) values (?)")
|
181
|
+
t = Time.now
|
182
|
+
@sth.execute(t)
|
183
|
+
@sth.finish
|
184
|
+
end
|
185
|
+
|
186
|
+
assert_nothing_raised do
|
187
|
+
@sth = @dbh.prepare("select * from time_test")
|
188
|
+
@sth.execute
|
189
|
+
row = @sth.fetch
|
190
|
+
assert_kind_of DateTime, row[0]
|
191
|
+
assert_equal t.hour, row[0].hour
|
192
|
+
assert_equal t.min, row[0].min
|
193
|
+
assert_equal t.sec, row[0].sec
|
194
|
+
@sth.finish
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_timestamp
|
199
|
+
@sth = nil
|
200
|
+
# We omit fractional second testing here -- timestamp precision
|
201
|
+
# is a very slippery, dependent on driver and driver version.
|
202
|
+
t = DBI::Timestamp.new(2008, 3, 8, 10, 39, 1)
|
203
|
+
assert_nothing_raised do
|
204
|
+
@sth = @dbh.prepare("insert into timestamp_test (mytimestamp) values (?)")
|
205
|
+
@sth.execute(t)
|
206
|
+
@sth.finish
|
207
|
+
end
|
208
|
+
|
209
|
+
assert_nothing_raised do
|
210
|
+
@sth = @dbh.prepare("select * from timestamp_test")
|
211
|
+
@sth.execute
|
212
|
+
row = @sth.fetch
|
213
|
+
assert_kind_of DateTime, row[0]
|
214
|
+
assert_equal t.year, row[0].year
|
215
|
+
assert_equal t.month, row[0].month
|
216
|
+
assert_equal t.day, row[0].day
|
217
|
+
assert_equal t.hour, row[0].hour
|
218
|
+
assert_equal t.min, row[0].min
|
219
|
+
assert_equal t.sec, row[0].sec
|
220
|
+
# omit fractional tests
|
221
|
+
@sth.finish
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_boolean_return
|
226
|
+
@sth = nil
|
227
|
+
|
228
|
+
unless dbtype == "odbc" # ODBC has no boolean type
|
229
|
+
assert_nothing_raised do
|
230
|
+
@sth = @dbh.prepare("insert into boolean_test (num, mybool) values (?, ?)")
|
231
|
+
@sth.execute(1, true)
|
232
|
+
@sth.execute(2, false)
|
233
|
+
@sth.finish
|
234
|
+
end
|
235
|
+
|
236
|
+
assert_nothing_raised do
|
237
|
+
@sth = @dbh.prepare("select * from boolean_test order by num")
|
238
|
+
@sth.execute
|
239
|
+
|
240
|
+
pairs = @sth.fetch_all
|
241
|
+
|
242
|
+
assert_equal(
|
243
|
+
[
|
244
|
+
[1, true],
|
245
|
+
[2, false],
|
246
|
+
], pairs
|
247
|
+
)
|
248
|
+
|
249
|
+
@sth.finish
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
DBDConfig.set_testbase(:sqlite, Class.new(Test::Unit::TestCase) do
|
5
|
+
|
6
|
+
def dbtype
|
7
|
+
"sqlite"
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_base
|
11
|
+
if @dbh # FIXME for some reason, @dbh isn't initialized in some cases. investigate.
|
12
|
+
assert_equal(@dbh.driver_name, "SQLite")
|
13
|
+
assert_kind_of(DBI::DBD::SQLite::Database, @dbh.instance_variable_get(:@handle))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_base_dbh
|
18
|
+
config = DBDConfig.get_config['sqlite']
|
19
|
+
@dbh = DBI.connect('dbi:SQLite:'+config['dbname'], nil, nil, { })
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup
|
23
|
+
set_base_dbh
|
24
|
+
DBDConfig.inject_sql(@dbh, dbtype, "dbd/sqlite/up.sql")
|
25
|
+
end
|
26
|
+
|
27
|
+
def teardown
|
28
|
+
@dbh.disconnect if @dbh.connected?
|
29
|
+
config = DBDConfig.get_config['sqlite']
|
30
|
+
FileUtils.rm_f(config['dbname'])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class TestSQLiteDatabase < DBDConfig.testbase(:sqlite)
|
2
|
+
def test_disconnect
|
3
|
+
assert_nil @dbh.disconnect
|
4
|
+
assert_nil @dbh.instance_variable_get("@db")
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_columns
|
8
|
+
assert_equal [
|
9
|
+
{
|
10
|
+
:name => "name",
|
11
|
+
:default => nil,
|
12
|
+
:nullable => true,
|
13
|
+
:precision => 255,
|
14
|
+
:type_name => "varchar"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
:name => "age",
|
18
|
+
:default => nil,
|
19
|
+
:nullable => true,
|
20
|
+
:type_name => "integer"
|
21
|
+
}
|
22
|
+
], @dbh.columns("names")
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class TestSQLiteDriver < DBDConfig.testbase(:sqlite)
|
2
|
+
def test_require
|
3
|
+
require 'dbd/SQLite'
|
4
|
+
assert_kind_of Module, DBI
|
5
|
+
assert_kind_of Module, DBI::DBD
|
6
|
+
assert_kind_of Class, DBI::DBD::SQLite
|
7
|
+
assert_kind_of Class, DBI::DBD::SQLite::Driver
|
8
|
+
assert_kind_of Class, DBI::DBD::SQLite::Database
|
9
|
+
assert_kind_of Class, DBI::DBD::SQLite::Statement
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_connect
|
13
|
+
config = DBDConfig.get_config['sqlite']
|
14
|
+
|
15
|
+
# this tests DBI more than SQLite, but makes sure our chain works with it.
|
16
|
+
dbh = DBI.connect("dbi:SQLite:" + config['dbname'], nil, nil, {})
|
17
|
+
assert dbh
|
18
|
+
assert_kind_of DBI::DatabaseHandle, dbh
|
19
|
+
|
20
|
+
# first argument should be a string
|
21
|
+
assert_raise(DBI::InterfaceError) do
|
22
|
+
DBI::DBD::SQLite::Driver.new.connect(nil, nil, nil, { })
|
23
|
+
end
|
24
|
+
|
25
|
+
# that string should have some frackin' length
|
26
|
+
assert_raise(DBI::InterfaceError) do
|
27
|
+
DBI::DBD::SQLite::Driver.new.connect("", nil, nil, { })
|
28
|
+
end
|
29
|
+
|
30
|
+
# last argument should be a hash
|
31
|
+
assert_raise(DBI::InterfaceError) do
|
32
|
+
DBI::DBD::SQLite::Driver.new.connect(config['dbname'], nil, nil, nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
dbh = nil
|
36
|
+
driver = nil
|
37
|
+
assert_nothing_raised do
|
38
|
+
driver = DBI::DBD::SQLite::Driver.new
|
39
|
+
dbh = driver.connect(config['dbname'], nil, nil, { })
|
40
|
+
end
|
41
|
+
|
42
|
+
assert_kind_of DBI::DBD::SQLite::Driver, driver
|
43
|
+
assert_kind_of DBI::DBD::SQLite::Database, dbh
|
44
|
+
|
45
|
+
assert !dbh.instance_variable_get("@autocommit")
|
46
|
+
|
47
|
+
dbh = nil
|
48
|
+
driver = nil
|
49
|
+
assert_nothing_raised do
|
50
|
+
dbh = DBI::DBD::SQLite::Driver.new.connect(config['dbname'], nil, nil, { "AutoCommit" => true, "sqlite_full_column_names" => true })
|
51
|
+
end
|
52
|
+
|
53
|
+
assert dbh
|
54
|
+
assert dbh.instance_variable_get("@attr_hash")
|
55
|
+
assert_equal 0, dbh.instance_variable_get("@open_handles")
|
56
|
+
assert_kind_of SQLite::Database, dbh.instance_variable_get("@db")
|
57
|
+
|
58
|
+
assert File.exists?(config['dbname'])
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
config = DBDConfig.get_config['sqlite']
|
66
|
+
FileUtils.rm_f(config['dbname'])
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class TestSQLiteStatement < DBDConfig.testbase(:sqlite)
|
2
|
+
def test_constructor
|
3
|
+
sth = DBI::DBD::SQLite::Statement.new("select * from foo", @dbh.instance_variable_get("@handle"))
|
4
|
+
|
5
|
+
assert_kind_of DBI::DBD::SQLite::Statement, sth
|
6
|
+
assert sth.instance_variable_get("@dbh")
|
7
|
+
assert_kind_of DBI::DBD::SQLite::Database, sth.instance_variable_get("@dbh")
|
8
|
+
assert_equal(@dbh.instance_variable_get("@handle"), sth.instance_variable_get("@dbh"))
|
9
|
+
assert_kind_of DBI::SQL::PreparedStatement, sth.instance_variable_get("@statement")
|
10
|
+
assert_equal({ }, sth.instance_variable_get("@attr"))
|
11
|
+
assert_equal([ ], sth.instance_variable_get("@params"))
|
12
|
+
assert_nil(sth.instance_variable_get("@result_set"))
|
13
|
+
assert_equal([ ], sth.instance_variable_get("@rows"))
|
14
|
+
|
15
|
+
sth = @dbh.prepare("select * from foo")
|
16
|
+
|
17
|
+
assert_kind_of DBI::StatementHandle, sth
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_bind_param
|
21
|
+
sth = DBI::DBD::SQLite::Statement.new("select * from foo", @dbh.instance_variable_get("@handle"))
|
22
|
+
|
23
|
+
assert_raise(DBI::InterfaceError) do
|
24
|
+
sth.bind_param(:foo, "monkeys")
|
25
|
+
end
|
26
|
+
|
27
|
+
# XXX this is fairly ugly, but...
|
28
|
+
# what i've attempted to do here is normalize what is tested, even
|
29
|
+
# though the data differs subtly. you'll notice that there are two
|
30
|
+
# arrays that get passed to the each block for evaluation. the first
|
31
|
+
# argument is the statment handle (raw from SQLite DBD or the facade
|
32
|
+
# from DBI), the second is how we access the @params internally held
|
33
|
+
# variable, and the third is how these params are scrubbed before we
|
34
|
+
# assert against them.
|
35
|
+
#
|
36
|
+
# the @params variable is in different spots in both statement handles
|
37
|
+
# and the values of the params are quoted differently. However, the
|
38
|
+
# full pipe works and I'd like to ensure that both do their job as a
|
39
|
+
# team.
|
40
|
+
#
|
41
|
+
[
|
42
|
+
[
|
43
|
+
sth,
|
44
|
+
proc { |x| x.instance_variable_get("@params") },
|
45
|
+
proc { |x| x }
|
46
|
+
],
|
47
|
+
[
|
48
|
+
@dbh.prepare("select * from foo"),
|
49
|
+
proc { |x| x.instance_variable_get("@handle").instance_variable_get("@params") },
|
50
|
+
proc { |x| x.gsub(/(^')|('$)/, '') }
|
51
|
+
]
|
52
|
+
].each do |sthpack|
|
53
|
+
sthpack[0].bind_param(1, "monkeys", nil)
|
54
|
+
|
55
|
+
params = sthpack[1].call(sthpack[0])
|
56
|
+
|
57
|
+
assert_equal "monkeys", sthpack[2].call(params[0])
|
58
|
+
|
59
|
+
# set a bunch of stuff.
|
60
|
+
%w(I like monkeys).each_with_index { |x, i| sthpack[0].bind_param(i+1, x) }
|
61
|
+
|
62
|
+
params = sthpack[1].call(sthpack[0])
|
63
|
+
|
64
|
+
assert_equal %w(I like monkeys), params.collect { |x| sthpack[2].call(x) }
|
65
|
+
|
66
|
+
# FIXME what to do with attributes? are they important in SQLite?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_column_info
|
71
|
+
sth = nil
|
72
|
+
|
73
|
+
assert_nothing_raised do
|
74
|
+
sth = @dbh.prepare("select * from names")
|
75
|
+
sth.execute
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_kind_of Array, sth.column_info
|
79
|
+
assert_kind_of DBI::ColumnInfo, sth.column_info[0]
|
80
|
+
assert_kind_of DBI::ColumnInfo, sth.column_info[1]
|
81
|
+
assert_equal [
|
82
|
+
{
|
83
|
+
:name => "name",
|
84
|
+
:sql_type => 12,
|
85
|
+
:precision => 255,
|
86
|
+
:type_name => "varchar"
|
87
|
+
},
|
88
|
+
{
|
89
|
+
:name => "age",
|
90
|
+
:sql_type => 4,
|
91
|
+
:type_name => "integer"
|
92
|
+
}
|
93
|
+
], sth.column_info
|
94
|
+
|
95
|
+
sth.finish
|
96
|
+
end
|
97
|
+
end
|