vertica 0.9.0.beta3 → 0.9.0.beta4

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.
@@ -0,0 +1,13 @@
1
+ module Vertica
2
+ module Messages
3
+ class CopyInResponse < BackendMessage
4
+ message_id 'G'
5
+
6
+ def initialize(data)
7
+ values = data.unpack('Cn*')
8
+ @format = values[0]
9
+ @column_formats = values.slice(2..-1)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,12 +1,19 @@
1
1
  module Vertica
2
2
  module Messages
3
3
  class ReadyForQuery < BackendMessage
4
+
5
+ STATUSES = {
6
+ 'I' => :no_transaction,
7
+ 'T' => :in_transaction,
8
+ 'E' => :failed_transaction
9
+ }
10
+
4
11
  message_id 'Z'
5
12
 
6
13
  attr_reader :transaction_status
7
14
 
8
15
  def initialize(data)
9
- @transaction_status = data.unpack('a').first
16
+ @transaction_status = STATUSES[data.unpack('a').first]
10
17
  end
11
18
  end
12
19
  end
@@ -6,12 +6,13 @@ module Vertica
6
6
  def initialize(portal_name, prepared_statement_name, parameter_values)
7
7
  @portal_name = portal_name
8
8
  @prepared_statement_name = prepared_statement_name
9
- @parameter_values = parameter_values.map(&:to_s)
9
+ @parameter_values = parameter_values
10
10
  end
11
11
 
12
12
  def to_bytes
13
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')
14
+ bytes << @parameter_values.map { |val| val.nil? ? [-1].pack('N') : [val.length, val].pack('Na*') }.join('')
15
+ bytes << [0].pack('n')
15
16
  message_string bytes
16
17
  end
17
18
  end
@@ -0,0 +1,15 @@
1
+ module Vertica
2
+ module Messages
3
+ class CopyData < FrontendMessage
4
+ message_id 'd'
5
+
6
+ def initialize(data)
7
+ @data = data
8
+ end
9
+
10
+ def to_bytes
11
+ message_string [@data].pack('a*')
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Vertica
2
+ module Messages
3
+ class CopyDone < FrontendMessage
4
+ message_id 'c'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ module Vertica
2
+ module Messages
3
+ class CopyFail < FrontendMessage
4
+ message_id 'f'
5
+
6
+ def initialize(error_message)
7
+ @error_message = error_message
8
+ end
9
+
10
+ def to_bytes
11
+ message_string [@error_message].pack('Z*')
12
+ end
13
+ end
14
+ end
15
+ end
@@ -6,17 +6,17 @@ module Vertica
6
6
 
7
7
  def initialize(password, auth_method = nil, options = {})
8
8
  @password = password
9
- @auth_method = auth_method || Messages::Authentication::CLEARTEXT_PASSWORD
9
+ @auth_method = auth_method || Vertica::Messages::Authentication::CLEARTEXT_PASSWORD
10
10
  @options = options
11
11
  end
12
12
 
13
13
  def encoded_password
14
14
  case @auth_method
15
- when Authentication::CLEARTEXT_PASSWORD
15
+ when Vertica::Messages::Authentication::CLEARTEXT_PASSWORD
16
16
  @password
17
- when Authentication::CRYPT_PASSWORD
17
+ when Vertica::Messages::Authentication::CRYPT_PASSWORD
18
18
  @password.crypt(@options[:salt])
19
- when Authentication::MD5_PASSWORD
19
+ when Vertica::Messages::Authentication::MD5_PASSWORD
20
20
  require 'digest/md5'
21
21
  @password = Digest::MD5.hexdigest(@password + @options[:user])
22
22
  @password = Digest::MD5.hexdigest(@password + @options[:salt])
@@ -53,13 +53,13 @@ require 'vertica/messages/backend_messages/empty_query_response'
53
53
  require 'vertica/messages/backend_messages/notice_response'
54
54
  require 'vertica/messages/backend_messages/error_response'
55
55
  require 'vertica/messages/backend_messages/no_data'
56
- require 'vertica/messages/backend_messages/notification_response'
57
56
  require 'vertica/messages/backend_messages/parameter_description'
58
57
  require 'vertica/messages/backend_messages/parameter_status'
59
58
  require 'vertica/messages/backend_messages/parse_complete'
60
59
  require 'vertica/messages/backend_messages/portal_suspended'
61
60
  require 'vertica/messages/backend_messages/ready_for_query'
