miniflare icon indicating copy to clipboard operation
miniflare copied to clipboard

Error: D1_ERROR: Wrong number of parameter bindings for SQL query.

Open alexgallacher opened this issue 1 year ago • 11 comments

Hi Team - I believe I'm experiencing the same issue identified in 504 where I'm getting the following error when attempting to Insert into D1. I understand a new Miniflare release should have fixed this issue.

✘ [ERROR] Error processing request: Error: D1_ERROR: Wrong number of parameter bindings for SQL query.

const sql = `
INSERT INTO Events (eventType, severity, eventId, source, eventTime, eventTimeUK, timeCreated)
VALUES (?, ?, ?, ?, ?, ?, ?)
`;
const parameters = [eventType, severity, eventId, source, eventTime, eventTimeUK, timeCreated]; // these are defined on the fly
const result = await db.prepare(sql).run(parameters);

I'm using ⛅️ wrangler 3.22.4. Perhaps I'm doing something wrong but any assistance would be greatly appreciated.

Many thanks for any comments in advance.

Alex.

alexgallacher avatar Jan 15 '24 23:01 alexgallacher

Hey! 👋 Thanks for raising this. Does this code work for you when deployed to production? Could you share the version of your database from wrangler d1 info <database_name> too?

mrbbot avatar Jan 16 '24 10:01 mrbbot

I just hit this as well. It also happens in production. I am running wrangler 3.50.0. There doesnt appear to be a version in the output from wrangler d1 info, but my created_at is 2023-09-29T23:08:01.953Z.

Sample query I am trying to parameterize:

    const limit = ctx.query.limit || 25
    const page = (ctx.query.page || 0) * limit

    const sql = oneline`
        SELECT t.id, t.name, t.description, t.shareLink, a.avatar, a.firstName, a.lastName FROM templates t
        LEFT JOIN accounts a ON t.ownerId = a.id
        INNER JOIN templates_fts s ON s.id = t.id
        WHERE templates_fts MATCH '{name description}: ?'
        ORDER BY bm25(templates_fts, 0, 2, 1)
        LIMIT ?
        OFFSET ?;
    `
    const result = await ctx.env.DB.prepare(sql)
      .bind(ctx.query.query, limit, page)
      .run()

Results in this error: D1_ERROR: Wrong number of parameter bindings for SQL query.

Query works fine when it isn't parameterized. I guess for now I can manually sanitize the input, but would be nice to have this fixed.

Let me know if you want me to open this issue in the workerd repo.

SupremeTechnopriest avatar Apr 12 '24 03:04 SupremeTechnopriest

Hey I just hit this as well, after bashing it around for longer than needed, co-pilot did a sneaky typeahead with the three dots to de-structure and it seems to have worked:

Example:

let deleting = ['test1', 'test2']
const records = await c.env.DB.prepare(`SELECT * FROM table WHERE column IN (${deleting.map(() => '?').join(', ')})`)
.bind(...deleting)
.run()
console.log('Records::', records)

seivad avatar Apr 15 '24 07:04 seivad

@seivad I'll try spreading an array into bind tomorrow and report back. Thanks for sharing!

SupremeTechnopriest avatar Apr 15 '24 08:04 SupremeTechnopriest

Didn't work for me. Didn't really expect it to... would have been surprised if it did.

SupremeTechnopriest avatar Apr 15 '24 20:04 SupremeTechnopriest

@SupremeTechnopriest I had this issue late last night but realised that the were a couple of quotes that were messing with the query. I'd look at the WHERE templates_fts MATCH '{name description}: ?' because I'm assuming ctx.query.query is also a string and it might not get formatted correctly.

matthewlynch avatar Apr 16 '24 12:04 matthewlynch

@matthewlynch InterestingI Yes it is also a string. How did you solve it on your end?

SupremeTechnopriest avatar Apr 16 '24 18:04 SupremeTechnopriest

The query definitely needs the quotes... It looks like the ? isn't being parsed out properly when its inside quotes. I think this is a bug in D1.

SupremeTechnopriest avatar Apr 16 '24 19:04 SupremeTechnopriest

@SupremeTechnopriest Can you log the value of sql and ctx.query.query? My assumption, based off the code you provided is that there are additional quotes being injected in the first parameter binding.

I noticed my issue when I started logging the queries being sent to D1 via the ORM I am using (Drizzle).

matthewlynch avatar Apr 16 '24 19:04 matthewlynch

@matthewlynch

SQL:

SELECT t.id, t.name, t.description, t.shareLink, a.avatar, a.firstName, a.lastName FROM templates t
      LEFT JOIN accounts a ON t.ownerId = a.id
      INNER JOIN templates_fts s ON s.id = t.id
      WHERE templates_fts MATCH '{name description}: ?'
      ORDER BY bm25(templates_fts, 0, 2, 1)
      LIMIT ?
      OFFSET ?

ctx.query.query:

foo

The query is a user's search term. So in theory this could be anything. I would expect that the parameterized query would sanitize and escape the input.

SupremeTechnopriest avatar Apr 16 '24 21:04 SupremeTechnopriest

I am also using drizzle, but to rule out any weirdness there I went direct to the database. Drizzle doesnt support virtual tables, so I would have to use:

sql``

For now I have to use sql.raw() to make this query work.

SupremeTechnopriest avatar Apr 16 '24 21:04 SupremeTechnopriest