MMOframework
Why AI Playground Libraries Documentation Search Agency
FR EN
Index
# Troubleshooting ## Both drivers ### `SQLSTATE[HY000]: General error: 25 column index out of range` More bindings were collected than the query has `?` placeholders. Almost always a **quoted placeholder**: ```php //wrong: renders the literal text `"?"`, but still binds the value $handler->statement('SELECT * FROM t WHERE name = "{name}"', ['name' => 'marc']); //right $handler->statement('SELECT * FROM t WHERE name = {name}', ['name' => 'marc']); ``` To see what a render really produced: ```php $binds = new MMO\pdo\statements\Binds(); $sql = $stmt->render(['binds' => $binds]); var_dump($sql, $binds->toArray()); //the `?` count must equal the bind count ``` ### `unrecognized token: "{"` A placeholder was not recognised and stayed in the query as literal text. A placeholder's name **must start with a letter**: `{_where}` is not a placeholder at all. ### `eNotFound: cannot filter … no such column` The query filters on a name that is neither a column of the table nor a property of its entity (a property without a column holds its default on every row, and is decided without SQL: see [Repository](Repository.md#filters)). Give the table the column, or filter on ones it has. Unlike the field list, a filter is never silently dropped — that would return more rows than were asked for. ### Nothing was written, and no error Historically: `do()` opened a transaction that was never committed, and `disconnect()` rolled it back. Fixed — but if you see it again, check `inTransaction()` after your write and make sure nothing calls `startTransaction()` without a matching `commit()`. ## SQLite ### `unable to open database file` Permissions: SQLite needs write access to the **directory**, not just the file, because it creates a journal beside it. Under a web server that means writable by the server user, not by you. For a demo or a test, avoid it entirely with `SqliteHandler::MEMORY`. ### `database is locked` Another connection holds a write transaction. Look for a `do()` whose exception was swallowed, or a handler that was never disconnected. ### `ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint` An upsert's conflict target must match **one** unique index exactly — `ON CONFLICT(id,name)` is invalid when `id` and `name` are separate keys. `Table::store()` picks a valid target itself; if you called `insertStatement()->duplicate()` by hand, mark only the columns of a single key as `true`. ### The id of a deleted row is given to the next one A table mmo.pdo created before 2026-09 has no `AUTOINCREMENT`, even when its key declared one: its id is SQLite's rowid, which gives the id of the highest row deleted again (`SELECT sql FROM sqlite_master WHERE name = 'user'` shows `PRIMARY KEY(id)`). SQLite cannot add the keyword to a table: rebuild it, with its other columns and constraints. ```sql BEGIN; CREATE TABLE `user_new` (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL); INSERT INTO `user_new` SELECT * FROM `user`; DROP TABLE `user`; ALTER TABLE `user_new` RENAME TO `user`; COMMIT; ``` Its sequence starts at the highest id copied: an id deleted before the rebuild, above that one, can still come back once. A key the repository generates itself (`INT PRIMARY KEY`) is another case: see [Repository](Repository.md#ids). ## MySQL ### `Access denied for user 'root'@'localhost' (using password: YES)` ```bash sudo mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mypassword'" ``` Or from a client: ```sql FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY 'YOURNEWPASSWORD'; FLUSH PRIVILEGES; ``` ### The password is rejected as too weak See what the server requires: ```sql SHOW VARIABLES LIKE 'validate_password%'; ``` ``` +--------------------------------------+-------+ | Variable_name | Value | +--------------------------------------+-------+ | validate_password.check_user_name | ON | | validate_password.dictionary_file | | | validate_password.length | 6 | | validate_password.mixed_case_count | 1 | | validate_password.number_count | 1 | | validate_password.policy | LOW | | validate_password.special_char_count | 1 | +--------------------------------------+-------+ ``` Check a candidate: ```sql SELECT VALIDATE_PASSWORD_STRENGTH('weak'); -- 25 SELECT VALIDATE_PASSWORD_STRENGTH('lessweak$_@123'); -- 50 SELECT VALIDATE_PASSWORD_STRENGTH('N0Tweak$_@123!'); -- 100 ``` Or relax the policy: ```sql SET GLOBAL validate_password.length = 6; SET GLOBAL validate_password.number_count = 0; ```