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.
Files changed (63) hide show
  1. data/README.md +85 -0
  2. data/Rakefile +56 -38
  3. data/VERSION +1 -0
  4. data/lib/vertica.rb +59 -11
  5. data/lib/vertica/bit_helper.rb +7 -24
  6. data/lib/vertica/column.rb +34 -53
  7. data/lib/vertica/connection.rb +123 -139
  8. data/lib/vertica/core_ext/numeric.rb +13 -0
  9. data/lib/vertica/core_ext/string.rb +22 -0
  10. data/lib/vertica/messages/{authentication.rb → backend_messages/authentication.rb} +6 -9
  11. data/lib/vertica/messages/{backend_key_data.rb → backend_messages/backend_key_data.rb} +2 -2
  12. data/lib/vertica/messages/{bind_complete.rb → backend_messages/bind_complete.rb} +0 -1
  13. data/lib/vertica/messages/{close_complete.rb → backend_messages/close_complete.rb} +0 -1
  14. data/lib/vertica/messages/{command_complete.rb → backend_messages/command_complete.rb} +3 -3
  15. data/lib/vertica/messages/{data_row.rb → backend_messages/data_row.rb} +3 -6
  16. data/lib/vertica/messages/{empty_query_response.rb → backend_messages/empty_query_response.rb} +0 -1
  17. data/lib/vertica/messages/backend_messages/error_response.rb +35 -0
  18. data/lib/vertica/messages/{no_data.rb → backend_messages/no_data.rb} +0 -1
  19. data/lib/vertica/messages/backend_messages/notice_response.rb +16 -0
  20. data/lib/vertica/messages/{notification_response.rb → backend_messages/notification_response.rb} +0 -0
  21. data/lib/vertica/messages/{parameter_description.rb → backend_messages/parameter_description.rb} +0 -0
  22. data/lib/vertica/messages/{parameter_status.rb → backend_messages/parameter_status.rb} +0 -0
  23. data/lib/vertica/messages/{parse_complete.rb → backend_messages/parse_complete.rb} +0 -1
  24. data/lib/vertica/messages/{portal_suspended.rb → backend_messages/portal_suspended.rb} +0 -1
  25. data/lib/vertica/messages/{ready_for_query.rb → backend_messages/ready_for_query.rb} +2 -2
  26. data/lib/vertica/messages/{row_description.rb → backend_messages/row_description.rb} +3 -3
  27. data/lib/vertica/messages/{unknown.rb → backend_messages/unknown.rb} +2 -2
  28. data/lib/vertica/messages/frontend_messages/bind.rb +28 -0
  29. data/lib/vertica/messages/frontend_messages/cancel_request.rb +21 -0
  30. data/lib/vertica/messages/frontend_messages/close.rb +24 -0
  31. data/lib/vertica/messages/frontend_messages/describe.rb +24 -0
  32. data/lib/vertica/messages/frontend_messages/execute.rb +20 -0
  33. data/lib/vertica/messages/frontend_messages/flush.rb +7 -0
  34. data/lib/vertica/messages/frontend_messages/parse.rb +23 -0
  35. data/lib/vertica/messages/frontend_messages/password.rb +35 -0
  36. data/lib/vertica/messages/frontend_messages/query.rb +17 -0
  37. data/lib/vertica/messages/frontend_messages/ssl_request.rb +12 -0
  38. data/lib/vertica/messages/frontend_messages/startup.rb +25 -0
  39. data/lib/vertica/messages/frontend_messages/sync.rb +7 -0
  40. data/lib/vertica/messages/frontend_messages/terminate.rb +7 -0
  41. data/lib/vertica/messages/message.rb +26 -57
  42. data/lib/vertica/result.rb +28 -20
  43. data/lib/vertica/vertica_socket.rb +14 -3
  44. data/test/test_helper.rb +7 -16
  45. metadata +55 -50
  46. data/README.textile +0 -69
  47. data/lib/vertica/messages/bind.rb +0 -36
  48. data/lib/vertica/messages/cancel_request.rb +0 -25
  49. data/lib/vertica/messages/close.rb +0 -30
  50. data/lib/vertica/messages/describe.rb +0 -30
  51. data/lib/vertica/messages/error_response.rb +0 -59
  52. data/lib/vertica/messages/execute.rb +0 -24
  53. data/lib/vertica/messages/flush.rb +0 -15
  54. data/lib/vertica/messages/notice_response.rb +0 -21
  55. data/lib/vertica/messages/parse.rb +0 -31
  56. data/lib/vertica/messages/password.rb +0 -33
  57. data/lib/vertica/messages/query.rb +0 -20
  58. data/lib/vertica/messages/ssl_request.rb +0 -14
  59. data/lib/vertica/messages/startup.rb +0 -38
  60. data/lib/vertica/messages/sync.rb +0 -15
  61. data/lib/vertica/messages/terminate.rb +0 -14
  62. data/test/create_schema.sql +0 -4
  63. 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/gempackagetask'
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
- desc "Clean"
15
- task :clean do
16
- include FileUtils
17
- rm_rf 'pkg'
18
- end
19
-
20
- desc "Run tests"
21
- Rake::TestTask.new("test") do |t|
22
- t.libs << ["test", "ext"]
23
- t.pattern = 'test/*_test.rb'
24
- t.verbose = true
25
- t.warning = true
26
- end
27
-
28
- task :doc => [:rdoc]
29
- namespace :doc do
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
- desc "Run rcov on current app"
41
- task :rcov do
42
- system "rm -rf coverage && rcov -o coverage -x rcov.rb test/*_test.rb"
43
- system("open coverage/index.html") if PLATFORM['darwin']
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
- VERSION = "0.7.3"
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
- require 'vertica/column'
18
- require 'vertica/result'
19
- require 'vertica/connection'
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 }
@@ -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).unpack('C').first
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).unpack('n').first
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 write_cstring(value)
35
- raise ArgumentError, "Invalid cstring" if value.include?("\000")
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")[0..-2]
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
@@ -6,63 +6,44 @@ module Vertica
6
6
  attr_reader :size
