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