62
61
  require 'vertica/messages/backend_messages/row_description'
62
+ require 'vertica/messages/backend_messages/copy_in_response'
63
63
  require 'vertica/messages/backend_messages/unknown'
64
64
 
65
65
  require 'vertica/messages/frontend_messages/bind'
@@ -75,3 +75,6 @@ require 'vertica/messages/frontend_messages/ssl_request'
75
75
  require 'vertica/messages/frontend_messages/startup'
76
76
  require 'vertica/messages/frontend_messages/sync'
77
77
  require 'vertica/messages/frontend_messages/terminate'
78
+ require 'vertica/messages/frontend_messages/copy_done'
79
+ require 'vertica/messages/frontend_messages/copy_fail'
80
+ require 'vertica/messages/frontend_messages/copy_data'
@@ -0,0 +1,84 @@
1
+ class Vertica::Query
2
+
3
+ attr_reader :connection, :sql
4
+ attr_accessor :row_handler, :copy_handler, :row_style
5
+
6
+ def initialize(connection, sql, options = {})
7
+ @connection, @sql = connection, sql
8
+
9
+ @row_style = options[:row_style] || @connection.row_style || :hash
10
+ @row_handler = options[:row_handler]
11
+ @copy_handler = options[:copy_handler]
12
+ end
13
+
14
+
15
+ def run
16
+ @connection.write Vertica::Messages::Query.new(@sql)
17
+ result, error = nil, nil
18
+ begin
19
+ case message = @connection.read_message
20
+ when Vertica::Messages::ErrorResponse
21
+ error = message.error_message
22
+ when Vertica::Messages::EmptyQueryResponse
23
+ error = "The provided query was empty."
24
+ when Vertica::Messages::CopyInResponse
25
+ handle_copy_from_stdin
26
+ when Vertica::Messages::RowDescription, Vertica::Messages::CommandComplete
27
+ result = retreive_result(message, Vertica::Result.new(row_style))
28
+ else
29
+ @connection.process_message(message)
30
+ end
31
+ end until message.kind_of?(Vertica::Messages::ReadyForQuery)
32
+
33
+ raise Vertica::Error::QueryError, error unless error.nil?
34
+ return result
35
+ end
36
+
37
+ def copy_data(data)
38
+ @connection.write Vertica::Messages::CopyData.new(data)
39
+ return self
40
+ end
41
+
42
+ alias_method :<<, :copy_data
43
+
44
+ protected
45
+
46
+ def handle_copy_from_stdin
47
+ if copy_handler.nil?
48
+ @connection.write Vertica::Messages::CopyFail.new('no handler provided')
49
+ else
50
+ begin
51
+ if copy_handler.call(self) == :rollback
52
+ @connection.write Vertica::Messages::CopyFail.new("rollback")
53
+ else
54
+ @connection.write Vertica::Messages::CopyDone.new
55
+ end
56
+ rescue => e
57
+ @connection.write Vertica::Messages::CopyFail.new(e.message)
58
+ raise
59
+ end
60
+ end
61
+ end
62
+
63
+ def retreive_result(message, result)
64
+ until message.kind_of?(Vertica::Messages::CommandComplete)
65
+ case message
66
+ when Vertica::Messages::RowDescription
67
+ result.descriptions = message
68
+ when Vertica::Messages::DataRow
69
+ record = result.format_row(message)
70
+ result.add_row(record) if buffer_rows?
71
+ @row_handler.call(record) if @row_handler
72
+ else
73
+ @connection.process_message(message)
74
+ end
75
+ message = @connection.read_message
76
+ end
77
+ result.tag = message.tag
78
+ return result
79
+ end
80
+
81
+ def buffer_rows?
82
+ @row_handler.nil? && @copy_handler.nil?
83
+ end
84
+ end
@@ -1,58 +1,54 @@
1
- module Vertica
2
- class Result
3
-
4
- include Enumerable
5
-
6
- attr_reader :columns
7
- attr_reader :rows
8
-
9
- attr_accessor
10
-
11
- def initialize(row_style = :hash)
12
- @row_style = row_style
13
- @rows = []
14
- end
1
+ class Vertica::Result
2
+ include Enumerable
3
+
4
+ attr_reader :columns
5
+ attr_reader :rows
6
+ attr_accessor :tag, :notice
7
+
8
+ def initialize(row_style = :hash)
9
+ @row_style = row_style
10
+ @rows = []
11
+ end
15
12
 
