Skip to content

Commit 0e90b8e

Browse files
committed
Add Elixir API for set_busy_timeout and cancel
- Add NIF stubs: set_busy_timeout/2, cancel/1 - Add public wrappers: Sqlite3.set_busy_timeout/2, Sqlite3.cancel/1 - cancel/1 includes nil guard (matches close/1 and interrupt/1 convention) - Fix bind_parameter_count/1 typespec: integer -> non_neg_integer() | {:error, reason()} - Fix bind_parameter_index/2 typespec: integer -> non_neg_integer() | {:error, reason()} The typespec fixes address pre-existing dialyzer warnings - both NIFs can return {:error, :invalid_statement} when statement->statement is NULL.
1 parent de700d3 commit 0e90b8e

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

lib/exqlite/sqlite3.ex

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,29 @@ defmodule Exqlite.Sqlite3 do
100100
def interrupt(nil), do: :ok
101101
def interrupt(conn), do: Sqlite3NIF.interrupt(conn)
102102

103+
@doc """
104+
Set the busy timeout in milliseconds without destroying the custom busy handler.
105+
106+
Unlike `PRAGMA busy_timeout` (which internally calls `sqlite3_busy_timeout()`
107+
and replaces any custom handler), this function only updates the timeout value
108+
that the custom busy handler reads. This preserves the ability to cancel
109+
busy waits via `cancel/1`.
110+
"""
111+
@spec set_busy_timeout(db(), integer()) :: :ok | {:error, reason()}
112+
def set_busy_timeout(conn, timeout_ms),
113+
do: Sqlite3NIF.set_busy_timeout(conn, timeout_ms)
114+
115+
@doc """
116+
Cancel a running query: wake any busy handler sleep and interrupt VDBE execution.
117+
118+
This is a superset of `interrupt/1` — it sets a cancel flag, signals the
119+
condvar to wake any busy handler sleep, AND calls `sqlite3_interrupt()`.
120+
After a cancel, the connection can be reused normally.
121+
"""
122+
@spec cancel(db() | nil) :: :ok | {:error, reason()}
123+
def cancel(nil), do: :ok
124+
def cancel(conn), do: Sqlite3NIF.cancel(conn)
125+
103126
@doc """
104127
Executes an sql script. Multiple stanzas can be passed at once.
105128
"""
@@ -136,7 +159,7 @@ defmodule Exqlite.Sqlite3 do
136159
2
137160
138161
"""
139-
@spec bind_parameter_count(statement) :: non_neg_integer | {:error, atom()}
162+
@spec bind_parameter_count(statement) :: non_neg_integer() | {:error, reason()}
140163
def bind_parameter_count(stmt), do: Sqlite3NIF.bind_parameter_count(stmt)
141164

142165
@type bind_value ::

lib/exqlite/sqlite3_nif.ex

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ defmodule Exqlite.Sqlite3NIF do
2626
@spec interrupt(db()) :: :ok | {:error, reason()}
2727
def interrupt(_conn), do: :erlang.nif_error(:not_loaded)
2828

29+
@spec set_busy_timeout(db(), integer()) :: :ok | {:error, reason()}
30+
def set_busy_timeout(_conn, _timeout_ms), do: :erlang.nif_error(:not_loaded)
31+
32+
@spec cancel(db()) :: :ok | {:error, reason()}
33+
def cancel(_conn), do: :erlang.nif_error(:not_loaded)
34+
2935
@spec execute(db(), String.t()) :: :ok | {:error, reason()}
3036
def execute(_conn, _sql), do: :erlang.nif_error(:not_loaded)
3137

@@ -69,10 +75,11 @@ defmodule Exqlite.Sqlite3NIF do
6975
@spec set_log_hook(pid()) :: :ok | {:error, reason()}
7076
def set_log_hook(_pid), do: :erlang.nif_error(:not_loaded)
7177

72-
@spec bind_parameter_count(statement) :: integer
78+
@spec bind_parameter_count(statement) :: non_neg_integer() | {:error, reason()}
7379
def bind_parameter_count(_stmt), do: :erlang.nif_error(:not_loaded)
7480

75-
@spec bind_parameter_index(statement, String.t()) :: integer
81+
@spec bind_parameter_index(statement, String.t()) ::
82+
non_neg_integer() | {:error, reason()}
7683
def bind_parameter_index(_stmt, _name), do: :erlang.nif_error(:not_loaded)
7784

7885
@spec bind_text(statement, non_neg_integer, String.t()) :: integer()

0 commit comments

Comments
 (0)