cql-rb 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad8c87f3d7ccc81d5b43765b4702882db21aab6f
4
- data.tar.gz: c997140f2444a259a62c79a90118f7a1d634b3d1
3
+ metadata.gz: 076ceeab9f5eff0e9ab577f1e433b087342a8457
4
+ data.tar.gz: 049f3ecd2f935016bdd4bb08a87648163609600b
5
5
  SHA512:
6
- metadata.gz: d409efa148092c538432f7d7ad0aa19dfd72370e1596415c5a69a8bb7a9918d0a5ca674f29a24115aa7cc62945c41ac8278f87540bd5e20becaabcf5039cfc44
7
- data.tar.gz: ee05afbf07ba5453e50bdaffe3a3c761a4419285fb8132d2241b334e32c9f25ee4da2f527b100d6f58a0c3fcbd4f6b56de9de873d2a9bac54dc0486d5c1c4c6e
6
+ metadata.gz: e08c27d6a73bd4fc11573958ae2216affc238180d90d92c32aee98b20103a8614e6c1b693845b000c465b4ba9fd04b25c45a9ba012535a91e635974d832c66e5
7
+ data.tar.gz: 0e897851f1dab23f7eaa7ac1380071f4fa2bf0511a16911a5976156d197a533ba83b0fc05a2ee925050b9bc8b96f3ebf31a937158eddd222503b6e68c5343a7d
data/lib/cql.rb CHANGED
@@ -17,6 +17,7 @@ module Cql
17
17
  Io = Ione::Io
18
18
  end
19
19
 
20
+ require 'cql/error_codes'
20
21
  require 'cql/uuid'
21
22
  require 'cql/time_uuid'
22
23
  require 'cql/compression'
@@ -6,6 +6,8 @@ module Cql
6
6
  # if any. `message` contains the human readable error message sent by the
7
7
  # server.
8
8
  class QueryError < CqlError
9
+ include ErrorCodes
10
+
9
11
  attr_reader :code, :cql, :details
10
12
 
11
13
  def initialize(code, message, cql=nil, details=nil)
@@ -365,7 +365,7 @@ module Cql
365
365
  def connect_with_protocol_version_fallback
366
366
  f = create_cluster_connector.connect_all(@hosts, @connections_per_node)
367
367
  f.fallback do |error|
368
- if error.is_a?(QueryError) && error.code == 0x0a && @protocol_version > 1
368
+ if error.is_a?(QueryError) && error.code == QueryError::PROTOCOL_ERROR && @protocol_version > 1
369
369
  @logger.warn('Could not connect using protocol version %d (will try again with %d): %s' % [@protocol_version, @protocol_version - 1, error.message])
370
370
  @protocol_version -= 1
371
371
  connect_with_protocol_version_fallback
@@ -24,7 +24,7 @@ module Cql
24
24
  connected_connections = connections.select(&:connected?)
25
25
  if connected_connections.empty?
26
26
  e = connections.first.error
27
- if e.is_a?(Cql::QueryError) && e.code == 0x100
27
+ if e.is_a?(QueryError) && e.code == QueryError::BAD_CREDENTIALS
28
28
  e = AuthenticationError.new(e.message)
29
29
  end
30
30
  raise e
@@ -150,7 +150,13 @@ module Cql
150
150
  def execute(*args)
151
151
  connection = @connection_manager.random_connection
152
152
  if connection[self]
153
- run(args, connection)
153
+ f = run(args, connection)
154
+ f.fallback do |e|
155
+ raise e unless e.is_a?(QueryError) && e.code == QueryError::UNPREPARED
156
+ prepare(connection).flat_map do
157
+ run(args, connection)
158
+ end
159
+ end
154
160
  else
155
161
  prepare(connection).flat_map do
156
162
  run(args, connection)
@@ -216,11 +222,12 @@ module Cql
216
222
  private
217
223
 
218
224
  def run(args, connection)
219
- bound_args = args.shift(@raw_metadata.size)
220
- unless bound_args.size == @raw_metadata.size && args.size <= 1
225
+ bound_args = args.take(@raw_metadata.size)
226
+ remaining_args = args.drop(@raw_metadata.size)
227
+ unless bound_args.size == @raw_metadata.size && remaining_args.size <= 1
221
228
  raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
222
229
  end
223
- options = @execute_options_decoder.decode_options(args.last)
230
+ options = @execute_options_decoder.decode_options(remaining_args.last)
224
231
  statement_id = connection[self]
225
232
  request_metadata = @raw_result_metadata.nil?