16
- def descriptions=(message)
17
- @columns = message.fields.map { |fd| Column.new(fd) }
18
- end
13
+ def descriptions=(message)
14
+ @columns = message.fields.map { |fd| Vertica::Column.new(fd) }
15
+ end
19
16
 
20
- def format_row_as_hash(row_data)
21
- row = {}
22
- row_data.values.each_with_index do |value, idx|
23
- col = columns[idx]
24
- row[col.name] = col.convert(value)
25
- end
26
- row
27
- end
28
-
29
- def format_row(row_data)
30
- send("format_row_as_#{@row_style}", row_data)
17
+ def format_row_as_hash(row_data)
18
+ row = {}
19
+ row_data.values.each_with_index do |value, idx|
20
+ col = columns[idx]
21
+ row[col.name] = col.convert(value)
31
22
  end
32
-
33
- def format_row_as_array(row_data)
34
- row = []
35
- row_data.values.each_with_index do |value, idx|
36
- row << columns[idx].convert(value)
37
- end
38
- row
39
- end
40
-
41
- def add_row(row_data)
42
- @rows << format_row(row_data)
23
+ row
24
+ end
25
+
26
+ def format_row(row_data)
27
+ send("format_row_as_#{@row_style}", row_data)
28
+ end
29
+
30
+ def format_row_as_array(row_data)
31
+ row = []
32
+ row_data.values.each_with_index do |value, idx|
33
+ row << columns[idx].convert(value)
43
34
  end
35
+ row
36
+ end
44
37
 
45
- def each_row(&block)
46
- @rows.each(&block)
47
- end
48
-
49
- alias_method :each, :each_row
38
+ def add_row(row)
39
+ @rows << row
40
+ end
50
41
 
51
- def row_count
52
- @rows.size
53
- end
42
+ def each_row(&block)
43
+ @rows.each(&block)
44
+ end
45
+
46
+ alias_method :each, :each_row
54
47
 
55
- alias_method :size, :row_count
56
- alias_method :length, :row_count
48
+ def row_count
49
+ @rows.size
57
50
  end
51
+
52
+ alias_method :size, :row_count
53
+ alias_method :length, :row_count
58
54
  end
@@ -5,7 +5,7 @@ class ConnectionTest < Test::Unit::TestCase
5
5
  def teardown
6
6
  @connection.close if @connection
7
7
  end
8
-
8
+
9
9
  def test_new_connection
10
10
  @connection = Vertica::Connection.new(TEST_CONNECTION_HASH)
11
11
 
@@ -19,8 +19,6 @@ class ConnectionTest < Test::Unit::TestCase
19
19
  # parameters
20
20
  assert @connection.parameters.kind_of?(Hash)
21
21
  assert @connection.parameters.include?('server_version')
22
-
23
- assert_equal [], @connection.notifications
24
22
  end
25
23
 
26
24
  def test_close_connection
@@ -67,7 +65,7 @@ class ConnectionTest < Test::Unit::TestCase
67
65
 
68
66
  def test_new_with_error_response
69
67
  assert_raises Vertica::Error::ConnectionError do
70
- Vertica::Connection.new(TEST_CONNECTION_HASH.merge(:database => 'nonexistant_db'))
68
+ Vertica::Connection.new(TEST_CONNECTION_HASH.merge('database' => 'nonexistant_db'))
71
69
  end
72
70
  end
73
71
  end
@@ -4,20 +4,19 @@ class QueryTest < Test::Unit::TestCase
4
4
 
5
5
  def setup
6
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')")
7
+ @connection.query("CREATE TABLE IF NOT EXISTS test_ruby_vertica_table (id int, name varchar(100))")
8
+ @connection.query("CREATE PROJECTION IF NOT EXISTS test_ruby_vertica_table_p (id, name) AS SELECT * FROM test_ruby_vertica_table SEGMENTED BY HASH(id) ALL NODES OFFSET 1")
9
+ @connection.query("INSERT INTO test_ruby_vertica_table VALUES (1, 'matt')")
10
10
  @connection.query("COMMIT")
11
11
  end
12
12
 
13
13
  def teardown
14
- @connection.query("DROP TABLE IF EXISTS test_table CASCADE;")
15
- @connection.query("COMMIT")
14
+ @connection.query("DROP TABLE IF EXISTS test_ruby_vertica_table CASCADE;")
16
15
  @connection.close
17
16
  end
18
17
 
19
18
  def test_select_query_with_results_as_hash
