vertica 0.7.4
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/LICENSE +19 -0
- data/README.textile +69 -0
- data/Rakefile +44 -0
- data/lib/vertica/bit_helper.rb +51 -0
- data/lib/vertica/column.rb +68 -0
- data/lib/vertica/connection.rb +247 -0
- data/lib/vertica/messages/authentication.rb +33 -0
- data/lib/vertica/messages/backend_key_data.rb +16 -0
- data/lib/vertica/messages/bind.rb +36 -0
- data/lib/vertica/messages/bind_complete.rb +8 -0
- data/lib/vertica/messages/cancel_request.rb +25 -0
- data/lib/vertica/messages/close.rb +30 -0
- data/lib/vertica/messages/close_complete.rb +8 -0
- data/lib/vertica/messages/command_complete.rb +16 -0
- data/lib/vertica/messages/data_row.rb +23 -0
- data/lib/vertica/messages/describe.rb +30 -0
- data/lib/vertica/messages/empty_query_response.rb +8 -0
- data/lib/vertica/messages/error_response.rb +59 -0
- data/lib/vertica/messages/execute.rb +24 -0
- data/lib/vertica/messages/flush.rb +15 -0
- data/lib/vertica/messages/message.rb +85 -0
- data/lib/vertica/messages/no_data.rb +8 -0
- data/lib/vertica/messages/notice_response.rb +21 -0
- data/lib/vertica/messages/notification_response.rb +18 -0
- data/lib/vertica/messages/parameter_description.rb +19 -0
- data/lib/vertica/messages/parameter_status.rb +17 -0
- data/lib/vertica/messages/parse.rb +31 -0
- data/lib/vertica/messages/parse_complete.rb +8 -0
- data/lib/vertica/messages/password.rb +33 -0
- data/lib/vertica/messages/portal_suspended.rb +8 -0
- data/lib/vertica/messages/query.rb +20 -0
- data/lib/vertica/messages/ready_for_query.rb +14 -0
- data/lib/vertica/messages/row_description.rb +29 -0
- data/lib/vertica/messages/ssl_request.rb +14 -0
- data/lib/vertica/messages/startup.rb +38 -0
- data/lib/vertica/messages/sync.rb +15 -0
- data/lib/vertica/messages/terminate.rb +14 -0
- data/lib/vertica/messages/unknown.rb +11 -0
- data/lib/vertica/notice.rb +11 -0
- data/lib/vertica/notification.rb +13 -0
- data/lib/vertica/result.rb +28 -0
- data/lib/vertica/vertica_socket.rb +8 -0
- data/lib/vertica.rb +19 -0
- data/test/connection_test.rb +191 -0
- data/test/create_schema.sql +4 -0
- data/test/test_helper.rb +25 -0
- data/vertica.gemspec +64 -0
- metadata +112 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class DataRow < BackendMessage
|
4
|
+
message_id ?D
|
5
|
+
|
6
|
+
attr_reader :field_count
|
7
|
+
attr_reader :fields
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
@fields = []
|
11
|
+
|
12
|
+
@field_count = stream.read_network_int16
|
13
|
+
@field_count.times do |field_index|
|
14
|
+
size = stream.read_network_int32
|
15
|
+
@fields << {
|
16
|
+
:size => size,
|
17
|
+
:value => size == -1 ? nil : stream.readn(size)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Describe < FrontendMessage
|
4
|
+
message_id ?D
|
5
|
+
|
6
|
+
def initialize(describe_type, describe_name)
|
7
|
+
if describe_type == :portal
|
8
|
+
@describe_type = ?P
|
9
|
+
elsif describe_type == :prepared_statement
|
10
|
+
@describe_type = ?S
|
11
|
+
else
|
12
|
+
raise ArgumentError.new("#{describe_type} is not a valid describe_type. Must be either :portal or :prepared_statement.")
|
13
|
+
end
|
14
|
+
@describe_name = describe_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_bytes(stream)
|
18
|
+
size = LENGTH_SIZE
|
19
|
+
size += 1
|
20
|
+
size += @describe_name.length + 1
|
21
|
+
|
22
|
+
stream.write_byte(message_id)
|
23
|
+
stream.write_network_int32(size) # size
|
24
|
+
stream.write_byte(@describe_type)
|
25
|
+
stream.write_cstring(@describe_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class ErrorResponse < BackendMessage
|
4
|
+
message_id ?E
|
5
|
+
|
6
|
+
def initialize(stream, size)
|
7
|
+
super
|
8
|
+
@errors = {}
|
9
|
+
|
10
|
+
field_type = stream.read_byte
|
11
|
+
while field_type != 0
|
12
|
+
@errors[field_type] = stream.read_cstring
|
13
|
+
field_type = stream.read_byte
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def error
|
18
|
+
s = []
|
19
|
+
@errors.each do |field_type, message|
|
20
|
+
s << [convert_field_type_to_string(field_type), message].flatten
|
21
|
+
end
|
22
|
+
s.sort_by { |e| e.first }.map { |e| "#{e[1]}: #{e[2]}" }.join(', ')
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def convert_field_type_to_string(field_type)
|
28
|
+
case field_type
|
29
|
+
when ?S
|
30
|
+
[1, "Severity"]
|
31
|
+
when ?C
|
32
|
+
[3, "Sqlstate"]
|
33
|
+
when ?M
|
34
|
+
[2, "Message"]
|
35
|
+
when ?D
|
36
|
+
[4, "Detail"]
|
37
|
+
when ?H
|
38
|
+
[5, "Hint"]
|
39
|
+
when ?P
|
40
|
+
[6, "Position"]
|
41
|
+
when ?p
|
42
|
+
[8, "Internal Position"]
|
43
|
+
when ?q
|
44
|
+
[0, "Internal Query"]
|
45
|
+
when ?W
|
46
|
+
[7, "Where"]
|
47
|
+
when ?F
|
48
|
+
[11, "File"]
|
49
|
+
when ?L
|
50
|
+
[12, "Line"]
|
51
|
+
when ?R
|
52
|
+
[10, "Routine"]
|
53
|
+
else
|
54
|
+
[13, field_type.to_s]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Execute < FrontendMessage
|
4
|
+
message_id ?E
|
5
|
+
|
6
|
+
def initialize(portal_name, max_rows)
|
7
|
+
@portal_name = portal_name
|
8
|
+
@max_rows = max_rows
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_bytes(stream)
|
12
|
+
size = LENGTH_SIZE
|
13
|
+
size += @portal_name.length + 1
|
14
|
+
size += 4
|
15
|
+
|
16
|
+
stream.write_byte(message_id)
|
17
|
+
stream.write_network_int32(size) # size
|
18
|
+
stream.write_cstring(@portal_name)
|
19
|
+
stream.write_network_int32(@max_rows)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Message
|
4
|
+
LENGTH_SIZE = 4
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def message_id(message_id)
|
9
|
+
self.const_set(:MESSAGE_ID, message_id)
|
10
|
+
class_eval "def message_id; MESSAGE_ID end"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class BackendMessage < Message
|
17
|
+
MessageIdMap = {}
|
18
|
+
|
19
|
+
attr_reader :size
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def message_id(message_id)
|
23
|
+
super
|
24
|
+
MessageIdMap[message_id.chr] = self
|
25
|
+
end
|
26
|
+
|
27
|
+
def read(stream)
|
28
|
+
type = stream.read_byte
|
29
|
+
size = stream.read_network_int32
|
30
|
+
|
31
|
+
raise Vertica::Error::MessageError.new("Bad message size: #{size}") unless size >= 4
|
32
|
+
|
33
|
+
message_klass = MessageIdMap[type.chr]
|
34
|
+
if message_klass.nil?
|
35
|
+
Messages::Unknown.new(type)
|
36
|
+
else
|
37
|
+
message_klass.new(stream, size)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(stream, size)
|
44
|
+
@size = size
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
class FrontendMessage < Message
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
require 'vertica/messages/unknown'
|
56
|
+
require 'vertica/messages/error_response'
|
57
|
+
require 'vertica/messages/startup'
|
58
|
+
require 'vertica/messages/authentication'
|
59
|
+
require 'vertica/messages/password'
|
60
|
+
require 'vertica/messages/parameter_status'
|
61
|
+
require 'vertica/messages/backend_key_data'
|
62
|
+
require 'vertica/messages/ready_for_query'
|
63
|
+
require 'vertica/messages/terminate'
|
64
|
+
require 'vertica/messages/notification_response'
|
65
|
+
require 'vertica/messages/query'
|
66
|
+
require 'vertica/messages/notice_response'
|
67
|
+
require 'vertica/messages/row_description'
|
68
|
+
require 'vertica/messages/command_complete'
|
69
|
+
require 'vertica/messages/data_row'
|
70
|
+
require 'vertica/messages/empty_query_response'
|
71
|
+
require 'vertica/messages/sync'
|
72
|
+
require 'vertica/messages/ssl_request'
|
73
|
+
require 'vertica/messages/parse'
|
74
|
+
require 'vertica/messages/parse_complete'
|
75
|
+
require 'vertica/messages/bind'
|
76
|
+
require 'vertica/messages/bind_complete'
|
77
|
+
require 'vertica/messages/describe'
|
78
|
+
require 'vertica/messages/flush'
|
79
|
+
require 'vertica/messages/parameter_description'
|
80
|
+
require 'vertica/messages/no_data'
|
81
|
+
require 'vertica/messages/execute'
|
82
|
+
require 'vertica/messages/close'
|
83
|
+
require 'vertica/messages/close_complete'
|
84
|
+
require 'vertica/messages/portal_suspended'
|
85
|
+
require 'vertica/messages/cancel_request'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class NoticeResponse < BackendMessage
|
4
|
+
message_id ?N
|
5
|
+
|
6
|
+
attr_reader :notices
|
7
|
+
|
8
|
+
def initialize(stream, size)
|
9
|
+
super
|
10
|
+
@notices = []
|
11
|
+
|
12
|
+
field_type = stream.read_byte
|
13
|
+
while field_type != 0
|
14
|
+
@notices << [field_type, stream.read_cstring]
|
15
|
+
field_type = stream.read_byte
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class NotificationResponse < BackendMessage
|
4
|
+
message_id ?A
|
5
|
+
|
6
|
+
attr_reader :pid
|
7
|
+
attr_reader :condition
|
8
|
+
attr_reader :addition_info
|
9
|
+
|
10
|
+
def initialize(stream, size)
|
11
|
+
super
|
12
|
+
@pid = stream.read_network_int32
|
13
|
+
@condition = stream.read_cstring
|
14
|
+
@addition_info = stream.read_cstring
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class ParameterDescription < BackendMessage
|
4
|
+
message_id ?t
|
5
|
+
|
6
|
+
attr_reader :parameter_count
|
7
|
+
attr_reader :parameter_types
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
super
|
11
|
+
@parameter_types = []
|
12
|
+
@parameter_count = stream.read_network_int16
|
13
|
+
@parameter_count.times do
|
14
|
+
@parameter_types << Vertica::Column::DATA_TYPES[stream.read_network_int32]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class ParameterStatus < BackendMessage
|
4
|
+
message_id ?S
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
super
|
11
|
+
@name = stream.read_cstring
|
12
|
+
@value = stream.read_cstring
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Parse < FrontendMessage
|
4
|
+
message_id ?P
|
5
|
+
|
6
|
+
def initialize(name, query, param_types)
|
7
|
+
@name = name
|
8
|
+
@query = query
|
9
|
+
@param_types = param_types
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_bytes(stream)
|
13
|
+
size = LENGTH_SIZE
|
14
|
+
size += @name.length + 1
|
15
|
+
size += @query.length + 1
|
16
|
+
size += 2
|
17
|
+
size += (@param_types.length * 4)
|
18
|
+
|
19
|
+
stream.write_byte(message_id)
|
20
|
+
stream.write_network_int32(size) # size
|
21
|
+
stream.write_cstring(@name)
|
22
|
+
stream.write_cstring(@query)
|
23
|
+
stream.write_network_int16(@param_types.length)
|
24
|
+
@param_types.each do |param_type|
|
25
|
+
stream.write_network_int32(param_type)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Vertica
|
4
|
+
module Messages
|
5
|
+
class Password < FrontendMessage
|
6
|
+
message_id ?p
|
7
|
+
|
8
|
+
def initialize(password, authentication_method = Messages::Authentication::CLEARTEXT_PASSWORD, options = {})
|
9
|
+
case authentication_method
|
10
|
+
when Messages::Authentication::CLEARTEXT_PASSWORD
|
11
|
+
@password = password
|
12
|
+
when Messages::Authentication::CRYPT_PASSWORD
|
13
|
+
@password = password.crypt(options[:salt])
|
14
|
+
when Messages::Authentication::MD5_PASSWORD
|
15
|
+
@password = Digest::MD5.hexdigest(password + options[:user])
|
16
|
+
@password = Digest::MD5.hexdigest(m + options[:salt])
|
17
|
+
@password = 'md5' + @password
|
18
|
+
else
|
19
|
+
raise ArgumentError.new("unsupported authentication method: #{authentication_method}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_bytes(stream)
|
24
|
+
size = LENGTH_SIZE
|
25
|
+
size += @password.length + 1
|
26
|
+
stream.write_byte(message_id)
|
27
|
+
stream.write_network_int32(size) # size
|
28
|
+
stream.write_cstring(@password)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Query < FrontendMessage
|
4
|
+
message_id ?Q
|
5
|
+
|
6
|
+
def initialize(query_string)
|
7
|
+
@query_string = query_string
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes(stream)
|
11
|
+
size = LENGTH_SIZE
|
12
|
+
size += @query_string.length + 1
|
13
|
+
stream.write_byte(message_id.bytes.first)
|
14
|
+
stream.write_network_int32(size) # size
|
15
|
+
stream.write_cstring(@query_string)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class RowDescription < BackendMessage
|
4
|
+
message_id ?T
|
5
|
+
|
6
|
+
attr_reader :field_count
|
7
|
+
attr_reader :fields
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
super
|
11
|
+
|
12
|
+
@fields = []
|
13
|
+
|
14
|
+
@field_count = stream.read_network_int16
|
15
|
+
@field_count.times do |field_index|
|
16
|
+
@fields << {
|
17
|
+
:name => stream.read_cstring,
|
18
|
+
:table_oid => stream.read_network_int32,
|
19
|
+
:attribute_number => stream.read_network_int16,
|
20
|
+
:data_type_oid => stream.read_network_int32,
|
21
|
+
:data_type_size => stream.read_network_int16,
|
22
|
+
:type_modifier => stream.read_network_int32,
|
23
|
+
:format_code => stream.read_network_int16
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class SslRequest < FrontendMessage
|
4
|
+
message_id nil
|
5
|
+
|
6
|
+
def to_bytes(stream)
|
7
|
+
size = LENGTH_SIZE + 4
|
8
|
+
stream.write_network_int32(size) # size
|
9
|
+
stream.write_network_int32(80877103) # size
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Startup < FrontendMessage
|
4
|
+
message_id nil
|
5
|
+
|
6
|
+
def initialize(user, database, options = nil)
|
7
|
+
@user = user
|
8
|
+
@database = database
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_bytes(stream)
|
13
|
+
size = LENGTH_SIZE + 4 # length + protocol
|
14
|
+
size += @user.length + 4 + 2 if @user
|
15
|
+
size += @database.length + 8 + 2 if @database
|
16
|
+
size += @options.length + 7 + 2 if @options
|
17
|
+
size += 1 # ending zero
|
18
|
+
|
19
|
+
stream.write_network_int32(size) # size
|
20
|
+
stream.write_network_int32(Vertica::PROTOCOL_VERSION) # proto version
|
21
|
+
if @user
|
22
|
+
stream.write_cstring('user')
|
23
|
+
stream.write_cstring(@user)
|
24
|
+
end
|
25
|
+
if @database
|
26
|
+
stream.write_cstring('database')
|
27
|
+
stream.write_cstring(@database)
|
28
|
+
end
|
29
|
+
if @options
|
30
|
+
stream.write_cstring('options')
|
31
|
+
stream.write_cstring(@options)
|
32
|
+
end
|
33
|
+
stream.write_byte(0)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Vertica
|
2
|
+
class Notification
|
3
|
+
attr_reader :process_pid
|
4
|
+
attr_reader :condition
|
5
|
+
attr_reader :additional_info
|
6
|
+
|
7
|
+
def initialize(process_pid, condition, additional_info)
|
8
|
+
@process_pid = process_pid
|
9
|
+
@condition = condition
|
10
|
+
@additional_info = additional_info
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Vertica
|
2
|
+
class Result
|
3
|
+
|
4
|
+
def initialize(field_descriptions, field_values)
|
5
|
+
@field_descriptions = field_descriptions
|
6
|
+
@field_values = field_values
|
7
|
+
end
|
8
|
+
|
9
|
+
def row_count
|
10
|
+
@row_count ||= @field_values.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def columns
|
14
|
+
@columns ||= @field_descriptions.map { |fd| Column.new(fd[:type_modifier], fd[:format_code], fd[:table_oid], fd[:name], fd[:attribute_number], fd[:data_type_oid], fd[:data_type_size]) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def rows
|
18
|
+
@field_values.map do |fv|
|
19
|
+
index = 0
|
20
|
+
fv.map do |f|
|
21
|
+
index += 1
|
22
|
+
self.columns[index-1].convert(f[:value])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/vertica.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Vertica
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
|
5
|
+
class ConnectionError < Error; end
|
6
|
+
|
7
|
+
class MessageError < Error; end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
PROTOCOL_VERSION = 3 << 16
|
12
|
+
|
13
|
+
VERSION = "0.7.3"
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'vertica/column'
|
18
|
+
require 'vertica/result'
|
19
|
+
require 'vertica/connection'
|