Skip to content

Feature/381 sparql 11 variable visibility#454

Open
remiceres wants to merge 17 commits into
feature/corese-nextfrom
feature/381-sparql-11-variable-visibility
Open

Feature/381 sparql 11 variable visibility#454
remiceres wants to merge 17 commits into
feature/corese-nextfrom
feature/381-sparql-11-variable-visibility

Conversation

@remiceres
Copy link
Copy Markdown
Contributor

Implemented for issue #381.

  • Added variable visibility validation for GROUP BY
  • Added variable visibility validation for HAVING
  • Added variable visibility validation for SELECT (expr AS ?var)
  • Added support for immediate alias visibility inside the same SELECT clause
  • Added ORDER BY scope validation for ASK queries
  • Extended non-SELECT ORDER BY scope validation to include VALUES
  • Added grouped SELECT projection validation:
    • reject projected variables that are not grouped and not aggregated
    • reject projection expressions that use non-grouped variables outside aggregates
  • Added implicit aggregate query validation when there is no explicit GROUP BY
  • Rejected SELECT * when GROUP BY is present
  • Extended the AST to support GROUP BY (expr AS ?alias)
  • Added validation support for GROUP BY expression aliases in:
    • SELECT
    • HAVING
    • ORDER BY
  • Added grouped HAVING validation:
    • reject variables used outside aggregates if they are not grouped
  • Added grouped ORDER BY validation:
    • reject variables used outside aggregates if they are not grouped
  • Added validation coverage for projected aggregate aliases used in ORDER BY
  • Refactored common semantic validation helpers to avoid duplication across grouped rules
  • Added and updated targeted parser and validation tests for all the cases above

@github-actions
Copy link
Copy Markdown

Overall Project 47.98% -0.1% 🍏
Files changed 79.61% 🍏

File Coverage
SelectProjectionScopeValidationRule.java 100% 🍏
HavingScopeValidationRule.java 100% 🍏
GroupByScopeValidationRule.java 100% 🍏
ScopeClause.java 100% 🍏
OrderByScopeValidationRule.java 100% 🍏
GroupedOrderByValidationRule.java 98.24% -1.76% 🍏
GroupedSelectProjectionValidationRule.java 98.17% -1.83% 🍏
AbstractSemanticValidationRule.java 97.17% -2.83% 🍏
GroupedHavingValidationRule.java 96.43% -3.57% 🍏
SelectQueryFeature.java 94.74% 🍏
GroupByAst.java 93.02% -4.65% 🍏
SparqlQuerySemanticValidator.java 92.42% 🍏
SolutionModifierFeature.java 90.8% -4.91% 🍏
SparqlAstBuilder.java 83.39% -0.8% 🍏
ProjectionAst.java 81.82% -2.6% 🍏
VariableScopeAnalyzer.java 69.4% -24.36%
ProjectionAsts.java 54.1% -31.15%

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 28, 2026

Test Results

  414 files    414 suites   19s ⏱️
2 293 tests 2 293 ✅ 0 💤 0 ❌
2 307 runs  2 307 ✅ 0 💤 0 ❌

Results for commit 9ad9945.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

Overall Project 47.99% -0.09% 🍏
Files changed 81.47% 🍏

File Coverage
SelectProjectionScopeValidationRule.java 100% 🍏
HavingScopeValidationRule.java 100% 🍏
GroupByScopeValidationRule.java 100% 🍏
ScopeClause.java 100% 🍏
OrderByScopeValidationRule.java 100% 🍏
GroupedOrderByValidationRule.java 98.86% -1.14% 🍏
GroupedSelectProjectionValidationRule.java 98.17% -1.83% 🍏
AbstractSemanticValidationRule.java 97.17% -2.83% 🍏
GroupedHavingValidationRule.java 96.43% -3.57% 🍏
SelectQueryFeature.java 94.74% 🍏
GroupByAst.java 93.02% -4.65% 🍏
SparqlQuerySemanticValidator.java 92.42% 🍏
SolutionModifierFeature.java 90.8% -4.91% 🍏
SparqlAstBuilder.java 83.39% -0.8% 🍏
ProjectionAst.java 81.82% -2.6% 🍏
VariableScopeAnalyzer.java 71.82% -21.94%
ProjectionAsts.java 65.57% -31.15%

@github-actions
Copy link
Copy Markdown

Overall Project 47.99% -0.09% 🍏
Files changed 81.47% 🍏

