Skip to content

Commit

Permalink
Fix validation error when repreparing queries (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
whatyouhide committed Oct 20, 2023
1 parent 032dc00 commit 9a4ddd7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
28 changes: 19 additions & 9 deletions lib/xandra.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1184,18 +1184,27 @@ defmodule Xandra do

## Helpers

defp reprepare_queries(conn, [%Simple{} | rest], options) do
reprepare_queries(conn, rest, options)
defp reprepare_queries(conn, queries, options) do
prepare_options =
options
|> Keyword.take(Keyword.keys(@prepare_opts_schema))
|> Keyword.put(:force, true)

{:ok, Enum.map(queries, &reprepare_query(conn, &1, prepare_options))}
catch
{:reprepare_error, error} ->
error
end

defp reprepare_queries(conn, [%Prepared{statement: statement} | rest], options) do
with {:ok, _prepared} <- prepare(conn, statement, Keyword.put(options, :force, true)) do
reprepare_queries(conn, rest, options)
end
defp reprepare_query(_conn, %Simple{} = query, _prepare_options) do
query
end

defp reprepare_queries(_conn, [], _options) do
:ok
defp reprepare_query(conn, %Prepared{statement: statement, values: values}, prepare_options) do
case prepare(conn, statement, prepare_options) do
{:ok, reprepared} -> %Prepared{reprepared | values: values}
other -> throw({:reprepare_error, other})
end
end

defp assert_valid_paging_state(options) do
Expand Down Expand Up @@ -1225,7 +1234,8 @@ defmodule Xandra do
defp execute_without_retrying(conn, %Batch{} = batch, nil, options) do
case Connection.execute(conn, batch, nil, options) do
{:error, %Error{reason: :unprepared}} ->
with :ok <- reprepare_queries(conn, batch.queries, options) do
with {:ok, queries} <- reprepare_queries(conn, batch.queries, options) do
batch = %Batch{batch | queries: queries}
execute(conn, batch, options)
end

Expand Down
25 changes: 25 additions & 0 deletions test/integration/batch_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,29 @@ defmodule BatchTest do

assert {:ok, %Page{}} = Xandra.execute(conn, batch)
end

# Regression for a bug we had (at Veeps) where we saw queries being reprepared, and
# Xandra would pass the execute/3 options down to prepare/3, which fails on validating
# most of those options.
test "if given prepared queries, potentially reprepares them", %{conn: conn, keyspace: keyspace} do
statement = "INSERT INTO #{keyspace}.users (id, name) VALUES (:id, :name)"
prepared_insert = Xandra.prepare!(conn, statement)

# Hacky, but works.
prepared_insert = %Xandra.Prepared{prepared_insert | id: "invalid", result_columns: nil}

batch =
Batch.new(:logged)
|> Batch.add(prepared_insert, [1, "Homer"])
|> Batch.add(prepared_insert, [2, "Marge"])

assert {:ok, %Void{}} = Xandra.execute(conn, batch)

{:ok, result} = Xandra.execute(conn, "SELECT name FROM users")

assert Enum.to_list(Enum.sort(result)) == [
%{"name" => "Homer"},
%{"name" => "Marge"}
]
end
end

0 comments on commit 9a4ddd7

Please sign in to comment.