diff options
author | Davis Haupt <davis.haupt@mongodb.com> | 2022-06-08 14:41:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-07-12 15:02:22 +0000 |
commit | 131c84d87f754210993c334b4825c69f042ee776 (patch) | |
tree | eff3bf5babcb51d22ce88168c7e13db75e258b48 /src | |
parent | abc54d1f92d8ee138856c6c1a6ee0ad0d0c280a1 (diff) | |
download | mongo-131c84d87f754210993c334b4825c69f042ee776.tar.gz |
SERVER-67628 create $encryptedBetween MatchExpression
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/commands/cqf/cqf_command_utils.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/matcher/doc_validation_error.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression.h | 2 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_algo.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.h | 65 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf_test.cpp | 63 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parameterization.h | 1 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_visitor.h | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/abt/match_expression_visitor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/bind_input_params.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query_encoder.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_filter.cpp | 5 |
13 files changed, 173 insertions, 0 deletions
diff --git a/src/mongo/db/commands/cqf/cqf_command_utils.cpp b/src/mongo/db/commands/cqf/cqf_command_utils.cpp index edde9962141..0e56e83ed90 100644 --- a/src/mongo/db/commands/cqf/cqf_command_utils.cpp +++ b/src/mongo/db/commands/cqf/cqf_command_utils.cpp @@ -347,6 +347,10 @@ public: unsupportedExpression(expr); } + void visit(const EncryptedBetweenMatchExpression* expr) override { + unsupportedExpression(expr); + } + private: void unsupportedExpression(const MatchExpression* expr) { _eligible = false; diff --git a/src/mongo/db/matcher/doc_validation_error.cpp b/src/mongo/db/matcher/doc_validation_error.cpp index 721f7b81c8e..84c94bfa0fd 100644 --- a/src/mongo/db/matcher/doc_validation_error.cpp +++ b/src/mongo/db/matcher/doc_validation_error.cpp @@ -1185,6 +1185,8 @@ public: MONGO_UNREACHABLE; } + void visit(const EncryptedBetweenMatchExpression* expr) final {} + private: // Set of utilities responsible for appending various fields to build a descriptive error. void appendOperatorName(const MatchExpression& expr) { @@ -1916,6 +1918,7 @@ public: void visit(const WhereNoOpMatchExpression* expr) final { MONGO_UNREACHABLE; } + void visit(const EncryptedBetweenMatchExpression* expr) final {} private: /** @@ -2229,6 +2232,9 @@ public: void visit(const WhereNoOpMatchExpression* expr) final { MONGO_UNREACHABLE; } + void visit(const EncryptedBetweenMatchExpression* expr) final { + _context->finishCurrentError(expr); + } private: void postVisitTreeOperator(const ListOfMatchExpression* expr, diff --git a/src/mongo/db/matcher/expression.h b/src/mongo/db/matcher/expression.h index 3b38a4d099a..aa3697d8b8c 100644 --- a/src/mongo/db/matcher/expression.h +++ b/src/mongo/db/matcher/expression.h @@ -86,6 +86,7 @@ public: BITS_ALL_CLEAR, BITS_ANY_SET, BITS_ANY_CLEAR, + ENCRYPTED_BETWEEN, // Negations. NOT, @@ -139,6 +140,7 @@ public: INTERNAL_SCHEMA_TYPE, INTERNAL_SCHEMA_UNIQUE_ITEMS, INTERNAL_SCHEMA_XOR, + }; /** diff --git a/src/mongo/db/matcher/expression_algo.cpp b/src/mongo/db/matcher/expression_algo.cpp index a28d02bf27b..3d08b62e037 100644 --- a/src/mongo/db/matcher/expression_algo.cpp +++ b/src/mongo/db/matcher/expression_algo.cpp @@ -606,6 +606,7 @@ std::unique_ptr<MatchExpression> splitMatchExpressionForColumns( case MatchExpression::ALWAYS_TRUE: case MatchExpression::ELEM_MATCH_OBJECT: case MatchExpression::ELEM_MATCH_VALUE: // This one should be feasible. May be valuable. + case MatchExpression::ENCRYPTED_BETWEEN: case MatchExpression::EXPRESSION: case MatchExpression::GEO: case MatchExpression::GEO_NEAR: diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index b5a6c0b1d8e..bb63946d66a 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -877,4 +877,19 @@ bool BitTestMatchExpression::equivalent(const MatchExpression* other) const { return path() == realOther->path() && myBitPositions == otherBitPositions; } + +void EncryptedBetweenMatchExpression::debugString(StringBuilder& debug, + int indentationLevel) const { + _debugAddSpace(debug, indentationLevel); + debug << path() << " " << kName; + debug << " " << rhs().toString(false); + + MatchExpression::TagData* td = getTag(); + if (td) { + debug << " "; + td->debugString(&debug); + } + + debug << "\n"; +} } // namespace mongo diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index bd6bc577672..8456e307e70 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -35,6 +35,7 @@ #include "mongo/bson/bsonelement_comparator.h" #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" +#include "mongo/bson/bsontypes.h" #include "mongo/db/exec/document_value/value.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_path.h" @@ -1053,4 +1054,68 @@ public: } }; +/** + * MatchExpression that represents a filter for a range of values. Similar semantics to the BETWEEN + * SQL operator. Used for encoding a range query against an encrypted field. + */ +class EncryptedBetweenMatchExpression final : public LeafMatchExpression { +public: + static constexpr StringData kName = "$encryptedBetween"_sd; + + EncryptedBetweenMatchExpression(StringData path, + BSONElement rhs, + clonable_ptr<ErrorAnnotation> annotation = nullptr) + : LeafMatchExpression(ENCRYPTED_BETWEEN, path, annotation) { + _backingBSON = BSON("" << rhs); + } + + + BSONElement rhs() const { + return _backingBSON.firstElement(); + } + + bool matchesSingleElement(const BSONElement& e, MatchDetails* details = nullptr) const final { + // TODO: SERVER-67627 Implement runtime tag generation for $encryptedBetween. + uasserted(6762800, "Not implemented"); + } + + BSONObj getSerializedRightHandSide() const final { + return BSON(kName << _backingBSON.firstElement()); + } + + std::unique_ptr<MatchExpression> shallowClone() const final { + std::unique_ptr<EncryptedBetweenMatchExpression> e = + std::make_unique<EncryptedBetweenMatchExpression>(path(), rhs(), _errorAnnotation); + if (getTag()) { + e->setTag(getTag()->clone()); + } + return e; + } + + virtual bool equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) { + return false; + } + auto otherCast = static_cast<const EncryptedBetweenMatchExpression*>(other); + return path() == otherCast->path() && rhs().binaryEqual(otherCast->rhs()); + }; + + void debugString(StringBuilder& debug, int indentationLevel) const; + + void acceptVisitor(MatchExpressionMutableVisitor* visitor) final { + visitor->visit(this); + } + + void acceptVisitor(MatchExpressionConstVisitor* visitor) const final { + visitor->visit(this); + } + +private: + BSONObj _backingBSON; + + ExpressionOptimizerFunc getOptimizer() const final { + return [](std::unique_ptr<MatchExpression> expression) { return expression; }; + } +}; + } // namespace mongo diff --git a/src/mongo/db/matcher/expression_leaf_test.cpp b/src/mongo/db/matcher/expression_leaf_test.cpp index 450e71d0367..0ca10c0475a 100644 --- a/src/mongo/db/matcher/expression_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_leaf_test.cpp @@ -29,15 +29,22 @@ /** Unit tests for MatchMatchExpression operator implementations in match_operators.{h,cpp}. */ +#include <memory> + #include "mongo/unittest/unittest.h" +#include "mongo/bson/bsonmisc.h" +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/expression_tree.h" +#include "mongo/db/matcher/expression_visitor.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/death_test.h" +#include "mongo/util/assert_util.h" namespace mongo { @@ -2260,4 +2267,60 @@ DEATH_TEST_REGEX(ComparisonMatchExpression, ASSERT_THROWS_CODE(eq.getChild(0), AssertionException, 6400209); } +TEST(EncryptedBetweenMatchExpression, EqualWithoutCollator) { + BSONObj operand = BSON("a" << 5); + EncryptedBetweenMatchExpression eb1("a", operand["a"]); + EncryptedBetweenMatchExpression eb2("a", operand["a"]); + ASSERT(eb1.equivalent(&eb2)); +} + + +TEST(EncryptedBetweenMatchExpression, UnequalWithoutCollator) { + BSONObj operand = BSON("a" << 5 << "b" << 10); + EncryptedBetweenMatchExpression eb1("a", operand["a"]); + EncryptedBetweenMatchExpression eb2("a", operand["b"]); + ASSERT_FALSE(eb1.equivalent(&eb2)); +} + + +TEST(EncryptedBetweenMatchExpression, UnequalDueToPath) { + BSONObj operand = BSON("a" << 5 << "b" << 10); + EncryptedBetweenMatchExpression eb1("a", operand["a"]); + EncryptedBetweenMatchExpression eb2("b", operand["a"]); + ASSERT_FALSE(eb1.equivalent(&eb2)); +} + +TEST(EncryptedBetweenMatchExpression, UnequalDueToRhs) { + BSONObj operand = BSON("a" << 5 << "b" << 10); + EncryptedBetweenMatchExpression eb1("a", operand["a"]); + EncryptedBetweenMatchExpression eb2("a", operand["b"]); + ASSERT_FALSE(eb1.equivalent(&eb2)); +} + +TEST(EncryptedBetweenMatchExpression, CanSerializeToBSON) { + auto op = BSON("$encryptedBetween" << BSON_ARRAY(1 << 5)); + EncryptedBetweenMatchExpression eb("a", op.firstElement()); + BSONObjBuilder bob; + eb.serialize(&bob, true); + ASSERT_BSONOBJ_EQ(bob.obj(), BSON("a" << op)); +} + +TEST(EncryptedBetweenMatchExpression, CanSerializeToBSONInsideAnd) { + auto op = BSON("$encryptedBetween" << BSON_ARRAY(1 << 5)); + auto eb = std::make_unique<EncryptedBetweenMatchExpression>("a", op.firstElement()); + auto v = std::vector<std::unique_ptr<MatchExpression>>(); + v.push_back(std::move(eb)); + AndMatchExpression nd(std::move(v)); + BSONObjBuilder bob; + nd.serialize(&bob, true); + ASSERT_BSONOBJ_EQ(bob.obj(), BSON("$and" << BSON_ARRAY(BSON("a" << op)))); +} + +TEST(EncryptedBetweenMatchExpression, ErrorsOnEvaluation) { + auto op = BSON("$encryptedBetween" << BSON_ARRAY(1 << 5)); + auto obj = BSON("$encryptedBetween" << 2); + EncryptedBetweenMatchExpression eb("", op.firstElement()); + ASSERT_THROWS_CODE(eb.matchesSingleElement(obj.firstElement()), AssertionException, 6762800); +} + } // namespace mongo diff --git a/src/mongo/db/matcher/expression_parameterization.h b/src/mongo/db/matcher/expression_parameterization.h index 57816d5de30..144a7c21b7d 100644 --- a/src/mongo/db/matcher/expression_parameterization.h +++ b/src/mongo/db/matcher/expression_parameterization.h @@ -90,6 +90,7 @@ public: void visit(BitsAllSetMatchExpression* expr) final; void visit(BitsAnyClearMatchExpression* expr) final; void visit(BitsAnySetMatchExpression* expr) final; + void visit(EncryptedBetweenMatchExpression* expr) final {} void visit(ElemMatchObjectMatchExpression* matchExpr) final {} void visit(ElemMatchValueMatchExpression* matchExpr) final {} void visit(EqualityMatchExpression* expr) final; diff --git a/src/mongo/db/matcher/expression_visitor.h b/src/mongo/db/matcher/expression_visitor.h index f31e604f518..5ea4d6dd531 100644 --- a/src/mongo/db/matcher/expression_visitor.h +++ b/src/mongo/db/matcher/expression_visitor.h @@ -55,6 +55,7 @@ class InternalExprGTMatchExpression; class InternalExprGTEMatchExpression; class InternalExprLTMatchExpression; class InternalExprLTEMatchExpression; +class EncryptedBetweenMatchExpression; class InternalSchemaAllElemMatchFromIndexMatchExpression; class InternalSchemaAllowedPropertiesMatchExpression; class InternalSchemaBinDataEncryptedTypeExpression; @@ -162,6 +163,7 @@ public: virtual void visit(MaybeConstPtr<TypeMatchExpression> expr) = 0; virtual void visit(MaybeConstPtr<WhereMatchExpression> expr) = 0; virtual void visit(MaybeConstPtr<WhereNoOpMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<EncryptedBetweenMatchExpression> expr) = 0; }; using MatchExpressionMutableVisitor = MatchExpressionVisitor<false>; diff --git a/src/mongo/db/pipeline/abt/match_expression_visitor.cpp b/src/mongo/db/pipeline/abt/match_expression_visitor.cpp index 833e46fbbc0..1bd53a7f1d7 100644 --- a/src/mongo/db/pipeline/abt/match_expression_visitor.cpp +++ b/src/mongo/db/pipeline/abt/match_expression_visitor.cpp @@ -406,6 +406,10 @@ public: unsupportedExpression(expr); } + void visit(const EncryptedBetweenMatchExpression* expr) override { + unsupportedExpression(expr); + } + private: void generateBoolConstant(const bool value) { _ctx.push<PathConstant>(Constant::boolean(value)); diff --git a/src/mongo/db/query/bind_input_params.cpp b/src/mongo/db/query/bind_input_params.cpp index d96aa4294bf..5efce4c8aab 100644 --- a/src/mongo/db/query/bind_input_params.cpp +++ b/src/mongo/db/query/bind_input_params.cpp @@ -32,6 +32,7 @@ #include "mongo/db/exec/sbe/values/bson.h" #include "mongo/db/exec/sbe/values/value.h" #include "mongo/db/matcher/expression_array.h" +#include "mongo/db/matcher/expression_visitor.h" #include "mongo/db/matcher/expression_where.h" #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/sbe_stage_builder_filter.h" @@ -242,6 +243,7 @@ public: void visit(const TextNoOpMatchExpression* expr) final {} void visit(const TwoDPtInAnnulusExpression* expr) final {} void visit(const WhereNoOpMatchExpression* expr) final {} + void visit(const EncryptedBetweenMatchExpression* expr) final {} private: void visitComparisonMatchExpression(const ComparisonMatchExpressionBase* expr) { diff --git a/src/mongo/db/query/canonical_query_encoder.cpp b/src/mongo/db/query/canonical_query_encoder.cpp index 52c0b10a916..c24be53a1b8 100644 --- a/src/mongo/db/query/canonical_query_encoder.cpp +++ b/src/mongo/db/query/canonical_query_encoder.cpp @@ -934,6 +934,9 @@ public: void visit(const TwoDPtInAnnulusExpression* expr) final { MONGO_UNREACHABLE_TASSERT(6142133); } + void visit(const EncryptedBetweenMatchExpression* expr) final { + MONGO_UNREACHABLE_TASSERT(6762801); + } private: /** diff --git a/src/mongo/db/query/sbe_stage_builder_filter.cpp b/src/mongo/db/query/sbe_stage_builder_filter.cpp index 5005ddef8a5..50a58292484 100644 --- a/src/mongo/db/query/sbe_stage_builder_filter.cpp +++ b/src/mongo/db/query/sbe_stage_builder_filter.cpp @@ -1218,6 +1218,9 @@ public: void visit(const WhereNoOpMatchExpression* expr) final { unsupportedExpression(expr); } + void visit(const EncryptedBetweenMatchExpression* expr) final { + unsupportedExpression(expr); + } private: void unsupportedExpression(const MatchExpression* expr) const { @@ -1928,6 +1931,7 @@ public: } void visit(const WhereNoOpMatchExpression* expr) final {} + void visit(const EncryptedBetweenMatchExpression* expr) final {} private: MatchExpressionVisitorContext* _context; @@ -2041,6 +2045,7 @@ public: void visit(const TypeMatchExpression* expr) final {} void visit(const WhereMatchExpression* expr) final {} void visit(const WhereNoOpMatchExpression* expr) final {} + void visit(const EncryptedBetweenMatchExpression* expr) final {} private: MatchExpressionVisitorContext* _context; |