tiny_tds 0.4.3 → 0.4.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.
@@ -0,0 +1,284 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class SchemaTest < TinyTds::TestCase
5
+
6
+ context 'Casting SQL Server schema' do
7
+
8
+ setup do
9
+ @@current_schema_loaded ||= load_current_schema
10
+ @client ||= new_connection
11
+ @gif1px = ruby19? ? File.read('test/schema/1px.gif',:mode=>"rb:BINARY") : File.read('test/schema/1px.gif')
12
+ end
13
+
14
+ context 'for shared types' do
15
+
16
+ should 'cast bigint' do
17
+ assert_equal -9223372036854775807, find_value(11, :bigint)
18
+ assert_equal 9223372036854775806, find_value(12, :bigint)
19
+ end
20
+
21
+ should 'cast 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
+ should 'cast 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
+ should 'cast 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
+ should 'cast datetime' do
42
+ # 1753-01-01T00:00:00.000
43
+ v = find_value 61, :datetime
44
+ assert_instance_of DateTime, 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 DateTime, 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 unless ruby186?
62
+ assert_equal local_offset, find_value(61, :datetime, :timezone => :local).offset
63
+ assert_equal 0, find_value(61, :datetime, :timezone => :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
+ should 'cast 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
+ should 'cast 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
+ should 'cast image' do
94
+ value = find_value(141,:image)
95
+ assert_equal @gif1px, value
96
+ assert_binary_encoding(value)
97
+ end
98
+
99
+ should 'cast int' do
100
+ assert_equal -2147483647, find_value(151, :int)
101
+ assert_equal 2147483646, find_value(152, :int)
102
+ end
103
+
104
+ should 'cast 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
+ should 'cast 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
+ should 'cast 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
126
+
127
+ should 'cast 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
+ should 'cast 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
+ should 'cast 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
+ should 'cast smalldatetime' do
149
+ # 1901-01-01 15:45:00
150
+ v = find_value 231, :smalldatetime
151
+ assert_instance_of DateTime, 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 local_offset, find_value(231, :smalldatetime, :timezone => :local).offset
159
+ assert_equal 0, find_value(231, :smalldatetime, :timezone => :utc).offset
160
+ # 2078-06-05 04:20:00
161
+ v = find_value 232, :smalldatetime
162
+ assert_instance_of DateTime, 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 local_offset, find_value(232, :smalldatetime, :timezone => :local).offset
170
+ assert_equal 0, find_value(232, :smalldatetime, :timezone => :utc).offset
171
+ end
172
+
173
+ should 'cast smallint' do
174
+ assert_equal -32767, find_value(241, :smallint)
175
+ assert_equal 32766, find_value(242, :smallint)
176
+ end
177
+
178
+ should 'cast 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
+ should 'cast text' do
186
+ assert_equal 'test text', find_value(271, :text)
187
+ assert_utf8_encoding find_value(271, :text)
188
+ end
189
+
190
+ should 'cast tinyint' do
191
+ assert_equal 0, find_value(301, :tinyint)
192
+ assert_equal 255, find_value(302, :tinyint)
193
+ end
194
+
195
+ should 'cast 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
199
+
200
+ should 'cast varbinary' do
201
+ value = find_value(321, :varbinary_50)
202
+ assert_equal @gif1px, value
203
+ assert_binary_encoding(value)
204
+ end
205
+
206
+ should 'cast 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
+ context 'for 2005 and up' do
215
+
216
+ should 'cast 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
+ should 'cast varbinary(max)' do
223
+ value = find_value(331, :varbinary_max)
224
+ assert_equal @gif1px, value
225
+ assert_binary_encoding(value)
226
+ end
227
+
228
+ should 'cast 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
+ should 'cast 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
+ context 'for 2008 and up' do
244
+
245
+ should 'cast date' do
246
+
247
+ end
248
+
249
+ should 'cast datetime2' do
250
+
251
+ end
252
+
253
+ should 'cast datetimeoffset' do
254
+
255
+ end
256
+
257
+ should 'cast geography' do
258
+
259
+ end
260
+
261
+ should 'cast geometry' do
262
+
263
+ end
264
+
265
+ should 'cast hierarchyid' do
266
+
267
+ end
268
+
269
+ should 'cast time' do
270
+
271
+ end
272
+
273
+ end if sqlserver_2008? || sqlserver_azure?
274
+
275
+ end
276
+
277
+
278
+
279
+ end
280
+
281
+
282
+
283
+
284
+
@@ -0,0 +1,199 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup
5
+ require 'tiny_tds'
6
+ require 'mini_shoulda'
7
+ require 'minitest/autorun'
8
+
9
+ class DateTime
10
+ def usec
11
+ if RUBY_VERSION >= '1.9'
12
+ (sec_fraction * 1_000_000).to_i
13
+ else
14
+ (sec_fraction * 60 * 60 * 24 * (10**6)).to_i
15
+ end
16
+ end
17
+ end
18
+
19
+ TINYTDS_SCHEMAS = ['sqlserver_2000', 'sqlserver_2005', 'sqlserver_2008', 'sqlserver_azure'].freeze
20
+
21
+ module TinyTds
22
+ class TestCase < MiniTest::Spec
23
+
24
+ class << self
25
+
26
+ def current_schema
27
+ ENV['TINYTDS_SCHEMA'] || 'sqlserver_2008'
28
+ end
29
+
30
+ TINYTDS_SCHEMAS.each do |schema|
31
+ define_method "#{schema}?" do
32
+ schema == self.current_schema
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ setup do
39
+
40
+ end
41
+
42
+ teardown do
43
+ ENV['TDSPORT'] = nil
44
+ ENV['TDSHOST'] = nil
45
+ end
46
+
47
+
48
+ protected
49
+
50
+ TINYTDS_SCHEMAS.each do |schema|
51
+ define_method "#{schema}?" do
52
+ schema == self.class.current_schema
53
+ end
54
+ end
55
+
56
+ def current_schema
57
+ self.class.current_schema
58
+ end
59
+
60
+ def new_connection(options={})
61
+ client = TinyTds::Client.new(connection_options(options))
62
+ unless sqlserver_azure?
63
+ client.execute("SET ANSI_DEFAULTS ON").do
64
+ client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
65
+ client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
66
+ end
67
+ client
68
+ end
69
+
70
+ def connection_options(options={})
71
+ username = sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_USER'] : 'tinytds'
72
+ password = sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_PASS'] : ''
73
+ { :dataserver => ENV['TINYTDS_UNIT_DATASERVER'],
74
+ :host => ENV['TINYTDS_UNIT_HOST'],
75
+ :username => username,
76
+ :password => password,
77
+ :database => 'tinytdstest',
78
+ :appname => 'TinyTds Dev',
79
+ :login_timeout => 5,
80
+ :timeout => 5,
81
+ :azure => sqlserver_azure?
82
+ }.merge(options)
83
+ end
84
+
85
+ def assert_client_works(client)
86
+ client.execute("SELECT 'client_works' as [client_works]").each
87
+ end
88
+
89
+ def assert_new_connections_work
90
+ client = new_connection
91
+ client.execute("SELECT 'new_connections_work' as [new_connections_work]").each
92
+ end
93
+
94
+ def assert_raise_tinytds_error(action)
95
+ error_raised = false
96
+ begin
97
+ action.call
98
+ rescue TinyTds::Error => e
99
+ error_raised = true
100
+ end
101
+ assert error_raised, 'expected a TinyTds::Error but none happened'
102
+ yield e
103
+ end
104
+
105
+ def inspect_tinytds_exception
106
+ begin
107
+ yield
108
+ rescue TinyTds::Error => e
109
+ props = { :source => e.source, :message => e.message, :severity => e.severity,
110
+ :db_error_number => e.db_error_number, :os_error_number => e.os_error_number }
111
+ raise "TinyTds::Error - #{props.inspect}"
112
+ end
113
+ end
114
+
115
+ def assert_binary_encoding(value)
116
+ assert_equal Encoding.find('BINARY'), value.encoding if ruby19?
117
+ end
118
+
119
+ def assert_utf8_encoding(value)
120
+ assert_equal Encoding.find('UTF-8'), value.encoding if ruby19?
121
+ end
122
+
123
+ def ruby18?
124
+ RUBY_VERSION < '1.9'
125
+ end
126
+
127
+ def ruby186?
128
+ RUBY_VERSION == '1.8.6'
129
+ end
130
+
131
+ def ruby19?
132
+ RUBY_VERSION >= '1.9'
133
+ end
134
+
135
+ def ruby192?
136
+ RUBY_VERSION == '1.9.2'
137
+ end
138
+
139
+ def rubyRbx?
140
+ RUBY_DESCRIPTION =~ /rubinius/i
141
+ end
142
+
143
+ def load_current_schema
144
+ loader = new_connection
145
+ schema_file = File.expand_path File.join(File.dirname(__FILE__), 'schema', "#{current_schema}.sql")
146
+ schema_sql = ruby18? ? File.read(schema_file) : File.open(schema_file,"rb:UTF-8") { |f|f.read }
147
+ loader.execute(drop_sql).each
148
+ loader.execute(schema_sql).cancel
149
+ loader.execute(sp_sql).cancel
150
+ loader.close
151
+ true
152
+ end
153
+
154
+ def drop_sql
155
+ %|IF EXISTS (
156
+ SELECT TABLE_NAME
157
+ FROM INFORMATION_SCHEMA.TABLES
158
+ WHERE TABLE_CATALOG = 'tinytdstest'
159
+ AND TABLE_TYPE = 'BASE TABLE'
160
+ AND TABLE_NAME = 'datatypes'
161
+ ) DROP TABLE [datatypes]
162
+ IF EXISTS (
163
+ SELECT name FROM sysobjects
164
+ WHERE name = 'tinytds_TestReturnCodes' AND type = 'P'
165
+ ) DROP PROCEDURE tinytds_TestReturnCodes|
166
+ end
167
+
168
+ def sp_sql
169
+ %|CREATE PROCEDURE tinytds_TestReturnCodes
170
+ AS
171
+ SELECT 1 as [one]
172
+ RETURN(420) |
173
+ end
174
+
175
+ def find_value(id, column, query_options={})
176
+ query_options[:timezone] ||= :utc
177
+ sql = "SELECT [#{column}] FROM [datatypes] WHERE [id] = #{id}"
178
+ @client.execute(sql).each(query_options).first[column.to_s]
179
+ end
180
+
181
+ def local_offset
182
+ TinyTds::Client.local_offset
183
+ end
184
+
185
+ def utc_offset
186
+ ::Time.local(2010).utc_offset
187
+ end
188
+
189
+ def rollback_transaction(client)
190
+ client.execute("BEGIN TRANSACTION").do
191
+ yield
192
+ ensure
193
+ client.execute("ROLLBACK TRANSACTION").do
194
+ end
195
+
196
+
197
+ end
198
+ end
199
+