GithubHelp home page GithubHelp logo

touchlab / sqliter Goto Github PK

View Code? Open in Web Editor NEW
168.0 16.0 35.0 4.16 MB

Minimal multiplatform sqlite library

Home Page: https://touchlab.co

Kotlin 27.70% C 70.08% Shell 0.02% JavaScript 1.02% CSS 0.14% MDX 1.05%
kotlin-library kotlin-multiplatform kotlin-native sqlite

sqliter's Introduction

SQLiter

Minimal sqlite for Kotlin multiplatform

example workflow name

Subscribe!

We build solutions that get teams started smoothly with Kotlin Multiplatform Mobile and ensure their success in production. Join our community to learn how your peers are adopting KMM. Sign up here!

SQLiter is a SQLite driver for Kotlin Native, currently Apple and Windows variants. SQLiter powers the SQLDelight library on native clients.

SQLiter is designed to serve as a driver to power user-friendly libraries rather than something to use directly but if you ever need it, you can find it on mavenCentral:

dependencies {
  implementation("co.touchlab:sqliter-driver:$version")
}

Getting Help

SQLiter support can be found in the Kotlin Community Slack, request access here. Post in the "#touchlab-tools" channel.

For direct assistance, please contact Touchlab to discuss support options.

sqliter's People

Contributors

05nelsonm avatar andersio avatar chippmann avatar chislett avatar conradev avatar danielrbaird avatar gildor avatar hbmartin avatar hfhbd avatar kpgalligan avatar martinbonnin avatar psh avatar qhhonx avatar qiaoyuang avatar robxyy avatar russhwolf avatar samhill303 avatar sellmair avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqliter's Issues

Review trace and profile

There are two primary considerations. First, enabling logging on android requires the following:

Enable using "adb shell setprop log.tag.SQLiteStatements VERBOSE".

Enable using "adb shell setprop log.tag.SQLiteTime VERBOSE".

Also, both methods are deprecated in sqlite. sqlite3_trace and sqlite3_profile should use v2's.

It appears that these methods are simply logging, rather than doing any kind of analysis, so might simply be adding similar logging. How to enable them on native, however, is up in the air. Probably just the db config.

This is easier for native, as it is c++. Android will need some jni.

Review moving to Kotlin 1.6.2x

We can bump the library to Kotlin 1.6.2x and make sure everything is still compatible.

There is an open PR: #55. It is removing the expect/actuals added to make posix work cross-platform. I'm not sure this is worth doing, so we should run it quick to see if there are any issues, then try publishing a version, but it can be difficult to predict dependency compatibility until somebody tries to actually consume the output. In the past we've had situations where the build worked, but then import did not.

TBD, but maybe just leave the posix stuff as it.

`ConcurrentDatabaseConnection` and its NSRecursiveLock

ConcurrentDatabaseConnection at the moment uses a NSRecursiveLock, which is kinda emulating the SQLite Serialized mode, i.e., open with flag SQLITE_OPEN_FULLMUTEX. Meanwhile, the SQLite3 distribution on Darwin platforms has long been defaulted to use the Multi-thread mode.

If a user is doing connection pooling, the connection should have already been exclusively bound to a thread, until the connection can truly be returned to the pool for reuse (e.g., all active statements are closed; no escaped reference). In this use case, the additional locking on every call would be:

  • quite defensive for a Multi-thread mode connection; and
  • unnecessary for a Serialized mode connection.

So it seems there are two opportunities of minor improvements:

  • Use SQLITE_OPEN_FULLMUTEX so we don't need to roll a lock manually in the library.

    (bonus: two objc_msgSend calls are skipped)

  • potentially expose a lock-less version of ConcurrentDatabaseConnection.

    Though for SQLDelight specifically, whether or not the lock-free option can be used depends on how cashapp/sqldelight#2123 is resolved.

SQLiteException in iOS app

I've created an issue also here: cashapp/sqldelight#2447, but it seems like it's more related to the SQLiter than to SQLDelight.
We've got a library that internally is using SQLDelight. One of our client is facing crashes on various versions of the iOS. Unfortunately he didn't provide us any steps to reproduce, he just mentioned that crash happens for the few users with the message like this: AudioburstMobileLibrary: ThrowSql_SQLiteException + 400.
Have you ever seen similar issue? What could go wrong in this case?
It seems like exception arises during the initialization process (library is using NativeSqliteDriver(schema, name) constructor).

