vertica 0.12.0 → 1.0.0.rc1
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.
- checksums.yaml +4 -4
- data/README.md +18 -20
- data/lib/vertica.rb +15 -8
- data/lib/vertica/column.rb +32 -13
- data/lib/vertica/connection.rb +143 -119
- data/lib/vertica/{messages/backend_messages → protocol/backend}/authentication.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/backend_key_data.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/bind_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/close_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/command_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/copy_in_response.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/data_row.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/empty_query_response.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/error_response.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/no_data.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/notice_response.rb +6 -6
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parameter_description.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parameter_status.rb +3 -3
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parse_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/portal_suspended.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/ready_for_query.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/row_description.rb +9 -9
- data/lib/vertica/{messages/backend_messages → protocol/backend}/unknown.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/bind.rb +2 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/cancel_request.rb +3 -4
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/close.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_data.rb +6 -6
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_done.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_fail.rb +5 -5
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/describe.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/execute.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/flush.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/parse.rb +3 -3
- data/lib/vertica/protocol/frontend/password.rb +32 -0
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/query.rb +3 -4
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/ssl_request.rb +2 -2
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/startup.rb +2 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/sync.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/terminate.rb +1 -1
- data/lib/vertica/protocol/message.rb +86 -0
- data/lib/vertica/query.rb +63 -44
- data/lib/vertica/result.rb +25 -47
- data/lib/vertica/row.rb +44 -0
- data/lib/vertica/row_description.rb +102 -0
- data/lib/vertica/version.rb +1 -1
- data/test/connection.yml.example +8 -8
- data/test/functional/functional_connection_test.rb +178 -0
- data/test/functional/{query_test.rb → functional_query_test.rb} +64 -67
- data/test/functional/functional_value_conversion_test.rb +117 -0
- data/test/test_helper.rb +1 -1
- data/test/unit/backend_message_test.rb +57 -57
- data/test/unit/column_test.rb +23 -23
- data/test/unit/frontend_message_test.rb +5 -5
- data/test/unit/quoting_test.rb +16 -5
- data/test/unit/result_test.rb +61 -0
- data/test/unit/row_description_test.rb +56 -0
- data/test/unit/row_test.rb +31 -0
- data/vertica.gemspec +1 -0
- metadata +67 -45
- data/lib/vertica/messages/frontend_messages/password.rb +0 -34
- data/lib/vertica/messages/message.rb +0 -79
- data/test/functional/connection_test.rb +0 -128
- data/test/functional/value_conversion_test.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d40466055bc43ffb3c72810432f2cf6738295399
|
4
|
+
data.tar.gz: c4c4c43a8cf12c22ce7cc3b46eadc68d90931453
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d9941765704d6e4c29efa04d1f7dbdf7f79ca787a6c8786019f8659c47f024f7245673cb7185cadce1ea6035bd8bbd2dfa4f526404ab0c922824309ce427c6b
|
7
|
+
data.tar.gz: aee68c7643bbafd0399cc3c8ff44b0ea13d9490a1ce553f426579ad87a0e28bf4fb0bc21f73f19bc9ebca85755195a4be485099775336b38a49e69127e4dd3a6
|
data/README.md
CHANGED
@@ -36,31 +36,32 @@ Or add it to your Gemfile:
|
|
36
36
|
The <code>Vertica.connect</code> methods takes a connection parameter hash and returns a
|
37
37
|
connection object. For most options, the gem will use a default value if no value is provided.
|
38
38
|
|
39
|
-
connection = Vertica.connect(
|
39
|
+
connection = Vertica.connect(
|
40
40
|
:host => 'db_server',
|
41
|
-
:
|
41
|
+
:username => 'user',
|
42
42
|
:password => 'password',
|
43
43
|
# :ssl => false, # use SSL for the connection
|
44
44
|
# :port => 5433, # default Vertica port: 5433
|
45
45
|
# :database => 'db', # there is only one database
|
46
46
|
# :role => nil, # the (additional) role(s) to enable for the user.
|
47
47
|
# :search_path => nil, # default: <user>,public,v_catalog
|
48
|
-
|
49
|
-
})
|
48
|
+
)
|
50
49
|
|
51
50
|
To close the connection when you're done with it, run <code>connection.close</code>.
|
52
51
|
|
53
52
|
You can pass `OpenSSL::SSL::SSLContext` in `:ssl` to customize SSL connection options.
|
54
53
|
|
55
|
-
###
|
54
|
+
### Running queries
|
56
55
|
|
57
|
-
You can run
|
58
|
-
unbuffered mode. For large result sets, you probably do not want to use buffered results
|
56
|
+
You can run queries using the <code>query</code> method, either in buffered and
|
57
|
+
unbuffered mode. For large result sets, you probably do not want to use buffered results,
|
58
|
+
because buffering the entire result may require a lot of memory.
|
59
59
|
|
60
60
|
Get all the result rows without buffering by providing a block:
|
61
61
|
|
62
62
|
connection.query("SELECT id, name FROM my_table") do |row|
|
63
|
-
puts row
|
63
|
+
puts row['id'] # => 123
|
64
|
+
puts row['name'] # => 'Jim Bob'
|
64
65
|
end
|
65
66
|
|
66
67
|
Note: you can only use the connection for one query at the time. If you try to run another
|
@@ -73,26 +74,23 @@ Store the result of the query method as a variable to get a buffered resultset:
|
|
73
74
|
result = connection.query("SELECT id, name FROM my_table")
|
74
75
|
connection.close
|
75
76
|
|
76
|
-
result.
|
77
|
-
result.row_count # => 2
|
77
|
+
result.size # => 2
|
78
78
|
|
79
79
|
result.each do |row|
|
80
|
-
puts row # =>
|
80
|
+
puts row # => Vertica::Row[123, "Jim Bob"]>
|
81
81
|
end
|
82
82
|
|
83
|
-
|
83
|
+
Rows are provided as `Vertica::Row` instances. You can access the individial fields by
|
84
|
+
referring to their name as String or Symbol, or the index of the field in the result.
|
84
85
|
|
85
|
-
|
86
|
-
|
86
|
+
result.each do |row|
|
87
|
+
puts row # => Vertica::Row[123, "Jim Bob"]>
|
87
88
|
|
88
|
-
|
89
|
-
puts row #
|
89
|
+
puts row['id'], row[:id], row[] # Three times '123'
|
90
|
+
puts row['name'], row[:name], row[1] # Three times 'Jim Bob'
|
90
91
|
end
|
91
92
|
|
92
|
-
|
93
|
-
returned as array.
|
94
|
-
|
95
|
-
### Loading data into Vertica using COPY
|
93
|
+
### Loading data into Vertica using COPY statements
|
96
94
|
|
97
95
|
Using the COPY statement, you can load arbitrary data from your ruby script to the database.
|
98
96
|
|
data/lib/vertica.rb
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'time'
|
2
3
|
require 'bigdecimal'
|
3
4
|
|
4
5
|
# Main module for this library. It contains the {.connect} method to return a
|
5
|
-
# {Vertica::Connection} instance, and methods to quote values ({.quote}) and
|
6
|
+
# {Vertica::Connection} instance, and methods to quote values ({.quote}) and
|
6
7
|
# identifiers ({.quote_identifier}) to safely include those in SQL strings to
|
7
8
|
# prevent SQL injection.
|
8
9
|
module Vertica
|
9
|
-
|
10
|
+
|
10
11
|
# The protocol version (3.0.0) implemented in this library.
|
11
12
|
PROTOCOL_VERSION = 3 << 16
|
12
13
|
|
13
14
|
# Opens a new connection to a Vertica database.
|
14
15
|
# @param (see Vertica::Connection#initialize)
|
15
16
|
# @return [Vertica::Connection] The created connection to Vertica, ready for queries.
|
16
|
-
def self.connect(
|
17
|
-
Vertica::Connection.new(
|
17
|
+
def self.connect(**kwargs)
|
18
|
+
Vertica::Connection.new(**kwargs)
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
# Properly quotes a value for safe usage in SQL queries.
|
21
22
|
#
|
22
23
|
# This method has quoting rules for common types. Any other object will be converted to
|
@@ -29,8 +30,8 @@ module Vertica
|
|
29
30
|
when nil then 'NULL'
|
30
31
|
when false then 'FALSE'
|
31
32
|
when true then 'TRUE'
|
32
|
-
when DateTime then value.strftime("'%Y-%m-%
|
33
|
-
when Time then value.strftime("'%Y-%m-%
|
33
|
+
when DateTime then value.strftime("'%Y-%m-%dT%H:%M:%S.%6N%z'::timestamptz")
|
34
|
+
when Time then value.strftime("'%Y-%m-%dT%H:%M:%S.%6N%z'::timestamptz")
|
34
35
|
when Date then value.strftime("'%Y-%m-%d'::date")
|
35
36
|
when String then "'#{value.gsub(/'/, "''")}'"
|
36
37
|
when BigDecimal then value.to_s('F')
|
@@ -39,7 +40,7 @@ module Vertica
|
|
39
40
|
else self.quote(value.to_s)
|
40
41
|
end
|
41
42
|
end
|
42
|
-
|
43
|
+
|
43
44
|
# Quotes an identifier for safe use within SQL queries, using double quotes.
|
44
45
|
# @param [:to_s] identifier The identifier to quote.
|
45
46
|
# @return [String] The quoted identifier that can be safely included in SQL queries.
|
@@ -51,3 +52,9 @@ end
|
|
51
52
|
require 'vertica/version'
|
52
53
|
require 'vertica/error'
|
53
54
|
require 'vertica/connection'
|
55
|
+
require 'vertica/query'
|
56
|
+
require 'vertica/column'
|
57
|
+
require 'vertica/row_description'
|
58
|
+
require 'vertica/row'
|
59
|
+
require 'vertica/result'
|
60
|
+
require 'vertica/protocol/message'
|
data/lib/vertica/column.rb
CHANGED
@@ -2,9 +2,11 @@ module Vertica
|
|
2
2
|
class Column
|
3
3
|
attr_reader :name
|
4
4
|
attr_reader :table_oid
|
5
|
-
attr_reader :
|
6
|
-
attr_reader :
|
5
|
+
attr_reader :attribute_number
|
6
|
+
attr_reader :format
|
7
7
|
attr_reader :data_type
|
8
|
+
attr_reader :data_type_size
|
9
|
+
attr_reader :data_type_modifier
|
8
10
|
|
9
11
|
STRING_CONVERTER = lambda { |s| s.force_encoding('utf-8') }
|
10
12
|
|
@@ -32,10 +34,10 @@ module Vertica
|
|
32
34
|
7 => [:float, FLOAT_CONVERTER],
|
33
35
|
8 => [:char, STRING_CONVERTER],
|
34
36
|
9 => [:varchar, STRING_CONVERTER],
|
35
|
-
10 => [:date, lambda { |s| Date.
|
37
|
+
10 => [:date, lambda { |s| Date.parse(s) }],
|
36
38
|
11 => [:time, nil],
|
37
|
-
12 => [:timestamp, lambda { |s|
|
38
|
-
13 => [:timestamp_tz, lambda { |s|
|
39
|
+
12 => [:timestamp, lambda { |s| Time.parse(s) }],
|
40
|
+
13 => [:timestamp_tz, lambda { |s| Time.parse(s) }],
|
39
41
|
14 => [:interval, nil],
|
40
42
|
15 => [:time_tz, nil],
|
41
43
|
16 => [:numeric, lambda { |s| BigDecimal.new(s) }],
|
@@ -46,15 +48,32 @@ module Vertica
|
|
46
48
|
|
47
49
|
DATA_TYPES = DATA_TYPE_CONVERSIONS.values.map { |t| t[0] }
|
48
50
|
|
49
|
-
def initialize(
|
50
|
-
@
|
51
|
-
@
|
52
|
-
@
|
53
|
-
@name = col.fetch(:name).to_sym
|
54
|
-
@attribute_number = col.fetch(:attribute_number)
|
55
|
-
@size = col.fetch(:data_type_size)
|
51
|
+
def initialize(name: nil, table_oid: nil, attribute_number: nil, format_code: 0, data_type_oid: nil, data_type_size: nil, data_type_modifier: nil)
|
52
|
+
@name = name
|
53
|
+
@table_oid = table_oid
|
54
|
+
@attribute_number = attribute_number
|
56
55
|
|
57
|
-
@
|
56
|
+
@format = format_code == 0 ? :text : :binary
|
57
|
+
@data_type_size = data_type_size
|
58
|
+
@data_type_modifier = data_type_modifier
|
59
|
+
@data_type, @converter = column_type_from_oid(data_type_oid)
|
60
|
+
end
|
61
|
+
|
62
|
+
def eql?(other)
|
63
|
+
self.class === other &&
|
64
|
+
other.name == name &&
|
65
|
+
other.format == format &&
|
66
|
+
other.data_type == data_type &&
|
67
|
+
other.data_type_size == data_type_size &&
|
68
|
+
other.data_type_modifier == data_type_modifier &&
|
69
|
+
other.table_oid == table_oid &&
|
70
|
+
other.attribute_number == attribute_number
|
71
|
+
end
|
72
|
+
|
73
|
+
alias_method :==, :eql?
|
74
|
+
|
75
|
+
def hash
|
76
|
+
[name, format, data_type, data_type_size, data_type_modifier, table_oid, attribute_number].hash
|
58
77
|
end
|
59
78
|
|
60
79
|
def convert(s)
|
data/lib/vertica/connection.rb
CHANGED
@@ -2,56 +2,37 @@ require 'socket'
|
|
2
2
|
|
3
3
|
class Vertica::Connection
|
4
4
|
|
5
|
-
attr_reader :
|
6
|
-
|
7
|
-
attr_accessor :row_style, :debug, :options
|
8
|
-
|
9
|
-
def self.cancel(existing_conn)
|
10
|
-
existing_conn.cancel
|
11
|
-
end
|
5
|
+
attr_reader :transaction_status, :parameters, :options
|
12
6
|
|
13
7
|
# Opens a connectio the a Vertica server
|
14
8
|
# @param [Hash] options The connection options to use.
|
15
|
-
def initialize(
|
16
|
-
|
9
|
+
def initialize(host: nil, port: 5433, username: nil, password: nil, database: nil, interruptable: false, ssl: nil, read_timeout: 600, debug: false, role: nil, search_path: nil, timezone: nil, autocommit: false, skip_startup: false, skip_initialize: false, user: nil)
|
10
|
+
reset_state
|
17
11
|
@notice_handler = nil
|
18
12
|
|
19
|
-
@options = {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
13
|
+
@options = {
|
14
|
+
host: host,
|
15
|
+
port: port.to_i,
|
16
|
+
username: username || user,
|
17
|
+
password: password,
|
18
|
+
database: database,
|
19
|
+
debug: debug,
|
20
|
+
ssl: ssl,
|
21
|
+
interruptable: interruptable,
|
22
|
+
read_timeout: read_timeout,
|
23
|
+
role: role,
|
24
|
+
search_path: search_path,
|
25
|
+
timezone: timezone,
|
26
|
+
autocommit: autocommit,
|
27
|
+
}
|
28
|
+
|
29
|
+
boot_connection(skip_initialize: skip_initialize) unless skip_startup
|
29
30
|
end
|
30
31
|
|
31
32
|
def on_notice(&block)
|
32
33
|
@notice_handler = block
|
33
34
|
end
|
34
35
|
|
35
|
-
def socket
|
36
|
-
@socket ||= begin
|
37
|
-
raw_socket = TCPSocket.new(@options[:host], @options[:port].to_i)
|
38
|
-
if @options[:ssl]
|
39
|
-
require 'openssl'
|
40
|
-
raw_socket.write Vertica::Messages::SslRequest.new.to_bytes
|
41
|
-
if raw_socket.read(1) == 'S'
|
42
|
-
ssl_context = @options[:ssl].is_a?(OpenSSL::SSL::SSLContext) ? @options[:ssl] : OpenSSL::SSL::SSLContext.new
|
43
|
-
raw_socket = OpenSSL::SSL::SSLSocket.new(raw_socket, ssl_context)
|
44
|
-
raw_socket.sync = true
|
45
|
-
raw_socket.connect
|
46
|
-
else
|
47
|
-
raise Vertica::Error::SSLNotSupported.new("SSL requested but server doesn't support it.")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
raw_socket
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
36
|
def ssl?
|
56
37
|
Object.const_defined?('OpenSSL') && @socket.kind_of?(OpenSSL::SSL::SSLSocket)
|
57
38
|
end
|
@@ -72,81 +53,90 @@ class Vertica::Connection
|
|
72
53
|
!busy?
|
73
54
|
end
|
74
55
|
|
75
|
-
def
|
76
|
-
|
77
|
-
write_bytes message.to_bytes
|
78
|
-
rescue SystemCallError, IOError => e
|
79
|
-
close_socket
|
80
|
-
raise Vertica::Error::ConnectionError.new(e.message)
|
56
|
+
def interruptable?
|
57
|
+
!session_id.nil?
|
81
58
|
end
|
82
59
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
60
|
+
def query(sql, **kwargs, &block)
|
61
|
+
row_handler = block_given? ? block : nil
|
62
|
+
job = Vertica::Query.new(self, sql, row_handler: row_handler, **kwargs)
|
63
|
+
run_with_mutex(job)
|
87
64
|
end
|
88
65
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
66
|
+
def copy(sql, source: nil, **kwargs, &block)
|
67
|
+
copy_handler = if block_given?
|
68
|
+
block
|
69
|
+
elsif source && File.exist?(source.to_s)
|
70
|
+
lambda { |data| file_copy_handler(source, data) }
|
71
|
+
elsif source.respond_to?(:read) && source.respond_to?(:eof?)
|
72
|
+
lambda { |data| io_copy_handler(source, data) }
|
73
|
+
end
|
74
|
+
|
75
|
+
job = Vertica::Query.new(self, sql, copy_handler: copy_handler, **kwargs)
|
76
|
+
|
77
|
+
run_with_mutex(job)
|
95
78
|
end
|
96
79
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
80
|
+
def inspect
|
81
|
+
safe_options = @options.reject { |name, _| name == :password }
|
82
|
+
"#<Vertica::Connection:#{object_id} @parameters=#{@parameters.inspect} @backend_pid=#{@backend_pid}, @backend_key=#{@backend_key}, @transaction_status=#{@transaction_status}, @socket=#{@socket}, @options=#{safe_options.inspect}>"
|
100
83
|
end
|
101
84
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
85
|
+
def close
|
86
|
+
write_message(Vertica::Protocol::Terminate.new)
|
87
|
+
ensure
|
88
|
+
close_socket
|
105
89
|
end
|
106
90
|
|
107
91
|
def cancel
|
108
|
-
conn = self.class.new(
|
109
|
-
conn.write_message
|
110
|
-
conn.write_message
|
111
|
-
conn.
|
92
|
+
conn = self.class.new(skip_startup: true, **options)
|
93
|
+
conn.write_message(Vertica::Protocol::CancelRequest.new(backend_pid, backend_key))
|
94
|
+
conn.write_message(Vertica::Protocol::Flush.new)
|
95
|
+
conn.close_socket
|
112
96
|
end
|
113
97
|
|
114
98
|
def interrupt
|
115
99
|
raise Vertica::Error::InterruptImpossible, "Session cannopt be interrupted because the session ID is not known!" if session_id.nil?
|
116
|
-
conn = self.class.new(
|
117
|
-
|
118
|
-
|
119
|
-
|
100
|
+
conn = self.class.new(skip_initialize: true, **options)
|
101
|
+
conn.query("SELECT CLOSE_SESSION(#{Vertica.quote(session_id)})").the_value
|
102
|
+
ensure
|
103
|
+
conn.close if conn
|
120
104
|
end
|
121
105
|
|
122
|
-
|
123
|
-
|
106
|
+
# @private
|
107
|
+
def write_message(message)
|
108
|
+
puts "=> #{message.inspect}" if options.fetch(:debug)
|
109
|
+
write_bytes(message.to_bytes)
|
110
|
+
rescue SystemCallError, IOError => e
|
111
|
+
close_socket
|
112
|
+
raise Vertica::Error::ConnectionError.new(e.message)
|
124
113
|
end
|
125
114
|
|
115
|
+
# @private
|
126
116
|
def read_message
|
127
|
-
type = read_bytes(
|
128
|
-
size = read_bytes(4).unpack('N').first
|
117
|
+
type, size = read_bytes(5).unpack('aN')
|
129
118
|
raise Vertica::Error::MessageError.new("Bad message size: #{size}.") unless size >= 4
|
130
|
-
message = Vertica::
|
131
|
-
puts "<= #{message.inspect}" if
|
119
|
+
message = Vertica::Protocol::BackendMessage.factory(type, read_bytes(size - 4))
|
120
|
+
puts "<= #{message.inspect}" if options.fetch(:debug)
|
132
121
|
return message
|
133
122
|
rescue SystemCallError, IOError => e
|
134
123
|
close_socket
|
135
124
|
raise Vertica::Error::ConnectionError.new(e.message)
|
136
125
|
end
|
137
126
|
|
127
|
+
# @private
|
138
128
|
def process_message(message)
|
139
129
|
case message
|
140
|
-
when Vertica::
|
130
|
+
when Vertica::Protocol::ErrorResponse
|
141
131
|
raise Vertica::Error::ConnectionError.new(message.error_message)
|
142
|
-
when Vertica::
|
132
|
+
when Vertica::Protocol::NoticeResponse
|
143
133
|
@notice_handler.call(message) if @notice_handler
|
144
|
-
when Vertica::
|
134
|
+
when Vertica::Protocol::BackendKeyData
|
145
135
|
@backend_pid = message.pid
|
146
136
|
@backend_key = message.key
|
147
|
-
when Vertica::
|
137
|
+
when Vertica::Protocol::ParameterStatus
|
148
138
|
@parameters[message.name] = message.value
|
149
|
-
when Vertica::
|
139
|
+
when Vertica::Protocol::ReadyForQuery
|
150
140
|
@transaction_status = message.transaction_status
|
151
141
|
@mutex.unlock
|
152
142
|
else
|
@@ -154,30 +144,29 @@ class Vertica::Connection
|
|
154
144
|
end
|
155
145
|
end
|
156
146
|
|
157
|
-
|
158
|
-
job = Vertica::Query.new(self, sql, { :row_style => @row_style }.merge(options))
|
159
|
-
job.row_handler = block if block_given?
|
160
|
-
run_with_mutex(job)
|
161
|
-
end
|
147
|
+
protected
|
162
148
|
|
163
|
-
|
164
|
-
job = Vertica::Query.new(self, sql, :row_style => @row_style)
|
165
|
-
if block_given?
|
166
|
-
job.copy_handler = block
|
167
|
-
elsif source && File.exist?(source.to_s)
|
168
|
-
job.copy_handler = lambda { |data| file_copy_handler(source, data) }
|
169
|
-
elsif source.respond_to?(:read) && source.respond_to?(:eof?)
|
170
|
-
job.copy_handler = lambda { |data| io_copy_handler(source, data) }
|
171
|
-
end
|
172
|
-
run_with_mutex(job)
|
173
|
-
end
|
149
|
+
attr_reader :backend_pid, :backend_key, :session_id
|
174
150
|
|
175
|
-
def
|
176
|
-
|
177
|
-
|
178
|
-
|
151
|
+
def socket
|
152
|
+
@socket ||= begin
|
153
|
+
raw_socket = TCPSocket.new(@options[:host], @options[:port].to_i)
|
154
|
+
if @options[:ssl]
|
155
|
+
require 'openssl'
|
156
|
+
raw_socket.write(Vertica::Protocol::SslRequest.new.to_bytes)
|
157
|
+
if raw_socket.read(1) == 'S'
|
158
|
+
ssl_context = @options[:ssl].is_a?(OpenSSL::SSL::SSLContext) ? @options[:ssl] : OpenSSL::SSL::SSLContext.new
|
159
|
+
raw_socket = OpenSSL::SSL::SSLSocket.new(raw_socket, ssl_context)
|
160
|
+
raw_socket.sync = true
|
161
|
+
raw_socket.connect
|
162
|
+
else
|
163
|
+
raise Vertica::Error::SSLNotSupported.new("SSL requested but server doesn't support it.")
|
164
|
+
end
|
165
|
+
end
|
179
166
|
|
180
|
-
|
167
|
+
raw_socket
|
168
|
+
end
|
169
|
+
end
|
181
170
|
|
182
171
|
def run_with_mutex(job)
|
183
172
|
boot_connection if closed?
|
@@ -193,19 +182,18 @@ class Vertica::Connection
|
|
193
182
|
end
|
194
183
|
end
|
195
184
|
|
196
|
-
|
185
|
+
DEFAULT_IO_COPY_HANDLER_BLOCK_SIZE = 1024 * 4096
|
186
|
+
private_constant :DEFAULT_IO_COPY_HANDLER_BLOCK_SIZE
|
197
187
|
|
198
188
|
def file_copy_handler(input_file, output)
|
199
189
|
File.open(input_file, 'r') do |input|
|
200
|
-
|
201
|
-
output << data
|
202
|
-
end
|
190
|
+
io_copy_handler(input, output)
|
203
191
|
end
|
204
192
|
end
|
205
193
|
|
206
194
|
def io_copy_handler(input, output)
|
207
195
|
until input.eof?
|
208
|
-
output << input.read(
|
196
|
+
output << input.read(DEFAULT_IO_COPY_HANDLER_BLOCK_SIZE)
|
209
197
|
end
|
210
198
|
end
|
211
199
|
|
@@ -241,27 +229,68 @@ class Vertica::Connection
|
|
241
229
|
end
|
242
230
|
|
243
231
|
def startup_connection
|
244
|
-
write_message
|
232
|
+
write_message(Vertica::Protocol::Startup.new(@options[:username], @options[:database]))
|
245
233
|
message = nil
|
246
234
|
begin
|
247
235
|
case message = read_message
|
248
|
-
when Vertica::
|
249
|
-
if message.code != Vertica::
|
250
|
-
write_message
|
236
|
+
when Vertica::Protocol::Authentication
|
237
|
+
if message.code != Vertica::Protocol::Authentication::OK
|
238
|
+
write_message(Vertica::Protocol::Password.new(@options[:password], auth_method: message.code, user: @options[:username], salt: message.salt))
|
251
239
|
end
|
252
240
|
else
|
253
241
|
process_message(message)
|
254
242
|
end
|
255
|
-
end until message.kind_of?(Vertica::
|
243
|
+
end until message.kind_of?(Vertica::Protocol::ReadyForQuery)
|
256
244
|
end
|
257
245
|
|
258
246
|
def initialize_connection
|
259
|
-
query("SET SEARCH_PATH TO #{options[:search_path]}") if options[:search_path]
|
260
|
-
query("SET ROLE #{options[:role]}") if options[:role]
|
261
247
|
@session_id = query("SELECT session_id FROM v_monitor.current_session").the_value if options[:interruptable]
|
248
|
+
initialize_connection_with_role
|
249
|
+
initialize_connection_with_search_path
|
250
|
+
initialize_connection_with_timezone
|
251
|
+
initialize_connection_with_autocommit
|
252
|
+
end
|
253
|
+
|
254
|
+
def initialize_connection_with_role
|
255
|
+
case options[:role]
|
256
|
+
when :all, :none, :default
|
257
|
+
query("SET ROLE #{options[:role].to_s.upcase}")
|
258
|
+
when String, Array
|
259
|
+
query("SET ROLE #{Vertica.quote(options[:role])}")
|
260
|
+
end
|
262
261
|
end
|
263
262
|
|
264
|
-
def
|
263
|
+
def initialize_connection_with_search_path
|
264
|
+
query("SET SEARCH_PATH TO #{Vertica.quote(options[:search_path])}") if options[:search_path]
|
265
|
+
end
|
266
|
+
|
267
|
+
def initialize_connection_with_timezone
|
268
|
+
query("SET TIME ZONE TO #{Vertica.quote(options[:timezone])}") if options[:timezone]
|
269
|
+
end
|
270
|
+
|
271
|
+
def initialize_connection_with_autocommit
|
272
|
+
query("SET AUTOCOMMIT TO ON") if options[:autocommit]
|
273
|
+
end
|
274
|
+
|
275
|
+
def close_socket
|
276
|
+
@socket.close if @socket
|
277
|
+
rescue SystemCallError, IOError
|
278
|
+
# ignore
|
279
|
+
ensure
|
280
|
+
reset_state
|
281
|
+
end
|
282
|
+
|
283
|
+
def reset_connection
|
284
|
+
close
|
285
|
+
boot_connection
|
286
|
+
end
|
287
|
+
|
288
|
+
def boot_connection(skip_initialize: false)
|
289
|
+
startup_connection
|
290
|
+
initialize_connection unless skip_initialize
|
291
|
+
end
|
292
|
+
|
293
|
+
def reset_state
|
265
294
|
@parameters = {}
|
266
295
|
@session_id = nil
|
267
296
|
@backend_pid = nil
|
@@ -271,8 +300,3 @@ class Vertica::Connection
|
|
271
300
|
@mutex = Mutex.new.lock
|
272
301
|
end
|
273
302
|
end
|
274
|
-
|
275
|
-
require 'vertica/query'
|
276
|
-
require 'vertica/column'
|
277
|
-
require 'vertica/result'
|
278
|
-
require 'vertica/messages/message'
|