226
233
  request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, request_metadata, options[:consistency], options[:serial_consistency], options[:page_size], options[:paging_state], options[:trace])
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module ErrorCodes
5
+ # Something unexpected happened. This indicates a server-side bug.
6
+ SERVER_ERROR = 0x0000
7
+
8
+ # Some client message triggered a protocol violation (for instance a QUERY
9
+ # message is sent before a STARTUP one has been sent).
10
+ PROTOCOL_ERROR = 0x000A
11
+
12
+ # CREDENTIALS request failed because Cassandra did not accept the provided credentials.
13
+ BAD_CREDENTIALS = 0x0100
14
+
15
+ # Unavailable exception.
16
+ #
17
+ # Details:
18
+ #
19
+ # * `:cl` - The consistency level of the query having triggered the exception.
20
+ # * `:required` - An int representing the number of nodes that should be alive to respect `:cl`.
21
+ # * `:alive` - An int representing the number of replica that were known to be
22
+ # alive when the request has been processed (since an unavailable
23
+ # exception has been triggered, there will be `:alive` < `:required`.
24
+ UNAVAILABLE = 0x1000
25
+
26
+ # The request cannot be processed because the coordinator node is overloaded.
27
+ OVERLOADED = 0x1001
28
+
29
+ # The request was a read request but the coordinator node is bootstrapping.
30
+ IS_BOOTSTRAPPING = 0x1002
31
+
32
+ # Error during a truncation error.
33
+ TRUNCATE_ERROR = 0x1003
34
+
35
+ # Timeout exception during a write request.
36
+ #
37
+ # Details:
38
+ #
39
+ # * `:cl` - The consistency level of the query having triggered the exception.
40
+ # * `:received` - An int representing the number of nodes having acknowledged the request.
41
+ # * `:blockfor` - The number of replica whose acknowledgement is required to achieve `:cl`.
42
+ # * `:write_type` - A string that describe the type of the write that timeouted. The value of that string can be one of:
43
+ # - `"SIMPLE"`: the write was a non-batched non-counter write.
44
+ # - `"BATCH"`: the write was a (logged) batch write. If this type is received, it means the batch log
45
+ # has been successfully written (otherwise a `"BATCH_LOG"` type would have been send instead).
46
+ # - `"UNLOGGED_BATCH"`: the write was an unlogged batch. Not batch log write has been attempted.
47
+ # - `"COUNTER"`: the write was a counter write (batched or not).
48
+ # - `"BATCH_LOG"`: the timeout occured during the write to the batch log when a (logged) batch write was requested.
49
+ WRITE_TIMEOUT = 0x1100
50
+
51
+ # Timeout exception during a read request.
52
+ #
53
+ # Details:
54
+ #
55
+ # * `:cl` - The consistency level of the query having triggered the exception
56
+ # * `:received` - An int representing the number of nodes having answered the request.
57
+ # * `:blockfor` - The number of replica whose response is required to achieve `:cl`.
58
+ # Please note that it is possible to have `:received` >= `:blockfor` if
59
+ # `:data_present` is false. And also in the (unlikely) case were `:cl` is
60
+ # achieved but the coordinator node timeout while waiting for read-repair
61
+ # acknowledgement.
62
+ # * `:data_present` - If `true`, it means the replica that was asked for data has not responded.
63
+ READ_TIMEOUT = 0x1200
64
+
65
+ # The submitted query has a syntax error.
66
+ SYNTAX_ERROR = 0x2000
67
+
68
+ # The logged user doesn't have the right to perform the query.
69
+ UNAUTHORIZED = 0x2100
70
+
71
+ # The query is syntactically correct but invalid.
72
+ INVALID = 0x2200
73
+
74
+ # The query is invalid because of some configuration issue.
75
+ CONFIG_ERROR = 0x2300
76
+
77
+ # The query attempted to create a keyspace or a table that was already existing.
78
+ #
79
+ # Details:
80
+ #
81
+ # * `:ks` - A string representing either the keyspace that already exists, or the
82
+ # keyspace in which the table that already exists is.
83
+ # * `:table` - A string representing the name of the table that already exists. If the
84
+ # query was attempting to create a keyspace, `:table` will be present but
85
+ # will be the empty string.
86
+ ALREADY_EXISTS = 0x2400
87
+
88
+ # Can be thrown while a prepared statement tries to be executed if the
89
+ # provide prepared statement ID is not known by this host.
90
+ #
91
+ # Details:
92
+ #
93
+ # * `:id` - The unknown ID.
94
+ UNPREPARED = 0x2500
95
+ end
96
+ end
@@ -13,24 +13,24 @@ module Cql
13
13
  def self.decode(code, message, protocol_version, buffer, length, trace_id=nil)
