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