Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CBL-6400: Port the changes to QueryParser in 3.2 branch (to support U… #2186

Merged
merged 3 commits into from
Nov 22, 2024

Conversation

jianminzhao
Copy link
Contributor

…NNEST) to 4.0 (master branch)

@cbl-bot
Copy link

cbl-bot commented Nov 15, 2024

Code Coverage Results:

Type Percentage
branches 66.33
functions 78.53
instantiations 70.71
lines 77.66
regions 73.51

Copy link
Collaborator

@snej snej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed it all yet, but there are some changes to make.

Comment on lines 135 to 144
for ( size_t pos = 0; pos != string::npos && pos < unnestPath.length(); ) {
size_t next = unnestPath.find(KeyStore::kUnnestLevelSeparator, pos);
if ( next == string::npos ) {
splitPaths.push_back(unnestPath.substr(pos));
pos = string::npos;
} else {
splitPaths.push_back(unnestPath.substr(pos, next - pos));
pos = next + KeyStore::kUnnestLevelSeparator.size;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can replace this loop with a call to split from StringUtils.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 149 to 153
string n1qlUnnestPaths = string(splitPaths[0]);
for ( unsigned i = 1; i < splitPaths.size(); ++i ) {
n1qlUnnestPaths += ", ";
n1qlUnnestPaths += splitPaths[i];
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, you're splitting unnestPath with one delimiter, and then joining the pieces with a different delimiter. I think you could do this more simply by just replacing kUnnestLevelSeparator with ", " in unnestPath...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


mutable FLDoc _doc = nullptr;
mutable FLDoc _doc = nullptr;
mutable FLDoc _unnestDoc = nullptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be released in the destructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if ( currSpec ) {
// If there is already index with the index name,
// eiher delete the current one, or use it (return false)
while ( true ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a loop. I guess you used a while so you could exit it with break? That makes the code confusing IMHO; it'd be clearer just to use ifs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to if's

db().deleteIndex(*currSpec);
}

// the following will throw if !spec.arrayOptions() || !spec.arrayOpeionts()->unnestPath
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "arrayOpeionts"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

// the following will throw if !spec.arrayOptions() || !spec.arrayOpeionts()->unnestPath
Array::iterator itPath((const Array*)spec.unnestPaths());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this into the first clause of the for statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

QueryTranslator qp(db(), "", sourceTableName);
qp.writeCreateIndex(spec.name, sourceTableName, (FLArrayIterator&)expressions, spec.where(),
(spec.type != IndexSpec::kValue));
string hexName{spec.type == IndexSpec::kArray ? litecore::hexName(sourceTableName) : ""};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use sourceTableName as the alternate value instead of ""? Then you don't have to have conditionals in the following two lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to use optional.

Collation collation; // Current collation in effect
bool collationApplied = true; // False if no COLLATE node generated
bool hasGroupBy = false; // Current SELECT include GROUP_BY
std::unordered_map<string, string> hashedTables; // hexName(tableName) -> tableName. Used for Unnest tables.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this above the bools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

SourceNode* C4NULLABLE from{}; // The main source
Collation collation; // Current collation in effect
bool collationApplied = true; // False if no COLLATE node generated
bool hasGroupBy = false; // Current SELECT include GROUP_BY
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting the flag here only works for the top-level query. If there's a nested SELECT expression, the flag will be set in the nested context and the QueryTranslator won't see it.
Instead, the node whose SQL generation depends on hasGroupBy should make that an instance variable, and set it when the node is constructed by looking at its parent SELECT statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. good point. Passed hasGroupBy from ctx to the UnnestNode.

@jianminzhao jianminzhao requested a review from snej November 18, 2024 18:09
Comment on lines 92 to 95
std::optional<string> hexName;
if ( spec.type == IndexSpec::kArray ) hexName.emplace(litecore::hexName(sourceTableName));
QueryTranslator qp(db(), "", hexName.value_or(sourceTableName));
qp.writeCreateIndex(spec.name, hexName.value_or(sourceTableName), (FLArrayIterator&)expressions, spec.where(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant was that it can be simplified to this:

Suggested change
std::optional<string> hexName;
if ( spec.type == IndexSpec::kArray ) hexName.emplace(litecore::hexName(sourceTableName));
QueryTranslator qp(db(), "", hexName.value_or(sourceTableName));
qp.writeCreateIndex(spec.name, hexName.value_or(sourceTableName), (FLArrayIterator&)expressions, spec.where(),
string name = ( spec.type == IndexSpec::kArray ) ? hexName(sourceTableName) : sourceTableName;
QueryTranslator qp(db(), "", name);
qp.writeCreateIndex(spec.name, name, (FLArrayIterator&)expressions, spec.where(),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -124,6 +124,8 @@ namespace litecore::qt {

void writeSQL(SQLWriter&, slice sqliteFnName, ExprNode* C4NULLABLE param) const;

void hasGroupBy() { _hasGroupBy = true; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name hasGroupBy is confusing because it sounds like it's an accessor, not a setter.
But this method isn't needed anyway...

Collation collation; // Current collation in effect
std::unordered_map<string, string> hashedTables; // hexName(tableName) -> tableName. Used for Unnest tables.
bool collationApplied = true; // False if no COLLATE node generated
bool hasGroupBy = false; // Current SELECT include GROUP_BY
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasGroupBy isn't needed anymore

@@ -60,6 +61,8 @@ namespace litecore {
} else if ( auto p = dynamic_cast<ParameterNode*>(&node) ) {
// Capture the parameter names:
_parameters.emplace(p->name());
} else if ( auto prop = dynamic_cast<PropertyNode*>(&node) ) {
if ( ctx.hasGroupBy ) prop->hasGroupBy();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this isn't what I meant. The _hasGroupBy flag should be set by the PropertyNode's constructor itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But at the time PropertyNode is constructed, we haven't parsed GROUP_BY. PropertyNode is constructed when source->parseChildExprs(ctx) is executed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SourceNode doesn't have to have parsed GROUP_BY yet, it just needs to check whether it exists. Add a flag SelectNode::_hasGroupBy that's set early in the parse method. PropertyNode can check that flag via an accessor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Done.

std::vector<SourceNode*> sources; // All sources
SourceNode* C4NULLABLE from{}; // The main source
Collation collation; // Current collation in effect
std::unordered_map<string, string> hashedTables; // hexName(tableName) -> tableName. Used for Unnest tables.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing that useshashedTables is one method of QueryTranslator; it doesn't belong here. It should be a member of QueryTranslator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Done

@@ -362,6 +378,7 @@ namespace litecore::qt {
}
addChild(_groupBy, group);
}
ctx.hasGroupBy = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this flag is a good idea. The context already has a reference to the SelectNode, so just add a bool hasGroupBy() accessor to SelectNode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed as suggested

@jianminzhao
Copy link
Contributor Author

The two failed tests with Jenkins check all passed all tests but timed out afterwards (for some technical reason.)

@jianminzhao jianminzhao merged commit c3ecb46 into master Nov 22, 2024
7 of 8 checks passed
@jianminzhao jianminzhao deleted the cbl-6400 branch November 22, 2024 00:05
jianminzhao added a commit that referenced this pull request Nov 22, 2024
- CBL-6400: Port the changes to QueryParser in 3.2 branch (to support UNNEST) (#2186)
- Update the fleece submodule to the tip of its master branch. (#2189)
- CBL-6422: Some tests of VectorSearch are failing in 4.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants