vertica 0.7.4 → 0.8.1
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.
- data/README.md +85 -0
- data/Rakefile +56 -38
- data/VERSION +1 -0
- data/lib/vertica.rb +59 -11
- data/lib/vertica/bit_helper.rb +7 -24
- data/lib/vertica/column.rb +34 -53
- data/lib/vertica/connection.rb +123 -139
- data/lib/vertica/core_ext/numeric.rb +13 -0
- data/lib/vertica/core_ext/string.rb +22 -0
- data/lib/vertica/messages/{authentication.rb → backend_messages/authentication.rb} +6 -9
- data/lib/vertica/messages/{backend_key_data.rb → backend_messages/backend_key_data.rb} +2 -2
- data/lib/vertica/messages/{bind_complete.rb → backend_messages/bind_complete.rb} +0 -1
- data/lib/vertica/messages/{close_complete.rb → backend_messages/close_complete.rb} +0 -1
- data/lib/vertica/messages/{command_complete.rb → backend_messages/command_complete.rb} +3 -3
- data/lib/vertica/messages/{data_row.rb → backend_messages/data_row.rb} +3 -6
- data/lib/vertica/messages/{empty_query_response.rb → backend_messages/empty_query_response.rb} +0 -1
- data/lib/vertica/messages/backend_messages/error_response.rb +35 -0
- data/lib/vertica/messages/{no_data.rb → backend_messages/no_data.rb} +0 -1
- data/lib/vertica/messages/backend_messages/notice_response.rb +16 -0
- data/lib/vertica/messages/{notification_response.rb → backend_messages/notification_response.rb} +0 -0
- data/lib/vertica/messages/{parameter_description.rb → backend_messages/parameter_description.rb} +0 -0
- data/lib/vertica/messages/{parameter_status.rb → backend_messages/parameter_status.rb} +0 -0
- data/lib/vertica/messages/{parse_complete.rb → backend_messages/parse_complete.rb} +0 -1
- data/lib/vertica/messages/{portal_suspended.rb → backend_messages/portal_suspended.rb} +0 -1
- data/lib/vertica/messages/{ready_for_query.rb → backend_messages/ready_for_query.rb} +2 -2
- data/lib/vertica/messages/{row_description.rb → backend_messages/row_description.rb} +3 -3
- data/lib/vertica/messages/{unknown.rb → backend_messages/unknown.rb} +2 -2
- data/lib/vertica/messages/frontend_messages/bind.rb +28 -0
- data/lib/vertica/messages/frontend_messages/cancel_request.rb +21 -0
- data/lib/vertica/messages/frontend_messages/close.rb +24 -0
- data/lib/vertica/messages/frontend_messages/describe.rb +24 -0
- data/lib/vertica/messages/frontend_messages/execute.rb +20 -0
- data/lib/vertica/messages/frontend_messages/flush.rb +7 -0
- data/lib/vertica/messages/frontend_messages/parse.rb +23 -0
- data/lib/vertica/messages/frontend_messages/password.rb +35 -0
- data/lib/vertica/messages/frontend_messages/query.rb +17 -0
- data/lib/vertica/messages/frontend_messages/ssl_request.rb +12 -0
- data/lib/vertica/messages/frontend_messages/startup.rb +25 -0
- data/lib/vertica/messages/frontend_messages/sync.rb +7 -0
- data/lib/vertica/messages/frontend_messages/terminate.rb +7 -0
- data/lib/vertica/messages/message.rb +26 -57
- data/lib/vertica/result.rb +28 -20
- data/lib/vertica/vertica_socket.rb +14 -3
- data/test/test_helper.rb +7 -16
- metadata +55 -50
- data/README.textile +0 -69
- data/lib/vertica/messages/bind.rb +0 -36
- data/lib/vertica/messages/cancel_request.rb +0 -25
- data/lib/vertica/messages/close.rb +0 -30
- data/lib/vertica/messages/describe.rb +0 -30
- data/lib/vertica/messages/error_response.rb +0 -59
- data/lib/vertica/messages/execute.rb +0 -24
- data/lib/vertica/messages/flush.rb +0 -15
- data/lib/vertica/messages/notice_response.rb +0 -21
- data/lib/vertica/messages/parse.rb +0 -31
- data/lib/vertica/messages/password.rb +0 -33
- data/lib/vertica/messages/query.rb +0 -20
- data/lib/vertica/messages/ssl_request.rb +0 -14
- data/lib/vertica/messages/startup.rb +0 -38
- data/lib/vertica/messages/sync.rb +0 -15
- data/lib/vertica/messages/terminate.rb +0 -14
- data/test/create_schema.sql +0 -4
- data/vertica.gemspec +0 -64
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Vertica
|
2
|
+
|
3
|
+
**WARNING:** This is not well tested software (yet) use at your own risk.
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
Vertica is a pure Ruby library for connecting to Vertica databases. You can learn more
|
8
|
+
about Vertica at http://www.vertica.com. This library currently supports queries. Prepared
|
9
|
+
statements still need a bit of work.
|
10
|
+
|
11
|
+
# Install
|
12
|
+
|
13
|
+
$ gem install vertica
|
14
|
+
|
15
|
+
# Source
|
16
|
+
|
17
|
+
Vertica's git repo is available on GitHub, which can be browsed at:
|
18
|
+
|
19
|
+
http://github.com/sprsquish/vertica
|
20
|
+
|
21
|
+
and cloned from:
|
22
|
+
|
23
|
+
git://github.com/sprsquish/vertica.git
|
24
|
+
|
25
|
+
# Usage
|
26
|
+
|
27
|
+
## Example Query
|
28
|
+
|
29
|
+
### Connecting
|
30
|
+
|
31
|
+
vertica = Vertica.connect({
|
32
|
+
:user => 'user',
|
33
|
+
:password => 'password',
|
34
|
+
:host => 'db_server',
|
35
|
+
:port => '5433',
|
36
|
+
:database => 'db
|
37
|
+
})
|
38
|
+
|
39
|
+
### Buffered Rows
|
40
|
+
|
41
|
+
All rows will first be fetched and buffered into a result object. Probably shouldn't use
|
42
|
+
this for large result sets.
|
43
|
+
|
44
|
+
result = vertica.query("SELECT id, name FROM my_table")
|
45
|
+
result.each_row |row|
|
46
|
+
puts row # => {:id => 123, :name => "Jim Bob"}
|
47
|
+
end
|
48
|
+
|
49
|
+
result.rows # => [{:id => 123, :name => "Jim Bob"}, {:id => 456, :name => "Joe Jack"}]
|
50
|
+
result.row_count # => 2
|
51
|
+
|
52
|
+
vertica.close
|
53
|
+
|
54
|
+
### Unbuffered Rows
|
55
|
+
|
56
|
+
The vertica gem will not buffer incoming results. The gem will read a result off the
|
57
|
+
socket and pass it to the provided block.
|
58
|
+
|
59
|
+
vertica.query("SELECT id, name FROM my_table") do |row|
|
60
|
+
puts row # => {:id => 123, :name => "Jim Bob"}
|
61
|
+
end
|
62
|
+
vertica.close
|
63
|
+
|
64
|
+
### Example Prepared Statement
|
65
|
+
|
66
|
+
This is flaky at best right now and needs some work. This will probably fail and destroy
|
67
|
+
your connection. You'll need to throw the connection away and start over.
|
68
|
+
|
69
|
+
vertica.prepare("my_prepared_statement", "SELECT * FROM my_table WHERE id = ?", 1)
|
70
|
+
result = vertica.execute_prepared("my_prepared_statement", 13)
|
71
|
+
result.each_rows |row|
|
72
|
+
puts row # => {:id => 123, :name => "Jim Bob"}
|
73
|
+
end
|
74
|
+
result.rows # => [{:id => 123, :name => "Jim Bob"}, {:id => 456, :name => "Joe Jack"}]
|
75
|
+
vertica.close
|
76
|
+
|
77
|
+
# TODO
|
78
|
+
|
79
|
+
* Tests.
|
80
|
+
* Lots of tests.
|
81
|
+
|
82
|
+
# Authors
|
83
|
+
|
84
|
+
* [Matt Bauer](http://github.com/mattbauer) all the hard work
|
85
|
+
* [Jeff Smick](http://github.com/sprsquish) current maintainer
|
data/Rakefile
CHANGED
@@ -1,44 +1,62 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'rake
|
3
|
-
require 'rake/rdoctask'
|
4
|
-
require 'rake/testtask'
|
5
|
-
|
6
|
-
load 'vertica.gemspec'
|
7
|
-
|
8
|
-
Rake::GemPackageTask.new(VERTICA_SPEC) do |pkg|
|
9
|
-
pkg.need_tar = true
|
10
|
-
end
|
11
|
-
|
12
|
-
task :default => "test"
|
2
|
+
require 'rake'
|
13
3
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
Rake::RDocTask.new do |rdoc|
|
31
|
-
files = ["README", "lib/**/*.rb"]
|
32
|
-
rdoc.rdoc_files.add(files)
|
33
|
-
rdoc.main = "README.textile"
|
34
|
-
rdoc.title = "Vertica Docs"
|
35
|
-
rdoc.rdoc_dir = "doc"
|
36
|
-
rdoc.options << "--line-numbers" << "--inline-source"
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = 'vertica'
|
8
|
+
gem.summary = 'Pure ruby library for interacting with Vertica'
|
9
|
+
gem.description = 'Query Vertica with ruby'
|
10
|
+
|
11
|
+
gem.email = 'sprsquish@gmail.com'
|
12
|
+
gem.homepage = 'http://github.com/sprsquish/vertica'
|
13
|
+
gem.authors = ['Jeff Smick', 'Matt Bauer']
|
14
|
+
|
15
|
+
gem.files = FileList["[A-Z]*", 'lib/**/*.rb'].to_a
|
16
|
+
|
17
|
+
gem.test_files = FileList['test/**/*.rb']
|
18
|
+
|
19
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
37
20
|
end
|
21
|
+
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
38
25
|
end
|
26
|
+
#
|
27
|
+
# require 'rake/testtask'
|
28
|
+
# Rake::TestTask.new(:test) do |test|
|
29
|
+
# test.libs << 'lib' << 'spec'
|
30
|
+
# test.pattern = 'spec/**/*_spec.rb'
|
31
|
+
# test.verbose = true
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# begin
|
35
|
+
# require 'rcov/rcovtask'
|
36
|
+
# Rcov::RcovTask.new do |test|
|
37
|
+
# test.libs << 'spec'
|
38
|
+
# test.pattern = 'spec/**/*_spec.rb'
|
39
|
+
# test.rcov_opts += ['--exclude \/Library\/Ruby,spec\/', '--xrefs']
|
40
|
+
# test.verbose = true
|
41
|
+
# end
|
42
|
+
# rescue LoadError
|
43
|
+
# task :rcov do
|
44
|
+
# abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
49
|
+
begin
|
50
|
+
require 'yard'
|
51
|
+
YARD::Rake::YardocTask.new do |t|
|
52
|
+
t.options = ['--no-private', '-m', 'markdown', '-o', './doc']
|
53
|
+
end
|
54
|
+
rescue LoadError
|
55
|
+
task :yardoc do
|
56
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
57
|
+
end
|
44
58
|
end
|
59
|
+
|
60
|
+
desc 'Generate documentation'
|
61
|
+
task :doc => :yard
|
62
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.1
|
data/lib/vertica.rb
CHANGED
@@ -1,19 +1,67 @@
|
|
1
1
|
module Vertica
|
2
|
-
|
3
2
|
class Error < StandardError
|
4
|
-
|
5
3
|
class ConnectionError < Error; end
|
6
|
-
|
7
4
|
class MessageError < Error; end
|
8
|
-
|
9
5
|
end
|
10
|
-
|
6
|
+
|
11
7
|
PROTOCOL_VERSION = 3 << 16
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION])).strip
|
9
|
+
|
10
|
+
def self.connect(*args)
|
11
|
+
Connection.new(*args)
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
%w[
|
16
|
+
socket
|
17
|
+
uri
|
18
|
+
openssl/ssl
|
19
|
+
bigdecimal
|
20
|
+
bigdecimal/util
|
21
|
+
date
|
22
|
+
|
23
|
+
vertica/core_ext/numeric
|
24
|
+
vertica/core_ext/string
|
25
|
+
|
26
|
+
vertica/bit_helper
|
27
|
+
vertica/vertica_socket
|
28
|
+
|
29
|
+
vertica/column
|
30
|
+
vertica/result
|
31
|
+
vertica/connection
|
32
|
+
|
33
|
+
vertica/messages/message
|
34
|
+
|
35
|
+
vertica/messages/backend_messages/authentication
|
36
|
+
vertica/messages/backend_messages/backend_key_data
|
37
|
+
vertica/messages/backend_messages/bind_complete
|
38
|
+
vertica/messages/backend_messages/close_complete
|
39
|
+
vertica/messages/backend_messages/command_complete
|
40
|
+
vertica/messages/backend_messages/data_row
|
41
|
+
vertica/messages/backend_messages/empty_query_response
|
42
|
+
vertica/messages/backend_messages/error_response
|
43
|
+
vertica/messages/backend_messages/no_data
|
44
|
+
vertica/messages/backend_messages/notice_response
|
45
|
+
vertica/messages/backend_messages/notification_response
|
46
|
+
vertica/messages/backend_messages/parameter_description
|
47
|
+
vertica/messages/backend_messages/parameter_status
|
48
|
+
vertica/messages/backend_messages/parse_complete
|
49
|
+
vertica/messages/backend_messages/portal_suspended
|
50
|
+
vertica/messages/backend_messages/ready_for_query
|
51
|
+
vertica/messages/backend_messages/row_description
|
52
|
+
vertica/messages/backend_messages/unknown
|
53
|
+
|
54
|
+
vertica/messages/frontend_messages/bind
|
55
|
+
vertica/messages/frontend_messages/cancel_request
|
56
|
+
vertica/messages/frontend_messages/close
|
57
|
+
vertica/messages/frontend_messages/describe
|
58
|
+
vertica/messages/frontend_messages/execute
|
59
|
+
vertica/messages/frontend_messages/flush
|
60
|
+
vertica/messages/frontend_messages/parse
|
61
|
+
vertica/messages/frontend_messages/password
|
62
|
+
vertica/messages/frontend_messages/query
|
63
|
+
vertica/messages/frontend_messages/ssl_request
|
64
|
+
vertica/messages/frontend_messages/startup
|
65
|
+
vertica/messages/frontend_messages/sync
|
66
|
+
vertica/messages/frontend_messages/terminate
|
67
|
+
].each { |r| require r }
|
data/lib/vertica/bit_helper.rb
CHANGED
@@ -6,44 +6,27 @@ module Vertica
|
|
6
6
|
raise "couldn't read #{n} characters" if s.nil? or s.size != n # TODO make into a Vertica Exception
|
7
7
|
s
|
8
8
|
end
|
9
|
-
|
10
|
-
def write_byte(value)
|
11
|
-
write [value].pack('C')
|
12
|
-
end
|
13
|
-
|
9
|
+
|
14
10
|
def read_byte
|
15
|
-
readn(1).
|
11
|
+
readn(1).to_byte
|
16
12
|
end
|
17
13
|
|
18
|
-
def write_network_int16(value)
|
19
|
-
write [value].pack('n')
|
20
|
-
end
|
21
|
-
|
22
14
|
def read_network_int16
|
23
|
-
readn(2).
|
24
|
-
end
|
25
|
-
|
26
|
-
def write_network_int32(value)
|
27
|
-
write [value].pack('N')
|
28
|
-
end
|
29
|
-
|
30
|
-
def read_network_int32
|
31
|
-
handle_endian_flavor(readn(4)).unpack('l').first
|
15
|
+
readn(2).to_network_int16
|
32
16
|
end
|
33
17
|
|
34
|
-
def
|
35
|
-
|
36
|
-
write "#{value}\000"
|
18
|
+
def read_network_int32
|
19
|
+
handle_endian_flavor(readn(4)).to_network_int32
|
37
20
|
end
|
38
21
|
|
39
22
|
def read_cstring
|
40
|
-
readline("\000")
|
23
|
+
readline("\000").from_cstring
|
41
24
|
end
|
42
25
|
|
43
26
|
def handle_endian_flavor(s)
|
44
27
|
little_endian? ? s.reverse : s
|
45
28
|
end
|
46
|
-
|
29
|
+
|
47
30
|
def little_endian?
|
48
31
|
@little_endian ||= ([0x12345678].pack("L") == "\x12\x34\x56\x78" ? false : true)
|
49
32
|
end
|
data/lib/vertica/column.rb
CHANGED
@@ -6,63 +6,44 @@ module Vertica
|
|
6
6
|
attr_reader :size
|
7
7
|
attr_reader :data_type
|
8
8
|
|
9
|
-
|
10
|
-
:unspecified,
|
11
|
-
:tuple,
|
12
|
-
:pos,
|
13
|
-
:record,
|
14
|
-
:unknown,
|
15
|
-
:bool,
|
16
|
-
:in,
|
17
|
-
:float,
|
18
|
-
:char,
|
19
|
-
:varchar,
|
20
|
-
:date,
|
21
|
-
:time,
|
22
|
-
:timestamp,
|
23
|
-
:timestamp_tz,
|
24
|
-
:interval,
|
25
|
-
:time_tz,
|
26
|
-
:
|
27
|
-
:bytea,
|
28
|
-
:rle_tuple
|
9
|
+
DATA_TYPE_CONVERSIONS = [
|
10
|
+
[:unspecified, nil],
|
11
|
+
[:tuple, nil],
|
12
|
+
[:pos, nil],
|
13
|
+
[:record, nil],
|
14
|
+
[:unknown, nil],
|
15
|
+
[:bool, lambda { |s| s == 't' }],
|
16
|
+
[:in, lambda { |s| s.to_i }],
|
17
|
+
[:float, lambda { |s| s.to_f }],
|
18
|
+
[:char, nil],
|
19
|
+
[:varchar, nil],
|
20
|
+
[:date, lambda { |s| Date.new(*s.split("-").map{|x| x.to_i}) }],
|
21
|
+
[:time, lambda { |s| Time.parse(s) }],
|
22
|
+
[:timestamp, lambda { |s| DateTime.parse(s, true) }],
|
23
|
+
[:timestamp_tz, lambda { |s| DateTime.parse(s, true) }],
|
24
|
+
[:interval, nil],
|
25
|
+
[:time_tz, lambda { |s| Time.parse(s) }],
|
26
|
+
[:numeric, lambda { |s| s.to_d }],
|
27
|
+
[:bytea, nil],
|
28
|
+
[:rle_tuple, nil]
|
29
29
|
]
|
30
|
-
|
31
|
-
DATA_TYPE_CONVERSIONS = {
|
32
|
-
:unspecified => nil,
|
33
|
-
:tuple => nil,
|
34
|
-
:pos => nil,
|
35
|
-
:record => nil,
|
36
|
-
:unknown => nil,
|
37
|
-
:bool => lambda { |s| s == 't' },
|
38
|
-
:in => lambda { |s| s.to_i },
|
39
|
-
:float => lambda { |s| s.to_f },
|
40
|
-
:char => nil,
|
41
|
-
:varchar => nil,
|
42
|
-
:date => lambda { |s| Date.new(*s.split("-").map{|x| x.to_i}) },
|
43
|
-
:time => lambda { |s| Time.parse(s) },
|
44
|
-
:timestamp => lambda { |s| DateTime.parse(s, true) },
|
45
|
-
:timestamp_tz => lambda { |s| DateTime.parse(s, true) },
|
46
|
-
:interval => nil,
|
47
|
-
:time_tz => lambda { |s| Time.parse(s) },
|
48
|
-
:numberic => lambda { |s| s.to_d },
|
49
|
-
:bytea => nil,
|
50
|
-
:rle_tuple => nil
|
51
|
-
}
|
52
30
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@
|
57
|
-
@
|
58
|
-
@
|
59
|
-
@
|
60
|
-
@
|
31
|
+
DATA_TYPES = DATA_TYPE_CONVERSIONS.map { |t| t[0] }
|
32
|
+
|
33
|
+
def initialize(col)
|
34
|
+
@type_modifier = col[:type_modifier]
|
35
|
+
@format = col[:format_code] == 0 ? :text : :binary
|
36
|
+
@table_oid = col[:table_oid]
|
37
|
+
@name = col[:name].to_sym
|
38
|
+
@attribute_number = col[:attribute_number]
|
39
|
+
@data_type = DATA_TYPE_CONVERSIONS[col[:data_type_oid]][0]
|
40
|
+
@converter = DATA_TYPE_CONVERSIONS[col[:data_type_oid]][1]
|
41
|
+
@size = col[:data_type_size]
|
61
42
|
end
|
62
|
-
|
43
|
+
|
63
44
|
def convert(s)
|
64
|
-
|
65
|
-
|
45
|
+
return unless s
|
46
|
+
@converter ? @converter.call(s) : s
|
66
47
|
end
|
67
48
|
end
|
68
49
|
end
|
data/lib/vertica/connection.rb
CHANGED
@@ -1,45 +1,78 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'stringio'
|
3
|
-
require 'vertica/vertica_socket'
|
4
|
-
require 'vertica/messages/message'
|
5
|
-
require 'openssl/ssl'
|
6
|
-
|
7
1
|
module Vertica
|
8
|
-
|
2
|
+
|
9
3
|
class Connection
|
10
|
-
|
4
|
+
|
5
|
+
STATUSES = {
|
6
|
+
?I => :no_transaction,
|
7
|
+
?T => :in_transaction,
|
8
|
+
?E => :failed_transaction
|
9
|
+
}
|
10
|
+
|
11
|
+
def self.cancel(existing_conn)
|
12
|
+
conn = self.new(existing_conn.options.merge(:skip_startup => true))
|
13
|
+
conn.write Messages::CancelRequest.new(existing_conn.backend_pid, existing_conn.backend_key)
|
14
|
+
conn.write Messages::Flush.new
|
15
|
+
conn.connection.close
|
16
|
+
end
|
17
|
+
|
11
18
|
def initialize(options = {})
|
12
19
|
reset_values
|
13
20
|
|
14
21
|
@options = options
|
15
|
-
|
16
|
-
|
22
|
+
|
17
23
|
unless options[:skip_startup]
|
18
|
-
Messages::Startup.new(@options[:user], @options[:database]).to_bytes
|
24
|
+
connection.write Messages::Startup.new(@options[:user], @options[:database]).to_bytes
|
19
25
|
process
|
20
26
|
end
|
21
27
|
end
|
22
|
-
|
28
|
+
|
29
|
+
def connection
|
30
|
+
@connection ||= begin
|
31
|
+
conn = VerticaSocket.new(@options[:host], @options[:port].to_s)
|
32
|
+
if @options[:ssl]
|
33
|
+
conn.write Messages::SslRequest.new.to_bytes
|
34
|
+
if conn.read_byte == ?S
|
35
|
+
conn = OpenSSL::SSL::SSLSocket.new(conn, OpenSSL::SSL::SSLContext.new)
|
36
|
+
conn.sync = true
|
37
|
+
conn.connect
|
38
|
+
else
|
39
|
+
raise Error::ConnectionError.new("SSL requested but server doesn't support it.")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
conn
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def opened?
|
47
|
+
@connection && @backend_pid && @transaction_status
|
48
|
+
end
|
49
|
+
|
50
|
+
def closed?
|
51
|
+
!opened?
|
52
|
+
end
|
53
|
+
|
54
|
+
def write(message)
|
55
|
+
connection.write_message message
|
56
|
+
end
|
57
|
+
|
23
58
|
def close
|
24
|
-
|
25
|
-
|
26
|
-
@
|
27
|
-
rescue Errno::ENOTCONN
|
28
|
-
# the backend closed the connection already
|
59
|
+
write Messages::Terminate.new
|
60
|
+
connection.shutdown
|
61
|
+
@connection = nil
|
62
|
+
rescue Errno::ENOTCONN # the backend closed the connection already
|
29
63
|
ensure
|
30
64
|
reset_values
|
31
65
|
end
|
32
|
-
|
66
|
+
|
33
67
|
def reset
|
34
68
|
close if opened?
|
35
69
|
reset_values
|
36
|
-
establish_connection
|
37
70
|
end
|
38
71
|
|
39
72
|
def options
|
40
73
|
@options.dup
|
41
74
|
end
|
42
|
-
|
75
|
+
|
43
76
|
def transaction_status
|
44
77
|
@transaction_status
|
45
78
|
end
|
@@ -47,7 +80,7 @@ module Vertica
|
|
47
80
|
def backend_pid
|
48
81
|
@backend_pid
|
49
82
|
end
|
50
|
-
|
83
|
+
|
51
84
|
def backend_key
|
52
85
|
@backend_key
|
53
86
|
end
|
@@ -55,7 +88,7 @@ module Vertica
|
|
55
88
|
def notifications
|
56
89
|
@notifications
|
57
90
|
end
|
58
|
-
|
91
|
+
|
59
92
|
def parameters
|
60
93
|
@parameters.dup
|
61
94
|
end
|
@@ -63,150 +96,117 @@ module Vertica
|
|
63
96
|
def put_copy_data; raise NotImplementedError.new; end
|
64
97
|
def put_copy_end; raise NotImplementedError.new; end
|
65
98
|
def get_copy_data; raise NotImplementedError.new; end
|
66
|
-
|
67
|
-
def
|
68
|
-
@conn && @backend_pid && @transaction_status
|
69
|
-
end
|
70
|
-
|
71
|
-
def closed?
|
72
|
-
!opened?
|
73
|
-
end
|
74
|
-
|
75
|
-
def query(query_string)
|
99
|
+
|
100
|
+
def query(query_string, &block)
|
76
101
|
raise ArgumentError.new("Query string cannot be blank or empty.") if query_string.nil? || query_string.empty?
|
77
|
-
raise_if_not_open
|
78
102
|
reset_result
|
79
|
-
|
80
|
-
|
81
|
-
process(true)
|
103
|
+
write Messages::Query.new(query_string)
|
104
|
+
@process_row = block
|
105
|
+
result = process(true)
|
106
|
+
result unless @process_row
|
82
107
|
end
|
83
|
-
|
108
|
+
|
84
109
|
def prepare(name, query, params_count = 0)
|
85
|
-
raise_if_not_open
|
86
|
-
|
87
110
|
param_types = Array.new(params_count).fill(0)
|
88
|
-
|
89
|
-
Messages::Parse.new(name, query, param_types)
|
90
|
-
Messages::Describe.new(:prepared_statement, name)
|
91
|
-
Messages::Sync.new
|
92
|
-
Messages::Flush.new
|
93
|
-
|
111
|
+
|
112
|
+
write Messages::Parse.new(name, query, param_types)
|
113
|
+
write Messages::Describe.new(:prepared_statement, name)
|
114
|
+
write Messages::Sync.new
|
115
|
+
write Messages::Flush.new
|
116
|
+
|
94
117
|
process
|
95
118
|
end
|
96
|
-
|
119
|
+
|
97
120
|
def execute_prepared(name, *param_values)
|
98
|
-
raise_if_not_open
|
99
|
-
|
100
121
|
portal_name = "" # use the unnamed portal
|
101
122
|
max_rows = 0 # return all rows
|
102
|
-
|
123
|
+
|
103
124
|
reset_result
|
104
|
-
|
105
|
-
Messages::Bind.new(portal_name, name, param_values)
|
106
|
-
Messages::Execute.new(portal_name, max_rows)
|
107
|
-
Messages::Sync.new
|
108
|
-
|
125
|
+
|
126
|
+
write Messages::Bind.new(portal_name, name, param_values)
|
127
|
+
write Messages::Execute.new(portal_name, max_rows)
|
128
|
+
write Messages::Sync.new
|
129
|
+
|
109
130
|
result = process(true)
|
110
131
|
|
111
132
|
# Close the portal
|
112
|
-
Messages::Close.new(:portal, portal_name)
|
113
|
-
Messages::Flush.new
|
114
|
-
|
133
|
+
write Messages::Close.new(:portal, portal_name)
|
134
|
+
write Messages::Flush.new
|
135
|
+
|
115
136
|
process
|
116
|
-
|
137
|
+
|
117
138
|
# Return the result from the prepared statement
|
118
139
|
result
|
119
140
|
end
|
120
141
|
|
121
|
-
def self.cancel(existing_conn)
|
122
|
-
conn = new(existing_conn.options.merge(:skip_startup => true))
|
123
|
-
Messages::CancelRequest.new(existing_conn.backend_pid, existing_conn.backend_key).to_bytes(conn.send(:conn))
|
124
|
-
Messages::Flush.new.to_bytes(conn.send(:conn))
|
125
|
-
conn.close
|
126
|
-
end
|
127
|
-
|
128
142
|
protected
|
129
|
-
|
130
|
-
def establish_connection
|
131
|
-
@conn = VerticaSocket.new(@options[:host], @options[:port].to_s)
|
132
|
-
|
133
|
-
if @options[:ssl]
|
134
|
-
Messages::SslRequest.new.to_bytes(@conn)
|
135
|
-
if @conn.read_byte == ?S
|
136
|
-
@conn = OpenSSL::SSL::SSLSocket.new(@conn, OpenSSL::SSL::SSLContext.new)
|
137
|
-
@conn.sync = true
|
138
|
-
@conn.connect
|
139
|
-
else
|
140
|
-
raise Error::ConnectionError.new("SSL requested but server doesn't support it.")
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
143
|
+
|
145
144
|
def process(return_result = false)
|
145
|
+
result = return_result ? Result.new : nil
|
146
146
|
loop do
|
147
|
-
message =
|
148
|
-
|
149
|
-
case message
|
147
|
+
case message = connection.read_message
|
150
148
|
when Messages::Authentication
|
151
149
|
if message.code != Messages::Authentication::OK
|
152
|
-
Messages::Password.new(@options[:password], message.code, {:user => @options[:user], :salt => message.salt})
|
150
|
+
write Messages::Password.new(@options[:password], message.code, {:user => @options[:user], :salt => message.salt})
|
153
151
|
end
|
152
|
+
|
154
153
|
when Messages::BackendKeyData
|
155
154
|
@backend_pid = message.pid
|
156
155
|
@backend_key = message.key
|
157
|
-
|
158
|
-
:nothing
|
159
|
-
when Messages::CloseComplete
|
160
|
-
break
|
161
|
-
when Messages::CommandComplete
|
162
|
-
break
|
163
|
-
# when Messages::CopyData
|
164
|
-
# # nothing
|
165
|
-
# when Messages::CopyDone
|
166
|
-
# # nothing
|
167
|
-
# when Messages::CopyInResponse
|
168
|
-
# raise 'not done'
|
169
|
-
# when Messages::CopyOutResponse
|
170
|
-
# raise 'not done'
|
156
|
+
|
171
157
|
when Messages::DataRow
|
172
|
-
@
|
173
|
-
|
174
|
-
|
158
|
+
@process_row.call(result.format_row(message)) if @process_row && result
|
159
|
+
result.add_row(message) if result && !@process_row
|
160
|
+
|
175
161
|
when Messages::ErrorResponse
|
176
162
|
raise Error::MessageError.new(message.error)
|
177
|
-
|
178
|
-
:nothing
|
163
|
+
|
179
164
|
when Messages::NoticeResponse
|
180
165
|
message.notices.each do |notice|
|
181
166
|
@notices << Notice.new(notice[0], notice[1])
|
182
167
|
end
|
168
|
+
|
183
169
|
when Messages::NotificationResponse
|
184
|
-
@notifications << Notification.new(message.pid, message.condition, message.additional_info)
|
185
|
-
|
186
|
-
:nothing
|
170
|
+
@notifications << Notification.new(message.pid, message.condition, message.additional_info)
|
171
|
+
|
187
172
|
when Messages::ParameterStatus
|
188
173
|
@parameters[message.name] = message.value
|
189
|
-
|
190
|
-
break
|
191
|
-
when Messages::PortalSuspended
|
192
|
-
break
|
174
|
+
|
193
175
|
when Messages::ReadyForQuery
|
194
|
-
@transaction_status =
|
176
|
+
@transaction_status = STATUSES[message.transaction_status]
|
195
177
|
break unless return_result
|
178
|
+
|
196
179
|
when Messages::RowDescription
|
197
|
-
|
180
|
+
result.descriptions = message if result
|
181
|
+
|
198
182
|
when Messages::Unknown
|
199
183
|
raise Error::MessageError.new("Unknown message type: #{message.message_id}")
|
184
|
+
|
185
|
+
when Messages::BindComplete,
|
186
|
+
Messages::NoData,
|
187
|
+
Messages::EmptyQueryResponse,
|
188
|
+
Messages::ParameterDescription
|
189
|
+
:nothing
|
190
|
+
|
191
|
+
when Messages::CloseComplete,
|
192
|
+
Messages::CommandComplete,
|
193
|
+
Messages::ParseComplete,
|
194
|
+
Messages::PortalSuspended
|
195
|
+
break
|
196
|
+
# when Messages::CopyData
|
197
|
+
# # nothing
|
198
|
+
# when Messages::CopyDone
|
199
|
+
# # nothing
|
200
|
+
# when Messages::CopyInResponse
|
201
|
+
# raise 'not done'
|
202
|
+
# when Messages::CopyOutResponse
|
203
|
+
# raise 'not done'
|
200
204
|
end
|
201
205
|
end
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
def raise_if_not_open
|
207
|
-
raise ConnectionError.new("connection doesn't exist or is already closed") if @conn.nil?
|
206
|
+
|
207
|
+
result
|
208
208
|
end
|
209
|
-
|
209
|
+
|
210
210
|
def reset_values
|
211
211
|
reset_notifications
|
212
212
|
reset_result
|
@@ -214,9 +214,10 @@ module Vertica
|
|
214
214
|
@backend_pid = nil
|
215
215
|
@backend_key = nil
|
216
216
|
@transaction_status = nil
|
217
|
-
@
|
217
|
+
@connection = nil
|
218
|
+
@process_row = nil
|
218
219
|
end
|
219
|
-
|
220
|
+
|
220
221
|
def reset_notifications
|
221
222
|
@notifications = []
|
222
223
|
end
|
@@ -224,23 +225,6 @@ module Vertica
|
|
224
225
|
def reset_result
|
225
226
|
@field_descriptions = []
|
226
227
|
@field_values = []
|
227
|
-
end
|
228
|
-
|
229
|
-
def convert_transaction_status_to_sym(status)
|
230
|
-
case status
|
231
|
-
when ?I
|
232
|
-
:no_transaction
|
233
|
-
when ?T
|
234
|
-
:in_transaction
|
235
|
-
when ?E
|
236
|
-
:failed_transaction
|
237
|
-
else
|
238
|
-
nil
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def conn
|
243
|
-
@conn
|
244
228
|
end
|
245
229
|
|
246
230
|
end
|