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
@@ -4,9 +4,8 @@ module Vertica
4
4
  message_id nil
5
5
 
6
6
  def to_bytes
7
- message_string 80877103.to_network_int32
7
+ message_string [80877103].pack('N')
8
8
  end
9
-
10
9
  end
11
10
  end
12
11
  end
@@ -11,15 +11,13 @@ module Vertica
11
11
  end
12
12
 
13
13
  def to_bytes
14
- bytes = [Vertica::PROTOCOL_VERSION.to_network_int32]
15
- bytes += ['user'.to_cstring, @user.to_cstring] if @user
16
- bytes += ['database'.to_cstring, @database.to_cstring] if @database
17
- bytes += ['options'.to_cstring, @options.to_cstring] if @options
18
- bytes << 0
19
-
20
- message_string bytes
14
+ str = [Vertica::PROTOCOL_VERSION].pack('N')
15
+ str << ["user", @user].pack('Z*Z*') if @user
16
+ str << ["database", @database].pack('Z*Z*') if @database
17
+ str << ["options", @options].pack('Z*Z*') if @options
18
+ str << [].pack('x')
19
+ message_string str
21
20
  end
22
-
23
21
  end
24
22
  end
25
23
  end
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class Sync < FrontendMessage
4
- message_id ?S
4
+ message_id 'S'
5
5
  end
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class Terminate < FrontendMessage
4
- message_id ?X
4
+ message_id 'X'
5
5
  end
6
6
  end
7
7
  end
@@ -8,39 +8,30 @@ module Vertica
8
8
 
9
9
  def message_string(msg)
10
10
  msg = msg.join if msg.is_a?(Array)
11
- size = (0.to_network_int32.size + msg.size).to_network_int32
12
- m_id = ''.to_byte #in 1.9 it seems to write out message ids as numbers, handle this here
13
- if (message_id)
14
- m_id = message_id.chr
15
- end
16
- "#{m_id}#{size}#{msg}"
11
+ bytesize = msg.respond_to?(:bytesize) ? 4 + msg.bytesize : 4 + msg.size
12
+ message_size = [bytesize].pack('N')
13
+ message_id ? "#{message_id}#{message_size}#{msg}" : "#{message_size}#{msg}"
17
14
  end
18
15
  end
19
16
 
20
17
  class BackendMessage < Message
21
18
  MessageIdMap = {}
22
19
 
23
- attr_reader :size
24
-
25
- def self.factory(type, stream, size)
20
+ def self.factory(type, data)
26
21
  #puts "factory reading message #{type} #{size} #{type.class}"
27
- if klass = MessageIdMap[type.chr] #explicitly use the char value, for 1.9 compat
28
- klass.new stream, size
22
+ if klass = MessageIdMap[type] #explicitly use the char value, for 1.9 compat
23
+ klass.new data
29
24
  else
30
- Messages::Unknown.new stream, size
25
+ Messages::Unknown.new type, data
31
26
  end
32
27
  end
33
28
 
34
29
  def self.message_id(message_id)
35
30
  super
36
- MessageIdMap[message_id.chr] = self #explicitly use the char value, for 1.9 compat
37
- end
38
-
39
- def self.read(stream)
31
+ MessageIdMap[message_id] = self #explicitly use the char value, for 1.9 compat
40
32
  end
41
33
 
42
- def initialize(stream, size)
43
- @size = size
34
+ def initialize(data)
44
35
  end
45
36
  end
46
37
 
@@ -1,5 +1,8 @@
1
1
  module Vertica
2
2
  class Result
3
+
4
+ include Enumerable
5
+
3
6
  attr_reader :columns
4
7
  attr_reader :rows
5
8
 
@@ -13,7 +16,7 @@ module Vertica
13
16
 
14
17
  def format_row(row_data)
15
18
  row = {}
16
- row_data.fields.each_with_index do |field, idx|
19
+ row_data.values.each_with_index do |field, idx|
17
20
  col = columns[idx]
18
21
  row[col.name] = col.convert(field)
19
22
  end
