Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix findAndModify for $set operator setting _id #2507

Merged
merged 4 commits into from
Apr 26, 2023

Conversation

chilagrow
Copy link
Member

@chilagrow chilagrow commented Apr 25, 2023

Description

Closes #2461.

Readiness checklist

  • I added/updated unit tests.
  • I added/updated integration/compatibility tests.
  • I added/updated comments and checked rendering.
  • I made spot refactorings.
  • I updated user documentation.
  • I ran task all, and it passed.
  • I ensured that PR title is good enough for the changelog.
  • (for maintainers only) I set Reviewers (@FerretDB/core), Labels, Project and project's Sprint fields.
  • I marked all done items in this checklist.

@chilagrow chilagrow added the code/bug Some user-visible feature works incorrectly label Apr 25, 2023
@chilagrow chilagrow self-assigned this Apr 25, 2023
@chilagrow chilagrow changed the title findAndModify returns error on $set _id findAndModify returns error on $set operator setting _id Apr 25, 2023
@codecov
Copy link

codecov bot commented Apr 25, 2023

Codecov Report

Merging #2507 (80fb3cc) into main (438fcea) will increase coverage by 1.36%.
The diff coverage is 0.00%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2507      +/-   ##
==========================================
+ Coverage   25.41%   26.78%   +1.36%     
==========================================
  Files         391      403      +12     
  Lines       18867    19976    +1109     
==========================================
+ Hits         4795     5350     +555     
- Misses      13536    14061     +525     
- Partials      536      565      +29     
Impacted Files Coverage Δ
internal/handlers/common/update.go 0.00% <0.00%> (ø)
internal/handlers/pg/msg_findandmodify.go 0.00% <0.00%> (ø)

... and 18 files with indirect coverage changes

Flag Coverage Δ
integration 5.06% <0.00%> (?)
mongodb 5.06% <0.00%> (?)
unit 25.38% <0.00%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@chilagrow
Copy link
Member Author

chilagrow commented Apr 26, 2023

So test script #2460 still does not pass. Even though mongosh and compat tests with go driver confirms that it is fixed.

task testjs using above PR's test.js script
$ task testjs
task: [testjs] docker compose run --rm legacy-mongo-shell 'mongodb://host.docker.internal:27017/' /legacy-mongo-shell/test.js

MongoDB shell version v6.0.5
connecting to: mongodb://host.docker.internal:27017/?compressors=disabled&gssapiServiceName=mongodb
WARNING: No implicit session: Logical Sessions are only supported on server versions 3.6 and greater.
Implicit session: dummy session
MongoDB server version: 6.0.42
uncaught exception: TypeError: actualErr is null :
@/legacy-mongo-shell/test.js:26:3
@/legacy-mongo-shell/test.js:29:3
failed to load: /legacy-mongo-shell/test.js
exiting with code -3
task: Failed to run task "testjs": exit status 253
task: Failed to run task "testjs": exit status 253

After running test script, checking the payload response body shows that error is writeError type not commandError type.

testjs request payload
{                                                                                                                                                                                                          
  "Checksum": 2773119528,                                                                                                                                                                                  
  "FlagBits": 1,                                                                                                                                                                                           
  "Sections": [                                                                                                                                                                                            
    {                                                                                                                                                                                                      
      "Document": {                                                                                                                                                                                        
        "$k": [                                                                                                                                                                                            
          "findandmodify",                                                                                                                                                                                 
          "query",                                                                                                                                                                                         
          "update",                                                                                                                                                                                        
          "upsert",                                                                                                                                                                                        
          "new",                                                                                                                                                                                           
          "$db"                                                                                                                                                                                            
        ],                                                                                                                                                                                                 
        "findandmodify": "test",                                                                                                                                                                           
        "query": {                                                                                                                                                                                         
          "$k": [                                                                                                                                                                                          
            "_id"                                                                                                                                                                                          
          ],                                                                                                                                                                                               
          "_id": "not_exists"                                                                                                                                                                              
        },                                                                                                                                                                                                 
        "update": {                                                                                                                                                                                        
          "$k": [                                                                                                                                                                                          
            "$set"                                                                                                                                                                                         
          ],                                                                                                                                                                                               
          "$set": {                                                                                                                                                                                        
            "$k": [                                                                                  
              "_id"                                                                                  
            ],                                                                                       
            "_id": "exists"                                                                          
          }                                                                                          
        },                                                                                           
        "upsert": true,                                                                                                                                                                                    
        "new": false,
        "$db": "test"    
      },             
      "Kind": 0
    }           
  ]                
}                 
testjs response payload
{
  "Checksum": 0,
  "FlagBits": 0,
  "Sections": [
    {
      "Document": {
        "$k": [
          "ok",
          "writeErrors"
        ],
        "ok": {
          "$f": 1
        },
        "writeErrors": [
          {
            "$k": [
              "code",
              "errmsg"
            ],
            "code": 66,
            "errmsg": "Performing an update on the path '_id' would modify the immutable field '_id'" 
          }
        ]
      },
      "Kind": 0
    }
  ]
}
testjs diff payload
Body diff:
--- res body
+++ proxy body
@@ -1,4 +1,4 @@
 {
-  "Checksum": 0,
-  "FlagBits": 0,
+  "Checksum": 2808560649,
+  "FlagBits": 1,
   "Sections": [
@@ -8,17 +8,12 @@
           "ok",
-          "writeErrors"
+          "errmsg",
+          "code",
+          "codeName"
         ],
         "ok": {
-          "$f": 1
+          "$f": 0
         },
-        "writeErrors": [
-          {
-            "$k": [
-              "code",
-              "errmsg"
-            ],
-            "code": 66,
-            "errmsg": "Performing an update on the path '_id' would modify the immutable field '_id'"
-          }
-        ]
+        "errmsg": "Plan executor error during findAndModify :: caused by :: Performing an update on the path '_id' would modify the immutable field '_id'",
+        "code": 66,
+        "codeName": "ImmutableField"
       },

