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