vertica 0.7.4
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.
- data/LICENSE +19 -0
- data/README.textile +69 -0
- data/Rakefile +44 -0
- data/lib/vertica/bit_helper.rb +51 -0
- data/lib/vertica/column.rb +68 -0
- data/lib/vertica/connection.rb +247 -0
- data/lib/vertica/messages/authentication.rb +33 -0
- data/lib/vertica/messages/backend_key_data.rb +16 -0
- data/lib/vertica/messages/bind.rb +36 -0
- data/lib/vertica/messages/bind_complete.rb +8 -0
- data/lib/vertica/messages/cancel_request.rb +25 -0
- data/lib/vertica/messages/close.rb +30 -0
- data/lib/vertica/messages/close_complete.rb +8 -0
- data/lib/vertica/messages/command_complete.rb +16 -0
- data/lib/vertica/messages/data_row.rb +23 -0
- data/lib/vertica/messages/describe.rb +30 -0
- data/lib/vertica/messages/empty_query_response.rb +8 -0
- data/lib/vertica/messages/error_response.rb +59 -0
- data/lib/vertica/messages/execute.rb +24 -0
- data/lib/vertica/messages/flush.rb +15 -0
- data/lib/vertica/messages/message.rb +85 -0
- data/lib/vertica/messages/no_data.rb +8 -0
- data/lib/vertica/messages/notice_response.rb +21 -0
- data/lib/vertica/messages/notification_response.rb +18 -0
- data/lib/vertica/messages/parameter_description.rb +19 -0
- data/lib/vertica/messages/parameter_status.rb +17 -0
- data/lib/vertica/messages/parse.rb +31 -0
- data/lib/vertica/messages/parse_complete.rb +8 -0
- data/lib/vertica/messages/password.rb +33 -0
- data/lib/vertica/messages/portal_suspended.rb +8 -0
- data/lib/vertica/messages/query.rb +20 -0
- data/lib/vertica/messages/ready_for_query.rb +14 -0
- data/lib/vertica/messages/row_description.rb +29 -0
- data/lib/vertica/messages/ssl_request.rb +14 -0
- data/lib/vertica/messages/startup.rb +38 -0
- data/lib/vertica/messages/sync.rb +15 -0
- data/lib/vertica/messages/terminate.rb +14 -0
- data/lib/vertica/messages/unknown.rb +11 -0
- data/lib/vertica/notice.rb +11 -0
- data/lib/vertica/notification.rb +13 -0
- data/lib/vertica/result.rb +28 -0
- data/lib/vertica/vertica_socket.rb +8 -0
- data/lib/vertica.rb +19 -0
- data/test/connection_test.rb +191 -0
- data/test/create_schema.sql +4 -0
- data/test/test_helper.rb +25 -0
- data/vertica.gemspec +64 -0
- metadata +112 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Matt Bauer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
h1. Vertica
|
2
|
+
|
3
|
+
by Matt Bauer
|
4
|
+
|
5
|
+
h2. 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 and
|
9
|
+
prepared statements.
|
10
|
+
|
11
|
+
h2. Install
|
12
|
+
|
13
|
+
$ gem install mattbauer-vertica --source http://gems.github.com
|
14
|
+
|
15
|
+
h2. Source
|
16
|
+
|
17
|
+
Vertica's git repo is available on GitHub, which can be browsed at:
|
18
|
+
|
19
|
+
http://github.com/mattbauer/vertica
|
20
|
+
|
21
|
+
and cloned from:
|
22
|
+
|
23
|
+
git://github.com/mattbauer/vertica.git
|
24
|
+
|
25
|
+
h2. Usage
|
26
|
+
|
27
|
+
h4. Example Query
|
28
|
+
|
29
|
+
<pre>
|
30
|
+
<code>
|
31
|
+
c = Vertica::Connection.new(
|
32
|
+
:user => 'user',
|
33
|
+
:password => 'password',
|
34
|
+
:host => 'db_server',
|
35
|
+
:port => '5433',
|
36
|
+
:database => 'db
|
37
|
+
)
|
38
|
+
r = c.query("SELECT * FROM my_table")
|
39
|
+
puts r.row_count
|
40
|
+
puts r.columns[0].name
|
41
|
+
puts r.rows
|
42
|
+
c.close
|
43
|
+
</code>
|
44
|
+
</pre>
|
45
|
+
|
46
|
+
h4. Example Prepared Statement
|
47
|
+
|
48
|
+
<pre>
|
49
|
+
<code>
|
50
|
+
c = Vertica::Connection.new(
|
51
|
+
:user => 'user',
|
52
|
+
:password => 'password',
|
53
|
+
:host => 'db_server',
|
54
|
+
:port => '5433',
|
55
|
+
:database => 'db
|
56
|
+
)
|
57
|
+
c.prepare("my_prepared_statement", "SELECT * FROM my_table WHERE id = ?", 1)
|
58
|
+
r = c.execute_prepared("my_prepared_statement", 13)
|
59
|
+
puts r.row_count
|
60
|
+
puts r.columns[0].name
|
61
|
+
puts r.rows
|
62
|
+
c.close
|
63
|
+
</code>
|
64
|
+
</pre>
|
65
|
+
|
66
|
+
h2. Running The Tests
|
67
|
+
|
68
|
+
To run the tests, change the values in test_helper.rb to match your db configuration. Then
|
69
|
+
execute the create_schema.sql on the database. Then you may run the tests.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
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"
|
13
|
+
|
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"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
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']
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Vertica
|
2
|
+
module BitHelper
|
3
|
+
|
4
|
+
def readn(n)
|
5
|
+
s = read(n)
|
6
|
+
raise "couldn't read #{n} characters" if s.nil? or s.size != n # TODO make into a Vertica Exception
|
7
|
+
s
|
8
|
+
end
|
9
|
+
|
10
|
+
def write_byte(value)
|
11
|
+
write [value].pack('C')
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_byte
|
15
|
+
readn(1).unpack('C').first
|
16
|
+
end
|
17
|
+
|
18
|
+
def write_network_int16(value)
|
19
|
+
write [value].pack('n')
|
20
|
+
end
|
21
|
+
|
22
|
+
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
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_cstring(value)
|
35
|
+
raise ArgumentError, "Invalid cstring" if value.include?("\000")
|
36
|
+
write "#{value}\000"
|
37
|
+
end
|
38
|
+
|
39
|
+
def read_cstring
|
40
|
+
readline("\000")[0..-2]
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_endian_flavor(s)
|
44
|
+
little_endian? ? s.reverse : s
|
45
|
+
end
|
46
|
+
|
47
|
+
def little_endian?
|
48
|
+
@little_endian ||= ([0x12345678].pack("L") == "\x12\x34\x56\x78" ? false : true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Vertica
|
2
|
+
class Column
|
3
|
+
attr_reader :name
|
4
|
+
attr_reader :table_oid
|
5
|
+
attr_reader :type_modifier
|
6
|
+
attr_reader :size
|
7
|
+
attr_reader :data_type
|
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
|
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
|
+
|
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
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert(s)
|
64
|
+
l = DATA_TYPE_CONVERSIONS[@data_type]
|
65
|
+
l ? l.call(s) : s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'stringio'
|
3
|
+
require 'vertica/vertica_socket'
|
4
|
+
require 'vertica/messages/message'
|
5
|
+
require 'openssl/ssl'
|
6
|
+
|
7
|
+
module Vertica
|
8
|
+
|
9
|
+
class Connection
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
reset_values
|
13
|
+
|
14
|
+
@options = options
|
15
|
+
establish_connection
|
16
|
+
|
17
|
+
unless options[:skip_startup]
|
18
|
+
Messages::Startup.new(@options[:user], @options[:database]).to_bytes(@conn)
|
19
|
+
process
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
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
|
29
|
+
ensure
|
30
|
+
reset_values
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset
|
34
|
+
close if opened?
|
35
|
+
reset_values
|
36
|
+
establish_connection
|
37
|
+
end
|
38
|
+
|
39
|
+
def options
|
40
|
+
@options.dup
|
41
|
+
end
|
42
|
+
|
43
|
+
def transaction_status
|
44
|
+
@transaction_status
|
45
|
+
end
|
46
|
+
|
47
|
+
def backend_pid
|
48
|
+
@backend_pid
|
49
|
+
end
|
50
|
+
|
51
|
+
def backend_key
|
52
|
+
@backend_key
|
53
|
+
end
|
54
|
+
|
55
|
+
def notifications
|
56
|
+
@notifications
|
57
|
+
end
|
58
|
+
|
59
|
+
def parameters
|
60
|
+
@parameters.dup
|
61
|
+
end
|
62
|
+
|
63
|
+
def put_copy_data; raise NotImplementedError.new; end
|
64
|
+
def put_copy_end; raise NotImplementedError.new; end
|
65
|
+
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)
|
76
|
+
raise ArgumentError.new("Query string cannot be blank or empty.") if query_string.nil? || query_string.empty?
|
77
|
+
raise_if_not_open
|
78
|
+
reset_result
|
79
|
+
|
80
|
+
Messages::Query.new(query_string).to_bytes(@conn)
|
81
|
+
process(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def prepare(name, query, params_count = 0)
|
85
|
+
raise_if_not_open
|
86
|
+
|
87
|
+
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
|
+
|
94
|
+
process
|
95
|
+
end
|
96
|
+
|
97
|
+
def execute_prepared(name, *param_values)
|
98
|
+
raise_if_not_open
|
99
|
+
|
100
|
+
portal_name = "" # use the unnamed portal
|
101
|
+
max_rows = 0 # return all rows
|
102
|
+
|
103
|
+
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
|
+
|
109
|
+
result = process(true)
|
110
|
+
|
111
|
+
# Close the portal
|
112
|
+
Messages::Close.new(:portal, portal_name).to_bytes(@conn)
|
113
|
+
Messages::Flush.new.to_bytes(@conn)
|
114
|
+
|
115
|
+
process
|
116
|
+
|
117
|
+
# Return the result from the prepared statement
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
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
|
+
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
|
+
|
145
|
+
def process(return_result = false)
|
146
|
+
loop do
|
147
|
+
message = Messages::BackendMessage.read(@conn)
|
148
|
+
|
149
|
+
case message
|
150
|
+
when Messages::Authentication
|
151
|
+
if message.code != Messages::Authentication::OK
|
152
|
+
Messages::Password.new(@options[:password], message.code, {:user => @options[:user], :salt => message.salt}).to_bytes(@conn)
|
153
|
+
end
|
154
|
+
when Messages::BackendKeyData
|
155
|
+
@backend_pid = message.pid
|
156
|
+
@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'
|
171
|
+
when Messages::DataRow
|
172
|
+
@field_values << message.fields
|
173
|
+
when Messages::EmptyQueryResponse
|
174
|
+
break
|
175
|
+
when Messages::ErrorResponse
|
176
|
+
raise Error::MessageError.new(message.error)
|
177
|
+
when Messages::NoData
|
178
|
+
:nothing
|
179
|
+
when Messages::NoticeResponse
|
180
|
+
message.notices.each do |notice|
|
181
|
+
@notices << Notice.new(notice[0], notice[1])
|
182
|
+
end
|
183
|
+
when Messages::NotificationResponse
|
184
|
+
@notifications << Notification.new(message.pid, message.condition, message.additional_info)
|
185
|
+
when Messages::ParameterDescription
|
186
|
+
:nothing
|
187
|
+
when Messages::ParameterStatus
|
188
|
+
@parameters[message.name] = message.value
|
189
|
+
when Messages::ParseComplete
|
190
|
+
break
|
191
|
+
when Messages::PortalSuspended
|
192
|
+
break
|
193
|
+
when Messages::ReadyForQuery
|
194
|
+
@transaction_status = convert_transaction_status_to_sym(message.transaction_status)
|
195
|
+
break unless return_result
|
196
|
+
when Messages::RowDescription
|
197
|
+
@field_descriptions = message.fields
|
198
|
+
when Messages::Unknown
|
199
|
+
raise Error::MessageError.new("Unknown message type: #{message.message_id}")
|
200
|
+
end
|
201
|
+
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?
|
208
|
+
end
|
209
|
+
|
210
|
+
def reset_values
|
211
|
+
reset_notifications
|
212
|
+
reset_result
|
213
|
+
@parameters = {}
|
214
|
+
@backend_pid = nil
|
215
|
+
@backend_key = nil
|
216
|
+
@transaction_status = nil
|
217
|
+
@conn = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def reset_notifications
|
221
|
+
@notifications = []
|
222
|
+
end
|
223
|
+
|
224
|
+
def reset_result
|
225
|
+
@field_descriptions = []
|
226
|
+
@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
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Authentication < BackendMessage
|
4
|
+
message_id ?R
|
5
|
+
|
6
|
+
OK = 0
|
7
|
+
KERBEROS_V5 = 2
|
8
|
+
CLEARTEXT_PASSWORD = 3
|
9
|
+
CRYPT_PASSWORD = 4
|
10
|
+
MD5_PASSWORD = 5
|
11
|
+
SCM_CREDENTIAL = 6
|
12
|
+
GSS = 7
|
13
|
+
GSS_CONTINUE = 8
|
14
|
+
SSPI = 9
|
15
|
+
|
16
|
+
attr_reader :code
|
17
|
+
attr_reader :salt
|
18
|
+
attr_reader :auth_data
|
19
|
+
|
20
|
+
def initialize(stream, size)
|
21
|
+
super
|
22
|
+
@code = stream.read_network_int32
|
23
|
+
if @code == CRYPT_PASSWORD
|
24
|
+
@salt = stream.readn(2)
|
25
|
+
elsif @code == MD5_PASSWORD
|
26
|
+
@salt = stream.readn(4)
|
27
|
+
elsif @code == GSS_CONTINUE
|
28
|
+
@auth_data = stream.readn(size - 9)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class BackendKeyData < BackendMessage
|
4
|
+
message_id ?K
|
5
|
+
|
6
|
+
attr_reader :pid
|
7
|
+
attr_reader :key
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
super
|
11
|
+
@pid = stream.read_network_int32
|
12
|
+
@key = stream.read_network_int32
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Bind < FrontendMessage
|
4
|
+
message_id ?B
|
5
|
+
|
6
|
+
def initialize(portal_name, prepared_statement_name, parameter_values)
|
7
|
+
@portal_name = portal_name
|
8
|
+
@prepared_statement_name = prepared_statement_name
|
9
|
+
@parameter_values = parameter_values.map { |pv| pv.to_s }
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_bytes(stream)
|
13
|
+
size = LENGTH_SIZE
|
14
|
+
size += @portal_name.length + 1
|
15
|
+
size += @prepared_statement_name.length + 1
|
16
|
+
size += 2 # parameter format code (0)
|
17
|
+
size += 2 # number of parameter values
|
18
|
+
size += @parameter_values.inject(0) { |sum, e| sum += (e.length + 4) }
|
19
|
+
size += 2
|
20
|
+
|
21
|
+
stream.write_byte(message_id)
|
22
|
+
stream.write_network_int32(size) # size
|
23
|
+
stream.write_cstring(@portal_name) # portal name ("")
|
24
|
+
stream.write_cstring(@prepared_statement_name) # prep
|
25
|
+
stream.write_network_int16(0) # format codes (0 - default text format)
|
26
|
+
stream.write_network_int16(@parameter_values.length) # number of parameters
|
27
|
+
@parameter_values.each do |parameter_value|
|
28
|
+
stream.write_network_int32(parameter_value.length) # parameter value (which is represented as a string) length
|
29
|
+
stream.write(parameter_value) # parameter value written out in text representation
|
30
|
+
end
|
31
|
+
stream.write_network_int16(0)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class CancelRequest < FrontendMessage
|
4
|
+
message_id nil
|
5
|
+
|
6
|
+
def initialize(backend_pid, backend_key)
|
7
|
+
@backend_pid = backend_pid
|
8
|
+
@backend_key = backend_key
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_bytes(stream)
|
12
|
+
size = LENGTH_SIZE
|
13
|
+
size += 4
|
14
|
+
size += 4
|
15
|
+
size += 4
|
16
|
+
|
17
|
+
stream.write_network_int32(size) # size
|
18
|
+
stream.write_network_int32(80877102)
|
19
|
+
stream.write_network_int32(@backend_pid)
|
20
|
+
stream.write_network_int32(@backend_key)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class Close < FrontendMessage
|
4
|
+
message_id ?C
|
5
|
+
|
6
|
+
def initialize(close_type, close_name)
|
7
|
+
if close_type == :portal
|
8
|
+
@close_type = ?P
|
9
|
+
elsif close_type == :prepared_statement
|
10
|
+
@close_type = ?S
|
11
|
+
else
|
12
|
+
raise ArgumentError.new("#{close_type} is not a valid close_type. Must be either :portal or :prepared_statement.")
|
13
|
+
end
|
14
|
+
@close_name = close_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_bytes(stream)
|
18
|
+
size = LENGTH_SIZE
|
19
|
+
size += 1
|
20
|
+
size += @close_name.length + 1
|
21
|
+
|
22
|
+
stream.write_byte(message_id)
|
23
|
+
stream.write_network_int32(size) # size
|
24
|
+
stream.write_byte(@close_type)
|
25
|
+
stream.write_cstring(@close_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Messages
|
3
|
+
class CommandComplete < BackendMessage
|
4
|
+
message_id ?C
|
5
|
+
|
6
|
+
attr_reader :tag
|
7
|
+
attr_reader :rows
|
8
|
+
|
9
|
+
def initialize(stream, size)
|
10
|
+
@tag = stream.read_cstring
|
11
|
+
@rows = @tag.split[-1].to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|