penwellr-RubyTSQL 1.0.19 → 1.0.21
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/tsql.rb +14 -0
- data/lib/tsql/command.rb +21 -0
- data/lib/tsql/connection.rb +8 -0
- data/lib/tsql/connection_string.rb +2 -0
- data/lib/tsql/data_reader.rb +3 -0
- data/lib/tsql/parameter.rb +2 -0
- data/lib/tsql/parameter_collection.rb +4 -0
- data/lib/tsql/tds_core.rb +21 -0
- data/lib/tsql/tds_packet.rb +55 -0
- data/lib/tsql/tds_token.rb +78 -0
- data/spec/lib/connection_spec.rb +8 -0
- data/spec/lib/connection_string_spec.rb +15 -0
- data/spec/lib/parameter_spec.rb +14 -0
- data/spec/lib/tds_core_spec.rb +32 -0
- data/spec/lib/tds_packet_spec.rb +63 -0
- data/spec/lib/tds_token_spec.rb +68 -0
- data/spec/lib/tsql_spec.rb +9 -0
- metadata +19 -3
data/lib/tsql.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module RubyTSQL; end
|
5
|
+
|
6
|
+
require 'tsql/connection_string'
|
7
|
+
require 'tsql/tds_packet'
|
8
|
+
require 'tsql/tds_token'
|
9
|
+
require 'tsql/tds_core'
|
10
|
+
require 'tsql/connection'
|
11
|
+
require 'tsql/parameter'
|
12
|
+
require 'tsql/parameter_collection'
|
13
|
+
require 'tsql/command'
|
14
|
+
require 'tsql/data_reader'
|
data/lib/tsql/command.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class RubyTSQL::Command
|
2
|
+
attr_accessor :parameters
|
3
|
+
|
4
|
+
def initialize(connection)
|
5
|
+
@connection = connection
|
6
|
+
parameters = RubyTSQL::ParameterCollection.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute_non_query
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute_reader
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute_scaler
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute_tuple
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
class RubyTSQL::TdsCore
|
3
|
+
PACKET_VERSION = [9, 0, 0, 0, 0, 0]
|
4
|
+
ENCRYPTION_OFF = 0
|
5
|
+
ENCRYPTION_ON = 1
|
6
|
+
ENCRYPTION_NOT_SUPPORTED = 2
|
7
|
+
ENCRYPTION_REQUIRED = 3
|
8
|
+
|
9
|
+
def create_prelogin_packet
|
10
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
11
|
+
packet.end_of_message = true
|
12
|
+
|
13
|
+
packet.add_token RubyTSQL::TdsToken::TOKEN_PRELOGIN_VERSION, PACKET_VERSION
|
14
|
+
packet.add_token RubyTSQL::TdsToken::TOKEN_PRELOGIN_ENCRYPTION, [ENCRYPTION_NOT_SUPPORTED]
|
15
|
+
packet.add_token RubyTSQL::TdsToken::TOKEN_PRELOGIN_INSTOPT, 0
|
16
|
+
packet.add_token RubyTSQL::TdsToken::TOKEN_PRELOGIN_THREADID, [0, 0, 0, 0]
|
17
|
+
packet.add_token RubyTSQL::TdsToken::TOKEN_PRELOGIN_MARS, false
|
18
|
+
|
19
|
+
packet
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class RubyTSQL::TdsPacket
|
2
|
+
PACKET_TYPE_BATCH = 1
|
3
|
+
PACKET_TYPE_RESPONSE = 4
|
4
|
+
PACKET_TYPE_ATTENTION = 6
|
5
|
+
PACKET_TYPE_LOGIN = 16
|
6
|
+
PACKET_TYPE_SSPI = 17
|
7
|
+
PACKET_TYPE_PRELOGIN = 18
|
8
|
+
|
9
|
+
attr_accessor :end_of_message
|
10
|
+
|
11
|
+
def initialize(packet_type)
|
12
|
+
@packet_type = packet_type
|
13
|
+
@tokens = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_token(token_type, value, length = nil)
|
17
|
+
@tokens << RubyTSQL::TdsToken.new(token_type, value, length)
|
18
|
+
@data = ''
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
packet_header = [@packet_type, get_status, calculate_length].pack("CCvxxxx")
|
23
|
+
|
24
|
+
if not @tokens.empty? then
|
25
|
+
token_header = ''
|
26
|
+
data = ''
|
27
|
+
position = 8
|
28
|
+
@tokens.each do |token|
|
29
|
+
position += token.header_size
|
30
|
+
end
|
31
|
+
|
32
|
+
@tokens.each do |token|
|
33
|
+
single_token_header = token.token_header position
|
34
|
+
position += token.length
|
35
|
+
token_header << single_token_header
|
36
|
+
data << token.data
|
37
|
+
end
|
38
|
+
|
39
|
+
token_header << 0xFF
|
40
|
+
else
|
41
|
+
token_header = ''
|
42
|
+
end
|
43
|
+
|
44
|
+
return packet_header + token_header + (data || @data || '')
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def get_status
|
49
|
+
@end_of_message ? 1 : 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def calculate_length
|
53
|
+
8
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class RubyTSQL::TdsToken
|
2
|
+
TOKEN_PRELOGIN_VERSION = 0
|
3
|
+
TOKEN_PRELOGIN_ENCRYPTION = 1
|
4
|
+
TOKEN_PRELOGIN_INSTOPT = 2
|
5
|
+
TOKEN_PRELOGIN_THREADID = 3
|
6
|
+
TOKEN_PRELOGIN_MARS = 4
|
7
|
+
|
8
|
+
TOKEN_TERMINATOR = 0xFF
|
9
|
+
|
10
|
+
attr_accessor :type
|
11
|
+
attr_accessor :length
|
12
|
+
attr_accessor :data
|
13
|
+
|
14
|
+
def initialize(token_type, value = [], length = nil)
|
15
|
+
@type = token_type
|
16
|
+
if value.is_a? Array then
|
17
|
+
@length = value.length
|
18
|
+
value = value.pack('C' * @length)
|
19
|
+
end
|
20
|
+
if value.is_a? Integer then
|
21
|
+
if not length then @length = 1 else @length = length end
|
22
|
+
|
23
|
+
case @length
|
24
|
+
when 1
|
25
|
+
value = [value].pack('C')
|
26
|
+
when 2
|
27
|
+
value = [value].pack('n')
|
28
|
+
when 4
|
29
|
+
value = [value].pack('I')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if (value.is_a? TrueClass) then
|
34
|
+
@length = 1
|
35
|
+
value = [1].pack('C')
|
36
|
+
end
|
37
|
+
|
38
|
+
if (value.is_a? FalseClass) then
|
39
|
+
@length = 1
|
40
|
+
value = [0].pack('C')
|
41
|
+
end
|
42
|
+
|
43
|
+
@length ||= 0
|
44
|
+
@data = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def token_header(data_position)
|
48
|
+
[@type, data_position, @length].pack('Cnn')
|
49
|
+
end
|
50
|
+
|
51
|
+
def header_size
|
52
|
+
token_header(0).length
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def token_type_value
|
57
|
+
case self.type
|
58
|
+
when :zero_length
|
59
|
+
return 0b00010000
|
60
|
+
when :fixed_length
|
61
|
+
length = self.length
|
62
|
+
result_flag = 0b00110000
|
63
|
+
case length
|
64
|
+
when 2
|
65
|
+
result_flag &= 0b00000100
|
66
|
+
when 4
|
67
|
+
result_flag &= 0b00001000
|
68
|
+
when 8
|
69
|
+
result_flag &= 0b00001100
|
70
|
+
end
|
71
|
+
return result_flag
|
72
|
+
when :variable_length
|
73
|
+
|
74
|
+
when :variable_count
|
75
|
+
return 0b00000000
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
+
|
3
|
+
# Time to add your specs!
|
4
|
+
# http://rspec.info/
|
5
|
+
describe RubyTSQL::ConnectionString do
|
6
|
+
it "should be able to be created"
|
7
|
+
it "should correctly parse the server name of (local) with no instance"
|
8
|
+
it "should correctly parse the server name of (local) with an instance"
|
9
|
+
it "should correctly parse the instance name of MSSQLSERVER with no instance"
|
10
|
+
it "should correctly parse the instance name equal to default when it is not specified"
|
11
|
+
it "should correctly parse the instance name with an instance"
|
12
|
+
it "should should not be connected when created"
|
13
|
+
it "should connect without raising an error"
|
14
|
+
it "should be connected after connecting"
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
+
|
3
|
+
describe RubyTSQL::Parameter do
|
4
|
+
it "should be able to be created with a type and no value"
|
5
|
+
it "should be able to be created with a value and no type"
|
6
|
+
it "should not be able to be created without a value or a type"
|
7
|
+
it "should be able to be assigned after being created without a value"
|
8
|
+
it "should be able to be assigned after being created with a value"
|
9
|
+
it "should ensure that when it is translated to sql that the parameter has an 'at' sign"
|
10
|
+
it "should infer the type of a textual input"
|
11
|
+
it "should infer the type of an integer input"
|
12
|
+
it "should infer the type of a boolean input"
|
13
|
+
it "should infer the type of a decimal input"
|
14
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
+
|
3
|
+
describe RubyTSQL::TdsCore do
|
4
|
+
|
5
|
+
def print_binary(input)
|
6
|
+
input = input.to_s unless input.kind_of? String
|
7
|
+
output = ''
|
8
|
+
|
9
|
+
input.each_byte do |char|
|
10
|
+
output += char.to_i.to_s + ' '
|
11
|
+
end
|
12
|
+
|
13
|
+
p output
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:all) do
|
17
|
+
@core = RubyTSQL::TdsCore.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should generate a pre-login packet" do
|
21
|
+
@core.create_prelogin_packet.should_not be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have created a pre-login packet with a length of 47" do
|
25
|
+
packet = @core.create_prelogin_packet
|
26
|
+
packet.to_s.length.should == 47
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse a pre-login response"
|
30
|
+
it "should generate a login packet"
|
31
|
+
it "should parse a login response"
|
32
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
+
|
3
|
+
describe RubyTSQL::TdsPacket do
|
4
|
+
it "should be able to be created given a packet type" do
|
5
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be able to be set as end of message" do
|
9
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
10
|
+
packet.end_of_message = true
|
11
|
+
packet.end_of_message.should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should produce an eight byte header when no data is attached" do
|
15
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
16
|
+
packet.end_of_message = true
|
17
|
+
|
18
|
+
packet.to_s.length.should == 8
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have the correct packet type in the first field" do
|
22
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
23
|
+
packet.end_of_message = true
|
24
|
+
|
25
|
+
packet.to_s[0].should == RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have a length of 8 in the header for an empty packet" do
|
29
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
30
|
+
packet.end_of_message = true
|
31
|
+
|
32
|
+
result_value = packet.to_s
|
33
|
+
result_value.unpack('@2v')[0].should == 8
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have zeros in the remaining fields of the header" do
|
37
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
38
|
+
packet.end_of_message = true
|
39
|
+
|
40
|
+
result_value = packet.to_s
|
41
|
+
(4..7).each do |field|
|
42
|
+
result_value[field].should == 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have the end of message bit set when end of message is true" do
|
47
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
48
|
+
packet.end_of_message = true
|
49
|
+
|
50
|
+
packet.to_s[1].should satisfy {|n| (n & 1) != 0}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not have the end of message bit set when end of message is false" do
|
54
|
+
packet = RubyTSQL::TdsPacket.new(RubyTSQL::TdsPacket::PACKET_TYPE_PRELOGIN)
|
55
|
+
packet.end_of_message = false
|
56
|
+
|
57
|
+
packet.to_s[1].should_not satisfy {|n| (n & 1) != 0}
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should error when there is no packet type given" do
|
61
|
+
lambda { packet = RubyTSQL::TdsPacket.new }.should raise_error
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
+
|
3
|
+
describe RubyTSQL::TdsToken do
|
4
|
+
|
5
|
+
it "should be able to be created" do
|
6
|
+
token = RubyTSQL::TdsToken.new(0)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return a proper header value" do
|
10
|
+
token = RubyTSQL::TdsToken.new(10)
|
11
|
+
header = token.token_header(8)
|
12
|
+
header.unpack('U*').should == [10, 0, 8, 0, 0]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return a proper header value when there is a non-zero length" do
|
16
|
+
token = RubyTSQL::TdsToken.new(10, [0, 1, 0])
|
17
|
+
header = token.token_header(8)
|
18
|
+
header.length.should == 5
|
19
|
+
header.unpack('U*').should == [10, 0, 8, 0, 3]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse boolean true values" do
|
23
|
+
token = RubyTSQL::TdsToken.new(10, true)
|
24
|
+
header = token.token_header(8)
|
25
|
+
header.length.should == 5
|
26
|
+
header.unpack('U*').should == [10, 0, 8, 0, 1]
|
27
|
+
token.data.unpack('U*').should == [1]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should parse boolean false values" do
|
31
|
+
token = RubyTSQL::TdsToken.new(10, false)
|
32
|
+
header = token.token_header(8)
|
33
|
+
header.length.should == 5
|
34
|
+
header.unpack('U*').should == [10, 0, 8, 0, 1]
|
35
|
+
token.data.unpack('U*').should == [0]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should parse an arbratary byte array" do
|
39
|
+
token = RubyTSQL::TdsToken.new(10, [1, 2, 3, 4, 5])
|
40
|
+
header = token.token_header(8)
|
41
|
+
header.length.should == 5
|
42
|
+
header.unpack('U*').should == [10, 0, 8, 0, 5]
|
43
|
+
token.data.unpack('U*').should == [1, 2, 3, 4, 5]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should parse a numeric defaulting to byte" do
|
47
|
+
token = RubyTSQL::TdsToken.new(10, 80)
|
48
|
+
header = token.token_header(8)
|
49
|
+
header.length.should == 5
|
50
|
+
header.unpack('U*').should == [10, 0, 8, 0, 1]
|
51
|
+
token.data.unpack('U*').should == [80]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should parse a numeric with a specificed length" do
|
55
|
+
token = RubyTSQL::TdsToken.new(10, 80, 2)
|
56
|
+
header = token.token_header(8)
|
57
|
+
header.length.should == 5
|
58
|
+
header.unpack('U*').should == [10, 0, 8, 0, 2]
|
59
|
+
token.data.unpack('U*').should == [00, 80]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should calculate token length" do
|
63
|
+
token = RubyTSQL::TdsToken.new(10, true)
|
64
|
+
header = token.token_header(8)
|
65
|
+
header.length.should == 5
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: penwellr-RubyTSQL
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Penwell
|
@@ -21,8 +21,7 @@ executables: []
|
|
21
21
|
extensions: []
|
22
22
|
|
23
23
|
extra_rdoc_files:
|
24
|
-
-
|
25
|
-
- Manifest.txt
|
24
|
+
- README.rdoc
|
26
25
|
files:
|
27
26
|
- History.txt
|
28
27
|
- Manifest.txt
|
@@ -34,6 +33,23 @@ files:
|
|
34
33
|
- tasks/rspec.rake
|
35
34
|
- spec/spec.opts
|
36
35
|
- spec/spec_helper.rb
|
36
|
+
- lib/tsql/command.rb
|
37
|
+
- lib/tsql/connection.rb
|
38
|
+
- lib/tsql/connection_string.rb
|
39
|
+
- lib/tsql/data_reader.rb
|
40
|
+
- lib/tsql/parameter.rb
|
41
|
+
- lib/tsql/parameter_collection.rb
|
42
|
+
- lib/tsql/tds_core.rb
|
43
|
+
- lib/tsql/tds_packet.rb
|
44
|
+
- lib/tsql/tds_token.rb
|
45
|
+
- lib/tsql.rb
|
46
|
+
- spec/lib/connection_spec.rb
|
47
|
+
- spec/lib/connection_string_spec.rb
|
48
|
+
- spec/lib/parameter_spec.rb
|
49
|
+
- spec/lib/tds_core_spec.rb
|
50
|
+
- spec/lib/tds_packet_spec.rb
|
51
|
+
- spec/lib/tds_token_spec.rb
|
52
|
+
- spec/lib/tsql_spec.rb
|
37
53
|
has_rdoc: false
|
38
54
|
homepage: http://github.com/penwellr/rb-tsql
|
39
55
|
licenses:
|