sidorares / sidorares/node-mysql2

[BUG] Named placeholders not properly replacing instances of nested placedholder

Open
#4,017 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

needs reproduction
Dominant language
TypeScript
Stars
4.4k
Forks
680
Avg merge
9h 7m
Merged PRs (30d)
59

Description

Bug: namedPlaceholders fails to replace tokens inside nested subqueries

Environment
  • mysql2 version: 3.10.2
  • Node.js version: v22.21.1
Description

When using the namedPlaceholders: true option, the library fails to identify and replace named tokens (e.g., :item_id) when they are located inside a nested subquery. The same query executes successfully when using positional ? placeholders.

Steps to Reproduce

1. Failing Example (Named Placeholders)
The following code throws a syntax error because the second :item_id is sent literally to the MySQL server.

const item_id = 123;

const [results] = await pool.query({
  namedPlaceholders: true,
  sql: `
    SELECT *
    FROM my_table AS t1
    WHERE t1.id = :item_id
      AND EXISTS (
        SELECT 1 
        FROM table_2 AS t2
        WHERE t2.link_id = :item_id
        LIMIT 1
      )
  `,
  values: {
    item_id,
  }
});
  1. Working Example (Positional Placeholders) Using standard ? placeholders with the exact same SQL structure works as expected.
const item_id = 123;

const [results] = await pool.query(`
    SELECT *
    FROM my_table AS t1
    WHERE t1.id = ?
      AND EXISTS (
        SELECT 1 
        FROM table_2 AS t2
        WHERE t2.link_id = ?
        LIMIT 1
      )
  `, [item_id, item_id]
);

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the namedPlaceholders example against mysql2 3.10.2 and compare it with the positional-placeholder example. Trace the named-placeholder replacement path for the repeated :item_id inside the EXISTS subquery, then add a regression test covering that SQL shape and confirm the token is no longer sent literally to MySQL.

Written by the indexing model from the issue text.

Assessment

Tech stack
mysql, node.js, typescript
Domain
backend, database
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.