effect icon indicating copy to clipboard operation
effect copied to clipboard

Writing instances of Uint8Array using unprepared statements fails

Open vecerek opened this issue 9 months ago • 2 comments

What version of Effect is running?

3.14.1

What steps can reproduce the bug?

Reproduction case available here. The steps can be found in the README. Simple, non-runnable example:

import { SqlClient } from "@effect/sql"
import { DBClientLayer } from "./db-client.ts"
import { Array, Effect, Logger } from "effect"
import { MigratorLayer } from "./migrator.ts"

const badId = new Uint8Array(Array.replicate(0x0, 16))
const anotherBadId = new Uint8Array(Array.replicate(0x1, 16))
const goodId = Buffer.from(new Uint8Array(Array.replicate(0x2, 16)))

const program = Effect.gen(function* () {
  const sql = yield* SqlClient.SqlClient

  yield* sql`TRUNCATE TABLE examples`

  // works
  yield* sql`INSERT INTO examples ${sql.insert({ id: goodId })}`.unprepared

  // works
  yield* sql`INSERT INTO examples ${sql.insert({ id: anotherBadId })}`

  // fails with:
  // [cause]: Error: Column count doesn't match value count at row 1
  //   code: 'ER_WRONG_VALUE_COUNT_ON_ROW',
  //   errno: 1136,
  //   sqlState: '21S01',
  //   sqlMessage: "Column count doesn't match value count at row 1",
  //   sql: 'INSERT INTO examples (`id`) VALUES (`0` = 0, `1` = 0, `2` = 0, `3` = 0, `4` = 0, `5` = 0, `6` = 0, `7` = 0, `8` = 0, `9` = 0, `10` = 0, `11` = 0, `12` = 0, `13` = 0, `14` = 0, `15` = 0)'
  yield* sql`INSERT INTO examples ${sql.insert({ id: badId })}`.unprepared
})

program.pipe(
  Effect.provide(MigratorLayer),
  Effect.provide(DBClientLayer),
  Effect.provide(Logger.json),
  Effect.runPromise
)

What is the expected behavior?

I expect the write operation to succeed regardless of the actual type of the binary data or the type of the statement used to execute the query.

What do you see instead?

Error: Column count doesn't match value count at row 1
  <stacktrace truncated> {
code: 'ER_WRONG_VALUE_COUNT_ON_ROW',
errno: 1136,
sqlState: '21S01',
sqlMessage: "Column count doesn't match value count at row 1",
sql: 'INSERT INTO examples (`id`) VALUES (`0` = 0, `1` = 0, `2` = 0, `3` = 0, `4` = 0, `5` = 0, `6` = 0, `7` = 0, `8` = 0, `9` = 0, `10` = 0, `11` = 0, `12` = 0, `13` = 0, `14` = 0, `15` = 0)'
}

Additional information

No response

vecerek avatar Mar 25 '25 20:03 vecerek

@tim-smart ~I think my original PR adding support for binary values isn't quite up to the challenge 😄~

NVM:

import { Array } from "effect"

const u = new Uint8Array(Array.replicate(0x0, 16))
// undefined
typeof u === "object" && "buffer" in u && u.buffer instanceof ArrayBuffer
// true

vecerek avatar Mar 25 '25 20:03 vecerek

This is probably an issue in mysql2 itself. I'll try to replicate it using mysql2 directly.

vecerek avatar May 15 '25 10:05 vecerek