vertica 0.8.1 → 0.9.0.beta1

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