Sqlcx.Statement (sqlcx v2.0.0-rc.1) View Source
Provides an interface for working with SQLite prepared statements.
Care should be taken when using prepared statements directly – they are not
immutable objects like most things in Elixir. Statements have internal states
in sqlite3/sqlcipher, such as bound arguments and returned rows. For instance,
if you call fetch_one/2
multiple times, the next row will be returned each
time, not the same one for all calls. Thus, sharing a statement between
different processes can cause problems if the processes accidentally
interleave operations on the statement. It's a good idea to create different
statements per process, or to wrap the statements up in a GenServer to prevent
interleaving operations.
See bind/3
for allowed parameter formats.
Example
iex> {:ok, db} = Sqlcx.open(":memory:")
iex> Sqlcx.query(db, "CREATE TABLE data (id, name);")
{:ok, []}
iex> {:ok, statement} = Sqlcx.Statement.prepare(db, "INSERT INTO data VALUES (?, ?);")
iex> Sqlcx.Statement.bind(statement, [1, "hello"])
iex> Sqlcx.Statement.exec(statement)
:ok
iex> {:ok, statement} = Sqlcx.Statement.prepare(db, "SELECT * FROM data;")
iex> Sqlcx.Statement.fetch_all(statement, db_timeout: 1_000)
{:ok, [[1, "hello"]]}
iex> Sqlcx.close(db)
:ok
RETURNING Clause Support
Since version 3.35.0, SQLite natively support the RETURNING extension to INSERT, DELETE, and UPDATE commands required by Ecto (see https://www.sqlite.org/lang_returning.html). Thus, we were able to drop the previous workaround.
Link to this section Summary
Functions
Binds values to a prepared statement.
Same as bind/3
but raises a Sqlcx.Statement.BindError
on error.
Returns a {:"$blob", data}
tuple for use with bind/3
Runs a statement that returns no results.
Same as exec/2
but raises a Sqlcx.Statement.ExecError on error.
Fetches all rows using a statement.
Same as fetch_all/2
but raises a Sqlcx.Statement.FetchError on error.
Fetches a single row using a statement. See fetch_all/2
for parameters.
Same as fetch_one/2
but raises a Sqlcx.Statement.FetchError on error.
Prepare a Sqlcx.Statement
Same as prepare/3
but raises a Sqlcx.Statement.PrepareError on error.
Same as prepare_bind/4
but raises an Sqlcx.Statement.PrepareError
or
Sqlcx.Statement.BindError
on error.
Reset the prepared statement back to its initial state.
Same as reset/3
but raises an Sqlcx.Statement.ResetError
on error.
Link to this section Types
Specs
bind_value() :: sql_value() | {pos_integer() | atom(), sql_value()}
Specs
exec_options() :: [{:db_timeout, timeout()}]
Specs
fetch_options(collection) :: [ db_timeout: timeout(), db_chunk_size: pos_integer(), into: collection, atomic_names: boolean() ]
Specs
prepare_options() :: [{:db_timeout, timeout()}]
Specs
Specs
statement()
Specs
t() :: %Sqlcx.Statement{ column_names: nil | [String.t()], column_types: nil | [String.t()], database: Sqlcx.connection(), statement: statement() }
Link to this section Functions
Specs
bind(t(), [bind_value()], [{:db_timeout, timeout()}]) :: {:ok, t()} | Sqlcx.error()
Binds values to a prepared statement.
All forms of parameters in SQL statements supported by sqlite3 are supported (see also sqlite3 docs):
?
: Unnamed/anonymous parameters (these will implicitly be assigned a number that is the previously largest assigned number + 1; numbering begins at 1),?NNN
, where 1 ≤NNN
≤ 32766: Numbered parameters, and:AAA
, whereAAA
is an alphanumeric identifier (e.g.,:my_param_value
). These will internally be assigned a number similarly to anonymous parameters, so do not mix named and numbered parameters or you will probably get unexpected results.
NB: Sqlite3 also supports the forms@AAA
and$AAA
but since the initial character (@
/$
) is part of the name, you would actually need to pass{:"@name", value}
or{:"$name", value}
.{:name, value}
is automatically interpreted as{:":name", value}
, so the:AAA
form should be preferred. Do not use$blob
as a parameter name since{:"$blob", _}
tuples will be interpreted as the sqliteBLOB
datatype. Do not use non-ASCII characters in parameter names.
Anonymous parameters of the form ?
are discouraged; prefer named or
numbered parameters.
Values
All sqlite3 data types are supported. The following values can be bound to a prepared statement:
nil
(aka:nil
), which will be transformed to SQLNULL
- Integers (
integer/0
) - Floats (
float/0
) - Strings (
String.t/0
): UTF-8-encoded strings of any length - Blobs (binaries,
binary/0
): Use{:"$blob", <<...>>}
(orblob/1
)
Note that sqlite3 does not have a boolean data type. Use integers 0 and 1.
Values are translated between Elixir and sqlite3 data types when bind
ing or
fetch
ing. Trying to bind
any other types, such as atoms or booleans, will
result in an error. Also not that sqlite3 is dynamically typed, so a column may
contain values of different types (and the declared column type doesn't
actually matter).
See also :esqlcipher.bind/3
Function parameters
bind/3
accepts the following arguments:
statement
- The statement to bind values into.values
- A list of values to bind to the statement. The list can contain either anonymous values (e.g.,[42, "foo", nil]
) or key–value tuples with numbers (e.g.,[{1, 42}, {5, "foo"}]
) or atoms as keys (e.g.,[{:foo, 42}, {:bar, "baz"}]
, which is of course equivalent to[foo: 42, bar: "baz"]
). These keys correspond to anonymous, numbered, or named parameters in SQL statements. These three types can but should not be mixed. If thevalues
list contains anonymous values without keys, these are internally numbered similarly to the internal sqlite3 parameter numbering scheme described above (i.e., starting at 1).
If a parameter from the SQL statement is missing in the value list, it will be silently bound asNULL
.
Also accepts the following keyword option:
db_timeout
– timeout in ms for thebind
command to run. Defaults to5000
, or the:db_timeout
application config value.
Returns
{:ok, statement}
on success{:error, {type, reason}}
for any errors (seeSqlcx.error/0
).
Unlike most Elixir objects, Sqlite3 statements are not immutable but have a
state. The statement
that this function returns is the exact same object as
the statement
parameter you pass as the first argument.
Specs
bind!(t(), [bind_value()], [{:db_timeout, timeout()}]) :: t()
Same as bind/3
but raises a Sqlcx.Statement.BindError
on error.
Returns the statement otherwise.
Specs
Returns a {:"$blob", data}
tuple for use with bind/3
Specs
exec(t(), exec_options()) :: :ok | Sqlcx.error()
Runs a statement that returns no results.
Should be called after the statement has been bound.
Parameters
statement
- The statement to run.
Also accepts the following keyword options:
db_timeout
- The time in ms allowed for the statement to run. Defaults to 5000, or the :db_timeout value in application config.
Returns
:ok
{:error, {type, reason}}
Specs
exec!(t(), exec_options()) :: :ok
Same as exec/2
but raises a Sqlcx.Statement.ExecError on error.
Returns :ok otherwise.
Specs
fetch_all(t(), fetch_options(collection)) :: {:ok, [collection]} | Sqlcx.error() when collection: Collectable.t()
fetch_all(t(), fetch_options(nil)) :: {:ok, [[sql_value()]]} | Sqlcx.error()
Fetches all rows using a statement.
Should be called after the statement has been bound.
Parameters
statement
- The statement to run.
Also accepts the following keyword options:
into
- The collection to put each row into. If provided, values arezip
ed with the column names, sointo: %{}
produces a Map (note that column names are Strings, not atoms). Defaults tonil
which simply outputs each row as a list of values without any column names.atomic_names
- Whether column names should be output as atoms instead of strings. Only has an effect wheninto
is also given since otherwise no column names are output at all. Iftrue
, the output might look like[%{foo: 1, bar: 2}]
instead of[%{"foo" => 1, "bar" => 2}]
(withinto: %{}
). Defaults tofalse
.db_timeout
- The time in ms allowed for each sqlite3 command to run. Defaults to 5000 ms, or the:db_timeout
value in application config. Note that the actual timeout may be many times larger because the timeout is applied to each internal fetch call individually.db_chunk_size
- The internal bulk size (rows are fetched in bulks with each individual fetch call having a timeout ofdb_timeout
). Defaults to 5000, or the:db_chunk_size
value in the application config.
Returns
{:ok, results}
on success{:error, {type, reason}}
for any errors (seeSqlcx.error/0
).
Specs
fetch_all!(t(), fetch_options(collection)) :: [collection] when collection: Collectable.t()
fetch_all!(t(), fetch_options(nil)) :: [[sql_value()]]
Same as fetch_all/2
but raises a Sqlcx.Statement.FetchError on error.
Returns the results otherwise.
Specs
fetch_one(t(), fetch_options(collection)) :: {:ok, collection} when collection: Collectable.t()
Fetches a single row using a statement. See fetch_all/2
for parameters.
Note that statements are not immutable objects! fetch_one
will return
subsequent rows if called on the same statement multiple times.
Specs
fetch_one!(t(), fetch_options(collection)) :: [collection] when collection: Collectable.t()
fetch_one!(t(), fetch_options(nil)) :: [[sql_value()]]
Same as fetch_one/2
but raises a Sqlcx.Statement.FetchError on error.
Returns the result otherwise.
Specs
prepare(Sqlcx.connection(), String.t(), prepare_options()) :: {:ok, t()} | Sqlcx.error()
Prepare a Sqlcx.Statement
Parameters
db
- The database to prepare the statement for.sql
- The SQL of the statement to prepare.
Also accepts the following keyword options:
db_timeout
– timeout in ms for theesqlcipher
commands involved in preparing the statement and binding values to it. Defaults to5000
, or the:db_timeout
application config value.
Returns
{:ok, statement}
on success{:error, {type, reason}}
for any errors (seet:Sqlcx.error()
).
Specs
prepare!(Sqlcx.connection(), String.t(), prepare_options()) :: t()
Same as prepare/3
but raises a Sqlcx.Statement.PrepareError on error.
Returns a new statement otherwise.
Specs
prepare_bind(Sqlcx.connection(), String.t(), [bind_value()], prepare_options()) :: {:ok, t()} | Sqlcx.error()
Specs
prepare_bind!(Sqlcx.connection(), String.t(), [bind_value()], prepare_options()) :: t()
Same as prepare_bind/4
but raises an Sqlcx.Statement.PrepareError
or
Sqlcx.Statement.BindError
on error.
Specs
reset(t()) :: {:ok, t()} | Sqlcx.error()
reset(t()) :: {:ok, t()} | Sqlcx.error()
Reset the prepared statement back to its initial state.
Once the statement has been reset, you can run it once more. By default, any
values bound to the statement will be retained. Set clear_bindings' to
true'
to change this.
Parameters
clear_bindings
- Whether to clear values bound to the statement
Also accepts the following keyword options:
db_timeout
– timeout in ms for thereset
command to run. Defaults to5000
, or the:db_timeout
application config value.
Returns
{:ok, statement}
on success{:error, {type, reason}}
for any errors (seeSqlcx.error/0
).
Specs
reset(t(), boolean() | [{:db_timeout, timeout()}]) :: {:ok, t()} | Sqlcx.error()
reset(t(), boolean() | [{:db_timeout, timeout()}]) :: {:ok, t()} | Sqlcx.error()
Specs
reset(t(), boolean(), [{:db_timeout, timeout()}]) :: {:ok, t()} | Sqlcx.error()
reset(t(), boolean(), [{:db_timeout, timeout()}]) :: {:ok, t()} | Sqlcx.error()
Same as reset/3
but raises an Sqlcx.Statement.ResetError
on error.