14
14
  details = {}
15
15
  case code
16
- when 0x1000 # unavailable
16
+ when UNAVAILABLE
17
17
  details[:cl] = buffer.read_consistency
18
18
  details[:required] = buffer.read_int
19
19
  details[:alive] = buffer.read_int
20
- when 0x1100 # write_timeout
20
+ when WRITE_TIMEOUT
21
21
  details[:cl] = buffer.read_consistency
22
22
  details[:received] = buffer.read_int
23
23
  details[:blockfor] = buffer.read_int
24
24
  details[:write_type] = buffer.read_string
25
- when 0x1200 # read_timeout
25
+ when READ_TIMEOUT
26
26
  details[:cl] = buffer.read_consistency
27
27
  details[:received] = buffer.read_int
28
28
  details[:blockfor] = buffer.read_int
29
29
  details[:data_present] = buffer.read_byte != 0
30
- when 0x2400 # already_exists
30
+ when ALREADY_EXISTS
31
31
  details[:ks] = buffer.read_string
32
32
  details[:table] = buffer.read_string
33
- when 0x2500
33
+ when UNPREPARED
34
34
  details[:id] = buffer.read_short_bytes
35
35
  end
36
36
  new(code, message, details)
@@ -3,6 +3,8 @@
3
3
  module Cql
4
4
  module Protocol
5
5
  class ErrorResponse < Response
6
+ include ErrorCodes
7
+
6
8
  attr_reader :code, :message
7
9
 
8
10
  def initialize(*args)
@@ -13,7 +15,7 @@ module Cql
13
15
  code = buffer.read_int
14
16
  message = buffer.read_string
15
17
  case code
16
- when 0x1000, 0x1100, 0x1200, 0x2400, 0x2500
18
+ when UNAVAILABLE, WRITE_TIMEOUT, READ_TIMEOUT, ALREADY_EXISTS, UNPREPARED
17
19
  new_length = length - 4 - 4 - message.bytesize
18
20
  DetailedErrorResponse.decode(code, message, protocol_version, buffer, new_length)
19
21
  else
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Cql
4
- VERSION = '2.0.4'.freeze
4
+ VERSION = '2.0.5'.freeze
5
5
  end
@@ -295,6 +295,25 @@ module Cql
295
295
  statement.execute(11, 'hello', trace: true).value
296
296
  tracing.should be_true
297
297
  end
298
+
299
+ it 'prepares the statement again when it is lost' do
300
+ prepare_requests = 0
301
+ connections.each do |c|
302
+ c[:num_prepare] = 0
303
+ c.handle_request do |r, t|
304
+ if r.is_a?(Protocol::ExecuteRequest) && c[:num_prepare] == 1
305
+ Protocol::ErrorResponse.new(0x2500, 'Unprepared')
306
+ else
307
+ if r == Protocol::PrepareRequest.new(cql)
308
+ c[:num_prepare] += 1
309
+ end
310
+ handle_request(c, r, t)
311
+ end
312
+ end
313
+ end
314
+ statement.execute(11, 'hello').value
315
+ connections.map { |c| c[:num_prepare] }.should include(2)
316
+ end
298
317
  end
299
318
 
300
319
  describe '#batch' do
@@ -108,6 +108,13 @@ describe 'A CQL client' do
108
108
  counters = result.each_with_object({}) { |row, acc| acc[row['id']] = row['count'] }
109
109
  counters.should eql('foo' => 11, 'bar' => 3)
110
110
  end
111
+
112
+ it 'handles altered tables' do
113
+ result1 = statement.execute('sue')
114
+ client.execute('ALTER TABLE users ADD password VARCHAR')
115
+ result2 = statement.execute('sue')
116
+ result2.to_a.should eql(result1.to_a)
117
+ end
111
118
  end
112
119
 
113
120
  context 'with multiple connections' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo Hultberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-26 00:00:00.000000000 Z
11
+ date: 2015-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ione
@@ -54,6 +54,7 @@ files:
54
54
  - lib/cql/compression.rb
55
55
  - lib/cql/compression/lz4_compressor.rb
56
56
  - lib/cql/compression/snappy_compressor.rb
57
+ - lib/cql/error_codes.rb
57
58
  - lib/cql/protocol.rb
58
59
  - lib/cql/protocol/cql_byte_buffer.rb
59
60
  - lib/cql/protocol/cql_protocol_handler.rb