denodrivers / sqlite3

The fastest and correct SQLite3 module for Deno runtime
https://jsr.io/@db/sqlite
Apache License 2.0
265 stars 22 forks source link

empty string and NOT NULL constraint #73

Closed nsf closed 1 year ago

nsf commented 1 year ago

Right now the following code:

import { Database } from "https://deno.land/x/sqlite3@0.6.1/mod.ts";

const db = new Database(":memory:");
db.exec(`
  CREATE TABLE foo (
    name TEXT NOT NULL
  );
`);

db.exec(`INSERT INTO foo (name) VALUES (?)`, "");

fails with:

error: Uncaught (in promise) Error: NOT NULL constraint failed: foo.name

I tried to figure out what's going on and seems like it's a problem with deno's ffi layer, where for an empty array it returns a null pointer:

~> deno --unstable
Deno 1.29.1
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
> const b = new Uint8Array();
undefined
> Deno.UnsafePointer.of(b)
0

Which in turn when used with sqlite3_bind_text causes sqlite3 to bind null: https://github.com/sqlite/sqlite/blob/3547e4997f29afa0df561653019b795e6f8f691a/src/vdbemem.c#L1155

This is the code which causes a problem: https://github.com/denodrivers/sqlite3/blob/4a01a0257b878d6229a368adcc418a5bfe8485e4/src/statement.ts#L256-L263

As a suggestion, perhaps something like this could work as a workaround:

// create a non-empty buffer globally somewhere
const emptyStrBuf = new Uint8Array(1);

// then when using sqlite3_bind_text in #bind check for empty string explicitly, 
// if it's empty use the buffer above, but specify zero length
if (param === "") {
   unwrap(
       sqlite3_bind_text(this.#handle, i + 1, emptyStrBuf, 0, 0),
   );
}

(using a non-empty array properly returns some valid pointer in deno)

> const b = new Uint8Array(1);
undefined
> Deno.UnsafePointer.of(b)
94900665479152