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.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/README.md +242 -0
  4. data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
  5. data/ext/cassandra_murmur3/extconf.rb +2 -0
  6. data/lib/cassandra/address_resolution.rb +36 -0
  7. data/lib/cassandra/address_resolution/policies.rb +2 -0
  8. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
  9. data/lib/cassandra/address_resolution/policies/none.rb +35 -0
  10. data/lib/cassandra/aggregate.rb +123 -0
  11. data/lib/cassandra/argument.rb +51 -0
  12. data/lib/cassandra/attr_boolean.rb +33 -0
  13. data/lib/cassandra/auth.rb +100 -0
  14. data/lib/cassandra/auth/providers.rb +17 -0
  15. data/lib/cassandra/auth/providers/password.rb +65 -0
  16. data/lib/cassandra/cassandra_logger.rb +80 -0
  17. data/lib/cassandra/cluster.rb +331 -0
  18. data/lib/cassandra/cluster/client.rb +1612 -0
  19. data/lib/cassandra/cluster/connection_pool.rb +78 -0
  20. data/lib/cassandra/cluster/connector.rb +372 -0
  21. data/lib/cassandra/cluster/control_connection.rb +962 -0
  22. data/lib/cassandra/cluster/failed_connection.rb +35 -0
  23. data/lib/cassandra/cluster/metadata.rb +142 -0
  24. data/lib/cassandra/cluster/options.rb +145 -0
  25. data/lib/cassandra/cluster/registry.rb +284 -0
  26. data/lib/cassandra/cluster/schema.rb +405 -0
  27. data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
  28. data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
  29. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -0
  32. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  33. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -0
  36. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  37. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  38. data/lib/cassandra/column.rb +66 -0
  39. data/lib/cassandra/column_container.rb +326 -0
  40. data/lib/cassandra/compression.rb +69 -0
  41. data/lib/cassandra/compression/compressors/lz4.rb +73 -0
  42. data/lib/cassandra/compression/compressors/snappy.rb +69 -0
  43. data/lib/cassandra/custom_data.rb +53 -0
  44. data/lib/cassandra/driver.rb +260 -0
  45. data/lib/cassandra/errors.rb +784 -0
  46. data/lib/cassandra/execution/info.rb +69 -0
  47. data/lib/cassandra/execution/options.rb +267 -0
  48. data/lib/cassandra/execution/profile.rb +153 -0
  49. data/lib/cassandra/execution/profile_manager.rb +71 -0
  50. data/lib/cassandra/execution/trace.rb +192 -0
  51. data/lib/cassandra/executors.rb +113 -0
  52. data/lib/cassandra/function.rb +156 -0
  53. data/lib/cassandra/function_collection.rb +85 -0
  54. data/lib/cassandra/future.rb +794 -0
  55. data/lib/cassandra/host.rb +102 -0
  56. data/lib/cassandra/index.rb +118 -0
  57. data/lib/cassandra/keyspace.rb +473 -0
  58. data/lib/cassandra/listener.rb +87 -0
  59. data/lib/cassandra/load_balancing.rb +121 -0
  60. data/lib/cassandra/load_balancing/policies.rb +20 -0
  61. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
  62. data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
  63. data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
  64. data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
  65. data/lib/cassandra/materialized_view.rb +92 -0
  66. data/lib/cassandra/null_logger.rb +56 -0
  67. data/lib/cassandra/protocol.rb +102 -0
  68. data/lib/cassandra/protocol/coder.rb +1085 -0
  69. data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
  70. data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
  71. data/lib/cassandra/protocol/request.rb +41 -0
  72. data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
  73. data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
  74. data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
  75. data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
  76. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  77. data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
  78. data/lib/cassandra/protocol/requests/query_request.rb +112 -0
  79. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  80. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  81. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  82. data/lib/cassandra/protocol/response.rb +28 -0
  83. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
  84. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
  85. data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
  86. data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
  87. data/lib/cassandra/protocol/responses/error_response.rb +142 -0
  88. data/lib/cassandra/protocol/responses/event_response.rb +30 -0
  89. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
  90. data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
  91. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
  92. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
  93. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
  94. data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
  95. data/lib/cassandra/protocol/responses/result_response.rb +42 -0
  96. data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
  97. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
  98. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
  99. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
  100. data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
  101. data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
  102. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
  103. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
  104. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
  105. data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
  106. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
  107. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
  108. data/lib/cassandra/protocol/v1.rb +326 -0
  109. data/lib/cassandra/protocol/v3.rb +358 -0
  110. data/lib/cassandra/protocol/v4.rb +478 -0
  111. data/lib/cassandra/reconnection.rb +49 -0
  112. data/lib/cassandra/reconnection/policies.rb +20 -0
  113. data/lib/cassandra/reconnection/policies/constant.rb +46 -0
  114. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  115. data/lib/cassandra/result.rb +276 -0
  116. data/lib/cassandra/retry.rb +154 -0
  117. data/lib/cassandra/retry/policies.rb +21 -0
  118. data/lib/cassandra/retry/policies/default.rb +53 -0
  119. data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
  120. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  121. data/lib/cassandra/session.rb +270 -0
  122. data/lib/cassandra/statement.rb +32 -0
  123. data/lib/cassandra/statements.rb +23 -0
  124. data/lib/cassandra/statements/batch.rb +146 -0
  125. data/lib/cassandra/statements/bound.rb +65 -0
  126. data/lib/cassandra/statements/prepared.rb +235 -0
  127. data/lib/cassandra/statements/simple.rb +118 -0
  128. data/lib/cassandra/statements/void.rb +38 -0
  129. data/lib/cassandra/table.rb +240 -0
  130. data/lib/cassandra/time.rb +103 -0
  131. data/lib/cassandra/time_uuid.rb +78 -0
  132. data/lib/cassandra/timestamp_generator.rb +37 -0
  133. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  134. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  135. data/lib/cassandra/trigger.rb +67 -0
  136. data/lib/cassandra/tuple.rb +131 -0
  137. data/lib/cassandra/types.rb +1704 -0
  138. data/lib/cassandra/udt.rb +443 -0
  139. data/lib/cassandra/util.rb +464 -0
  140. data/lib/cassandra/uuid.rb +110 -0
  141. data/lib/cassandra/uuid/generator.rb +212 -0
  142. data/lib/cassandra/version.rb +21 -0
  143. data/lib/datastax/cassandra.rb +47 -0
  144. data/lib/ycql.rb +842 -0
  145. 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