tiny_tds_vagas 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG +198 -0
- data/CODE_OF_CONDUCT.md +31 -0
- data/Gemfile +6 -0
- data/ISSUE_TEMPLATE.md +5 -0
- data/MIT-LICENSE +23 -0
- data/README.md +427 -0
- data/Rakefile +110 -0
- data/VERSION +1 -0
- data/appveyor.yml +52 -0
- data/bin/defncopy +3 -0
- data/bin/tsql +3 -0
- data/ext/tiny_tds/client.c +410 -0
- data/ext/tiny_tds/client.h +49 -0
- data/ext/tiny_tds/extconf.rb +329 -0
- data/ext/tiny_tds/extconsts.rb +15 -0
- data/ext/tiny_tds/result.c +608 -0
- data/ext/tiny_tds/result.h +32 -0
- data/ext/tiny_tds/tiny_tds_ext.c +12 -0
- data/ext/tiny_tds/tiny_tds_ext.h +17 -0
- data/lib/tiny_tds.rb +37 -0
- data/lib/tiny_tds/bin.rb +86 -0
- data/lib/tiny_tds/client.rb +124 -0
- data/lib/tiny_tds/error.rb +15 -0
- data/lib/tiny_tds/result.rb +8 -0
- data/lib/tiny_tds/version.rb +3 -0
- data/ports/patches/freetds/1.00/0001-mingw_missing_inet_pton.diff +34 -0
- data/test/appveyor/dbsetup.ps1 +27 -0
- data/test/appveyor/dbsetup.sql +9 -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 +217 -0
- data/test/result_test.rb +728 -0
- data/test/schema/1px.gif +0 -0
- data/test/schema/sqlserver_2000.sql +140 -0
- data/test/schema/sqlserver_2005.sql +140 -0
- data/test/schema/sqlserver_2008.sql +140 -0
- data/test/schema/sqlserver_2014.sql +140 -0
- data/test/schema/sqlserver_azure.sql +140 -0
- data/test/schema/sybase_ase.sql +138 -0
- data/test/schema_test.rb +443 -0
- data/test/test_helper.rb +213 -0
- data/test/thread_test.rb +98 -0
- data/tiny_tds.gemspec +28 -0
- metadata +201 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bench_press'
|
3
|
+
begin gem 'odbc', '0.99992' ; rescue Gem::LoadError ; end
|
4
|
+
require 'odbc'
|
5
|
+
|
6
|
+
extend BenchPress
|
7
|
+
|
8
|
+
author 'Ken Collins'
|
9
|
+
summary 'Benchmarking ODBC Querys'
|
10
|
+
|
11
|
+
reps 1_000
|
12
|
+
|
13
|
+
@client = ODBC.connect ENV['TINYTDS_UNIT_DATASERVER'], 'tinytds', ''
|
14
|
+
@client.use_time = true
|
15
|
+
|
16
|
+
@query_nothing = "SELECT NULL AS [null]"
|
17
|
+
@query_ints = "SELECT [int], [bigint], [smallint], [tinyint] FROM [datatypes]"
|
18
|
+
@query_binaries = "SELECT [binary_50], [image], [varbinary_50] FROM [datatypes]"
|
19
|
+
@query_bits = "SELECT [bit] FROM [datatypes]"
|
20
|
+
@query_chars = "SELECT [char_10], [nchar_10], [ntext], [nvarchar_50], [text], [varchar_50] FROM [datatypes]"
|
21
|
+
@query_dates = "SELECT [datetime], [smalldatetime] FROM [datatypes]"
|
22
|
+
@query_decimals = "SELECT [decimal_9_2], [decimal_16_4], [numeric_18_0], [numeric_36_2] FROM [datatypes]"
|
23
|
+
@query_floats = "SELECT [float], [real] FROM [datatypes]"
|
24
|
+
@query_moneys = "SELECT [money], [smallmoney] FROM [datatypes]"
|
25
|
+
@query_guids = "SELECT [uniqueidentifier] FROM [datatypes]"
|
26
|
+
@query_all = "SELECT * FROM [datatypes]"
|
27
|
+
|
28
|
+
def select_all(query)
|
29
|
+
h = @client.run(query)
|
30
|
+
h.fetch_all
|
31
|
+
h.drop
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
measure "Nothing" do
|
36
|
+
select_all @query_nothing
|
37
|
+
end
|
38
|
+
|
39
|
+
measure "Integers" do
|
40
|
+
select_all @query_ints
|
41
|
+
end
|
42
|
+
|
43
|
+
measure "Binaries" do
|
44
|
+
select_all @query_binaries
|
45
|
+
end
|
46
|
+
|
47
|
+
measure "Bits" do
|
48
|
+
select_all @query_bits
|
49
|
+
end
|
50
|
+
|
51
|
+
measure "Chars" do
|
52
|
+
select_all @query_chars
|
53
|
+
end
|
54
|
+
|
55
|
+
measure "Dates" do
|
56
|
+
select_all @query_dates
|
57
|
+
end
|
58
|
+
|
59
|
+
measure "Decimals" do
|
60
|
+
select_all @query_decimals
|
61
|
+
end
|
62
|
+
|
63
|
+
measure "Floats" do
|
64
|
+
select_all @query_floats
|
65
|
+
end
|
66
|
+
|
67
|
+
measure "Moneys" do
|
68
|
+
select_all @query_moneys
|
69
|
+
end
|
70
|
+
|
71
|
+
measure "Guids" do
|
72
|
+
select_all @query_guids
|
73
|
+
end
|
74
|
+
|
75
|
+
measure "All" do
|
76
|
+
select_all @query_all
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
=begin
|
81
|
+
|
82
|
+
System Information
|
83
|
+
------------------
|
84
|
+
Operating System: Mac OS X 10.6.4 (10F569)
|
85
|
+
CPU: Intel Core 2 Duo 2.4 GHz
|
86
|
+
Processor Count: 2
|
87
|
+
Memory: 4 GB
|
88
|
+
ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10.4.0]
|
89
|
+
|
90
|
+
"Nothing" is up to 98% faster over 1,000 repetitions
|
91
|
+
----------------------------------------------------
|
92
|
+
|
93
|
+
Nothing 0.297961950302124 secs Fastest
|
94
|
+
Bits 0.377611875534058 secs 21% Slower
|
95
|
+
Guids 0.381000995635986 secs 21% Slower
|
96
|
+
Moneys 0.405518054962158 secs 26% Slower
|
97
|
+
Floats 0.409428119659424 secs 27% Slower
|
98
|
+
Integers 0.448167085647583 secs 33% Slower
|
99
|
+
Decimals 0.471596956253052 secs 36% Slower
|
100
|
+
Dates 0.52501106262207 secs 43% Slower
|
101
|
+
Binaries 3.66349482536316 secs 91% Slower
|
102
|
+
Chars 6.82928085327148 secs 95% Slower
|
103
|
+
All 28.4982612133026 secs 98% Slower
|
104
|
+
|
105
|
+
=end
|
106
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bench_press'
|
3
|
+
$:.unshift File.expand_path('../../../lib',__FILE__)
|
4
|
+
require 'tiny_tds'
|
5
|
+
|
6
|
+
extend BenchPress
|
7
|
+
|
8
|
+
author 'Ken Collins'
|
9
|
+
summary 'Benchmark TinyTds Querys'
|
10
|
+
|
11
|
+
reps 1_000
|
12
|
+
|
13
|
+
@client = TinyTds::Client.new({
|
14
|
+
:dataserver => ENV['TINYTDS_UNIT_DATASERVER'],
|
15
|
+
:username => 'tinytds',
|
16
|
+
:password => '',
|
17
|
+
:database => 'tinytdstest',
|
18
|
+
:appname => 'TinyTds Dev',
|
19
|
+
:login_timeout => 5,
|
20
|
+
:timeout => 5
|
21
|
+
})
|
22
|
+
|
23
|
+
@query_nothing = "SELECT NULL AS [null]"
|
24
|
+
@query_ints = "SELECT [int], [bigint], [smallint], [tinyint] FROM [datatypes]"
|
25
|
+
@query_binaries = "SELECT [binary_50], [image], [varbinary_50] FROM [datatypes]"
|
26
|
+
@query_bits = "SELECT [bit] FROM [datatypes]"
|
27
|
+
@query_chars = "SELECT [char_10], [nchar_10], [ntext], [nvarchar_50], [text], [varchar_50] FROM [datatypes]"
|
28
|
+
@query_dates = "SELECT [datetime], [smalldatetime] FROM [datatypes]"
|
29
|
+
@query_decimals = "SELECT [decimal_9_2], [decimal_16_4], [numeric_18_0], [numeric_36_2] FROM [datatypes]"
|
30
|
+
@query_floats = "SELECT [float], [real] FROM [datatypes]"
|
31
|
+
@query_moneys = "SELECT [money], [smallmoney] FROM [datatypes]"
|
32
|
+
@query_guids = "SELECT [uniqueidentifier] FROM [datatypes]"
|
33
|
+
@query_all = "SELECT * FROM [datatypes]"
|
34
|
+
|
35
|
+
def select_all(query)
|
36
|
+
@client.execute(query).each
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
measure "Nothing" do
|
41
|
+
select_all @query_nothing
|
42
|
+
end
|
43
|
+
|
44
|
+
measure "Integers" do
|
45
|
+
select_all @query_ints
|
46
|
+
end
|
47
|
+
|
48
|
+
measure "Binaries" do
|
49
|
+
select_all @query_binaries
|
50
|
+
end
|
51
|
+
|
52
|
+
measure "Bits" do
|
53
|
+
select_all @query_bits
|
54
|
+
end
|
55
|
+
|
56
|
+
measure "Chars" do
|
57
|
+
select_all @query_chars
|
58
|
+
end
|
59
|
+
|
60
|
+
measure "Dates" do
|
61
|
+
select_all @query_dates
|
62
|
+
end
|
63
|
+
|
64
|
+
measure "Decimals" do
|
65
|
+
select_all @query_decimals
|
66
|
+
end
|
67
|
+
|
68
|
+
measure "Floats" do
|
69
|
+
select_all @query_floats
|
70
|
+
end
|
71
|
+
|
72
|
+
measure "Moneys" do
|
73
|
+
select_all @query_moneys
|
74
|
+
end
|
75
|
+
|
76
|
+
measure "Guids" do
|
77
|
+
select_all @query_guids
|
78
|
+
end
|
79
|
+
|
80
|
+
measure "All" do
|
81
|
+
select_all @query_all
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
=begin
|
86
|
+
|
87
|
+
Query Tinytds
|
88
|
+
=============
|
89
|
+
Author: Ken Collins
|
90
|
+
Date: September 11, 2011
|
91
|
+
Summary: Benchmark TinyTds Querys
|
92
|
+
|
93
|
+
System Information
|
94
|
+
------------------
|
95
|
+
Operating System: Mac OS X 10.7.1 (11B26)
|
96
|
+
CPU: Quad-Core Intel Xeon 2.66 GHz
|
97
|
+
Processor Count: 4
|
98
|
+
Memory: 24 GB
|
99
|
+
ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin11.1.0], MBARI 0x6770, Ruby Enterprise Edition 2011.03
|
100
|
+
|
101
|
+
----------------------------------------------------
|
102
|
+
(before 64bit times) (after 64bit times)
|
103
|
+
Nothing 0.287657022476196 secs Nothing 0.289273977279663 secs
|
104
|
+
Bits 0.406533002853394 secs Bits 0.424988031387329 secs
|
105
|
+
Guids 0.419962882995605 secs Guids 0.427381992340088 secs
|
106
|
+
Floats 0.452103137969971 secs Floats 0.455377101898193 secs
|
107
|
+
Moneys 0.481696844100952 secs Moneys 0.485175132751465 secs
|
108
|
+
Integers 0.496185064315796 secs Integers 0.525003910064697 secs
|
109
|
+
Binaries 0.538873195648193 secs Decimals 0.541536808013916 secs
|
110
|
+
Decimals 0.540570974349976 secs Binaries 0.542865991592407 secs
|
111
|
+
Dates 0.761389970779419 secs Dates 1.51440119743347 secs
|
112
|
+
Chars 0.793163061141968 secs Chars 0.666505098342896 secs
|
113
|
+
All 4.4630811214447 secs All 5.17242312431335 secs
|
114
|
+
|
115
|
+
=end
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ClientTest < TinyTds::TestCase
|
5
|
+
|
6
|
+
describe 'With valid credentials' do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@client = new_connection
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'must not be closed' do
|
13
|
+
assert !@client.closed?
|
14
|
+
assert @client.active?
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows client connection to be closed' do
|
18
|
+
assert @client.close
|
19
|
+
assert @client.closed?
|
20
|
+
assert !@client.active?
|
21
|
+
action = lambda { @client.execute('SELECT 1 as [one]').each }
|
22
|
+
assert_raise_tinytds_error(action) do |e|
|
23
|
+
assert_match %r{closed connection}i, e.message, 'ignore if non-english test run'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has getters for the tds version information (brittle since conf takes precedence)' do
|
28
|
+
if sybase_ase?
|
29
|
+
assert_equal 7, @client.tds_version
|
30
|
+
assert_equal 'DBTDS_5_0 - 5.0 SQL Server', @client.tds_version_info
|
31
|
+
elsif @client.tds_73?
|
32
|
+
assert_equal 11, @client.tds_version
|
33
|
+
assert_equal 'DBTDS_7_3 - Microsoft SQL Server 2008', @client.tds_version_info
|
34
|
+
else
|
35
|
+
assert_equal 9, @client.tds_version
|
36
|
+
assert_equal 'DBTDS_7_1/DBTDS_8_0 - Microsoft SQL Server 2000', @client.tds_version_info
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'uses UTF-8 client charset/encoding by default' do
|
41
|
+
assert_equal 'UTF-8', @client.charset
|
42
|
+
assert_equal Encoding.find('UTF-8'), @client.encoding
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'has a #escape method used for quote strings' do
|
46
|
+
assert_equal "''hello''", @client.escape("'hello'")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'allows valid iconv character set' do
|
50
|
+
['CP850', 'CP1252', 'ISO-8859-1'].each do |encoding|
|
51
|
+
client = new_connection(:encoding => encoding)
|
52
|
+
assert_equal encoding, client.charset
|
53
|
+
assert_equal Encoding.find(encoding), client.encoding
|
54
|
+
client.close
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'must be able to use :host/:port connection' do
|
59
|
+
host = ENV['TINYTDS_UNIT_HOST_TEST'] || ENV['TINYTDS_UNIT_HOST']
|
60
|
+
port = ENV['TINYTDS_UNIT_PORT_TEST'] || ENV['TINYTDS_UNIT_PORT'] || 1433
|
61
|
+
client = new_connection dataserver: nil, host: host, port: port
|
62
|
+
client.close
|
63
|
+
end unless sqlserver_azure?
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'With in-valid options' do
|
68
|
+
|
69
|
+
it 'raises an argument error when no :host given and :dataserver is blank' do
|
70
|
+
assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'raises an argument error when no :username is supplied' do
|
74
|
+
assert_raises(ArgumentError) { TinyTds::Client.new :username => nil }
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'raises TinyTds exception with undefined :dataserver' do
|
78
|
+
options = connection_options :login_timeout => 1, :dataserver => 'DOESNOTEXIST'
|
79
|
+
action = lambda { new_connection(options) }
|
80
|
+
assert_raise_tinytds_error(action) do |e|
|
81
|
+
assert_equal 20012, e.db_error_number
|
82
|
+
assert_equal 2, e.severity
|
83
|
+
assert_match %r{server name not found in configuration files}i, e.message, 'ignore if non-english test run'
|
84
|
+
end
|
85
|
+
assert_new_connections_work
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'raises TinyTds exception with long query past :timeout option' do
|
89
|
+
client = new_connection :timeout => 1
|
90
|
+
action = lambda { client.execute("WaitFor Delay '00:00:02'").do }
|
91
|
+
assert_raise_tinytds_error(action) do |e|
|
92
|
+
assert_equal 20003, e.db_error_number
|
93
|
+
assert_equal 6, e.severity
|
94
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
95
|
+
end
|
96
|
+
assert_client_works(client)
|
97
|
+
close_client(client)
|
98
|
+
assert_new_connections_work
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'must not timeout per sql batch when not under transaction' do
|
102
|
+
client = new_connection :timeout => 2
|
103
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
104
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
105
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
106
|
+
close_client(client)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'must not timeout per sql batch when under transaction' do
|
110
|
+
client = new_connection :timeout => 2
|
111
|
+
begin
|
112
|
+
client.execute("BEGIN TRANSACTION").do
|
113
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
114
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
115
|
+
client.execute("WaitFor Delay '00:00:01'").do
|
116
|
+
ensure
|
117
|
+
client.execute("COMMIT TRANSACTION").do
|
118
|
+
close_client(client)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'must run this test to prove we account for dropped connections' do
|
123
|
+
skip
|
124
|
+
begin
|
125
|
+
client = new_connection :login_timeout => 2, :timeout => 2
|
126
|
+
assert_client_works(client)
|
127
|
+
STDOUT.puts "Disconnect network!"
|
128
|
+
sleep 10
|
129
|
+
STDOUT.puts "This should not get stuck past 6 seconds!"
|
130
|
+
action = lambda { client.execute('SELECT 1 as [one]').each }
|
131
|
+
assert_raise_tinytds_error(action) do |e|
|
132
|
+
assert_equal 20003, e.db_error_number
|
133
|
+
assert_equal 6, e.severity
|
134
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
135
|
+
end
|
136
|
+
ensure
|
137
|
+
STDOUT.puts "Reconnect network!"
|
138
|
+
sleep 10
|
139
|
+
action = lambda { client.execute('SELECT 1 as [one]').each }
|
140
|
+
assert_raise_tinytds_error(action) do |e|
|
141
|
+
assert_equal 20047, e.db_error_number
|
142
|
+
assert_equal 1, e.severity
|
143
|
+
assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
|
144
|
+
end
|
145
|
+
close_client(client)
|
146
|
+
assert_new_connections_work
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'raises TinyTds exception with wrong :username' do
|
151
|
+
skip if ENV['CI'] && sqlserver_azure? # Some issue with db_error_number.
|
152
|
+
options = connection_options :username => 'willnotwork'
|
153
|
+
action = lambda { new_connection(options) }
|
154
|
+
assert_raise_tinytds_error(action) do |e|
|
155
|
+
assert_equal sybase_ase? ? 4002 : 18456, e.db_error_number
|
156
|
+
assert_equal 14, e.severity
|
157
|
+
assert_match %r{login failed}i, e.message, 'ignore if non-english test run'
|
158
|
+
end
|
159
|
+
assert_new_connections_work
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'Private methods' do
|
165
|
+
|
166
|
+
let(:client) { @client = new_connection }
|
167
|
+
|
168
|
+
it '#parse_username returns username if azure is not true' do
|
169
|
+
username = 'user@abc123.database.windows.net'
|
170
|
+
client.send(:parse_username, username: username).must_equal username
|
171
|
+
end
|
172
|
+
|
173
|
+
it '#parse_username returns short username if azure is true' do
|
174
|
+
client.send(:parse_username,
|
175
|
+
username: 'user@abc123.database.windows.net',
|
176
|
+
host: 'abc123.database.windows.net',
|
177
|
+
azure: true
|
178
|
+
).must_equal 'user@abc123'
|
179
|
+
end
|
180
|
+
|
181
|
+
it '#parse_username returns full username if azure is false' do
|
182
|
+
client.send(:parse_username,
|
183
|
+
username: 'user@abc123.database.windows.net',
|
184
|
+
host: 'abc123.database.windows.net',
|
185
|
+
azure: false
|
186
|
+
).must_equal 'user@abc123.database.windows.net'
|
187
|
+
end
|
188
|
+
|
189
|
+
it '#parse_username returns short username if passed and azure is true' do
|
190
|
+
client.send(:parse_username,
|
191
|
+
username: 'user@abc123',
|
192
|
+
host: 'abc123.database.windows.net',
|
193
|
+
azure: true
|
194
|
+
).must_equal 'user@abc123'
|
195
|
+
end
|
196
|
+
|
197
|
+
it '#parse_username returns username with servername if passed and azure is true' do
|
198
|
+
client.send(:parse_username,
|
199
|
+
username: 'user',
|
200
|
+
host: 'abc123.database.windows.net',
|
201
|
+
azure: true
|
202
|
+
).must_equal 'user@abc123'
|
203
|
+
end
|
204
|
+
|
205
|
+
it '#parse_username returns username with servername if passed and azure is false' do
|
206
|
+
client.send(:parse_username,
|
207
|
+
username: 'user',
|
208
|
+
host: 'abc123.database.windows.net',
|
209
|
+
azure: false
|
210
|
+
).must_equal 'user'
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
end
|
217
|
+
|