diff options
author | Nikita Lapkov <nikita.lapkov@mongodb.com> | 2021-02-25 12:13:12 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-03-01 19:25:51 +0000 |
commit | f7d172d0decc6128b6ce497357bbf0ff0e676355 (patch) | |
tree | 018d07884f5a7e876d84aedab69b6270183f2197 /src/mongo/db | |
parent | 4b95014f05755a197d81f97879a24c9a6e5c535d (diff) | |
download | mongo-f7d172d0decc6128b6ce497357bbf0ff0e676355.tar.gz |
SERVER-54493 Support BSONType::RegEx values in $regex match expression in SBE
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/exec/sbe/values/value.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/values/value.h | 2 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/vm/vm.h | 5 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_filter.cpp | 26 |
4 files changed, 43 insertions, 12 deletions
diff --git a/src/mongo/db/exec/sbe/values/value.cpp b/src/mongo/db/exec/sbe/values/value.cpp index 52f49ede825..11fdac4f871 100644 --- a/src/mongo/db/exec/sbe/values/value.cpp +++ b/src/mongo/db/exec/sbe/values/value.cpp @@ -45,9 +45,25 @@ namespace sbe { namespace value { std::pair<TypeTags, Value> makeCopyBsonRegex(const BsonRegex& regex) { - auto buffer = new char[regex.byteSize()]; - memcpy(buffer, regex.data(), regex.byteSize()); - return {TypeTags::bsonRegex, bitcastFrom<char*>(buffer)}; + auto buffer = std::make_unique<char[]>(regex.byteSize()); + memcpy(buffer.get(), regex.data(), regex.byteSize()); + return {TypeTags::bsonRegex, bitcastFrom<char*>(buffer.release())}; +} + +std::pair<TypeTags, Value> makeNewBsonRegex(std::string_view pattern, std::string_view flags) { + // Add 2 to account NULL bytes after pattern and flags. + auto totalSize = pattern.size() + flags.size() + 2; + auto buffer = std::make_unique<char[]>(totalSize); + auto rawBuffer = buffer.get(); + + // Copy pattern first and flags after it. + memcpy(rawBuffer, pattern.data(), pattern.size()); + memcpy(rawBuffer + pattern.size() + 1, flags.data(), flags.size()); + + // Ensure NULL byte is placed after each part. + rawBuffer[pattern.size()] = '\0'; + rawBuffer[totalSize - 1] = '\0'; + return {TypeTags::bsonRegex, bitcastFrom<char*>(buffer.release())}; } std::pair<TypeTags, Value> makeCopyBsonJavascript(std::string_view code) { diff --git a/src/mongo/db/exec/sbe/values/value.h b/src/mongo/db/exec/sbe/values/value.h index 86f1ebef155..d24fe5b2bae 100644 --- a/src/mongo/db/exec/sbe/values/value.h +++ b/src/mongo/db/exec/sbe/values/value.h @@ -947,6 +947,8 @@ inline BsonRegex getBsonRegexView(Value val) noexcept { std::pair<TypeTags, Value> makeCopyBsonRegex(const BsonRegex& regex); +std::pair<TypeTags, Value> makeNewBsonRegex(std::string_view pattern, std::string_view flags); + inline std::string_view getBsonJavascriptView(Value val) noexcept { return getStringView(TypeTags::StringBig, val); } diff --git a/src/mongo/db/exec/sbe/vm/vm.h b/src/mongo/db/exec/sbe/vm/vm.h index 5dfe25cc536..7a51732a972 100644 --- a/src/mongo/db/exec/sbe/vm/vm.h +++ b/src/mongo/db/exec/sbe/vm/vm.h @@ -127,6 +127,11 @@ std::pair<value::TypeTags, value::Value> genericCompare( auto threeWayResult = memcmp(lhsObjId, rhsObjId, sizeof(value::ObjectIdType)); auto booleanResult = op(threeWayResult, 0); return {value::TypeTags::Boolean, value::bitcastFrom<bool>(booleanResult)}; + } else if (lhsTag == value::TypeTags::bsonRegex && rhsTag == value::TypeTags::bsonRegex) { + auto lhsRegex = value::getBsonRegexView(lhsValue); + auto rhsRegex = value::getBsonRegexView(rhsValue); + auto result = op(lhsRegex.dataView(), rhsRegex.dataView()); + return {value::TypeTags::Boolean, value::bitcastFrom<bool>(result)}; } return {value::TypeTags::Nothing, 0}; diff --git a/src/mongo/db/query/sbe_stage_builder_filter.cpp b/src/mongo/db/query/sbe_stage_builder_filter.cpp index 8f5d9b36b55..6b44d54063b 100644 --- a/src/mongo/db/query/sbe_stage_builder_filter.cpp +++ b/src/mongo/db/query/sbe_stage_builder_filter.cpp @@ -1541,16 +1541,24 @@ public: void visit(const RegexMatchExpression* expr) final { auto makePredicate = [expr](sbe::value::SlotId inputSlot, EvalStage inputStage) -> EvalExprStagePair { - auto [regexTag, regexVal] = + auto [bsonRegexTag, bsonRegexVal] = + sbe::value::makeNewBsonRegex(expr->getString(), expr->getFlags()); + auto [compiledRegexTag, compiledRegexVal] = sbe::value::makeNewPcreRegex(expr->getString(), expr->getFlags()); - // TODO: In the future, this needs to account for the fact that the regex match - // expression matches strings, but also matches stored regexes. For example, - // {$match: {a: /foo/}} matches the document {a: /foo/} in addition to {a: "foobar"}. - return {makeFillEmptyFalse(sbe::makeE<sbe::EFunction>( - "regexMatch", - sbe::makeEs(sbe::makeE<sbe::EConstant>(regexTag, regexVal), - sbe::makeE<sbe::EVariable>(inputSlot)))), - std::move(inputStage)}; + // TODO SERVER-54837: Support BSONType::Symbol once it is added to SBE. + sbe::EVariable inputVar{inputSlot}; + auto resultExpr = makeBinaryOp( + sbe::EPrimBinary::logicOr, + makeFillEmptyFalse( + makeBinaryOp(sbe::EPrimBinary::eq, + inputVar.clone(), + sbe::makeE<sbe::EConstant>(bsonRegexTag, bsonRegexVal))), + makeFillEmptyFalse( + makeFunction("regexMatch", + sbe::makeE<sbe::EConstant>(compiledRegexTag, compiledRegexVal), + inputVar.clone()))); + + return {std::move(resultExpr), std::move(inputStage)}; }; generatePredicate(_context, expr->fieldRef(), std::move(makePredicate)); |