[CSHARP-849] Bug in query builder when selecting with ids for some ulong values Created: 21/Oct/13  Updated: 20/Mar/14  Resolved: 20/Mar/14

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.8.3
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Hassan Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 7, VS 2012, x64 bit CPU


Attachments: Text File Program.cs    

 Description   

When selecting a document using C# drivers v1.8.3.9. If the id is casted as ulong the query does not return document for some ulong values (e.g. 5935691471546811785). But for most ulongs the query does return the documents (e.g. 5935691471546877322). There appears to be no pattern for ulong values for which document will be returned or not. But if the id is casted as long, query always returns the document with the id.

Finds nothing ("Enumeration yielded no results"):
• collection.Find(Query.EQ(Collection.Fields.ID, (ulong) 5935691471546811785))
• {
"_id" : NumberLong("5935691471546811785"),
"test" : ["test_does_not_work"
}

Finds the document:
• collection.Find(Query.EQ(Collection.Fields.ID, (ulong) 5935691471546877322))

• {
"_id" : NumberLong("5935691471546877322"),
"test" : ["test_works"
}

Fix:
Finds the document:
collection.Find(Query.EQ(Collection.Fields.ID, (long) 5935691471546811785))



 Comments   
Comment by Robert Stam [ 22/Oct/13 ]

I was unable to reproduce this with the particular values you provided, but I can reproduce it with some carefully chosen values. What is happening is that BSON doesn't have a ulong data type, so when you query using a ulong value it is converted to a BsonDouble. If the ulong value is large enough the BsonDouble loses a few bits of precision in the low order digits. This is not a driver bug, it is just what happens when a very large 64 bit ulong is converted to a 64 bit double and doesn't quite fit.

I reproduced it using the following code (see the attached Program.cs for the full code):

collection.Insert(new BsonDocument { { "_id", 1 }, { "x", new BsonInt64(long.MaxValue - 1) } });
collection.Insert(new BsonDocument { { "_id", 2 }, { "x", new BsonInt64(long.MaxValue) } });
 
EchoDocuments(collection, Query.EQ("x", long.MaxValue - 1));
EchoDocuments(collection, Query.EQ("x", (ulong)(long.MaxValue - 1)));
 
EchoDocuments(collection, Query.EQ("x", long.MaxValue));
EchoDocuments(collection, Query.EQ("x", (ulong)long.MaxValue));

And the output was:

Documents matching: { "x" : NumberLong("9223372036854775806") }
{ "_id" : 1, "x" : NumberLong("9223372036854775806") }
 
Documents matching: { "x" : 9.2233720368547758E+18 }
{ "_id" : 1, "x" : NumberLong("9223372036854775806") }
{ "_id" : 2, "x" : NumberLong("9223372036854775807") }
 
Documents matching: { "x" : NumberLong("9223372036854775807") }
{ "_id" : 2, "x" : NumberLong("9223372036854775807") }
 
Documents matching: { "x" : 9.2233720368547758E+18 }
{ "_id" : 1, "x" : NumberLong("9223372036854775806") }
{ "_id" : 2, "x" : NumberLong("9223372036854775807") }

In the absence of rounding errors you would expect the first two queries to return _id 1 only, and the last two queries to return _id 2 only, but the rounding errors cause the 2nd and 4th queries to return both documents.

The workaround is to cast to a (long) exactly as you have done.

Generated at Wed Feb 07 21:38:00 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.