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

Correct handling of Datasets #1845

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 7 additions & 18 deletions src/parser/SparqlParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
using AntlrParser = SparqlAutomaticParser;

// _____________________________________________________________________________
ParsedQuery SparqlParser::parseQuery(std::string query) {
ParsedQuery SparqlParser::parseQuery(
std::string query, const std::vector<DatasetClause>& datasets) {
// The second argument is the `PrefixMap` for QLever's internal IRIs.
using S = std::string;
sparqlParserHelpers::ParserAndVisitor p{
std::move(query),
{{S{QLEVER_INTERNAL_PREFIX_NAME}, S{QLEVER_INTERNAL_PREFIX_IRI}}}};
// Note: `AntlrParser::query` is a method of `AntlrParser` (which is an alias
// for `SparqlAutomaticParser`) that returns the `QueryContext*` for the whole
// query.
{{S{QLEVER_INTERNAL_PREFIX_NAME}, S{QLEVER_INTERNAL_PREFIX_IRI}}},
parsedQuery::DatasetClauses::fromClauses(datasets)};
// Note: `AntlrParser::queryOrUpdate` is a method of `AntlrParser` (which is
// an alias for `SparqlAutomaticParser`) that returns the
// `QueryOrUpdateContext*` for the whole query or update.
auto resultOfParseAndRemainingText =
p.parseTypesafe(&AntlrParser::queryOrUpdate);
// The query rule ends with <EOF> so the parse always has to consume the whole
Expand All @@ -26,16 +28,3 @@ ParsedQuery SparqlParser::parseQuery(std::string query) {
AD_CONTRACT_CHECK(resultOfParseAndRemainingText.remainingText_.empty());
return std::move(resultOfParseAndRemainingText.resultOfParse_);
}

// _____________________________________________________________________________
ParsedQuery SparqlParser::parseQuery(
std::string operation, const std::vector<DatasetClause>& datasets) {
auto parsedOperation = parseQuery(std::move(operation));
// SPARQL Protocol 2.1.4 specifies that the dataset from the query
// parameters overrides the dataset from the query itself.
if (!datasets.empty()) {
parsedOperation.datasetClauses_ =
parsedQuery::DatasetClauses::fromClauses(datasets);
}
return parsedOperation;
}
6 changes: 2 additions & 4 deletions src/parser/SparqlParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
// message is given.
class SparqlParser {
public:
static ParsedQuery parseQuery(std::string query);
// A convenience function for parsing the query and setting the datasets.
static ParsedQuery parseQuery(std::string operation,
const std::vector<DatasetClause>& datasets);
static ParsedQuery parseQuery(
std::string operation, const std::vector<DatasetClause>& datasets = {});
};
8 changes: 5 additions & 3 deletions src/parser/SparqlParserHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ using std::string;

// _____________________________________________________________________________
ParserAndVisitor::ParserAndVisitor(
std::string input,
std::string input, ParsedQuery::DatasetClauses datasetClauses,
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting disableSomeChecks)
: input_{unescapeUnicodeSequences(std::move(input))},
visitor_{{}, disableSomeChecks} {
visitor_{{}, std::move(datasetClauses), disableSomeChecks} {
// The default in ANTLR is to log all errors to the console and to continue
// the parsing. We need to turn parse errors into exceptions instead to
// propagate them to the user.
Expand All @@ -32,8 +32,10 @@ ParserAndVisitor::ParserAndVisitor(
// _____________________________________________________________________________
ParserAndVisitor::ParserAndVisitor(
std::string input, SparqlQleverVisitor::PrefixMap prefixes,
ParsedQuery::DatasetClauses datasetClauses,
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting disableSomeChecks)
: ParserAndVisitor{std::move(input), disableSomeChecks} {
: ParserAndVisitor{std::move(input), std::move(datasetClauses),
disableSomeChecks} {
visitor_.setPrefixMapManually(std::move(prefixes));
}

Expand Down
3 changes: 2 additions & 1 deletion src/parser/SparqlParserHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ struct ParserAndVisitor {
SparqlAutomaticParser parser_{&tokens_};
SparqlQleverVisitor visitor_;
explicit ParserAndVisitor(
string input,
string input, ParsedQuery::DatasetClauses datasetClauses = {},
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting disableSomeChecks =
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting::False);
ParserAndVisitor(
string input, SparqlQleverVisitor::PrefixMap prefixes,
ParsedQuery::DatasetClauses datasetClauses = {},
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting disableSomeChecks =
SparqlQleverVisitor::DisableSomeChecksOnlyForTesting::False);

Expand Down
36 changes: 22 additions & 14 deletions src/parser/sparqlParser/SparqlQleverVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,12 +318,23 @@ parsedQuery::BasicGraphPattern Visitor::toGraphPattern(
return pattern;
}

// ____________________________________________________________________________________
parsedQuery::DatasetClauses SparqlQleverVisitor::setAndGetDatasetClauses(
const std::vector<DatasetClause>& clauses) {
// TODO: is it a good idea to do this implicitly (the fields are nullopt) or
// should this be done explicitly (with a bool flag)?
if (!activeDatasetClauses_.defaultGraphs_.has_value() &&
!activeDatasetClauses_.namedGraphs_.has_value()) {
activeDatasetClauses_ = parsedQuery::DatasetClauses::fromClauses(clauses);
}
return activeDatasetClauses_;
Comment on lines +324 to +330
Copy link
Member Author

Choose a reason for hiding this comment

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

TODO: finish

}

// ____________________________________________________________________________________
ParsedQuery Visitor::visit(Parser::ConstructQueryContext* ctx) {
ParsedQuery query;
query.datasetClauses_ = parsedQuery::DatasetClauses::fromClauses(
visitVector(ctx->datasetClause()));
activeDatasetClauses_ = query.datasetClauses_;
query.datasetClauses_ =
setAndGetDatasetClauses(visitVector(ctx->datasetClause()));
if (ctx->constructTemplate()) {
query._clause = visit(ctx->constructTemplate())
.value_or(parsedQuery::ConstructClause{});
Expand Down Expand Up @@ -367,9 +378,8 @@ ParsedQuery Visitor::visit(Parser::DescribeQueryContext* ctx) {
}

// Parse the FROM and FROM NAMED clauses.
activeDatasetClauses_ = parsedQuery::DatasetClauses::fromClauses(
visitVector(ctx->datasetClause()));
describeClause.datasetClauses_ = activeDatasetClauses_;
describeClause.datasetClauses_ =
setAndGetDatasetClauses(visitVector(ctx->datasetClause()));

// Parse the WHERE clause and construct a SELECT query from it. For `DESCRIBE
// *`, add each visible variable as a resource to describe.
Expand Down Expand Up @@ -414,9 +424,8 @@ ParsedQuery Visitor::visit(Parser::DescribeQueryContext* ctx) {
// ____________________________________________________________________________________
ParsedQuery Visitor::visit(Parser::AskQueryContext* ctx) {
parsedQuery_._clause = ParsedQuery::AskClause{};
parsedQuery_.datasetClauses_ = parsedQuery::DatasetClauses::fromClauses(
visitVector(ctx->datasetClause()));
activeDatasetClauses_ = parsedQuery_.datasetClauses_;
parsedQuery_.datasetClauses_ =
setAndGetDatasetClauses(visitVector(ctx->datasetClause()));
visitWhereClause(ctx->whereClause(), parsedQuery_);
// NOTE: It can make sense to have solution modifiers with an ASK query, for
// example, a GROUP BY with a HAVING.
Expand Down Expand Up @@ -661,9 +670,9 @@ ParsedQuery Visitor::visit(Parser::ModifyContext* ctx) {
}
};
AD_CORRECTNESS_CHECK(visibleVariables_.empty());
auto graphPattern = visit(ctx->groupGraphPattern());
parsedQuery_.datasetClauses_ =
parsedQuery::DatasetClauses::fromClauses(visitVector(ctx->usingClause()));
setAndGetDatasetClauses(visitVector(ctx->usingClause()));
auto graphPattern = visit(ctx->groupGraphPattern());
parsedQuery_._rootGraphPattern = std::move(graphPattern);
parsedQuery_.registerVariablesVisibleInQueryBody(visibleVariables_);
visibleVariables_.clear();
Expand Down Expand Up @@ -1263,9 +1272,8 @@ void Visitor::visit(Parser::PrefixDeclContext* ctx) {
// ____________________________________________________________________________________
ParsedQuery Visitor::visit(Parser::SelectQueryContext* ctx) {
parsedQuery_._clause = visit(ctx->selectClause());
parsedQuery_.datasetClauses_ = parsedQuery::DatasetClauses::fromClauses(
visitVector(ctx->datasetClause()));
activeDatasetClauses_ = parsedQuery_.datasetClauses_;
parsedQuery_.datasetClauses_ =
setAndGetDatasetClauses(visitVector(ctx->datasetClause()));
visitWhereClause(ctx->whereClause(), parsedQuery_);
parsedQuery_.addSolutionModifiers(visit(ctx->solutionModifier()));
return parsedQuery_;
Expand Down
13 changes: 11 additions & 2 deletions src/parser/sparqlParser/SparqlQleverVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,15 @@ class SparqlQleverVisitor {

public:
SparqlQleverVisitor() = default;
// If `datasetOverride` contains datasets, then the datasets in
// the operation itself are ignored. This is used for the datasets from the
// url parameters which override those in the operation.
explicit SparqlQleverVisitor(
PrefixMap prefixMap,
PrefixMap prefixMap, ParsedQuery::DatasetClauses datasetOverride,
DisableSomeChecksOnlyForTesting disableSomeChecksOnlyForTesting =
DisableSomeChecksOnlyForTesting::False)
: prefixMap_{std::move(prefixMap)},
: activeDatasetClauses_{std::move(datasetOverride)},
prefixMap_{std::move(prefixMap)},
disableSomeChecksOnlyForTesting_{disableSomeChecksOnlyForTesting} {}

const PrefixMap& prefixMap() const { return prefixMap_; }
Expand Down Expand Up @@ -629,5 +633,10 @@ class SparqlQleverVisitor {
static parsedQuery::BasicGraphPattern toGraphPattern(
const ad_utility::sparql_types::Triples& triples);

// Set the datasets state of the visitor if no override is defined. Returns
// the currently active datasets.
parsedQuery::DatasetClauses setAndGetDatasetClauses(
const std::vector<DatasetClause>& clauses);

FRIEND_TEST(SparqlParser, ensureExceptionOnInvalidGraphTerm);
};
4 changes: 4 additions & 0 deletions test/QueryPlannerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2968,6 +2968,10 @@ TEST(QueryPlanner, Exists) {
filter);
h::expect("Describe ?x FROM <g> { ?x ?y ?z FILTER EXISTS {?a ?b ?c}}",
h::Describe(::testing::_, filter));
h::expect(
"DELETE { ?x <b> <c> } USING <g> WHERE { ?x ?y ?z FILTER EXISTS {?a ?b "
"?c}}",
filter);

// Test the interaction of FROM NAMES with EXISTS
auto varG = std::vector{Variable{"?g"}};
Expand Down
Loading
Loading