do_sqlserver-tinytds 0.10.17.alpha

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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +3 -0
  5. data/.rspec +2 -0
  6. data/CONNECTING.markdown +40 -0
  7. data/ChangeLog.markdown +56 -0
  8. data/FAQS.markdown +8 -0
  9. data/Gemfile +3 -0
  10. data/Gemfile.lock +30 -0
  11. data/INSTALL.markdown +76 -0
  12. data/LICENSE +21 -0
  13. data/README.md +95 -0
  14. data/Rakefile +7 -0
  15. data/buildfile +27 -0
  16. data/do_sqlserver_tinytds.gemspec +31 -0
  17. data/lib/do_sqlserver.rb +1 -0
  18. data/lib/do_sqlserver_tinytds.rb +360 -0
  19. data/lib/do_sqlserver_tinytds/addressable_extension.rb +69 -0
  20. data/lib/do_sqlserver_tinytds/tiny_tds_extension.rb +123 -0
  21. data/lib/do_sqlserver_tinytds/transaction.rb +36 -0
  22. data/lib/do_sqlserver_tinytds/version.rb +5 -0
  23. data/spec/command_spec.rb +9 -0
  24. data/spec/connection_spec.rb +21 -0
  25. data/spec/encoding_spec.rb +8 -0
  26. data/spec/reader_spec.rb +8 -0
  27. data/spec/result_spec.rb +16 -0
  28. data/spec/spec_helper.rb +155 -0
  29. data/spec/typecast/array_spec.rb +8 -0
  30. data/spec/typecast/bigdecimal_spec.rb +9 -0
  31. data/spec/typecast/boolean_spec.rb +9 -0
  32. data/spec/typecast/byte_array_spec.rb +31 -0
  33. data/spec/typecast/class_spec.rb +8 -0
  34. data/spec/typecast/date_spec.rb +11 -0
  35. data/spec/typecast/datetime_spec.rb +9 -0
  36. data/spec/typecast/float_spec.rb +9 -0
  37. data/spec/typecast/integer_spec.rb +8 -0
  38. data/spec/typecast/nil_spec.rb +10 -0
  39. data/spec/typecast/other_spec.rb +8 -0
  40. data/spec/typecast/range_spec.rb +8 -0
  41. data/spec/typecast/string_spec.rb +8 -0
  42. data/spec/typecast/time_spec.rb +8 -0
  43. metadata +169 -0
  44. metadata.gz.sig +3 -0
