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