tursodatabase / libsql-js

A better-sqlite3 compatible API for libSQL that supports Bun, Deno, and Node
MIT License
194 stars 22 forks source link

BUG: libsql doesn't return columns and `.reader` always false #116

Open azmy60 opened 4 months ago

azmy60 commented 4 months ago

Hi!

Currently we're working on adding libsql to Beekeeper Studio! And I ran into an issue where I can't see the columns and the .reader flag always return false from a prepared statement. Somehow it happens when connecting to a remote server, but it works fine when connecting to :memory:.

A snippet to reproduce:

const Database = require("libsql");
const db = new Database("<URL>", { authToken: "<TOKEN>"});
const stmt = db.prepare("SELECT 1;");
console.log("reader:" + stmt.reader, "columns:" + stmt.columns().length); // reader:false columns:0
console.log(stmt.all()); // [ { '1': 1 } ]
console.log("reader:" + stmt.reader, "columns:" + stmt.columns().length); // after running all(), it still prints reader:false columns:0 ?
azmy60 commented 4 months ago

Also it seems like I can't run .raw() method even though my query is a SELECT query:

The raw() method is only for statements that return data

It might be related to this issue.

The .raw() method would allow me to return data in array form, for example, if I run select 1 as a, 2 as a, this should return arrays ([[1, 2]]) instead objects ([{ a: 2 }]) so the values don't conflict.

rathboma commented 4 months ago

@azmy60 ++ for adding this issue.

Really starting to love libSQL, thanks for starting the project.

@penberg if you look at this, the biggest issue from a user perspective is: SELECT queries that have duplicate column names in the response return broken data

# current result (bad)
{ 'a': 2}
# expected (good)
[ 1, 2 ]

This is a common problem with node SQL drivers, and is explicitly supported with better-sqlite3 using raw mode, which seems to be broken in libsql, and then by calling columns as azmy stated. pg has rowMode: array, etc, etc.

Thanks again for all your work. Here is our PR:

https://github.com/beekeeper-studio/beekeeper-studio/pull/2220

giovannibenussi commented 4 months ago

Hey! Just want to give a heads up that we're investigating this issue. I created a reproducer for this in this repo in case anyone wants to replicate the issue locally: https://github.com/tursodatabase/libsql-js-116

I'll let you know once we have a fix for this!

penberg commented 4 months ago

The implementation of reader in Rust looks like this:

    pub fn js_is_reader(mut cx: FunctionContext) -> JsResult<JsBoolean> {
        let stmt: Handle<'_, JsBox<Statement>> = cx.this()?;
        let raw_stmt = stmt.stmt.blocking_lock();
        Ok(cx.boolean(!raw_stmt.columns().is_empty()))
    }

This suggests an issue in the libSQL remote protocol implementation in https://github.com/tursodatabase/libsql.

@giovannibenussi Can you confirm btw that the problem happens also with 0.4.0-pre.2? I am asking because it contains the most up-to-date version of libsql and want to rule out that we already silently fixed this in libsql crate.

giovannibenussi commented 4 months ago

The issue happens with 0.4.0-pre.2 too. I tested with 0.4.0-pre.6 and the issue happens too.