Runtime Environment
SQLDelight version: 1.4.4
Application OS: Various versions of iOS: 14.5.1, 14.4.2, 14.0.1
Devices: iPhone 11 Pro Max, iPhone 11 Pro, iPhone 12, iPhone XS, iPhone X

Exception

at 0   ThrowSql_SQLiteException
at 1   android::throw_sqlite3_exception(int, char const*, char const*)
at 2   android::throw_sqlite3_exception(sqlite3, char const*)
at 3   SQLiter_SQLiteConnection_nativePrepareStatement
at 4   kfun:co.touchlab.sqliter.NativeDatabaseConnection#createStatement(kotlin.String){}co.touchlab.sqliter.Statement
at 5   kfun:co.touchlab.sqliter#[email protected](kotlin.String;kotlin.Function1<co.touchlab.sqliter.Statement,0:0>){0§<kotlin.Any?>}0:0
at 6   kfun:co.touchlab.sqliter#[email protected](kotlin.String){}kotlin.String
at 7   kfun:co.touchlab.sqliter.NativeDatabaseManager.createConnection#internal
at 8   kfun:co.touchlab.sqliter.NativeDatabaseManager#createMultiThreadedConnection(){} co.touchab.sqliter.DatabaseConnection
at 9   kfun:com.squareup.sqldelight.drivers.native.NativeSqliteDriver.$<init>$lambda-0$FUNCTION_REFERENCE$418.invoke#internal
at 10   kfun:com.squareup.sqldelight.drivers.native.SinglePool#<init>(kotlin.Function0<1:0>){}

Undefined symbols for architecture arm64

I'm currently using sqldelight 2.0.0-alpha03 and when trying to use the native in memory database on iOS in tests (./gradlew iosSimulatorArm64Test)

I get:

w: Mimalloc allocator isn't supported on target ios_simulator_arm64. Used standard mode.
e: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors

The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1.
output:
ld: warning: object file (/var/folders/mg/nrx5qjvs09v1wfmrfrlpnd800000gn/T/konan_temp4851479586738549723/result.o) was built for newer iOS Simulator version (14.0) than being linked (9.0)
Undefined symbols for architecture arm64:
  "_sqlite3_column_type", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_type_wrapper108 in result.o
  "_sqlite3_finalize", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_finalize_wrapper109 in result.o
  "_sqlite3_column_text", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_text_wrapper103 in result.o
  "_sqlite3_column_name", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_name_wrapper87 in result.o
  "_sqlite3_prepare16_v2", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_prepare16_v2_wrapper61 in result.o
  "_sqlite3_bind_text", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_text_wrapper75 in result.o
  "_sqlite3_clear_bindings", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_clear_bindings_wrapper85 in result.o
  "_sqlite3_bind_null", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_null_wrapper74 in result.o
  "_sqlite3_column_double", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_double_wrapper100 in result.o
  "_sqlite3_close_v2", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_close_v2_wrapper7 in result.o
  "_sqlite3_busy_timeout", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_busy_timeout_wrapper22 in result.o
  "_sqlite3_bind_double", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_double_wrapper71 in result.o
  "_sqlite3_column_blob", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_blob_wrapper99 in result.o
  "_sqlite3_step", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_step_wrapper97 in result.o
  "_sqlite3_column_bytes", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_bytes_wrapper106 in result.o
  "_sqlite3_bind_parameter_index", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_parameter_index_wrapper84 in result.o
  "_sqlite3_db_readonly", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_db_readonly_wrapper177 in result.o
  "_sqlite3_bind_blob", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_blob_wrapper69 in result.o
  "_sqlite3_errmsg", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_errmsg_wrapper53 in result.o
  "_sqlite3_reset", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_reset_wrapper110 in result.o
  "_sqlite3_changes", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_changes_wrapper16 in result.o
  "_sqlite3_db_config", referenced from:
      knifunptr_co_touchlab_sqliter_sqlite314_sqlite3_db_config in result.o
  "_sqlite3_open_v2", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_open_v2_wrapper43 in result.o
  "_sqlite3_column_int64", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_int64_wrapper102 in result.o
  "_sqlite3_bind_int64", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_bind_int64_wrapper73 in result.o
  "_sqlite3_last_insert_rowid", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_last_insert_rowid_wrapper14 in result.o
  "_sqlite3_exec", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_exec_wrapper8 in result.o
  "_sqlite3_column_count", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_column_count_wrapper86 in result.o
  "_sqlite3_close", referenced from:
      _co_touchlab_sqliter_sqlite3_sqlite3_close_wrapper6 in result.o
