Skip to content
This repository has been archived by the owner on Jan 2, 2023. It is now read-only.

Commit

Permalink
Prepare statement again when it is lost
Browse files Browse the repository at this point in the history
If an ALTER TABLE is performed the prepared statements are lost. In this case the statement should be prepared again.
  • Loading branch information
stenlarsson committed Jul 15, 2015
1 parent 050c9ef commit cd1e9f4
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
15 changes: 11 additions & 4 deletions lib/cql/client/prepared_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,13 @@ def self.prepare(cql, execute_options_decoder, connection_manager, logger)
def execute(*args)
connection = @connection_manager.random_connection
if connection[self]
run(args, connection)
f = run(args, connection)
f.fallback do |e|
raise e unless e.is_a?(Cql::QueryError) && e.code == 0x2500 # unprepared
prepare(connection).flat_map do
run(args, connection)
end
end
else
prepare(connection).flat_map do
run(args, connection)
Expand Down Expand Up @@ -216,11 +222,12 @@ def add_to_batch(batch, connection, bound_args)
private

def run(args, connection)
bound_args = args.shift(@raw_metadata.size)
unless bound_args.size == @raw_metadata.size && args.size <= 1
bound_args = args.take(@raw_metadata.size)
remaining_args = args.drop(@raw_metadata.size)
unless bound_args.size == @raw_metadata.size && remaining_args.size <= 1
raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
end
options = @execute_options_decoder.decode_options(args.last)
options = @execute_options_decoder.decode_options(remaining_args.last)
statement_id = connection[self]
request_metadata = @raw_result_metadata.nil?
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])
Expand Down
19 changes: 19 additions & 0 deletions spec/cql/client/prepared_statement_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,25 @@ def handle_request(connection, request, timeout)
statement.execute(11, 'hello', trace: true).value
tracing.should be_true
end

it 'prepares statement again when it is lost' do
prepare_requests = 0
connections.each do |c|
c[:num_prepare] = 0
c.handle_request do |r, t|
if r.is_a?(Protocol::ExecuteRequest) && c[:num_prepare] == 1
Protocol::ErrorResponse.new(0x2500, 'Unprepared')
else
if r == Protocol::PrepareRequest.new(cql)
c[:num_prepare] += 1
end
handle_request(c, r, t)
end
end
end
statement.execute(11, 'hello').value
connections.map { |c| c[:num_prepare] }.should include(2)
end
end

describe '#batch' do
Expand Down
7 changes: 7 additions & 0 deletions spec/integration/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ def create_keyspace_and_table
counters = result.each_with_object({}) { |row, acc| acc[row['id']] = row['count'] }
counters.should eql('foo' => 11, 'bar' => 3)
end

it 'handles altered tables' do
result1 = statement.execute('sue')
client.execute('ALTER TABLE users ADD password VARCHAR')
result2 = statement.execute('sue')
result2.to_a.should eql(result1.to_a)
end
end

context 'with multiple connections' do
Expand Down

0 comments on commit cd1e9f4

Please sign in to comment.