firebird 0.10.0

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.
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fb/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "firebird"
8
+ s.version = Fb::VERSION
9
+ s.date = "2019-06-08"
10
+ s.summary = "Firebird database driver"
11
+ s.description = "Ruby Firebird Extension Library"
12
+ s.licenses = ["MIT"]
13
+ s.requirements = "Firebird client library fbclient.dll, libfbclient.so or Firebird.framework."
14
+ s.require_paths = ["lib", "ext"]
15
+ s.author = "Popa Adrian Marius"
16
+ s.email = "mapopa@gmail.com"
17
+ s.homepage = "http://github.com/mariuz/fb"
18
+ # s.has_rdoc = true
19
+ # s.extra_rdoc_files = ['README']
20
+ # s.rdoc_options << '--title' << 'Fb -- Ruby Firebird Extension' << '--main' << 'README' << '-x' << 'test'
21
+ # s.files = ['ext/fb/extconf.rb', 'ext/fb/fb.c', 'README', 'lib/fb.rb'] + Dir.glob("test/*.rb")
22
+ s.files = `git ls-files`.split($/)
23
+ s.platform = case RUBY_PLATFORM
24
+ when /win32/ then Gem::Platform::WIN32
25
+ else
26
+ Gem::Platform::RUBY
27
+ end
28
+ s.extensions = ['ext/fb/extconf.rb'] if s.platform == Gem::Platform::RUBY
29
+ s.add_development_dependency "rake", ">= 0"
30
+ s.add_development_dependency "rake-compiler", ">= 0"
31
+ if RUBY_VERSION =~ /^2/
32
+ s.add_development_dependency "minitest", ">= 0"
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ require 'fb/fb_ext'
2
+
3
+ module Fb
4
+ class Connection
5
+ def execute_script(sql)
6
+ stmts = []
7
+ delim = ';'
8
+ while sql =~ /\S/
9
+ stmt, sql = sql.split(delim, 2)
10
+ if stmt =~ /^\s*set\s+term\s+(\S+)/i
11
+ delim = $1
12
+ elsif stmt =~ /\S/
13
+ stmts << stmt
14
+ end
15
+ end
16
+ self.transaction do
17
+ stmts.each do |stmt|
18
+ self.execute(stmt)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Fb
2
+ VERSION = "0.10.0"
3
+ end
@@ -0,0 +1 @@
1
+ ruby extconf.rb --with-opt-dir=c:/Firebird --with-dotnet-dir=C:\PROGRA~1\MICROS~2.NET\Vc7 --with-win32-dir=C:\PROGRA~1\MI9547~1
@@ -0,0 +1,550 @@
1
+ require File.expand_path("../test_helper", __FILE__)
2
+
3
+ class ConnectionTestCases < FbTestCase
4
+ def test_execute
5
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
6
+ sql_select = "SELECT * FROM RDB$DATABASE"
7
+ Database.create(@parms) do |connection|
8
+ assert !connection.transaction_started
9
+ connection.execute(sql_schema)
10
+ connection.execute(sql_select)
11
+ assert connection.transaction_started
12
+ connection.commit
13
+ assert !connection.transaction_started
14
+ connection.drop
15
+ end
16
+ end
17
+
18
+ def test_query_select
19
+ sql_select = "SELECT * FROM RDB$DATABASE"
20
+ Database.create(@parms) do |connection|
21
+
22
+ d = connection.query(sql_select)
23
+ assert_instance_of Array, d
24
+ assert_equal 1, d.size
25
+ assert_instance_of Array, d.first
26
+ if @fb_version == 3
27
+ assert_equal 5, d.first.size
28
+ else
29
+ assert_equal 4, d.first.size
30
+ end
31
+
32
+ a = connection.query(:array, sql_select)
33
+ assert_instance_of Array, a
34
+ assert_equal 1, a.size
35
+ assert_instance_of Array, a.first
36
+ if @fb_version == 3
37
+ assert_equal 5, a.first.size
38
+ else
39
+ assert_equal 4, a.first.size
40
+ end
41
+
42
+ h = connection.query(:hash, sql_select)
43
+ assert_instance_of Array, h
44
+ assert_equal 1, h.size
45
+ assert_instance_of Hash, h.first
46
+ if @fb_version == 3
47
+ assert_equal 5, h.first.keys.size
48
+ else
49
+ assert_equal 4, h.first.keys.size
50
+ end
51
+ assert h.first.keys.include?("RDB$DESCRIPTION")
52
+ assert h.first.keys.include?("RDB$RELATION_ID")
53
+ assert h.first.keys.include?("RDB$SECURITY_CLASS")
54
+ assert h.first.keys.include?("RDB$CHARACTER_SET_NAME")
55
+ if @fb_version == 3
56
+ assert h.first.keys.include?("RDB$LINGER")
57
+ end
58
+ end
59
+ end
60
+
61
+ def test_query_update
62
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
63
+ sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
64
+ sql_update = "UPDATE TEST SET ID = ?, NAME = ? WHERE ID = ?"
65
+ sql_delete = "DELETE FROM TEST WHERE ID = ?"
66
+ sql_select = "SELECT * FROM TEST"
67
+ Database.create(@parms) do |connection|
68
+ su = connection.query(sql_schema)
69
+ assert_equal(-1, su)
70
+
71
+ i = connection.query(sql_insert, 1, "NAME")
72
+ assert_equal 1, i
73
+
74
+ u = connection.query(sql_update, 1, "NAME2", 1)
75
+ assert_equal 1, u
76
+
77
+ d = connection.query(sql_delete, 1)
78
+ assert_equal 1, d
79
+
80
+ q = connection.query(sql_select)
81
+ assert_instance_of Array, q
82
+ assert_equal 0, q.size
83
+ end
84
+ end
85
+
86
+ def test_insert_blobs_text
87
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20), MEMO BLOB SUB_TYPE TEXT)"
88
+ sql_insert = "INSERT INTO TEST (ID, NAME, MEMO) VALUES (?, ?, ?)"
89
+ sql_select = "SELECT * FROM TEST ORDER BY ID"
90
+ Database.create(@parms) do |connection|
91
+ connection.execute(sql_schema);
92
+ memo = "x" * 65535
93
+ assert memo.size > 50000
94
+ connection.transaction do
95
+ 10.times do |i|
96
+ connection.execute(sql_insert, i, i.to_s, memo);
97
+ end
98
+ end
99
+ connection.execute(sql_select) do |cursor|
100
+ i = 0
101
+ cursor.each :hash do |row|
102
+ assert_equal i, row["ID"]
103
+ assert_equal i.to_s, row["NAME"]
104
+ assert_equal memo, row["MEMO"]
105
+ i += 1
106
+ end
107
+ end
108
+ connection.drop
109
+ end
110
+ end
111
+
112
+ def test_insert_blobs_binary
113
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20), ATTACHMENT BLOB SEGMENT SIZE 1000)"
114
+ sql_insert = "INSERT INTO TEST (ID, NAME, ATTACHMENT) VALUES (?, ?, ?)"
115
+ sql_select = "SELECT * FROM TEST ORDER BY ID"
116
+ Database.create(@parms) do |connection|
117
+ connection.execute(sql_schema);
118
+ attachment = SecureRandom.random_bytes(250_000)
119
+ connection.transaction do
120
+ 3.times do |i|
121
+ connection.execute(sql_insert, i, i.to_s, attachment);
122
+ end
123
+ end
124
+ connection.execute(sql_select) do |cursor|
125
+ i = 0
126
+ cursor.each :array do |row|
127
+ assert_equal i, row[0], "ID's do not match"
128
+ assert_equal i.to_s, row[1], "NAME's do not match"
129
+ assert_equal attachment.size, row[2].size, "ATTACHMENT sizes do not match"
130
+ i += 1
131
+ end
132
+ end
133
+ connection.drop
134
+ end
135
+ end
136
+
137
+ def test_rows_affected
138
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
139
+ sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
140
+ sql_update = "UPDATE TEST SET NAME = 'no name' WHERE ID < ?"
141
+ sql_delete = "DELETE FROM TEST WHERE ID > ?"
142
+ sql_select = "SELECT * FROM TEST"
143
+ Database.create(@parms) do |connection|
144
+ connection.execute(sql_schema)
145
+ connection.transaction do
146
+ 10.times do |i|
147
+ affected = connection.execute(sql_insert, i, "name");
148
+ assert_equal 1, affected
149
+ end
150
+ end
151
+ affected = connection.execute(sql_update, 5)
152
+ assert_equal 5, affected
153
+ affected = connection.execute(sql_delete, 5)
154
+ assert_equal 4, affected
155
+ rows = connection.execute(sql_select) do |cursor| cursor.fetchall end
156
+ assert_equal 6, rows.size
157
+ end
158
+ end
159
+
160
+ def test_multi_insert
161
+ sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
162
+ sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
163
+ sql_select = "SELECT * FROM TEST"
164
+ sql_data = [
165
+ [1, "Name 1"],
166
+ [2, "Name 2"],
167
+ [3, "Name 3"]]
168
+ sql_data1 = [4, "Name 4"]
169
+ sql_data2 = [5, "Name 5"]
170
+ sql_data3 = [6, "Name 6"]
171
+ Database.create(@parms) do |connection|
172
+ connection.execute(sql_schema)
173
+ connection.execute(sql_insert, sql_data)
174
+ rs = connection.query(sql_select)
175
+ assert_equal 3, rs.size
176
+
177
+ connection.execute(sql_insert, sql_data1, sql_data2, sql_data3)
178
+ rs = connection.query(sql_select)
179
+ assert_equal 6, rs.size
180
+ end
181
+ end
182
+
183
+ def test_dialects
184
+ Database.create(@parms) do |connection|
185
+ assert_equal 3, connection.dialect
186
+ assert_equal 3, connection.db_dialect
187
+ connection.drop
188
+ end
189
+ end
190
+
191
+ def test_open?
192
+ db = Database.create(@parms);
193
+ connection = db.connect
194
+ assert connection.open?
195
+ connection.close
196
+ assert !connection.open?
197
+ db.drop
198
+ end
199
+
200
+ def test_properties_instance
201
+ db = Database.new(@parms)
202
+ db.create
203
+ db.connect do |connection|
204
+ assert_equal @parms[:database], connection.database
205
+ assert_equal @parms[:username], connection.username
206
+ assert_equal @parms[:password], connection.password
207
+ assert_equal @parms[:role], connection.role
208
+ assert_equal @parms[:charset], connection.charset
209
+ connection.drop
210
+ end
211
+ end
212
+
213
+ def test_properties_singleton
214
+ Database.create(@parms) do |connection|
215
+ assert_equal @parms[:database], connection.database
216
+ assert_equal @parms[:username], connection.username
217
+ assert_equal @parms[:password], connection.password
218
+ assert_equal @parms[:role], connection.role
219
+ assert_equal @parms[:charset], connection.charset
220
+ connection.drop
221
+ end
222
+ end
223
+
224
+ def test_drop_instance
225
+ db = Database.create(@parms)
226
+ assert File.exist?(@db_file)
227
+ connection = db.connect
228
+ assert connection.open?
229
+ connection.drop
230
+ assert !connection.open?
231
+ assert !File.exist?(@db_file)
232
+ end
233
+
234
+ def test_drop_singleton
235
+ Database.create(@parms) do |connection|
236
+ assert File.exist?(@db_file)
237
+ connection.drop
238
+ assert !File.exist?(@db_file)
239
+ end
240
+ end
241
+
242
+ def test_to_s
243
+ db = Database.new(@parms)
244
+ db.create
245
+ connection = db.connect
246
+ begin
247
+ assert_equal "#{@parms[:database]} (OPEN)", connection.to_s
248
+ ensure
249
+ connection.close
250
+ assert_equal "#{@parms[:database]} (CLOSED)", connection.to_s
251
+ end
252
+ end
253
+
254
+ def test_table_names
255
+ sql_schema = <<-END
256
+ CREATE TABLE TEST1 (ID INT);
257
+ CREATE TABLE TEST2 (ID INT);
258
+ END
259
+ Database.create(@parms) do |connection|
260
+ connection.execute_script(sql_schema)
261
+ table_names = connection.table_names
262
+ assert_equal 'TEST1', table_names[0]
263
+ assert_equal 'TEST2', table_names[1]
264
+ end
265
+ end
266
+
267
+ def test_table_names_downcased
268
+ sql_schema = <<-END
269
+ CREATE TABLE TEST1 (ID INT);
270
+ CREATE TABLE "Test2" (ID INT);
271
+ END
272
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
273
+ connection.execute_script(sql_schema)
274
+ table_names = connection.table_names
275
+ assert_equal 'test1', table_names[0]
276
+ assert_equal 'Test2', table_names[1]
277
+ end
278
+ end
279
+
280
+ def test_generator_names
281
+ sql_schema = <<-END
282
+ CREATE GENERATOR TEST1_SEQ;
283
+ CREATE GENERATOR TEST2_SEQ;
284
+ END
285
+ Database.create(@parms) do |connection|
286
+ connection.execute_script(sql_schema)
287
+ names = connection.generator_names
288
+ assert_equal 'TEST1_SEQ', names[0]
289
+ assert_equal 'TEST2_SEQ', names[1]
290
+ end
291
+ end
292
+
293
+ def test_generator_names_downcased
294
+ sql_schema = <<-END
295
+ CREATE GENERATOR TEST1_SEQ;
296
+ CREATE GENERATOR "TEST2_seq";
297
+ END
298
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
299
+ connection.execute_script(sql_schema)
300
+ names = connection.generator_names
301
+ assert_equal 'test1_seq', names[0]
302
+ assert_equal 'TEST2_seq', names[1]
303
+ end
304
+ end
305
+
306
+ def test_view_names
307
+ sql_schema = <<-END
308
+ CREATE TABLE TEST1 (ID INT, NAME1 VARCHAR(10));
309
+ CREATE TABLE TEST2 (ID INT, NAME2 VARCHAR(10));
310
+ CREATE VIEW VIEW1 AS SELECT TEST1.ID, TEST1.NAME1, TEST2.NAME2 FROM TEST1 JOIN TEST2 ON TEST1.ID = TEST2.ID;
311
+ CREATE VIEW VIEW2 AS SELECT TEST2.ID, TEST1.NAME1, TEST2.NAME2 FROM TEST1 JOIN TEST2 ON TEST1.NAME1 = TEST2.NAME2;
312
+ END
313
+ Database.create(@parms) do |connection|
314
+ connection.execute_script(sql_schema)
315
+ names = connection.view_names
316
+ assert_equal 'VIEW1', names[0]
317
+ assert_equal 'VIEW2', names[1]
318
+ end
319
+ end
320
+
321
+ def test_view_names_downcased
322
+ sql_schema = <<-END
323
+ CREATE TABLE TEST1 (ID INT, NAME1 VARCHAR(10));
324
+ CREATE TABLE TEST2 (ID INT, NAME2 VARCHAR(10));
325
+ CREATE VIEW VIEW1 AS SELECT TEST1.ID, TEST1.NAME1, TEST2.NAME2 FROM TEST1 JOIN TEST2 ON TEST1.ID = TEST2.ID;
326
+ CREATE VIEW "View2" AS SELECT TEST2.ID, TEST1.NAME1, TEST2.NAME2 FROM TEST1 JOIN TEST2 ON TEST1.NAME1 = TEST2.NAME2;
327
+ END
328
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
329
+ connection.execute_script(sql_schema)
330
+ names = connection.view_names
331
+ assert_equal 'view1', names[0]
332
+ assert_equal 'View2', names[1]
333
+ end
334
+ end
335
+
336
+ def test_role_names
337
+ sql_schema = <<-END
338
+ create role reader;
339
+ create role writer;
340
+ END
341
+ Database.create(@parms) do |connection|
342
+ connection.execute_script(sql_schema)
343
+ names = connection.role_names
344
+ assert_equal 'READER', names[0]
345
+ assert_equal 'WRITER', names[1]
346
+ end
347
+ end
348
+
349
+ def test_role_names_downcased
350
+ sql_schema = <<-END
351
+ create role reader;
352
+ create role writer;
353
+ END
354
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
355
+ connection.execute_script(sql_schema)
356
+ names = connection.role_names
357
+ assert_equal 'reader', names[0]
358
+ assert_equal 'writer', names[1]
359
+ end
360
+ end
361
+
362
+ def test_procedure_names
363
+ sql_schema = <<-END_SQL
364
+ CREATE PROCEDURE PLUSONE(NUM1 INTEGER) RETURNS (NUM2 INTEGER) AS
365
+ BEGIN
366
+ NUM2 = NUM1 + 1;
367
+ SUSPEND;
368
+ END;
369
+ END_SQL
370
+ Database.create(@parms) do |connection|
371
+ connection.execute(sql_schema)
372
+ names = connection.procedure_names
373
+ assert_equal 'PLUSONE', names[0]
374
+ end
375
+ end
376
+
377
+ def test_procedure_names_downcased
378
+ sql_schema = <<-END_SQL
379
+ CREATE PROCEDURE PLUSONE(NUM1 INTEGER) RETURNS (NUM2 INTEGER) AS
380
+ BEGIN
381
+ NUM2 = NUM1 + 1;
382
+ SUSPEND;
383
+ END;
384
+ END_SQL
385
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
386
+ connection.execute(sql_schema)
387
+ names = connection.procedure_names
388
+ assert_equal 'plusone', names[0]
389
+ end
390
+ end
391
+
392
+ def test_trigger_names
393
+ table_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20)); CREATE GENERATOR TEST_SEQ;"
394
+ trigger_schema = <<-END_SQL
395
+ CREATE TRIGGER TEST_INSERT FOR TEST ACTIVE BEFORE INSERT AS
396
+ BEGIN
397
+ IF (NEW.ID IS NULL) THEN
398
+ NEW.ID = CAST(GEN_ID(TEST_SEQ, 1) AS INT);
399
+ END
400
+ END_SQL
401
+ Database.create(@parms) do |connection|
402
+ connection.execute_script(table_schema)
403
+ connection.execute(trigger_schema)
404
+ names = connection.trigger_names
405
+ assert names.include?('TEST_INSERT')
406
+ end
407
+ end
408
+
409
+ def test_trigger_names_downcased
410
+ table_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20)); CREATE GENERATOR TEST_SEQ;"
411
+ trigger_schema = <<-END_SQL
412
+ CREATE TRIGGER TEST_INSERT FOR TEST ACTIVE BEFORE INSERT AS
413
+ BEGIN
414
+ IF (NEW.ID IS NULL) THEN
415
+ NEW.ID = CAST(GEN_ID(TEST_SEQ, 1) AS INT);
416
+ END
417
+ END_SQL
418
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
419
+ connection.execute_script(table_schema)
420
+ connection.execute(trigger_schema)
421
+ names = connection.trigger_names
422
+ assert names.include?('test_insert')
423
+ end
424
+ end
425
+
426
+ def test_index_names
427
+ sql_schema = <<-END
428
+ CREATE TABLE MASTER (ID INT NOT NULL, NAME1 VARCHAR(10));
429
+ CREATE TABLE DETAIL (ID INT NOT NULL, MASTER_ID INT, NAME2 VARCHAR(10));
430
+ ALTER TABLE MASTER ADD CONSTRAINT PK_MASTER PRIMARY KEY(ID);
431
+ ALTER TABLE DETAIL ADD CONSTRAINT PK_DETAIL PRIMARY KEY(ID);
432
+ ALTER TABLE DETAIL ADD CONSTRAINT FK_DETAIL_MASTER_ID FOREIGN KEY(MASTER_ID) REFERENCES MASTER(ID);
433
+ CREATE UNIQUE ASCENDING INDEX IX_MASTER_NAME1 ON MASTER(NAME1);
434
+ CREATE DESCENDING INDEX IX_DETAIL_ID_DESC ON DETAIL(ID);
435
+ END
436
+ Database.create(@parms) do |connection|
437
+ connection.execute_script(sql_schema)
438
+ indexes = connection.indexes # Hash of Structs using index names as keys
439
+ assert_equal 5, indexes.size
440
+ assert indexes.keys.include?('PK_MASTER')
441
+ assert indexes.keys.include?('PK_DETAIL')
442
+ assert indexes.keys.include?('FK_DETAIL_MASTER_ID')
443
+ assert indexes.keys.include?('IX_MASTER_NAME1')
444
+ assert indexes.keys.include?('IX_DETAIL_ID_DESC')
445
+
446
+ assert indexes['PK_MASTER'].columns.include?('ID')
447
+ assert indexes['PK_DETAIL'].columns.include?('ID')
448
+
449
+ master_indexes = indexes.values.select {|ix| ix.table_name == 'MASTER' }
450
+ assert_equal 2, master_indexes.size
451
+
452
+ detail_indexes = indexes.values.select {|ix| ix.table_name == 'DETAIL' }
453
+ assert_equal 3, detail_indexes.size
454
+
455
+ assert_equal 'MASTER', indexes['PK_MASTER'].table_name
456
+ assert indexes['PK_MASTER'].unique
457
+ assert !indexes['PK_MASTER'].descending
458
+
459
+ assert_equal 'MASTER', indexes['IX_MASTER_NAME1'].table_name
460
+ assert indexes['IX_MASTER_NAME1'].unique
461
+ assert !indexes['IX_MASTER_NAME1'].descending
462
+
463
+ assert_equal 'DETAIL', indexes['PK_DETAIL'].table_name
464
+ assert indexes['PK_DETAIL'].unique
465
+ assert !indexes['PK_DETAIL'].descending
466
+
467
+ assert_equal 'DETAIL', indexes['FK_DETAIL_MASTER_ID'].table_name
468
+ assert !indexes['FK_DETAIL_MASTER_ID'].unique
469
+ assert !indexes['FK_DETAIL_MASTER_ID'].descending
470
+
471
+ assert_equal 'DETAIL', indexes['IX_DETAIL_ID_DESC'].table_name
472
+ assert !indexes['IX_DETAIL_ID_DESC'].unique
473
+ assert indexes['IX_DETAIL_ID_DESC'].descending
474
+
475
+ connection.drop
476
+ end
477
+ end
478
+
479
+ def test_index_names_downcased
480
+ sql_schema = <<-END
481
+ CREATE TABLE MASTER (ID INT NOT NULL, NAME1 VARCHAR(10));
482
+ CREATE TABLE DETAIL (ID INT NOT NULL, MASTER_ID INT, NAME2 VARCHAR(10));
483
+ ALTER TABLE MASTER ADD CONSTRAINT PK_MASTER PRIMARY KEY(ID);
484
+ ALTER TABLE DETAIL ADD CONSTRAINT PK_DETAIL PRIMARY KEY(ID);
485
+ ALTER TABLE DETAIL ADD CONSTRAINT FK_DETAIL_MASTER_ID FOREIGN KEY(MASTER_ID) REFERENCES MASTER(ID);
486
+ CREATE UNIQUE ASCENDING INDEX IX_MASTER_NAME1 ON MASTER(NAME1);
487
+ CREATE DESCENDING INDEX "IX_DETAIL_ID_desc" ON DETAIL(ID);
488
+ END
489
+ Database.create(@parms.merge(:downcase_names => true)) do |connection|
490
+ connection.execute_script(sql_schema)
491
+ indexes = connection.indexes # Hash of Structs using index names as keys
492
+ assert_equal 5, indexes.size
493
+ assert indexes.keys.include?('pk_master')
494
+ assert indexes.keys.include?('pk_detail')
495
+ assert indexes.keys.include?('fk_detail_master_id')
496
+ assert indexes.keys.include?('ix_master_name1')
497
+ assert indexes.keys.include?('IX_DETAIL_ID_desc')
498
+ assert indexes['pk_master'].columns.include?('id'), "columns missing id"
499
+ assert indexes['pk_detail'].columns.include?('id'), "columns missing id"
500
+ connection.drop
501
+ end
502
+ end
503
+
504
+ def test_columns
505
+ sql_schema = <<-END
506
+ create domain STRING10 as VARCHAR(10);
507
+ create table TEST (
508
+ I INTEGER,
509
+ SI SMALLINT,
510
+ BI BIGINT,
511
+ F FLOAT,
512
+ D DOUBLE PRECISION,
513
+ C CHAR,
514
+ C10 CHAR(10),
515
+ VC VARCHAR(1),
516
+ VC10 STRING10,
517
+ VC10000 VARCHAR(10000),
518
+ DT DATE,
519
+ TM TIME,
520
+ TS TIMESTAMP,
521
+ N92 NUMERIC(9,2),
522
+ D92 DECIMAL(9,2));
523
+ END
524
+ expected = [
525
+ # name, domain, sql_type, sql_subtype, length, precision, scale, default, nullable
526
+ Struct::FbColumn.new("I", nil, "INTEGER", 0, 4, 0, 0, nil, true),
527
+ Struct::FbColumn.new("SI", nil, "SMALLINT", 0, 2, 0, 0, nil, true),
528
+ Struct::FbColumn.new("BI", nil, "BIGINT", 0, 8, 0, 0, nil, true),
529
+ Struct::FbColumn.new("F", nil, "FLOAT", 0, 4, nil, 0, nil, true),
530
+ Struct::FbColumn.new("D", nil, "DOUBLE PRECISION", 0, 8, nil, 0, nil, true),
531
+ Struct::FbColumn.new("C", nil, "CHAR", 0, 1, nil, 0, nil, true),
532
+ Struct::FbColumn.new("C10", nil, "CHAR", 0, 10, nil, 0, nil, true),
533
+ Struct::FbColumn.new("VC", nil, "VARCHAR", 0, 1, nil, 0, nil, true),
534
+ Struct::FbColumn.new("VC10", "STRING10", "VARCHAR", 0, 10, nil, 0, nil, true),
535
+ Struct::FbColumn.new("VC10000", nil, "VARCHAR", 0, 10000, nil, 0, nil, true),
536
+ Struct::FbColumn.new("DT", nil, "DATE", 0, 4, nil, 0, nil, true),
537
+ Struct::FbColumn.new("TM", nil, "TIME", 0, 4, nil, 0, nil, true),
538
+ Struct::FbColumn.new("TS", nil, "TIMESTAMP", 0, 8, nil, 0, nil, true),
539
+ Struct::FbColumn.new("N92", nil, "NUMERIC", 1, 4, 9, -2, nil, true),
540
+ Struct::FbColumn.new("D92", nil, "DECIMAL", 2, 4, 9, -2, nil, true),
541
+ ]
542
+ Database.create(@parms) do |connection|
543
+ connection.execute_script(sql_schema)
544
+ columns = connection.columns('TEST')
545
+ expected.each_with_index do |column, i|
546
+ assert_equal column, columns[i]
547
+ end
548
+ end
549
+ end
550
+ end