ld: symbol(s) not found for architecture arm64

Is it really just adding suppot for arm64 here or is there more crafting involved?

Better driver specific docs

We mostly rely on sqldelight docs for driver config, but it really would make sense to add some better docs here. Specifically, this came up recently with encryption. See: #58

I think we can add docs on the following:

  • Creating a connection
  • Configuration options available
  • Helper functions (delete database, etc)
  • Overview of linking to sqlite3
  • Using encryption

iOS 14 with cypher key crash.

when using the following configuration:

NativeSqliteDriver(
    DatabaseConfiguration(
        name = DATABASE_NAME,
        version = MyDatabase.Schema.version,
        create = { connection ->
            wrapConnection(connection) {
                if(connection.getVersion()==0)
                    MyDatabase.Schema.create(it)
            }
        },
        upgrade = { connection, oldVersion, newVersion ->
            wrapConnection(connection) { MyDatabase.Schema.migrate(it, oldVersion, newVersion) }
        },
        key = "SuperSecretkey"
    )
)

Getting an exception on iOS14 runtime:
SQLiteException - unknown error (code 0): Queries can be performed using SQLiteDatabase query or rawQuery methods only.

DatabaseConnection.kt
In the line: withStatement("PRAGMA key = \"$cipherKey\";") { execute() }

Seems that the PRAGMA key = ... statement should be executed as a query instead of a plain statement.

The following workaround solves the issue:

 NativeSqliteDriver(
    DatabaseConfiguration(
        name = DATABASE_NAME,
        version = MyDatabase.Schema.version,
        create = { connection ->
            wrapConnection(connection) {
                if(connection.getVersion()==0)
                    MyDatabase.Schema.create(it)
            }
        },
        upgrade = { connection, oldVersion, newVersion ->
            wrapConnection(connection) { MyDatabase.Schema.migrate(it, oldVersion, newVersion) }
        },
        //Workaround for DatabaseConnection.setCipherKey causing an exception on iOS 14
        configConnection = { connection,v ->
            val key = "SuperSecretkey"
            val statement = "PRAGMA key = \"$key\";"
            connection.withStatement(statement) {
                stringForQuery()
            }
        }
    )
)

But it would be nice if the set key work out of the box.

Add tracing

Add an option to configure tracing on start

Database not encrypted since iOS 15.2

Hello

I'm raising an issue here because I run out of ideas on how to fix my project by myself.

The problem is that my database is not encrypted anymore on iOS (actually since iOS 15.2 and above).
I prepared a KMM project with basic DB operations (create DB, add table and a row)
The example project can be found here
To test a db encryption I just run an iOS application on simulators (e.g: try with iOS 15.0 and iOS 15.2) and perform following tests for both iOS versions:
When the app is launched a db file is created and can be easily accessed from local drive by entering the path logged by the app.
To test db encryption I just open the file "sqlite test.db" and execute for example ".tables". If database is encrypted then I'm receiving an error - which is expected and desired, otherwise db tables are listed.
You can notice that databases are encrypted prior to iOS 15.2 and not encrypted since.

Any help would be appreciated as you guys have the best tools to debug the problem.

P.S: Just to make sure it can work, I created a native project with SQLite and SQLCipher libs - the result is that the db is encrypted on any iOS version with native approach.

With regards
PJ

Fix windows tests

Kotlin 1.6.10+ breaks the way we get sqlite's linker library. We can still publish, but can't run tests on windows. Need to figure that out.

Facility for corrupt database handling

Apparently you can corrupt your db files. The android sqlite stack handles this, but knarch.db was never going to properly do so. Should provide some facility for doing so.

Fix tests

the tests don't run because the native code is being linked multiple times.

error: Linking globals named 'CreateCStringFromStringWithSize': symbol multiply defined!

I think we'll need to do a local kotlin native build and play around. Somehow it's being added twice.

Support in memory sqlite db

