Skip to content

Fix Checking for Changed Fields in QBMapper->update#56337

Open
Bibo-Joshi wants to merge 2 commits intonextcloud:masterfrom
Bibo-Joshi:qbmapper-update-fix
Open

Fix Checking for Changed Fields in QBMapper->update#56337
Bibo-Joshi wants to merge 2 commits intonextcloud:masterfrom
Bibo-Joshi:qbmapper-update-fix

Conversation

@Bibo-Joshi
Copy link
Contributor

@Bibo-Joshi Bibo-Joshi commented Nov 9, 2025

  • Resolves: No GitHub issues. I did not find any tickets mentioning this behavior and directly created a PR. Hope this is okay

Summary

The logic in QBMapper->update currently doesn't work correctly if only the id field 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

  • Clarify if sign-off is required for the copilot commit. I can squash both commits, if that helps. Though I do expect that you do a squash-merge anyways …
  • Clarify need for backports. IMO it would be good to backport this. That way, developers on all supported NC versions can profit from this
  • Give a shout-out to NC for their open source commitment 💖

Checklist

  • Code is properly formatted
  • Sign-off message is added to all commits
  • Tests (unit, integration, api and/or acceptance) are included
  • [ ] Screenshots before/after for front-end changes
  • Documentation ([manuals](https://github.com/nextcloud/documentation/) or wiki) has been updated or is not required
  • Backports requested where applicable (ex: critical bugfixes)
  • Labels added where applicable (ex: bug/enhancement, 3. to review, feature component)
  • Milestone added for target branch/version (ex: 32.x for stable32)

Bibo-Joshi and others added 2 commits November 9, 2025 19:43
Signed-off-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
@Bibo-Joshi Bibo-Joshi requested a review from a team as a code owner November 9, 2025 19:41
@Bibo-Joshi Bibo-Joshi requested review from Altahrim, CarlSchwan, icewind1991 and leftybournes and removed request for a team November 9, 2025 19:41
@github-actions
Copy link
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants