Packages
exqlite
0.1.1
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.0
0.30.1
0.30.0
0.29.0
0.28.0
0.27.1
0.27.0
0.26.0
0.25.0
0.24.2
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.2
0.16.1
0.16.0
0.15.0
0.14.0
0.13.15
0.13.14
0.13.13
0.13.12
0.13.11
0.13.10
0.13.9
0.13.8
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.2
0.4.1
0.4.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
An Elixir SQLite3 library
Current section
Files
Jump to
Current section
Files
c_src/sqlite3_nif.c
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <erl_nif.h>
#include <sqlite3.h>
#include "utf8.h"
#define MAX_ATOM_LENGTH 255
#define MAX_PATHNAME 512
static ErlNifResourceType* connection_type = NULL;
static ErlNifResourceType* statement_type = NULL;
typedef struct connection
{
sqlite3* db;
} connection_t;
typedef struct statement
{
sqlite3_stmt* statement;
} statement_t;
static const char*
get_sqlite3_return_code_msg(int rc)
{
switch (rc) {
case SQLITE_OK:
return "ok";
case SQLITE_ERROR:
return "sqlite_error";
case SQLITE_INTERNAL:
return "internal";
case SQLITE_PERM:
return "perm";
case SQLITE_ABORT:
return "abort";
case SQLITE_BUSY:
return "busy";
case SQLITE_LOCKED:
return "locked";
case SQLITE_NOMEM:
return "nomem";
case SQLITE_READONLY:
return "readonly";
case SQLITE_INTERRUPT:
return "interrupt";
case SQLITE_IOERR:
return "ioerr";
case SQLITE_CORRUPT:
return "corrupt";
case SQLITE_NOTFOUND:
return "notfound";
case SQLITE_FULL:
return "full";
case SQLITE_CANTOPEN:
return "cantopen";
case SQLITE_PROTOCOL:
return "protocol";
case SQLITE_EMPTY:
return "empty";
case SQLITE_SCHEMA:
return "schema";
case SQLITE_TOOBIG:
return "toobig";
case SQLITE_CONSTRAINT:
return "constraint";
case SQLITE_MISMATCH:
return "mismatch";
case SQLITE_MISUSE:
return "misuse";
case SQLITE_NOLFS:
return "nolfs";
case SQLITE_AUTH:
return "auth";
case SQLITE_FORMAT:
return "format";
case SQLITE_RANGE:
return "range";
case SQLITE_NOTADB:
return "notadb";
case SQLITE_NOTICE:
return "notice";
case SQLITE_WARNING:
return "warning";
case SQLITE_ROW:
return "row";
case SQLITE_DONE:
return "done";
case SQLITE_ERROR_MISSING_COLLSEQ:
return "error_missing_collseq";
case SQLITE_ERROR_RETRY:
return "error_retry";
case SQLITE_ERROR_SNAPSHOT:
return "error_snapshot";
case SQLITE_IOERR_READ:
return "ioerr_read";
case SQLITE_IOERR_SHORT_READ:
return "ioerr_short_read";
case SQLITE_IOERR_WRITE:
return "ioerr_write";
case SQLITE_IOERR_FSYNC:
return "ioerr_fsync";
case SQLITE_IOERR_DIR_FSYNC:
return "ioerr_dir_fsync";
case SQLITE_IOERR_TRUNCATE:
return "ioerr_truncate";
case SQLITE_IOERR_FSTAT:
return "ioerr_fstat";
case SQLITE_IOERR_UNLOCK:
return "ioerr_unlock";
case SQLITE_IOERR_RDLOCK:
return "ioerr_rdlock";
case SQLITE_IOERR_DELETE:
return "ioerr_delete";
case SQLITE_IOERR_BLOCKED:
return "ioerr_blocked";
case SQLITE_IOERR_NOMEM:
return "ioerr_nomem";
case SQLITE_IOERR_ACCESS:
return "ioerr_access";
case SQLITE_IOERR_CHECKRESERVEDLOCK:
return "ioerr_checkreservedlock";
case SQLITE_IOERR_LOCK:
return "ioerr_lock";
case SQLITE_IOERR_CLOSE:
return "ioerr_close";
case SQLITE_IOERR_DIR_CLOSE:
return "ioerr_dir_close";
case SQLITE_IOERR_SHMOPEN:
return "ioerr_shmopen";
case SQLITE_IOERR_SHMSIZE:
return "ioerr_shmsize";
case SQLITE_IOERR_SHMLOCK:
return "ioerr_shmlock";
case SQLITE_IOERR_SHMMAP:
return "ioerr_shmmap";
case SQLITE_IOERR_SEEK:
return "ioerr_seek";
case SQLITE_IOERR_DELETE_NOENT:
return "ioerr_delete_noent";
case SQLITE_IOERR_MMAP:
return "ioerr_mmap";
case SQLITE_IOERR_GETTEMPPATH:
return "ioerr_gettemppath";
case SQLITE_IOERR_CONVPATH:
return "ioerr_convpath";
case SQLITE_IOERR_VNODE:
return "ioerr_vnode";
case SQLITE_IOERR_AUTH:
return "ioerr_auth";
case SQLITE_IOERR_BEGIN_ATOMIC:
return "ioerr_begin_atomic";
case SQLITE_IOERR_COMMIT_ATOMIC:
return "ioerr_commit_atomic";
case SQLITE_IOERR_ROLLBACK_ATOMIC:
return "ioerr_rollback_atomic";
case SQLITE_IOERR_DATA:
return "ioerr_data";
case SQLITE_IOERR_CORRUPTFS:
return "ioerr_corruptfs";
case SQLITE_LOCKED_SHAREDCACHE:
return "locked_sharedcache";
case SQLITE_LOCKED_VTAB:
return "locked_vtab";
case SQLITE_BUSY_RECOVERY:
return "busy_recovery";
case SQLITE_BUSY_SNAPSHOT:
return "busy_snapshot";
case SQLITE_BUSY_TIMEOUT:
return "busy_timeout";
case SQLITE_CANTOPEN_NOTEMPDIR:
return "cantopen_notempdir";
case SQLITE_CANTOPEN_ISDIR:
return "cantopen_isdir";
case SQLITE_CANTOPEN_FULLPATH:
return "cantopen_fullpath";
case SQLITE_CANTOPEN_CONVPATH:
return "cantopen_convpath";
case SQLITE_CANTOPEN_DIRTYWAL:
return "cantopen_dirtywal";
case SQLITE_CANTOPEN_SYMLINK:
return "cantopen_symlink";
case SQLITE_CORRUPT_VTAB:
return "corrupt_vtab";
case SQLITE_CORRUPT_SEQUENCE:
return "corrupt_sequence";
case SQLITE_CORRUPT_INDEX:
return "corrupt_index";
case SQLITE_READONLY_RECOVERY:
return "readonly_recovery";
case SQLITE_READONLY_CANTLOCK:
return "readonly_cantlock";
case SQLITE_READONLY_ROLLBACK:
return "readonly_rollback";
case SQLITE_READONLY_DBMOVED:
return "readonly_dbmoved";
case SQLITE_READONLY_CANTINIT:
return "readonly_cantinit";
case SQLITE_READONLY_DIRECTORY:
return "readonly_directory";
case SQLITE_ABORT_ROLLBACK:
return "abort_rollback";
case SQLITE_CONSTRAINT_CHECK:
return "constraint_check";
case SQLITE_CONSTRAINT_COMMITHOOK:
return "constraint_commithook";
case SQLITE_CONSTRAINT_FOREIGNKEY:
return "constraint_foreignkey";
case SQLITE_CONSTRAINT_FUNCTION:
return "constraint_function";
case SQLITE_CONSTRAINT_NOTNULL:
return "constraint_notnull";
case SQLITE_CONSTRAINT_PRIMARYKEY:
return "constraint_primarykey";
case SQLITE_CONSTRAINT_TRIGGER:
return "constraint_trigger";
case SQLITE_CONSTRAINT_UNIQUE:
return "constraint_unique";
case SQLITE_CONSTRAINT_VTAB:
return "constraint_vtab";
case SQLITE_CONSTRAINT_ROWID:
return "constraint_rowid";
case SQLITE_CONSTRAINT_PINNED:
return "constraint_pinned";
case SQLITE_NOTICE_RECOVER_WAL:
return "notice_recover_wal";
case SQLITE_NOTICE_RECOVER_ROLLBACK:
return "notice_recover_rollback";
case SQLITE_WARNING_AUTOINDEX:
return "warning_autoindex";
default:
return "unknown";
}
}
static const char*
get_sqlite3_error_msg(int rc, sqlite3* db)
{
if (rc == SQLITE_MISUSE) {
return "Sqlite3 was invoked incorrectly.";
}
const char* message = sqlite3_errmsg(db);
if (!message) {
return "No error message available.";
}
return message;
}
static ERL_NIF_TERM
make_atom(ErlNifEnv* env, const char* atom_name)
{
assert(env);
assert(atom_name);
ERL_NIF_TERM atom;
if (enif_make_existing_atom(env, atom_name, &atom, ERL_NIF_LATIN1)) {
return atom;
}
return enif_make_atom(env, atom_name);
}
static ERL_NIF_TERM
make_ok_tuple(ErlNifEnv* env, ERL_NIF_TERM value)
{
assert(env);
assert(value);
return enif_make_tuple2(env, make_atom(env, "ok"), value);
}
static ERL_NIF_TERM
make_error_tuple(ErlNifEnv* env, const char* reason)
{
assert(env);
assert(reason);
return enif_make_tuple2(env, make_atom(env, "error"), make_atom(env, reason));
}
static ERL_NIF_TERM
make_sqlite3_error_tuple(ErlNifEnv* env, int rc, sqlite3* db)
{
const char* error_code_msg = get_sqlite3_return_code_msg(rc);
const char* msg = get_sqlite3_error_msg(rc, db);
return enif_make_tuple2(
env,
make_atom(env, "error"),
enif_make_tuple2(
env,
make_atom(env, error_code_msg),
enif_make_string(env, msg, ERL_NIF_LATIN1)));
}
static ERL_NIF_TERM
exqlite_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
int rc = 0;
int size = 0;
connection_t* conn = NULL;
char filename[MAX_PATHNAME];
ERL_NIF_TERM result;
if (argc != 1) {
return enif_make_badarg(env);
}
size = enif_get_string(env, argv[0], filename, MAX_PATHNAME, ERL_NIF_LATIN1);
if (size <= 0) {
return make_error_tuple(env, "invalid_filename");
}
conn = enif_alloc_resource(connection_type, sizeof(connection_t));
if (!conn) {
return make_error_tuple(env, "out_of_memory");
}
rc = sqlite3_open(filename, &conn->db);
if (rc != SQLITE_OK) {
enif_release_resource(conn);
return make_error_tuple(env, "database_open_failed");
}
sqlite3_busy_timeout(conn->db, 2000);
result = enif_make_resource(env, conn);
enif_release_resource(conn);
return make_ok_tuple(env, result);
}
static ERL_NIF_TERM
exqlite_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
connection_t* conn = NULL;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
sqlite3_close_v2(conn->db);
conn->db = NULL;
return make_atom(env, "ok");
}
///
/// @brief Executes an SQL string.
///
static ERL_NIF_TERM
exqlite_execute(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
ErlNifBinary bin;
connection_t* conn = NULL;
ERL_NIF_TERM eos = enif_make_int(env, 0);
int rc = SQLITE_OK;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
if (!enif_inspect_iolist_as_binary(env, enif_make_list2(env, argv[1], eos), &bin)) {
return make_error_tuple(env, "sql_not_iolist");
}
enif_inspect_iolist_as_binary(env,
enif_make_list2(env, argv[1], eos),
&bin);
rc = sqlite3_exec(conn->db, (char*)bin.data, NULL, NULL, NULL);
if (rc != SQLITE_OK) {
return make_sqlite3_error_tuple(env, rc, conn->db);
}
return make_atom(env, "ok");
}
///
/// @brief Get the number of changes recently done to the database.
///
static ERL_NIF_TERM
exqlite_changes(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
connection_t* conn = NULL;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
int changes = sqlite3_changes(conn->db);
return make_ok_tuple(env, enif_make_int(env, changes));
}
///
/// @brief Prepares an Sqlite3 statement for execution
///
static ERL_NIF_TERM
exqlite_prepare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
ErlNifBinary bin;
connection_t* conn = NULL;
statement_t* statement = NULL;
ERL_NIF_TERM result;
int rc;
ERL_NIF_TERM eos = enif_make_int(env, 0);
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
if (!enif_inspect_iolist_as_binary(env, enif_make_list2(env, argv[1], eos), &bin)) {
return make_error_tuple(env, "sql_not_iolist");
}
statement = enif_alloc_resource(statement_type, sizeof(statement_t));
if (!statement) {
return make_error_tuple(env, "out_of_memory");
}
rc = sqlite3_prepare_v3(conn->db, (char*)bin.data, bin.size, 0, &statement->statement, NULL);
if (rc != SQLITE_OK) {
enif_release_resource(statement);
return make_sqlite3_error_tuple(env, rc, conn->db);
}
result = enif_make_resource(env, statement);
enif_release_resource(statement);
return make_ok_tuple(env, result);
}
static int
bind(ErlNifEnv* env, const ERL_NIF_TERM arg, sqlite3_stmt* statement, int index)
{
int the_int;
ErlNifSInt64 the_long_int;
double the_double;
char the_atom[MAX_ATOM_LENGTH + 1];
ErlNifBinary the_blob;
int arity;
const ERL_NIF_TERM* tuple;
if (enif_get_int(env, arg, &the_int)) {
return sqlite3_bind_int(statement, index, the_int);
}
if (enif_get_int64(env, arg, &the_long_int)) {
return sqlite3_bind_int64(statement, index, the_long_int);
}
if (enif_get_double(env, arg, &the_double)) {
return sqlite3_bind_double(statement, index, the_double);
}
if (enif_get_atom(env, arg, the_atom, sizeof(the_atom), ERL_NIF_LATIN1)) {
if (0 == utf8ncmp("undefined", the_atom, 9)) {
return sqlite3_bind_null(statement, index);
}
return sqlite3_bind_text(statement, index, the_atom, utf8len(the_atom), SQLITE_TRANSIENT);
}
if (enif_inspect_iolist_as_binary(env, arg, &the_blob)) {
return sqlite3_bind_text(statement, index, (char*)the_blob.data, the_blob.size, SQLITE_TRANSIENT);
}
if (enif_get_tuple(env, arg, &arity, &tuple)) {
if (arity != 2) {
return -1;
}
if (enif_get_atom(env, tuple[0], the_atom, sizeof(the_atom), ERL_NIF_LATIN1)) {
if (0 == utf8ncmp("blob", the_atom, 4)) {
if (enif_inspect_iolist_as_binary(env, tuple[1], &the_blob)) {
return sqlite3_bind_blob(statement, index, the_blob.data, the_blob.size, SQLITE_TRANSIENT);
}
}
}
}
return -1;
}
///
/// @brief Binds arguments to the sql statement
///
static ERL_NIF_TERM
exqlite_bind(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
unsigned int parameter_count = 0;
unsigned int argument_list_length = 0;
connection_t* conn = NULL;
statement_t* statement = NULL;
ERL_NIF_TERM list;
ERL_NIF_TERM head;
ERL_NIF_TERM tail;
if (argc != 3) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
if (!enif_get_resource(env, argv[1], statement_type, (void**)&statement)) {
return make_error_tuple(env, "invalid_statement");
}
if (!enif_get_list_length(env, argv[2], &argument_list_length)) {
return make_error_tuple(env, "bad_argument_list");
}
parameter_count = (unsigned int)sqlite3_bind_parameter_count(statement->statement);
if (parameter_count != argument_list_length) {
return make_error_tuple(env, "arguments_wrong_length");
}
sqlite3_reset(statement->statement);
list = argv[2];
for (unsigned int i = 0; i < argument_list_length; i++) {
enif_get_list_cell(env, list, &head, &tail);
int rc = bind(env, head, statement->statement, i + 1);
if (rc == -1) {
return enif_make_tuple2(
env,
make_atom(env, "error"),
enif_make_tuple2(
env,
make_atom(env, "wrong_type"),
head));
}
if (rc != SQLITE_OK) {
return make_sqlite3_error_tuple(env, rc, conn->db);
}
list = tail;
}
return make_atom(env, "ok");
}
static ERL_NIF_TERM
make_binary(ErlNifEnv* env, const void* bytes, unsigned int size)
{
ErlNifBinary blob;
ERL_NIF_TERM term;
if (!enif_alloc_binary(size, &blob)) {
return make_atom(env, "out_of_memory");
}
memcpy(blob.data, bytes, size);
term = enif_make_binary(env, &blob);
enif_release_binary(&blob);
return term;
}
static ERL_NIF_TERM
make_cell(ErlNifEnv* env, sqlite3_stmt* statement, unsigned int i)
{
size_t len = 0;
switch (sqlite3_column_type(statement, i)) {
case SQLITE_INTEGER:
return enif_make_int64(env, sqlite3_column_int64(statement, i));
case SQLITE_FLOAT:
return enif_make_double(env, sqlite3_column_double(statement, i));
case SQLITE_NULL:
return make_atom(env, "undefined");
case SQLITE_BLOB:
len = sqlite3_column_bytes(statement, i);
return enif_make_tuple2(
env,
make_atom(env, "blob"),
make_binary(env, sqlite3_column_blob(statement, i), len));
case SQLITE_TEXT:
len = sqlite3_column_bytes(statement, i);
return enif_make_tuple2(
env,
make_atom(env, "text"),
make_binary(env, sqlite3_column_text(statement, i), len));
default:
return make_atom(env, "unsupported");
}
}
static ERL_NIF_TERM
make_row(ErlNifEnv* env, sqlite3_stmt* statement)
{
assert(env);
assert(statement);
ERL_NIF_TERM* columns = NULL;
ERL_NIF_TERM row;
unsigned int count = sqlite3_column_count(statement);
columns = enif_alloc(sizeof(ERL_NIF_TERM) * count);
if (!columns) {
return make_error_tuple(env, "out_of_memory");
}
for (unsigned int i = 0; i < count; i++) {
columns[i] = make_cell(env, statement, i);
}
row = enif_make_list_from_array(env, columns, count);
enif_free(columns);
return enif_make_tuple2(env, make_atom(env, "row"), row);
}
static ERL_NIF_TERM
exqlite_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
statement_t* statement = NULL;
connection_t* conn = NULL;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
if (!enif_get_resource(env, argv[1], statement_type, (void**)&statement)) {
return make_error_tuple(env, "invalid_statement");
}
int rc = sqlite3_step(statement->statement);
switch (rc) {
case SQLITE_ROW:
return make_row(env, statement->statement);
case SQLITE_BUSY:
return make_atom(env, "busy");
case SQLITE_DONE:
return make_atom(env, "done");
default:
return make_sqlite3_error_tuple(env, rc, conn->db);
}
}
static ERL_NIF_TERM
exqlite_columns(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
int size = 0;
statement_t* statement = NULL;
connection_t* conn = NULL;
ERL_NIF_TERM* columns;
ERL_NIF_TERM result;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
if (!enif_get_resource(env, argv[1], statement_type, (void**)&statement)) {
return make_error_tuple(env, "invalid_statement");
}
size = sqlite3_column_count(statement->statement);
if (size == 0) {
return make_ok_tuple(env, enif_make_list(env, 0));
} else if (size < 0) {
return make_error_tuple(env, "invalid_column_count");
}
columns = enif_alloc(sizeof(ERL_NIF_TERM) * size);
if (!columns) {
return make_error_tuple(env, "out_of_memory");
}
for (int i = 0; i < size; i++) {
const char* name = sqlite3_column_name(statement->statement, i);
const char* type = sqlite3_column_decltype(statement->statement, i);
if (!name) {
enif_free(columns);
return make_error_tuple(env, "out_of_memory");
}
if (type == NULL) {
type = "nil";
}
columns[i] = enif_make_tuple2(env, make_atom(env, name), make_atom(env, type));
}
result = enif_make_list_from_array(env, columns, size);
enif_free(columns);
return make_ok_tuple(env, result);
}
static ERL_NIF_TERM
exqlite_last_insert_rowid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
assert(env);
connection_t* conn = NULL;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], connection_type, (void**)&conn)) {
return make_error_tuple(env, "invalid_connection");
}
sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(conn->db);
return make_ok_tuple(env, enif_make_int64(env, last_rowid));
}
static void
connection_type_destructor(ErlNifEnv* env, void* arg)
{
assert(env);
assert(arg);
connection_t* conn = (connection_t*)arg;
if (conn->db) {
sqlite3_close_v2(conn->db);
conn->db = NULL;
}
}
static void
statement_type_destructor(ErlNifEnv* env, void* arg)
{
assert(env);
statement_t* statement = (statement_t*)arg;
sqlite3_finalize(statement->statement);
statement->statement = NULL;
}
static int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
assert(env);
connection_type = enif_open_resource_type(
env,
"exqlite",
"connection_type",
connection_type_destructor,
ERL_NIF_RT_CREATE,
NULL);
if (!connection_type) {
return -1;
}
statement_type = enif_open_resource_type(
env,
"exqlite",
"statement_type",
statement_type_destructor,
ERL_NIF_RT_CREATE,
NULL);
if (!statement_type) {
return -1;
}
return 0;
}
//
// Most of our nif functions are going to be IO bounded
//
static ErlNifFunc nif_funcs[] = {
{"open", 1, exqlite_open, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"close", 1, exqlite_close, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"execute", 2, exqlite_execute, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"changes", 1, exqlite_changes, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"prepare", 2, exqlite_prepare, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"bind", 3, exqlite_bind, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"step", 2, exqlite_step, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"columns", 2, exqlite_columns, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"last_insert_rowid", 1, exqlite_last_insert_rowid, ERL_NIF_DIRTY_JOB_IO_BOUND},
};
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, NULL)