specifically the name property of DatabaseConfiguration should be nullable, and when null should mean the created SQLite db is in memory

Use `sqlite3_close_v2` instead of `sqlite3_close`.

sqlite3_close_v2 marks connection as closed zombie, and internally defers deallocation of the connection as soon as all outstanding resources are finalized.

Switching to sqlite3_close_v2 allows consumers of SQLiter to avoid extraneous resource tracking, as long as they are already closing/finalizing the resources properly (mainly active prepared statements).

An example scenario that will benefit from this is SQLDelight's NativeSqlDriver:

https://github.com/cashapp/sqldelight/blob/51e0621abe103761717d3d9078dcde3734ad8c04/drivers/native-driver/src/nativeMain/kotlin/com/squareup/sqldelight/drivers/native/NativeSqlDatabase.kt#L248-249

It might be a step towards not needing precise tracking of active statement objects, and in turn reducing the need on less performant shareable data structures in K/N.

https://www.sqlite.org/c3ref/close.html

The sqlite3_close_v2() interface is intended for use with host languages that are garbage collected, and where the order in which destructors are called is arbitrary.

Version 1.0.1 PRAGMA key = ? error

First of all let me thank you for an amazing tool!
After upgrading to the version 1.0.1 I have a following error, when providing encryptionConfig for the NativeSqliteDriver DatabaseConfiguration:

error while compiling: PRAGMA key = ?; | error code SQLITE_ERROR
co.touchlab.sqliter.interop.SQLiteExceptionErrorCode: error while compiling: PRAGMA key = ?;

It may be somehow related to the issue fixed in this PR

Tests for tracing logs

Added a verbose logger for the statement, but need to write some tests on it. May ultimately not support that, as I'm not sure of its real utility.

Binding empty data blob in 1.0.0 and 1.0.1 crashes

If you bind an empty data blob like ByteArray(0) to a statement, you'll get a crash:

kotlin.ArrayIndexOutOfBoundsException
	at kotlin.Throwable#<init>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Throwable.kt:27)
	at kotlin.Exception#<init>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:21)
	at kotlin.RuntimeException#<init>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:32)
	at kotlin.IndexOutOfBoundsException#<init>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:90)
	at kotlin.ArrayIndexOutOfBoundsException#<init>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:97)
	at <global>.ThrowArrayIndexOutOfBoundsException(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt:23)
	at <global>.Kotlin_Arrays_getByteArrayAddressOfElement(Unknown Source)
	at kotlinx.cinterop#[email protected]<kotlin.ByteArray>(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Pinning.kt:47)
	at kotlinx.cinterop.<no(/Users/teamcity2/buildAgent/work/11ac87a349af04d5/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Pinning.kt:91)
	at co.touchlab.sqliter.interop.ActualSqliteStatement#bindBlob(/Users/runner/work/SQLiter/SQLiter/sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/interop/ActualSqliteStatement.kt:126)
	at co.touchlab.sqliter.native.NativeStatement#bindBlob(/Users/runner/work/SQLiter/SQLiter/sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/native/NativeStatement.kt:92)
	at co.touchlab.sqliter.concurrency.ConcurrentDatabaseConnection.ConcurrentStatement#bindBlob(/Users/runner/work/SQLiter/SQLiter/sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/concurrency/ConcurrentDatabaseConnection.kt)
	at co.touchlab.sqliter#[email protected](/Users/runner/work/SQLiter/SQLiter/sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/Statement.kt:60)
	at com.squareup.sqldelight.drivers.native.SqliterStatement#bindBytes(/Users/runner/work/1/s/sqldelight-copy/drivers/native-driver/src/nativeMain/kotlin/com/squareup/sqldelight/drivers/native/SqliterPreparedStatement.kt:17)

Test coverage

Notes on tests that should be added:

kotlin/co/touchlab/sqliter/Cursor.kt
All of the extension functions

co.touchlab.sqliter.Statement
Check extension methods

DatabaseFileContext
Extensions

Review logging

Currently the default logger prints errors. Also, there's a "trace" level that doesn't seem to be used. Review logging plan.

`migrateIfNeeded()` and multiple processes

The PRAMGA user_version read for determining need of creation & migration is not part of the subsequent write transaction. It seems to be a plausible race condition, which multiple processes might coincidentially make the decision to run the same prime or migration schema simutaneously. Perhaps the write transaction should be applied to the whole migrateIfNeeded() scope?

