An SQLite3 driver for Elixir

Overview

Exqlite

Build Status

An Elixir SQLite3 library.

If you are looking for the Ecto adapater, take a look at the Ecto SQLite3 library.

Documentation: https://hexdocs.pm/exqlite Package: https://hex.pm/packages/exqlite

Caveats

  • Prepared statements are not cached.
  • Prepared statements are not immutable. You must be careful when manipulating statements and binding values to statements. Do not try to manipulate the statements concurrently. Keep it isolated to one process.
  • Simultaneous writing is not supported by SQLite3 and will not be supported here.
  • All native calls are run through the Dirty NIF scheduler.
  • Datetimes are stored without offsets. This is due to how SQLite3 handles date and times. If you would like to store a timezone, you will need to create a second column somewhere storing the timezone name and shifting it when you get it from the database. This is more reliable than storing the offset as +03:00 as it does not respect daylight savings time.

Installation

defp deps do
  {:exqlite, "~> 0.5.4"}
end

Configuration

config :exqlite, default_chunk_size: 100
  • default_chunk_size - The chunk size that is used when multi-stepping when not specifying the chunk size explicitly.

Usage

The Exqlite.Sqlite3 module usage is fairly straight forward.

# We'll just keep it in memory right now
{:ok, conn} = Exqlite.Sqlite3.open(":memory:")

# Create the table
:ok = Exqlite.Sqlite3.execute(conn, "create table test (id integer primary key, stuff text)");

# Prepare a statement
{:ok, statement} = Exqlite.Sqlite3.prepare(conn, "insert into test (stuff) values (?1)")
:ok = Exqlite.Sqlite3.bind(conn, statement, ["Hello world"])

# Step is used to run statements
:done = Exqlite.Sqlite3.step(conn, statement)

# Prepare a select statement
{:ok, statement} = Exqlite.Sqlite3.prepare(conn, "select id, stuff from test");

# Get the results
{:row, [1, "Hello world"]} = Exqlite.Sqlite3.step(conn, statement)

# No more results
:done = Exqlite.Sqlite3.step(conn, statement)

Why SQLite3

I needed an Ecto3 adapter to store time series data for a personal project. I didn't want to go through the hassle of trying to setup a postgres database or mysql database when I was just wanting to explore data ingestion and some map reduce problems.

I also noticed that other SQLite3 implementations didn't really fit my needs. At some point I also wanted to use this with a nerves project on an embedded device that would be resiliant to power outages and still maintain some state that ets can not afford.

Under The Hood

We are using the Dirty NIF scheduler to execute the sqlite calls. The rationale behind this is that maintaining each sqlite's connection command pool is complicated and error prone.

Contributing

Feel free to check the project out and submit pull requests.

