_quote_ident() always doubles % to %%, but aiomysql only runs query % args
substitution when args is not None - _run/_fetchall/_fetchone were passing
params or None, so no-params DDL (create_database/create_table/drop) and
no-condition get/delete/exists shipped literal %% to the server, silently
targeting the wrong object and making IF EXISTS no-op (regression 2e837da).
_run/_fetchall/_fetchone now forward None as-is (preserving layer-2's
documented "no params, no substitution" contract) but always pass a real
tuple otherwise, so layer-1's %%-escaped identifiers always collapse back
to a single % as intended. The three no-params DDL verbs now pass an
explicit empty tuple so substitution runs for them too.
connect()/close() had the same lock asymmetry as psql (close() wasn't
guarded by _connect_lock, so a close() racing an in-flight connect() could
no-op while the new pool went live) - fixed in lockstep with the psql twin
fix, and create_pool() is now inside the same try/log/re-raise as the
SELECT-1 validation.
Signed-off-by: disqualifier <dev@disqualifier.me>
close() now nulls self._pool so a closed instance reports not-connected instead of
masquerading as live (twin of psql-7); connect() is guarded by an internal asyncio.Lock
so concurrent connect() calls serialize instead of racing to create and orphan multiple
live pools (twin of psql-8). _quote_ident now escapes a literal % in identifiers (mysql-7:
PyMySQL's query % args substitution otherwise breaks any Layer-1 call against a %-bearing
table/column name). fetchval/exists tolerate a caller-overridden tuple cursorclass via a
new _first_value helper (mysql-8). Documents the %%-escaping rule for literal % in raw SQL
text (mysql-6) and the upsert() VALUES() deprecation on MySQL 8.0.20+ (mysql-9).
Signed-off-by: disqualifier <dev@disqualifier.me>
_where() rendered None conditions as col = %s bound to NULL, which sql
never matches, so get/get_one/exists/delete silently missed NULL rows
despite insert() writing NULL fine — fixed to emit col IS NULL, in
lockstep with the psql lib's identical fix.
Separately, __init__ now rejects autocommit=False in pool_kwargs: with
it, _run/_fetchall never commit, so on pool release aiomysql closes the
in-transaction connection and MySQL rolls back server-side while
insert()/delete()/upsert()/execute() still return success signals
(lastrowid/rowcount) for writes that were silently discarded.
Signed-off-by: disqualifier <dev@disqualifier.me>
- connect() closes an existing pool on re-connect and tears down the built pool on SELECT-1
validation failure (sibling of psql-3).
- _Transaction now awaits pool.release() in both __aexit__ and the __aenter__ failure path,
matching psql and aiomysql's idiom (no un-awaited _wakeup task per transaction).
- README: insert-returns-lastrowid headline precision + upsert-rowcount convention note.
verified vs real MariaDB (re-connect, 5-tx release, full suite). bump v0.1.1 -> v0.1.2
Signed-off-by: disqualifier <dev@disqualifier.me>
same acquire-then-fail leak as psql: begin() failing after acquire leaked the conn. release
on failure. verified against MariaDB: 6 forced begin-failures no longer drain the pool.
bump v0.1.0 -> v0.1.1
Signed-off-by: disqualifier <dev@disqualifier.me>