7
7
  attr_reader :data_type
8
8
 
9
- DATA_TYPES = [
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
- :numberic,
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
- def initialize(type_modifier, format_code, table_oid, name, attribute_number, data_type_oid, size)
54
- @type_modifier = type_modifier
55
- @format = (format_code == 0 ? :text : :binary)
56
- @table_oid = table_oid
57
- @name = name
58
- @attribute_number = attribute_number
59
- @data_type = DATA_TYPES[data_type_oid]
60
- @size = size
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
- l = DATA_TYPE_CONVERSIONS[@data_type]
65
- l ? l.call(s) : s
45
+ return unless s
46
+ @converter ? @converter.call(s) : s
66
47
  end
67
48
  end
68
49
  end
@@ -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
- establish_connection
16
-
22
+
17
23
  unless options[:skip_startup]
18
- Messages::Startup.new(@options[:user], @options[:database]).to_bytes(@conn)
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
- raise_if_not_open
25
- Messages::Terminate.new.to_bytes(@conn)
26
- @conn.shutdown
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 opened?
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
- Messages::Query.new(query_string).to_bytes(@conn)
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).to_bytes(@conn)
90
- Messages::Describe.new(:prepared_statement, name).to_bytes(@conn)
91
- Messages::Sync.new.to_bytes(@conn)
92
- Messages::Flush.new.to_bytes(@conn)
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).to_bytes(@conn)
106
- Messages::Execute.new(portal_name, max_rows).to_bytes(@conn)
107
- Messages::Sync.new.to_bytes(@conn)
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).to_bytes(@conn)
113
- Messages::Flush.new.to_bytes(@conn)
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 = Messages::BackendMessage.read(@conn)
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}).to_bytes(@conn)
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
- when Messages::BindComplete
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
- @field_values << message.fields
173
- when Messages::EmptyQueryResponse
174
- break
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
- when Messages::NoData
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
- when Messages::ParameterDescription
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
- when Messages::ParseComplete
190
- break
191
- when Messages::PortalSuspended
192
- break
174
+
193
175
  when Messages::ReadyForQuery
194
- @transaction_status = convert_transaction_status_to_sym(message.transaction_status)
176
+ @transaction_status = STATUSES[message.transaction_status]
195
177
  break unless return_result
178
+
196
179
  when Messages::RowDescription
197
- @field_descriptions = message.fields
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
- return_result ? Result.new(@field_descriptions, @field_values) : nil
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
- @conn = nil
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