Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-19348

$mod results are inconsistent with indexing enabled on Infinity, -Infinity, NaN

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Fixed
    • Affects Version/s: 2.2.7, 2.4.14, 2.6.10, 3.1.5
    • Fix Version/s: 3.1.7
    • Component/s: Indexing, Querying
    • Labels:
    • Backwards Compatibility:
      Minor Change
    • Operating System:
      ALL
    • Steps To Reproduce:
      Hide

      In the shell:

      > db.test.insert({ a : Infinity })
      WriteResult({ "nInserted" : 1})
      > db.test.insert({ a: -Infinity })
      WriteResult({ "nInserted" : 1 })
      > db.test.insert({ a: NaN })
      WriteResult({ "nInserted" : 1 })
      > db.test.find({ a : { $mod: [10, -8] }})
      { "_id" : ObjectId("559edbdb37a9ccb7245bb7f9"), "a" : Infinity }
      { "_id" : ObjectId("559edbdc37a9ccb7245bb7fa"), "a" : -Infinity }
      { "_id" : ObjectId("559edbdf37a9ccb7245bb7fb"), "a" : NaN }
      > db.test.ensureIndex({ a: 1})
      {
              "createdCollectionAutomatically" : false,
              "numIndexesBefore" : 1,
              "numIndexesAfter" : 2,
              "ok" : 1
      }
      > db.test.find({ a : { $mod: [10, -8] }})
      > db.test.dropIndex({ a : 1 })
      { "nIndexesWas" : 2, "ok" : 1 }
      > db.test.find({ a : { $mod: [10, -8] }})
      { "_id" : ObjectId("559edbdb37a9ccb7245bb7f9"), "a" : Infinity }
      { "_id" : ObjectId("559edbdc37a9ccb7245bb7fa"), "a" : -Infinity }
      { "_id" : ObjectId("559edbdf37a9ccb7245bb7fb"), "a" : NaN }
       
      
      

      Show
      In the shell: > db.test.insert({ a : Infinity }) WriteResult({ "nInserted" : 1}) > db.test.insert({ a: -Infinity }) WriteResult({ "nInserted" : 1 }) > db.test.insert({ a: NaN }) WriteResult({ "nInserted" : 1 }) > db.test.find({ a : { $mod: [10, -8] }}) { "_id" : ObjectId("559edbdb37a9ccb7245bb7f9"), "a" : Infinity } { "_id" : ObjectId("559edbdc37a9ccb7245bb7fa"), "a" : -Infinity } { "_id" : ObjectId("559edbdf37a9ccb7245bb7fb"), "a" : NaN } > db.test.ensureIndex({ a: 1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.test.find({ a : { $mod: [10, -8] }}) > db.test.dropIndex({ a : 1 }) { "nIndexesWas" : 2, "ok" : 1 } > db.test.find({ a : { $mod: [10, -8] }}) { "_id" : ObjectId("559edbdb37a9ccb7245bb7f9"), "a" : Infinity } { "_id" : ObjectId("559edbdc37a9ccb7245bb7fa"), "a" : -Infinity } { "_id" : ObjectId("559edbdf37a9ccb7245bb7fb"), "a" : NaN }  

      Description

      The $mod operator in find queries currently casts values to long long when matching, using the unsafe BSONElement.numberLong(...). This means NaN, -Infinity, and Infinity are all converted to the minimum long long, although the behavior is undefined. Behavior for doubles out of range of long long is also undefined, although I haven't checked precisely what does occur.

      If $mod is going to convert to long long, it might be appropriate to not match any values outside the range of long long, as all of them will have undefined value.

      This would solve the indexing problem, and we could scan the interval of NumberLong s instead of NumberDouble.

      This issue was introduced because BSONElement.appendMinForType and BSONElement.appendMaxForType appends the maximum and minimum double value, not Infinity. Elsewhere in src/mongo/db/query/index_bounds_builder.cpp, appendMin/MaxForType is not used, in favor of explicitly using Infinity. In practice the only time this function is called is for the $mod and $type match expressions.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              david.hatch David Hatch
              Reporter:
              david.hatch David Hatch
              Participants:
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: