[SERVER-31846] Provide error message when $exists : "false" i.e. value is string (not boolean) Created: 06/Nov/17  Updated: 06/Dec/22

Status: Backlog
Project: Core Server
Component/s: Querying
Affects Version/s: 3.0.12, 3.4.10, 3.6.0-rc2
Fix Version/s: None

Type: Task Priority: Minor - P4
Reporter: Roswitha Remling (Inactive) Assignee: Backlog - Query Optimization
Resolution: Unresolved Votes: 0
Labels: neweng
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to SERVER-12979 Respond with error upon encountering ... Backlog
Assigned Teams:
Query Optimization
Participants:
Case:

 Description   

Currently $exists : "false" evaluates to true, as does "true" and any other string

Shouldn't there be an error if you are trying to compare a string to a Boolean?

Tested on 3.0.12 and 3.4.10



 Comments   
Comment by Asya Kamsky [ 19/Nov/17 ]

Could this be handled in the driver/shell? If they do any syntax validation for queries then this could be something they check. My guess is they only check for valid json.

Comment by Asya Kamsky [ 10/Nov/17 ]

Note: fixing this issue will be backwards breaking.

Comment by Kyle Suarez [ 06/Nov/17 ]

I think the behavior is present in current master as well. In the MatchExpressionParser, we simply coerce the value to a boolean:

match_expression_parser.cpp

1615
        case PathAcceptingKeyword::EXISTS: {
1616
            if (!e)
1617
                return {Status(ErrorCodes::BadValue, "$exists can't be eoo")};
1618
            auto temp = stdx::make_unique<ExistsMatchExpression>();
1619
            auto s = temp->init(name);
1620
            if (!s.isOK())
1621
                return s;
1622
            if (e.trueValue())
1623
                return {std::move(temp)};
1624
            auto temp2 = stdx::make_unique<NotMatchExpression>();
1625
            s = temp2->init(temp.release());
1626
            if (!s.isOK())
1627
                return s;
1628
            return {std::move(temp2)};
1629
        }

BSONElement::trueValue() is another one of those dubious conversion functions in the BSON library, and it looks like any BSONType::String falls through to the default case and is coerced into true:

bson_element.h

719
inline bool BSONElement::trueValue() const {
720
    // NOTE Behavior changes must be replicated in Value::coerceToBool().
721
    switch (type()) {
722
        case NumberLong:
723
            return _numberLong() != 0;
724
        case NumberDouble:
725
            return _numberDouble() != 0;
726
        case NumberDecimal:
727
            return _numberDecimal().isNotEqual(Decimal128(0));
728
        case NumberInt:
729
            return _numberInt() != 0;
730
        case mongo::Bool:
731
            return boolean();
732
        case EOO:
733
        case jstNULL:
734
        case Undefined:
735
            return false;
736
        default:
737
            return true;
738
    }
739
}

We could consider changing this in a future release, but I'd be afraid of changing this in a stable branch like v3.4 in case there are people who rely on this bizarre behavior.

Generated at Thu Feb 08 04:28:22 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.