yugabyte-ycql-driver 3.2.3.1
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 +7 -0
- data/.yardopts +13 -0
- data/README.md +242 -0
- data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
- data/ext/cassandra_murmur3/extconf.rb +2 -0
- data/lib/cassandra/address_resolution.rb +36 -0
- data/lib/cassandra/address_resolution/policies.rb +2 -0
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
- data/lib/cassandra/address_resolution/policies/none.rb +35 -0
- data/lib/cassandra/aggregate.rb +123 -0
- data/lib/cassandra/argument.rb +51 -0
- data/lib/cassandra/attr_boolean.rb +33 -0
- data/lib/cassandra/auth.rb +100 -0
- data/lib/cassandra/auth/providers.rb +17 -0
- data/lib/cassandra/auth/providers/password.rb +65 -0
- data/lib/cassandra/cassandra_logger.rb +80 -0
- data/lib/cassandra/cluster.rb +331 -0
- data/lib/cassandra/cluster/client.rb +1612 -0
- data/lib/cassandra/cluster/connection_pool.rb +78 -0
- data/lib/cassandra/cluster/connector.rb +372 -0
- data/lib/cassandra/cluster/control_connection.rb +962 -0
- data/lib/cassandra/cluster/failed_connection.rb +35 -0
- data/lib/cassandra/cluster/metadata.rb +142 -0
- data/lib/cassandra/cluster/options.rb +145 -0
- data/lib/cassandra/cluster/registry.rb +284 -0
- data/lib/cassandra/cluster/schema.rb +405 -0
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
- data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
- data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
- data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -0
- data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
- data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
- data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
- data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -0
- data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
- data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
- data/lib/cassandra/column.rb +66 -0
- data/lib/cassandra/column_container.rb +326 -0
- data/lib/cassandra/compression.rb +69 -0
- data/lib/cassandra/compression/compressors/lz4.rb +73 -0
- data/lib/cassandra/compression/compressors/snappy.rb +69 -0
- data/lib/cassandra/custom_data.rb +53 -0
- data/lib/cassandra/driver.rb +260 -0
- data/lib/cassandra/errors.rb +784 -0
- data/lib/cassandra/execution/info.rb +69 -0
- data/lib/cassandra/execution/options.rb +267 -0
- data/lib/cassandra/execution/profile.rb +153 -0
- data/lib/cassandra/execution/profile_manager.rb +71 -0
- data/lib/cassandra/execution/trace.rb +192 -0
- data/lib/cassandra/executors.rb +113 -0
- data/lib/cassandra/function.rb +156 -0
- data/lib/cassandra/function_collection.rb +85 -0
- data/lib/cassandra/future.rb +794 -0
- data/lib/cassandra/host.rb +102 -0
- data/lib/cassandra/index.rb +118 -0
- data/lib/cassandra/keyspace.rb +473 -0
- data/lib/cassandra/listener.rb +87 -0
- data/lib/cassandra/load_balancing.rb +121 -0
- data/lib/cassandra/load_balancing/policies.rb +20 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
- data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
- data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
- data/lib/cassandra/materialized_view.rb +92 -0
- data/lib/cassandra/null_logger.rb +56 -0
- data/lib/cassandra/protocol.rb +102 -0
- data/lib/cassandra/protocol/coder.rb +1085 -0
- data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
- data/lib/cassandra/protocol/request.rb +41 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
- data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
- data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
- data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
- data/lib/cassandra/protocol/requests/options_request.rb +39 -0
- data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
- data/lib/cassandra/protocol/requests/query_request.rb +112 -0
- data/lib/cassandra/protocol/requests/register_request.rb +38 -0
- data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
- data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
- data/lib/cassandra/protocol/response.rb +28 -0
- data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
- data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
- data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
- data/lib/cassandra/protocol/responses/error_response.rb +142 -0
- data/lib/cassandra/protocol/responses/event_response.rb +30 -0
- data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
- data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
- data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
- data/lib/cassandra/protocol/responses/result_response.rb +42 -0
- data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
- data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
- data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
- data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
- data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
- data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
- data/lib/cassandra/protocol/v1.rb +326 -0
- data/lib/cassandra/protocol/v3.rb +358 -0
- data/lib/cassandra/protocol/v4.rb +478 -0
- data/lib/cassandra/reconnection.rb +49 -0
- data/lib/cassandra/reconnection/policies.rb +20 -0
- data/lib/cassandra/reconnection/policies/constant.rb +46 -0
- data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
- data/lib/cassandra/result.rb +276 -0
- data/lib/cassandra/retry.rb +154 -0
- data/lib/cassandra/retry/policies.rb +21 -0
- data/lib/cassandra/retry/policies/default.rb +53 -0
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
- data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
- data/lib/cassandra/session.rb +270 -0
- data/lib/cassandra/statement.rb +32 -0
- data/lib/cassandra/statements.rb +23 -0
- data/lib/cassandra/statements/batch.rb +146 -0
- data/lib/cassandra/statements/bound.rb +65 -0
- data/lib/cassandra/statements/prepared.rb +235 -0
- data/lib/cassandra/statements/simple.rb +118 -0
- data/lib/cassandra/statements/void.rb +38 -0
- data/lib/cassandra/table.rb +240 -0
- data/lib/cassandra/time.rb +103 -0
- data/lib/cassandra/time_uuid.rb +78 -0
- data/lib/cassandra/timestamp_generator.rb +37 -0
- data/lib/cassandra/timestamp_generator/simple.rb +38 -0
- data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
- data/lib/cassandra/trigger.rb +67 -0
- data/lib/cassandra/tuple.rb +131 -0
- data/lib/cassandra/types.rb +1704 -0
- data/lib/cassandra/udt.rb +443 -0
- data/lib/cassandra/util.rb +464 -0
- data/lib/cassandra/uuid.rb +110 -0
- data/lib/cassandra/uuid/generator.rb +212 -0
- data/lib/cassandra/version.rb +21 -0
- data/lib/datastax/cassandra.rb +47 -0
- data/lib/ycql.rb +842 -0
- metadata +243 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright DataStax, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#++
|
|
18
|
+
|
|
19
|
+
module Cassandra
|
|
20
|
+
module Protocol
|
|
21
|
+
class WriteTimeoutErrorResponse < ErrorResponse
|
|
22
|
+
attr_reader :consistency, :received, :blockfor, :write_type
|
|
23
|
+
|
|
24
|
+
def initialize(custom_payload,
|
|
25
|
+
warnings,
|
|
26
|
+
code,
|
|
27
|
+
message,
|
|
28
|
+
consistency,
|
|
29
|
+
received,
|
|
30
|
+
blockfor,
|
|
31
|
+
write_type)
|
|
32
|
+
super(custom_payload, warnings, code, message)
|
|
33
|
+
|
|
34
|
+
write_type.downcase!
|
|
35
|
+
|
|
36
|
+
@consistency = consistency
|
|
37
|
+
@received = received
|
|
38
|
+
@blockfor = blockfor
|
|
39
|
+
@write_type = write_type.to_sym
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_error(keyspace, statement, options, hosts, consistency, retries)
|
|
43
|
+
Errors::WriteTimeoutError.new(@message,
|
|
44
|
+
@custom_payload,
|
|
45
|
+
@warnings,
|
|
46
|
+
keyspace,
|
|
47
|
+
statement,
|
|
48
|
+
options,
|
|
49
|
+
hosts,
|
|
50
|
+
consistency,
|
|
51
|
+
retries,
|
|
52
|
+
@write_type,
|
|
53
|
+
@consistency,
|
|
54
|
+
@blockfor,
|
|
55
|
+
@received)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def to_s
|
|
59
|
+
"#{super} #{@write_type} #{@consistency} #{@blockfor} #{@received}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright DataStax, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#++
|
|
18
|
+
|
|
19
|
+
module Cassandra
|
|
20
|
+
module Protocol
|
|
21
|
+
# @private
|
|
22
|
+
module V1
|
|
23
|
+
class Encoder
|
|
24
|
+
HEADER_FORMAT = 'c4N'.freeze
|
|
25
|
+
|
|
26
|
+
def initialize(compressor = nil, protocol_version = 1)
|
|
27
|
+
@compressor = compressor
|
|
28
|
+
@protocol_version = protocol_version
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def encode(buffer, request, stream_id)
|
|
32
|
+
flags = request.trace? ? 2 : 0
|
|
33
|
+
body = request.write(CqlByteBuffer.new, @protocol_version, self)
|
|
34
|
+
|
|
35
|
+
if @compressor && request.compressable? && @compressor.compress?(body)
|
|
36
|
+
flags |= 1
|
|
37
|
+
body = @compressor.compress(body)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
|
|
41
|
+
buffer << header.pack(HEADER_FORMAT)
|
|
42
|
+
buffer << body
|
|
43
|
+
buffer
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def write_parameters(buffer, params, types, names = EMPTY_LIST)
|
|
47
|
+
Coder.write_values_v1(buffer, params, types)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Decoder
|
|
52
|
+
def initialize(handler, compressor = nil)
|
|
53
|
+
@handler = handler
|
|
54
|
+
@compressor = compressor
|
|
55
|
+
@state = :header
|
|
56
|
+
@header = nil
|
|
57
|
+
@length = nil
|
|
58
|
+
@buffer = CqlByteBuffer.new
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def <<(data)
|
|
62
|
+
@buffer << data
|
|
63
|
+
|
|
64
|
+
__send__(:"decode_#{@state}", @buffer)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
READY = ReadyResponse.new
|
|
70
|
+
|
|
71
|
+
def decode_header(buffer)
|
|
72
|
+
buffer_length = buffer.length
|
|
73
|
+
|
|
74
|
+
while buffer_length >= 8
|
|
75
|
+
frame_header = buffer.read_int
|
|
76
|
+
frame_length = buffer.read_int
|
|
77
|
+
|
|
78
|
+
if (buffer_length - 8) < frame_length
|
|
79
|
+
@header = frame_header
|
|
80
|
+
@length = frame_length
|
|
81
|
+
@state = :body
|
|
82
|
+
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
actual_decode(buffer, frame_header, frame_length)
|
|
87
|
+
buffer_length = buffer.length
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def decode_body(buffer)
|
|
94
|
+
frame_header = @header
|
|
95
|
+
frame_length = @length
|
|
96
|
+
buffer_length = buffer.length
|
|
97
|
+
|
|
98
|
+
until buffer_length < frame_length
|
|
99
|
+
actual_decode(buffer, frame_header, frame_length)
|
|
100
|
+
buffer_length = buffer.length
|
|
101
|
+
|
|
102
|
+
if buffer_length < 8
|
|
103
|
+
@header = nil
|
|
104
|
+
@length = nil
|
|
105
|
+
@state = :header
|
|
106
|
+
|
|
107
|
+
return
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
frame_header = buffer.read_int
|
|
111
|
+
frame_length = buffer.read_int
|
|
112
|
+
buffer_length -= 8
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
@header = frame_header
|
|
116
|
+
@length = frame_length
|
|
117
|
+
|
|
118
|
+
nil
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def actual_decode(buffer, fields, size)
|
|
122
|
+
protocol_version = (fields >> 24) & 0x7f
|
|
123
|
+
compression = (fields >> 16) & 0x01
|
|
124
|
+
tracing = (fields >> 16) & 0x02
|
|
125
|
+
stream_id = (fields >> 8) & 0xff
|
|
126
|
+
stream_id = (stream_id & 0x7f) - (stream_id & 0x80)
|
|
127
|
+
opcode = fields & 0xff
|
|
128
|
+
|
|
129
|
+
if compression == 1
|
|
130
|
+
if @compressor
|
|
131
|
+
buffer = CqlByteBuffer.new(@compressor.decompress(buffer.read(size)))
|
|
132
|
+
size = buffer.size
|
|
133
|
+
else
|
|
134
|
+
raise Errors::DecodingError,
|
|
135
|
+
'Compressed frame received, but no compressor configured'
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
if tracing == 2
|
|
140
|
+
trace_id = buffer.read_uuid
|
|
141
|
+
size -= 16
|
|
142
|
+
else
|
|
143
|
+
trace_id = nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
extra_length = buffer.length - size
|
|
147
|
+
response = decode_response(opcode, protocol_version, buffer, size, trace_id)
|
|
148
|
+
|
|
149
|
+
buffer.discard(buffer.length - extra_length) if buffer.length > extra_length
|
|
150
|
+
|
|
151
|
+
if stream_id == -1
|
|
152
|
+
@handler.notify_event_listeners(response)
|
|
153
|
+
else
|
|
154
|
+
@handler.complete_request(stream_id, response)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
CODE_ERROR = 0x00
|
|
159
|
+
CODE_READY = 0x02
|
|
160
|
+
CODE_AUTHENTICATE = 0x03
|
|
161
|
+
CODE_SUPPORTED = 0x06
|
|
162
|
+
CODE_RESULT = 0x08
|
|
163
|
+
CODE_EVENT = 0x0c
|
|
164
|
+
CODE_AUTH_CHALLENGE = 0x0e
|
|
165
|
+
CODE_AUTH_SUCCESS = 0x10
|
|
166
|
+
|
|
167
|
+
def decode_response(opcode, protocol_version, buffer, size, trace_id)
|
|
168
|
+
case opcode
|
|
169
|
+
when CODE_READY then
|
|
170
|
+
READY
|
|
171
|
+
when CODE_AUTHENTICATE then
|
|
172
|
+
AuthenticateResponse.new(buffer.read_string)
|
|
173
|
+
when CODE_AUTH_CHALLENGE then
|
|
174
|
+
AuthChallengeResponse.new(buffer.read_bytes)
|
|
175
|
+
when CODE_AUTH_SUCCESS then
|
|
176
|
+
AuthSuccessResponse.new(buffer.read_bytes)
|
|
177
|
+
when CODE_SUPPORTED then
|
|
178
|
+
SupportedResponse.new(buffer.read_string_multimap)
|
|
179
|
+
when CODE_ERROR
|
|
180
|
+
code = buffer.read_int
|
|
181
|
+
message = buffer.read_string
|
|
182
|
+
|
|
183
|
+
case code
|
|
184
|
+
when 0x1000 then
|
|
185
|
+
UnavailableErrorResponse.new(nil,
|
|
186
|
+
nil,
|
|
187
|
+
code,
|
|
188
|
+
message,
|
|
189
|
+
buffer.read_consistency,
|
|
190
|
+
buffer.read_int,
|
|
191
|
+
buffer.read_int)
|
|
192
|
+
when 0x1100 then
|
|
193
|
+
WriteTimeoutErrorResponse.new(nil,
|
|
194
|
+
nil,
|
|
195
|
+
code,
|
|
196
|
+
message,
|
|
197
|
+
buffer.read_consistency,
|
|
198
|
+
buffer.read_int,
|
|
199
|
+
buffer.read_int,
|
|
200
|
+
buffer.read_string)
|
|
201
|
+
when 0x1200 then
|
|
202
|
+
ReadTimeoutErrorResponse.new(nil,
|
|
203
|
+
nil,
|
|
204
|
+
code,
|
|
205
|
+
message,
|
|
206
|
+
buffer.read_consistency,
|
|
207
|
+
buffer.read_int,
|
|
208
|
+
buffer.read_int,
|
|
209
|
+
(buffer.read_byte != 0))
|
|
210
|
+
when 0x2400 then
|
|
211
|
+
AlreadyExistsErrorResponse.new(nil,
|
|
212
|
+
nil,
|
|
213
|
+
code,
|
|
214
|
+
message,
|
|
215
|
+
buffer.read_string,
|
|
216
|
+
buffer.read_string)
|
|
217
|
+
when 0x2500 then
|
|
218
|
+
UnpreparedErrorResponse.new(nil,
|
|
219
|
+
nil,
|
|
220
|
+
code,
|
|
221
|
+
message,
|
|
222
|
+
buffer.read_short_bytes)
|
|
223
|
+
else
|
|
224
|
+
ErrorResponse.new(nil, nil, code, message)
|
|
225
|
+
end
|
|
226
|
+
when CODE_RESULT
|
|
227
|
+
result_type = buffer.read_int
|
|
228
|
+
case result_type
|
|
229
|
+
when 0x0001 # Void
|
|
230
|
+
VoidResultResponse.new(nil, nil, trace_id)
|
|
231
|
+
when 0x0002 # Rows
|
|
232
|
+
original_buffer_length = buffer.length
|
|
233
|
+
column_specs, paging_state = Coder.read_metadata_v1(buffer)
|
|
234
|
+
|
|
235
|
+
if column_specs.nil?
|
|
236
|
+
consumed_bytes = original_buffer_length - buffer.length
|
|
237
|
+
remaining_bytes =
|
|
238
|
+
CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
|
|
239
|
+
RawRowsResultResponse.new(nil,
|
|
240
|
+
nil,
|
|
241
|
+
protocol_version,
|
|
242
|
+
remaining_bytes,
|
|
243
|
+
paging_state,
|
|
244
|
+
trace_id,
|
|
245
|
+
nil)
|
|
246
|
+
else
|
|
247
|
+
RowsResultResponse.new(nil,
|
|
248
|
+
nil,
|
|
249
|
+
Coder.read_values_v1(buffer, column_specs),
|
|
250
|
+
column_specs,
|
|
251
|
+
paging_state,
|
|
252
|
+
trace_id)
|
|
253
|
+
end
|
|
254
|
+
when 0x0003 # SetKeyspace
|
|
255
|
+
SetKeyspaceResultResponse.new(nil, nil, buffer.read_string, trace_id)
|
|
256
|
+
when 0x0004 # Prepared
|
|
257
|
+
id = buffer.read_short_bytes
|
|
258
|
+
params_metadata = Coder.read_metadata_v1(buffer).first
|
|
259
|
+
result_metadata = nil
|
|
260
|
+
result_metadata = Coder.read_metadata_v1(buffer).first if protocol_version > 1
|
|
261
|
+
|
|
262
|
+
PreparedResultResponse.new(nil,
|
|
263
|
+
nil,
|
|
264
|
+
id,
|
|
265
|
+
params_metadata,
|
|
266
|
+
result_metadata,
|
|
267
|
+
nil,
|
|
268
|
+
trace_id)
|
|
269
|
+
when 0x0005 # SchemaChange
|
|
270
|
+
change = buffer.read_string
|
|
271
|
+
keyspace = buffer.read_string
|
|
272
|
+
name = buffer.read_string
|
|
273
|
+
arguments = EMPTY_LIST
|
|
274
|
+
target = nil
|
|
275
|
+
|
|
276
|
+
if name.empty?
|
|
277
|
+
name = nil
|
|
278
|
+
target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
|
279
|
+
else
|
|
280
|
+
target = Constants::SCHEMA_CHANGE_TARGET_TABLE
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
SchemaChangeResultResponse.new(nil,
|
|
284
|
+
nil,
|
|
285
|
+
change,
|
|
286
|
+
keyspace,
|
|
287
|
+
name,
|
|
288
|
+
target,
|
|
289
|
+
arguments,
|
|
290
|
+
nil)
|
|
291
|
+
else
|
|
292
|
+
raise Errors::DecodingError,
|
|
293
|
+
"Unsupported result type: #{result_type.inspect}"
|
|
294
|
+
end
|
|
295
|
+
when CODE_EVENT
|
|
296
|
+
event_type = buffer.read_string
|
|
297
|
+
case event_type
|
|
298
|
+
when 'SCHEMA_CHANGE'
|
|
299
|
+
change = buffer.read_string
|
|
300
|
+
keyspace = buffer.read_string
|
|
301
|
+
name = buffer.read_string
|
|
302
|
+
arguments = EMPTY_LIST
|
|
303
|
+
|
|
304
|
+
if name.empty?
|
|
305
|
+
name = nil
|
|
306
|
+
target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
|
307
|
+
else
|
|
308
|
+
target = Constants::SCHEMA_CHANGE_TARGET_TABLE
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
SchemaChangeEventResponse.new(change, keyspace, name, target, arguments)
|
|
312
|
+
when 'STATUS_CHANGE'
|
|
313
|
+
StatusChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
|
|
314
|
+
when 'TOPOLOGY_CHANGE'
|
|
315
|
+
TopologyChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
|
|
316
|
+
else
|
|
317
|
+
raise Errors::DecodingError, "Unsupported event type: #{event_type.inspect}"
|
|
318
|
+
end
|
|
319
|
+
else
|
|
320
|
+
raise Errors::DecodingError, "Unsupported response opcode: #{opcode.inspect}"
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright DataStax, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#++
|
|
18
|
+
|
|
19
|
+
module Cassandra
|
|
20
|
+
module Protocol
|
|
21
|
+
# @private
|
|
22
|
+
module V3
|
|
23
|
+
class Encoder
|
|
24
|
+
HEADER_FORMAT = 'c2ncN'.freeze
|
|
25
|
+
|
|
26
|
+
def initialize(compressor = nil, protocol_version = 3)
|
|
27
|
+
@compressor = compressor
|
|
28
|
+
@protocol_version = protocol_version
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def encode(buffer, request, stream_id)
|
|
32
|
+
flags = request.trace? ? 2 : 0
|
|
33
|
+
body = request.write(CqlByteBuffer.new, @protocol_version, self)
|
|
34
|
+
|
|
35
|
+
if @compressor && request.compressable? && @compressor.compress?(body)
|
|
36
|
+
flags |= 1
|
|
37
|
+
body = @compressor.compress(body)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
|
|
41
|
+
buffer << header.pack(HEADER_FORMAT)
|
|
42
|
+
buffer << body
|
|
43
|
+
|
|
44
|
+
buffer
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def write_parameters(buffer, params, types, names = EMPTY_LIST)
|
|
48
|
+
Coder.write_values_v3(buffer, params, types, names)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Decoder
|
|
53
|
+
def initialize(handler, compressor = nil)
|
|
54
|
+
@handler = handler
|
|
55
|
+
@compressor = compressor
|
|
56
|
+
@state = :initial
|
|
57
|
+
@header = nil
|
|
58
|
+
@version = nil
|
|
59
|
+
@code = nil
|
|
60
|
+
@length = nil
|
|
61
|
+
@buffer = CqlByteBuffer.new
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def <<(data)
|
|
65
|
+
@buffer << data
|
|
66
|
+
|
|
67
|
+
__send__(:"decode_#{@state}", @buffer)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
READY = ReadyResponse.new
|
|
73
|
+
|
|
74
|
+
def decode_initial(buffer)
|
|
75
|
+
return if buffer.length < 9
|
|
76
|
+
|
|
77
|
+
frame_header = buffer.read_int
|
|
78
|
+
protocol_version = (frame_header >> 24) & 0x7f
|
|
79
|
+
|
|
80
|
+
if protocol_version < 3
|
|
81
|
+
stream_id = (frame_header >> 8) & 0xff
|
|
82
|
+
stream_id = (stream_id & 0x7f) - (stream_id & 0x80)
|
|
83
|
+
|
|
84
|
+
error_response = ErrorResponse.new(nil, nil, 0x000A,
|
|
85
|
+
'Invalid or unsupported protocol version')
|
|
86
|
+
@handler.complete_request(stream_id, error_response)
|
|
87
|
+
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
@header = frame_header
|
|
92
|
+
@code = buffer.read_byte
|
|
93
|
+
@length = buffer.read_int
|
|
94
|
+
@state = :body
|
|
95
|
+
|
|
96
|
+
decode_body(buffer)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def decode_header(buffer)
|
|
100
|
+
buffer_length = buffer.length
|
|
101
|
+
|
|
102
|
+
while buffer_length >= 9
|
|
103
|
+
frame_header = buffer.read_int
|
|
104
|
+
frame_code = buffer.read_byte
|
|
105
|
+
frame_length = buffer.read_int
|
|
106
|
+
|
|
107
|
+
if (buffer_length - 9) < frame_length
|
|
108
|
+
@header = frame_header
|
|
109
|
+
@code = frame_code
|
|
110
|
+
@length = frame_length
|
|
111
|
+
@state = :body
|
|
112
|
+
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
actual_decode(buffer, frame_header, frame_length, frame_code)
|
|
117
|
+
buffer_length = buffer.length
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def decode_body(buffer)
|
|
124
|
+
frame_header = @header
|
|
125
|
+
frame_code = @code
|
|
126
|
+
frame_length = @length
|
|
127
|
+
buffer_length = buffer.length
|
|
128
|
+
|
|
129
|
+
until buffer_length < frame_length
|
|
130
|
+
actual_decode(buffer, frame_header, frame_length, frame_code)
|
|
131
|
+
buffer_length = buffer.length
|
|
132
|
+
|
|
133
|
+
if buffer_length < 9
|
|
134
|
+
@header = nil
|
|
135
|
+
@code = nil
|
|
136
|
+
@length = nil
|
|
137
|
+
@state = :header
|
|
138
|
+
|
|
139
|
+
return
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
frame_header = buffer.read_int
|
|
143
|
+
frame_code = buffer.read_byte
|
|
144
|
+
frame_length = buffer.read_int
|
|
145
|
+
buffer_length -= 9
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
@header = frame_header
|
|
149
|
+
@code = frame_code
|
|
150
|
+
@length = frame_length
|
|
151
|
+
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def actual_decode(buffer, fields, frame_length, code)
|
|
156
|
+
protocol_version = (fields >> 24) & 0x7f
|
|
157
|
+
compression = (fields >> 16) & 0x01
|
|
158
|
+
tracing = (fields >> 16) & 0x02
|
|
159
|
+
stream_id = fields & 0xffff
|
|
160
|
+
stream_id = (stream_id & 0x7fff) - (stream_id & 0x8000)
|
|
161
|
+
opcode = code & 0xff
|
|
162
|
+
|
|
163
|
+
# If we're dealing with a compressed body, read the whole body, decompress,
|
|
164
|
+
# and treat the uncompressed body as if that's what we got in the first place.
|
|
165
|
+
# This means we must reset frame_length to that uncompressed size.
|
|
166
|
+
if compression == 1
|
|
167
|
+
if @compressor
|
|
168
|
+
buffer = CqlByteBuffer.new(
|
|
169
|
+
@compressor.decompress(buffer.read(frame_length))
|
|
170
|
+
)
|
|
171
|
+
frame_length = buffer.size
|
|
172
|
+
else
|
|
173
|
+
raise Errors::DecodingError,
|
|
174
|
+
'Compressed frame received, but no compressor configured'
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# We want to read one full frame; but after we read/parse chunks of the body
|
|
179
|
+
# there may be more cruft left in the frame that we don't care about. So,
|
|
180
|
+
# we save off the current size of the buffer, do all our reads for the
|
|
181
|
+
# frame, get the final remaining size, and based on that discard possible
|
|
182
|
+
# remaining bytes in the frame. In particular, we account for the possibility
|
|
183
|
+
# that the buffer contains some/all of a subsequent frame as well, and we
|
|
184
|
+
# don't want to mess with that.
|
|
185
|
+
|
|
186
|
+
buffer_starting_length = buffer.length
|
|
187
|
+
|
|
188
|
+
trace_id = (buffer.read_uuid if tracing == 2)
|
|
189
|
+
|
|
190
|
+
remaining_frame_length = frame_length -
|
|
191
|
+
(buffer_starting_length - buffer.length)
|
|
192
|
+
response = decode_response(opcode, protocol_version, buffer,
|
|
193
|
+
remaining_frame_length, trace_id)
|
|
194
|
+
|
|
195
|
+
# Calculate and discard remaining cruft in the frame.
|
|
196
|
+
extra_length = frame_length - (buffer_starting_length - buffer.length)
|
|
197
|
+
buffer.discard(extra_length) if extra_length > 0
|
|
198
|
+
|
|
199
|
+
if stream_id == -1
|
|
200
|
+
@handler.notify_event_listeners(response)
|
|
201
|
+
else
|
|
202
|
+
@handler.complete_request(stream_id, response)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def decode_response(opcode, protocol_version, buffer, size, trace_id)
|
|
207
|
+
case opcode
|
|
208
|
+
when 0x00 # ERROR
|
|
209
|
+
code = buffer.read_int
|
|
210
|
+
message = buffer.read_string
|
|
211
|
+
|
|
212
|
+
case code
|
|
213
|
+
when 0x1000
|
|
214
|
+
UnavailableErrorResponse.new(nil,
|
|
215
|
+
nil,
|
|
216
|
+
code,
|
|
217
|
+
message,
|
|
218
|
+
buffer.read_consistency,
|
|
219
|
+
buffer.read_int,
|
|
220
|
+
buffer.read_int)
|
|
221
|
+
when 0x1100
|
|
222
|
+
WriteTimeoutErrorResponse.new(nil,
|
|
223
|
+
nil,
|
|
224
|
+
code,
|
|
225
|
+
message,
|
|
226
|
+
buffer.read_consistency,
|
|
227
|
+
buffer.read_int,
|
|
228
|
+
buffer.read_int,
|
|
229
|
+
buffer.read_string)
|
|
230
|
+
when 0x1200
|
|
231
|
+
ReadTimeoutErrorResponse.new(nil,
|
|
232
|
+
nil,
|
|
233
|
+
code,
|
|
234
|
+
message,
|
|
235
|
+
buffer.read_consistency,
|
|
236
|
+
buffer.read_int,
|
|
237
|
+
buffer.read_int,
|
|
238
|
+
(buffer.read_byte != 0))
|
|
239
|
+
when 0x2400
|
|
240
|
+
AlreadyExistsErrorResponse.new(nil,
|
|
241
|
+
nil,
|
|
242
|
+
code,
|
|
243
|
+
message,
|
|
244
|
+
buffer.read_string,
|
|
245
|
+
buffer.read_string)
|
|
246
|
+
when 0x2500
|
|
247
|
+
UnpreparedErrorResponse.new(nil,
|
|
248
|
+
nil,
|
|
249
|
+
code,
|
|
250
|
+
message,
|
|
251
|
+
buffer.read_short_bytes)
|
|
252
|
+
else
|
|
253
|
+
ErrorResponse.new(nil, nil, code, message)
|
|
254
|
+
end
|
|
255
|
+
when 0x02 # READY
|
|
256
|
+
READY
|
|
257
|
+
when 0x03 # AUTHENTICATE
|
|
258
|
+
AuthenticateResponse.new(buffer.read_string)
|
|
259
|
+
when 0x06 # SUPPORTED
|
|
260
|
+
SupportedResponse.new(buffer.read_string_multimap)
|
|
261
|
+
when 0x08 # RESULT
|
|
262
|
+
result_type = buffer.read_int
|
|
263
|
+
case result_type
|
|
264
|
+
when 0x0001 # Void
|
|
265
|
+
VoidResultResponse.new(nil, nil, trace_id)
|
|
266
|
+
when 0x0002 # Rows
|
|
267
|
+
original_buffer_length = buffer.length
|
|
268
|
+
column_specs, paging_state = Coder.read_metadata_v3(buffer)
|
|
269
|
+
|
|
270
|
+
if column_specs.nil?
|
|
271
|
+
consumed_bytes = original_buffer_length - buffer.length
|
|
272
|
+
remaining_bytes =
|
|
273
|
+
CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
|
|
274
|
+
RawRowsResultResponse.new(nil,
|
|
275
|
+
nil,
|
|
276
|
+
protocol_version,
|
|
277
|
+
remaining_bytes,
|
|
278
|
+
paging_state,
|
|
279
|
+
trace_id,
|
|
280
|
+
nil)
|
|
281
|
+
else
|
|
282
|
+
RowsResultResponse.new(nil,
|
|
283
|
+
nil,
|
|
284
|
+
Coder.read_values_v3(buffer, column_specs),
|
|
285
|
+
column_specs,
|
|
286
|
+
paging_state,
|
|
287
|
+
trace_id)
|
|
288
|
+
end
|
|
289
|
+
when 0x0003 # SetKeyspace
|
|
290
|
+
SetKeyspaceResultResponse.new(nil, nil, buffer.read_string, trace_id)
|
|
291
|
+
when 0x0004 # Prepared
|
|
292
|
+
id = buffer.read_short_bytes
|
|
293
|
+
params_metadata = Coder.read_metadata_v3(buffer).first
|
|
294
|
+
result_metadata = nil
|
|
295
|
+
result_metadata = Coder.read_metadata_v3(buffer).first if protocol_version > 1
|
|
296
|
+
|
|
297
|
+
PreparedResultResponse.new(nil,
|
|
298
|
+
nil,
|
|
299
|
+
id,
|
|
300
|
+
params_metadata,
|
|
301
|
+
result_metadata,
|
|
302
|
+
nil,
|
|
303
|
+
trace_id)
|
|
304
|
+
when 0x0005 # SchemaChange
|
|
305
|
+
change = buffer.read_string
|
|
306
|
+
target = buffer.read_string
|
|
307
|
+
keyspace = buffer.read_string
|
|
308
|
+
arguments = EMPTY_LIST
|
|
309
|
+
name = nil
|
|
310
|
+
|
|
311
|
+
name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
|
|
312
|
+
|
|
313
|
+
SchemaChangeResultResponse.new(nil,
|
|
314
|
+
nil,
|
|
315
|
+
change,
|
|
316
|
+
keyspace,
|
|
317
|
+
name,
|
|
318
|
+
target,
|
|
319
|
+
arguments,
|
|
320
|
+
nil)
|
|
321
|
+
else
|
|
322
|
+
raise Errors::DecodingError,
|
|
323
|
+
"Unsupported result type: #{result_type.inspect}"
|
|
324
|
+
end
|
|
325
|
+
when 0x0C # EVENT
|
|
326
|
+
event_type = buffer.read_string
|
|
327
|
+
case event_type
|
|
328
|
+
when 'SCHEMA_CHANGE'
|
|
329
|
+
change = buffer.read_string
|
|
330
|
+
target = buffer.read_string
|
|
331
|
+
keyspace = buffer.read_string
|
|
332
|
+
name = nil
|
|
333
|
+
arguments = EMPTY_LIST
|
|
334
|
+
|
|
335
|
+
name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
|
|
336
|
+
|
|
337
|
+
SchemaChangeEventResponse.new(change, keyspace, name, target, arguments)
|
|
338
|
+
when 'STATUS_CHANGE'
|
|
339
|
+
StatusChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
|
|
340
|
+
when 'TOPOLOGY_CHANGE'
|
|
341
|
+
TopologyChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
|
|
342
|
+
else
|
|
343
|
+
raise Errors::DecodingError,
|
|
344
|
+
"Unsupported event type: #{event_type.inspect}"
|
|
345
|
+
end
|
|
346
|
+
when 0x0E # AUTH_CHALLENGE
|
|
347
|
+
AuthChallengeResponse.new(buffer.read_bytes)
|
|
348
|
+
when 0x10 # AUTH_SUCCESS
|
|
349
|
+
AuthSuccessResponse.new(buffer.read_bytes)
|
|
350
|
+
else
|
|
351
|
+
raise Errors::DecodingError,
|
|
352
|
+
"Unsupported response opcode: #{opcode.inspect}"
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|