But when running the same query on mongosh, it returns correct commandError type and the payload, the same one as proxy. Also same as compat result.

test> db.test.runCommand({"findAndModify":"test", query:{_id:"non-existent"}, update:{$set: {_id:"existing"}}, upsert:true})
MongoServerError: Performing an update on the path '_id' would modify the immutable field '_id'
mongosh request payload
{              
  "Checksum": 0, 
  "FlagBits": 0,
  "Sections": [                                                                                                                                                                                            
    {              
      "Document": {                 
        "$k": [
          "ok",
          "errmsg",
          "code",
          "codeName"
        ],
        "ok": {
          "$f": 0
        },                                                                                           
        "errmsg": "Performing an update on the path '_id' would modify the immutable field '_id'",
        "code": 66,                                                                                  
        "codeName": "ImmutableField"                                                                 
      },                                                                                             
      "Kind": 0                                                                                      
    }                                                                                                                                                                                                      
  ]           
}    
mongosh response payload
 {              
  "Checksum": 0, 
  "FlagBits": 0,
  "Sections": [                                                                                                                                                                                            
    {              
      "Document": {                 
        "$k": [
          "ok",
          "errmsg",
          "code",
          "codeName"
        ],
        "ok": {
          "$f": 0
        },                                                                                           
        "errmsg": "Performing an update on the path '_id' would modify the immutable field '_id'",
        "code": 66,                                                                                  
        "codeName": "ImmutableField"                                                                 
      },                                                                                             
      "Kind": 0                                                                                      
    }                                                                                                                                                                                                      
  ]           
}    

The message in diff is the only difference which is expected.

mongosh diff payload
Body diff:
--- res body
+++ proxy body
@@ -15,3 +15,3 @@
         },
-        "errmsg": "Performing an update on the path '_id' would modify the immutable field '_id'",
+        "errmsg": "Plan executor error during findAndModify :: caused by :: Performing an update on the path '_id' would modify the immutable field '_id'",
         "code": 66,

I conclude the driver under the hood or legacy mongosh or something is changing commandError to writeError. This sounds crazy. But unfortunately the test script cannot pass, even though the fix is in place and mongosh and compat tests confirm that.

@chilagrow chilagrow requested review from a team, w84thesun, rumyantseva and noisersup April 26, 2023 03:43
@chilagrow chilagrow marked this pull request as ready for review April 26, 2023 03:43
@chilagrow chilagrow requested a review from a team as a code owner April 26, 2023 03:43
@chilagrow chilagrow enabled auto-merge (squash) April 26, 2023 03:43
Copy link
Contributor

@w84thesun w84thesun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that's unexpected results with that shell! I'd say if the compat test pass we are ok.

Copy link
Contributor

@rumyantseva rumyantseva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@chilagrow chilagrow merged commit 91de3db into FerretDB:main Apr 26, 2023
@AlekSi AlekSi added this to the v1.1.0 milestone May 9, 2023
@AlekSi AlekSi changed the title findAndModify returns error on $set operator setting _id Fix findAndModify for $set operator setting _id May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code/bug Some user-visible feature works incorrectly
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

findAndModify should not allow upsert on existing _id
4 participants