vertica 0.7.4 → 0.8.1

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