summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2021-04-22 14:11:31 +0000
committerHenning Baldersheim <balder@yahoo-inc.com>2021-04-22 14:19:17 +0000
commit77d585e79ed10d687ca50db4c731c285e80f833b (patch)
tree16a35a5d666a3eb3dfe7c4f405b2c90189d534f1 /searchlib
parent7bb93176d1c15704f89d69fa6daaaefdb19692c9 (diff)
- Prevent the rewrite that happens with equiv and phrase to handle floating point queries in string fields, from happening in under a same-element node.
- Add raw stackdump from previously failing query.
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/query/streaming_query_test.cpp18
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/query.cpp6
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/querynode.cpp15
3 files changed, 35 insertions, 4 deletions
diff --git a/searchlib/src/tests/query/streaming_query_test.cpp b/searchlib/src/tests/query/streaming_query_test.cpp
index 5ce34cfcc3f..21d55b485c0 100644
--- a/searchlib/src/tests/query/streaming_query_test.cpp
+++ b/searchlib/src/tests/query/streaming_query_test.cpp
@@ -708,6 +708,24 @@ TEST("require that we do not break the stack on bad query") {
EXPECT_FALSE(term.isValid());
}
+TEST("a unhandled sameElement stack") {
+ const char * stack = "\022\002\026xyz_abcdefghij_xyzxyzxQ\001\vxxxxxx_name\034xxxxxx_xxxx_xxxxxxx_xxxxxxxxE\002\005delta\b<0.00393";
+ vespalib::stringref stackDump(stack);
+ EXPECT_EQUAL(85u, stackDump.size());
+ AllowRewrite empty;
+ const Query q(empty, stackDump);
+ EXPECT_TRUE(q.valid());
+ const QueryNode & root = q.getRoot();
+ auto sameElement = dynamic_cast<const SameElementQueryNode *>(&root);
+ EXPECT_TRUE(sameElement != nullptr);
+ EXPECT_EQUAL(2u, sameElement->size());
+ EXPECT_EQUAL("xyz_abcdefghij_xyzxyzx", sameElement->getIndex());
+ auto term0 = dynamic_cast<const QueryTerm *>((*sameElement)[0].get());
+ EXPECT_TRUE(term0 != nullptr);
+ auto term1 = dynamic_cast<const QueryTerm *>((*sameElement)[1].get());
+ EXPECT_TRUE(term1 != nullptr);
+}
+
namespace {
void verifyQueryTermNode(const vespalib::string & index, const QueryNode *node) {
EXPECT_TRUE(dynamic_cast<const QueryTerm *>(node) != nullptr);
diff --git a/searchlib/src/vespa/searchlib/query/streaming/query.cpp b/searchlib/src/vespa/searchlib/query/streaming/query.cpp
index bec1bdfc8ae..c6b5ba45d9a 100644
--- a/searchlib/src/vespa/searchlib/query/streaming/query.cpp
+++ b/searchlib/src/vespa/searchlib/query/streaming/query.cpp
@@ -2,6 +2,7 @@
#include "query.h"
#include <vespa/searchlib/parsequery/stackdumpiterator.h>
#include <vespa/vespalib/objects/visit.hpp>
+#include <cassert>
namespace search::streaming {
@@ -155,6 +156,11 @@ bool SameElementQueryNode::evaluate() const {
const HitList &
SameElementQueryNode::evaluateHits(HitList & hl) const
{
+ // TODO This should have been done in a different way, but there are currently no way for that.
+ // Sanity check should be cheap enough that it does not matter.
+ for (const auto & child : *this) {
+ assert(dynamic_cast<const QueryTerm *>(child.get()) != nullptr);
+ }
hl.clear();
if ( !AndQueryNode::evaluate()) return hl;
diff --git a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp
index cabc9b6dae4..906e2bf4a34 100644
--- a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp
+++ b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp
@@ -10,8 +10,10 @@ namespace search::streaming {
namespace {
vespalib::stringref DEFAULT("default");
- bool isPhraseOrNear(const QueryNode * qn) {
- return dynamic_cast<const NearQueryNode *> (qn) || dynamic_cast<const PhraseQueryNode *> (qn);
+ bool disableRewrite(const QueryNode * qn) {
+ return dynamic_cast<const NearQueryNode *> (qn) ||
+ dynamic_cast<const PhraseQueryNode *> (qn) ||
+ dynamic_cast<const SameElementQueryNode *>(qn);
}
}
@@ -56,7 +58,7 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor
if (qc->isFlattenable(queryRep.getType())) {
arity += queryRep.getArity();
} else {
- UP child = Build(qc, factory, queryRep, allowRewrite && !isPhraseOrNear(qn.get()));
+ UP child = Build(qc, factory, queryRep, allowRewrite && !disableRewrite(qn.get()));
qc->push_back(std::move(child));
}
}
@@ -128,7 +130,12 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor
auto qt = std::make_unique<QueryTerm>(factory.create(), ssTerm, ssIndex, sTerm);
qt->setWeight(queryRep.GetWeight());
qt->setUniqueId(queryRep.getUniqueId());
- if ( qt->encoding().isBase10Integer() || ! qt->encoding().isFloat() || ! factory.getRewriteFloatTerms() || !allowRewrite || (ssTerm.find('.') == vespalib::string::npos)) {
+ if (qt->encoding().isBase10Integer() ||
+ ! qt->encoding().isFloat() ||
+ ! factory.getRewriteFloatTerms() ||
+ ! allowRewrite ||
+ (ssTerm.find('.') == vespalib::string::npos))
+ {
qn = std::move(qt);
} else {
auto phrase = std::make_unique<PhraseQueryNode>();