vertica 0.8.1 → 0.9.0.beta1
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/Gemfile +2 -0
- data/Gemfile.lock +23 -0
- data/Rakefile +12 -9
- data/VERSION +1 -1
- data/lib/vertica.rb +2 -7
- data/lib/vertica/connection.rb +47 -57
- data/lib/vertica/messages/backend_messages/authentication.rb +6 -7
- data/lib/vertica/messages/backend_messages/backend_key_data.rb +4 -7
- data/lib/vertica/messages/backend_messages/bind_complete.rb +1 -1
- data/lib/vertica/messages/backend_messages/close_complete.rb +1 -1
- data/lib/vertica/messages/backend_messages/command_complete.rb +13 -7
- data/lib/vertica/messages/backend_messages/data_row.rb +10 -10
- data/lib/vertica/messages/backend_messages/empty_query_response.rb +1 -1
- data/lib/vertica/messages/backend_messages/error_response.rb +2 -30
- data/lib/vertica/messages/backend_messages/no_data.rb +1 -1
- data/lib/vertica/messages/backend_messages/notice_response.rb +33 -7
- data/lib/vertica/messages/backend_messages/notification_response.rb +4 -9
- data/lib/vertica/messages/backend_messages/parameter_description.rb +5 -9
- data/lib/vertica/messages/backend_messages/parameter_status.rb +4 -8
- data/lib/vertica/messages/backend_messages/parse_complete.rb +1 -1
- data/lib/vertica/messages/backend_messages/portal_suspended.rb +1 -1
- data/lib/vertica/messages/backend_messages/ready_for_query.rb +3 -4
- data/lib/vertica/messages/backend_messages/row_description.rb +15 -15
- data/lib/vertica/messages/backend_messages/unknown.rb +2 -2
- data/lib/vertica/messages/frontend_messages/bind.rb +3 -12
- data/lib/vertica/messages/frontend_messages/cancel_request.rb +1 -5
- data/lib/vertica/messages/frontend_messages/close.rb +5 -9
- data/lib/vertica/messages/frontend_messages/describe.rb +5 -9
- data/lib/vertica/messages/frontend_messages/execute.rb +2 -6
- data/lib/vertica/messages/frontend_messages/flush.rb +1 -1
- data/lib/vertica/messages/frontend_messages/parse.rb +2 -8
- data/lib/vertica/messages/frontend_messages/password.rb +5 -6
- data/lib/vertica/messages/frontend_messages/query.rb +2 -3
- data/lib/vertica/messages/frontend_messages/ssl_request.rb +1 -2
- data/lib/vertica/messages/frontend_messages/startup.rb +6 -8
- data/lib/vertica/messages/frontend_messages/sync.rb +1 -1
- data/lib/vertica/messages/frontend_messages/terminate.rb +1 -1
- data/lib/vertica/messages/message.rb +9 -18
- data/lib/vertica/result.rb +8 -1
- data/test/functional/connection_test.rb +73 -0
- data/test/functional/query_test.rb +150 -0
- data/test/test_helper.rb +7 -13
- data/test/unit/backend_message_test.rb +106 -0
- metadata +72 -20
- data/lib/vertica/bit_helper.rb +0 -34
- data/lib/vertica/core_ext/numeric.rb +0 -13
- data/lib/vertica/core_ext/string.rb +0 -22
- data/lib/vertica/notice.rb +0 -11
- data/lib/vertica/vertica_socket.rb +0 -19
- data/test/connection_test.rb +0 -191
@@ -1,16 +1,42 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class NoticeResponse < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'N'
|
5
|
+
|
6
|
+
FIELDS_DEFINITIONS = [
|
7
|
+
{ :type => 'q', :name => "Internal Query" },
|
8
|
+
{ :type => 'S', :name => "Severity" },
|
9
|
+
{ :type => 'M', :name => "Message" },
|
10
|
+
{ :type => 'C', :name => "Sqlstate" },
|
11
|
+
{ :type => 'D', :name => "Detail" },
|
12
|
+
{ :type => 'H', :name => "Hint" },
|
13
|
+
{ :type => 'P', :name => "Position" },
|
14
|
+
{ :type => 'W', :name => "Where" },
|
15
|
+
{ :type => 'p', :name => "Internal Position" },
|
16
|
+
{ :type => 'R', :name => "Routine" },
|
17
|
+
{ :type => 'F', :name => "File" },
|
18
|
+
{ :type => 'L', :name => "Line" }
|
19
|
+
]
|
20
|
+
|
21
|
+
FIELDS = Hash[*FIELDS_DEFINITIONS.map { |f| [f[:type], f[:name]] }.flatten]
|
22
|
+
|
23
|
+
attr_reader :values
|
5
24
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
25
|
+
def initialize(data)
|
26
|
+
@values, pos = {}, 0
|
27
|
+
while pos < data.size - 1
|
28
|
+
key, value = data.unpack("@#{pos}aZ*")
|
29
|
+
@values[FIELDS[key]] = value
|
30
|
+
pos += value.size + 2
|
31
|
+
end
|
12
32
|
end
|
13
33
|
|
34
|
+
def error_message
|
35
|
+
ordered_values = FIELDS_DEFINITIONS.map do |field|
|
36
|
+
"#{field[:name]}: #{@values[field[:name]]}" if @values[field[:name]]
|
37
|
+
end
|
38
|
+
ordered_values.compact.join(', ')
|
39
|
+
end
|
14
40
|
end
|
15
41
|
end
|
16
42
|
end
|
@@ -1,17 +1,12 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class NotificationResponse < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'A'
|
5
5
|
|
6
|
-
attr_reader :pid
|
7
|
-
attr_reader :condition
|
8
|
-
attr_reader :addition_info
|
6
|
+
attr_reader :pid, :condition, :addition_info
|
9
7
|
|
10
|
-
def initialize(
|
11
|
-
|
12
|
-
@pid = stream.read_network_int32
|
13
|
-
@condition = stream.read_cstring
|
14
|
-
@addition_info = stream.read_cstring
|
8
|
+
def initialize(data)
|
9
|
+
@pid, @condition, @addition_info = data.unpack('NZ*Z*')
|
15
10
|
end
|
16
11
|
end
|
17
12
|
end
|
@@ -1,18 +1,14 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class ParameterDescription < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 't'
|
5
5
|
|
6
|
-
attr_reader :parameter_count
|
7
6
|
attr_reader :parameter_types
|
8
7
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
@parameter_count.times do
|
14
|
-
@parameter_types << Vertica::Column::DATA_TYPES[stream.read_network_int32]
|
15
|
-
end
|
8
|
+
def initialize(data)
|
9
|
+
parameter_count = data.unpack('n').first
|
10
|
+
parameter_type_ids = data.unpack("@2N#{parameter_count}")
|
11
|
+
@parameter_types = parameter_type_ids.map { |id| Vertica::Column::DATA_TYPES[id] }
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class ParameterStatus < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'S'
|
5
5
|
|
6
|
-
attr_reader :name
|
7
|
-
attr_reader :value
|
6
|
+
attr_reader :name, :value
|
8
7
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
@name = stream.read_cstring
|
12
|
-
@value = stream.read_cstring
|
8
|
+
def initialize(data)
|
9
|
+
@name, @value = data.unpack('Z*Z*')
|
13
10
|
end
|
14
|
-
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class ReadyForQuery < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'Z'
|
5
5
|
|
6
6
|
attr_reader :transaction_status
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
|
10
|
-
@transaction_status = stream.read_byte
|
8
|
+
def initialize(data)
|
9
|
+
@transaction_status = data.unpack('a').first
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class RowDescription < BackendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'T'
|
5
5
|
|
6
|
-
attr_reader :field_count
|
7
6
|
attr_reader :fields
|
8
7
|
|
9
|
-
def initialize(
|
10
|
-
super
|
11
|
-
|
8
|
+
def initialize(data)
|
12
9
|
@fields = []
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
field_count = data.unpack('n').first
|
11
|
+
pos = 2
|
12
|
+
field_count.times do |field_index|
|
13
|
+
field_info = data.unpack("@#{pos}Z*NnNnNn")
|
16
14
|
@fields << {
|
17
|
-
:name =>
|
18
|
-
:table_oid =>
|
19
|
-
:attribute_number =>
|
20
|
-
:data_type_oid =>
|
21
|
-
:data_type_size =>
|
22
|
-
:type_modifier =>
|
23
|
-
:format_code =>
|
15
|
+
:name => field_info[0],
|
16
|
+
:table_oid => field_info[1],
|
17
|
+
:attribute_number => field_info[2],
|
18
|
+
:data_type_oid => field_info[3],
|
19
|
+
:data_type_size => field_info[4],
|
20
|
+
:type_modifier => field_info[5],
|
21
|
+
:format_code => field_info[6],
|
24
22
|
}
|
23
|
+
|
24
|
+
pos += 19 + field_info[0].size
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class Bind < FrontendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'B'
|
5
5
|
|
6
6
|
def initialize(portal_name, prepared_statement_name, parameter_values)
|
7
7
|
@portal_name = portal_name
|
@@ -10,19 +10,10 @@ module Vertica
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def to_bytes
|
13
|
-
bytes = [
|
14
|
-
|
15
|
-
@prepared_statement_name.to_cstring, # prep
|
16
|
-
0.to_network_int16, # format codes (0 - default text format)
|
17
|
-
@parameter_values.length.to_network_int16, # number of parameters
|
18
|
-
]
|
19
|
-
@parameter_values.each do |parameter_value|
|
20
|
-
bytes << parameter_value.length.to_network_int32 # parameter value (which is represented as a string) length
|
21
|
-
bytes << parameter_value # parameter value written out in text representation
|
22
|
-
end
|
13
|
+
bytes = [@portal_name, @prepared_statement_name, 0, @parameter_values.length].pack('Z*Z*nn')
|
14
|
+
bytes << @parameter_values.map { |val| [val.length, val].pack('Na*') }.join('') << [0].pack('n')
|
23
15
|
message_string bytes
|
24
16
|
end
|
25
|
-
|
26
17
|
end
|
27
18
|
end
|
28
19
|
end
|
@@ -1,24 +1,20 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class Close < FrontendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'C'
|
5
5
|
|
6
6
|
def initialize(close_type, close_name)
|
7
7
|
@close_name = close_name
|
8
8
|
@close_type = case close_type
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
when :portal then 'P'
|
10
|
+
when :prepared_statement then 'S'
|
11
|
+
else raise ArgumentError.new("#{close_type} is not a valid close_type. Must be either :portal or :prepared_statement.")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_bytes
|
16
|
-
message_string(
|
17
|
-
@close_type.to_byte,
|
18
|
-
@close_name.to_cstring
|
19
|
-
])
|
16
|
+
message_string [@close_type, @close_name].pack('AZ*')
|
20
17
|
end
|
21
|
-
|
22
18
|
end
|
23
19
|
end
|
24
20
|
end
|
@@ -1,24 +1,20 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class Describe < FrontendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'D'
|
5
5
|
|
6
6
|
def initialize(describe_type, describe_name)
|
7
7
|
@describe_name = describe_name
|
8
8
|
@describe_type = case describe_type
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
when :portal then 'P'
|
10
|
+
when :prepared_statement then 'S'
|
11
|
+
else raise ArgumentError.new("#{describe_type} is not a valid describe_type. Must be either :portal or :prepared_statement.")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_bytes
|
16
|
-
message_string(
|
17
|
-
@describe_type.to_byte,
|
18
|
-
@describe_name.to_cstring
|
19
|
-
])
|
16
|
+
message_string [@describe_type, @describe_name].pack('AZ*')
|
20
17
|
end
|
21
|
-
|
22
18
|
end
|
23
19
|
end
|
24
20
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class Execute < FrontendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'E'
|
5
5
|
|
6
6
|
def initialize(portal_name, max_rows)
|
7
7
|
@portal_name = portal_name
|
@@ -9,12 +9,8 @@ module Vertica
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def to_bytes
|
12
|
-
message_string
|
13
|
-
@portal_name.to_cstring,
|
14
|
-
@max_rows.to_network_int32
|
15
|
-
])
|
12
|
+
message_string [@portal_name, @max_rows].pack('Z*N')
|
16
13
|
end
|
17
|
-
|
18
14
|
end
|
19
15
|
end
|
20
16
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Vertica
|
2
2
|
module Messages
|
3
3
|
class Parse < FrontendMessage
|
4
|
-
message_id
|
4
|
+
message_id 'P'
|
5
5
|
|
6
6
|
def initialize(name, query, param_types)
|
7
7
|
@name = name
|
@@ -10,14 +10,8 @@ module Vertica
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def to_bytes
|
13
|
-
message_string([
|
14
|
-
@name.to_cstring,
|
15
|
-
@query.to_cstring,
|
16
|
-
@param_types.length.to_network_int16,
|
17
|
-
@param_types.map { |type| type.to_network_int32 }
|
18
|
-
].flatten)
|
13
|
+
message_string([@name, @query, @param_types.length, *@param_types].pack('Z*Z*nN*'))
|
19
14
|
end
|
20
|
-
|
21
15
|
end
|
22
16
|
end
|
23
17
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
module Vertica
|
3
3
|
module Messages
|
4
4
|
class Password < FrontendMessage
|
5
|
-
message_id
|
5
|
+
message_id 'p'
|
6
6
|
|
7
7
|
def initialize(password, auth_method = nil, options = {})
|
8
8
|
@password = password
|
@@ -10,16 +10,16 @@ module Vertica
|
|
10
10
|
@options = options
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
13
|
+
def encoded_password
|
14
14
|
case @auth_method
|
15
15
|
when Authentication::CLEARTEXT_PASSWORD
|
16
16
|
@password
|
17
17
|
when Authentication::CRYPT_PASSWORD
|
18
|
-
@password.crypt(options[:salt])
|
18
|
+
@password.crypt(@options[:salt])
|
19
19
|
when Authentication::MD5_PASSWORD
|
20
20
|
require 'digest/md5'
|
21
21
|
@password = Digest::MD5.hexdigest(@password + @options[:user])
|
22
|
-
@password = Digest::MD5.hexdigest(
|
22
|
+
@password = Digest::MD5.hexdigest(@password + @options[:salt])
|
23
23
|
@password = 'md5' + @password
|
24
24
|
else
|
25
25
|
raise ArgumentError.new("unsupported authentication method: #{@auth_method}")
|
@@ -27,9 +27,8 @@ module Vertica
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def to_bytes
|
30
|
-
message_string
|
30
|
+
message_string [encoded_password].pack('Z*')
|
31
31
|
end
|
32
|
-
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -2,16 +2,15 @@ module Vertica
|
|
2
2
|
module Messages
|
3
3
|
|
4
4
|
class Query < FrontendMessage
|
5
|
-
message_id
|
5
|
+
message_id 'Q'
|
6
6
|
|
7
7
|
def initialize(query_string)
|
8
8
|
@query_string = query_string
|
9
9
|
end
|
10
10
|
|
11
11
|
def to_bytes
|
12
|
-
message_string @query_string.
|
12
|
+
message_string [@query_string].pack('Z*')
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
16
15
|
end
|
17
16
|
end
|