Skip to content

Commit eb3014c

Browse files
committed
CBL-6285: Explain for predictive query no longer names an index
The main issue is that we need to know the kv table on which the PredictiveNode is created, and the pass that SourceNodes are assigned table names is run after the pass all nodes are created. Several technical changes. - SourceNode::collection() is empty string only if it's not given in the query expression. (Currently it will be turned to empty string if explicitly given "_default." - We assign the table name to the main data source in the pass of node creation, so that it can be used when PredictiveNode is populated. It can be later altered if flag _usesDeleted is set. - The result of keystore.compileQuery() should be the same, except that empty data source in the FROM clause will be substituted for with collection corresponding to the invoking key store.
1 parent c3ecb46 commit eb3014c

File tree

6 files changed

+26
-9
lines changed

6 files changed

+26
-9
lines changed

LiteCore/Query/Translator/IndexedNodes.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ namespace litecore::qt {
225225
expr.append(args[1]);
226226
string id = expressionIdentifier(expr);
227227

228-
if ( ctx.delegate.hasPredictiveIndex(id) ) {
228+
if ( ctx.delegate.hasPredictiveIndex(id, ctx) ) {
229229
return new (ctx) PredictionNode(args, ctx, id);
230230
} else {
231231
return FunctionNode::parse(kPredictionFnName, args, ctx);

LiteCore/Query/Translator/Node.hh

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace litecore::qt {
2929
class SelectNode;
3030
class SourceNode;
3131
class SQLWriter;
32+
struct ParseContext;
3233
template <class T>
3334
class List;
3435

@@ -74,8 +75,10 @@ namespace litecore::qt {
7475

7576
struct ParseDelegate {
7677
#ifdef COUCHBASE_ENTERPRISE
77-
std::function<bool(string_view id)> hasPredictiveIndex;
78+
std::function<bool(string_view id, ParseContext& ctx)> hasPredictiveIndex;
7879
#endif
80+
std::function<void(SourceNode*, ParseContext&)> assignTableNameToMainSource;
81+
std::function<string_view()> translatorDefaultCollection;
7982
};
8083

8184
/** State used during parsing, passed down through the recursive descent. */

LiteCore/Query/Translator/QueryTranslator.cc

+9-2
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,18 @@ namespace litecore {
3939
RootContext QueryTranslator::makeRootContext() const {
4040
RootContext root;
4141
#ifdef COUCHBASE_ENTERPRISE
42-
root.hasPredictiveIndex = [&](string_view id) -> bool {
43-
string indexTable = _delegate.predictiveTableName(_defaultTableName, string(id));
42+
root.hasPredictiveIndex = [&](string_view id, ParseContext& ctx) -> bool {
43+
string tableName = ctx.from ? string(ctx.from->tableName()) : _defaultTableName;
44+
string indexTable = _delegate.predictiveTableName(tableName, string(id));
4445
return _delegate.tableExists(indexTable);
4546
};
4647
#endif
48+
QueryTranslator* mutableThis = const_cast<QueryTranslator*>(this);
49+
root.assignTableNameToMainSource = [mutableThis](SourceNode* source, ParseContext& ctx) -> void {
50+
Assert(source->isCollection());
51+
mutableThis->assignTableNameToSource(source, ctx);
52+
};
53+
root.translatorDefaultCollection = [&]() -> string_view { return _defaultCollectionName; };
4754
return root;
4855
}
4956

LiteCore/Query/Translator/SelectNodes.cc

+6-3
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ namespace litecore::qt {
129129
bool explicitCollection = false;
130130
if ( slice collection = optionalString(getCaseInsensitive(dict, "COLLECTION"), "COLLECTION") ) {
131131
explicitCollection = true;
132-
if ( collection == "_" || collection == kDefaultCollectionName ) {
133-
_collection = "";
132+
if ( collection == "_" ) {
133+
_collection = kDefaultCollectionName;
134134
_columnName = collection;
135135
} else {
136136
_collection = collection;
@@ -432,7 +432,9 @@ namespace litecore::qt {
432432
addIndexes(ctx);
433433

434434
for ( SourceNode* source : _sources ) {
435-
if ( !source->_usesDeleted && source->_collection.empty() && source->isCollection() ) {
435+
string_view coll{source->collection()};
436+
if ( coll.empty() ) coll = ctx.delegate.translatorDefaultCollection();
437+
if ( !source->_usesDeleted && coll == "_default" && source->isCollection() ) {
436438
// The default collection may contain deleted documents in its main table,
437439
// so if the query didn't ask for deleted docs, add a condition to the WHERE
438440
// or ON clause that only passes live docs:
@@ -481,6 +483,7 @@ namespace litecore::qt {
481483
isFrom = true;
482484
require(_sources.empty(), "multiple non-join FROM items");
483485
ctx.from = source;
486+
ctx.delegate.assignTableNameToMainSource(source, ctx);
484487
}
485488
ctx.sources.emplace_back(source);
486489
}

LiteCore/Query/Translator/SelectNodes.hh

+4-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ namespace litecore::qt {
113113
void disambiguateColumnName(ParseContext&);
114114
void writeASandON(SQLWriter& ctx) const;
115115

116-
void setUsesDeleted() { _usesDeleted = true; }
116+
void setUsesDeleted() {
117+
_usesDeleted = true; // It will turn kv_.xyz to all_.xyz
118+
_tableName = string_view{};
119+
}
117120

118121
private:
119122
string_view _scope; // Scope name, or empty for default

LiteCore/tests/PredictiveQueryTest.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,11 @@ N_WAY_TEST_CASE_METHOD(QueryTest, "Predictive Query compound indexed", "[Query][
206206
// Query numbers in descending order of square-ness:
207207
std::stringstream sstr;
208208
sstr << "{'WHAT': [['.num'], " << square << "],"
209+
<< " 'FROM': [{'COLLECTION': '" + collectionName + "'}],"
209210
<< " 'WHERE': ['AND', ['>=', " << square + ", 1], ['>=', " << even << ", 1]],"
210211
<< " 'ORDER_BY': [['DESC', ['.num']]] }";
211212

212-
Retained<Query> query{store->compileQuery(json5(sstr.str()))};
213+
Retained<Query> query{db->compileQuery(json5(sstr.str()))};
213214
string explanation = query->explain();
214215
Log("Explanation: %s", explanation.c_str());
215216

0 commit comments

Comments
 (0)