fun migrateIfNeeded(
create: (DatabaseConnection) -> Unit,
upgrade: (DatabaseConnection, Int, Int) -> Unit,
version: Int
) {
val initialVersion = getVersion()
if (initialVersion == 0) {
this.withTransaction {
create(this)
setVersion(version)
}
} else if(initialVersion != version) {

Use sqlite amalgamation for compatibility

I propose to use the sqlite amalgamation (https://www.sqlite.org/amalgamation.html) rather than linking the libsqlite3 library which is installed on the host.

This has several advantages:

  • It is more portable:
    • as it does not rely on the sqlite version installed on the building host
    • as it does not depend on installed library versions on the building host (like glibc, which was an issue in this PR). This also means that developers on linux can run the tests locally as well even with very recent linux installs
  • Consumer of this library don't have to link sqlite themselves
  • We don't have to link sqlite ourselves
  • It should (at least according to the sqlite docs) give a slight performance boost

While i already have a working prototype branch using sqliter in conjunction with sqldelight one test fails:


Can you @kpgalligan tell me why and what this hardcoded timeout is and why it's set to 1300?
Because with my prototyping branch the actual value is slightly lower (around 1000) and hence I'm unsure if this is a bug in my prototyping branch or not.

Refactor visibility of sqliter

The public and internal apis aren't well defined. There's a whole lot that could be made internal or private. A good example would be SqliteDatabase

Optimize C string to Kotlin String conversion

I did some synthetic benchmarking in this area recently, and discovered that toKStringFromUtf8() is quite underwhelming, especially in debug builds. Imagine in debug builds, 100 rows of 2KB worth of strings take a whopping 18ms — more than a frame at 60fps.

The results were filed in this issue: https://youtrack.jetbrains.com/issue/KT-44357.

Since toKStringFromUtf8() is a hot path for getting strings out of SQLite, it might be valuable for SQLiter to drop toKStringFromUtf8() for the alternatives listed, until improvements were made to the stdlib. Most importantly, these alternatives have a way less drastic debug-release performance gap, so developer experience is improved too.

TL;DR of the options:

  • Given the known size via sqlite3_column_bytes(), memcpy() the C string to a ByteArray, and then use ByteArray.decodeToString().

  • Convert the C string first to NSString, and then to KString via toString() or as String.

    This is the fastest option, though it is exclusive to Darwin targets.

K/N compiler crashes if you consume sqliter and also have a sqlite3 cinterop file with package = sqlite3

Our library also picked package = sqlite3 for our sqlite cinterop, just sqliter did, which resulted in this hard-to-debug crash https://youtrack.jetbrains.com/issue/KT-46358.

package in this case defines the package used for the code K/N generates for interop'ing with that C. it should probably be name-spaced to the sqliter package: co.touchlab.sqliter

If you encounter this as a consumer, you can fix this yourself by fixing your cinterop's package name

Significant performance difference between SQLDelight and C++ on iOS

I replicate here issue from SQLDelight repo as per advise of @AlecStrong, he assumes the issue may have something to do with SQLiter

First I faced this notable speed difference on iOS on simple select queries - C++ was about 4 times faster than KMM implementation using SQLDelight.

So I decided to prepare a test including bulk inserts and selects for both C++ and KMM with 100 000 records, results are: for inserts C++ is ~5 times faster than KMM, for selects C++ is ~7 times faster than KMM.

I prepared a test project with both implementations here

Is there something to do to improve SQLDelight performance? Maybe some tuning which I'm not aware of? Or is it generally a Kotlin issue?

My test repo

Pull error message from sqlite anywhere we have a failure

When throwing sqlite exceptions, it makes sense to pull the error message and include that in the exception. Use sqlite3_errmsg. I am concerned that this may have issues in a multithreaded environment, but since we're making sure one connection is being accessed by one thread at a time, it'll probably be fine.

Continue review of CTS tests

Some of the relevant CTS suite tests have been copied into the testing source set. Some are redundant and some don't apply. Continue reviewing which ones might be helpful, and possibly include more functionality if it's super useful.

JVM implementation?

It seems like there is no actual implementation for the JVM yet? What's the status here?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.