Skip to content

Commit c443284

Browse files
Replicate seg fault (#191)
* Replicate seg fault * Insert in one query * Add check for statement and its member element presence * Handle situation where the connection's db is not set Co-authored-by: Matthew Johnston <warmwaffles@gmail.com>
1 parent 0008856 commit c443284

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

c_src/sqlite3_nif.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ exqlite_multi_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
470470
return make_error_tuple(env, "invalid_statement");
471471
}
472472

473+
if (!statement || !statement->statement) {
474+
return make_error_tuple(env, "invalid_statement");
475+
}
476+
473477
if (!enif_get_int(env, argv[2], &chunk_size)) {
474478
return make_error_tuple(env, "invalid_chunk_size");
475479
}
@@ -627,6 +631,13 @@ exqlite_transaction_status(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
627631
return make_error_tuple(env, "invalid_connection");
628632
}
629633

634+
// If the connection times out, DbConnection disconnects the client
635+
// and then re-opens a new connection. There is a condition where by
636+
// the connection's database is not set but the calling elixir / erlang
637+
// pass an incomplete reference.
638+
if (!conn->db) {
639+
return make_ok_tuple(env, make_atom(env, "error"));
640+
}
630641
int autocommit = sqlite3_get_autocommit(conn->db);
631642
return make_ok_tuple(
632643
env,

test/exqlite/integration_test.exs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule Exqlite.IntegrationTest do
22
use ExUnit.Case
33

4+
import ExUnit.CaptureLog
5+
46
alias Exqlite.Connection
57
alias Exqlite.Sqlite3
68
alias Exqlite.Query
@@ -169,4 +171,40 @@ defmodule Exqlite.IntegrationTest do
169171

170172
File.rm(path)
171173
end
174+
175+
test "exceeding timeout" do
176+
path = Temp.path!()
177+
178+
{:ok, conn} =
179+
DBConnection.start_link(Connection,
180+
idle_interval: 5_000,
181+
database: path,
182+
journal_mode: :wal,
183+
cache_size: -64_000,
184+
temp_store: :memory
185+
)
186+
187+
query = %Query{statement: "create table foo(id integer, val integer)"}
188+
{:ok, _, _} = DBConnection.execute(conn, query, [])
189+
190+
values = for i <- 1..10000, do: "(#{i}, #{i})"
191+
192+
query = %Query{
193+
statement: "insert into foo(id, val) values #{Enum.join(values, ",")}"
194+
}
195+
196+
{:ok, _, _} = DBConnection.execute(conn, query, [])
197+
198+
# Don't want to muddy the test output
199+
{_, log} =
200+
with_log(fn ->
201+
query = %Query{statement: "select * from foo"}
202+
{:ok, _, _} = DBConnection.execute(conn, query, [], timeout: 1)
203+
end)
204+
205+
# We want to ensure the timeout is logged
206+
assert log =~ "timed out"
207+
208+
File.rm(path)
209+
end
172210
end

0 commit comments

Comments
 (0)