Comments
  • Performance issues / possible memory leak

    Performance issues / possible memory leak

    Howdy :wave:

    I'm in the process of converting a market making trading system that creates many orders from ETS to Ecto. I plan on supporting any database that Ecto currently has support for, but I've started with SQLite because I want to be able to distribute it without any external dependencies.

    SQLite is probably not the best choice for this kind of system due to the high number of writes. But I've pushed forward with the philosophy that if I can make it work somewhat performant in SQLite it should be great with other DB's.

    Everything has gone pretty well so far, however now that I'm running it in production for long periods of time I'm noticing that there is severe performance degradation over time that causes a total lock in the SQLite DB. I've attached a graph below of my telemetry output. It shows:

    • Linear memory growth
    • Periodic spikes down in memory (I'm assuming GC or freed memory)
    • Eventually a total lock where the metrics are no longer getting updated

    tai-vm-sqlite-locked

    I'm also attaching a graph of query times with the hope that they're helpful

    tai-sqlite-orders-query-times-locked

    The following SQL statements are executed regularly as the hot path

    06:12:03.214 [debug] QUERY OK source="orders" db=1.1ms idle=181.7ms
    SELECT o0.client_id, o0.close, o0.credential, o0.cumulative_qty, o0.last_received_at, o0.last_venue_timestamp, o0.leaves_qty, o0.post_only, o0.price, o0.product_symbol, o0.product_type, o0.qty, o0.side, o0.status, o0.time_in_force, o0.type, o0.venue, o0.venue_order_id, o0.venue_product_symbol, o0.inserted_at, o0.updated_at FROM orders AS o0 WHERE (o0.client_id = ?) [<<14, 229, 20, 50, 21, 17, 75, 71, 159, 117, 143, 85, 153, 162, 63, 28>>]
    
    06:12:03.217 [debug] QUERY OK db=2.2ms queue=0.1ms idle=111.7ms
    begin []
    
    06:12:03.219 [debug] QUERY OK source="orders" db=1.9ms
    UPDATE orders AS o0 SET status = ?, leaves_qty = ?, last_received_at = ?, last_venue_timestamp = ? WHERE ((o0.client_id = ?) AND o0.status IN (?,?,?,?)) RETURNING client_id, close, credential, cumulative_qty, last_received_at, last_venue_timestamp, leaves_qty, post_only, price, product_symbol, product_type, qty, side, status, time_in_force, type, venue, venue_order_id, venue_product_symbol ["canceled", "0", ~U[2021-06-01 06:12:03Z], ~U[2021-06-01 06:12:02Z], <<14, 229, 20, 50, 21, 17, 75, 71, 159, 117, 143, 85, 153, 162, 63, 28>>, "create_accepted", "open", "pending_cancel", "cancel_accepted"]
    
    06:12:03.222 [debug] QUERY OK db=1.7ms
    INSERT INTO order_transitions (order_client_id,transition,id,inserted_at,updated_at) VALUES (?,?,?,?,?) [<<14, 229, 20, 50, 21, 17, 75, 71, 159, 117, 143, 85, 153, 162, 63, 28>>, "\"{\\\"last_received_at\\\":\\\"2021-06-01T06:12:03.212374Z\\\",\\\"last_venue_timestamp\\\":\\\"2021-06-01T06:12:02.986417Z\\\",\\\"__type__\\\":\\\"cancel\\\"}\"", <<29, 70, 168, 213, 105, 47, 77, 115, 169, 224, 255, 68, 17, 101, 121, 245>>, ~U[2021-06-01 06:12:03.219952Z], ~U[2021-06-01 06:12:03.219952Z]]
    
    06:12:03.222 [debug] QUERY OK db=0.7ms
    commit []
    

    They're issued from this Elixir module https://github.com/fremantle-industries/tai/blob/orders-ecto-repo/apps/tai/lib/tai/new_orders/services/apply_order_transition.ex

      defp update_order_and_save_transition(client_id, %transition_mod{} = transition, order_transition_changeset) do
        from_status = transition_mod.from()
        attrs = transition_mod.attrs(transition)
        update_order_query = build_update_order_query(client_id, from_status, attrs)
    
        # The previous order needs to be selected outside of the transaction to
        # prevent a possible deadlock.
        case OrderRepo.get(Order, client_id) do
          %Order{} = previous_order_before_update ->
            # Check if the existing order has a status that supports this
            # transition in memory and only rely on the transaction rollback
            # as a fallback. There is a performance penalty to rolling back
            # a transaction.
            if Enum.member?(from_status, previous_order_before_update.status) do
              fn ->
                case OrderRepo.update_all(update_order_query, []) do
                  {0, []} ->
                    status_was = previous_order_before_update.status
                    reason = {:invalid_status, status_was}
                    OrderRepo.rollback(reason)
    
                  {1, [current_order]} ->
                    case OrderRepo.insert(order_transition_changeset) do
                      {:ok, _} -> {previous_order_before_update, current_order}
                      {:error, reason} -> OrderRepo.rollback(reason)
                    end
    
                  {:error, reason} ->
                    OrderRepo.rollback(reason)
                end
              end
              |> OrderRepo.transaction()
            else
              status_was = previous_order_before_update.status
              reason = {:invalid_status, status_was}
              {:error, reason}
            end
    
          nil ->
            {:error, :order_not_found}
        end
      end
    
    bug 
    opened by rupurt 33
  • Database busy error

    Database busy error

    @kevinlang I am going to track the database busy issue here.

    Previous discussions:

    • https://github.com/warmwaffles/exqlite/pull/38
    • https://github.com/warmwaffles/exqlite/pull/39#issuecomment-792447244
    bug 
    opened by warmwaffles 25
  • Upstreaming the ecto-related parts

    Upstreaming the ecto-related parts

    I was going to start a new conversation in the elixir-ecto Google group to see what the path forward is for upstreaming most of the ecto related stuff into ecto_sql, now that nearly all of the integration tests are onboarded and stable.

    In that scenario, this exqlite repo would mainly contain the core non-ecto driver parts, like the db_connection stuff and the NIF.

    Does that sound good, @warmwaffles ? Any reservations or thoughts?

    opened by kevinlang 22
  • Use a struct as response from executed query to get the rows and columns

    Use a struct as response from executed query to get the rows and columns

    Hi!

    Firstly, I want to say that I loved the project and it's great to have support for SQLite in Elixir.

    We have been building a new feature to support SQLite through livebook app and kino_db library, which allows users to input their database path and loads data directly from a Livebook (same as Jupyter Notebook).

    And one of our features is to support the "table" format to visualize data, but Exqlite doesn't return a response with columns and rows to make it happen, so I've been thinking about make some contributions to the project.

    Context

    In this PR we added the support to handle Exqlite connection and how we should execute the user's query input. And our goal is make it easy to implement the Table.Reader protocol from table. Since we're not going to add the protocol here, we only need row and columns information.

    Then. I've been thinking if it should be a option in the Exqlite.Connection.connect/1 function or maybe create a new function to fetch all rows and returns the Exqlite.Query struct or maybe a new one to represent the result from SQLite.

    What you all think? Would be great to talk about, and if y'all have any recommendations or thoughts, please feel free to send.

    feature request 
    opened by aleDsz 21
  • Concerning warning compiling under Nerves

    Concerning warning compiling under Nerves

    Is this something to worry about?

    08:41:16.929 [warn]  The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
    {:error,
     {:load_failed,
      'Failed to load NIF library: \'/home/lawik/projects/calendar_gadget/firmware/_build/rpi0_dev/lib/exqlite/priv/sqlite3_nif.so: wrong ELF class: ELFCLASS32\''}}
    

    I haven't tried it yet, maybe it works, I'll update as I do.

    bug 
    opened by lawik 16
  • Add windows to CI

    Add windows to CI

    This is my first attempt for the Windows CI (and nearly my fist attempt to work with Github Actions). The extensions_test.exs is currently failing, so I mark this as draft first.

    Let me tell your thoughts?

    Close #120

    opened by cw789 15
  • Segfault when exceeding DBConnection timeout

    Segfault when exceeding DBConnection timeout

    I was debugging a sudden reboot on our nerves system with a expensive query. I had the memory usage and OOM in mind, but today I found out that raising the timeout actually makes the query succeed (no reboot). Making the timout be exceeded on my local machine I could reproduce the issue and even get the seg fault message (see below). I don't think the query matters for as long as the timeout is exceeded.

    iex(6)> Task.start(fn -> Repo.checkout(fn -> Ecto.Adapters.SQL.query!(Repo, query) end, timeout: :timer.seconds(1)) end)
    {:ok, #PID<0.2359.0>}
    iex(7)> 11:24:58.427 [error] Exqlite.Connection (#PID<0.2164.0>) disconnected: ** (DBConnection.ConnectionError) client #PID<0.2359.0> timed out because it queued and checked out the connection for longer than 1000ms
    
    #PID<0.2359.0> was at location:
    
        (exqlite 0.8.6) lib/exqlite/sqlite3.ex:91: Exqlite.Sqlite3.multi_step/3
        (exqlite 0.8.6) lib/exqlite/sqlite3.ex:138: Exqlite.Sqlite3.fetch_all/4
        (exqlite 0.8.6) lib/exqlite/connection.ex:529: Exqlite.Connection.get_rows/2
        (exqlite 0.8.6) lib/exqlite/connection.ex:475: Exqlite.Connection.execute/4
        (db_connection 2.4.1) lib/db_connection/holder.ex:354: DBConnection.Holder.holder_apply/4
        (db_connection 2.4.1) lib/db_connection.ex:1333: DBConnection.run_execute/5
        (db_connection 2.4.1) lib/db_connection.ex:650: DBConnection.execute/4
    
    11:25:00.283 [debug] …
    [os_mon] cpu supervisor port (cpu_sup): Erlang has closed
    [os_mon] memory supervisor port (memsup): Erlang has closed
    [1]    37300 segmentation fault  iex -S mix
    
    opened by LostKobrakai 14
  • Unable to handle BIGINT on 32 Bit arm

    Unable to handle BIGINT on 32 Bit arm

    Hi,

    I am currently working on a custom armv7 board (similar to a raspberry pi), and am having trouble upgrading to using exqlite. I was using esqlite, and everything was working fine, but due to the fact that https://github.com/elixir-sqlite/sqlitex and https://github.com/elixir-sqlite/sqlite_ecto2 are no longer being maintained and needed to use ecto 2, I am trying to switch over to the exqlite, ecto_sqlite3 combination where I can also get ecto 3.

    The issue in exqlite is failing to handle integers greater than 32 bit in size during a schema migration, although esqlite can handle them. For example, for the integer 20180801160101, -1250163803 is being returned when doing a multistep.

    The ecto query is

    #Ecto.Query<from s0 in "schema_migrations", select: type(s0.version, :integer)>
    

    Unfortunately, I am unable to upload the sqlite3 file I am using due to GitHub restrictions.

    Some things to note:

    • This works fine on 64 bit machines
    • Both esqlite and exqlite are using sqlite v3.38 (as in the latest of both repositories)
    • I have not changed the schema_migrations schema. It is this one that is getting used: https://github.com/elixir-ecto/ecto_sql/blob/master/lib/ecto/migration/schema_migration.ex#L10

    Software Versions:

    • Elixir 1.12.3-otp-24
    • Erlang 24.1.3
    • Linux Kernel 5.4.66
    • exqlite 0.10.2
    • sqlite 3.38
    • ecto_sql - 3.380-dev
    • ecto 3.7.0
    • ecto_sqlite3 - 0.7.4
    bug 
    opened by alanj853 13
  • Fix segfault when database connections timeout

    Fix segfault when database connections timeout

    Hypothesis

    the issue seems to be that there is a race condition between exqlite_close and exqlite_prepare. The issue happens when we execute sqlite3_prepare_v3 on a connection after we close the connection with sqlite3_close_v2.

    sqlite3_close_v2 does handle previously prepared statements, but here we are preparing the statement in-parallel while we are closing the connection. Which is causing occasional SQLITE_MISUSE.

    How can we reach this state?

    Given

    • exqlite_close is executed by connection process
    • while handle_prepare and other callbacks are called in the client process
    • a NIF call can not be interrupted/cancelled once started, irrespective of client side process timeout, or process kill.

    Scenario

    1. client checkout a connection and makes a query
    2. client makes exqlite_prepare NIF call but fail to complete within connection timeout duration. It 1ms in the test case. This NIF call is still running or scheduled to run even after the timeout.
    3. due to connection timeout, connection-process receives timeout and initiate connection close (disconnect callback)
    4. connection-process calls exqlite_close NIF

    2 & 4 are run in-parallel leading to race-condition mentioned previously causing segfault.

    Fix

    I tried to fix the race-condition using mutex, and sofar haven't seen a single failure.

    This is PoC, I guess we should handle multiple other cases as well, not just the one between close & prepare if this is the issue.

    Should fix https://github.com/elixir-sqlite/exqlite/issues/190

    opened by akash-akya 12
  • Disable debug (or strip binary)

    Disable debug (or strip binary)

    Hi, I see at the top of the makefile we have:

    CFLAGS ?= -g

    The output binary for me (on arm32bit) is 9398756 Oct 16 16:51 lib/exqlite-0.6.4/priv/sqlite3_nif.so

    However, after stripping I get: 1589804 Oct 25 10:39 lib/exqlite-0.6.4/priv/sqlite3_nif.so

    I'm building to a semi-embedded type system, so this is quite a considerable disk saving.

    Would you consider making the stripped, non debug exe the standard situation and a flag to toggle on debugging? Alternatively do you have a suggestion on how to disable the debug as part of my release build please?

    Thanks for considering this

    feature request 
    opened by ewildgoose 12
  • sqlite3_nif: Unspecified error

    sqlite3_nif: Unspecified error

    Using Windows 10, exqite appears to build correctly, but I get sqlite3_nif: Unspecified error when trying to run {:ok, conn} = Exqlite.Sqlite3.open(":memory:")

    c:\git\test-elixir\playground>mix deps.get
    -> Running mix loadconfig (inside Playground.MixProject)
    <- Ran mix loadconfig in 0ms
    -> Running mix deps.get (inside Playground.MixProject)
    -> Running mix archive.check (inside Playground.MixProject)
    <- Ran mix archive.check in 0ms
    Resolving Hex dependencies...
    Resolution completed in 0.117s
    New:
      connection 1.1.0
      db_connection 2.4.3
      elixir_make 0.7.3
      exqlite 0.12.0
      telemetry 1.1.0
    * Getting exqlite (Hex package)
      Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/exqlite-0.12.0.tar)
    * Getting db_connection (Hex package)
      Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/db_connection-2.4.3.tar)
    * Getting elixir_make (Hex package)
      Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/elixir_make-0.7.3.tar)
    * Getting connection (Hex package)
      Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/connection-1.1.0.tar)
    * Getting telemetry (Hex package)
      Fetched package (https://repo.hex.pm/tarballs/telemetry-1.1.0.tar)
    -> Running mix will_recompile (inside Playground.MixProject)
    <- Ran mix will_recompile in 1ms
    <- Ran mix deps.get in 1044ms
    
    c:\git\test-elixir\playground>iex -S mix
    -> Running mix loadconfig (inside Playground.MixProject)
    <- Ran mix loadconfig in 0ms
    -> Running mix run (inside Playground.MixProject)
    -> Running mix app.start (inside Playground.MixProject)
    -> Running mix app.config (inside Playground.MixProject)
    -> Running mix compile (inside Playground.MixProject)
    -> Running mix loadpaths (inside Playground.MixProject)
    -> Running mix archive.check (inside Playground.MixProject)
    <- Ran mix archive.check in 0ms
    -> Running mix deps.loadpaths (inside Playground.MixProject)
    -> Running mix deps.precompile (inside Playground.MixProject)
    <- Ran mix deps.precompile in 2ms
    ==> connection
    -> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    -> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    <- Ran mix loadpaths in 0ms
    -> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    -> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    <- Ran mix compile.yecc in 1ms
    -> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    <- Ran mix compile.leex in 0ms
    -> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    <- Ran mix compile.erlang in 0ms
    -> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    Compiling 1 file (.ex)
    <- Ran mix compile.elixir in 194ms
    -> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
    Generated connection app
    <- Ran mix compile.app in 3ms
    <- Ran mix compile.all in 212ms
    <- Ran mix compile in 213ms
    ===> Expanded command sequence to be run: []
    ===> Running provider: do
    ===> Expanded command sequence to be run: [app_discovery,{bare,compile}]
    ===> Running provider: app_discovery
    ===> Found top-level apps: [telemetry]
            using config: [{src_dirs,["src"]},{lib_dirs,["apps/*","lib/*","."]}]
    ===> Running provider: {bare,compile}
    ===> Compile (untagged)
    ===> Running hooks for compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {pre_hooks, []}.
    ===> Running hooks for erlc_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {pre_hooks, []}.
    ===> Analyzing applications...
    ===> Compiling telemetry
    ===> compile options: {erl_opts, [debug_info]}.
    ===> files to analyze ["c:/git/test-elixir/playground/deps/telemetry/src/telemetry_sup.erl",
                           "c:/git/test-elixir/playground/deps/telemetry/src/telemetry_handler_table.erl",
                           "c:/git/test-elixir/playground/deps/telemetry/src/telemetry_app.erl",
                           "c:/git/test-elixir/playground/deps/telemetry/src/telemetry.erl"]
    ===>      Compiled telemetry_app.erl
    ===>      Compiled telemetry_sup.erl
    ===>      Compiled telemetry_handler_table.erl
    ===>      Compiled telemetry.erl
    ===> Running hooks for erlc_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {post_hooks, []}.
    ===> Running hooks for app_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {pre_hooks, []}.
    ===> Running hooks for app_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {post_hooks, []}.
    ===> Running hooks for compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
    ===>    {post_hooks, []}.
    ==> db_connection
    -> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    -> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    <- Ran mix loadpaths in 0ms
    -> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    -> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    <- Ran mix compile.yecc in 0ms
    -> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    <- Ran mix compile.leex in 0ms
    -> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    <- Ran mix compile.erlang in 0ms
    -> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    Compiling 14 files (.ex)
    <- Ran mix compile.elixir in 706ms
    -> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
    Generated db_connection app
    <- Ran mix compile.app in 1ms
    <- Ran mix compile.all in 723ms
    <- Ran mix compile in 724ms
    ==> elixir_make
    -> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    -> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    <- Ran mix loadpaths in 0ms
    -> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    -> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    <- Ran mix compile.yecc in 0ms
    -> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    <- Ran mix compile.leex in 0ms
    -> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    <- Ran mix compile.erlang in 0ms
    -> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    Compiling 6 files (.ex)
    <- Ran mix compile.elixir in 199ms
    -> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
    Generated elixir_make app
    <- Ran mix compile.app in 0ms
    <- Ran mix compile.all in 222ms
    <- Ran mix compile in 222ms
    ==> exqlite
    -> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    -> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    <- Ran mix loadpaths in 0ms
    -> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    -> Running mix compile.elixir_make --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    
    Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
            del /f /q priv
    Could Not Find c:\git\test-elixir\playground\deps\exqlite\priv
            erl -noshell -s init stop -eval "io:setopts(standard_io, [{encoding, unicode}]), io:format(\"ERTS_INCLUDE_PATH=~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)])." > Makefile.auto.win
            nmake -                   -F Makefile.win priv\sqlite3_nif.dll
    
    Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
            if NOT EXIST "priv" mkdir "priv"
            cl -I"c:/Program Files/Erlang OTP/usr/include" -DNDEBUG=1 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_RBU=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS3=1 -DENABLE_UPDATE_DELETE_LIMIT=1 -DENABLE_STAT4=1 -DENABLE_SOUNDEX=1 -DENABLE_LOAD_EXTENSION=1 -DENABLE_FTS3_PARENTHESIS=1 -DALLOW_COVERING_INDEX_SCAN=1 -DHAVE_USLEEP=1 -DSQLITE_DQS=0 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_USE_URI=1 -DSQLITE_THREADSAFE=1 -Ic_src -EHsc -O2  -I"c:/Program Files/Erlang OTP/erts-13.0.4/include/" -LD -MD -Fepriv\sqlite3_nif.dll c_src\sqlite3.c  c_src\sqlite3_nif.c
    Microsoft (R) C/C++ Optimizing Compiler Version 19.34.31937 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    sqlite3.c
    sqlite3_nif.c
    Generating Code...
    Microsoft (R) Incremental Linker Version 14.34.31937.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /dll
    /implib:priv\sqlite3_nif.lib
    /out:priv\sqlite3_nif.dll
    sqlite3.obj
    sqlite3_nif.obj
       Creating library priv\sqlite3_nif.lib and object priv\sqlite3_nif.exp
    <- Ran mix compile.elixir_make in 7901ms
    -> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    <- Ran mix compile.yecc in 0ms
    -> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    <- Ran mix compile.leex in 0ms
    -> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    <- Ran mix compile.erlang in 0ms
    -> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    Compiling 13 files (.ex)
    <- Ran mix compile.elixir in 359ms
    -> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
    Generated exqlite app
    <- Ran mix compile.app in 1ms
    <- Ran mix compile.all in 8311ms
    <- Ran mix compile in 8312ms
    ==> playground
    -> Running mix will_recompile (inside Playground.MixProject)
    <- Ran mix will_recompile in 0ms
    <- Ran mix deps.loadpaths in 11010ms
    <- Ran mix loadpaths in 11011ms
    -> Running mix compile.all (inside Playground.MixProject)
    -> Running mix compile.yecc (inside Playground.MixProject)
    <- Ran mix compile.yecc in 0ms
    -> Running mix compile.leex (inside Playground.MixProject)
    <- Ran mix compile.leex in 0ms
    -> Running mix compile.erlang (inside Playground.MixProject)
    <- Ran mix compile.erlang in 0ms
    -> Running mix compile.elixir (inside Playground.MixProject)
    Compiling 1 file (.ex)
    <- Ran mix compile.elixir in 22ms
    -> Running mix compile.app (inside Playground.MixProject)
    Generated playground app
    <- Ran mix compile.app in 1ms
    <- Ran mix compile.all in 29ms
    -> Running mix compile.protocols (inside Playground.MixProject)
    <- Ran mix compile.protocols in 226ms
    <- Ran mix compile in 11281ms
    <- Ran mix app.config in 11282ms
    <- Ran mix app.start in 11288ms
    <- Ran mix run in 11290ms
    Interactive Elixir (1.14.2) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> {:ok, conn} = Exqlite.Sqlite3.open(":memory:")
    ** (UndefinedFunctionError) function Exqlite.Sqlite3NIF.open/2 is undefined (module Exqlite.Sqlite3NIF is not available)
        (exqlite 0.12.0) Exqlite.Sqlite3NIF.open(':memory:', 6)
        iex:1: (file)
    iex(1)>
    16:44:34.039 [warning] The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
    {:error,
     {:load_failed,
      'Failed to load NIF library c:/git/test-elixir/playground/_build/dev/lib/exqlite/priv/sqlite3_nif: \'Unspecified error\''}}
    
    iex(1)>
    
    opened by voltagex 11
  • SQLCipher: How to set `cipher_compatibility`?

    SQLCipher: How to set `cipher_compatibility`?

    Thank you so much for this library!

    I followed the README to use SQLCipher, and compiling worked great.

    When trying to open an encrypted database I got this error:

    file is not a database
    

    The problem is that the database was encrypted with SQLCipher version 3 while I'm using version 4. It works when I manually set set_pragma(db, "cipher_compatibility", 3) in Exqlite.Connection.set_key. This is the equivalent to doing:

    PRAGMA cipher_compatibility = 3;
    

    I was wondering: how to implement this properly?

    Any call after set_key without setting the version, like https://github.com/elixir-sqlite/exqlite/blob/d1f71760bde4a6558734446065acf60028b0969b/lib/exqlite/connection.ex#L447 will lead to file is not a database errors. I guess cipher_compatibility is not a standard pragma value but specific to SQLCipher. I'm thankful for any tips.

    opened by adri 7
  • Feature request: Add support for Data Change Notification Callbacks

    Feature request: Add support for Data Change Notification Callbacks

    It would be great if exqlite supported Data Change Notification Callbacks, eg. set_update_hook, similar to mmzeeman/esqlite. esqlite is great, however it is very Erlang-focused and the original Elixir wrapper library for it has been abandoned. It would be very useful to be able to act on hooks within a project that is using ecto_sqlite3.

    opened by OldhamMade 6
  • Integration of mvsqlite

    Integration of mvsqlite

    I was looking at https://github.com/losfair/mvsqlite and it seems like it's a drop in replacement for sqlite.

    I wasn't sure how to do the integration to elixir properly and it feels like I should fork exqlite, but I didn't want to separate efforts.

    opened by fire 13
  • Benchmark multi_step vs step implementation

    Benchmark multi_step vs step implementation

    Originally I implemented the adapter to use single steps and just let it work with erlang's scheduler. I remember I ran into issues where selecting data was actually slower than just batching the results in a list and returning them.

    What I would like to do is add a benchee test that works with both methods on a large data set, to really see what sort of improvements can be made and can be quantified.

    If we can just utilize step alone and let the scheduler work, that would simplify the NIF code.

    opened by warmwaffles 0
  • Replace DirtyNIF execution model with threadpool

    Replace DirtyNIF execution model with threadpool

    The dirtynif execution model is okay for most cases, but we have an issue where long running writes need to timeout / be interrupted mid execution and aborted. The only way to do that is to utilize https://sqlite.org/c3ref/progress_handler.html

    opened by warmwaffles 0
Releases(v0.12.0)
Owner
elixir-sqlite
Elixir Sqlite
elixir-sqlite
An extra-lightweight Ruby gem for working with SQLite3 databases

Extralite Extralite is an extra-lightweight SQLite3 wrapper for Ruby. It provides a single class with a minimal set of methods to interact with an SQL

Digital Fabric 115 Dec 14, 2022
An Sqlite3 Elixir library

Exqlite An SQLite3 library with an Ecto adapter implementation. Caveats When using the Ecto adapter, all prepared statements are cached using an LRU c

Matthew Johnston 147 Dec 30, 2022
SQLite3++ - C++ wrapper of SQLite3 API

ANNOUNCEMENTS Use files in headeronly_src directory. The files in src are exactly same but in the form of h/cpp files, which you need to compile and l

Wongoo Lee 506 Jan 3, 2023
My TFLite-Elixir bindings

TFLite-Elixir [WIP] There are mainly two reasons why I write this library. Port has limited throughput. It would be easier and more flexible to make c

Cocoa 14 Sep 20, 2022
Loads a signed kernel driver which allows you to map any driver to kernel mode without any traces of the signed / mapped driver.

CosMapper Loads a signed kernel driver (signed with leaked cert) which allows you to map any driver to kernel mode without any traces of the signed /

null 157 Jan 2, 2023
DOS CMD line build of a current SQLite3

DOSQLite This is a DOS/32 build of the command line tool for SQLite 3 based on sqlite-amalgamation-3340100. It was built using DJGPP like my other pro

null 8 Nov 25, 2022
An extra-lightweight Ruby gem for working with SQLite3 databases

Extralite Extralite is an extra-lightweight SQLite3 wrapper for Ruby. It provides a single class with a minimal set of methods to interact with an SQL

Digital Fabric 115 Dec 14, 2022
SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.

SQLiteC++ SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper. About SQLiteC++: SQLiteC++ offers an encapsulation around the native C

Sébastien Rombauts 1.6k Dec 31, 2022
This is a demo for sqlite3.

说明 This is a demo for sqlite3. sqlite3 基础知识 sqlite3 命令分两类 系统命令 以 . 开头的命令 .q 退出sqlite3命令模式 .open 创建一个数据库 .databases 列出数据库 .schema 列出表结构 .tables 列出数据库中的

流浪小兵 1 Nov 24, 2021
VSQLite++ - A welldesigned and portable SQLite3 Wrapper for C++ (C)

VSQLite++ - A welldesigned and portable SQLite3 Wrapper for C++ (C)

Vinzenz 'evilissimo' Feenstra 27 Dec 29, 2021
libsinsp, libscap, the kernel module driver, and the eBPF driver sources

falcosecurity/libs As per the OSS Libraries Contribution Plan, this repository has been chosen to be the new home for libsinsp, libscap, the kernel mo

Falco 133 Dec 29, 2022
manually map driver for a signed driver memory space

smap manually map driver for a signed driver memory space credits https://github.com/btbd/umap tested system Windows 10 Education 20H2 UEFI installati

ekknod 89 Dec 17, 2022
x64 Windows kernel driver mapper, inject unsigned driver using anycall

anymapper x64 Windows kernel driver mapper, inject unsigned driver using anycall This project is WIP. Todo Fix: Can't make API calls from IAT nor func

Kento Oki 72 Dec 26, 2022
Driver leap - Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries

Driver Leap Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries Installation (for users) Install Ultralea

null 68 Jan 5, 2023
Hygieia, a vulnerable driver traces scanner written in C++ as an x64 Windows kernel driver.

Hygieia The Greek goddess of health, her name is the source for the word "hygiene". Hygieia is a windows driver that works similarly to how pagewalkr

Deputation 103 Dec 4, 2022
SinMapper - usermode driver mapper that forcefully loads any signed kernel driver

usermode driver mapper that forcefully loads any signed kernel driver (legit cert) with a big enough section (example: .data, .rdata) to map your driver over. the main focus of this project is to prevent modern anti-cheats (BattlEye, EAC) from finding your driver and having the power to hook anything due to being inside of legit memory (signed legit driver).

null 170 Dec 29, 2022
ARCHIVED - libbson has moved to https://github.com/mongodb/mongo-c-driver/tree/master/src/libbson

libbson ARCHIVED - libbson is now maintained in a subdirectory of the libmongoc project: https://github.com/mongodb/mongo-c-driver/tree/master/src/lib

mongodb 344 Nov 29, 2022
This project aims to facilitate debugging a kernel driver in windows by adding support for a code change on the fly without reboot/unload, and more!

BSOD Survivor Tired of always telling yourself when you got a BSOD that what if I could just return to the caller function which caused the BSOD, and

Ido Westler 159 Dec 21, 2022
Lotus 1-2-3 R4D Display Driver for DOSEMU

Lotus 1-2-3 R4D Display Driver for DOSEMU2 This is a WIP display driver for Lotus 1-2-3 R4D to enable support for arbitrary text resolutions in DOSEMU

Tavis Ormandy 112 Dec 2, 2022
C++ Driver for MongoDB

MongoDB C++ Driver Welcome to the MongoDB C++ Driver! Branches - releases/stable versus master The default checkout branch of this repository is relea

mongodb 931 Dec 28, 2022