fb 0.5.4
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/README +218 -0
- data/extconf.rb +48 -0
- data/fb.c +3008 -0
- data/test/ConnectionTestCases.rb +462 -0
- data/test/CursorTestCases.rb +235 -0
- data/test/DataTypesTestCases.rb +428 -0
- data/test/DatabaseTestCases.rb +180 -0
- data/test/FbTestCases.rb +33 -0
- data/test/FbTestSuite.rb +8 -0
- data/test/TransactionTestCases.rb +259 -0
- metadata +67 -0
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/FbTestCases'
|
3
|
+
require 'fb'
|
4
|
+
include Fb
|
5
|
+
|
6
|
+
class DatabaseTestCases < Test::Unit::TestCase
|
7
|
+
include FbTestCases
|
8
|
+
|
9
|
+
def setup
|
10
|
+
super
|
11
|
+
@database = "localhost:#{@db_file}"
|
12
|
+
@reader = {
|
13
|
+
:database => "localhost:#{@db_file}",
|
14
|
+
:username => 'rubytest',
|
15
|
+
:password => 'rubytest',
|
16
|
+
:charset => 'NONE',
|
17
|
+
:role => 'READER' }
|
18
|
+
@writer = {
|
19
|
+
:database => "localhost:#{@db_file}",
|
20
|
+
:username => 'rubytest',
|
21
|
+
:password => 'rubytest',
|
22
|
+
:charset => 'NONE',
|
23
|
+
:role => 'WRITER' }
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_new
|
27
|
+
db = Database.new
|
28
|
+
assert_instance_of Database, db
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_properties_read
|
32
|
+
db = Database.new
|
33
|
+
assert_nil db.database
|
34
|
+
assert_nil db.username
|
35
|
+
assert_nil db.password
|
36
|
+
assert_nil db.charset
|
37
|
+
assert_nil db.role
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_properties_write
|
41
|
+
db = Database.new
|
42
|
+
db.database = @database
|
43
|
+
assert_equal @database, db.database
|
44
|
+
db.username = 'sysdba'
|
45
|
+
assert_equal 'sysdba', db.username
|
46
|
+
db.password = 'masterkey'
|
47
|
+
assert_equal 'masterkey', db.password
|
48
|
+
db.charset = 'NONE'
|
49
|
+
assert_equal 'NONE', db.charset
|
50
|
+
db.role = 'READER'
|
51
|
+
assert_equal 'READER', db.role
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_initialize_hash
|
55
|
+
db = Database.new(@parms)
|
56
|
+
assert_equal @database, db.database
|
57
|
+
assert_equal 'sysdba', db.username
|
58
|
+
assert_equal 'masterkey', db.password
|
59
|
+
assert_equal 'NONE', db.charset
|
60
|
+
assert_equal 'READER', db.role
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_initialize_string
|
64
|
+
db = Database.new(@parms_s)
|
65
|
+
assert_equal @database, db.database
|
66
|
+
assert_equal 'sysdba', db.username
|
67
|
+
assert_equal 'masterkey', db.password
|
68
|
+
assert_equal 'NONE', db.charset
|
69
|
+
assert_equal 'READER', db.role
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_create_instance
|
73
|
+
db = Database.new(@parms)
|
74
|
+
db.create
|
75
|
+
assert File.exists?(@db_file)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_create_instance_block
|
79
|
+
db = Database.new(@parms)
|
80
|
+
db.create do |connection|
|
81
|
+
connection.execute("select * from RDB$DATABASE") do |cursor|
|
82
|
+
row = cursor.fetch
|
83
|
+
assert_instance_of Array, row
|
84
|
+
end
|
85
|
+
assert_equal 3, connection.dialect
|
86
|
+
assert_equal 3, connection.db_dialect
|
87
|
+
end
|
88
|
+
assert File.exists?(@db_file)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_create_singleton
|
92
|
+
db = Database.create(@parms);
|
93
|
+
assert File.exists?(@db_file)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_create_singleton_with_defaults
|
97
|
+
db = Database.create(:database => "localhost:#{@db_file}");
|
98
|
+
assert File.exists?(@db_file)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_create_singleton_block
|
102
|
+
db = Database.create(@parms) do |connection|
|
103
|
+
connection.execute("select * from RDB$DATABASE") do |cursor|
|
104
|
+
row = cursor.fetch
|
105
|
+
assert_instance_of Array, row
|
106
|
+
end
|
107
|
+
end
|
108
|
+
assert_instance_of Database, db
|
109
|
+
assert File.exists?(@db_file)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_create_bad_param
|
113
|
+
assert_raise TypeError do
|
114
|
+
db = Database.create(1)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_create_bad_page_size
|
119
|
+
assert_raise Error do
|
120
|
+
db = Database.create(@parms.merge(:page_size => 1000))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_connect_instance
|
125
|
+
db = Database.create(@parms)
|
126
|
+
connection = db.connect
|
127
|
+
assert_instance_of Connection, connection
|
128
|
+
connection.close
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_connect_singleton
|
132
|
+
db = Database.create(@parms)
|
133
|
+
connection = Database.connect(@parms)
|
134
|
+
assert_instance_of Connection, connection
|
135
|
+
connection.close
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_drop_instance
|
139
|
+
assert !File.exists?(@db_file)
|
140
|
+
db = Database.create(@parms)
|
141
|
+
assert File.exists?(@db_file)
|
142
|
+
db.drop
|
143
|
+
assert !File.exists?(@db_file)
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_drop_singleton
|
147
|
+
assert !File.exists?(@db_file)
|
148
|
+
Database.create(@parms)
|
149
|
+
assert File.exists?(@db_file)
|
150
|
+
Database.drop(@parms)
|
151
|
+
assert !File.exists?(@db_file)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_role_support
|
155
|
+
Database.create(@parms) do |connection|
|
156
|
+
connection.execute("create table test (id int, test varchar(10))")
|
157
|
+
connection.execute("create role writer")
|
158
|
+
connection.execute("grant all on test to writer")
|
159
|
+
connection.execute("grant writer to rubytest")
|
160
|
+
connection.commit
|
161
|
+
connection.execute("insert into test values (1, 'test role')")
|
162
|
+
end
|
163
|
+
Database.connect(@reader) do |connection|
|
164
|
+
assert_raise Error do
|
165
|
+
connection.execute("select * from test") do |cursor|
|
166
|
+
flunk "Should not reach here."
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
Database.connect(@writer) do |connection|
|
171
|
+
connection.execute("select * from test") do |cursor|
|
172
|
+
row = cursor.fetch :hash
|
173
|
+
assert_equal 1, row["ID"]
|
174
|
+
assert_equal 'test role', row["TEST"]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
Database.drop(@parms)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
data/test/FbTestCases.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
module FbTestCases
|
5
|
+
def setup
|
6
|
+
@db_file = case RUBY_PLATFORM
|
7
|
+
when /win32/ then 'c:/var/fbdata/drivertest.fdb'
|
8
|
+
when /darwin/ then '/var/fbdata/drivertest.fdb'
|
9
|
+
else '/var/fbdata/drivertest.fdb'
|
10
|
+
end
|
11
|
+
@db_host = 'localhost'
|
12
|
+
@parms = {
|
13
|
+
:database => "#{@db_host}:#{@db_file}",
|
14
|
+
:username => 'sysdba',
|
15
|
+
:password => 'masterkey',
|
16
|
+
:charset => 'NONE',
|
17
|
+
:role => 'READER' }
|
18
|
+
@parms_s = "database = #{@db_host}:#{@db_file}; username = sysdba; password = masterkey; charset = NONE; role = READER;"
|
19
|
+
rm_rf @db_file
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'fb'
|
24
|
+
|
25
|
+
class Fb::Connection
|
26
|
+
def execute_script(sql_schema)
|
27
|
+
self.transaction do
|
28
|
+
sql_schema.strip.split(';').each do |stmt|
|
29
|
+
self.execute(stmt);
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/test/FbTestSuite.rb
ADDED
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/FbTestCases'
|
3
|
+
require 'fb'
|
4
|
+
include Fb
|
5
|
+
|
6
|
+
class TransactionTestCases < Test::Unit::TestCase
|
7
|
+
include FbTestCases
|
8
|
+
|
9
|
+
def test_transaction
|
10
|
+
Database.create(@parms) do |connection|
|
11
|
+
n = 0
|
12
|
+
assert !connection.transaction_started
|
13
|
+
connection.transaction
|
14
|
+
assert connection.transaction_started
|
15
|
+
connection.commit
|
16
|
+
assert !connection.transaction_started
|
17
|
+
connection.transaction
|
18
|
+
assert connection.transaction_started
|
19
|
+
connection.rollback
|
20
|
+
assert !connection.transaction_started
|
21
|
+
connection.drop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_transaction_block
|
26
|
+
Database.create(@parms) do |connection|
|
27
|
+
n = 0
|
28
|
+
assert !connection.transaction_started
|
29
|
+
connection.transaction do
|
30
|
+
assert connection.transaction_started
|
31
|
+
end
|
32
|
+
assert !connection.transaction_started
|
33
|
+
assert_raise RuntimeError do
|
34
|
+
connection.transaction do
|
35
|
+
assert connection.transaction_started
|
36
|
+
raise "generic exception"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
assert !connection.transaction_started
|
40
|
+
connection.drop
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_auto_transaction_select_with_exception
|
45
|
+
sql_select = "SELECT * FROM RDB$DATABASE"
|
46
|
+
Database.create(@parms) do |connection|
|
47
|
+
assert !connection.transaction_started
|
48
|
+
assert_raise RuntimeError do
|
49
|
+
connection.execute(sql_select) do |cursor|
|
50
|
+
assert connection.transaction_started
|
51
|
+
raise "abort"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
assert !connection.transaction_started
|
55
|
+
connection.drop
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_auto_transaction_insert_with_exception
|
60
|
+
sql_schema = "CREATE TABLE TEST (ID INT NOT NULL PRIMARY KEY, NAME VARCHAR(20))"
|
61
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
62
|
+
Database.create(@parms) do |connection|
|
63
|
+
connection.execute(sql_schema)
|
64
|
+
assert !connection.transaction_started
|
65
|
+
connection.execute(sql_insert, 1, "one")
|
66
|
+
assert !connection.transaction_started
|
67
|
+
assert_raise Error do
|
68
|
+
connection.execute(sql_insert, 1, "two")
|
69
|
+
end
|
70
|
+
assert !connection.transaction_started, "transaction is active"
|
71
|
+
connection.drop
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_auto_transaction_query
|
76
|
+
Database.create(@parms) do |connection|
|
77
|
+
assert !connection.transaction_started
|
78
|
+
rs = connection.query("select * from rdb$database")
|
79
|
+
assert !connection.transaction_started
|
80
|
+
connection.drop
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_query_in_transaction
|
85
|
+
Database.create(@parms) do |connection|
|
86
|
+
assert !connection.transaction_started
|
87
|
+
connection.transaction do
|
88
|
+
assert connection.transaction_started
|
89
|
+
rs = connection.query("select * from rdb$database")
|
90
|
+
assert connection.transaction_started
|
91
|
+
end
|
92
|
+
assert !connection.transaction_started
|
93
|
+
connection.drop
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_insert_commit
|
98
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
99
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
100
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
101
|
+
Database.create(@parms) do |connection|
|
102
|
+
connection.execute(sql_schema);
|
103
|
+
connection.transaction
|
104
|
+
10.times do |i|
|
105
|
+
connection.execute(sql_insert, i, i.to_s);
|
106
|
+
end
|
107
|
+
connection.commit
|
108
|
+
connection.execute(sql_select) do |cursor|
|
109
|
+
rows = cursor.fetchall
|
110
|
+
assert_equal 10, rows.size
|
111
|
+
10.times do |i|
|
112
|
+
assert_equal i, rows[i][0]
|
113
|
+
assert_equal i.to_s, rows[i][1]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
connection.drop
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_insert_rollback
|
121
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
122
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
123
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
124
|
+
Database.create(@parms) do |connection|
|
125
|
+
connection.execute(sql_schema)
|
126
|
+
connection.transaction
|
127
|
+
10.times do |i|
|
128
|
+
connection.execute(sql_insert, i, i.to_s);
|
129
|
+
end
|
130
|
+
connection.rollback
|
131
|
+
rows = connection.execute(sql_select) do |cursor| cursor.fetchall end
|
132
|
+
assert_equal 0, rows.size
|
133
|
+
connection.drop
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_transaction_block_insert_commit
|
138
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
139
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
140
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
141
|
+
Database.create(@parms) do |connection|
|
142
|
+
connection.execute(sql_schema);
|
143
|
+
assert !connection.transaction_started
|
144
|
+
result = connection.transaction do
|
145
|
+
assert connection.transaction_started
|
146
|
+
10.times do |i|
|
147
|
+
connection.execute(sql_insert, i, i.to_s);
|
148
|
+
end
|
149
|
+
assert connection.transaction_started
|
150
|
+
"transaction block result"
|
151
|
+
end
|
152
|
+
assert_equal "transaction block result", result
|
153
|
+
assert !connection.transaction_started
|
154
|
+
connection.execute(sql_select) do |cursor|
|
155
|
+
assert_equal 10, cursor.fetchall.size
|
156
|
+
end
|
157
|
+
connection.drop
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_transaction_block_insert_rollback
|
162
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
163
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
164
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
165
|
+
Database.create(@parms) do |connection|
|
166
|
+
connection.execute(sql_schema)
|
167
|
+
assert !connection.transaction_started
|
168
|
+
assert_raise RuntimeError do
|
169
|
+
connection.transaction do
|
170
|
+
10.times do |i|
|
171
|
+
connection.execute(sql_insert, i, i.to_s);
|
172
|
+
end
|
173
|
+
raise "Raise an exception, causing the transaction to be rolled back."
|
174
|
+
end
|
175
|
+
end
|
176
|
+
rows = connection.execute(sql_select) do |cursor| cursor.fetchall end
|
177
|
+
assert_equal 0, rows.size
|
178
|
+
connection.drop
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_simultaneous_transactions
|
183
|
+
db_file1 = "#{@db_file}1"
|
184
|
+
db_file2 = "#{@db_file}2"
|
185
|
+
rm_rf db_file1
|
186
|
+
rm_rf db_file2
|
187
|
+
parms1 = @parms.merge(:database => "#{@db_host}:#{db_file1}")
|
188
|
+
parms2 = @parms.merge(:database => "#{@db_host}:#{db_file2}")
|
189
|
+
Database.create(parms1) do |conn1|
|
190
|
+
Database.create(parms2) do |conn2|
|
191
|
+
assert !conn1.transaction_started, "conn1 transaction is started"
|
192
|
+
assert !conn2.transaction_started, "conn2 transaction is started"
|
193
|
+
conn1.transaction do
|
194
|
+
assert conn1.transaction_started, "conn1 transaction is not started"
|
195
|
+
assert !conn2.transaction_started, "conn2 transaction is started"
|
196
|
+
conn2.transaction do
|
197
|
+
assert conn2.transaction_started, "conn2 transaction is not started"
|
198
|
+
assert conn1.transaction_started, "conn1 transaction is not started"
|
199
|
+
end
|
200
|
+
assert !conn2.transaction_started, "conn2 transaction is still active"
|
201
|
+
assert conn1.transaction_started, "conn1 transaction is not still active"
|
202
|
+
end
|
203
|
+
assert !conn1.transaction_started, "conn1 transaction is still active"
|
204
|
+
conn2.drop
|
205
|
+
end
|
206
|
+
conn1.drop
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_transaction_options_snapshot
|
211
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
212
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
213
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
214
|
+
sql_delete = "DELETE FROM TEST WHERE ID < ?"
|
215
|
+
Database.create(@parms) do |conn1|
|
216
|
+
conn1.execute(sql_schema)
|
217
|
+
conn1.transaction do
|
218
|
+
10.times do |i|
|
219
|
+
conn1.execute(sql_insert, i, "NAME#{i}")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
Database.connect(@parms) do |conn2|
|
223
|
+
conn2.transaction("SNAPSHOT") do
|
224
|
+
affected = conn1.execute(sql_delete, 5)
|
225
|
+
assert_equal 5, affected
|
226
|
+
rs1 = conn2.query(sql_select)
|
227
|
+
assert_equal 10, rs1.size
|
228
|
+
end
|
229
|
+
rs2 = conn2.query(sql_select)
|
230
|
+
assert_equal 5, rs2.size
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_transaction_options_read_committed
|
236
|
+
sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
|
237
|
+
sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
|
238
|
+
sql_select = "SELECT * FROM TEST ORDER BY ID"
|
239
|
+
sql_delete = "DELETE FROM TEST WHERE ID < ?"
|
240
|
+
Database.create(@parms) do |conn1|
|
241
|
+
conn1.execute(sql_schema)
|
242
|
+
conn1.transaction do
|
243
|
+
10.times do |i|
|
244
|
+
conn1.execute(sql_insert, i, "NAME#{i}")
|
245
|
+
end
|
246
|
+
end
|
247
|
+
Database.connect(@parms) do |conn2|
|
248
|
+
conn2.transaction("READ COMMITTED") do
|
249
|
+
affected = conn1.execute(sql_delete, 5)
|
250
|
+
assert_equal 5, affected
|
251
|
+
rs1 = conn2.query(sql_select)
|
252
|
+
assert_equal 5, rs1.size
|
253
|
+
end
|
254
|
+
rs2 = conn2.query(sql_select)
|
255
|
+
assert_equal 5, rs2.size
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|