summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/bson/util/bsoncolumn_test.cpp24
-rw-r--r--src/mongo/bson/util/simple8b_type_util.cpp13
2 files changed, 34 insertions, 3 deletions
diff --git a/src/mongo/bson/util/bsoncolumn_test.cpp b/src/mongo/bson/util/bsoncolumn_test.cpp
index 386d824a8cc..215b4bc1eac 100644
--- a/src/mongo/bson/util/bsoncolumn_test.cpp
+++ b/src/mongo/bson/util/bsoncolumn_test.cpp
@@ -1188,6 +1188,30 @@ TEST_F(BSONColumnTest, DoubleIntegerOverflow) {
verifyDecompression(binData, {e1, e2});
}
+TEST_F(BSONColumnTest, DoubleZerosSignDifference) {
+ BSONColumnBuilder cb("test"_sd);
+
+ // 0.0 compares equal to -0.0 when compared as double. Make sure we can handle this case without
+ // data loss.
+ auto d1 = createElementDouble(0.0);
+ auto d2 = createElementDouble(-0.0);
+ cb.append(d1);
+ cb.append(d2);
+
+ // These numbers are encoded as a large integer that does not fit in Simple8b so the result is
+ // two uncompressed literals.
+ ASSERT_EQ(deltaDoubleMemory(d2, d1), 0xFFFFFFFFFFFFFFFF);
+
+ BufBuilder expected;
+ appendLiteral(expected, d1);
+ appendLiteral(expected, d2);
+ appendEOO(expected);
+
+ auto binData = cb.finalize();
+ verifyBinary(binData, expected);
+ verifyDecompression(binData, {d1, d2});
+}
+
TEST_F(BSONColumnTest, Decimal128Base) {
BSONColumnBuilder cb("test"_sd);
diff --git a/src/mongo/bson/util/simple8b_type_util.cpp b/src/mongo/bson/util/simple8b_type_util.cpp
index b009c723f0b..1ec42cdf8bf 100644
--- a/src/mongo/bson/util/simple8b_type_util.cpp
+++ b/src/mongo/bson/util/simple8b_type_util.cpp
@@ -144,10 +144,14 @@ boost::optional<uint8_t> Simple8bTypeUtil::calculateDecimalShiftMultiplier(doubl
}
boost::optional<int64_t> Simple8bTypeUtil::encodeDouble(double val, uint8_t scaleIndex) {
- if (scaleIndex == kMemoryAsInteger) {
+ auto bitCastToInt64 = [](double value) {
int64_t ret;
- memcpy(&ret, &val, sizeof(ret));
+ memcpy(&ret, &value, sizeof(ret));
return ret;
+ };
+
+ if (scaleIndex == kMemoryAsInteger) {
+ return bitCastToInt64(val);
}
// Checks for both overflow and handles NaNs
@@ -166,7 +170,10 @@ boost::optional<int64_t> Simple8bTypeUtil::encodeDouble(double val, uint8_t scal
// We use encodeInt64 to handle negative floats by taking the signed bit and placing it at the
// lsb position
int64_t valueToBeEncoded = std::llround(valTimesMultiplier);
- if (valueToBeEncoded / scaleMultiplier != val) {
+
+ // We need to check that we can get the exact bit pattern back. 0.0 and -0.0 compares as equal
+ // when comparing as doubles but they have different bit patterns.
+ if (bitCastToInt64(valueToBeEncoded / scaleMultiplier) != bitCastToInt64(val)) {
return boost::none;
}
// Delta encoding. Gap should never induce overflow