diff options
author | Arun Banala <arun.banala@mongodb.com> | 2019-03-26 19:58:24 +0000 |
---|---|---|
committer | Arun Banala <arun.banala@mongodb.com> | 2019-04-26 15:19:48 +0100 |
commit | 7e700f6668fcbd5b96d46884364f1a7377945abb (patch) | |
tree | fd8d07efa6037c2ea49a6d295cf19621396e5528 /src/mongo/db/pipeline/expression_test.cpp | |
parent | 28430f0ec94060dbe2f5d3e8c77d77f5570b6de9 (diff) | |
download | mongo-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.cpp | 156 |
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 { |