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