Known Limitations
Last updated
This page collects behaviors in the current version that you need to work around, each with its cause and an alternative.
Missing Features
| Limitation | Alternative |
|---|---|
No transactions: every query() checks out a fresh pooled connection and releases it afterward, so BEGIN/COMMIT may land on different connections |
Open a connection with mysql2/promise and manage the transaction yourself |
No delete(), groupBy(), having(), or orWhere() |
Use Raw SQL |
where() cannot express IS NULL/IS NOT NULL: a null value becomes = NULL or turns the operator into the value |
Use raw SQL; see Select and Where |
where(column, "IN", []) produces an IN () syntax error |
Check for an empty array before calling |
select("name AS n") is backtick-quoted as a whole |
Write "users.name AS n" |
table("db.table") is quoted as `db.table` |
Set database in the connection config, or use raw SQL |
mysql2 pool options such as ssl, timezone, and queueLimit cannot be passed |
See Configuration |
Security
Data values are bound through placeholders, but the following fragments are written into SQL directly and must never carry user input:
| Fragment | Methods |
|---|---|
| Column and table names | Every builder method |
| Operators | where(), innerJoin()/leftJoin()/rightJoin() |
LIMIT/OFFSET numbers |
limit(), offset() |
| Increment column and step | increase() |
String updateData |
upsert() |
Shared State
| Limitation | Detail |
|---|---|
| Builder state is global and static | A chain split by an await can be reset by another request's table(); see Builder State |
| State is not cleared after execution | A chain that does not start with table() reuses the previous table and conditions |
update() without where() updates the whole table |
There is no guard; confirm the condition before calling |
| One pair of pools per process | You cannot connect to several separate database clusters at once |
Lifecycle
| Limitation | Detail |
|---|---|
Importing registers SIGINT/SIGTERM handlers that exit with code 0 |
Cuts off your application's own async cleanup; see Lifecycle and Shutdown |
Calling init() again does not close the old pools |
Call close() first |
| The slow query threshold is fixed at 20ms and printed to stdout | See Slow Query Log |
insert() does not apply the MySQL function allowlist |
"NOW()" is stored as a string; see Insert and Update |