@@ -0,0 +1,69 @@
1
+ #require "addressable/uri"
2
+ #
3
+ #module Addressable
4
+ # class URI
5
+ # def self.parse(uri)
6
+ #
7
+ # # If we were given nil, return nil.
8
+ # return nil unless uri
9
+ # # If a URI object is passed, just return itself.
10
+ # return uri.dup if uri.kind_of?(self)
11
+ #
12
+ # # If a URI object of the Ruby standard library variety is passed,
13
+ # # convert it to a string, then parse the string.
14
+ # # We do the check this way because we don't want to accidentally
15
+ # # cause a missing constant exception to be thrown.
16
+ # if uri.class.name =~ /^URI\b/
17
+ # uri = uri.to_s
18
+ # end
19
+ #
20
+ # # Otherwise, convert to a String
21
+ # begin
22
+ # uri = uri.to_str
23
+ # rescue TypeError, NoMethodError
24
+ # raise TypeError, "Can't convert #{uri.class} into String."
25
+ # end if not uri.is_a? String
26
+ #
27
+ # # This Regexp supplied as an example in RFC 3986, and it works great.
28
+ # scan = uri.scan(URIREGEX)
29
+ # fragments = scan[0]
30
+ # scheme = fragments[1]
31
+ # authority = fragments[3]
32
+ # path = fragments[4]
33
+ # query = fragments[6]
34
+ # fragment = fragments[8]
35
+ # user = nil
36
+ # password = nil
37
+ # host = nil
38
+ # port = nil
39
+ # database = nil
40
+ # if authority != nil
41
+ # # The Regexp above doesn't split apart the authority.
42
+ # userinfo = authority[/^([^\[\]]*)@/, 1]
43
+ # if userinfo != nil
44
+ # user = userinfo.strip[/^([^:]*):?/, 1]
45
+ # password = userinfo.strip[/:(.*)$/, 1]
46
+ # end
47
+ # host = authority.gsub(/^([^\[\]]*)@/, EMPTYSTR).gsub(/:([^:@\[\]]*?)$/, EMPTYSTR)
48
+ # port = authority[/:(\d+).*$/ , 1]#authority[/:([^:@\[\]]*?)$/, 1]
49
+ # database = authority[/:\d+(.*)$/ , 1]
50
+ # end
51
+ # if port == EMPTYSTR
52
+ # port = nil
53
+ # end
54
+ #
55
+ # return Addressable::URI.new(
56
+ # :scheme => scheme,
57
+ # :user => user,
58
+ # :password => password,
59
+ # :host => host,
60
+ # :port => port,
61
+ # :path => path,
62
+ # :query => query,
63
+ # :fragment => fragment,
64
+ # :database => database
65
+ # )
66
+ #
67
+ # end
68
+ # end
69
+ #end
@@ -0,0 +1,123 @@
1
+ require 'tiny_tds'
2
+
3
+ module TinyTds
4
+ class Client
5
+ #raw_execute - freetds does not support dynamic sql so
6
+ #we're going to translate dynamic sql statements into a plain
7
+ #sql statement
8
+ def raw_execute(text , *var_list)
9
+
10
+ dynamic_sql = text.clone
11
+ flat_sql = var_list.empty? ? dynamic_sql : process_questioned_sql(dynamic_sql , *var_list)
12
+ execute(flat_sql)
13
+ end
14
+
15
+ :private
16
+
17
+ def process_questioned_sql(sql , *vars)
18
+ sql_type = classify_sql(sql)
19
+
20
+ result = substitute_quoted_questions(sql)
21
+ _sql = result[:sql]
22
+
23
+ vars.each do |var|
24
+ _sql.sub!("?" , convert_type_to_s(var , sql_type))
25
+ end
26
+
27
+ #place back strings in the sql that contained "?"
28
+ result[:container].each do |k,v|
29
+ _sql.gsub!(k , v)
30
+ end
31
+
32
+ _sql
33
+ end
34
+
35
+ def substitute_quoted_questions(sql)
36
+ container = {}
37
+ #collect strings in the sql that contains a question_mark
38
+ qstrings = sql.scan(/"[^"]*"/).select{|s| s.include?("?")}
39
+
40
+ #temporarily replace quoted values
41
+ counter = 0
42
+ qstrings.each do |qstring|
43
+ key = "(((####{counter}###)))"
44
+ sql.gsub!(qstring, key)
45
+
46
+ container[key] = qstring
47
+ counter += 1
48
+ end
49
+
50
+ {:sql => sql, :container => container}
51
+ end
52
+
53
+ #convert_type_to_s - convert Ruby collection objects fed into the query into
54
+ #sql strings
55
+ def convert_type_to_s(arg , sql_type)
56
+
57
+ case sql_type
58
+ when :between
59
+ case arg
60
+ when Range , Array
61
+ "#{sql_stringify_value(arg.first)} AND #{sql_stringify_value(arg.last)}"
62
+ else
63
+ raise "Type not found..."
64
+ end
65
+ when :in
66
+ case arg
67
+ when Range , Array
68
+ " (#{arg.collect{|e| "#{sql_stringify_value(e)}"}.join(" , ")}) "
69
+ else
70
+ raise "Type not found..."
71
+ end
72
+ else
73
+ case arg
74
+ when Range , Array
75
+ arg.collect{|e| "#{sql_stringify_value(e)}"}.join(" , ")
76
+ else
77
+ sql_stringify_value(arg)
78
+ end
79
+ end
80
+ end
81
+
82
+ #convert_type_to_s - convert Ruby object fed into the query into
83
+ #sql string
84
+ def sql_stringify_value(value)
85
+ case
86
+ when value.is_a?(String)
87
+ "N'#{value}'"
88
+ when value.is_a?(Numeric)
89
+ value.to_s
90
+ when value.is_a?(NilClass)
91
+ "NULL"
92
+ when value.is_a?(DateTime)
93
+ value.strftime("'%m/%d/%Y %I:%M:%S %p'")
94
+ when value.is_a?(Time)
95
+ DateTime.new(value.year, value.month, value.day,
96
+ value.hour, value.min, value.sec,
97
+ Rational(value.gmt_offset / 3600, 24)).strftime("'%m/%d/%Y %I:%M:%S %p'")
98
+ else
99
+ "N'#{value.to_s}'"
100
+ end
101
+ end
102
+
103
+ #classify_sql - determine if this sql has a between or in
104
+ def classify_sql(sql)
105
+ case
106
+ when sql[/between.+\?/i] #var should be an array
107
+ :between
108
+ when sql[/\sin\s+\?/i]
109
+ :in
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ class Error
116
+ alias :to_str :to_s
117
+
118
+ def errstr
119
+ @errstr ||= []
120
+ @errstr
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,36 @@
1
+ module DataObjects
2
+
3
+ module SqlServer
4
+
5
+ class Transaction < DataObjects::Transaction
6
+
7
+ def begin
8
+ connection.instance_variable_get("@connection").autocommit = false
9
+ end
10
+
11
+ def commit
12
+ connection.instance_variable_get("@connection").commit
13
+ ensure
14
+ connection.instance_variable_get("@connection").autocommit = true
15
+ end
16
+
17
+ def rollback
18
+ connection.instance_variable_get("@connection").rollback
19
+ ensure
20
+ connection.instance_variable_get("@connection").autocommit = true
21
+ end
22
+
23
+ def rollback_prepared
24
+ # TODO: what should be done differently?
25
+ rollback
26
+ end
27
+
28
+ def prepare
29
+ # TODO: what should be done here?
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,5 @@
1
+ module DataObjects
2
+ module SqlServer
3
+ VERSION = '0.10.17.alpha'
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
4
+ require 'data_objects/spec/shared/command_spec'
5
+
6
+ describe DataObjects::SqlServer::Command do
7
+ it_should_behave_like 'a Command'
8
+ it_should_behave_like 'a Command with async'
9
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
4
+ require 'data_objects/spec/shared/connection_spec'
5
+
6
+ describe DataObjects::SqlServer::Connection do
7
+
8
+ before :all do
9
+ @driver = CONFIG.scheme
10
+ @user = CONFIG.user
11
+ @password = CONFIG.pass
12
+ @host = CONFIG.host
13
+ @port = CONFIG.port
14
+ @database = CONFIG.database
15
+ end
16
+
17
+ it_should_behave_like 'a Connection'
18
+ it_should_behave_like 'a Connection with authentication support'
19
+ it_should_behave_like 'a Connection with JDBC URL support' if JRUBY
20
+ it_should_behave_like 'a Connection via JDNI' if JRUBY
21
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
4
+ require 'data_objects/spec/shared/encoding_spec'
5
+
6
+ describe DataObjects::SqlServer::Connection do
7
+ it_should_behave_like 'a driver supporting different encodings'
8
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
4
+ require 'data_objects/spec/shared/reader_spec'
5
+
6
+ describe DataObjects::SqlServer::Reader do
7
+ it_should_behave_like 'a Reader'
8
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
4
+ require 'data_objects/spec/shared/result_spec'
5
+
6
+ # splitting the descibe into two separate declaration avoids
7
+ # concurrent execution of the "it_should_behave_like ....."
8
+ # needed by some databases (sqlite3)
9
+
10
+ describe DataObjects::SqlServer::Result do
11
+ it_should_behave_like 'a Result'
12
+ end
13
+
14
+ describe DataObjects::SqlServer::Result do
15
+ it_should_behave_like 'a Result which returns inserted key with sequences'
16
+ end
@@ -0,0 +1,155 @@
1
+ $TESTING=true
2
+ JRUBY = nil
3
+
4
+ require 'rubygems'
5
+ require 'rspec'
6
+ require 'date'
7
+ require 'ostruct'
8
+ require 'fileutils'
9
+
10
+ driver_lib = File.expand_path('../../lib', __FILE__)
11
+ $LOAD_PATH.unshift(driver_lib) unless $LOAD_PATH.include?(driver_lib)
12
+
13
+
14
+ repo_root = File.expand_path('../../..', __FILE__)
15
+
16
+
17
+ require 'data_objects'
18
+ require 'data_objects/spec/setup'
19
+ require 'data_objects/spec/lib/pending_helpers'
20
+ require 'do_sqlserver_tinytds'
21
+ require 'ruby-debug'
22
+
23
+ DataObjects::SqlServer.logger = DataObjects::Logger.new(STDOUT, :off)
24
+ at_exit { DataObjects.logger.flush }
25
+
26
+
27
+ CONFIG = OpenStruct.new
28
+ CONFIG.scheme = 'sqlserver'
29
+ CONFIG.user = ENV['DO_SQLSERVER_USER'] || 'sa'
30
+ CONFIG.pass = ENV['DO_SQLSERVER_PASS'] || 'p@$$word'
31
+ CONFIG.host = ENV['DO_SQLSERVER_HOST'] || 'MSSQLLOCAL'
32
+ CONFIG.port = ENV['DO_SQLSERVER_PORT'] || '1433'
33
+ CONFIG.instance = ENV['DO_SQLSERVER_INSTANCE'] || 'SQLEXPRESS'
34
+ CONFIG.database = ENV['DO_SQLSERVER_DATABASE'] || "/datamapper_test"
35
+
36
+ CONFIG.driver = 'sqlserver'
37
+ CONFIG.uri = ENV["DO_SQLSERVER_SPEC_URI"] ||"#{CONFIG.scheme}://#{CONFIG.user}:#{CONFIG.pass}@#{CONFIG.host}:#{CONFIG.port}#{CONFIG.database}"
38
+ CONFIG.sleep = "WAITFOR DELAY '00:00:00:10'"
39
+
40
+ module DataObjectsSpecHelpers
41
+
42
+ def setup_test_environment
43
+ conn = DataObjects::Connection.new(CONFIG.uri)
44
+
45
+ conn.create_command(<<-EOF).execute_non_query
46
+ IF OBJECT_ID('invoices') IS NOT NULL DROP TABLE invoices
47
+ EOF
48
+
49
+ conn.create_command(<<-EOF).execute_non_query
50
+ IF OBJECT_ID('users') IS NOT NULL DROP TABLE users
51
+ EOF
52
+
53
+ conn.create_command(<<-EOF).execute_non_query
54
+ IF OBJECT_ID('widgets') IS NOT NULL DROP TABLE widgets
55
+ EOF
56
+
57
+ conn.create_command(<<-EOF).execute_non_query
58
+ CREATE TABLE [users] (
59
+ [id] int NOT NULL IDENTITY,
60
+ [name] nvarchar(200) default 'Billy' NULL,
61
+ [fired_at] timestamp,
62
+ PRIMARY KEY ([id])
63
+ );
64
+ EOF
65
+
66
+ conn.create_command(<<-EOF).execute_non_query
67
+ CREATE TABLE [invoices] (
68
+ [id] int NOT NULL IDENTITY,
69
+ [invoice_number] varchar(50) NOT NULL,
70
+ PRIMARY KEY ([id])
71
+ );
72
+ EOF
73
+
74
+ conn.create_command(<<-EOF).execute_non_query
75
+ CREATE TABLE [widgets] (
76
+ [id] int NOT NULL IDENTITY,
77
+ [code] char(8) default 'A14' NULL,
78
+ [name] varchar(200) default 'Super Widget' NULL,
79
+ [shelf_location] nvarchar(max) NULL,
80
+ [description] nvarchar(max) NULL,
81
+ [image_data] image NULL,
82
+ [ad_description] varchar(8000) NULL,
83
+ [ad_image] image NULL,
84
+ [whitepaper_text] nvarchar(max) NULL,
85
+ [cad_drawing] image NULL,
86
+ [flags] bit default 0 NULL,
87
+ [number_in_stock] smallint default 500,
88
+ [number_sold] int default 0,
89
+ [super_number] bigint default 9223372036854775807,
90
+ [weight] float default 1.23,
91
+ [cost1] real default 10.23 NULL,
92
+ [cost2] decimal(8,2) default 50.23 NULL,
93
+ [release_date] smalldatetime default '2008-02-14' NULL, -- date type is SQL Server 2008 only
94
+ [release_datetime] datetime default '2008-02-14 00:31:12' NULL,
95
+ [release_timestamp] smalldatetime /* default '2008-02-14 00:31:31' */ NULL,
96
+ -- [status] enum('active','out of stock') NOT NULL default 'active',
97
+ PRIMARY KEY ([id])
98
+ );
99
+ EOF
100
+
101
+ 1.upto(16) do |n|
102
+ conn.create_command(<<-EOF).execute_non_query #(::Extlib::ByteArray.new("CAD \001 \000 DRAWING"))
103
+ insert into widgets(code, name, shelf_location, description, image_data, ad_description, ad_image, whitepaper_text, cad_drawing, super_number, weight)
104
+ VALUES ('W#{n.to_s.rjust(7,"0")}', 'Widget #{n}', 'A14', 'This is a description', 'IMAGE DATA', 'Buy this product now!', 'AD IMAGE DATA', 'String', 0x2145475754578785 , 1234, 13.4);
105
+ EOF
106
+ end
107
+
108
+ conn.create_command(<<-EOF).execute_non_query
109
+ update widgets set flags = 1 where id = 2
110
+ EOF
111
+
112
+ conn.create_command(<<-EOF).execute_non_query
113
+ update widgets set ad_description = NULL where id = 3
114
+ EOF
115
+
116
+ conn.create_command(<<-EOF).execute_non_query
117
+ update widgets set flags = NULL where id = 4
118
+ EOF
119
+
120
+ conn.create_command(<<-EOF).execute_non_query
121
+ update widgets set cost1 = NULL where id = 5
122
+ EOF
123
+
124
+ conn.create_command(<<-EOF).execute_non_query
125
+ update widgets set cost2 = NULL where id = 6
126
+ EOF
127
+
128
+ conn.create_command(<<-EOF).execute_non_query
129
+ update widgets set release_date = NULL where id = 7
130
+ EOF
131
+
132
+ conn.create_command(<<-EOF).execute_non_query
133
+ update widgets set release_datetime = NULL where id = 8
134
+ EOF
135
+
136
+ # (cannot update a Timestamp column w/MSSQL)
137
+ # so we use a smalldatetime
138
+ conn.create_command(<<-EOF).execute_non_query
139
+ update widgets set release_timestamp = NULL where id = 9
140
+ EOF
141
+
142
+ conn.create_command(<<-EOF).execute_non_query
143
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
144
+ EOF
145
+
146
+ conn.close
147
+
148
+ end
149
+
150
+ end
151
+
152
+ RSpec.configure do |config|
153
+ config.include(DataObjectsSpecHelpers)
154
+ config.include(DataObjects::Spec::PendingHelpers)
155
+ end