A backtick identifier containing a single quote flips the lexer's quote state, silently corrupting the next string literal (MySQL/MariaDB)
Possibly a duplicate of #166 , my bot found the following...
Version
usql 0.21.4 (Homebrew), macOS 14.6 (darwin/arm64). Server: mariadb:latest (11.x) in Docker, my:// driver.
Summary
In MySQL/MariaDB dialect, a backtick-quoted identifier that contains a ' opens a phantom string in usql's client-side lexer. The quote state stays flipped for the rest of the statement, so the next string literal is re-processed with C-style backslash escapes applied before being sent to the server. usql exits 0 and prints no warning — the statement just does something other than what was written.
Only literals that follow such an identifier are affected. Identifier-after-literal, plain backticks, and every other quoting combination I tried are byte-correct.
Repro
docker run --rm -d -p 13306:3306 -e MARIADB_ROOT_PASSWORD=secret --name usql-bug mariadbWrite the statement to a file so no shell touches it:
printf "%s" "select 1 as \`we'ird\`, hex('a\\\\b')" > q.sql
cat q.sql # select 1 as `we'ird`, hex('a\\b')
usql -q -A -t -X -w 'my://root:[email protected]:13306/' -c "$(cat q.sql)"
docker exec -e MYSQL_PWD=secret usql-bug mariadb -u root -N -B --raw -e "$(cat q.sql)"| Statement | mariadb client |
usql |
|---|---|---|
select hex('a\\b') |
615C62 (a\b) |
615C62 ✅ |
select 1 as `plain`, hex('a\\b') |
615C62 |
615C62 ✅ |
select hex('a\\b'), 1 as `we'ird` |
615C62 |
615C62 ✅ |
select 1 as `we'ird`, hex('a\\b') |
615C62 |
6108 (a + 0x08 backspace) ❌ |
\\b should reach the server as a two-character escape for a literal backslash. usql instead delivers a backspace, i.e. it applied C unescaping a second time.
Why it bites in practice
The same shape in DDL silently stores the wrong password:
printf "%s" "create user \`we'ird-User\`@\`%\` identified by 'pa''ss\\\\w0rd'" > c.sql
usql -q -A -t -X -w 'my://root:[email protected]:13306/' -c "$(cat c.sql)" # exit 0
docker exec -e MYSQL_PWD=secret usql-bug mariadb -u root -N -B -e \
"select user, authentication_string = password('pa''ss\\\\w0rd') as correct_pw, \
authentication_string = password('pa''ssw0rd') as backslash_eaten \
from mysql.user where user like '%User'"
# we'ird-User 0 1Piping the identical file into the mariadb client gives correct_pw = 1. Through usql the account exists with password pa'ssw0rd instead of pa'ss\w0rd, and nothing reports a problem — a config-management tool then reports "unchanged" forever against credentials that don't work.
Two related silent no-ops
Both also exit 0 with no output, which is what made this hard to spot:
- Same
create userstatement via-fwith a trailing;→ the account is never created. - Any
-ffile whose final statement has no trailing;→ the buffered statement is discarded at EOF rather than executed. (psqlexecutes it.) Independent of the quoting bug.
Expected
The statement text reaches the server unmodified (as the vendor clients do), or usql errors out rather than exiting 0 having sent something different / nothing at all.
Source: xo/usql