20
- r = @connection.query("SELECT * FROM test_table")
19
+ r = @connection.query("SELECT * FROM test_ruby_vertica_table")
21
20
  assert_equal 1, r.row_count
22
21
  assert_equal 2, r.columns.length
23
22
  assert_equal :integer, r.columns[0].data_type
@@ -27,10 +26,10 @@ class QueryTest < Test::Unit::TestCase
27
26
 
28
27
  assert_equal [{:id => 1, :name => "matt"}], r.rows
29
28
  end
30
-
29
+
31
30
  def test_select_query_with_results_as_array
32
31
  @connection.row_style = :array
33
- r = @connection.query("SELECT * FROM test_table")
32
+ r = @connection.query("SELECT * FROM test_ruby_vertica_table")
34
33
  assert_equal 1, r.row_count
35
34
  assert_equal 2, r.columns.length
36
35
  assert_equal :integer, r.columns[0].data_type
@@ -40,10 +39,10 @@ class QueryTest < Test::Unit::TestCase
40
39
 
41
40
  assert_equal [[1, "matt"]], r.rows
42
41
  end
43
-
42
+
44
43
 
45
44
  def test_select_query_with_no_results
46
- r = @connection.query("SELECT * FROM test_table WHERE 1 != 1")
45
+ r = @connection.query("SELECT * FROM test_ruby_vertica_table WHERE 1 != 1")
47
46
  assert_equal 0, r.row_count
48
47
  assert_equal 2, r.columns.length
49
48
  assert_equal :integer, r.columns[0].data_type
@@ -54,7 +53,7 @@ class QueryTest < Test::Unit::TestCase
54
53
  end
55
54
 
56
55
  def test_insert
57
- r = @connection.query("INSERT INTO test_table VALUES (2, 'stefanie')")
56
+ r = @connection.query("INSERT INTO test_ruby_vertica_table VALUES (2, 'stefanie')")
58
57
  assert_equal 1, r.row_count
59
58
  assert_equal 1, r.columns.length
60
59
  assert_equal :integer, r.columns[0].data_type
@@ -64,7 +63,7 @@ class QueryTest < Test::Unit::TestCase
64
63
 
65
64
 
66
65
  def test_delete_of_no_rows
67
- r = @connection.query("DELETE FROM test_table WHERE 1 != 1")
66
+ r = @connection.query("DELETE FROM test_ruby_vertica_table WHERE 1 != 1")
68
67
  assert_equal 1, r.row_count
69
68
  assert_equal 1, r.columns.length
70
69
  assert_equal :integer, r.columns[0].data_type
@@ -73,7 +72,7 @@ class QueryTest < Test::Unit::TestCase
73
72
  end
74
73
 
75
74
  def test_delete_of_a_row
76
- r = @connection.query("DELETE FROM test_table WHERE id = 1")
75
+ r = @connection.query("DELETE FROM test_ruby_vertica_table WHERE id = 1")
77
76
  assert_equal 1, r.row_count
78
77
  assert_equal 1, r.columns.length
79
78
  assert_equal :integer, r.columns[0].data_type
@@ -82,75 +81,20 @@ class QueryTest < Test::Unit::TestCase
82
81
  end
83
82
 
84
83
  def test_empty_query
85
- assert_raises ArgumentError do
84
+ assert_raises Vertica::Error::QueryError do
86
85
  @connection.query("")
87
86
  end
88
- assert_raises ArgumentError do
87
+ assert_raises Vertica::Error::QueryError do
89
88
  @connection.query(nil)
90
89
  end
91
- end
92
-
93
- # FIXME: now hangs forever
94
- # def test_non_query
95
- # @connection.query("--just a comment")
96
- # end
97
-
98
- def test_sql_error
99
90
  assert_raises Vertica::Error::QueryError do
100
- @connection.query("SELECT * FROM nonexisting")
101
- end
102
- assert_raises Vertica::Error::QueryError do
103
- @connection.query("BLAH")
91
+ @connection.query("-- just a SQL comment")
104
92
  end
105
93
  end
106
94
 
