tiny_tds 0.4.5.rc1-x86-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.
data/lib/tiny_tds.rb ADDED
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+ require 'date'
3
+ require 'bigdecimal'
4
+ require 'rational' unless RUBY_VERSION >= '1.9.2'
5
+
6
+ require 'tiny_tds/version'
7
+ require 'tiny_tds/error'
8
+ require 'tiny_tds/client'
9
+ require 'tiny_tds/result'
10
+
11
+ # support multiple ruby version (fat binaries under windows)
12
+ begin
13
+ RUBY_VERSION =~ /(\d+.\d+)/
14
+ require "tiny_tds/#{$1}/tiny_tds"
15
+ rescue LoadError
16
+ require 'tiny_tds/tiny_tds'
17
+ end
18
+
19
+
data/tasks/ports.rake ADDED
@@ -0,0 +1,58 @@
1
+ require "mini_portile"
2
+ require "rake/extensioncompiler"
3
+
4
+ namespace :ports do
5
+
6
+ ICONV_VERSION = "1.13.1"
7
+ FREETDS_VERSION = ENV['TINYTDS_FREETDS_082'] ? "0.82" : "0.91"
8
+ FREETDS_VERSION_INFO = {
9
+ "0.82" => {:files => "http://ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-stable.tgz"},
10
+ "0.91" => {:files => "http://www.ibiblio.org/pub/Linux/ALPHA/freetds/current/freetds-current.tgz"} }
11
+
12
+ ORIGINAL_HOST = RbConfig::CONFIG["arch"]
13
+
14
+ directory "ports"
15
+
16
+ $recipes = {}
17
+ $recipes[:libiconv] = MiniPortile.new "libiconv", ICONV_VERSION
18
+ $recipes[:libiconv].files << "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
19
+
20
+ $recipes[:freetds] = MiniPortile.new "freetds", FREETDS_VERSION
21
+ $recipes[:freetds].files << FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
22
+
23
+ desc "Compile libiconv support library"
24
+ task :libiconv => ["ports"] do
25
+ recipe = $recipes[:libiconv]
26
+ checkpoint = "ports/.#{recipe.name}.#{recipe.version}.#{recipe.host}.timestamp"
27
+ unless File.exist?(checkpoint)
28
+ recipe.cook
29
+ touch checkpoint
30
+ end
31
+ recipe.activate
32
+ end
33
+
34
+ desc "Compile freetds library"
35
+ task :freetds => ["ports", :libiconv] do
36
+ recipe = $recipes[:freetds]
37
+ checkpoint = "ports/.#{recipe.name}.#{recipe.version}.#{recipe.host}.timestamp"
38
+ unless File.exist?(checkpoint)
39
+ # recipe.configure_options << "--disable-debug"
40
+ recipe.configure_options << '--sysconfdir="C:/Sites"' if recipe.host != ORIGINAL_HOST
41
+ recipe.configure_options << "--disable-odbc"
42
+ recipe.configure_options << "--with-tdsver=7.1"
43
+ recipe.cook
44
+ touch checkpoint
45
+ end
46
+ recipe.activate
47
+ end
48
+
49
+ end
50
+
51
+ task :cross do
52
+ host = ENV.fetch("HOST", Rake::ExtensionCompiler.mingw_host)
53
+ $recipes.each do |_, recipe|
54
+ recipe.host = host
55
+ end
56
+ # hook compile task with dependencies
57
+ Rake::Task["compile"].prerequisites.unshift "ports:freetds"
58
+ end
@@ -0,0 +1,77 @@
1
+ $:.unshift File.expand_path('../../../lib',__FILE__)
2
+ require 'rubygems'
3
+ require 'bench_press'
4
+ require 'tiny_tds'
5
+ require 'odbc'
6
+ require 'odbc_utf8'
7
+
8
+ extend BenchPress
9
+
10
+ author 'Ken Collins'
11
+ summary 'Query everything.'
12
+
13
+ reps 1_000
14
+
15
+ @odbc = ODBC.connect ENV['TINYTDS_UNIT_DATASERVER'], 'tinytds', ''
16
+ @odbc.use_time = true
17
+
18
+ @odbc_utf8 = ODBC_UTF8.connect ENV['TINYTDS_UNIT_DATASERVER'], 'tinytds', ''
19
+ @odbc_utf8.use_time = true
20
+
21
+ @tinytds = TinyTds::Client.new(
22
+ :dataserver => ENV['TINYTDS_UNIT_DATASERVER'],
23
+ :username => 'tinytds',
24
+ :password => '',
25
+ :database => 'tinytdstest',
26
+ :appname => 'TinyTds Dev',
27
+ :login_timeout => 5,
28
+ :timeout => 5 )
29
+
30
+ @query_all = "SELECT * FROM [datatypes]"
31
+
32
+
33
+ measure "ODBC (ascii-8bit)" do
34
+ h = @odbc.run(@query_all)
35
+ h.fetch_all
36
+ h.drop
37
+ end
38
+
39
+ # measure "ODBC (utf8)" do
40
+ # h = @odbc_utf8.run(@query_all)
41
+ # h.fetch_all
42
+ # h.drop
43
+ # end
44
+
45
+ measure "TinyTDS (row caching)" do
46
+ @tinytds.execute(@query_all).each
47
+ end
48
+
49
+ measure "TinyTDS (no caching)" do
50
+ @tinytds.execute(@query_all).each(:cache_rows => false)
51
+ end
52
+
53
+
54
+
55
+ =begin
56
+
57
+ Author: Ken Collins
58
+ Date: January 22, 2011
59
+ Summary: Query everything.
60
+
61
+ System Information
62
+ ------------------
63
+ Operating System: Mac OS X 10.6.6 (10J567)
64
+ CPU: Intel Core 2 Duo 1.6 GHz
65
+ Processor Count: 2
66
+ Memory: 4 GB
67
+ ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.3], MBARI 0x6770, Ruby Enterprise Edition 2010.02
68
+
69
+ "TinyTDS (row caching)" is up to 79% faster over 1,000 repetitions
70
+ ------------------------------------------------------------------
71
+
72
+ TinyTDS (row caching) 4.90862512588501 secs Fastest
73
+ TinyTDS (no caching) 4.91626906394958 secs 0% Slower
74
+ ODBC (ascii-8bit) 23.959536075592 secs 79% Slower
75
+
76
+ =end
77
+
@@ -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,111 @@
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
+ System Information
88
+ ------------------
89
+ Operating System: Mac OS X 10.6.4 (10F569)
90
+ CPU: Intel Core 2 Duo 2.4 GHz
91
+ Processor Count: 2
92
+ Memory: 4 GB
93
+ ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10.4.0]
94
+
95
+ "Nothing" is up to 89% faster over 1,000 repetitions
96
+ ----------------------------------------------------
97
+
98
+ Nothing 0.357741832733154 secs Fastest
99
+ Guids 0.460683107376099 secs 22% Slower
100
+ Bits 0.483309984207153 secs 25% Slower
101
+ Floats 0.505340099334717 secs 29% Slower
102
+ Moneys 0.523844003677368 secs 31% Slower
103
+ Integers 0.616975069046021 secs 42% Slower
104
+ Binaries 0.639773845672607 secs 44% Slower
105
+ Decimals 0.670897960662842 secs 46% Slower
106
+ Chars 0.800287008285522 secs 55% Slower
107
+ Dates 0.950634956359863 secs 62% Slower
108
+ All 2.91044211387634 secs 87% Slower
109
+
110
+ =end
111
+
@@ -0,0 +1,163 @@
1
+ require 'test_helper'
2
+
3
+ class ClientTest < TinyTds::TestCase
4
+
5
+ context 'With valid credentials' do
6
+
7
+ setup do
8
+ @client = new_connection
9
+ end
10
+
11
+ should 'not be closed' do
12
+ assert !@client.closed?
13
+ assert @client.active?
14
+ end
15
+
16
+ should 'allow client connection to be closed' do
17
+ assert @client.close
18
+ assert @client.closed?
19
+ assert !@client.active?
20
+ action = lambda { @client.execute('SELECT 1 as [one]').each }
21
+ assert_raise_tinytds_error(action) do |e|
22
+ assert_match %r{closed connection}i, e.message, 'ignore if non-english test run'
23
+ end
24
+ end
25
+
26
+ should 'have a getters for the tds version information (brittle since conf takes precedence)' do
27
+ assert_equal 9, @client.tds_version
28
+ assert_equal 'DBTDS_8_0 - Microsoft SQL Server 2000', @client.tds_version_info
29
+ end
30
+
31
+ should 'use UTF-8 client charset/encoding by default' do
32
+ assert_equal 'UTF-8', @client.charset
33
+ assert_equal Encoding.find('UTF-8'), @client.encoding if ruby19?
34
+ end
35
+
36
+ should 'have a #escape method used for quote strings' do
37
+ assert_equal "''hello''", @client.escape("'hello'")
38
+ end
39
+
40
+ should 'allow valid iconv character set' do
41
+ ['CP850', 'CP1252', 'ISO-8859-1'].each do |encoding|
42
+ client = new_connection(:encoding => encoding)
43
+ assert_equal encoding, client.charset
44
+ assert_equal Encoding.find(encoding), client.encoding if ruby19?
45
+ end
46
+ end
47
+
48
+ should 'be able to use :host/:port connection' do
49
+ client = new_connection :dataserver => nil, :host => ENV['TINYTDS_UNIT_HOST'], :port => 1433
50
+ end
51
+
52
+ end
53
+
54
+ context 'With in-valid options' do
55
+
56
+ should 'raise an argument error when no :host given and :dataserver is blank' do
57
+ assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
58
+ end
59
+
60
+ should 'raise an argument error when no :username is supplied' do
61
+ assert_raises(ArgumentError) { TinyTds::Client.new :username => nil }
62
+ end
63
+
64
+ should 'raise TinyTds exception with undefined :dataserver' do
65
+ options = connection_options :login_timeout => 1, :dataserver => '127.0.0.2'
66
+ action = lambda { new_connection(options) }
67
+ assert_raise_tinytds_error(action) do |e|
68
+ assert [20008,20009].include?(e.db_error_number)
69
+ assert_equal 9, e.severity
70
+ assert_match %r{unable to (open|connect)}i, e.message, 'ignore if non-english test run'
71
+ end
72
+ assert_new_connections_work
73
+ end
74
+
75
+ should 'raise TinyTds exception with long query past :timeout option' do
76
+ client = new_connection :timeout => 1
77
+ action = lambda { client.execute("WaitFor Delay '00:00:02'").do }
78
+ assert_raise_tinytds_error(action) do |e|
79
+ assert_equal 20003, e.db_error_number
80
+ assert_equal 6, e.severity
81
+ assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
82
+ end
83
+ assert_client_works(client)
84
+ assert_new_connections_work
85
+ end
86
+
87
+ should 'not timeout per sql batch when not under transaction' do
88
+ client = new_connection :timeout => 2
89
+ client.execute("WaitFor Delay '00:00:01'").do
90
+ client.execute("WaitFor Delay '00:00:01'").do
91
+ client.execute("WaitFor Delay '00:00:01'").do
92
+ end
93
+
94
+ should 'not timeout per sql batch when under transaction' do
95
+ client = new_connection :timeout => 2
96
+ begin
97
+ client.execute("BEGIN TRANSACTION").do
98
+ client.execute("WaitFor Delay '00:00:01'").do
99
+ client.execute("WaitFor Delay '00:00:01'").do
100
+ client.execute("WaitFor Delay '00:00:01'").do
101
+ ensure
102
+ client.execute("COMMIT TRANSACTION").do
103
+ end
104
+ end
105
+
106
+ should_eventually 'run this test to prove we account for dropped connections' do
107
+ begin
108
+ client = new_connection :login_timeout => 2, :timeout => 2
109
+ assert_client_works(client)
110
+ STDOUT.puts "Disconnect network!"
111
+ sleep 10
112
+ STDOUT.puts "This should not get stuck past 6 seconds!"
113
+ action = lambda { client.execute('SELECT 1 as [one]').each }
114
+ assert_raise_tinytds_error(action) do |e|
115
+ assert_equal 20003, e.db_error_number
116
+ assert_equal 6, e.severity
117
+ assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
118
+ end
119
+ ensure
120
+ STDOUT.puts "Reconnect network!"
121
+ sleep 10
122
+ action = lambda { client.execute('SELECT 1 as [one]').each }
123
+ assert_raise_tinytds_error(action) do |e|
124
+ assert_equal 20047, e.db_error_number
125
+ assert_equal 1, e.severity
126
+ assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
127
+ end
128
+ assert_new_connections_work
129
+ end
130
+ end
131
+
132
+ should 'raise TinyTds exception with wrong :username' do
133
+ options = connection_options :username => 'willnotwork'
134
+ action = lambda { new_connection(options) }
135
+ assert_raise_tinytds_error(action) do |e|
136
+ if sqlserver_azure?
137
+ assert_match %r{server name cannot be determined}i, e.message, 'ignore if non-english test run'
138
+ else
139
+ assert_equal 18456, e.db_error_number
140
+ assert_equal 14, e.severity
141
+ assert_match %r{login failed}i, e.message, 'ignore if non-english test run'
142
+ end
143
+ end
144
+ assert_new_connections_work
145
+ end
146
+
147
+ should 'fail miserably with unknown encoding option' do
148
+ options = connection_options :encoding => 'ISO-WTF'
149
+ action = lambda { new_connection(options) }
150
+ assert_raise_tinytds_error(action) do |e|
151
+ assert_equal 20002, e.db_error_number
152
+ assert_equal 9, e.severity
153
+ assert_match %r{connection failed}i, e.message, 'ignore if non-english test run'
154
+ end
155
+ assert_new_connections_work
156
+ end
157
+
158
+ end
159
+
160
+
161
+
162
+ end
163
+