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

"TypeError: Invalid ArrayBuffer pointer, pointer is null" while reading blob column #122

Closed ianawilson closed 8 months ago

ianawilson commented 9 months ago

A coworker of mine is getting a null pointer exception from this line: https://github.com/denodrivers/sqlite3/blob/0.10.0/src/statement.ts#L112 while running all() on a prepared statement. I don't have this issue on my machine, but it's cropped up on theirs.

I don't know if I'm reading that line correctly, but it looks to me like the library is calling UnsafePointerView.getArrayBuffer() statically when it looks like it expects an instance to be created with a constructor containing the pointer, and getArrayBuffer() can be called on that instance. (Reference for getArrayBuffer())

TypeError: Invalid ArrayBuffer pointer, pointer is null
    at Function.getArrayBuffer (ext:deno_ffi/00_ffi.js:175:16)
    at getColumn (https://deno.land/x/sqlite3@0.10.0/src/statement.ts:112:32)
    at eval (eval at getRowObject (https://deno.land/x/sqlite3@0.10.0/src/statement.ts:352:28), <anonymous>:190:29)
    at Statement.#allNoArgs [as all] (https://deno.land/x/sqlite3@0.10.0/src/statement.ts:546:19)

Any thoughts or ideas for troubleshooting this? I'm not entirely clear why this works on my machine, but not my coworker's, so I'm not sure if this is an environmental issue or library issue.

DjDeveloperr commented 9 months ago

Ohh, I think this is a case where NULL blob value is not handled. Is the column value null in this case?

ianawilson commented 9 months ago

Ohh, I think this is a case where NULL blob value is not handled. Is the column value null in this case?

Mm, I don't think so. I just tried it on the test db, which does have some null values in the blob columns, and it properly reads the column and puts a null in the Record<>.

We have three different databases we are trying this on:

This leads me to somewhat believe it's due to some difference between our database files. My coworker's db has a much larger SQLite database, and we have different SQLite versions when you file db.sqlite:

Working db file:

SQLite 3.x database, last written using SQLite version 3039005, writer version 2, read version 2, file counter 17, database pages 84, cookie 0x3a, schema 4, largest root page 60, UTF-8, vacuum mode 1, version-valid-for 17

Problem db file:

SQLite 3.x database, last written using SQLite version 3043002, writer version 2, read version 2, file counter 14317, database pages 11104, 1st free page 10821, free pages 6, cookie 0x65, schema 4, largest root page 60, UTF-8, vacuum mode 1, version-valid-for 14317

ianawilson commented 8 months ago

Hey @DjDeveloperr any additional thoughts or questions here? It seemed like an issue with how this library is using UnsafePointerView.getArrayBuffer(), but I haven't looked more deeply.

Thanks for your help!

DjDeveloperr commented 8 months ago

The issue here is how is the column value type SQLITE_BLOB while the sqlite3_column_blob function returns null pointer for blob contents... it is supposed to return the null value type if it was null. Maybe it really has to do with how null values are stored in different SQLite versions?

Are we able to confirm here if the column we're trying to read here in the problematic db file has a null value? If it does, this should be an easy fix. Not sure why this changed at all across versions though. Or you can provide me a minimum reproducible example that I can use to fix this bug myself!

Sorry for responding late, quite overloaded with college and job workload :(

ianawilson commented 8 months ago

Hey, no worries, we've all got busy lives!

I need to get some more info about this. It's happening on someone else's machine, so I need to get a copy of their db or figure out how to repro it myself. The query it's failing on is a select * on a pretty big table, so I need to work with them to figure out what a problematic row actually looks like. I'll come back with either steps or an example to repro when I can.

Thanks, Ian

DjDeveloperr commented 8 months ago

I think I got it:

From https://www.sqlite.org/c3ref/column_blob.html

Strings returned by sqlite3_column_text() and sqlite3_column_text16(), even empty strings, are always zero-terminated. The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.

The blob is just zero length, and that case is not handled here.

ianawilson commented 8 months ago

Amazing, thank you so much! I'll give that a try with my coworker. Do you plan on creating a release with this?

DjDeveloperr commented 8 months ago

There's a new release now - 0.11.1, you can try that out!