summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/expression_test.cpp
diff options
context:
space:
mode:
authorArun Banala <arun.banala@mongodb.com>2019-03-26 19:58:24 +0000
committerArun Banala <arun.banala@mongodb.com>2019-04-26 15:19:48 +0100
commit7e700f6668fcbd5b96d46884364f1a7377945abb (patch)
treefd8d07efa6037c2ea49a6d295cf19621396e5528 /src/mongo/db/pipeline/expression_test.cpp
parent28430f0ec94060dbe2f5d3e8c77d77f5570b6de9 (diff)
downloadmongo-7e700f6668fcbd5b96d46884364f1a7377945abb.tar.gz
SERVER-40083 Don't recompile each time $regex is evaluated when regex argument is a constant
Diffstat (limited to 'src/mongo/db/pipeline/expression_test.cpp')
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp156
1 files changed, 93 insertions, 63 deletions
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index 5028d870e24..c1ba68f4cd2 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -5956,24 +5956,93 @@ TEST(GetComputedPathsTest, ExpressionMapNotConsideredRenameWithDottedInputPath)
namespace ExpressionRegexTest {
-TEST(ExpressionRegexFindTest, BasicTest) {
- Value input(fromjson("{input: 'asdf', regex: '^as' }"));
- BSONObj expectedOut(fromjson("{match: 'as', idx:0, captures:[]}"));
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexFind regexF(expCtx);
- regexF.addOperand(ExpressionConstant::create(expCtx, input));
- Value output = regexF.evaluate(Document());
- ASSERT_BSONOBJ_EQ(toBson(output.getDocument()), expectedOut);
+class ExpressionRegexTest {
+public:
+ template <typename SubClass, int N>
+ static intrusive_ptr<Expression> generateOptimizedExpression(const BSONObj& input) {
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ auto expression = ExpressionFixedArity<SubClass, N>::parse(
+ expCtx, input.firstElement(), expCtx->variablesParseState);
+ return expression->optimize();
+ }
+
+ static void testAllExpressions(const BSONObj& input,
+ bool optimized,
+ const std::vector<Value>& expectedFindAllOutput) {
+ {
+ // For $regexFindAll.
+ auto expression = generateOptimizedExpression<ExpressionRegexFindAll, 1>(input);
+ auto regexFindAllExpr = dynamic_cast<ExpressionRegexFindAll*>(expression.get());
+ ASSERT_EQ(regexFindAllExpr->hasConstantRegex(), optimized);
+ Value output = regexFindAllExpr->evaluate(Document());
+ ASSERT_VALUE_EQ(output, Value(expectedFindAllOutput));
+ }
+
+ {
+ // For $regexFind.
+ auto expression = generateOptimizedExpression<ExpressionRegexFind, 1>(input);
+ auto regexFindExpr = dynamic_cast<ExpressionRegexFind*>(expression.get());
+ ASSERT_EQ(regexFindExpr->hasConstantRegex(), optimized);
+ Value output = regexFindExpr->evaluate(Document());
+ ASSERT_VALUE_EQ(
+ output, expectedFindAllOutput.empty() ? Value(BSONNULL) : expectedFindAllOutput[0]);
+ }
+
+ {
+ // For $regexMatch.
+ auto expression = generateOptimizedExpression<ExpressionRegexMatch, 1>(input);
+ auto regexMatchExpr = dynamic_cast<ExpressionRegexMatch*>(expression.get());
+ ASSERT_EQ(regexMatchExpr->hasConstantRegex(), optimized);
+ Value output = regexMatchExpr->evaluate(Document());
+ ASSERT_VALUE_EQ(output, expectedFindAllOutput.empty() ? Value(false) : Value(true));
+ }
+ }
+};
+
+TEST(ExpressionRegexTest, BasicTest) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'asdf', regex: '^as' }}"),
+ true,
+ {Value(fromjson("{match: 'as', idx:0, captures:[]}"))});
}
-TEST(ExpressionRegexFindTest, ExtendedRegexOptions) {
- Value input(fromjson("{input: 'FirstLine\\nSecondLine', regex: '^second' , options: 'mi'}"));
- BSONObj expectedOut(fromjson("{match: 'Second', idx:10, captures:[]}"));
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexFind regexF(expCtx);
- regexF.addOperand(ExpressionConstant::create(expCtx, input));
- Value output = regexF.evaluate(Document());
- ASSERT_BSONOBJ_EQ(toBson(output.getDocument()), expectedOut);
+TEST(ExpressionRegexTest, ExtendedRegexOptions) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'FirstLine\\nSecondLine', regex: "
+ "'^second' , options: 'mi'}}"),
+ true,
+ {Value(fromjson("{match: 'Second', idx:10, captures:[]}"))});
+}
+
+TEST(ExpressionRegexTest, MultipleMatches) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'a1b2c3', regex: '([a-c][1-3])' }}"),
+ true,
+ {Value(fromjson("{match: 'a1', idx:0, captures:['a1']}")),
+ Value(fromjson("{match: 'b2', idx:2, captures:['b2']}")),
+ Value(fromjson("{match: 'c3', idx:4, captures:['c3']}"))});
+}
+
+TEST(ExpressionRegexTest, OptimizPatternWhenInputIsVariable) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: '$input', regex: '([a-c][1-3])' }}"), true, {});
+}
+
+TEST(ExpressionRegexTest, NoOptimizePatternWhenRegexVariable) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'asdf', regex: '$regex' }}"), false, {});
+}
+
+TEST(ExpressionRegexTest, NoOptimizePatternWhenOptionsVariable) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'asdf', regex: '(asdf)', options: '$options' }}"),
+ false,
+ {Value(fromjson("{match: 'asdf', idx:0, captures:['asdf']}"))});
+}
+
+TEST(ExpressionRegexTest, NoMatch) {
+ ExpressionRegexTest::testAllExpressions(
+ fromjson("{$regexFindAll : {input: 'a1b2c3', regex: 'ab' }}"), true, {});
}
TEST(ExpressionRegexFindTest, FailureCase) {
@@ -5985,27 +6054,6 @@ TEST(ExpressionRegexFindTest, FailureCase) {
ASSERT_THROWS_CODE(regexF.evaluate(Document()), DBException, 51105);
}
-TEST(ExpressionRegexFindAllTest, MultipleMatches) {
- Value input(fromjson("{input: 'a1b2c3', regex: '([a-c][1-3])' }"));
- std::vector<Value> expectedOut = {Value(fromjson("{match: 'a1', idx:0, captures:['a1']}")),
- Value(fromjson("{match: 'b2', idx:2, captures:['b2']}")),
- Value(fromjson("{match: 'c3', idx:4, captures:['c3']}"))};
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexFindAll regexF(expCtx);
- regexF.addOperand(ExpressionConstant::create(expCtx, input));
- Value output = regexF.evaluate(Document());
- ASSERT_VALUE_EQ(output, Value(expectedOut));
-}
-
-TEST(ExpressionRegexFindAllTest, NoMatch) {
- Value input(fromjson("{input: 'a1b2c3', regex: 'ab' }"));
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexFindAll regexF(expCtx);
- regexF.addOperand(ExpressionConstant::create(expCtx, input));
- Value output = regexF.evaluate(Document());
- ASSERT_VALUE_EQ(output, Value(std::vector<Value>()));
-}
-
TEST(ExpressionRegexFindAllTest, FailureCase) {
Value input(fromjson("{input: 'FirstLine\\nSecondLine', regex: '[0-9'}"));
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
@@ -6014,6 +6062,14 @@ TEST(ExpressionRegexFindAllTest, FailureCase) {
ASSERT_THROWS_CODE(regexF.evaluate(Document()), DBException, 51111);
}
+TEST(ExpressionRegexMatchTest, FailureCase) {
+ Value input(fromjson("{regex: 'valid', input: {invalid : 'input'} , options: 'mi'}"));
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ ExpressionRegexMatch regexMatchExpr(expCtx);
+ regexMatchExpr.addOperand(ExpressionConstant::create(expCtx, input));
+ ASSERT_THROWS_CODE(regexMatchExpr.evaluate(Document()), DBException, 51104);
+}
+
TEST(ExpressionRegexFindAllTest, InvalidUTF8InInput) {
std::string inputField = "1234 ";
// Append an invalid UTF-8 character.
@@ -6039,32 +6095,6 @@ TEST(ExpressionRegexFindAllTest, InvalidUTF8InRegex) {
ASSERT_THROWS_CODE(regexF.evaluate(Document()), DBException, 51111);
}
-TEST(ExpressionRegexMatchTest, NoMatch) {
- Value input(fromjson("{input: 'asdf', regex: '^sd' }"));
- Value expectedOut(false);
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexMatch regexMatchExpr(expCtx);
- regexMatchExpr.addOperand(ExpressionConstant::create(expCtx, input));
- ASSERT_VALUE_EQ(regexMatchExpr.evaluate(Document()), expectedOut);
-}
-
-TEST(ExpressionRegexMatchTest, ExtendedRegexOptions) {
- Value input(fromjson("{input: 'FirstLine\\nSecondLine', regex: '^second' , options: 'mi'}"));
- Value expectedOut(true);
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexMatch regexMatchExpr(expCtx);
- regexMatchExpr.addOperand(ExpressionConstant::create(expCtx, input));
- ASSERT_VALUE_EQ(regexMatchExpr.evaluate(Document()), expectedOut);
-}
-
-TEST(ExpressionRegexMatchTest, FailureCase) {
- Value input(fromjson("{regex: 'valid', input: {invalid : 'input'} , options: 'mi'}"));
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- ExpressionRegexMatch regexMatchExpr(expCtx);
- regexMatchExpr.addOperand(ExpressionConstant::create(expCtx, input));
- ASSERT_THROWS_CODE(regexMatchExpr.evaluate(Document()), DBException, 51104);
-}
-
} // namespace ExpressionRegexTest
class All : public Suite {