tiny_tds 0.4.5.rc1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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
+