drizzle-team / drizzle-team/drizzle-orm

[Pg-kit]: aws-data-api adapter forwards $N placeholders untranslated (no known Studio trigger on 1.0.0-rc.4)

Open
#6,147 5 comments 0 reactions 1 assignee Claimed by @RomanNabukhotnyi View on GitHub
drizzle/studio
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

**Correction (2026-09-12).** The Studio claim below is wrong. Studio's client uses `AwsPgDialect` for this driver and emits `:N`; I could not find a normal Studio action that sends `$N` with bound values. What stands is narrower: drizzle-kit's `aws-data-api` `query` and `proxy` forward SQL to `prepareQuery` without translating placeholders, and the Data API only binds `:N`. Details in [this comment](https://github.com/drizzle-team/drizzle-orm/issues/6147#issuecomment-5650035780). On `main` (`0.31.10`) the same untranslated path is reached by kit's own composite primary key introspection, which is #2372.

---

### What version of `drizzle-orm` are you using?

1.0.0-rc.4 (also reproduced on 0.45.2)

### What version of `drizzle-kit` are you using?

1.0.0-rc.4 (also reproduced on 0.31.10)

### Other packages

@aws-sdk/client-rds-data@3.1114.0 (also reproduced on 3.928.0)

### Describe the Bug

**Reproduction:** https://github.com/simiancraft/drizzle-kit-rds-data-api-repro

**Undesired behavior.** Over the RDS Data API, any query drizzle-kit sends with positional `$N` placeholders fails, because the Data API binds named parameters only and drizzle-kit forwards the placeholders unchanged. On `1.0.0-rc.4` this is reachable through `drizzle-kit studio`, whose client sends raw SQL:

```
ERROR: bind message supplies 0 parameters, but prepared statement "sqlx_s_35" requires 1; SQLState: 08P01
```

**Desired result.** Parameterized queries execute, so studio works against a Data API connection.

**Environment.** Aurora Serverless v2, PostgreSQL 15.12, Data API enabled. Not a monorepo. The reproduction creates its catalog with plain DDL over the Data API rather than with drizzle-kit, so the tool under test is isolated from the fixture that produces its input.

### Steps to reproduce

```bash
git clone https://github.com/simiancraft/drizzle-kit-rds-data-api-repro
cd drizzle-kit-rds-data-api-repro
git checkout rc # drizzle-kit + drizzle-orm 1.0.0-rc.4
cp .env.example .env # your own cluster ARN, secret ARN, database
bun install
bun run seed # creates the catalog with plain DDL

bun x drizzle-kit studio --port 5599 # in one shell
bun run probe:studio 5599 # in another
```

Use an empty, dedicated database.

### Isolating it to parameter binding

The probe sends the same query twice over the same connection, once without parameters and once with one:

```
### CONTROL: no parameters
sql: select count(*)::text as n from regions
result: [{"n":"0"}]

### TEST: one bound parameter
sql: select count(*)::text as n from regions where country_code = $1
params: ["US"]
result: {"status":"error","error":"ERROR: bind message supplies 0 parameters,
but prepared statement \"sqlx_s_35\" requires 1; SQLState: 08P01"}
```

The control succeeds, so the failure is the parameter binding rather than the query, the credentials, or the connection. Sent straight to the Data API with no drizzle involved, `SELECT $1::text` returns the identical `08P01`, which is the defect in one line.

### Cause

`AwsPgDialect.escapeParam(num)` returns `` `:${num + 1}` ``, so SQL the ORM *generates* already carries Data API named placeholders. SQL that arrives at drizzle-kit's proxy does not come from the dialect, and nothing translates it.

Two sites, with different mechanisms that produce the same error:

1. **Placeholders are not translated.** [`cli/connections.ts` L96 and L116 on `beta`](https://github.com/drizzle-team/drizzle-orm/blob/748058e837d9c4247330e3d45580cbdae52bffda/drizzle-kit/src/cli/connections.ts#L96) (L79 and L89 [on `main`](https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-kit/src/cli/connections.ts#L79)) pass `sql` to `session.prepareQuery` verbatim.

2. **Parameters are dropped.** [`ext/api-postgres.ts` L134 on `beta`](https://github.com/drizzle-team/drizzle-orm/blob/748058e837d9c4247330e3d45580cbdae52bffda/drizzle-kit/src/ext/api-postgres.ts#L134) ([`api.ts` L139 on `main`](https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-kit/src/api.ts#L139)) accepts `params` and executes `sql.raw(query)` without them. On `beta` it is named `_params`, so the discard may well be deliberate; if it is, then callers passing parameters into it are the problem instead. That one is your call, not ours.

### Why `pull` is not affected on 1.0.0-rc.4

Not because binding was fixed, but because that path stopped using parameters. [`dialects/postgres/aws-introspect.ts`](https://github.com/drizzle-team/drizzle-orm/blob/748058e837d9c4247330e3d45580cbdae52bffda/drizzle-kit/src/dialects/postgres/aws-introspect.ts) contains zero positional placeholders, and it carries the `::text` casts the Data API needs (`contype::text`, `attidentity::text`, `attgenerated::text`, `pg_get_serial_sequence(...)::regclass::oid`), since the Data API rejects `char` and `regclass` result columns. That is a genuine improvement over the 0.31.x line; `pull` on `1.0.0-rc.4` is clean for us, including against a 43 table, 384 column, 100 index, 62 foreign key schema. It leaves the proxy path uncovered.

| Surface | 0.31.10 | 1.0.0-rc.4 |
|---|---|---|
| `pull` / `push` introspection | fails | works |
| `studio` proxy | not tested by us (`pull` fails first) | **fails** |
| programmatic `pushSchema` | params discarded in source | params discarded in source |

### Possibly related

- #2372 (open) reports `bind message supplies 0 parameters` from `push` on a composite primary key, which is the same underlying incompatibility reached through a different command. Its reported symptom appears fixed on `1.0.0-rc.4` by the parameter-free introspection above, which is why we filed this separately rather than commenting there; the defect underneath it is still live and still reachable. @petejodo diagnosed site 2 there in January 2025.
- #3273 (closed) reports `Unsupported data type "CHAR"` in studio, which is a different defect on the same driver, addressed by the casts in `aws-introspect.ts`.
- #2982 (open) is the umbrella report for drizzle-kit over the Data API.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.