sqlitex v1.2.0 Sqlitex.Statement

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. 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.

Example

iex(2)> {:ok, db} = Sqlitex.open(":memory:")
iex(3)> Sqlitex.query(db, "CREATE TABLE data (id, name);")
{:ok, []}
iex(4)> {:ok, statement} = Sqlitex.Statement.prepare(db, "INSERT INTO data VALUES (?, ?);")
iex(5)> Sqlitex.Statement.bind_values(statement, [1, "hello"])
iex(6)> Sqlitex.Statement.exec(statement)
:ok
iex(7)> {:ok, statement} = Sqlitex.Statement.prepare(db, "SELECT * FROM data;")
iex(8)> Sqlitex.Statement.fetch_all(statement)
{:ok, [[id: 1, name: "hello"]]}
iex(9)> Sqlitex.close(db)
:ok

RETURNING Clause Support

SQLite does not support the RETURNING extension to INSERT, DELETE, and UPDATE commands. (See https://www.postgresql.org/docs/9.6/static/sql-insert.html for a description of the Postgres implementation of this clause.)

Ecto 2.0+ relies on being able to capture this information, so have invented our own implementation with the following syntax:

;--RETURNING ON [INSERT | UPDATE | DELETE] <table>,<col>,<col>,...

When the prepare/2 and prepare!/2 functions are given a query that contains the above returning clause, they separate this clause from the end of the query and store it separately in the Statement struct. Only the portion of the query preceding the returning clause is passed to SQLite’s prepare function.

Later, when such a statement struct is passed to fetch_all/2 or fetch_all!/2 the returning clause is parsed and the query is performed with the following additional logic:

SAVEPOINT sp_<random>;
CREATE TEMP TABLE temp.t_<random> (<returning>);
CREATE TEMP TRIGGER tr_<random> AFTER UPDATE ON main.<table> BEGIN
    INSERT INTO t_<random> SELECT NEW.<returning>;
END;
UPDATE ...; -- whatever the original statement was
DROP TRIGGER tr_<random>;
SELECT <returning> FROM temp.t_<random>;
DROP TABLE temp.t_<random>;
RELEASE sp_<random>;

A more detailed description of the motivations for making this change is here: https://github.com/jazzyb/sqlite_ecto/wiki/Sqlite.Ecto’s-Pseudo-Returning-Clause

Summary

Functions

Binds values to a Sqlitex.Statement

Same as bind_values/2 but raises a Sqlitex.Statement.BindValuesError on error

Runs a statement that returns no results

Same as exec/1 but raises a Sqlitex.Statement.ExecError on error

Fetches all rows using a statement

Same as fetch_all/2 but raises a Sqlitex.Statement.FetchAllError on error

Prepare a Sqlitex.Statement

Same as prepare/2 but raises a Sqlitex.Statement.PrepareError on error

Functions

bind_values(statement, values)

Binds values to a Sqlitex.Statement

Parameters

  • statement - The statement to bind values into.
  • values - A list of values to bind into the statement.

Returns

  • {:ok, statement} on success
  • See :esqlite3.prepare for errors.

Value transformations

Some values will be transformed before insertion into the database.

  • nil - Converted to :undefined
  • true - Converted to 1
  • false - Converted to 0
  • datetime - Converted into a string. See datetime_to_string
  • %Decimal - Converted into a number.
bind_values!(statement, values)

Same as bind_values/2 but raises a Sqlitex.Statement.BindValuesError on error.

Returns the statement otherwise.

exec(statement)

Runs a statement that returns no results.

Should be called after the statement has been bound.

Parameters

  • statement - The statement to run.

Returns

  • :ok
  • {:error, error}
exec!(statement)

Same as exec/1 but raises a Sqlitex.Statement.ExecError on error.

Returns :ok otherwise.

fetch_all(statement, into \\ [])

Fetches all rows using a statement.

Should be called after the statement has been bound.

Parameters

  • statement - The statement to run.
  • into - The collection to put the results into. Defaults to an empty list.

Returns

  • {:ok, results}
  • {:error, error}
fetch_all!(statement, into \\ [])

Same as fetch_all/2 but raises a Sqlitex.Statement.FetchAllError on error.

Returns the results otherwise.

prepare(db, sql)

Prepare a Sqlitex.Statement

Parameters

  • db - The database to prepare the statement for.
  • sql - The SQL of the statement to prepare.

Returns

  • {:ok, statement} on success
  • See :esqlite3.prepare for errors.
prepare!(db, sql)

Same as prepare/2 but raises a Sqlitex.Statement.PrepareError on error.

Returns a new statement otherwise.

time_to_string(arg)