XqliteNIF (Xqlite v0.7.0)
View SourceLow-level Native Implemented Functions (NIFs) for interacting with SQLite.
This module provides direct, performant access to SQLite operations, powered by
Rust and the rusqlite crate. It forms the foundation of the Xqlite library.
Connection lifecycle:
- Open a database connection using
open/2,open_in_memory/1, oropen_temporary/0. These return an opaque connection resource (Xqlite.conn/0). - Perform operations (queries, executes, pragmas, etc.) using this resource.
- Conceptually close the connection with
close/1when done.
Operation cancellation:
For long-running queries or executions, cancellable versions of NIFs are provided
(e.g., query_cancellable/4, execute_cancellable/4):
- Create a
reference/0token withcreate_cancel_token/0. - Pass this token to a cancellable NIF.
- To interrupt the NIF, call
cancel_operation/1with the token from another process. The NIF will then typically return{:error, :operation_cancelled}.
Error handling:
Most functions return {:ok, value} or :ok on success, and
{:error, reason_tuple} on failure. The reason_tuple provides structured
error information (e.g., {:sqlite_failure, code, extended_code, message}).
Usage note:
These are low-level functions. For more idiomatic Elixir usage, consider
the helper functions in the Xqlite module or higher-level abstractions
if available (e.g., an Ecto adapter). This module is intended for direct
SQLite control or for building such abstractions.
Summary
Functions
Returns true when conn is in auto-commit mode (no active transaction),
false otherwise.
Backs up the named schema to a file at dest_path.
Backs up a database to a file with progress reporting and cancellation.
Begins a new database transaction with the given mode.
Closes the blob handle, releasing its resources.
Opens a BLOB for incremental I/O.
Reads length bytes from the blob starting at offset.
Moves the blob handle to a different row in the same table/column.
Returns the size of the blob in bytes.
Writes data to the blob starting at offset.
Signals an intent to cancel operations associated with a given cancellation token.
Returns the number of rows modified, inserted, or deleted by the most
recently completed INSERT, UPDATE, or DELETE statement on this
connection. Does not count changes from triggers or foreign key actions.
Applies a changeset binary to a connection.
Concatenates two changeset binaries into one.
Inverts a changeset binary.
Conceptually closes the database connection.
Commits the current database transaction.
Retrieves the compile-time options the linked SQLite C library was built with.
Returns a structured snapshot of sqlite3_db_status counters for the
connection.
Creates a new cancellation token resource.
Deserializes a binary into the named schema, replacing its contents.
Enables or disables extension loading for the given connection.
Executes a SQL statement that does not return rows (e.g., INSERT, UPDATE, DELETE, DDL).
Executes one or more SQL statements separated by semicolons.
Executes one or more SQL statements separated by semicolons, with support for cancellation.
Executes a SQL statement that does not return rows, with support for cancellation.
Runs a SQL statement and returns a structured report of how SQLite executed it.
Retrieves the original SQL text used to create a specific schema object.
Reads the current value of an SQLite PRAGMA.
Retrieves the rowid of the most recent successful INSERT into a rowid table.
Loads a SQLite extension from the shared library at path.
Opens a connection to an SQLite database file.
Opens a connection to an in-memory SQLite database identified by uri.
Opens a read-only connection to an in-memory SQLite database identified
by uri.
Opens a read-only connection to an SQLite database file.
Opens a connection to a private, temporary on-disk SQLite database.
Executes a SQL query that returns rows (e.g., SELECT, PRAGMA that returns data, INSERT ... RETURNING).
Executes a SQL query that returns rows, with support for cancellation.
Executes a SQL query and returns results with the affected row count.
Cancellable version of query_with_changes/3.
Registers a PID to receive commit events on the connection. Multi-subscriber.
Registers a PID to receive SQLite diagnostic log events. Multi-subscriber.
Registers a progress-tick subscriber on the connection.
Registers a PID to receive rollback events on the connection. Multi-subscriber.
Registers a PID to receive change notifications for this connection. Multi-subscriber.
Registers a PID to receive WAL events on the connection. Multi-subscriber.
Releases a named savepoint.
Removes any busy handler from the connection.
Restores the named schema from a file at src_path.
Rolls back the current database transaction.
Rolls back the transaction to a named savepoint.
Creates a new savepoint within the current transaction.
Retrieves detailed information about columns in a specific table or view.
Retrieves information about all attached databases for the connection.
Retrieves information about foreign key constraints originating from a table.
Retrieves detailed information about the columns that make up a specific index.
Retrieves information about all indexes associated with a table.
Lists schema objects (tables, views, etc.) in a specified database schema.
Serializes an attached database to a contiguous binary.
Attaches a table to be tracked by the session.
Captures a changeset from the session.
Deletes the session, releasing its resources.
Returns true if the session has recorded no changes.
Creates a new change-tracking session on the connection.
Captures a patchset from the session.
Installs a busy handler on the connection (raw NIF).
Sets the value of an SQLite PRAGMA.
Returns the version string of the underlying SQLite C library.
Closes an active stream and releases its underlying SQLite statement resources.
Fetches a batch of rows from an active stream handle.
Retrieves the column names for an opened stream.
Prepares a SQL query for streaming and returns an opaque stream handle resource.
Returns the total number of rows modified, inserted, or deleted by all
INSERT, UPDATE, or DELETE statements since the connection was
opened, including changes from triggers.
Returns whether the connection is currently inside a transaction.
Returns the transaction state for the given schema (defaults to "main").
Unregisters a commit subscriber by handle. Idempotent.
Unregisters a log subscriber by handle. Idempotent — unknown handles are no-ops.
Unregisters a progress-tick subscriber by its handle.
Unregisters a rollback subscriber by handle. Idempotent.
Unregisters an update subscriber by handle. Idempotent — unknown handles are no-ops.
Unregisters a WAL subscriber by handle. Idempotent.
Forces a WAL checkpoint. Equivalent to sqlite3_wal_checkpoint_v2.
Types
@type stream_fetch_ok_result() :: %{rows: [[term()]]}
@type transaction_mode() :: :deferred | :immediate | :exclusive
Functions
@spec autocommit(Xqlite.conn()) :: {:ok, boolean()} | Xqlite.error()
Returns true when conn is in auto-commit mode (no active transaction),
false otherwise.
Equivalent to sqlite3_get_autocommit. Zero-cost; always available.
@spec backup( conn :: Xqlite.conn(), schema :: String.t(), dest_path :: String.t() ) :: :ok | Xqlite.error()
Backs up the named schema to a file at dest_path.
The destination file is created or overwritten. The source database remains readable during the backup.
Use Xqlite.backup/2 for a defaulted "main" schema.
@spec backup_with_progress( conn :: Xqlite.conn(), schema :: String.t(), dest_path :: String.t(), pid :: pid(), pages_per_step :: pos_integer(), cancel_tokens :: [reference()] ) :: :ok | Xqlite.error()
Backs up a database to a file with progress reporting and cancellation.
Copies pages_per_step pages at a time, sending
{:xqlite_backup_progress, remaining, pagecount} messages to pid
after each step. Between steps, all of cancel_tokens are polled —
if any is signalled, returns {:error, :operation_cancelled}
(OR-semantics). Pass an empty list for no-cancellation.
Use create_cancel_token/0 to create tokens and cancel_operation/1
from another process to signal one.
@spec begin(conn :: Xqlite.conn(), mode :: transaction_mode()) :: :ok | Xqlite.error()
Begins a new database transaction with the given mode.
Modes:
:deferred— acquires locks lazily (default SQLite behavior):immediate— acquires a write lock immediately (fails fast on contention):exclusive— acquires an exclusive lock (blocks readers too)
Returns :ok on success.
Returns {:error, reason} if a transaction cannot be started (e.g., if one
is already active on this connection, or due to other SQLite errors).
Returns {:error, :invalid_transaction_mode} for unrecognized mode atoms.
@spec blob_close(blob :: reference()) :: :ok | Xqlite.error()
Closes the blob handle, releasing its resources.
@spec blob_open( conn :: Xqlite.conn(), db :: String.t(), table :: String.t(), column :: String.t(), row_id :: integer(), read_only :: boolean() ) :: {:ok, reference()} | Xqlite.error()
Opens a BLOB for incremental I/O.
Returns an opaque blob handle for reading/writing chunks of a BLOB value without loading the entire thing into memory.
db— database name (typically"main")table— table namecolumn— column name containing the BLOBrow_id— rowid of the rowread_only—truefor read-only access,falsefor read-write
@spec blob_read( blob :: reference(), offset :: non_neg_integer(), length :: pos_integer() ) :: {:ok, binary()} | Xqlite.error()
Reads length bytes from the blob starting at offset.
@spec blob_reopen(blob :: reference(), row_id :: integer()) :: :ok | Xqlite.error()
Moves the blob handle to a different row in the same table/column.
More efficient than closing and re-opening for sequential row access.
@spec blob_size(blob :: reference()) :: {:ok, non_neg_integer()} | Xqlite.error()
Returns the size of the blob in bytes.
@spec blob_write(blob :: reference(), offset :: non_neg_integer(), data :: binary()) :: :ok | Xqlite.error()
Writes data to the blob starting at offset.
Cannot change the blob size — the data must fit within the existing
blob. Use zeroblob() in SQL to pre-allocate the desired size.
@spec cancel_operation(token_resource :: reference()) :: :ok | Xqlite.error()
Signals an intent to cancel operations associated with a given cancellation token.
When this function is called, any active SQLite operations (executed via
cancellable NIFs like query_cancellable/4 or execute_cancellable/4)
that were started with the provided token_resource will be interrupted
at the next opportunity (SQLite's progress handler check).
token_resource is an opaque reference previously created by
create_cancel_token/0.
This function is idempotent; calling it multiple times on the same token has no additional effect after the first call. The cancellation signal remains active for the token.
Returns :ok. This function indicates the signal has been set; it does not
guarantee that the operation has already stopped. The cancellable NIF function
will return {:error, :operation_cancelled} when it actually terminates due
to the cancellation.
Returns {:error, reason} if the provided token_resource is not a valid
cancellation token resource (e.g., a different type of reference).
@spec changes(conn :: Xqlite.conn()) :: {:ok, non_neg_integer()} | Xqlite.error()
Returns the number of rows modified, inserted, or deleted by the most
recently completed INSERT, UPDATE, or DELETE statement on this
connection. Does not count changes from triggers or foreign key actions.
@spec changeset_apply( conn :: Xqlite.conn(), changeset :: binary(), conflict_strategy :: :omit | :replace | :abort ) :: :ok | Xqlite.error()
Applies a changeset binary to a connection.
conflict_strategy determines behavior on conflicts:
:omit— skip conflicting changes:replace— overwrite with the changeset's values:abort— abort the entire apply operation
@spec changeset_concat(a :: binary(), b :: binary()) :: {:ok, binary()} | Xqlite.error()
Concatenates two changeset binaries into one.
@spec changeset_invert(changeset :: binary()) :: {:ok, binary()} | Xqlite.error()
Inverts a changeset binary.
INSERT becomes DELETE, DELETE becomes INSERT, UPDATE values are swapped.
@spec close(conn :: Xqlite.conn()) :: :ok
Conceptually closes the database connection.
After a connection is closed, any further attempts to use its resource handle
with other NIF functions will likely result in errors.
It is safe to call close/1 multiple times on the same connection resource;
subsequent calls are no-ops and will also return :ok.
For on-disk temporary databases created with open_temporary/0, closing the
connection also deletes the underlying temporary file.
conn is the database connection resource.
Returns :ok. This function is designed to always succeed from the Elixir perspective
once a valid connection resource has been established, even if the underlying
SQLite close operation might encounter an issue (which is rare and typically
handled internally by rusqlite).
@spec commit(conn :: Xqlite.conn()) :: :ok | Xqlite.error()
Commits the current database transaction.
Equivalent to executing the SQL statement COMMIT; or END TRANSACTION;.
All changes made within the transaction become permanent.
conn is the database connection resource.
Returns :ok on success.
Returns {:error, reason} if the transaction cannot be committed (e.g., if
no transaction is active, or due to other SQLite errors like deferred constraint
violations).
@spec compile_options(conn :: Xqlite.conn()) :: {:ok, [String.t()]} | Xqlite.error()
Retrieves the compile-time options the linked SQLite C library was built with.
Corresponds to the PRAGMA compile_options; statement. This is useful for
diagnosing which features (e.g., THREADSAFE, ENABLE_FTS5) are available.
conn is the database connection resource.
Returns {:ok, list_of_options} on success, where list_of_options is a
list of strings (e.g., ["COMPILER=clang-14.0.3", "ENABLE_FTS5", "THREADSAFE=1"]).
Returns {:error, reason} on failure.
@spec connection_stats(Xqlite.conn()) :: {:ok, map()} | Xqlite.error()
Returns a structured snapshot of sqlite3_db_status counters for the
connection.
Returns {:ok, %{…}} with the following keys (all non-negative integers):
:lookaside_used— lookaside slots in use.:cache_used— heap bytes in the pager cache.:schema_used— heap bytes in the schema cache.:stmt_used— heap bytes across prepared statements.:lookaside_hit— count of lookaside allocations satisfied from the pool.:lookaside_miss_size— count of allocations that bypassed lookaside because they were too big.:lookaside_miss_full— count of allocations that bypassed lookaside because it was full.:cache_hit— pager cache hit count.:cache_miss— pager cache miss count.:cache_write— count of dirty pages written.:deferred_fks— pending deferred FK violations (only relevant underPRAGMA defer_foreign_keys = ON).:cache_used_shared— heap bytes in the shared pager cache attributable to this connection.:cache_spill— count of dirty-cache spills to disk.:tempbuf_spill— count oftempdbspill events.
All counters are "current" values; high-water marks are not exposed yet. Call repeatedly for time-series monitoring.
@spec create_cancel_token() :: {:ok, reference()} | Xqlite.error()
Creates a new cancellation token resource.
This token can be passed to cancellable NIF operations (e.g.,
query_cancellable/4, execute_cancellable/4). To signal cancellation
for operations associated with this token, call cancel_operation/1
on the returned token resource.
Each token is independent. Cancelling one token does not affect others. The token resource should be managed appropriately; it does not need explicit closing beyond normal Elixir garbage collection of the resource reference.
Returns {:ok, token_resource} on success, where token_resource is an
opaque reference representing the cancellation token.
Returns {:error, reason} in the unlikely event of a resource allocation failure.
@spec deserialize( conn :: Xqlite.conn(), schema :: String.t(), data :: binary(), read_only :: boolean() ) :: :ok | Xqlite.error()
Deserializes a binary into the named schema, replacing its contents.
The binary must be a valid SQLite database image (as produced by
serialize/2). After deserialization the connection operates on the
new database entirely in memory.
When read_only is true, write operations on the schema fail with
{:error, {:read_only_database, _}}. When false it is writable and
may grow as needed.
Use Xqlite.deserialize/4 for defaulted schema/read_only.
Returns :ok on success or {:error, reason} on failure.
@spec enable_load_extension(conn :: Xqlite.conn(), enabled :: boolean()) :: :ok | Xqlite.error()
Enables or disables extension loading for the given connection.
Extension loading is disabled by default for security. You must call
enable_load_extension(conn, true) before calling load_extension/2 or
load_extension/3. Call enable_load_extension(conn, false) when done
loading to re-lock the connection.
@spec execute(conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword()) :: {:ok, non_neg_integer()} | Xqlite.error()
Executes a SQL statement that does not return rows (e.g., INSERT, UPDATE, DELETE, DDL).
conn is the database connection resource.
sql is the SQL statement string.
params is an optional list of positional parameters. Named parameters are not
supported for execute/3; use query/3 with INSERT ... RETURNING if named
parameters and result retrieval are needed for DML.
Use an empty list [] if the statement has no parameters.
Supported Elixir parameter types are integers, floats, strings, nil,
booleans (true/false), and binaries (blobs).
Returns {:ok, affected_rows} on success, where affected_rows is a non-negative
integer indicating the number of rows modified, inserted, or deleted. For DDL
statements like CREATE TABLE, affected_rows is typically 0.
Returns {:error, reason} on failure. For example, {:error, :execute_returned_results}
if a statement unexpectedly returns data (e.g., a SELECT statement or an
INSERT ... RETURNING statement was passed).
@spec execute_batch(conn :: Xqlite.conn(), sql_batch :: String.t()) :: :ok | Xqlite.error()
Executes one or more SQL statements separated by semicolons.
This function is useful for running multiple DDL statements, a series of DML statements without parameters, or other sequences of SQL operations. Parameters are not supported for statements within the batch.
conn is the database connection resource.
sql_batch is a string containing one or more SQL statements. SQLite executes
the statements sequentially. If an error occurs in one statement, subsequent
statements in the batch are typically not executed, and the function returns
an error. The changes made by prior successful statements within the batch
are usually persisted unless the batch execution occurs within an explicit
transaction that is later rolled back.
Returns :ok if all statements in the batch execute successfully.
Returns {:error, reason} if any statement fails.
@spec execute_batch_cancellable( conn :: Xqlite.conn(), sql_batch :: String.t(), cancel_tokens :: [reference()] ) :: :ok | Xqlite.error()
Executes one or more SQL statements separated by semicolons, with support for cancellation.
This is a cancellable version of execute_batch/2.
See execute_batch/2 for details on parameters, return values, and general behavior.
cancel_tokens is a list of references; any signal cancels (OR-semantics).
Empty list = no cancellation.
Returns :ok if all statements in the batch execute successfully.
Returns {:error, :operation_cancelled} if any token was cancelled.
Returns {:error, other_reason} for other types of failures.
@spec execute_cancellable( conn :: Xqlite.conn(), sql :: String.t(), params :: list(), cancel_tokens :: [reference()] ) :: {:ok, non_neg_integer()} | Xqlite.error()
Executes a SQL statement that does not return rows, with support for cancellation.
This is a cancellable version of execute/3.
See execute/3 for details on parameters, return values, and general behavior.
cancel_tokens is a list of references created by create_cancel_token/0;
any signal cancels the operation (OR-semantics). Empty list = no
cancellation.
Returns {:ok, affected_rows} on successful completion.
Returns {:error, :operation_cancelled} if any token was cancelled.
Returns {:error, other_reason} for other types of failures.
@spec explain_analyze( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword() ) :: {:ok, map()} | Xqlite.error()
Runs a SQL statement and returns a structured report of how SQLite executed it.
Combines three sources:
EXPLAIN QUERY PLAN <sql>— SQLite's static query plan tree (under:query_plan).sqlite3_stmt_scanstatus_v2— per-scan runtime stats (under:scans), one entry per loop in the executed plan.sqlite3_stmt_status— statement-level counters (under:stmt_counters).
Also reports wall-clock execution time and the number of rows produced. Rows
themselves are discarded — use query/3 if you need them.
The feature requires SQLite to be built with SQLITE_ENABLE_STMT_SCANSTATUS,
which xqlite enables in its bundled build.
Returns {:ok, report} where report is a map with the shape:
%{
wall_time_ns: non_neg_integer(),
rows_produced: non_neg_integer(),
stmt_counters: %{
fullscan_step: integer(),
sort: integer(),
autoindex: integer(),
vm_step: integer(),
reprepare: integer(),
run: integer(),
filter_miss: integer(),
filter_hit: integer(),
memused_bytes: integer()
},
scans: [%{
loops: integer(),
rows_visited: integer(),
estimated_rows: float(),
name: String.t(),
explain: String.t(),
selectid: integer(),
parentid: integer()
}],
query_plan: [%{
id: integer(),
parent: integer(),
detail: String.t()
}]
}
@spec get_create_sql(conn :: Xqlite.conn(), object_name :: String.t()) :: {:ok, String.t() | nil} | Xqlite.error()
Retrieves the original SQL text used to create a specific schema object.
This function queries the sqlite_schema table (formerly sqlite_master)
for the sql column corresponding to the given object name.
conn is the database connection resource.
object_name (String.t()): The name of the table, index, trigger, or view
whose creation SQL is to be retrieved. Object names are typically case-sensitive.
Returns {:ok, sql_string} on success if the object exists, where sql_string
is the CREATE ... statement.
Returns {:ok, nil} if no object with the given name is found in the schema.
Returns {:error, reason} for other failures.
@spec get_pragma(conn :: Xqlite.conn(), name :: String.t()) :: {:ok, term() | :no_value} | Xqlite.error()
Reads the current value of an SQLite PRAGMA.
PRAGMA statements are used to modify the operation of the SQLite library or to query the library for internal data. See SQLite documentation for a list of available PRAGMAs.
conn is the database connection resource.
name is the string name of the PRAGMA to read (e.g., "user_version", "journal_mode").
Returns {:ok, value} where value is the PRAGMA's current value, converted
to an appropriate Elixir term (integer, string, boolean for some common 0/1 PRAGMAs).
Returns {:ok, :no_value} if the PRAGMA does not return a value (e.g., PRAGMA optimize)
or if the PRAGMA name is invalid/unknown to SQLite.
Returns {:error, reason} for other failures.
Note: Some PRAGMAs require an argument to read (e.g., PRAGMA table_info(table_name)).
This function is for PRAGMAs that are read without an argument or whose argument is
part of the name string itself if SQLite supports that syntax. For more complex
PRAGMA queries, use XqliteNIF.query/3. The Xqlite.Pragma module provides
higher-level helpers for many common PRAGMAs.
Reading wal_autocheckpoint reports xqlite's emulated threshold rather
than issuing the PRAGMA: SQLite only reports a threshold while its own
internal WAL hook occupies the hook slot, which xqlite's master callback
holds (see register_wal_hook/2). A raw PRAGMA wal_autocheckpoint;
query would always report 0 on an xqlite connection.
@spec last_insert_rowid(conn :: Xqlite.conn()) :: {:ok, integer()} | Xqlite.error()
Retrieves the rowid of the most recent successful INSERT into a rowid table.
This function calls SQLite's sqlite3_last_insert_rowid() for the given
connection. The value returned is the rowid of the last row inserted by an
INSERT statement on that specific database connection.
Important Considerations:
- The value is connection-specific. Inserts on other connections do not affect it.
- It is only updated by successful
INSERTstatements. Failed inserts, updates, deletes, or other SQL statements do not change its value. - It does not work for
WITHOUT ROWIDtables. For such tables, you must use theINSERT ... RETURNINGclause to get the primary key values of inserted rows. - If no successful
INSERTs have occurred on the connection since it was opened, this function typically returns0. - The rowid can be an alias for the
INTEGER PRIMARY KEYcolumn if one exists.
conn is the database connection resource.
Returns {:ok, rowid_integer} on success, where rowid_integer is the last
inserted rowid.
Returns {:error, reason} only in rare cases of severe connection failure, as
the underlying SQLite C function itself doesn't typically return errors that
map to common Xqlite.error() types beyond connection validity.
@spec load_extension( conn :: Xqlite.conn(), path :: String.t(), entry_point :: String.t() | nil ) :: :ok | Xqlite.error()
Loads a SQLite extension from the shared library at path.
Pass nil for entry_point to let SQLite auto-detect. Extension
loading must be enabled first via enable_load_extension/2.
Use Xqlite.load_extension/2 for a defaulted entry_point of nil.
@spec open(path :: String.t()) :: {:ok, Xqlite.conn()} | Xqlite.error()
Opens a connection to an SQLite database file.
path is the file path to the database. If the file does not exist,
SQLite will attempt to create it. URI filenames are supported
(e.g., "file:my_db.sqlite?mode=ro").
Returns {:ok, conn_resource} on success, where conn_resource is an
opaque reference to the database connection. Returns {:error, reason}
on failure, e.g., if the path is invalid or permissions are insufficient.
@spec open_in_memory(uri :: String.t()) :: {:ok, Xqlite.conn()} | Xqlite.error()
Opens a connection to an in-memory SQLite database identified by uri.
Pass ":memory:" for a private, temporary in-memory database, or a URI
filename like "file:memdb1?mode=memory&cache=shared" to create a
shared-cache in-memory database reachable from other connections in the
same process.
Returns {:ok, conn_resource} on success or {:error, reason} on failure.
@spec open_in_memory_readonly(uri :: String.t()) :: {:ok, Xqlite.conn()} | Xqlite.error()
Opens a read-only connection to an in-memory SQLite database identified
by uri.
Typical use is connecting to a named shared-cache in-memory database
opened read-write by another connection, e.g.
"file:memdb1?mode=memory&cache=shared". Pass ":memory:" for a
private, empty read-only database.
Uses SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_MEMORY | SQLITE_OPEN_URI flags.
Returns {:ok, conn_resource} on success or {:error, reason} on failure.
@spec open_readonly(path :: String.t()) :: {:ok, Xqlite.conn()} | Xqlite.error()
Opens a read-only connection to an SQLite database file.
The database must already exist — SQLite will not create it.
Write operations (INSERT, UPDATE, DELETE, CREATE TABLE, etc.) will fail
with {:error, {:read_only_database, message}}.
Uses SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_URI flags.
Returns {:ok, conn_resource} on success or {:error, reason} on failure.
@spec open_temporary() :: {:ok, Xqlite.conn()} | Xqlite.error()
Opens a connection to a private, temporary on-disk SQLite database.
The database file is created by SQLite in a temporary location and is automatically deleted when the connection is closed. Each call creates a new, independent temporary database.
Returns {:ok, conn_resource} on success or {:error, reason} on failure.
@spec query( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword() ) :: {:ok, Xqlite.query_result()} | Xqlite.error()
Executes a SQL query that returns rows (e.g., SELECT, PRAGMA that returns data, INSERT ... RETURNING).
conn is the database connection resource.
sql is the SQL query string.
params is an optional list of positional parameters ([val1, val2]) or a
keyword list of named parameters ([name1: val1, name2: val2]).
Use an empty list [] if the query has no parameters.
Supported Elixir parameter types are integers, floats, strings, nil,
booleans (true/false), and binaries (blobs).
Returns {:ok, result_map} on success or {:error, reason} on failure.
The result_map is %{columns: [String.t()], rows: [[term()]], num_rows: non_neg_integer()}.
columns is a list of column name strings.
rows is a list of lists, where each inner list represents a row and contains
Elixir terms corresponding to the SQLite values.
num_rows is the count of rows fetched.
If the query is an INSERT ... RETURNING statement, the rows will contain
the returned values. For statements that do not return rows (e.g., a simple INSERT
without RETURNING), this function will likely succeed but return an empty
rows list and num_rows: 0, or potentially an error like :execute_returned_results
if SQLite's API indicates results were returned unexpectedly for a non-query.
It is generally recommended to use execute/3 for non-row-returning statements.
@spec query_cancellable( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword(), cancel_tokens :: [reference()] ) :: {:ok, Xqlite.query_result()} | Xqlite.error()
Executes a SQL query that returns rows, with support for cancellation.
This is a cancellable version of query/3.
See query/3 for details on parameters, return values, and general behavior.
conn is the database connection resource.
sql is the SQL query string.
params is an optional list of positional or keyword parameters.
cancel_tokens is a list of resources created by create_cancel_token/0.
If any token in the list is cancelled via cancel_operation/1 while the
query is executing, the query will be interrupted (OR-semantics — the
earliest signal wins). Pass an empty list to run without cancellation.
Use Xqlite.query_cancellable/4 to pass either a single token or a list;
this raw NIF accepts only the list form.
Returns {:ok, result_map} on successful completion, where result_map is
%{columns: [...], rows: [...], num_rows: ...}.
Returns {:error, :operation_cancelled} if the operation was cancelled.
Returns {:error, other_reason} for other types of failures.
@spec query_with_changes( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword() ) :: {:ok, map()} | Xqlite.error()
Executes a SQL query and returns results with the affected row count.
Returns {:ok, %{columns, rows, num_rows, changes}} where changes is
sqlite3_changes() captured atomically inside the connection lock. For
SELECT statements (non-empty columns), changes is 0. For DML, it's the
actual affected row count.
This is the recommended function when you need reliable affected row counts.
Unlike calling query/3 then changes/1 separately, the count is captured
before the lock is released, so it cannot be stale.
@spec query_with_changes_cancellable( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword(), cancel_tokens :: [reference()] ) :: {:ok, map()} | Xqlite.error()
Cancellable version of query_with_changes/3.
cancel_tokens is a list of references; OR-semantics on cancellation.
@spec register_commit_hook(conn :: Xqlite.conn(), pid :: pid()) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a PID to receive commit events on the connection. Multi-subscriber.
Immediately before each commit (regardless of journal mode), every registered subscriber receives
{:xqlite_commit}Observation-only — the master callback never vetoes the commit.
@spec register_log_hook(pid :: pid()) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a PID to receive SQLite diagnostic log events. Multi-subscriber.
SQLite's global log callback (sqlite3_config(SQLITE_CONFIG_LOG)) sends
diagnostic messages for events like auto-index creation, schema changes,
and warnings that don't surface as errors. Each registered PID receives
messages in the form {:xqlite_log, error_code, message}.
This is a global, per-process subscription — but multiple PIDs can
subscribe independently. The first call installs the master callback;
subsequent calls just add to the subscriber list. Use the returned
handle to unregister this specific subscriber via
unregister_log_hook/1.
Returns {:ok, handle} on success or {:error, reason} on failure.
@spec register_progress_hook( conn :: Xqlite.conn(), pid :: pid(), every_n :: pos_integer(), tag :: String.t() | nil ) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a progress-tick subscriber on the connection.
After every ~64 SQLite VM instructions (8 ops × every_n callback
invocations), forwards
{:xqlite_progress, count, elapsed_ms} # tag = nil
{:xqlite_progress, tag, count, elapsed_ms} # tag != nilto pid. count is the per-subscriber decimated counter (starts at
0, incremented every callback fire, emit when divisible by every_n).
elapsed_ms is the wall time since this subscriber was registered.
Multiple subscribers can coexist on the same connection — each gets a
unique handle. Subscribers are independent: registering or
unregistering one never affects another. The registration handle is
the value returned in {:ok, handle} and is what unregister_progress_hook/2
expects.
every_n must be >= 1. tag is a string (typically
Atom.to_string(:my_atom) from the Xqlite.register_progress_hook/3
wrapper) used to disambiguate messages from multiple subscribers
inside the same listener process; pass nil to omit the tag.
This subscriber-list shares the SQLite progress-handler slot with cancellation. Both compose: cancel signals interrupt the query before tick emission. Tick subscribers do not affect cancellation latency beyond a handful of nanoseconds per fire.
Returns {:ok, handle} on success or {:error, reason} on failure.
@spec register_rollback_hook(conn :: Xqlite.conn(), pid :: pid()) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a PID to receive rollback events on the connection. Multi-subscriber.
After each rollback (whether user-initiated or forced by a constraint / deferred-FK failure at commit), every registered subscriber receives
{:xqlite_rollback}Note: SQLite does not invoke this callback for ROLLBACK TO SAVEPOINT operations — only for outer-transaction rollbacks.
@spec register_update_hook(conn :: Xqlite.conn(), pid :: pid()) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a PID to receive change notifications for this connection. Multi-subscriber.
Each registered PID receives messages in the form:
{:xqlite_update, action, db_name, table_name, rowid} where:
actionis:insert,:update, or:deletedb_nameis the database name (e.g.,"main","temp")table_nameis the table that was modifiedrowidis the rowid of the affected row
Multiple subscribers can coexist on the same connection — each gets a
unique handle. The callback fires for every subscriber on every
update. Use the returned handle to unregister via
unregister_update_hook/2.
The callback fires before the change is committed — if the enclosing transaction rolls back, every subscriber will have already received the notification.
Returns {:ok, handle} on success or {:error, reason} on failure.
@spec register_wal_hook(conn :: Xqlite.conn(), pid :: pid()) :: {:ok, non_neg_integer()} | Xqlite.error()
Registers a PID to receive WAL events on the connection. Multi-subscriber.
After each commit in WAL mode, every registered subscriber receives
{:xqlite_wal, db_name, pages}— db_name is a binary ("main", "temp", or attached database
name), pages is a non-negative integer (number of frames in the WAL
log).
Useful for WAL-size monitoring and triggering manual checkpoints when the log grows past a threshold. Multiple subscribers register independently; each gets a unique handle.
WAL subscribers coexist with automatic checkpointing: SQLite's
wal_hook slot and its built-in autocheckpoint are mutually exclusive
at the C level, so xqlite's master callback emulates the
autocheckpoint itself (passive checkpoint once the WAL reaches the
wal_autocheckpoint threshold, default 1000 pages). Changing the
threshold through set_pragma/3 keeps both behaviors intact.
Warning — raw-SQL PRAGMA wal_autocheckpoint
Issuing PRAGMA wal_autocheckpoint = N through query/3,
execute/3, or execute_batch/2 installs SQLite's internal WAL
hook in place of ours: subscribers silently stop receiving events
(no memory is leaked). Only set_pragma/3 repairs the slot —
always set this PRAGMA through it.
Returns {:ok, handle} on success or {:error, reason} on failure.
@spec release_savepoint(conn :: Xqlite.conn(), name :: String.t()) :: :ok | Xqlite.error()
Releases a named savepoint.
Equivalent to executing RELEASE SAVEPOINT 'name'; or simply RELEASE 'name';.
This removes the specified savepoint and all savepoints established after it.
The changes made since the savepoint was established are incorporated into the
current transaction (i.e., they are not rolled back). The transaction remains active.
conn is the database connection resource.
name is the string identifier of an existing savepoint.
Returns :ok on success.
Returns {:error, reason} on failure (e.g., if the named savepoint does not
exist, or other SQLite errors).
@spec remove_busy_handler(Xqlite.conn()) :: :ok | Xqlite.error()
Removes any busy handler from the connection.
Safe to call when no handler is installed (no-op on both sides). After
removal, SQLite returns SQLITE_BUSY immediately on contention unless
a busy_timeout is subsequently set.
Returns :ok.
@spec restore( conn :: Xqlite.conn(), schema :: String.t(), src_path :: String.t() ) :: :ok | Xqlite.error()
Restores the named schema from a file at src_path.
The connection's existing data in that schema is overwritten.
Use Xqlite.restore/2 for a defaulted "main" schema.
@spec rollback(conn :: Xqlite.conn()) :: :ok | Xqlite.error()
Rolls back the current database transaction.
Equivalent to executing the SQL statement ROLLBACK; or ROLLBACK TRANSACTION;.
All changes made within the transaction since the last COMMIT or SAVEPOINT
are discarded.
conn is the database connection resource.
Returns :ok on success.
Returns {:error, reason} if the transaction cannot be rolled back (e.g., if
no transaction is active, or due to other SQLite errors).
@spec rollback_to_savepoint(conn :: Xqlite.conn(), name :: String.t()) :: :ok | Xqlite.error()
Rolls back the transaction to a named savepoint.
Equivalent to executing ROLLBACK TO SAVEPOINT 'name';. Changes made after
the specified savepoint are undone, but the savepoint itself remains active
(it is not released). The transaction also remains active.
conn is the database connection resource.
name is the string identifier of an existing savepoint.
Returns :ok on success.
Returns {:error, reason} on failure (e.g., if the named savepoint does not
exist, or other SQLite errors).
@spec savepoint(conn :: Xqlite.conn(), name :: String.t()) :: :ok | Xqlite.error()
Creates a new savepoint within the current transaction.
Equivalent to executing SAVEPOINT 'name';. Savepoints allow partial rollbacks
of a transaction. If the current transaction is not a DEFERRED transaction,
a SAVEPOINT command will implicitly start one.
conn is the database connection resource.
name is a string identifier for the savepoint. Savepoint names can be reused,
and a new savepoint with an existing name will hide the older one.
Returns :ok on success.
Returns {:error, reason} on failure (e.g., if SQLite cannot create the savepoint).
@spec schema_columns(conn :: Xqlite.conn(), table_name :: String.t()) :: {:ok, [Xqlite.Schema.ColumnInfo.t()]} | Xqlite.error()
Retrieves detailed information about columns in a specific table or view.
Corresponds to the PRAGMA table_xinfo('table_name'); statement, which provides
more details than PRAGMA table_info, including column hidden status.
conn is the database connection resource.
table_name (String.t()): The name of the table or view for which to retrieve
column information. The name is case-sensitive based on SQLite's handling.
Returns {:ok, list_of_column_info} on success, where list_of_column_info
is a list of Xqlite.Schema.ColumnInfo structs, ordered by column ID.
If the table does not exist, an empty list is returned within the {:ok, []} tuple.
Each struct contains:
:column_id(integer()): 0-indexed ID of the column within the table.:name(String.t()): Name of the column.:type_affinity(atom): Resolved data type affinity (e.g.,:integer,:text).:declared_type(String.t()): Original data type string fromCREATE TABLE.:nullable(boolean()):trueif the column allows NULL values.:default_value(String.t() | nil): Default value expression as a string literal, ornil. For generated columns, this will benilas the expression is not in this field fromPRAGMA table_xinfo.:primary_key_index(non_neg_integer()): 1-based index within the PK if part of it, else0.:hidden_kind(atom): Indicates if/how a column is hidden/generated (e.g.,:normal,:stored_generated,:virtual_generated). Returns{:error, reason}for other failures.
@spec schema_databases(conn :: Xqlite.conn()) :: {:ok, [Xqlite.Schema.DatabaseInfo.t()]} | Xqlite.error()
Retrieves information about all attached databases for the connection.
Corresponds to the PRAGMA database_list; statement. Each active connection
has at least a "main" database and often a "temp" database. Additional
databases can be attached using the ATTACH DATABASE SQL command.
conn is the database connection resource.
Returns {:ok, list_of_database_info} on success, where list_of_database_info
is a list of Xqlite.Schema.DatabaseInfo structs.
Each struct contains:
:name(String.t()): The logical name of the database (e.g., "main", "temp", or attached name).:file(String.t() | nil): The absolute path to the database file, ornilfor in-memory databases, or an empty string for temporary databases opened withXqliteNIF.open_temporary/0. Returns{:error, reason}on failure.
@spec schema_foreign_keys(conn :: Xqlite.conn(), table_name :: String.t()) :: {:ok, [Xqlite.Schema.ForeignKeyInfo.t()]} | Xqlite.error()
Retrieves information about foreign key constraints originating from a table.
Corresponds to the PRAGMA foreign_key_list('table_name'); statement.
This lists foreign keys defined on the specified table_name that
reference other tables.
conn is the database connection resource.
table_name (String.t()): The name of the table whose foreign key constraints
are to be listed. Case-sensitive based on SQLite's handling.
Returns {:ok, list_of_foreign_key_info} on success. list_of_foreign_key_info
is a list of Xqlite.Schema.ForeignKeyInfo structs. If the table does not
exist or has no foreign keys, an empty list is returned within the {:ok, []} tuple.
Each struct contains:
:id(integer()): ID of the foreign key constraint (0-based index for the table).:column_sequence(integer()): 0-based index of the column within the FK (for compound FKs).:target_table(String.t()): Name of the table referenced by the foreign key.:from_column(String.t()): Name of the column in the current table that is part of the FK.:to_column(String.t() | nil): Name of the column in the target table referenced.:on_update(atom): Action on update (e.g.,:cascade,:set_null).:on_delete(atom): Action on delete (e.g.,:restrict,:no_action).:match_clause(atom): TheMATCHclause type (e.g.,:none,:simple). Returns{:error, reason}for other failures.
@spec schema_index_columns(conn :: Xqlite.conn(), index_name :: String.t()) :: {:ok, [Xqlite.Schema.IndexColumnInfo.t()]} | Xqlite.error()
Retrieves detailed information about the columns that make up a specific index.
Corresponds to the PRAGMA index_xinfo('index_name'); statement, which provides
more details than PRAGMA index_info, including sort order, collation, and
whether a column is a key or an included column.
conn is the database connection resource.
index_name (String.t()): The name of the index for which to retrieve column
information. Index names are typically case-sensitive.
Returns {:ok, list_of_index_column_info} on success. list_of_index_column_info
is a list of Xqlite.Schema.IndexColumnInfo structs, ordered by their sequence
within the index definition. If the index does not exist, an empty list is
returned within the {:ok, []} tuple.
Each struct contains:
:index_column_sequence(integer()): 0-based position of this column in the index key.:table_column_id(integer()): ID of the column in the base table (cidfromPRAGMA table_info).-1for expressions not directly on a table column, or for the rowid.-2is sometimes used by SQLite for expressions inPRAGMA index_xinfo.:name(String.t() | nil): Name of the table column, ornilif the index is on an expression or rowid.:sort_order(atom): Sort order (e.g.,:asc,:desc).:collation(String.t()): Name of the collation sequence used.:is_key_column(boolean()):trueif part of the primary index key,falseif an "included" column (SQLite >= 3.9.0). Returns{:error, reason}for other failures.
@spec schema_indexes(conn :: Xqlite.conn(), table_name :: String.t()) :: {:ok, [Xqlite.Schema.IndexInfo.t()]} | Xqlite.error()
Retrieves information about all indexes associated with a table.
Corresponds to the PRAGMA index_list('table_name'); statement. This includes
explicitly created indexes (CREATE INDEX) and indexes automatically created
by SQLite for PRIMARY KEY and UNIQUE constraints.
conn is the database connection resource.
table_name (String.t()): The name of the table whose indexes are to be listed.
Case-sensitive based on SQLite's handling.
Returns {:ok, list_of_index_info} on success. list_of_index_info is a list
of Xqlite.Schema.IndexInfo structs. If the table does not exist or has no
indexes, an empty list is returned within the {:ok, []} tuple.
Each struct contains:
:name(String.t()): Name of the index.:unique(boolean()):trueif the index enforces uniqueness.:origin(atom): How the index was created (e.g.,:create_index,:unique_constraint,:primary_key_constraint).:partial(boolean()):trueif the index is partial (has aWHEREclause). Returns{:error, reason}for other failures.
@spec schema_list_objects(conn :: Xqlite.conn(), schema_name :: String.t() | nil) :: {:ok, [Xqlite.Schema.SchemaObjectInfo.t()]} | Xqlite.error()
Lists schema objects (tables, views, etc.) in a specified database schema.
Corresponds to the PRAGMA table_list; statement, filtered by the optional
schema_name. This PRAGMA primarily lists tables, views, and virtual tables.
conn is the database connection resource.
schema_name (optional String.t()): The name of the schema (e.g., "main", "temp",
or an attached database name). If nil or omitted, information for all schemas
accessible by the connection may be returned (behavior can depend on how PRAGMA table_list
is implemented if no schema is specified, though SQLite typically defaults to "main" or all).
It is recommended to specify a schema for predictable results.
Returns {:ok, list_of_object_info} on success, where list_of_object_info
is a list of Xqlite.Schema.SchemaObjectInfo structs for objects matching
the specified schema.
Each struct contains:
:schema(String.t()): Name of the schema containing the object.:name(String.t()): Name of the object.:object_type(atom): The type of object (e.g.,:table,:view,:virtual).:column_count(integer()): Number of columns (meaningful for tables/views).:is_without_rowid(boolean()):trueif the table was created with theWITHOUT ROWIDoptimization.:strict(boolean()):trueif the table was declared usingSTRICTmode. Returns{:error, reason}on failure.
@spec serialize(conn :: Xqlite.conn(), schema :: String.t()) :: {:ok, binary()} | Xqlite.error()
Serializes an attached database to a contiguous binary.
Atomic, point-in-time snapshot. Use Xqlite.serialize/1 for a default
"main" schema.
Returns {:ok, binary} on success or {:error, reason} on failure.
@spec session_attach(session :: reference(), table :: String.t() | nil) :: :ok | Xqlite.error()
Attaches a table to be tracked by the session.
Pass a table name to track that table, or nil to track all tables.
@spec session_changeset(session :: reference()) :: {:ok, binary()} | Xqlite.error()
Captures a changeset from the session.
Returns a binary containing all INSERT/UPDATE/DELETE operations recorded since the session was created or the last changeset capture.
@spec session_delete(session :: reference()) :: :ok | Xqlite.error()
Deletes the session, releasing its resources.
The session handle must not be used after this call.
Returns true if the session has recorded no changes.
@spec session_new(conn :: Xqlite.conn()) :: {:ok, reference()} | Xqlite.error()
Creates a new change-tracking session on the connection.
Returns an opaque session handle. Attach tables to track with
session_attach/2 before making changes.
@spec session_patchset(session :: reference()) :: {:ok, binary()} | Xqlite.error()
Captures a patchset from the session.
Like session_changeset/1 but the patchset format is more compact —
it omits original primary key values for UPDATE operations.
@spec set_busy_handler( conn :: Xqlite.conn(), pid :: pid(), max_retries :: non_neg_integer(), max_elapsed_ms :: non_neg_integer(), sleep_ms :: non_neg_integer() ) :: :ok | Xqlite.error()
Installs a busy handler on the connection (raw NIF).
Most users want Xqlite.set_busy_handler/3, which accepts keyword
options with sane defaults.
When SQLite encounters a locked database (another writer holds
RESERVED+) the handler decides whether to retry or surface
SQLITE_BUSY to the caller. Each invocation is also forwarded to
pid as
{:xqlite_busy, retries_so_far, elapsed_ms}so callers can observe contention (telemetry, structured logging, adaptive backoff).
max_retries— stop after this many retries and let the caller seeSQLITE_BUSY.max_elapsed_ms— absolute time ceiling in milliseconds from the first busy event in the window.sleep_ms— milliseconds to sleep between retries. Zero disables the pause.
Replacing an existing handler is atomic: the previous handler's state is reclaimed before the new one takes effect.
Warning — PRAGMA busy_timeout silently replaces this handler
PRAGMA busy_timeout / sqlite3_busy_timeout replaces the installed
handler at the SQLite C level without going through our atomic slot.
Messages stop flowing; no memory is leaked (the internal state is
reclaimed on the next set_busy_handler/5 / remove_busy_handler/1
/ connection close). Prefer Xqlite.busy_timeout/2 to switch to
plain-timeout semantics.
Returns :ok.
@spec set_pragma(conn :: Xqlite.conn(), name :: String.t(), value :: term()) :: {:ok, term()} | Xqlite.error()
Sets the value of an SQLite PRAGMA.
conn is the database connection resource.
name is the string name of the PRAGMA to set (e.g., "user_version", "foreign_keys").
value is the Elixir term to set the PRAGMA to. Supported Elixir types include:
- Integers
- Strings
- Booleans (
truetypically maps toONor1,falsetoOFFor0) - Atoms that SQLite can interpret (e.g.,
:on,:off,:wal,:delete). Refer to SQLite documentation for valid values for specific PRAGMAs.
The NIF attempts to format the Elixir value into a string literal suitable
for the PRAGMA name = value_literal; SQL statement.
Returns {:ok, value} where value is what SQLite echoed back from the
PRAGMA assignment, or nil if the PRAGMA produced no output. For example,
PRAGMA journal_mode = wal returns {:ok, "wal"} on success. Note that
SQLite might silently ignore invalid PRAGMA names or invalid values for a
valid PRAGMA. Returns {:error, reason} if there's an issue preparing or
executing the PRAGMA statement (e.g., unsupported Elixir type for value,
syntax error).
Setting wal_autocheckpoint through this function additionally repairs
the WAL hook slot: the PRAGMA installs SQLite's internal autocheckpoint
callback in place of xqlite's master WAL callback, so this NIF
re-installs the master and mirrors the new threshold into its emulated
autocheckpoint (see register_wal_hook/2). Raw-SQL PRAGMA statements
get no such repair.
The Xqlite.Pragma module provides higher-level helpers for setting many
common PRAGMAs with more type safety.
@spec sqlite_version() :: {:ok, String.t()} | Xqlite.error()
Returns the version string of the underlying SQLite C library.
This is a runtime check and does not require an active database connection. It is useful for diagnostics to confirm which version of SQLite the NIF was linked against.
@spec stream_close(stream_handle :: reference()) :: :ok | Xqlite.error()
Closes an active stream and releases its underlying SQLite statement resources.
This function should be called when a stream is no longer needed, either after all rows have been consumed or if the stream needs to be abandoned prematurely. It is safe to call this function multiple times on the same handle; subsequent calls after the first will be no-ops.
stream_handle is the opaque resource returned by stream_open/4.
Returns :ok if successful, or {:error, reason} if the handle is invalid
or an error occurs during finalization (rare).
@spec stream_fetch(stream_handle :: reference(), batch_size :: pos_integer()) :: {:ok, stream_fetch_ok_result()} | :done | Xqlite.error()
Fetches a batch of rows from an active stream handle.
stream_handle is the opaque resource obtained from stream_open/4.
batch_size indicates the maximum number of rows to fetch in this call.
A batch_size of 0 will return an empty list of rows without advancing
the stream, unless the stream is already exhausted (in which case it returns :done).
Returns:
{:ok, %{rows: [[term()]]}}if rows are fetched. The inner list represents a row, and the outer list is the batch of rows. The list of rows may be empty ifbatch_sizewas0and the stream is not yet done, or if the query itself yielded results but this particular fetch point encountered no more rows before hittingSQLITE_DONEor an error within the batch limit.:doneto indicate the end of the stream (all rows have been consumed).{:error, reason}if an error occurs during fetching from SQLite.
@spec stream_get_columns(stream_handle :: reference()) :: {:ok, [String.t()]} | Xqlite.error()
Retrieves the column names for an opened stream.
stream_handle is the opaque resource returned by stream_open/4.
Returns {:ok, list_of_column_names} where list_of_column_names is a list of strings,
or {:error, reason} if the handle is invalid or another error occurs.
The list of column names will be empty if the query yields no columns.
@spec stream_open( conn :: Xqlite.conn(), sql :: String.t(), params :: list() | keyword(), opts :: keyword() ) :: {:ok, reference()} | Xqlite.error()
Prepares a SQL query for streaming and returns an opaque stream handle resource.
This function does not execute the query immediately but prepares it for
row-by-row fetching. The returned handle is opaque and must be used with
other stream_* NIF functions or managed by a higher-level streaming abstraction
like Xqlite.stream/4.
conn is the database connection resource.
sql is the SQL query string.
params is a list of positional parameters or a keyword list of named parameters.
opts is a keyword list for future stream-specific options (currently unused).
Returns {:ok, stream_handle_resource} or {:error, reason}.
The stream_handle_resource is an opaque reference.
@spec total_changes(conn :: Xqlite.conn()) :: {:ok, non_neg_integer()} | Xqlite.error()
Returns the total number of rows modified, inserted, or deleted by all
INSERT, UPDATE, or DELETE statements since the connection was
opened, including changes from triggers.
@spec transaction_status(conn :: Xqlite.conn()) :: {:ok, boolean()} | Xqlite.error()
Returns whether the connection is currently inside a transaction.
Returns {:ok, true} if a transaction is active (i.e., after begin/2
and before commit/1 or rollback/1).
Returns {:ok, false} if the connection is in autocommit mode.
@spec txn_state(Xqlite.conn(), String.t() | nil) :: {:ok, :none | :read | :write | :unknown} | Xqlite.error()
Returns the transaction state for the given schema (defaults to "main").
Equivalent to sqlite3_txn_state. Zero-cost; always available.
Possible values:
:none— no transaction active on this schema.:read— a read transaction is active (SHARED lock).:write— a write transaction is active (RESERVED+ lock).:unknown— future variants (SQLite added a state we don't map yet).
Why not a full 5-state lock ladder?
sqlite3_file_control(SQLITE_FCNTL_LOCKSTATE) would give the full
NONE / SHARED / RESERVED / PENDING / EXCLUSIVE picture, but it requires
SQLite compiled with SQLITE_DEBUG — a build flag that enables every
assert() inside SQLite with a real performance cost. We do not compile
with it. txn_state is the honest production-safe substitute.
@spec unregister_commit_hook(conn :: Xqlite.conn(), handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters a commit subscriber by handle. Idempotent.
@spec unregister_log_hook(handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters a log subscriber by handle. Idempotent — unknown handles are no-ops.
@spec unregister_progress_hook(conn :: Xqlite.conn(), handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters a progress-tick subscriber by its handle.
Idempotent — passing an unknown handle (already-unregistered, or
never registered on this connection) is a no-op and returns :ok.
Returns :ok on success or {:error, :connection_closed} if the
connection has been closed.
@spec unregister_rollback_hook(conn :: Xqlite.conn(), handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters a rollback subscriber by handle. Idempotent.
@spec unregister_update_hook(conn :: Xqlite.conn(), handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters an update subscriber by handle. Idempotent — unknown handles are no-ops.
@spec unregister_wal_hook(conn :: Xqlite.conn(), handle :: non_neg_integer()) :: :ok | Xqlite.error()
Unregisters a WAL subscriber by handle. Idempotent.
@spec wal_checkpoint( Xqlite.conn(), :passive | :full | :restart | :truncate, String.t() | nil ) :: {:ok, map()} | Xqlite.error()
Forces a WAL checkpoint. Equivalent to sqlite3_wal_checkpoint_v2.
mode picks the checkpoint strategy:
:passive(default) — checkpoints as many pages as possible without blocking readers or writers. Never returnsbusy: true.:full— waits for any concurrent writers to finish, then checkpoints all pages. Will setbusy: trueif readers prevent completion.:restart— as:full, plus waits for existing readers to drain so the next writer can restart the WAL from the beginning.:truncate— as:restart, plus truncates the WAL file on disk.
schema is the attached-database name (defaults to nil, meaning the
main database).
Returns {:ok, %{log_pages: n, checkpointed_pages: n, busy: bool}}:
log_pages— size of the WAL log in pages after the checkpoint, or-1if WAL mode is not active.checkpointed_pages— number of pages the checkpoint actually moved from the WAL into the main database, or-1if inactive.busy—trueif the checkpoint did not complete all of its work because other connections held back progress.log_pages/checkpointed_pagesare still populated with partial data.