107
- def test_cancel
108
- Vertica::Connection.cancel(@connection)
109
- end
110
-
111
- # def test_prepared_statement_with_no_params
112
- # @connection.prepare("my_ps", "SELECT * FROM test_table")
113
- # r = @connection.execute_prepared("my_ps")
114
- # assert_equal 1, r.row_count
115
- # assert_equal 2, r.columns.length
116
- # assert_equal :integer, 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 [{:id => 1, :name => "matt"}], r.rows
121
- # end
122
- #
123
- # def test_prepared_statement_with_one_param
124
- # c = Vertica::Connection.new(TEST_CONNECTION_HASH)
125
- # c.prepare("my_ps", "SELECT * FROM test_table WHERE id = ?", 1)
126
- # r = c.execute_prepared("my_ps", 1)
127
- # assert_equal 1, r.row_count
128
- # assert_equal 2, r.columns.length
129
- # assert_equal :integer, r.columns[0].data_type
130
- # assert_equal 'id', r.columns[0].name
131
- # assert_equal :varchar, r.columns[1].data_type
132
- # assert_equal 'name', r.columns[1].name
133
- # assert_equal [[1, 'matt']], r.rows
134
- # c.close
135
- # end
136
- #
137
- # def test_prepared_statement_with_two_params
138
- # c = Vertica::Connection.new(TEST_CONNECTION_HASH)
139
- # c.prepare("my_ps", "SELECT * FROM test_table WHERE id = ? OR id = ?", 2)
140
- # r = c.execute_prepared("my_ps", 1, 3)
141
- # assert_equal 1, r.row_count
142
- # assert_equal 2, r.columns.length
143
- # assert_equal :integer, 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 [[1, 'matt']], r.rows
148
- # c.close
149
- # end
150
-
151
95
  def test_cleanup_after_select
152
- 5.times do
153
- r = @connection.query("SELECT * FROM test_table")
96
+ 3.times do
97
+ r = @connection.query("SELECT * FROM test_ruby_vertica_table")
154
98
  assert_equal 1, r.row_count
155
99
  assert_equal 2, r.columns.length
156
100
  assert_equal :integer, r.columns[0].data_type
@@ -159,5 +103,53 @@ class QueryTest < Test::Unit::TestCase
159
103
  assert_equal :name, r.columns[1].name
160
104
  assert_equal [{:id => 1, :name => "matt"}], r.rows
161
105
  end
106
+ end
107
+
108
+ def test_sql_error
109
+ assert_raises Vertica::Error::QueryError do
110
+ @connection.query("SELECT * FROM nonexistingfdg")
111
+ end
112
+ assert_raises Vertica::Error::QueryError do
113
+ @connection.query("BLAH")
114
+ end
115
+ end
116
+
117
+ def test_copy_in_with_customer_handler
118
+ @connection.copy "COPY test_ruby_vertica_table FROM STDIN" do |data|
119
+ data.copy_data "11|Stuff\r\n"
120
+ data << "12|More stuff\n13|Fin" << "al stuff\n"
121
+ end
122
+
123
+ result = @connection.query("SELECT * FROM test_ruby_vertica_table ORDER BY id", :row_style => :array)
124
+ assert_equal 4, result.length
125
+ assert_equal [[1, "matt"], [11, "Stuff"], [12, "More stuff"], [13, "Final stuff"]], result.rows
126
+ end
127
+
128
+ def test_copy_in_with_file
129
+ filename = File.expand_path('../../resources/test_ruby_vertica_table.csv', __FILE__)
130
+ @connection.copy "COPY test_ruby_vertica_table FROM STDIN", filename
131
+ result = @connection.query("SELECT * FROM test_ruby_vertica_table ORDER BY id", :row_style => :array)
132
+ assert_equal 4, result.length
133
+ assert_equal [[1, "matt"], [11, "Stuff"], [12, "More stuff"], [13, "Final stuff"]], result.rows
134
+ end
135
+
136
+ def test_copy_in_with_io
137
+ io = StringIO.new("11|Stuff\r\n12|More stuff\n13|Final stuff\n")
138
+ @connection.copy "COPY test_ruby_vertica_table FROM STDIN", io
139
+ result = @connection.query("SELECT * FROM test_ruby_vertica_table ORDER BY id", :row_style => :array)
140
+ assert_equal 4, result.length
141
+ assert_equal [[1, "matt"], [11, "Stuff"], [12, "More stuff"], [13, "Final stuff"]], result.rows
142
+ end
143
+
144
+ def test_cancel
145
+ Vertica::Connection.cancel(@connection)
146
+ # TODO: actually test whether this works.
147
+ end
148
+
149
+ def test_notice_handler
150
+ notice_received = false
151
+ @connection.on_notice { |notice| notice_received = true }
152
+ @connection.query('COMMIT')
153
+ assert notice_received
162
154
  end
163
155
  end