tiny_tds 0.6.2-x64-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.
- checksums.yaml +15 -0
- data/.gitignore +19 -0
- data/CHANGELOG +180 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +23 -0
- data/README.md +385 -0
- data/Rakefile +114 -0
- data/compile/rake-compiler-dev-box.patch +31 -0
- data/ext/patch/Makefile.in.diff +29 -0
- data/ext/patch/dblib-30-char-username.diff +11 -0
- data/ext/patch/sspi_w_kerberos.diff +42 -0
- data/ext/tiny_tds/client.c +408 -0
- data/ext/tiny_tds/client.h +46 -0
- data/ext/tiny_tds/extconf.rb +102 -0
- data/ext/tiny_tds/result.c +599 -0
- data/ext/tiny_tds/result.h +36 -0
- data/ext/tiny_tds/tiny_tds_ext.c +12 -0
- data/ext/tiny_tds/tiny_tds_ext.h +15 -0
- data/lib/tiny_tds.rb +19 -0
- data/lib/tiny_tds/client.rb +96 -0
- data/lib/tiny_tds/error.rb +29 -0
- data/lib/tiny_tds/result.rb +8 -0
- data/lib/tiny_tds/version.rb +3 -0
- data/tasks/ports.rake +79 -0
- data/test/benchmark/query.rb +77 -0
- data/test/benchmark/query_odbc.rb +106 -0
- data/test/benchmark/query_tinytds.rb +126 -0
- data/test/client_test.rb +170 -0
- data/test/result_test.rb +732 -0
- data/test/schema/1px.gif +0 -0
- data/test/schema/sqlserver_2000.sql +138 -0
- data/test/schema/sqlserver_2005.sql +138 -0
- data/test/schema/sqlserver_2008.sql +138 -0
- data/test/schema/sqlserver_azure.sql +138 -0
- data/test/schema/sybase_ase.sql +138 -0
- data/test/schema_test.rb +305 -0
- data/test/test_helper.rb +195 -0
- data/test/thread_test.rb +95 -0
- metadata +171 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
|
4
|
+
* Binary Data - Our test binary data is a 1 pixel gif. The basic (raw) data is below. Quoting this data
|
5
|
+
would involve this (encode) method and be (encoded) with the 0x prefix for raw SQL. In other clients the
|
6
|
+
(raw_db) value without the 0x prefix would need to be (packed) again yield the original (raw) value.
|
7
|
+
|
8
|
+
(raw) - "GIF89a\001\000\001\000\221\000\000\377\377\377\377\377\377\376\001\002\000\000\000!\371\004\004\024\000\377\000,\000\000\000\000\001\000\001\000\000\002\002D\001\000;"
|
9
|
+
(encode) - "0x#{raw.unpack("H*")[0]}"
|
10
|
+
(encoded) - "0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b"
|
11
|
+
(raw_db) - "47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b"
|
12
|
+
(packed) - [raw_db].pack('H*')
|
13
|
+
|
14
|
+
*/
|
15
|
+
|
16
|
+
CREATE TABLE [datatypes] (
|
17
|
+
[id] [int] IDENTITY NOT NULL PRIMARY KEY,
|
18
|
+
[bigint] [bigint] NULL,
|
19
|
+
[binary_50] [binary](50) NULL,
|
20
|
+
[bit] [bit] DEFAULT 0,
|
21
|
+
[char_10] [char](10) NULL,
|
22
|
+
[date] [date] NULL,
|
23
|
+
[datetime] [datetime] NULL,
|
24
|
+
-- [datetime2_7] [datetime2](7) NULL,
|
25
|
+
-- [datetimeoffset_2] [datetimeoffset](2) NULL,
|
26
|
+
-- [datetimeoffset_7] [datetimeoffset](7) NULL,
|
27
|
+
[decimal_9_2] [decimal](9, 2) NULL,
|
28
|
+
[decimal_16_4] [decimal](16, 4) NULL,
|
29
|
+
[float] [float] NULL,
|
30
|
+
-- [geography] [geography] NULL,
|
31
|
+
-- [geometry] [geometry] NULL,
|
32
|
+
-- [hierarchyid] [hierarchyid] NULL,
|
33
|
+
[image] [image] NULL,
|
34
|
+
[int] [int] NULL,
|
35
|
+
[money] [money] NULL,
|
36
|
+
[nchar_10] [nchar](10) NULL,
|
37
|
+
-- [ntext] [ntext] NULL,
|
38
|
+
[numeric_18_0] [numeric](18, 0) NULL,
|
39
|
+
[numeric_36_2] [numeric](36, 2) NULL,
|
40
|
+
[nvarchar_50] [nvarchar](50) NULL,
|
41
|
+
-- [nvarchar_max] [nvarchar](max) NULL,
|
42
|
+
[real] [real] NULL,
|
43
|
+
[smalldatetime] [smalldatetime] NULL,
|
44
|
+
[smallint] [smallint] NULL,
|
45
|
+
[smallmoney] [smallmoney] NULL,
|
46
|
+
[text] [text] NULL,
|
47
|
+
-- [time_2] [time](2) NULL,
|
48
|
+
-- [time_7] [time](7) NULL,
|
49
|
+
[timestamp] [timestamp] NULL,
|
50
|
+
[tinyint] [tinyint] NULL,
|
51
|
+
-- [uniqueidentifier] [uniqueidentifier] NULL,
|
52
|
+
[varbinary_50] [varbinary](50) NULL,
|
53
|
+
-- [varbinary_max] [varbinary](max) NULL,
|
54
|
+
[varchar_50] [varchar](50) NULL
|
55
|
+
-- [varchar_max] [varchar](max) NULL,
|
56
|
+
-- [xml] [xml] NULL
|
57
|
+
)
|
58
|
+
|
59
|
+
SET IDENTITY_INSERT [datatypes] ON
|
60
|
+
|
61
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 11, -9223372036854775807 )
|
62
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 12, 9223372036854775806 )
|
63
|
+
INSERT INTO [datatypes] ([id], [binary_50]) VALUES ( 21, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
64
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 31, 1 )
|
65
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 32, 0 )
|
66
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 41, '1234567890' )
|
67
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 42, '12345678' )
|
68
|
+
INSERT INTO [datatypes] ([id], [date]) VALUES ( 51, '0001-01-01' )
|
69
|
+
INSERT INTO [datatypes] ([id], [date]) VALUES ( 52, '9999-12-31' )
|
70
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 61, '1753-01-01T00:00:00.000' )
|
71
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 62, '9999-12-31T23:59:59.997' )
|
72
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 63, '2010-01-01T12:34:56.123' )
|
73
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 71, '0001-01-01T00:00:00.0000000Z' )
|
74
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 72, '1984-01-24T04:20:00.0000000-08:00' )
|
75
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 73, '9999-12-31T23:59:59.9999999Z' )
|
76
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 81, '1984-01-24T04:20:00.0000000-08:00' ) -- 1984-01-24 04:20:00.00 -08:00
|
77
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 82, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.00 +00:00
|
78
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 83, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.99 +00:00
|
79
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 84, '1984-01-24T04:20:00.0000000-08:00' ) -- 1984-01-24 04:20:00.0000000 -08:00
|
80
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 85, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.0000000 +00:00
|
81
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 86, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.9999999 +00:00
|
82
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 91, 12345.01 )
|
83
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 92, 1234567.89 )
|
84
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 93, 0.0 )
|
85
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 94, 123456789012.3456 )
|
86
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 101, 123.00000001 )
|
87
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 102, 0.0 )
|
88
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 103, 123.45 )
|
89
|
+
-- INSERT INTO [datatypes] ([id], [geography]) VALUES ( 111, geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326) ) -- 0xE610000001148716D9CEF7D34740D7A3703D0A975EC08716D9CEF7D34740CBA145B6F3955EC0
|
90
|
+
-- INSERT INTO [datatypes] ([id], [geometry]) VALUES ( 121, geometry::STGeomFromText('LINESTRING (100 100, 20 180, 180 180)', 0) ) -- 0x0000000001040300000000000000000059400000000000005940000000000000344000000000008066400000000000806640000000000080664001000000010000000001000000FFFFFFFF0000000002
|
91
|
+
-- INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 131, CAST('/1/' AS hierarchyid) ) -- 0x58
|
92
|
+
-- INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 132, CAST('/2/' AS hierarchyid) ) -- 0x68
|
93
|
+
INSERT INTO [datatypes] ([id], [image]) VALUES ( 141, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
94
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 151, -2147483647 )
|
95
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 152, 2147483646 )
|
96
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 161, 4.20 )
|
97
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 162, -922337203685477.5807 )
|
98
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 163, 922337203685477.5806 )
|
99
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 171, N'1234567890' )
|
100
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 172, N'123456åå' )
|
101
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 173, N'abc123' )
|
102
|
+
-- INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 181, N'test ntext' )
|
103
|
+
-- INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 182, N'test ntext' ) -- Removed UTF-8 chars. They make sybase choke in comments.
|
104
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 191, 191 )
|
105
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 192, 123456789012345678 )
|
106
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 193, 12345678901234567890.01 )
|
107
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 194, 123.46 )
|
108
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 201, N'test nvarchar_50' )
|
109
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 202, N'test nvarchar_50 åå' )
|
110
|
+
-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 211, N'test nvarchar_max' )
|
111
|
+
-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 212, N'test nvarchar_max' ) -- Removed UTF-8 chars. They make sybase choke in comments.
|
112
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 221, 123.45 )
|
113
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 222, 0.0 )
|
114
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 223, 0.00001 )
|
115
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 231, '1901-01-01T15:45:00.000' ) -- 1901-01-01 15:45:00
|
116
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 232, '2078-06-05T04:20:00.000' ) -- 2078-06-05 04:20:00
|
117
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 241, -32767 )
|
118
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 242, 32766 )
|
119
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 251, 4.20 )
|
120
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 252, -214748.3647 )
|
121
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 253, 214748.3646 )
|
122
|
+
INSERT INTO [datatypes] ([id], [text]) VALUES ( 271, 'test text' )
|
123
|
+
-- INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 281, '1901-01-01T15:45:00.0100001Z' ) -- 15:45:00.01
|
124
|
+
-- INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 282, '1984-01-24T04:20:00.0000001-08:00' ) -- 04:20:00.00
|
125
|
+
-- INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 283, '1901-01-01T15:45:00.0100001Z' ) -- 15:45:00.0100001
|
126
|
+
-- INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 284, '1984-01-24T04:20:00.0000001-08:00' ) -- 04:20:00.0000001
|
127
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 301, 0 )
|
128
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 302, 255 )
|
129
|
+
-- INSERT INTO [datatypes] ([id], [uniqueidentifier]) VALUES ( 311, NEWID() )
|
130
|
+
INSERT INTO [datatypes] ([id], [varbinary_50]) VALUES ( 321, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
131
|
+
-- INSERT INTO [datatypes] ([id], [varbinary_max]) VALUES ( 331, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
132
|
+
INSERT INTO [datatypes] ([id], [varchar_50]) VALUES ( 341, 'test varchar_50' )
|
133
|
+
-- INSERT INTO [datatypes] ([id], [varchar_max]) VALUES ( 351, 'test varchar_max' )
|
134
|
+
-- INSERT INTO [datatypes] ([id], [xml]) VALUES ( 361, '<foo><bar>batz</bar></foo>' )
|
135
|
+
|
136
|
+
SET IDENTITY_INSERT [datatypes] OFF
|
137
|
+
|
138
|
+
|
data/test/schema_test.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class SchemaTest < TinyTds::TestCase
|
5
|
+
|
6
|
+
describe 'Casting SQL Server schema' do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@@current_schema_loaded ||= load_current_schema
|
10
|
+
@client = new_connection
|
11
|
+
@gif1px = File.read('test/schema/1px.gif',:mode=>"rb:BINARY")
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'for shared types' do
|
15
|
+
|
16
|
+
it 'casts bigint' do
|
17
|
+
assert_equal -9223372036854775807, find_value(11, :bigint)
|
18
|
+
assert_equal 9223372036854775806, find_value(12, :bigint)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'casts binary' do
|
22
|
+
binary_value = sqlserver_azure? ? @gif1px : @gif1px+"\000"
|
23
|
+
value = find_value(21, :binary_50)
|
24
|
+
assert_equal binary_value, value
|
25
|
+
assert_binary_encoding(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'casts bit' do
|
29
|
+
assert_equal true, find_value(31, :bit)
|
30
|
+
assert_equal false, find_value(32, :bit)
|
31
|
+
assert_equal nil, find_value(21, :bit)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'casts char' do
|
35
|
+
partial_char = sqlserver_azure? ? '12345678' : '12345678 '
|
36
|
+
assert_equal '1234567890', find_value(41, :char_10)
|
37
|
+
assert_equal partial_char, find_value(42, :char_10)
|
38
|
+
assert_utf8_encoding find_value(42, :char_10)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'casts datetime' do
|
42
|
+
# 1753-01-01T00:00:00.000
|
43
|
+
v = find_value 61, :datetime
|
44
|
+
assert_instance_of Time, v, 'not in range of Time class'
|
45
|
+
assert_equal 1753, v.year
|
46
|
+
assert_equal 01, v.month
|
47
|
+
assert_equal 01, v.day
|
48
|
+
assert_equal 0, v.hour
|
49
|
+
assert_equal 0, v.min
|
50
|
+
assert_equal 0, v.sec
|
51
|
+
assert_equal 0, v.usec
|
52
|
+
# 9999-12-31T23:59:59.997
|
53
|
+
v = find_value 62, :datetime
|
54
|
+
assert_instance_of Time, v, 'not in range of Time class'
|
55
|
+
assert_equal 9999, v.year
|
56
|
+
assert_equal 12, v.month
|
57
|
+
assert_equal 31, v.day
|
58
|
+
assert_equal 23, v.hour
|
59
|
+
assert_equal 59, v.min
|
60
|
+
assert_equal 59, v.sec
|
61
|
+
assert_equal 997000, v.usec
|
62
|
+
assert_equal utc_offset, find_value(62, :datetime, :timezone => :local).utc_offset
|
63
|
+
assert_equal 0, find_value(62, :datetime, :timezone => :utc).utc_offset
|
64
|
+
# 2010-01-01T12:34:56.123
|
65
|
+
v = find_value 63, :datetime
|
66
|
+
assert_instance_of Time, v, 'in range of Time class'
|
67
|
+
assert_equal 2010, v.year
|
68
|
+
assert_equal 01, v.month
|
69
|
+
assert_equal 01, v.day
|
70
|
+
assert_equal 12, v.hour
|
71
|
+
assert_equal 34, v.min
|
72
|
+
assert_equal 56, v.sec
|
73
|
+
assert_equal 123000, v.usec
|
74
|
+
assert_equal utc_offset, find_value(63, :datetime, :timezone => :local).utc_offset
|
75
|
+
assert_equal 0, find_value(63, :datetime, :timezone => :utc).utc_offset
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'casts decimal' do
|
79
|
+
assert_instance_of BigDecimal, find_value(91, :decimal_9_2)
|
80
|
+
assert_equal BigDecimal.new('12345.01'), find_value(91, :decimal_9_2)
|
81
|
+
assert_equal BigDecimal.new('1234567.89'), find_value(92, :decimal_9_2)
|
82
|
+
assert_equal BigDecimal.new('0.0'), find_value(93, :decimal_16_4)
|
83
|
+
assert_equal BigDecimal.new('123456789012.3456'), find_value(94, :decimal_16_4)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'casts float' do
|
87
|
+
assert_equal 123.00000001, find_value(101,:float)
|
88
|
+
assert_equal 0.0, find_value(102,:float)
|
89
|
+
assert_equal find_value(102,:float).object_id, find_value(102,:float).object_id, 'use global zero float'
|
90
|
+
assert_equal 123.45, find_value(103,:float)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'casts image' do
|
94
|
+
value = find_value(141,:image)
|
95
|
+
assert_equal @gif1px, value
|
96
|
+
assert_binary_encoding(value)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'casts int' do
|
100
|
+
assert_equal -2147483647, find_value(151, :int)
|
101
|
+
assert_equal 2147483646, find_value(152, :int)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'casts money' do
|
105
|
+
assert_instance_of BigDecimal, find_value(161, :money)
|
106
|
+
assert_equal BigDecimal.new('4.20'), find_value(161, :money)
|
107
|
+
assert_equal BigDecimal.new('922337203685477.5806'), find_value(163 ,:money)
|
108
|
+
assert_equal BigDecimal.new('-922337203685477.5807'), find_value(162 ,:money)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'casts nchar' do
|
112
|
+
assert_equal '1234567890', find_value(171, :nchar_10)
|
113
|
+
assert_equal '123456åå ', find_value(172, :nchar_10)
|
114
|
+
assert_equal 'abc123 ', find_value(173, :nchar_10)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'casts ntext' do
|
118
|
+
assert_equal 'test ntext', find_value(181, :ntext)
|
119
|
+
assert_equal 'test ntext åå', find_value(182, :ntext)
|
120
|
+
assert_utf8_encoding find_value(182, :ntext)
|
121
|
+
# If this test fails, try setting the "text size" in your freetds.conf. See: http://www.freetds.org/faq.html#textdata
|
122
|
+
large_value = "x" * 5000
|
123
|
+
large_value_id = @client.execute("INSERT INTO [datatypes] ([ntext]) VALUES (N'#{large_value}')").insert
|
124
|
+
assert_equal large_value, find_value(large_value_id, :ntext)
|
125
|
+
end unless sybase_ase?
|
126
|
+
|
127
|
+
it 'casts numeric' do
|
128
|
+
assert_instance_of BigDecimal, find_value(191, :numeric_18_0)
|
129
|
+
assert_equal BigDecimal('191'), find_value(191, :numeric_18_0)
|
130
|
+
assert_equal BigDecimal('123456789012345678'), find_value(192, :numeric_18_0)
|
131
|
+
assert_equal BigDecimal('12345678901234567890.01'), find_value(193, :numeric_36_2)
|
132
|
+
assert_equal BigDecimal('123.46'), find_value(194, :numeric_36_2)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'casts nvarchar' do
|
136
|
+
assert_equal 'test nvarchar_50', find_value(201, :nvarchar_50)
|
137
|
+
assert_equal 'test nvarchar_50 åå', find_value(202, :nvarchar_50)
|
138
|
+
assert_utf8_encoding find_value(202, :nvarchar_50)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'casts real' do
|
142
|
+
assert_in_delta 123.45, find_value(221, :real), 0.01
|
143
|
+
assert_equal 0.0, find_value(222, :real)
|
144
|
+
assert_equal find_value(222, :real).object_id, find_value(222, :real).object_id, 'use global zero float'
|
145
|
+
assert_in_delta 0.00001, find_value(223, :real), 0.000001
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'casts smalldatetime' do
|
149
|
+
# 1901-01-01 15:45:00
|
150
|
+
v = find_value 231, :smalldatetime
|
151
|
+
assert_instance_of Time, v
|
152
|
+
assert_equal 1901, v.year
|
153
|
+
assert_equal 01, v.month
|
154
|
+
assert_equal 01, v.day
|
155
|
+
assert_equal 15, v.hour
|
156
|
+
assert_equal 45, v.min
|
157
|
+
assert_equal 00, v.sec
|
158
|
+
assert_equal Time.local(1901).utc_offset, find_value(231, :smalldatetime, :timezone => :local).utc_offset
|
159
|
+
assert_equal 0, find_value(231, :smalldatetime, :timezone => :utc).utc_offset
|
160
|
+
# 2078-06-05 04:20:00
|
161
|
+
v = find_value 232, :smalldatetime
|
162
|
+
assert_instance_of Time, v
|
163
|
+
assert_equal 2078, v.year
|
164
|
+
assert_equal 06, v.month
|
165
|
+
assert_equal 05, v.day
|
166
|
+
assert_equal 04, v.hour
|
167
|
+
assert_equal 20, v.min
|
168
|
+
assert_equal 00, v.sec
|
169
|
+
assert_equal Time.local(2078,6).utc_offset, find_value(232, :smalldatetime, :timezone => :local).utc_offset
|
170
|
+
assert_equal 0, find_value(232, :smalldatetime, :timezone => :utc).utc_offset
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'casts smallint' do
|
174
|
+
assert_equal -32767, find_value(241, :smallint)
|
175
|
+
assert_equal 32766, find_value(242, :smallint)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'casts smallmoney' do
|
179
|
+
assert_instance_of BigDecimal, find_value(251, :smallmoney)
|
180
|
+
assert_equal BigDecimal.new("4.20"), find_value(251, :smallmoney)
|
181
|
+
assert_equal BigDecimal.new("-214748.3647"), find_value(252, :smallmoney)
|
182
|
+
assert_equal BigDecimal.new("214748.3646"), find_value(253, :smallmoney)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'casts text' do
|
186
|
+
assert_equal 'test text', find_value(271, :text)
|
187
|
+
assert_utf8_encoding find_value(271, :text)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'casts tinyint' do
|
191
|
+
assert_equal 0, find_value(301, :tinyint)
|
192
|
+
assert_equal 255, find_value(302, :tinyint)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'casts uniqueidentifier' do
|
196
|
+
assert_match %r|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}|, find_value(311, :uniqueidentifier)
|
197
|
+
assert_utf8_encoding find_value(311, :uniqueidentifier)
|
198
|
+
end unless sybase_ase?
|
199
|
+
|
200
|
+
it 'casts varbinary' do
|
201
|
+
value = find_value(321, :varbinary_50)
|
202
|
+
assert_equal @gif1px, value
|
203
|
+
assert_binary_encoding(value)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'casts varchar' do
|
207
|
+
assert_equal 'test varchar_50', find_value(341, :varchar_50)
|
208
|
+
assert_utf8_encoding find_value(341, :varchar_50)
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
describe 'for 2005 and up' do
|
215
|
+
|
216
|
+
it 'casts nvarchar(max)' do
|
217
|
+
assert_equal 'test nvarchar_max', find_value(211, :nvarchar_max)
|
218
|
+
assert_equal 'test nvarchar_max åå', find_value(212, :nvarchar_max)
|
219
|
+
assert_utf8_encoding find_value(212, :nvarchar_max)
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'casts varbinary(max)' do
|
223
|
+
value = find_value(331, :varbinary_max)
|
224
|
+
assert_equal @gif1px, value
|
225
|
+
assert_binary_encoding(value)
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'casts varchar(max)' do
|
229
|
+
value = find_value(351, :varchar_max)
|
230
|
+
assert_equal 'test varchar_max', value
|
231
|
+
assert_utf8_encoding(value)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'casts xml' do
|
235
|
+
value = find_value(361, :xml)
|
236
|
+
assert_equal '<foo><bar>batz</bar></foo>', value
|
237
|
+
assert_utf8_encoding(value)
|
238
|
+
end
|
239
|
+
|
240
|
+
end if sqlserver_2005? || sqlserver_2008? || sqlserver_azure?
|
241
|
+
|
242
|
+
|
243
|
+
describe 'for 2008 and up' do
|
244
|
+
|
245
|
+
# These data types always come back as SYBTEXT and there is no way I can
|
246
|
+
# find out the column's human readable name.
|
247
|
+
#
|
248
|
+
# * [date]
|
249
|
+
# * [datetime2]
|
250
|
+
# * [datetimeoffset]
|
251
|
+
# * [time]
|
252
|
+
#
|
253
|
+
# I have tried the following and I only get back either "char" or 0/null.
|
254
|
+
#
|
255
|
+
# rb_warn("SYBTEXT: dbprtype: %s", dbprtype(coltype));
|
256
|
+
# rb_warn("SYBTEXT: dbcolutype: %s", dbcolutype(rwrap->client, col));
|
257
|
+
# rb_warn("SYBTEXT: dbcolutype: %ld", dbcolutype(rwrap->client, col));
|
258
|
+
|
259
|
+
# it 'casts date' do
|
260
|
+
# value = find_value 51, :date
|
261
|
+
# assert_equal '', value
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# it 'casts datetime2' do
|
265
|
+
# value = find_value 72, :datetime2_7
|
266
|
+
# assert_equal '', value
|
267
|
+
# end
|
268
|
+
#
|
269
|
+
# it 'casts datetimeoffset' do
|
270
|
+
# value = find_value 81, :datetimeoffset_2
|
271
|
+
# assert_equal '', value
|
272
|
+
# end
|
273
|
+
#
|
274
|
+
# it 'casts geography' do
|
275
|
+
# value = find_value 111, :geography
|
276
|
+
# assert_equal '', value
|
277
|
+
# end
|
278
|
+
#
|
279
|
+
# it 'casts geometry' do
|
280
|
+
# value = find_value 121, :geometry
|
281
|
+
# assert_equal '', value
|
282
|
+
# end
|
283
|
+
#
|
284
|
+
# it 'casts hierarchyid' do
|
285
|
+
# value = find_value 131, :hierarchyid
|
286
|
+
# assert_equal '', value
|
287
|
+
# end
|
288
|
+
#
|
289
|
+
# it 'casts time' do
|
290
|
+
# value = find_value 283, :time_7
|
291
|
+
# assert_equal '', value
|
292
|
+
# end
|
293
|
+
|
294
|
+
end if sqlserver_2008? || sqlserver_azure?
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'bundler' ; Bundler.require :development, :test
|
3
|
+
require 'tiny_tds'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
class DateTime
|
7
|
+
def usec
|
8
|
+
(sec_fraction * 1_000_000).to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
TINYTDS_SCHEMAS = ['sqlserver_2000', 'sqlserver_2005', 'sqlserver_2008', 'sqlserver_azure', 'sybase_ase'].freeze
|
13
|
+
|
14
|
+
module TinyTds
|
15
|
+
class TestCase < MiniTest::Spec
|
16
|
+
|
17
|
+
class << self
|
18
|
+
|
19
|
+
def current_schema
|
20
|
+
ENV['TINYTDS_SCHEMA'] || 'sqlserver_2008'
|
21
|
+
end
|
22
|
+
|
23
|
+
TINYTDS_SCHEMAS.each do |schema|
|
24
|
+
define_method "#{schema}?" do
|
25
|
+
schema == self.current_schema
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def sqlserver?
|
30
|
+
current_schema =~ /sqlserver/
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
after do
|
36
|
+
@client.close if @client.is_a?(TinyTds::Client)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
TINYTDS_SCHEMAS.each do |schema|
|
42
|
+
define_method "#{schema}?" do
|
43
|
+
schema == self.class.current_schema
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_schema
|
48
|
+
self.class.current_schema
|
49
|
+
end
|
50
|
+
|
51
|
+
def sqlserver?
|
52
|
+
self.class.sqlserver?
|
53
|
+
end
|
54
|
+
|
55
|
+
def new_connection(options={})
|
56
|
+
client = TinyTds::Client.new(connection_options(options))
|
57
|
+
if sybase_ase?
|
58
|
+
client.execute("SET ANSINULL ON").do
|
59
|
+
elsif !sqlserver_azure?
|
60
|
+
client.execute("SET ANSI_DEFAULTS ON").do
|
61
|
+
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
|
62
|
+
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
|
63
|
+
end
|
64
|
+
client
|
65
|
+
end
|
66
|
+
|
67
|
+
def connection_options(options={})
|
68
|
+
username = sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_USER'] : ENV['TINYTDS_UNIT_USER'] || 'tinytds'
|
69
|
+
password = sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_PASS'] : ENV['TINYTDS_UNIT_PASS'] || ''
|
70
|
+
{ :dataserver => ENV['TINYTDS_UNIT_DATASERVER'],
|
71
|
+
:host => ENV['TINYTDS_UNIT_HOST'],
|
72
|
+
:port => ENV['TINYTDS_UNIT_PORT'],
|
73
|
+
:tds_version => ENV['TINYTDS_UNIT_VERSION'],
|
74
|
+
:username => username,
|
75
|
+
:password => password,
|
76
|
+
:database => 'tinytdstest',
|
77
|
+
:appname => 'TinyTds Dev',
|
78
|
+
:login_timeout => 5,
|
79
|
+
:timeout => 5,
|
80
|
+
:azure => sqlserver_azure?
|
81
|
+
}.merge(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def assert_client_works(client)
|
85
|
+
client.execute("SELECT 'client_works' as [client_works]").each.must_equal [{'client_works' => 'client_works'}]
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert_new_connections_work
|
89
|
+
client = new_connection
|
90
|
+
client.execute("SELECT 'new_connections_work' as [new_connections_work]").each
|
91
|
+
end
|
92
|
+
|
93
|
+
def assert_raise_tinytds_error(action)
|
94
|
+
error_raised = false
|
95
|
+
begin
|
96
|
+
action.call
|
97
|
+
rescue TinyTds::Error => e
|
98
|
+
error_raised = true
|
99
|
+
end
|
100
|
+
assert error_raised, 'expected a TinyTds::Error but none happened'
|
101
|
+
yield e
|
102
|
+
end
|
103
|
+
|
104
|
+
def inspect_tinytds_exception
|
105
|
+
begin
|
106
|
+
yield
|
107
|
+
rescue TinyTds::Error => e
|
108
|
+
props = { :source => e.source, :message => e.message, :severity => e.severity,
|
109
|
+
:db_error_number => e.db_error_number, :os_error_number => e.os_error_number }
|
110
|
+
raise "TinyTds::Error - #{props.inspect}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def assert_binary_encoding(value)
|
115
|
+
assert_equal Encoding.find('BINARY'), value.encoding
|
116
|
+
end
|
117
|
+
|
118
|
+
def assert_utf8_encoding(value)
|
119
|
+
assert_equal Encoding.find('UTF-8'), value.encoding
|
120
|
+
end
|
121
|
+
|
122
|
+
def rubyRbx?
|
123
|
+
RUBY_DESCRIPTION =~ /rubinius/i
|
124
|
+
end
|
125
|
+
|
126
|
+
def load_current_schema
|
127
|
+
loader = new_connection
|
128
|
+
schema_file = File.expand_path File.join(File.dirname(__FILE__), 'schema', "#{current_schema}.sql")
|
129
|
+
schema_sql = File.open(schema_file,"rb:UTF-8") { |f|f.read }
|
130
|
+
loader.execute(drop_sql).each
|
131
|
+
loader.execute(schema_sql).cancel
|
132
|
+
loader.execute(sp_sql).cancel
|
133
|
+
loader.close
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
def drop_sql
|
138
|
+
sybase_ase? ? drop_sql_sybase : drop_sql_microsoft
|
139
|
+
end
|
140
|
+
|
141
|
+
def drop_sql_sybase
|
142
|
+
%|IF EXISTS(
|
143
|
+
SELECT 1 FROM sysobjects WHERE type = 'U' AND name = 'datatypes'
|
144
|
+
) DROP TABLE datatypes
|
145
|
+
IF EXISTS(
|
146
|
+
SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestReturnCodes'
|
147
|
+
) DROP PROCEDURE tinytds_TestReturnCodes|
|
148
|
+
end
|
149
|
+
|
150
|
+
def drop_sql_microsoft
|
151
|
+
%|IF EXISTS (
|
152
|
+
SELECT TABLE_NAME
|
153
|
+
FROM INFORMATION_SCHEMA.TABLES
|
154
|
+
WHERE TABLE_CATALOG = 'tinytdstest'
|
155
|
+
AND TABLE_TYPE = 'BASE TABLE'
|
156
|
+
AND TABLE_NAME = 'datatypes'
|
157
|
+
) DROP TABLE [datatypes]
|
158
|
+
IF EXISTS (
|
159
|
+
SELECT name FROM sysobjects
|
160
|
+
WHERE name = 'tinytds_TestReturnCodes' AND type = 'P'
|
161
|
+
) DROP PROCEDURE tinytds_TestReturnCodes|
|
162
|
+
end
|
163
|
+
|
164
|
+
def sp_sql
|
165
|
+
%|CREATE PROCEDURE tinytds_TestReturnCodes
|
166
|
+
AS
|
167
|
+
SELECT 1 as [one]
|
168
|
+
RETURN(420) |
|
169
|
+
end
|
170
|
+
|
171
|
+
def find_value(id, column, query_options={})
|
172
|
+
query_options[:timezone] ||= :utc
|
173
|
+
sql = "SELECT [#{column}] FROM [datatypes] WHERE [id] = #{id}"
|
174
|
+
@client.execute(sql).each(query_options).first[column.to_s]
|
175
|
+
end
|
176
|
+
|
177
|
+
def local_offset
|
178
|
+
TinyTds::Client.local_offset
|
179
|
+
end
|
180
|
+
|
181
|
+
def utc_offset
|
182
|
+
::Time.local(2010).utc_offset
|
183
|
+
end
|
184
|
+
|
185
|
+
def rollback_transaction(client)
|
186
|
+
client.execute("BEGIN TRANSACTION").do
|
187
|
+
yield
|
188
|
+
ensure
|
189
|
+
client.execute("ROLLBACK TRANSACTION").do
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|