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.
Files changed (50) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +23 -0
  3. data/Rakefile +12 -9
  4. data/VERSION +1 -1
  5. data/lib/vertica.rb +2 -7
  6. data/lib/vertica/connection.rb +47 -57
  7. data/lib/vertica/messages/backend_messages/authentication.rb +6 -7
  8. data/lib/vertica/messages/backend_messages/backend_key_data.rb +4 -7
  9. data/lib/vertica/messages/backend_messages/bind_complete.rb +1 -1
  10. data/lib/vertica/messages/backend_messages/close_complete.rb +1 -1
  11. data/lib/vertica/messages/backend_messages/command_complete.rb +13 -7
  12. data/lib/vertica/messages/backend_messages/data_row.rb +10 -10
  13. data/lib/vertica/messages/backend_messages/empty_query_response.rb +1 -1
  14. data/lib/vertica/messages/backend_messages/error_response.rb +2 -30
  15. data/lib/vertica/messages/backend_messages/no_data.rb +1 -1
  16. data/lib/vertica/messages/backend_messages/notice_response.rb +33 -7
  17. data/lib/vertica/messages/backend_messages/notification_response.rb +4 -9
  18. data/lib/vertica/messages/backend_messages/parameter_description.rb +5 -9
  19. data/lib/vertica/messages/backend_messages/parameter_status.rb +4 -8
  20. data/lib/vertica/messages/backend_messages/parse_complete.rb +1 -1
  21. data/lib/vertica/messages/backend_messages/portal_suspended.rb +1 -1
  22. data/lib/vertica/messages/backend_messages/ready_for_query.rb +3 -4
  23. data/lib/vertica/messages/backend_messages/row_description.rb +15 -15
  24. data/lib/vertica/messages/backend_messages/unknown.rb +2 -2
  25. data/lib/vertica/messages/frontend_messages/bind.rb +3 -12
  26. data/lib/vertica/messages/frontend_messages/cancel_request.rb +1 -5
  27. data/lib/vertica/messages/frontend_messages/close.rb +5 -9
  28. data/lib/vertica/messages/frontend_messages/describe.rb +5 -9
  29. data/lib/vertica/messages/frontend_messages/execute.rb +2 -6
  30. data/lib/vertica/messages/frontend_messages/flush.rb +1 -1
  31. data/lib/vertica/messages/frontend_messages/parse.rb +2 -8
  32. data/lib/vertica/messages/frontend_messages/password.rb +5 -6
  33. data/lib/vertica/messages/frontend_messages/query.rb +2 -3
  34. data/lib/vertica/messages/frontend_messages/ssl_request.rb +1 -2
  35. data/lib/vertica/messages/frontend_messages/startup.rb +6 -8
  36. data/lib/vertica/messages/frontend_messages/sync.rb +1 -1
  37. data/lib/vertica/messages/frontend_messages/terminate.rb +1 -1
  38. data/lib/vertica/messages/message.rb +9 -18
  39. data/lib/vertica/result.rb +8 -1
  40. data/test/functional/connection_test.rb +73 -0
  41. data/test/functional/query_test.rb +150 -0
  42. data/test/test_helper.rb +7 -13
  43. data/test/unit/backend_message_test.rb +106 -0
  44. metadata +72 -20
  45. data/lib/vertica/bit_helper.rb +0 -34
  46. data/lib/vertica/core_ext/numeric.rb +0 -13
  47. data/lib/vertica/core_ext/string.rb +0 -22
  48. data/lib/vertica/notice.rb +0 -11
  49. data/lib/vertica/vertica_socket.rb +0 -19
  50. data/test/connection_test.rb +0 -191
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class NoData < BackendMessage
4
- message_id ?n
4
+ message_id 'n'
5
5
  end
6
6
  end
7
7
  end
@@ -1,16 +1,42 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class NoticeResponse < BackendMessage
4
- message_id ?N
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
- attr_reader :notices
7
-
8
- def initialize(stream, size)
9
- super
10
- @notices, type = [], nil
11
- @notices << [type, stream.read_cstring] while (type = stream.read_byte) != 0
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 ?A
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(stream, size)
11
- super
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 ?t
4
+ message_id 't'
5
5
 
6
- attr_reader :parameter_count
7
6
  attr_reader :parameter_types
8
7
 
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
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 ?S
4
+ message_id 'S'
5
5
 
6
- attr_reader :name
7
- attr_reader :value
6
+ attr_reader :name, :value
8
7
 
9
- def initialize(stream, size)
10
- super
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,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class ParseComplete < BackendMessage
4
- message_id ?1
4
+ message_id '1'
5
5
  end
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class PortalSuspended < BackendMessage
4
- message_id ?s
4
+ message_id 's'
5
5
  end
6
6
  end
7
7
  end
@@ -1,13 +1,12 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class ReadyForQuery < BackendMessage
4
- message_id ?Z
4
+ message_id 'Z'
5
5
 
6
6
  attr_reader :transaction_status
7
7
 
8
- def initialize(stream, size)
9
- super
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 ?T
4
+ message_id 'T'
5
5
 
6
- attr_reader :field_count
7
6
  attr_reader :fields
8
7
 
9
- def initialize(stream, size)
10
- super
11
-
8
+ def initialize(data)
12
9
  @fields = []
13
-
14
- @field_count = stream.read_network_int16
15
- @field_count.times do |field_index|
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 => 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
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
@@ -3,8 +3,8 @@ module Vertica
3
3
  class Unknown < BackendMessage
4
4
  attr_reader :message_id
5
5
 
6
- def initialize(stream, size)
7
- @message_id = message_id
6
+ def initialize(message_id, data)
7
+ @message_id, @data = message_id, data
8
8
  end
9
9
  end
10
10
  end
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class Bind < FrontendMessage
4
- message_id ?B
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
- @portal_name.to_cstring, # portal name ("")
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
@@ -9,11 +9,7 @@ module Vertica
9
9
  end
10
10
 
11
11
  def to_bytes
12
- message_string([
13
- 80877102.to_network_int32,
14
- @backend_pid.to_network_int32,
15
- @backend_key.to_network_int32
16
- ])
12
+ message_string [80877102, @backend_pid, @backend_key].pack('N3')
17
13
  end
18
14
 
19
15
  end
@@ -1,24 +1,20 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class Close < FrontendMessage
4
- message_id ?C
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
- 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.")
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 ?D
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
- 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.")
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 ?E
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 Flush < FrontendMessage
4
- message_id ?H
4
+ message_id 'H'
5
5
  end
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class Parse < FrontendMessage
4
- message_id ?P
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 ?p
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 password
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(m + @options[:salt])
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 password.to_cstring
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 ?Q
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.to_cstring
12
+ message_string [@query_string].pack('Z*')
13
13
  end
14
14
  end
15
-
16
15
  end
17
16
  end