summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavis Haupt <davis.haupt@mongodb.com>2022-06-08 14:41:38 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-07-12 15:02:22 +0000
commit131c84d87f754210993c334b4825c69f042ee776 (patch)
treeeff3bf5babcb51d22ce88168c7e13db75e258b48 /src
parentabc54d1f92d8ee138856c6c1a6ee0ad0d0c280a1 (diff)
downloadmongo-131c84d87f754210993c334b4825c69f042ee776.tar.gz
SERVER-67628 create $encryptedBetween MatchExpression
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/cqf/cqf_command_utils.cpp4
-rw-r--r--src/mongo/db/matcher/doc_validation_error.cpp6
-rw-r--r--src/mongo/db/matcher/expression.h2
-rw-r--r--src/mongo/db/matcher/expression_algo.cpp1
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp15
-rw-r--r--src/mongo/db/matcher/expression_leaf.h65
-rw-r--r--src/mongo/db/matcher/expression_leaf_test.cpp63
-rw-r--r--src/mongo/db/matcher/expression_parameterization.h1
-rw-r--r--src/mongo/db/matcher/expression_visitor.h2
-rw-r--r--src/mongo/db/pipeline/abt/match_expression_visitor.cpp4
-rw-r--r--src/mongo/db/query/bind_input_params.cpp2
-rw-r--r--src/mongo/db/query/canonical_query_encoder.cpp3
-rw-r--r--src/mongo/db/query/sbe_stage_builder_filter.cpp5
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;