marcboeker / go-duckdb

go-duckdb provides a database/sql driver for the DuckDB database engine.
MIT License
623 stars 97 forks source link

JSON (or any extension type) usage with Appender #170

Closed disq closed 6 months ago

disq commented 6 months ago

Repro like this (test code mostly copied from other tests)

func TestAppenderJSON(t *testing.T) {
    db, appender := prepareAppender(t, `SET autoinstall_known_extensions=1; SET autoload_known_extensions=1; CREATE TABLE test (data json)`)
    defer db.Close()

    //data := json.RawMessage(`{"key": "value"}`)
    data := `{"key": "value"}`
    err := appender.AppendRow(data)
    require.NoError(t, err)

    err = appender.Close()
    require.NoError(t, err)

    // Verify results.
    res, err := db.QueryContext(
        context.Background(),
        `SELECT data FROM test`,
    )
    require.NoError(t, err)
    defer res.Close()

    i := 0
    for res.Next() {
        //var b *json.RawMessage
        var b string
        err = res.Scan(
            &b,
        )
        require.NoError(t, err)
        require.Equal(t, data, b)
        i++
    }
    require.Equal(t, 1, i)
}

DuckDB error: Type mismatch in Append DataChunk and the types required for appender, expected JSON but got VARCHAR for column 1

If replaced with json.RawMessage, then the []uint8 block gets confused:

panic: interface conversion: interface {} is json.RawMessage, not []uint8

with *json.RawMessage:

expected: []uint8, actual: *json.RawMessage

disq commented 6 months ago

Fixed in https://github.com/marcboeker/go-duckdb/pull/171, using string

func TestAppenderJSON(t *testing.T) {
    connector, con, appender := prepareAppender(t, `SET autoinstall_known_extensions=1; SET autoload_known_extensions=1; CREATE TABLE test (data json)`)
    defer con.Close()
    defer connector.Close()

    data := `{"key": "value"}`
    err := appender.AppendRow(data)
    require.NoError(t, err)

    err = appender.Close()
    require.NoError(t, err)

    // Verify results.
    db := sql.OpenDB(connector)
    res, err := db.QueryContext(
        context.Background(),
        `SELECT data FROM test`,
    )
    require.NoError(t, err)
    defer res.Close()

    i := 0
    for res.Next() {
        var b string
        err = res.Scan(
            &b,
        )
        require.NoError(t, err)
        require.Equal(t, data, b)
        i++
    }
    require.Equal(t, 1, i)
}