@@ -27,10 +30,14 @@ module Vertica
27
30
  def each_row(&block)
28
31
  @rows.each(&block)
29
32
  end
33
+
34
+ alias_method :each, :each_row
30
35
 
31
36
  def row_count
32
37
  @rows.size
33
38
  end
34
39
 
40
+ alias_method :size, :row_count
41
+ alias_method :length, :row_count
35
42
  end
36
43
  end
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+
3
+ class ConnectionTest < Test::Unit::TestCase
4
+
5
+ def teardown
6
+ @connection.close if @connection
7
+ end
8
+
9
+ def test_new_connection
10
+ @connection = Vertica::Connection.new(TEST_CONNECTION_HASH)
11
+
12
+ assert !@connection.parameters.empty?
13
+ assert @connection.backend_pid
14
+ assert @connection.backend_key
15
+ assert @connection.transaction_status
16
+ assert @connection.opened?
17
+ assert !@connection.closed?
18
+
19
+ # parameters
20
+ assert @connection.parameters.kind_of?(Hash)
21
+ assert @connection.parameters.include?('server_version')
22
+
23
+ assert_equal [], @connection.notifications
24
+ end
25
+
26
+ def test_close_connection
27
+ @connection = Vertica::Connection.new(TEST_CONNECTION_HASH)
28
+ @connection.close
29
+
30
+ assert !@connection.opened?
31
+ assert @connection.closed?
32
+ assert_equal({}, @connection.parameters)
33
+ assert_nil @connection.backend_pid
34
+ assert_nil @connection.backend_key
35
+ assert_nil @connection.transaction_status
36
+ end
37
+
38
+ def test_connection_with_ssl
39
+ @connection = Vertica::Connection.new(TEST_CONNECTION_HASH.merge(:ssl => true))
40
+
41
+ assert @connection.ssl?
42
+ assert !@connection.parameters.empty?
43
+ assert @connection.backend_pid
44
+ assert @connection.backend_key
45
+ assert @connection.transaction_status
46
+
47
+ @connection.close
48
+
49
+ assert_equal({}, @connection.parameters)
50
+ assert_nil @connection.backend_pid
51
+ assert_nil @connection.backend_key
52
+ assert_nil @connection.transaction_status
53
+ end
54
+
55
+ def test_reset
56
+ @connection = Vertica::Connection.new(TEST_CONNECTION_HASH)
57
+ assert !@connection.parameters.empty?
58
+ assert @connection.backend_pid
59
+ assert @connection.backend_key
60
+ assert @connection.transaction_status
61
+ @connection.reset
62
+ assert_equal({}, @connection.parameters)
63
+ assert_nil @connection.backend_pid
64
+ assert_nil @connection.backend_key
65
+ assert_nil @connection.transaction_status
66
+ end
67
+
68
+ def test_new_with_error_response
69
+ assert_raises Vertica::Error::ConnectionError do
70
+ Vertica::Connection.new(TEST_CONNECTION_HASH.merge(:database => 'nonexistant_db'))
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,150 @@
1
+ require 'test_helper'
2
+
3
+ class QueryTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @connection = Vertica::Connection.new(TEST_CONNECTION_HASH)
7
+ @connection.query("CREATE TABLE IF NOT EXISTS test_table (id int, name varchar(100))")
8
+ @connection.query("CREATE PROJECTION IF NOT EXISTS test_table_p (id, name) AS SELECT * FROM test_table SEGMENTED BY HASH(id) ALL NODES OFFSET 1")
9
+ @connection.query("INSERT INTO test_table VALUES (1, 'matt')")
10
+ @connection.query("COMMIT")
11
+ end
12
+
13
+ def teardown
14
+ @connection.query("DROP TABLE IF EXISTS test_table CASCADE;")
15
+ @connection.query("COMMIT")
16
+ @connection.close
17
+ end
18
+
19
+ def test_select_query_with_results
20
+ r = @connection.query("SELECT * FROM test_table")
21
+ assert_equal 1, r.row_count
22
+ assert_equal 2, r.columns.length
23
+ assert_equal :in, r.columns[0].data_type
24
+ assert_equal :id, r.columns[0].name
25
+ assert_equal :varchar, r.columns[1].data_type
26
+ assert_equal :name, r.columns[1].name
27
+
28
+ # assert_equal [[1, 'matt']], r.rows
29
+ assert_equal [{:id => 1, :name => "matt"}], r.rows
30
+ end
31
+
32
+ def test_select_query_with_no_results
33
+ r = @connection.query("SELECT * FROM test_table WHERE 1 != 1")
34
+ assert_equal 0, r.row_count
35
+ assert_equal 2, r.columns.length
36
+ assert_equal :in, r.columns[0].data_type
37
+ assert_equal :id, r.columns[0].name
38
+ assert_equal :varchar, r.columns[1].data_type
39
+ assert_equal :name, r.columns[1].name
40
+ assert_equal [], r.rows
41
+ end
42
+
43
+ def test_insert
44
+ r = @connection.query("INSERT INTO test_table VALUES (2, 'stefanie')")
45
+ assert_equal 1, r.row_count
46
+ assert_equal 1, r.columns.length
47
+ assert_equal :in, r.columns[0].data_type
48
+ assert_equal :OUTPUT, r.columns[0].name
49
+ assert_equal [{:OUTPUT => 1}], r.rows
50
+ end
51
+
52
+
53
+ def test_delete_of_no_rows
54
+ r = @connection.query("DELETE FROM test_table WHERE 1 != 1")
55
+ assert_equal 1, r.row_count
56
+ assert_equal 1, r.columns.length
57
+ assert_equal :in, r.columns[0].data_type
58
+ assert_equal :OUTPUT, r.columns[0].name
59
+ assert_equal [{:OUTPUT => 0}], r.rows
60
+ end
61
+
62
+ def test_delete_of_a_row
63
+ r = @connection.query("DELETE FROM test_table WHERE id = 1")
64
+ assert_equal 1, r.row_count
65
+ assert_equal 1, r.columns.length
66
+ assert_equal :in, r.columns[0].data_type
67
+ assert_equal :OUTPUT, r.columns[0].name
68
+ assert_equal [{:OUTPUT => 1}], r.rows
69
+ end
70
+
71
+ def test_empty_query
72
+ assert_raises ArgumentError do
73
+ @connection.query("")
74
+ end
75
+ assert_raises ArgumentError do
76
+ @connection.query(nil)
77
+ end
78
+ end
79
+
80
+ # FIXME: now hangs forever
81
+ # def test_non_query
82
+ # @connection.query("--just a comment")
83
+ # end
84
+
85
+ def test_sql_error
86
+ assert_raises Vertica::Error::QueryError do
87
+ @connection.query("SELECT * FROM nonexisting")
88
+ end
89
+ assert_raises Vertica::Error::QueryError do
90
+ @connection.query("BLAH")
91
+ end
92
+ end
93
+
94
+ def test_cancel
95
+ Vertica::Connection.cancel(@connection)
96
+ end
97
+
98
+ # def test_prepared_statement_with_no_params
99
+ # @connection.prepare("my_ps", "SELECT * FROM test_table")
100
+ # r = @connection.execute_prepared("my_ps")
101
+ # assert_equal 1, r.row_count
102
+ # assert_equal 2, r.columns.length
103
+ # assert_equal :in, r.columns[0].data_type
104
+ # assert_equal :id, r.columns[0].name
105
+ # assert_equal :varchar, r.columns[1].data_type
106
+ # assert_equal :name, r.columns[1].name
107
+ # assert_equal [{:id => 1, :name => "matt"}], r.rows
108
+ # end
109
+ #
110
+ # def test_prepared_statement_with_one_param
111
+ # c = Vertica::Connection.new(TEST_CONNECTION_HASH)
112
+ # c.prepare("my_ps", "SELECT * FROM test_table WHERE id = ?", 1)
113
+ # r = c.execute_prepared("my_ps", 1)
114
+ # assert_equal 1, r.row_count
115
+ # assert_equal 2, r.columns.length
116
+ # assert_equal :in, r.columns[0].data_type
117
+ # assert_equal 'id', r.columns[0].name
118
+ # assert_equal :varchar, r.columns[1].data_type
119
+ # assert_equal 'name', r.columns[1].name
120
+ # assert_equal [[1, 'matt']], r.rows
121
+ # c.close
122
+ # end
123
+ #
124
+ # def test_prepared_statement_with_two_params
125
+ # c = Vertica::Connection.new(TEST_CONNECTION_HASH)
126
+ # c.prepare("my_ps", "SELECT * FROM test_table WHERE id = ? OR id = ?", 2)
127
+ # r = c.execute_prepared("my_ps", 1, 3)
128
+ # assert_equal 1, r.row_count
129
+ # assert_equal 2, r.columns.length
130
+ # assert_equal :in, r.columns[0].data_type
131
+ # assert_equal 'id', r.columns[0].name
132
+ # assert_equal :varchar, r.columns[1].data_type
133
+ # assert_equal 'name', r.columns[1].name
134
+ # assert_equal [[1, 'matt']], r.rows
135
+ # c.close
136
+ # end
137
+
138
+ def test_cleanup_after_select
139
+ 5.times do
140
+ r = @connection.query("SELECT * FROM test_table")
141
+ assert_equal 1, r.row_count
142
+ assert_equal 2, r.columns.length
143
+ assert_equal :in, r.columns[0].data_type
144
+ assert_equal :id, r.columns[0].name
145
+ assert_equal :varchar, r.columns[1].data_type
146
+ assert_equal :name, r.columns[1].name
147
+ assert_equal [{:id => 1, :name => "matt"}], r.rows
148
+ end
149
+ end
150
+ end
data/test/test_helper.rb CHANGED
@@ -1,16 +1,10 @@
1
- require "test/unit"
1
+ require 'rubygems'
2
+ require 'bundler/setup'
2
3
 