File Coverage
SelectProjectionScopeValidationRule.java 100% 🍏
HavingScopeValidationRule.java 100% 🍏
GroupByScopeValidationRule.java 100% 🍏
ScopeClause.java 100% 🍏
OrderByScopeValidationRule.java 100% 🍏
GroupedOrderByValidationRule.java 98.86% -1.14% 🍏
GroupedSelectProjectionValidationRule.java 98.17% -1.83% 🍏
AbstractSemanticValidationRule.java 97.17% -2.83% 🍏
GroupedHavingValidationRule.java 96.43% -3.57% 🍏
SelectQueryFeature.java 94.74% 🍏
GroupByAst.java 93.02% -4.65% 🍏
SparqlQuerySemanticValidator.java 92.42% 🍏
SolutionModifierFeature.java 90.8% -4.91% 🍏
SparqlAstBuilder.java 83.39% -0.8% 🍏
ProjectionAst.java 81.82% -2.6% 🍏
VariableScopeAnalyzer.java 71.82% -21.94%
ProjectionAsts.java 65.57% -31.15%

@remiceres remiceres requested a review from prbblrypier May 28, 2026 13:40
@remiceres remiceres self-assigned this May 28, 2026
@remiceres remiceres requested a review from MaillPierre May 28, 2026 13:41
@remiceres remiceres added the Refactoring Issue created during the 2025 refactoring effort label May 28, 2026
Copy link
Copy Markdown
Contributor

@MaillPierre MaillPierre left a comment

Choose a reason for hiding this comment

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

I have some comments before approving because I'm lost by some changes.

QueryAst ast = parser.parse("""
SELECT * WHERE {
?s ?p ?o .
BIND(IF(BOUND(?s), COUNT(?o), ?p) AS ?result)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you explain this test please ? I don't understand where the aggregate is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Here the aggregate is COUNT(?o) inside the IF(...) expression.

This test is here to check collectReferencedVariablesOutsideAggregates(...)

The query itself does not really make sense as a full example.
It is only used to build a AST with some variables outside an aggregate and one variable inside an aggregate

The only part really used by the test is:
BIND(IF(BOUND(?s), COUNT(?o), ?p) AS ?result)

In this expression:

  • ?s is outside the aggregate
  • ?p is outside the aggregate
  • ?o is inside COUNT(?o)

So the helper should keep ?s and ?p, and ignore ?o


QueryAst ast = parser.parse("""
SELECT ?s WHERE {
SELECT (AVG(?val) AS ?avg) WHERE {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why change that ? AVG(?val) appears twice in the query now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I changed it because the old query was not valid

In the old version SELECT ?s ... ORDER BY AVG(?val)
AVG(?val) makes the query an aggregate query, but ?s is not grouped and not aggregated.

The new version keeps the same thing we want to test (ORDER BY AVG(?val)), but also makes the full query valid: SELECT (AVG(?val) AS ?avg) ... ORDER BY AVG(?val)

So yes, AVG(?val) appears twice, once to make the query valid and once because this is the ORDER BY expression we want to parse

WHERE {
?s ?p ?o .
}
ORDER BY ?s
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is grammatically correct ... It does not make any sense, though. Only HAVING and LIMIT would impact the query execution.
This is just a comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I agree.

This test is mainly here for parser/AST consistency.
It is not here because ORDER BY is especially useful for ASK.

I first had this kind of check for SELECT, and in this PR I extended it to the other query forms too, to keep the behavior consistent.

So here the goal is only to check that ORDER BY is parsed and stored correctly in the AST for ASK.


private void validateProjectionExpression(
String projectionVariableName,
ProjectionAst projection,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add GROUP BY.

Set<String> groupedVariables,

return;
}
for (String referencedVariable : collectReferencedVariablesOutsideAggregates(expression)) {
diagnostics.add(buildGroupedProjectionDiagnostic(referencedVariable));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

            if (!groupedVariables.contains(referencedVariable)) {
                diagnostics.add(buildGroupedProjectionDiagnostic(referencedVariable));
            }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we can add the following test :

   @Test
    @DisplayName("Should accept grouped SELECT expression using a variable from GROUP BY ?var")
    void shouldAcceptGroupedSelectExpressionUsingGroupedVariable() {
        SparqlParser parser = newParserDefault();

        QueryAst ast = parser.parse("""
                SELECT ?groupedVar (STR(?groupedVar) AS ?alias) WHERE {
                    ?groupedVar ?p ?o
                }
                GROUP BY ?groupedVar
                """);

        SelectQueryAst selectQueryAst = assertInstanceOf(SelectQueryAst.class, ast);
        ProjectionAst projection = selectQueryAst.projection();
        assertFalse(projection.selectAll());
        assertEquals(2, projection.variables().size());
        assertEquals("groupedVar", projection.variables().get(0).name());
        assertEquals("alias", projection.variables().get(1).name());
        assertTrue(projection.expressionBoundVariables().contains("alias"));
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactoring Issue created during the 2025 refactoring effort

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants