do_sqlserver-tinytds 0.10.17.alpha

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