3
- $:.unshift(File.dirname(__FILE__) + '/../lib')
4
- require "vertica"
4
+ require 'yaml'
5
+ require 'test/unit'
5
6
 
6
- class Test::Unit::TestCase
7
+ require 'vertica'
7
8
 
8
- TEST_CONNECTION_HASH = {
9
- :user => '',
10
- :password => '',
11
- :host => '',
12
- :port => '',
13
- :database => ''
14
- }
15
-
16
- end
9
+ hash = YAML.load(File.read(File.expand_path("../connection.yml", __FILE__)))
10
+ TEST_CONNECTION_HASH = hash.inject(Hash.new) { |carry, (k, v)| carry[k.to_sym] = v; carry }
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+
3
+ class BackendMessageTest < Test::Unit::TestCase
4
+
5
+ def test_cleartext_authentication_message
6
+ msg = Vertica::Messages::Authentication.new("\x00\x00\x00\x03")
7
+ assert_equal Vertica::Messages::Authentication::CLEARTEXT_PASSWORD , msg.code
8
+ assert_nil msg.salt
9
+ assert_nil msg.auth_data
10
+ end
11
+
12
+ def test_parameter_status_message
13
+ msg = Vertica::Messages::ParameterStatus.new("standard_conforming_strings\x00on\x00")
14
+ assert_equal "standard_conforming_strings", msg.name
15
+ assert_equal "on", msg.value
16
+ end
17
+
18
+ def test_backend_key_data_message
19
+ msg = Vertica::Messages::BackendKeyData.new("\x00\x01\xED\xD8\x02\xC4\"\t")
20
+ assert_equal 126424, msg.pid
21
+ assert_equal 46408201, msg.key
22
+ end
23
+
24
+ def test_ready_for_query_message
25
+ msg = Vertica::Messages::ReadyForQuery.new("I")
26
+ assert_equal 'I', msg.transaction_status
27
+ end
28
+
29
+ def test_error_response_message
30
+ data = "SFATAL\x00C3D000\x00Mdatabase \"nonexistant_db\" does not exist\x00F/scratch_a/release/vbuild/vertica/Basics/ClientAuthentication.cpp\x00L1496\x00RClientAuthentication\x00\x00"
31
+ msg = Vertica::Messages::ErrorResponse.new(data)
32
+ assert_equal msg.values, {
33
+ "Severity" => "FATAL",
34
+ "Sqlstate" => "3D000",
35
+ "Message" => "database \"nonexistant_db\" does not exist",
36
+ "File" => "/scratch_a/release/vbuild/vertica/Basics/ClientAuthentication.cpp",
37
+ "Line" => "1496",
38
+ "Routine" => "ClientAuthentication"
39
+ }
40
+
41
+ assert_equal "Severity: FATAL, Message: database \"nonexistant_db\" does not exist, Sqlstate: 3D000, Routine: ClientAuthentication, File: /scratch_a/release/vbuild/vertica/Basics/ClientAuthentication.cpp, Line: 1496", msg.error_message
42
+ end
43
+
44
+ def test_notice_response_message
45
+ data = "SINFO\x00C00000\x00Mcannot commit; no transaction in progress\x00F/scratch_a/release/vbuild/vertica/Commands/PGCall.cpp\x00L3502\x00Rprocess_vertica_transaction\x00\x00"
46
+ msg = Vertica::Messages::NoticeResponse.new(data)
47
+
48
+ assert_equal msg.values, {
49
+ "Severity" => "INFO",
50
+ "Sqlstate" => "00000",
51
+ "Message" => "cannot commit; no transaction in progress",
52
+ "File" => "/scratch_a/release/vbuild/vertica/Commands/PGCall.cpp",
53
+ "Line" => "3502",
54
+ "Routine" => "process_vertica_transaction"
55
+ }
56
+ end
57
+
58
+ def test_row_description_message
59
+ msg = Vertica::Messages::RowDescription.new("\x00\x01OUTPUT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\b\x00\x00\x00\b\x00\x00")
60
+ assert_equal 1, msg.fields.size
61
+ assert_equal msg.fields[0], {
62
+ :name => "OUTPUT",
63
+ :table_oid => 0,
64
+ :attribute_number => 0,
65
+ :data_type_oid => 6,
66
+ :data_type_size => 8,
67
+ :type_modifier => 8,
68
+ :format_code => 0
69
+ }
70
+
71
+ msg = Vertica::Messages::RowDescription.new("\x00\x02id\x00\x00\np8\x00\x01\x00\x00\x00\x06\x00\b\xFF\xFF\xFF\xFF\x00\x00name\x00\x00\np8\x00\x02\x00\x00\x00\t\xFF\xFF\x00\x00\x00h\x00\x00")
72
+ assert_equal msg.fields[0], {
73
+ :name => "id",
74
+ :table_oid => 684088,
75
+ :attribute_number => 1,
76
+ :data_type_oid => 6,
77
+ :data_type_size => 8,
78
+ :type_modifier => 4294967295,
79
+ :format_code => 0
80
+ }
81
+ assert_equal msg.fields[1], {
82
+ :name => "name",
83
+ :table_oid => 684088,
84
+ :attribute_number => 2,
85
+ :data_type_oid => 9,
86
+ :data_type_size => 65535,
87
+ :type_modifier => 104,
88
+ :format_code => 0
89
+ }
90
+ end
91
+
92
+ def test_data_row_message
93
+ msg = Vertica::Messages::DataRow.new("\x00\x01\x00\x00\x00\x011")
94
+ assert_equal ['1'], msg.values
95
+
96
+ msg = Vertica::Messages::DataRow.new("\x00\x02\x00\x00\x00\x011\x00\x00\x00\x04matt")
97
+ assert_equal ['1', 'matt'], msg.values
98
+ end
99
+
100
+ def test_command_complete_message
101
+ msg = Vertica::Messages::CommandComplete.new("CREATE TABLE\x00")
102
+ assert_equal "CREATE TABLE", msg.tag
103
+ assert_nil msg.rows
104
+ assert_nil msg.oid
105
+ end
106
+ end