Fix Checking for Changed Fields in QBMapper->update#56337
Fix Checking for Changed Fields in QBMapper->update#56337Bibo-Joshi wants to merge 2 commits intonextcloud:masterfrom
QBMapper->update#56337Conversation
Signed-off-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
Summary
The logic in
QBMapper->updatecurrently doesn't work correctly if only theidfield was changed/specified on the entity. This can lead to an invalid DB operation. See the following example raw log entry:Details
{"reqId":"aRDMUoN__vucPPsb6QAWvwAAAAA","level":3,"time":"2025-11-09T17:16:02+00:00","remoteAddr":"87.123.2.61","user":"admin","app":"no app in context","method":"PATCH","url":"/ocs/v2.php/apps/orchestrascoresmanager/scores/2","message":"An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0","version":"32.0.1.2","exception":{"Exception":"OC\\DB\\Exceptions\\DbalException","Message":"An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","Code":1064,"Trace":[{"file":"/home/www/cloud-test/lib/private/DB/ConnectionAdapter.php","line":69,"function":"wrap","class":"OC\\DB\\Exceptions\\DbalException","type":"::","args":[{"__class__":"Doctrine\\DBAL\\Exception\\SyntaxErrorException"},"","UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1"]},{"file":"/home/www/cloud-test/lib/private/DB/QueryBuilder/QueryBuilder.php","line":308,"function":"executeStatement","class":"OC\\DB\\ConnectionAdapter","type":"->","args":["UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/public/AppFramework/Db/QBMapper.php","line":198,"function":"executeStatement","class":"OC\\DB\\QueryBuilder\\QueryBuilder","type":"->","args":[]},{"file":"/home/www/cloud-test/apps/orchestrascoresmanager/lib/Controller/ScoreApiController.php","line":195,"function":"update","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":204,"function":"patchScore","class":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","type":"->","args":[2,null,null,null,null,null,null,null,null,null,null,null,[8,9]]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":118,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/App.php","line":153,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/Route/Router.php","line":321,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","patchScore",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.orchestrascoresmanager.scoreapi.patchscore","id":"2"}]},{"file":"/home/www/cloud-test/ocs/v1.php","line":61,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/orchestrascoresmanager/scores/2"]},{"file":"/home/www/cloud-test/ocs/v2.php","line":8,"args":["/home/www/cloud-test/ocs/v1.php"],"function":"require_once"}],"File":"/home/www/cloud-test/lib/private/DB/Exceptions/DbalException.php","Line":56,"Previous":{"Exception":"Doctrine\\DBAL\\Exception\\SyntaxErrorException","Message":"An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","Code":1064,"Trace":[{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connection.php","line":1976,"function":"convert","class":"Doctrine\\DBAL\\Driver\\API\\MySQL\\ExceptionConverter","type":"->","args":[{"__class__":"Doctrine\\DBAL\\Driver\\PDO\\Exception"},{"__class__":"Doctrine\\DBAL\\Query"}]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connection.php","line":1918,"function":"handleDriverException","class":"Doctrine\\DBAL\\Connection","type":"->","args":[{"__class__":"Doctrine\\DBAL\\Driver\\PDO\\Exception"},{"__class__":"Doctrine\\DBAL\\Query"}]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connection.php","line":1218,"function":"convertExceptionDuringQuery","class":"Doctrine\\DBAL\\Connection","type":"->","args":[{"__class__":"Doctrine\\DBAL\\Driver\\PDO\\Exception"},"UPDATE `oc_osm_score` SET WHERE `id` = ?",[2],[1]]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php","line":292,"function":"executeStatement","class":"Doctrine\\DBAL\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = ?",[2],[1]]},{"file":"/home/www/cloud-test/lib/private/DB/Connection.php","line":467,"function":"executeStatement","class":"Doctrine\\DBAL\\Connections\\PrimaryReadReplicaConnection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/ConnectionAdapter.php","line":67,"function":"executeStatement","class":"OC\\DB\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/QueryBuilder/QueryBuilder.php","line":308,"function":"executeStatement","class":"OC\\DB\\ConnectionAdapter","type":"->","args":["UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/public/AppFramework/Db/QBMapper.php","line":198,"function":"executeStatement","class":"OC\\DB\\QueryBuilder\\QueryBuilder","type":"->","args":[]},{"file":"/home/www/cloud-test/apps/orchestrascoresmanager/lib/Controller/ScoreApiController.php","line":195,"function":"update","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":204,"function":"patchScore","class":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","type":"->","args":[2,null,null,null,null,null,null,null,null,null,null,null,[8,9]]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":118,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/App.php","line":153,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/Route/Router.php","line":321,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","patchScore",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.orchestrascoresmanager.scoreapi.patchscore","id":"2"}]},{"file":"/home/www/cloud-test/ocs/v1.php","line":61,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/orchestrascoresmanager/scores/2"]},{"file":"/home/www/cloud-test/ocs/v2.php","line":8,"args":["/home/www/cloud-test/ocs/v1.php"],"function":"require_once"}],"File":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php","Line":88,"Previous":{"Exception":"Doctrine\\DBAL\\Driver\\PDO\\Exception","Message":"SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","Code":1064,"Trace":[{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php","line":132,"function":"new","class":"Doctrine\\DBAL\\Driver\\PDO\\Exception","type":"::","args":[{"__class__":"PDOException","errorInfo":["42000",1064,"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1"]}]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connection.php","line":1212,"function":"execute","class":"Doctrine\\DBAL\\Driver\\PDO\\Statement","type":"->","args":[]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php","line":292,"function":"executeStatement","class":"Doctrine\\DBAL\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = ?",[2],[1]]},{"file":"/home/www/cloud-test/lib/private/DB/Connection.php","line":467,"function":"executeStatement","class":"Doctrine\\DBAL\\Connections\\PrimaryReadReplicaConnection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/ConnectionAdapter.php","line":67,"function":"executeStatement","class":"OC\\DB\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/QueryBuilder/QueryBuilder.php","line":308,"function":"executeStatement","class":"OC\\DB\\ConnectionAdapter","type":"->","args":["UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/public/AppFramework/Db/QBMapper.php","line":198,"function":"executeStatement","class":"OC\\DB\\QueryBuilder\\QueryBuilder","type":"->","args":[]},{"file":"/home/www/cloud-test/apps/orchestrascoresmanager/lib/Controller/ScoreApiController.php","line":195,"function":"update","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":204,"function":"patchScore","class":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","type":"->","args":[2,null,null,null,null,null,null,null,null,null,null,null,[8,9]]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":118,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/App.php","line":153,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/Route/Router.php","line":321,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","patchScore",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.orchestrascoresmanager.scoreapi.patchscore","id":"2"}]},{"file":"/home/www/cloud-test/ocs/v1.php","line":61,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/orchestrascoresmanager/scores/2"]},{"file":"/home/www/cloud-test/ocs/v2.php","line":8,"args":["/home/www/cloud-test/ocs/v1.php"],"function":"require_once"}],"File":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Driver/PDO/Exception.php","Line":24,"Previous":{"Exception":"PDOException","Message":"SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","Code":"42000","Trace":[{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php","line":130,"function":"execute","class":"PDOStatement","type":"->","args":[null]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connection.php","line":1212,"function":"execute","class":"Doctrine\\DBAL\\Driver\\PDO\\Statement","type":"->","args":[]},{"file":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php","line":292,"function":"executeStatement","class":"Doctrine\\DBAL\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = ?",[2],[1]]},{"file":"/home/www/cloud-test/lib/private/DB/Connection.php","line":467,"function":"executeStatement","class":"Doctrine\\DBAL\\Connections\\PrimaryReadReplicaConnection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/ConnectionAdapter.php","line":67,"function":"executeStatement","class":"OC\\DB\\Connection","type":"->","args":["UPDATE `oc_osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/private/DB/QueryBuilder/QueryBuilder.php","line":308,"function":"executeStatement","class":"OC\\DB\\ConnectionAdapter","type":"->","args":["UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1",{"dcValue1":2},{"dcValue1":1}]},{"file":"/home/www/cloud-test/lib/public/AppFramework/Db/QBMapper.php","line":198,"function":"executeStatement","class":"OC\\DB\\QueryBuilder\\QueryBuilder","type":"->","args":[]},{"file":"/home/www/cloud-test/apps/orchestrascoresmanager/lib/Controller/ScoreApiController.php","line":195,"function":"update","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":204,"function":"patchScore","class":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","type":"->","args":[2,null,null,null,null,null,null,null,null,null,null,null,[8,9]]},{"file":"/home/www/cloud-test/lib/private/AppFramework/Http/Dispatcher.php","line":118,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/AppFramework/App.php","line":153,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\OrchestraScoresManager\\Controller\\ScoreApiController"},"patchScore"]},{"file":"/home/www/cloud-test/lib/private/Route/Router.php","line":321,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\OrchestraScoresManager\\Controller\\ScoreApiController","patchScore",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.orchestrascoresmanager.scoreapi.patchscore","id":"2"}]},{"file":"/home/www/cloud-test/ocs/v1.php","line":61,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/orchestrascoresmanager/scores/2"]},{"file":"/home/www/cloud-test/ocs/v2.php","line":8,"args":["/home/www/cloud-test/ocs/v1.php"],"function":"require_once"}],"File":"/home/www/cloud-test/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php","Line":130}}},"message":"An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1","exception":{"query":"UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1"},"CustomMessage":"An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id` = 2' at line 1"},"id":"6910ea8a99735"}The important part here is
UPDATE `*PREFIX*osm_score` SET WHERE `id` = :dcValue1"where there are no values specified to be set.I discovered this bug while implementing a custom app, where I have an entity with transient attributes. In my API PATCH endpoint, either transient attributes or db-mapped attributes can be changed. When calling
$mapper->update($entity)if only the transient attributes were changed, this exception is raised. I currently have to manually replicate the check the contents of$entity->getUpdatedFields()before calling$mapper->update($entity).For the unit tests, I had help from the AI b/c I'm not familiar with the test setup of NC so far. I did verify that they succeed and they look sane to me. Nevertheless, I'm ofc happey for suggestions on how to improve them.
Please let me know if you need any additional information or if I should improve anything about the PR.
TODO
Checklist
[ ] Screenshots before/after for front-end changes([manuals](https://github.com/nextcloud/documentation/) or wiki) has been updated oris not required3. to review, feature component)stable32)