An Sqlite3 Elixir library

Overview

Exqlite

An SQLite3 library with an Ecto adapter implementation.

Caveats

  • When using the Ecto adapter, all prepared statements are cached using an LRU cache.
  • 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.
  • 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.1.0"}
end

Usage Without Ecto

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)

Usage With Ecto

Define your repo similar to this.

defmodule MyApp.Repo do
  use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Exqlite
end

Configure your repository similar to the following. If you want to know more about the possible options to pass the repository, checkout the documentation for Exqlite.Connection.connect/1. It will have more information on what is configurable.

config :my_app,
  ecto_repos: [MyApp.Repo]

config :my_app, MyApp.Repo,
  database: "path/to/my/database.db",
  show_sensitive_data_on_connection_error: false,
  journal_mode: :wal,
  cache_size: -64000,
  temp_store: :memory,
  pool_size: 1

Note

  • Pool size is set to 1 but can be increased to 4. When set to 10 there was a lot of database busy errors. Currently this is a known issue and is being looked in to.

  • Cache size is a negative number because that is how SQLite3 defines the cache size in kilobytes. If you make it positive, that is the number of pages in memory to use. Both have their pros and cons. Check the documentation out for SQLite3.

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
  • [question] sqlite extension alignment problem in exqlite, but not in sqlite3

    [question] sqlite extension alignment problem in exqlite, but not in sqlite3

    👋

    I understand that it's unlikely to be a problem in exqlite, but just in case you have any idea as to what I'm doing wrong.


    Repo: https://github.com/ruslandoga/sqlite-zig-problem

    I'm trying to write an extension for sqlite in zig and I'm getting an alignment panic when fetching sqlite's aggregate context. But, I'm only getting it when executing the query from elixir, not from sqlite3 cli.

    Meaning,

    sqlite> .load dist/extc
    sqlite> .load dist/extzig
    
    -- this uses c extension
    sqlite> with recursive ten(x) as (select 1 union all select x+1 from ten where x<10) select sumc(x) from ten;
    55.0
    
    -- this uses zig extension
    sqlite> with recursive ten(x) as (select 1 union all select x+1 from ten where x<10) select sumzig(x) from ten;
    55.0
    

    but in elixir:

    iex(1)> E.sumc
    # [debug] QUERY OK db=0.6ms decode=1.3ms idle=738.5ms
    # with recursive ten(x) as (select 1 union all select x+1 from ten where x<10) select sumc(x) from ten []
    %Exqlite.Result{
      columns: ["sumc(x)"],
      command: :execute,
      num_rows: 1,
      rows: [[55.0]]
    }
    
    iex(2)> E.sumzig
    thread 8760720 panic: incorrect alignment
    
    question 
    opened by ruslandoga 11
  • 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
  • "error: no such column" on complex "conflict target"

    Hi, running this the following in the console is accepted:

    INSERT INTO "counter_interfaces" ("device_id","device_type") VALUES ("123","3g") ON CONFLICT ("device_id", COALESCE("sim_id", "")) DO UPDATE SET "device_id" = EXCLUDED."device_id","device_type" = EXCLUDED."device_type","sim_id" = EXCLUDED."sim_id";
    

    However, when run through exqlite I get an error:

    iex(7)> {:ok, statement} = Exqlite.Sqlite3.prepare(conn, ~s<INSERT INTO "counter_interfaces" ("device_id","device_type") VALUES (?,?) ON CONFLICT ("device_id",coalesce("sim_id", "")) DO UPDATE SET "device_id" = EXCLUDED."device_id","device_type" = EXCLUDED."device_type","sim_id" = EXCLUDED."sim_id">)                               ** 
    
    (MatchError) no match of right hand side value: {:error, "no such column: "}
    

    The database definition is as follows:

        create table("counter_interfaces") do
          add :device_id,   :string, null: false
          add :device_type, :string,  null: false
          add :sim_id,      :string, null: true
        end
        create unique_index("counter_interfaces", [:device_id, "coalesce(sim_id, '')"], name: :unique_counter_interfaces_on_any_sim_id)
    

    What I'm trying to achieve is a situation where I have a unique constraint on multiple device_id/sim_id pairs, including the case that sim_id is nil (the default case for sqlite is that uniqueness is not enforced for columns which are null)

    I'm not clear if this problem is coming from the sqlite parser or something in exqlite? That it works ok on the sqlite command line suggests exqlite? Any suggestions?

    bug 
    opened by ewildgoose 9
Releases(v0.12.0)
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
Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++

libasyncd Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++. What is libasyncd? Libasyncd is an embeddable event-driven asynch

Seungyoung 166 Dec 5, 2022
C library to create simple HTTP servers and Web Applications.

Onion http server library Travis status Coverity status Onion is a C library to create simple HTTP servers and Web Applications. master the developmen

David Moreno Montero 1.9k Dec 31, 2022
Support for multiple RPC protocols in a single library

AnyRPC A multiprotocol remote procedure call system for C++ Overview AnyRPC provides a common system to work with a number of different remote procedu

Steve Gieseking 56 Nov 17, 2022
Pion Network Library (Boost licensed open source)

Pion Network Library C++ framework for building lightweight HTTP interfaces Project Home: https://github.com/splunk/pion Retrieving the code git clone

Splunk GitHub 293 Nov 17, 2022
A C++11 RESTful web server library

Served Overview Served is a C++ library for building high performance RESTful web servers. Served builds upon Boost.ASIO to provide a simple API for d

Meltwater 696 Dec 28, 2022
bittyhttp - A threaded HTTP library for building REST services in C.

bittyhttp - A threaded HTTP library for building REST services in C.

Colin Luoma 12 Nov 29, 2021
A Zig binding to the webview library. Make Zig applications with a nice HTML5 frontend a reality!

A Zig binding to the webview library. Make Zig applications with a nice HTML5 frontend a reality!

ZigLibs 52 Dec 29, 2022
An SQLite3 driver for Elixir

Exqlite An Elixir SQLite3 library. If you are looking for the Ecto adapater, take a look at the Ecto SQLite3 library. Documentation: https://hexdocs.p

elixir-sqlite 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
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
SSD1306 library and simple graphics core library based on Adafruit GFX Library.

Raspberry Pico SSD1306 + GFX Library Based on Adafruit GFX Library https://github.com/adafruit/Adafruit-GFX-Library Usage Hardware Connect your SSD130

Marcin Bober 31 Sep 1, 2022
This library provides a cross-platform image loading library in C11 for projects based on our foundation library

Image Library - Public Domain This library provides a cross-platform image loading library in C11 for projects based on our foundation library.

Mattias Jansson 1 Jan 29, 2022
The dgSPARSE Library (Deep Graph Sparse Library) is a high performance library for sparse kernel acceleration on GPUs based on CUDA.

dgSPARSE Library Introdution The dgSPARSE Library (Deep Graph Sparse Library) is a high performance library for sparse kernel acceleration on GPUs bas

dgSPARSE 59 Dec 5, 2022
C-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library

Build Status Travis CI VM: Linux x64: Raspberry Pi 3: Jetson TX2: Backstory I set to build ccv with a minimalism inspiration. That was back in 2010, o

Liu Liu 6.9k Jan 6, 2023