fix: layer-1 verbs always substitute params, so a % identifier reaches the server intact
T3-16: _norm_params turned an empty params list into None, so aiomysql skipped query % args and a no-condition get/get_one/exists/delete on a table named 50%_off sent `50%%_off` (table not found). layer 1 now passes its params list as-is; only the layer-2 methods normalize. Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
1 parent
febace7d5d
commit
7eb5d552f5
1 file changed
+10
-8
+10
-8
@@ -198,18 +198,20 @@ class MysqlDB:
|
||||
async def _run(self, query: str, params: Optional[Sequence] = None):
|
||||
"""execute a statement on a pooled cursor; return (rowcount, lastrowid)
|
||||
|
||||
params go through `_norm_params` (see it for the no-substitution/str-bytes handling)
|
||||
params are passed to aiomysql as-is: layer 1 always hands a list (even empty) so
|
||||
`query % args` runs and collapses `_quote_ident`'s `%%`; layer 2 normalizes first
|
||||
via `_norm_params`
|
||||
"""
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute(query, _norm_params(params))
|
||||
await cur.execute(query, params)
|
||||
return cur.rowcount, cur.lastrowid
|
||||
|
||||
async def _fetchall(self, query: str, params: Optional[Sequence] = None) -> List[dict]:
|
||||
"""execute a query and return all rows as dicts"""
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute(query, _norm_params(params))
|
||||
await cur.execute(query, params)
|
||||
rows = await cur.fetchall()
|
||||
return list(rows)
|
||||
|
||||
@@ -217,7 +219,7 @@ class MysqlDB:
|
||||
"""execute a query and return the first row dict, or None"""
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute(query, _norm_params(params))
|
||||
await cur.execute(query, params)
|
||||
return await cur.fetchone()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -230,7 +232,7 @@ class MysqlDB:
|
||||
lastrowid, or reach for the raw pool.
|
||||
"""
|
||||
try:
|
||||
rowcount, _ = await self._run(query, params)
|
||||
rowcount, _ = await self._run(query, _norm_params(params))
|
||||
except _DRIVER_ERRORS:
|
||||
log.debug("mysql.execute(): %s", query, exc_info=True)
|
||||
raise
|
||||
@@ -239,7 +241,7 @@ class MysqlDB:
|
||||
async def fetch(self, query: str, params: Optional[Sequence] = None) -> List[dict]:
|
||||
"""run a query and return all rows as plain dicts (empty list = no rows)"""
|
||||
try:
|
||||
return await self._fetchall(query, params)
|
||||
return await self._fetchall(query, _norm_params(params))
|
||||
except _DRIVER_ERRORS:
|
||||
log.debug("mysql.fetch(): %s", query, exc_info=True)
|
||||
raise
|
||||
@@ -247,7 +249,7 @@ class MysqlDB:
|
||||
async def fetchone(self, query: str, params: Optional[Sequence] = None) -> Optional[dict]:
|
||||
"""run a query and return the first row as a dict, or None if no rows"""
|
||||
try:
|
||||
return await self._fetchone(query, params)
|
||||
return await self._fetchone(query, _norm_params(params))
|
||||
except _DRIVER_ERRORS:
|
||||
log.debug("mysql.fetchone(): %s", query, exc_info=True)
|
||||
raise
|
||||
@@ -255,7 +257,7 @@ class MysqlDB:
|
||||
async def fetchval(self, query: str, params: Optional[Sequence] = None) -> Any:
|
||||
"""run a query and return the first column of the first row, or None"""
|
||||
try:
|
||||
row = await self._fetchone(query, params)
|
||||
row = await self._fetchone(query, _norm_params(params))
|
||||
except _DRIVER_ERRORS:
|
||||
log.debug("mysql.fetchval(): %s", query, exc_info=True)
|
||||
raise
|
||||
|
||||
Reference in new issue
Block a user