vertica 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/LICENSE +19 -0
  2. data/README.textile +69 -0
  3. data/Rakefile +44 -0
  4. data/lib/vertica/bit_helper.rb +51 -0
  5. data/lib/vertica/column.rb +68 -0
  6. data/lib/vertica/connection.rb +247 -0
  7. data/lib/vertica/messages/authentication.rb +33 -0
  8. data/lib/vertica/messages/backend_key_data.rb +16 -0
  9. data/lib/vertica/messages/bind.rb +36 -0
  10. data/lib/vertica/messages/bind_complete.rb +8 -0
  11. data/lib/vertica/messages/cancel_request.rb +25 -0
  12. data/lib/vertica/messages/close.rb +30 -0
  13. data/lib/vertica/messages/close_complete.rb +8 -0
  14. data/lib/vertica/messages/command_complete.rb +16 -0
  15. data/lib/vertica/messages/data_row.rb +23 -0
  16. data/lib/vertica/messages/describe.rb +30 -0
  17. data/lib/vertica/messages/empty_query_response.rb +8 -0
  18. data/lib/vertica/messages/error_response.rb +59 -0
  19. data/lib/vertica/messages/execute.rb +24 -0
  20. data/lib/vertica/messages/flush.rb +15 -0
  21. data/lib/vertica/messages/message.rb +85 -0
  22. data/lib/vertica/messages/no_data.rb +8 -0
  23. data/lib/vertica/messages/notice_response.rb +21 -0
  24. data/lib/vertica/messages/notification_response.rb +18 -0
  25. data/lib/vertica/messages/parameter_description.rb +19 -0
  26. data/lib/vertica/messages/parameter_status.rb +17 -0
  27. data/lib/vertica/messages/parse.rb +31 -0
  28. data/lib/vertica/messages/parse_complete.rb +8 -0
  29. data/lib/vertica/messages/password.rb +33 -0
  30. data/lib/vertica/messages/portal_suspended.rb +8 -0
  31. data/lib/vertica/messages/query.rb +20 -0
  32. data/lib/vertica/messages/ready_for_query.rb +14 -0
  33. data/lib/vertica/messages/row_description.rb +29 -0
  34. data/lib/vertica/messages/ssl_request.rb +14 -0
  35. data/lib/vertica/messages/startup.rb +38 -0
  36. data/lib/vertica/messages/sync.rb +15 -0
  37. data/lib/vertica/messages/terminate.rb +14 -0
  38. data/lib/vertica/messages/unknown.rb +11 -0
  39. data/lib/vertica/notice.rb +11 -0
  40. data/lib/vertica/notification.rb +13 -0
  41. data/lib/vertica/result.rb +28 -0
  42. data/lib/vertica/vertica_socket.rb +8 -0
  43. data/lib/vertica.rb +19 -0
  44. data/test/connection_test.rb +191 -0
  45. data/test/create_schema.sql +4 -0
  46. data/test/test_helper.rb +25 -0
  47. data/vertica.gemspec +64 -0
  48. 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,8 @@
1
+ module Vertica
2
+ module Messages
3
+ class EmptyQueryResponse < BackendMessage
4
+ message_id ?I
5
+
6
+ end
7
+ end
8
+ 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,15 @@
1
+ module Vertica
2
+ module Messages
3
+ class Flush < FrontendMessage
4
+ message_id ?H
5
+
6
+ def to_bytes(stream)
7
+ size = LENGTH_SIZE
8
+
9
+ stream.write_byte(message_id)
10
+ stream.write_network_int32(size) # size
11
+ end
12
+
13
+ end
14
+ end
15
+ 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,8 @@
1
+ module Vertica
2
+ module Messages
3
+ class NoData < BackendMessage
4
+ message_id ?n
5
+
6
+ end
7
+ end
8
+ end
@@ -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,8 @@
1
+ module Vertica
2
+ module Messages
3
+ class ParseComplete < BackendMessage
4
+ message_id ?1
5
+
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Vertica
2
+ module Messages
3
+ class PortalSuspended < BackendMessage
4
+ message_id ?s
5
+
6
+ end
7
+ end
8
+ 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,14 @@
1
+ module Vertica
2
+ module Messages
3
+ class ReadyForQuery < BackendMessage
4
+ message_id ?Z
5
+
6
+ attr_reader :transaction_status
7
+
8
+ def initialize(stream, size)
9
+ super
10
+ @transaction_status = stream.read_byte
11
+ end
12
+ end
13
+ end
14
+ 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,15 @@
1
+ module Vertica
2
+ module Messages
3
+ class Sync < FrontendMessage
4
+ message_id ?S
5
+
6
+ def to_bytes(stream)
7
+ size = LENGTH_SIZE
8
+
9
+ stream.write_byte(message_id)
10
+ stream.write_network_int32(size)
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module Vertica
2
+ module Messages
3
+ class Terminate < FrontendMessage
4
+ message_id ?X
5
+
6
+ def to_bytes(stream)
7
+ size = LENGTH_SIZE
8
+ stream.write_byte(message_id.bytes.first)
9
+ stream.write_network_int32(size)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Vertica
2
+ module Messages
3
+ class Unknown < BackendMessage
4
+ attr_reader :message_id
5
+
6
+ def initialize(message_id)
7
+ @message_id = message_id
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Vertica
2
+ class Notice
3
+ attr_reader :field_type
4
+ attr_reader :field_value
5
+
6
+ def initialize(field_type, field_value)
7
+ @field_type = field_type
8
+ @field_value = field_value
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,8 @@
1
+ require 'socket'
2
+ require 'vertica/bit_helper'
3
+
4
+ module Vertica
5
+ class VerticaSocket < TCPSocket
6
+ include BitHelper
7
+ end
8
+ 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'