From 5e3c773da7d3e6379639bc8b5fd1449cf0855b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20C=C3=A9r=C3=A8s?= Date: Mon, 26 Oct 2026 15:27:40 +0100 Subject: [PATCH 1/2] refactor(engine): extract VariableLayout and rename engine Query to QueryPlan (#643) --- .../diagnostics/DiagnosticProducer.java | 4 +- .../diagnostics/ExecutionDiagnostics.java | 4 +- .../impl/engine/eval/EnvironmentImpl.java | 6 +- .../next/query/impl/engine/eval/Eval.java | 52 +++--- .../query/impl/engine/eval/EvalGraph.java | 4 +- .../next/query/impl/engine/eval/EvalJoin.java | 4 +- .../query/impl/engine/eval/EvalOptional.java | 4 +- .../query/impl/engine/eval/SelectCursor.java | 20 +- .../impl/engine/event/ProcessVisitor.java | 10 +- .../impl/engine/filter/FilterOptimizer.java | 8 +- .../query/impl/engine/model/Pointerable.java | 8 +- .../engine/pattern/CompiledQueryPlan.java | 16 +- .../pattern/{Query.java => QueryPlan.java} | 176 +++++++----------- .../impl/engine/pattern/VariableLayout.java | 169 +++++++++++++++++ .../planning/CardinalityPatternOrdering.java | 8 +- .../planning/ConnectedPatternOrdering.java | 10 +- .../planning/HeuristicPatternOrdering.java | 4 +- .../impl/engine/planning/QueryPlanner.java | 30 +-- .../impl/engine/planning/QueryStatistics.java | 6 +- .../impl/engine/solution/GroupAggregator.java | 4 +- .../query/impl/engine/solution/Mapping.java | 12 +- .../query/impl/engine/solution/Mappings.java | 32 ++-- .../query/impl/engine/solution/Memory.java | 14 +- .../engine/solution/SolutionMaterializer.java | 12 +- .../query/impl/engine/spi/Environment.java | 4 +- .../next/query/impl/engine/spi/Producer.java | 10 +- .../impl/engine/storage/ProducerDefault.java | 8 +- .../storage/StorageBindingEnvironment.java | 4 +- .../storage/StorageManagerProducer.java | 14 +- .../sparql/bridge/ConstructQueryCompiler.java | 10 +- .../sparql/bridge/CoreseAstQueryBuilder.java | 24 +-- .../sparql/bridge/DescribeQueryCompiler.java | 8 +- .../sparql/bridge/DirectGroupAggregation.java | 10 +- .../bridge/SolutionModifierCompiler.java | 34 ++-- .../impl/sparql/bridge/WhereCompiler.java | 4 +- .../sparql/execution/PreparedQueryPlan.java | 12 +- .../sparql/execution/SparqlQueryExecutor.java | 32 ++-- .../execution/StreamingTupleQueryResult.java | 10 +- .../impl/sparql/execution/TopKSelector.java | 4 +- .../QueryDeliveryDiagnosticsTest.java | 6 +- .../next/query/impl/engine/eval/EvalTest.java | 6 +- .../engine/pattern/CompiledQueryPlanTest.java | 18 +- .../{QueryTest.java => QueryPlanTest.java} | 78 ++++---- .../engine/pattern/VariableLayoutTest.java | 135 ++++++++++++++ .../planning/CardinalityQueryPlannerTest.java | 54 +++--- .../engine/solution/GroupAggregatorTest.java | 8 +- .../impl/engine/solution/MappingsTest.java | 16 +- .../impl/engine/solution/MemoryTest.java | 8 +- .../engine/storage/ContextSelectionTest.java | 4 +- .../storage/StorageManagerProducerTest.java | 18 +- .../bridge/CoreseAstQueryBuilderAskTest.java | 32 ++-- .../CoreseAstQueryBuilderConstructTest.java | 32 ++-- .../CoreseAstQueryBuilderDescribeTest.java | 28 +-- .../CoreseAstQueryBuilderMinusScopeTest.java | 6 +- .../bridge/CoreseAstQueryBuilderTest.java | 42 ++--- .../bridge/DirectGroupAggregationTest.java | 22 +-- .../bridge/WhereCompilerExistsTest.java | 4 +- .../sparql/execution/TopKSelectorTest.java | 6 +- .../memory/ProducerDeduplicationTest.java | 6 +- 59 files changed, 799 insertions(+), 535 deletions(-) rename src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/{Query.java => QueryPlan.java} (90%) create mode 100644 src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java rename src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/{QueryTest.java => QueryPlanTest.java} (90%) create mode 100644 src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/DiagnosticProducer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/DiagnosticProducer.java index e830a5264..1d1476a2a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/DiagnosticProducer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/DiagnosticProducer.java @@ -2,7 +2,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Edge; import fr.inria.corese.core.next.query.impl.engine.model.Node; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerProducer; import fr.inria.corese.core.next.storage.api.StorageManager; @@ -32,7 +32,7 @@ public DiagnosticProducer(StorageManager storage, ExecutionDiagnostics diagnosti } @Override - public long estimateCardinality(Query query, Node graphNode, Edge edge) { + public long estimateCardinality(QueryPlan query, Node graphNode, Edge edge) { long count = super.estimateCardinality(query, graphNode, edge); diagnostics.estimated(edge, count); return count; diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/ExecutionDiagnostics.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/ExecutionDiagnostics.java index 9dc53a5d0..861f50106 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/ExecutionDiagnostics.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/ExecutionDiagnostics.java @@ -11,7 +11,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.path.PropertyPathEdge; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import java.util.ArrayList; import java.util.Collections; @@ -120,7 +120,7 @@ public void compilationTime(long nanos) { * @param query completed runtime query * @param nanos elapsed completion nanoseconds */ - public void planned(Query query, long nanos) { + public void planned(QueryPlan query, long nanos) { planningNanos += nanos; visit(query, "query", null); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EnvironmentImpl.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EnvironmentImpl.java index a9507caf8..bed85332d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EnvironmentImpl.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EnvironmentImpl.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.engine.eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -18,7 +18,7 @@ public class EnvironmentImpl implements Environment { protected static final String NOT_SUPPORTED_YET = "Not supported yet."; - protected Query query; + protected QueryPlan query; public EnvironmentImpl(){ // The base environment starts without a query or bindings. @@ -72,7 +72,7 @@ public int pathLength(Node node) { @Override - public Query getQuery() { + public QueryPlan getQuery() { return query; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/Eval.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/Eval.java index 4bbfafa74..42eb60c4c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/Eval.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/Eval.java @@ -10,7 +10,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Loopable; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.MappingSet; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -73,7 +73,7 @@ public final class Eval implements ExpType { Matcher match; // Stacks for binding edges and nodes Memory memory; - Query query; + QueryPlan query; Mappings results; // initial results to be completed @@ -163,15 +163,15 @@ public void set(Evaluator e) { /** * Main eval function */ - public Mappings query(Query q) { + public Mappings query(QueryPlan q) { return query(null, q, null); } - public Mappings query(Node graphNode, Query q, Mapping m) { + public Mappings query(Node graphNode, QueryPlan q, Mapping m) { return queryBasic(graphNode, q, m); } - Mappings queryBasic(Node graphNode, Query q, Mapping m) { + Mappings queryBasic(Node graphNode, QueryPlan q, Mapping m) { initMemory(q); share(m); getProducer().start(q); @@ -217,7 +217,7 @@ void share(ProcessVisitor vis) { * use case: optional(A, B) map = relevant subset of results of A * for main query and subquery */ - Mappings eval(Node gNode, Query q, Mapping m, Mappings map) { + Mappings eval(Node gNode, QueryPlan q, Mapping m, Mappings map) { init(q); if (q.isValidate()) { // just compile and complete query @@ -241,8 +241,8 @@ Mappings eval(Node gNode, Query q, Mapping m, Mappings map) { * Mappings map is results or previous statement, possibly null * use case: optional(A, B) map = relevant subset of results of A */ - @SuppressWarnings("java:S1845") // Query execution method named query by convention - void query(Node gNode, Query q, Mapping m, Mappings map) { + @SuppressWarnings("java:S1845") // QueryPlan execution method named query by convention + void query(Node gNode, QueryPlan q, Mapping m, Mappings map) { if (m != null) { // bind mapping variables into memory bind(m); @@ -261,7 +261,7 @@ void query(Node gNode, Query q, Mapping m, Mappings map) { /** * Bind external values one by one in memory and eval one by one */ - void queryWithValues(Node gNode, Query q, Mappings map) { + void queryWithValues(Node gNode, QueryPlan q, Mappings map) { Exp values = q.getValues(); if (!values.isPostpone()) { @@ -279,7 +279,7 @@ void queryWithValues(Node gNode, Query q, Mappings map) { eval(gNode, q, map); } - void eval(Node gNode, Query q, Mappings map) { + void eval(Node gNode, QueryPlan q, Mappings map) { evalExp(gNode, q.getBody(), map); } void evalExp(Node gNode, Exp exp, Mappings map) { @@ -298,7 +298,7 @@ public void setMappings(Mappings lMap) { * for optional, minus, union, join, graph * not for subquery which has its own processing */ - Mappings subEval(Query q, Node gNode, Stack stack, Mappings map, int n) { + Mappings subEval(QueryPlan q, Node gNode, Stack stack, Mappings map, int n) { setSubEval(true); starter(q); eval(getProducer(), gNode, stack, map, n); @@ -488,7 +488,7 @@ Eval copy(Memory m, Producer p, Evaluator e, boolean extern) { * copy memory for sub query copy sub query select variables that are * already bound in current memory Use case: subquery and exists */ - private Memory copyMemory(Memory memory, Query query, Query sub, Exp exp) { + private Memory copyMemory(Memory memory, QueryPlan query, QueryPlan sub, Exp exp) { Memory mem = new Memory(match, evaluator); getEvaluator().init(mem); if (sub == null) { @@ -521,7 +521,7 @@ public BindingContext getBind() { return getEnvironment().getBind(); } - public Query getQuery() { + public QueryPlan getQuery() { return query; } @@ -558,16 +558,16 @@ public Mappings getResults() { } // total init (for global query) - public void init(Query q) { + public void init(QueryPlan q) { initMemory(q); start(q); } - void initMemory(Query q) { + void initMemory(QueryPlan q) { if (memory == null) { // when subquery, memory is already assigned // assign stack index to EDGE and NODE - q.complete(getProducer());//service while1 / Query + q.complete(getProducer());//service while1 / QueryPlan memory = new Memory(match, evaluator); memory.setEval(this); getEvaluator().init(memory); @@ -579,10 +579,10 @@ void initMemory(Query q) { } // partial init (for global query and subqueries) - public void start(Query q) { + public void start(QueryPlan q) { state.setLimit(q.getLimitOffset()); // ASK only needs its first solution after OFFSET. Keep the requested - // Query modifiers intact, and evaluate fully when sorting/grouping needs it. + // QueryPlan modifiers intact, and evaluate fully when sorting/grouping needs it. if (q.isAsk() && !q.isOrderBy() && !q.hasGroupBy() && !q.isAggregate()) { state.setLimit((int) Math.min(state.getLimit(), (long) q.getOffset() + 1)); } @@ -598,7 +598,7 @@ public int getLimit() { } // for sub exp - private void starter(Query q) { + private void starter(QueryPlan q) { query = q; // create result holder if (initialResults != null) { @@ -1018,7 +1018,7 @@ private int processServiceMappings(Producer p, Node graphNode, Stack stack, int // process additional variable provided by service // such as ?_server_0 in federated mode - void complete(Query q, Mapping map, boolean addNode) { + void complete(QueryPlan q, Mapping map, boolean addNode) { int i = 0; for (Node node : map.getQueryNodes()) { Node out = q.getOuterNode(node); @@ -1291,7 +1291,7 @@ private int edge(Producer p, Node graphNode, Exp exp, Mappings data, Stack stack Memory env = getMemory(); // used by RuleEngine ResultWatcher ProducerImpl env.setExp(exp); - Query qq = getQuery(); + QueryPlan qq = getQuery(); // for default graph triple pattern, consider select from if any // for named graph triple pattern, from named is useless here because graphNode = URI of one named graph List graphNodeList = qq.getFrom(graphNode); @@ -1395,7 +1395,7 @@ private int edge(Producer p, Node graphNode, Exp exp, Mappings data, Stack stack */ private int query(Producer p, Node graphNode, Exp exp, Mappings data, Stack stack, int n) { int backtrack = n - 1; - Query subQuery = exp.getQuery(); + QueryPlan subQuery = exp.getQuery(); Memory env = getMemory(); getVisitor().start(subQuery); @@ -1448,11 +1448,11 @@ Mappings selectQueryMappings(Mappings data) { * res is a result of sub query bind the select nodes of sub query into * current memory retrieve outer node that correspond to sub node */ - private boolean push(Query subQuery, Mapping res, int n) { + private boolean push(QueryPlan subQuery, Mapping res, int n) { int k = 0; Memory env = memory; Matcher mm = match; - Query qq = query; + QueryPlan qq = query; for (Exp exp : subQuery.getSelectFun()) { Node subNode = exp.getNode(); @@ -1487,9 +1487,9 @@ private boolean push(Query subQuery, Mapping res, int n) { /** * pop select nodes of sub query */ - private void pop(Query subQuery, Mapping ans) { + private void pop(QueryPlan subQuery, Mapping ans) { Memory env = memory; - Query qq = query; + QueryPlan qq = query; for (Node subNode : subQuery.getSelect()) { if (ans.isBound(subNode)) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalGraph.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalGraph.java index b04391388..d051493c7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalGraph.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalGraph.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.engine.eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; import fr.inria.corese.core.next.query.impl.engine.solution.Memory; @@ -105,7 +105,7 @@ private boolean isNamedGraph(Producer producer, Node graphNode, Node graph) { */ private Mappings graphNodes(Producer p, Exp exp, Mappings map) { Memory env = engine.getMemory(); - Query qq = engine.getQuery(); + QueryPlan qq = engine.getQuery(); Matcher mm = engine.getMatcher(); Node name = exp.getGraphName(); Mappings res = null; diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalJoin.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalJoin.java index 6b7ec8987..d96619bd7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalJoin.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalJoin.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.engine.eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.MappingSet; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -34,7 +34,7 @@ void setStop() { stop = true; } - Query getQuery() { + QueryPlan getQuery() { return engine.getMemory().getQuery(); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalOptional.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalOptional.java index 1151cb3ee..bc27fd27a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalOptional.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalOptional.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.engine.eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.MappingSet; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -192,7 +192,7 @@ boolean filter(Environment memory, Producer p, Node gNode, Mapping map, Exp exp) return true; } - Query getQuery() { + QueryPlan getQuery() { return engine.getMemory().getQuery(); } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/SelectCursor.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/SelectCursor.java index 5bd71da8f..a521add6d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/SelectCursor.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/eval/SelectCursor.java @@ -8,7 +8,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.ExpType.Type; import fr.inria.corese.core.next.query.impl.engine.path.PropertyPathEdge; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Memory; import fr.inria.corese.core.next.query.impl.engine.spi.Producer; @@ -35,7 +35,7 @@ public final class SelectCursor implements Iterator, AutoCloseable { private final Node scopeGraph; private final boolean nested; private final boolean applySlice; - private final Query query; + private final QueryPlan query; private final Memory memory; private final Producer producer; private final List instructions = new ArrayList<>(); @@ -55,7 +55,7 @@ public final class SelectCursor implements Iterator, AutoCloseable { * @param query completed execution query * @return first materialization guard, or NONE for eligible algebra */ - public static FallbackReason fallbackReason(Query query) { + public static FallbackReason fallbackReason(QueryPlan query) { if (!query.isSelect()) return FallbackReason.QUERY_FORM; if (query.isOrderBy()) return FallbackReason.ORDER_BY; return operatorFallbackReason(query); @@ -68,13 +68,13 @@ public static FallbackReason fallbackReason(Query query) { * @param query completed execution query * @return whether ORDER BY has a finite, representable LIMIT plus OFFSET and eligible input */ - public static boolean supportsOrderedInput(Query query) { + public static boolean supportsOrderedInput(QueryPlan query) { return query.isSelect() && query.isOrderBy() && query.getLimit() < Integer.MAX_VALUE && (long) query.getLimit() + query.getOffset() <= Integer.MAX_VALUE && operatorFallbackReason(query) == FallbackReason.NONE; } - private static FallbackReason operatorFallbackReason(Query query) { + private static FallbackReason operatorFallbackReason(QueryPlan query) { if (query.hasGroupBy() || query.isAggregate() || query.getHaving() != null) return FallbackReason.AGGREGATION; return fallbackReason(query.getBody(), query.getValues() != null && !singleton(query.getValues())); } @@ -161,7 +161,7 @@ private static boolean tripleJoin(Exp exp) { * @param query completed eligible SELECT * @param bindings initial parameter bindings, or null */ - public SelectCursor(Eval eval, Query query, Mapping bindings) { + public SelectCursor(Eval eval, QueryPlan query, Mapping bindings) { this(null, eval, query, bindings, query.getBody(), null, true); } @@ -171,15 +171,15 @@ public SelectCursor(Eval eval, Query query, Mapping bindings) { * The caller owns both this cursor and its producer's stable read view. * * @param eval fresh evaluator owned by this execution - * @param query completed query accepted by {@link #supportsOrderedInput(Query)} + * @param query completed query accepted by {@link #supportsOrderedInput(QueryPlan)} * @param bindings initial parameter bindings, or null * @return unsliced input cursor */ - public static SelectCursor orderedInput(Eval eval, Query query, Mapping bindings) { + public static SelectCursor orderedInput(Eval eval, QueryPlan query, Mapping bindings) { return new SelectCursor(null, eval, query, bindings, query.getBody(), null, false); } - private SelectCursor(SelectCursor parent, Eval eval, Query query, Mapping bindings, Exp body, Node graph, + private SelectCursor(SelectCursor parent, Eval eval, QueryPlan query, Mapping bindings, Exp body, Node graph, boolean applySlice) { this.eval = eval; this.query = query; @@ -243,7 +243,7 @@ public boolean hasNext() { } private static void checkInterrupted() { - if (Thread.currentThread().isInterrupted()) throw new QueryEvaluationException("Query interrupted"); + if (Thread.currentThread().isInterrupted()) throw new QueryEvaluationException("QueryPlan interrupted"); } private boolean selectRow() { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/event/ProcessVisitor.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/event/ProcessVisitor.java index 31da72849..c35e156af 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/event/ProcessVisitor.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/event/ProcessVisitor.java @@ -2,7 +2,7 @@ import fr.inria.corese.core.next.query.impl.engine.eval.Eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -29,11 +29,11 @@ default DatatypeValue defaultValue() { return null; } - default DatatypeValue init(Query q) { + default DatatypeValue init(QueryPlan q) { return defaultValue(); } - default DatatypeValue before(Query q) { + default DatatypeValue before(QueryPlan q) { return defaultValue(); } @@ -41,7 +41,7 @@ default DatatypeValue after(Mappings map) { return defaultValue(); } - default DatatypeValue start(Query q) { + default DatatypeValue start(QueryPlan q) { return defaultValue(); } @@ -53,7 +53,7 @@ default DatatypeValue orderby(Mappings map) { return defaultValue(); } - default boolean distinct(Eval eval, Query q, Mapping map) { + default boolean distinct(Eval eval, QueryPlan q, Mapping map) { return true; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java index f8bf10441..a554b885b 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java @@ -7,7 +7,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import java.util.ArrayList; import java.util.List; @@ -39,10 +39,10 @@ */ public final class FilterOptimizer implements ExprType { - private Query kgramQuery; + private QueryPlan kgramQuery; private final ExpressionPatternMatcher matcher; - public FilterOptimizer(Query q){ + public FilterOptimizer(QueryPlan q){ kgramQuery = q; matcher = new ExpressionPatternMatcher(); } @@ -56,7 +56,7 @@ public FilterOptimizer(Query q){ * x p t . y p z filter(y = x) * we can bind y = x before enumerate y p z */ - public void process(Query q, Exp exp) { + public void process(QueryPlan q, Exp exp) { this.kgramQuery = q; Filter ff = exp.getFilter(); Expr ee = ff.getExp(); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/model/Pointerable.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/model/Pointerable.java index b654b549d..f4e000b56 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/model/Pointerable.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/model/Pointerable.java @@ -3,7 +3,7 @@ import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import java.util.ArrayList; @@ -35,7 +35,11 @@ default Node getNode() { return null; } - default Query getQuery() { + default QueryPlan getQueryPlan() { + return getQuery(); + } + + default QueryPlan getQuery() { return null; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java index 78ccedfb7..24ed380a9 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java @@ -14,10 +14,10 @@ * result mappings, initial bindings or execution context is retained. */ public final class CompiledQueryPlan { - private final Query image; + private final QueryPlan image; private final List estimates; - private CompiledQueryPlan(Query query, Map counts) { + private CompiledQueryPlan(QueryPlan query, Map counts) { PlanCopy copies = new PlanCopy(); image = copies.copy(query); estimates = counts.entrySet().stream() @@ -25,13 +25,13 @@ private CompiledQueryPlan(Query query, Map counts) { } /** - * Captures a completed query without retaining any compiler-owned mutable object. + * Captures a completed query plan without retaining any compiler-owned mutable object. * - * @param query completed native query + * @param query completed native query plan * @param counts estimates obtained while ordering its patterns * @return immutable compilation image */ - public static CompiledQueryPlan capture(Query query, Map counts) { + public static CompiledQueryPlan capture(QueryPlan query, Map counts) { return new CompiledQueryPlan(query, counts); } @@ -39,11 +39,11 @@ public static CompiledQueryPlan capture(Query query, Map counts) { * Creates independent runtime containers without AST translation or planning. * * @param diagnostics optional request-scoped collector, or null - * @return completed query owned by one execution + * @return completed query plan owned by one execution */ - public Query newExecution(ExecutionDiagnostics diagnostics) { + public QueryPlan newExecution(ExecutionDiagnostics diagnostics) { PlanCopy copies = new PlanCopy(); - Query runtime = copies.copy(image); + QueryPlan runtime = copies.copy(image); if (diagnostics != null) { for (Estimate estimate : estimates) { diagnostics.estimated(copies.copy(estimate.edge()), estimate.cardinality()); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/Query.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java similarity index 90% rename from src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/Query.java rename to src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java index 6b81a1f2a..c635eb841 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/Query.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java @@ -30,7 +30,7 @@ * @author Olivier Corby, Edelweiss, INRIA 2009 * */ -public final class Query extends Exp { +public final class QueryPlan extends Exp { public static final int QP_T0 = 0; //No QP settings @@ -38,7 +38,7 @@ public final class Query extends Exp { public static final int QP_HEURISTICS_BASED = 2;//Heuristics based QP public static final int QP_BGP = 3;//BGP based QP - private static final Logger logger = LoggerFactory.getLogger(Query.class); + private static final Logger logger = LoggerFactory.getLogger(QueryPlan.class); int limit = Integer.MAX_VALUE; int offset = 0; @@ -47,24 +47,10 @@ public final class Query extends Exp { private int number = 0; private boolean distinctResults; - int iNode = 0; - int iEdge = 0; + private final VariableLayout layout; List from; List named; List selectNode; - // all nodes (on demand) - - // std pattern but minus/exists (without select) - List patternNodes; - // std pattern but minus/exists select nodes - List patternSelectNodes; - // minus/exists (without select) - List queryNodes; - // minus/exists select nodes - List querySelectNodes; - // final query bindings nodes - List bindingNodes; - private List constructNodes; List relaxEdges; List selectExp; List orderBy; @@ -81,8 +67,8 @@ public final class Query extends Exp { // use case: graph ?g (select where ...) Node gNode; // Root query whose dataset is inherited by this subquery. - private Query globalQuery; - Query outerQuery; + private QueryPlan globalQuery; + QueryPlan outerQuery; private Object queryObject; FilterOptimizer compiler; @@ -96,9 +82,9 @@ public final class Query extends Exp { HashMap ptable; HashMap etable; // query for class/property definition checking - HashMap table; + HashMap table; // Extended queries for additional group by - List queries; + List queries; private boolean isCompiled = false; private boolean datasetSpecified; private boolean reportEnabled; @@ -131,17 +117,14 @@ public final class Query extends Exp { private boolean isService = false; - private final List argList; private Mapping mapping; - - - private String service; /** Creates an uncompiled query whose mutable containers belong to its compiler. */ - public Query() { + public QueryPlan() { super(Type.QUERY); + layout = new VariableLayout(); from = new ArrayList<>(); named = new ArrayList<>(); selectExp = new ArrayList<>(); @@ -157,13 +140,7 @@ public Query() { etable = new HashMap<>(); queries = new ArrayList<>(); selectNode = new ArrayList<>(); - patternNodes = new ArrayList<>(); - queryNodes = new ArrayList<>(); - patternSelectNodes = new ArrayList<>(); - querySelectNodes = new ArrayList<>(); - bindingNodes = new ArrayList<>(); relaxEdges = new ArrayList<>(); - argList = new ArrayList<>(); querySorter = new QueryPlanner(this); } @@ -172,29 +149,22 @@ public Query() { * Registration precedes graph links because subqueries refer to their outer query. */ @SuppressWarnings("this-escape") // PlanCopy only records identity; no execution observes the shell before construction finishes. - private Query(Query source, PlanCopy copies) { + private QueryPlan(QueryPlan source, PlanCopy copies) { super(Type.QUERY); copies.remember(source, this); source.copyPlanFields(this, copies); + layout = new VariableLayout(); + layout.copyFrom(source.layout, copies); querySorter = null; compiler = null; - argList = copies.copy(source.argList); this.limit = source.limit; this.offset = source.offset; this.slice = source.slice; this.number = source.number; this.distinctResults = source.distinctResults; - this.iNode = source.iNode; - this.iEdge = source.iEdge; this.from = copies.copy(source.from); this.named = copies.copy(source.named); this.selectNode = copies.copy(source.selectNode); - this.patternNodes = copies.copy(source.patternNodes); - this.patternSelectNodes = copies.copy(source.patternSelectNodes); - this.queryNodes = copies.copy(source.queryNodes); - this.querySelectNodes = copies.copy(source.querySelectNodes); - this.bindingNodes = copies.copy(source.bindingNodes); - this.constructNodes = copies.copy(source.constructNodes); this.relaxEdges = copies.copy(source.relaxEdges); this.selectExp = copies.copy(source.selectExp); this.orderBy = copies.copy(source.orderBy); @@ -246,25 +216,25 @@ private Query(Query source, PlanCopy copies) { /** Copies a completed query, with fresh containers and no retained planning producer. */ @Override - public Query copyPlan(PlanCopy copies) { + public QueryPlan copyPlan(PlanCopy copies) { if (!isCompiled) { throw new IllegalStateException("Only completed queries can form an execution image"); } - return new Query(this, copies); + return new QueryPlan(this, copies); } - Query(Exp e) { + QueryPlan(Exp e) { this(); add(e); } - public static Query create(Exp e) { - return new Query(e); + public static QueryPlan create(Exp e) { + return new QueryPlan(e); } /** Creates an empty compiled query. */ - public static Query create() { - return new Query(); + public static QueryPlan create() { + return new QueryPlan(); } @Override @@ -314,11 +284,11 @@ public StringBuilder toString(StringBuilder sb) { } - public Query get(Edge e) { + public QueryPlan get(Edge e) { return table.get(e); } - public List getQueries() { + public List getQueries() { return queries; } @@ -389,7 +359,7 @@ public void setBody(Exp exp){ add(exp); } - void setGlobalQuery(Query q) { + void setGlobalQuery(QueryPlan q) { globalQuery = q; inherit(q); } @@ -397,7 +367,7 @@ void setGlobalQuery(Query q) { /** * inherit from and from named */ - void inherit(Query q) { + void inherit(QueryPlan q) { if (!isService()) { setFrom(q.getFrom()); setNamed(q.getNamed()); @@ -406,18 +376,18 @@ void inherit(Query q) { } - public Query getGlobalQuery() { + public QueryPlan getGlobalQuery() { if (globalQuery != null) { return globalQuery; } return this; } - public void setOuterQuery(Query q) { + public void setOuterQuery(QueryPlan q) { outerQuery = q; } - public Query getOuterQuery() { + public QueryPlan getOuterQuery() { if (outerQuery == null) { return this; } @@ -492,21 +462,25 @@ public boolean isDatasetSpecified() { return datasetSpecified; } + public VariableLayout getLayout() { + return layout; + } + public List getPatternNodes() { - return patternNodes; + return layout.getPatternNodes(); } public List getQueryNodes() { - return queryNodes; + return layout.getQueryNodes(); } public List getPatternSelectNodes() { - return patternSelectNodes; + return layout.getPatternSelectNodes(); } public List getBindingNodes() { if (getValues() == null) { - return bindingNodes; + return layout.getBindingNodes(); } return getValues().getNodeList(); } @@ -553,28 +527,19 @@ public List getSelectFun() { } public Node getPatternNode(String name) { - return get(patternNodes, name); + return layout.getPatternNode(name); } public Node getQueryNode(String name) { - return get(queryNodes, name); + return layout.getQueryNode(name); } public Node getPatternSelectNode(String name) { - return get(patternSelectNodes, name); + return layout.getPatternSelectNode(name); } public Node getQuerySelectNode(String name) { - return get(querySelectNodes, name); - } - - Node get(List list, String name) { - for (Node node : list) { - if (name.equals(node.getLabel())) { - return node; - } - } - return null; + return layout.getQuerySelectNode(name); } public void setSlice(int n) { @@ -857,11 +822,11 @@ public Exp getInsert() { } public List getConstructNodes() { - return constructNodes; + return layout.getConstructNodes(); } public void setConstructNodes(List constructNodes) { - this.constructNodes = constructNodes; + layout.setConstructNodes(constructNodes); } public void setDelete(Exp c) { @@ -905,11 +870,11 @@ public Node getSelectNode(String label) { } public int nbNodes() { - return iNode; + return layout.getNodeIndex(); } public int nbEdges() { - return iEdge; + return layout.getEdgeIndex(); } @@ -946,7 +911,7 @@ void basicComplete(Producer prod) { complete2(); - for (Query q : getQueries()) { + for (QueryPlan q : getQueries()) { q.complete(prod); } @@ -993,7 +958,12 @@ void index(List list) { } @Override - public Query getQuery() { + public QueryPlan getQuery() { + return this; + } + + @Override + public QueryPlan getQueryPlan() { return this; } @@ -1056,19 +1026,7 @@ public Node getExtNode(String name, boolean select) { } void store(Node node, boolean exist, boolean select) { - if (select) { - if (exist) { - add(querySelectNodes, node); - } else { - add(patternSelectNodes, node); - } - } else { - if (exist) { - add(queryNodes, node); - } else { - add(patternNodes, node); - } - } + layout.store(node, exist, select); } /** @@ -1193,7 +1151,7 @@ void collectExist(Expr exp) { * return the min of index of exp Nodes * query is (sub)query this is global query */ - int index(Query query, Exp exp, boolean isExist, int start) { + int index(QueryPlan query, Exp exp, boolean isExist, int start) { int min = switch (exp.type()) { case EDGE, XPATH, EVAL -> indexEdgeExp(exp); case VALUES -> indexValuesExp(exp); @@ -1214,7 +1172,7 @@ int index(Query query, Exp exp, boolean isExist, int start) { private int indexEdgeExp(Exp exp) { Edge edge = exp.getEdge(); - edge.setEdgeIndex(iEdge++); + edge.setEdgeIndex(layout.allocateEdgeIndex()); return indexExpEdge(exp); } @@ -1227,7 +1185,7 @@ private int indexValuesExp(Exp exp) { return min; } - private int indexBindExp(Query query, Exp exp, boolean isExist) { + private int indexBindExp(QueryPlan query, Exp exp, boolean isExist) { Node qn = exp.getNode(); int min = index(qn); if (exp.getNodeList() != null) { @@ -1239,7 +1197,7 @@ private int indexBindExp(Query query, Exp exp, boolean isExist) { return indexExpFilter(query, exp, isExist); } - private int indexDefaultExp(Query query, Exp exp, boolean isExist, int start) { + private int indexDefaultExp(QueryPlan query, Exp exp, boolean isExist, int start) { int min = Integer.MAX_VALUE; int startIndex = (start >= 0) ? start : globalNodeIndex(); int ind = exp.isUnion() ? startIndex : -1; @@ -1251,7 +1209,7 @@ private int indexDefaultExp(Query query, Exp exp, boolean isExist, int start) { } // use case: index filter exists (?x ?p ?y) - int indexExpFilter(Query query, Exp exp, boolean isExist) { + int indexExpFilter(QueryPlan query, Exp exp, boolean isExist) { int min = Integer.MAX_VALUE; boolean hasExist = index(query, exp.getFilter()); List lVar = exp.getFilter().getVariables(true); @@ -1276,9 +1234,9 @@ int indexExpFilter(Query query, Exp exp, boolean isExist) { return min; } - int indexExpQuery(Query query, Exp exp, boolean isExist) { + int indexExpQuery(QueryPlan query, Exp exp, boolean isExist) { int min = Integer.MAX_VALUE; - Query qq = exp.getQuery(); + QueryPlan qq = exp.getQuery(); qq.setCompiled(); qq.setGlobalQuery(this); qq.setOuterQuery(query); @@ -1337,7 +1295,7 @@ int newGlobalNodeIndex() { } int newNodeIndex() { - return iNode++; + return layout.allocateNodeIndex(); } int globalNodeIndex() { @@ -1345,7 +1303,7 @@ int globalNodeIndex() { } int getNodeIndex() { - return iNode; + return layout.getNodeIndex(); } /** @@ -1361,10 +1319,8 @@ public List toExp(List lNode) { return lExp; } - - public List getArgList() { - return argList; + return layout.getArgList(); } /** @@ -1392,14 +1348,14 @@ public List getNodes(Filter f) { * Dependency with filter exp for tracking filter(exists {PAT}) * */ - boolean index(Query query, Filter f) { + boolean index(QueryPlan query, Filter f) { return index(query, f.getExp()); } /** * Looking for filter(exist {}) */ - boolean index(Query query, Expr exp) { + boolean index(QueryPlan query, Expr exp) { boolean b = false; if (exp.oper() == ExprType.EXIST) { index(query, getPattern(exp), true, -1); @@ -1412,21 +1368,21 @@ boolean index(Query query, Expr exp) { return b; } - public Query orderBy(Node node) { + public QueryPlan orderBy(Node node) { if (node != null && doesNotContain(getOrderBy(), node)) { addOrderBy(node); } return this; } - public Query groupBy(Node node) { + public QueryPlan groupBy(Node node) { if (node != null && doesNotContain(getGroupBy(), node)) { addGroupBy(node); } return this; } - void setSelect(Query q1, Query q2) { + void setSelect(QueryPlan q1, QueryPlan q2) { List list = new ArrayList<>(); list.addAll(q1.getSelectFun()); for (Exp exp : q2.getSelectFun()) { @@ -1519,7 +1475,7 @@ public List getEdges(){ @Override public String getDatatypeLabel() { - return "[Query]"; + return "[QueryPlan]"; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java new file mode 100644 index 000000000..e1185f710 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java @@ -0,0 +1,169 @@ +package fr.inria.corese.core.next.query.impl.engine.pattern; + +import fr.inria.corese.core.next.query.impl.engine.model.Node; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages the variable layout, node collection, and binding index allocation for query plans. + */ +public final class VariableLayout { + + private int nodeIndex = 0; + private int edgeIndex = 0; + + private List patternNodes = new ArrayList<>(); + private List patternSelectNodes = new ArrayList<>(); + private List queryNodes = new ArrayList<>(); + private List querySelectNodes = new ArrayList<>(); + private List bindingNodes = new ArrayList<>(); + private List constructNodes = new ArrayList<>(); + private List argList = new ArrayList<>(); + + public VariableLayout() { + // Default constructor initializing empty variable collections and layout counters. + } + + public void copyFrom(VariableLayout source, PlanCopy copies) { + this.nodeIndex = source.nodeIndex; + this.edgeIndex = source.edgeIndex; + this.patternNodes = copies.copy(source.patternNodes); + this.patternSelectNodes = copies.copy(source.patternSelectNodes); + this.queryNodes = copies.copy(source.queryNodes); + this.querySelectNodes = copies.copy(source.querySelectNodes); + this.bindingNodes = copies.copy(source.bindingNodes); + this.constructNodes = copies.copy(source.constructNodes); + this.argList = copies.copy(source.argList); + } + + public int allocateNodeIndex() { + return nodeIndex++; + } + + public int getNodeIndex() { + return nodeIndex; + } + + public void setNodeIndex(int nodeIndex) { + this.nodeIndex = nodeIndex; + } + + public int allocateEdgeIndex() { + return edgeIndex++; + } + + public int getEdgeIndex() { + return edgeIndex; + } + + public void setEdgeIndex(int edgeIndex) { + this.edgeIndex = edgeIndex; + } + + public void store(Node node, boolean exist, boolean select) { + if (select) { + if (exist) { + add(querySelectNodes, node); + } else { + add(patternSelectNodes, node); + } + } else { + if (exist) { + add(queryNodes, node); + } else { + add(patternNodes, node); + } + } + } + + private void add(List list, Node node) { + if (node != null && node.isVariable() && !node.isBlank() && !list.contains(node)) { + list.add(node); + } + } + + public Node getNode(String name, Node selectNode) { + return getExtNode(name, false, selectNode); + } + + public Node getExtNode(String name, boolean select, Node selectNode) { + Node node = getPatternNode(name); + if (node != null) { + return node; + } + if (select && selectNode != null) { + return selectNode; + } + node = getQueryNode(name); + if (node != null) { + return node; + } + node = getPatternSelectNode(name); + if (node != null) { + return node; + } + return getQuerySelectNode(name); + } + + public Node getPatternNode(String name) { + return get(patternNodes, name); + } + + public Node getQueryNode(String name) { + return get(queryNodes, name); + } + + public Node getPatternSelectNode(String name) { + return get(patternSelectNodes, name); + } + + public Node getQuerySelectNode(String name) { + return get(querySelectNodes, name); + } + + private Node get(List list, String name) { + for (Node node : list) { + if (name.equals(node.getLabel())) { + return node; + } + } + return null; + } + + public List getPatternNodes() { + return patternNodes; + } + + public List getPatternSelectNodes() { + return patternSelectNodes; + } + + public List getQueryNodes() { + return queryNodes; + } + + public List getQuerySelectNodes() { + return querySelectNodes; + } + + public List getBindingNodes() { + return bindingNodes; + } + + public void setBindingNodes(List bindingNodes) { + this.bindingNodes = bindingNodes; + } + + public List getConstructNodes() { + return constructNodes; + } + + public void setConstructNodes(List constructNodes) { + this.constructNodes = constructNodes; + } + + public List getArgList() { + return argList; + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityPatternOrdering.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityPatternOrdering.java index 0bf8e896a..3aa59865c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityPatternOrdering.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityPatternOrdering.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.path.PropertyPathEdge; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.storage.api.model.PredicateStatistics; import fr.inria.corese.core.next.storage.api.model.StorageStatistics; @@ -42,7 +42,7 @@ private CardinalityPatternOrdering() { * @param bindings constant-binding hints collected by the planner * @param statistics producer's session-visible statistics */ - static void sort(Query query, Node graph, Exp expression, List variables, + static void sort(QueryPlan query, Node graph, Exp expression, List variables, List bindings, QueryStatistics statistics) { flattenTripleGroups(expression); List bound = new ArrayList<>(); @@ -68,7 +68,7 @@ static void sort(Query query, Node graph, Exp expression, List variables } private record PlanningContext( - Query query, + QueryPlan query, Node graph, QueryStatistics statistics, List bound, @@ -110,7 +110,7 @@ private static boolean isTriple(Exp expression) { return expression.isEdge() && !(expression.getEdge() instanceof PropertyPathEdge); } - private static long[] cardinalities(Query query, Node graph, Exp expression, int start, int end, + private static long[] cardinalities(QueryPlan query, Node graph, Exp expression, int start, int end, QueryStatistics statistics) { long[] counts = new long[end - start]; for (int i = start; i < end; i++) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/ConnectedPatternOrdering.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/ConnectedPatternOrdering.java index 6c621eaa3..34681b09c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/ConnectedPatternOrdering.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/ConnectedPatternOrdering.java @@ -1,6 +1,6 @@ package fr.inria.corese.core.next.query.impl.engine.planning; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -19,7 +19,7 @@ public class ConnectedPatternOrdering { @SuppressWarnings("java:S3776") - public void sort(Query q, Exp exp, List lVar, List lBind) { + public void sort(QueryPlan q, Exp exp, List lVar, List lBind) { List lNode = new ArrayList<>(); @@ -67,11 +67,11 @@ public boolean leaveFirst() { * variable node bound count 2 constant node count 1 variable node not bound * count 0 */ - boolean shift(Query q, Exp e1, Exp e2, List lNode, List lVar, List lBind) { + boolean shift(QueryPlan q, Exp e1, Exp e2, List lNode, List lVar, List lBind) { return before(q, e1, e2, lNode, lVar, lBind); } - protected boolean before(Query q, Exp e1, Exp e2, List lNode, List lVar, List lBind) { + protected boolean before(QueryPlan q, Exp e1, Exp e2, List lNode, List lVar, List lBind) { int n1 = e1.nBind(lNode, lVar, lBind); int n2 = e2.nBind(lNode, lVar, lBind); @@ -86,7 +86,7 @@ protected boolean before(Query q, Exp e1, Exp e2, List lNode, List /** * Edge with node in bindings has advantage */ - protected boolean beforeBind(Query q, Exp e2, Exp e1) { + protected boolean beforeBind(QueryPlan q, Exp e2, Exp e1) { Mappings list = q.getActualMappings(); if (list != null && !list.isEmpty()) { Mapping map = list.get(0); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/HeuristicPatternOrdering.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/HeuristicPatternOrdering.java index 86557b073..7d1ae637f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/HeuristicPatternOrdering.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/HeuristicPatternOrdering.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.engine.planning; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.ExpType; @@ -32,7 +32,7 @@ public class HeuristicPatternOrdering extends ConnectedPatternOrdering { * @param bindings constant-binding hints * @param statistics producer's statistics capability */ - public void sort(Query query, Node graph, Exp expression, List variables, + public void sort(QueryPlan query, Node graph, Exp expression, List variables, List bindings, QueryStatistics statistics) { CardinalityPatternOrdering.sort(query, graph, expression, variables, bindings, statistics); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryPlanner.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryPlanner.java index 199be6830..a77c1a238 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryPlanner.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryPlanner.java @@ -5,7 +5,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Filter; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Producer; import fr.inria.corese.core.next.query.impl.engine.filter.FilterOptimizer; @@ -23,21 +23,21 @@ public final class QueryPlanner implements ExpType { private final HeuristicPatternOrdering sort = new HeuristicPatternOrdering(); - private final Query query; + private final QueryPlan query; private final FilterOptimizer compiler; private Producer prod; - private Query statisticsQuery; + private QueryPlan statisticsQuery; private Node statisticsGraph; // Assign sorter according to query plan profile - public QueryPlanner(Query q) { + public QueryPlanner(QueryPlan q) { query = q; compiler = new FilterOptimizer(q); statisticsQuery = q; } /** - * Contract: For each BGP: Sort Query Edges Insert Filters at first place + * Contract: For each BGP: Sort QueryPlan Edges Insert Filters at first place * where variables are bound This must be recursively done for exists {} * pattern in filter and bind including select, order by, group by and * having @@ -58,7 +58,7 @@ void compile(Filter f) { /** * FilterOptimizer additional filters that may contain exists {}. */ - void modifier(Query q) { + void modifier(QueryPlan q) { compile(q.getSelectFun()); compile(q.getOrderBy()); compile(q.getGroupBy()); @@ -77,7 +77,7 @@ void modifier(Query q) { * the List of variables already bound */ Exp compile(Exp exp, VString varList, boolean option) { - Query previousQuery = statisticsQuery; + QueryPlan previousQuery = statisticsQuery; Node previousGraph = statisticsGraph; if (exp.isQuery() && exp.getQuery().isDatasetSpecified()) { statisticsQuery = exp.getQuery(); @@ -107,7 +107,7 @@ private Exp compileExpression(Exp exp, VString varList, boolean option) { case QUERY: // match query and subquery - Query q = exp.getQuery(); + QueryPlan q = exp.getQuery(); modifier(q); if (!varList.isEmpty()) { // lVar = intersection(select variables,lVar) @@ -121,7 +121,7 @@ private Exp compileExpression(Exp exp, VString varList, boolean option) { option = true; } - // Query planning + // QueryPlan planning exp = queryPlan(exp, varList); int size = varList.size(); @@ -150,7 +150,7 @@ private Exp compileExpression(Exp exp, VString varList, boolean option) { return exp; } - VString getSelectVariables(Query q, VString lVar) { + VString getSelectVariables(QueryPlan q, VString lVar) { VString list = new VString(); for (Exp ee : q.getSelectFun()) { Node node = ee.getNode(); @@ -172,11 +172,11 @@ Exp queryPlan(Exp exp, VString lVar) { // sort edges wrt connection switch (getQuery().getPlanProfile()) { - case Query.QP_T0: + case QueryPlan.QP_T0: sortFilter(exp, lVar); break; - case Query.QP_BGP, Query.QP_DEFAULT, Query.QP_HEURISTICS_BASED: + case QueryPlan.QP_BGP, QueryPlan.QP_DEFAULT, QueryPlan.QP_HEURISTICS_BASED: orderPatterns(exp, lVar, lBind); // move filters sortFilter(exp, lVar); @@ -195,7 +195,7 @@ Exp queryPlan(Exp exp, VString lVar) { private void orderPatterns(Exp exp, List variables, List bindings) { if (getProducer() instanceof QueryStatistics statistics) { sort.sort(statisticsQuery, statisticsGraph, exp, variables, bindings, statistics); - } else if (getQuery().getPlanProfile() == Query.QP_HEURISTICS_BASED) { + } else if (getQuery().getPlanProfile() == QueryPlan.QP_HEURISTICS_BASED) { sort.sort(exp, bindings, getProducer()); } else { sort.sort(getQuery(), exp, variables, bindings); @@ -243,7 +243,7 @@ void graph(Exp exp) { exp.setNodeList(exp.getInScopeNodes()); } - void setBind(Query q, Exp exp){ + void setBind(QueryPlan q, Exp exp){ if (q.isUseBind()){ exp.setBind(); } @@ -444,7 +444,7 @@ void service(Exp exp, int nbService) { } } - public Query getQuery() { + public QueryPlan getQuery() { return query; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryStatistics.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryStatistics.java index 0c604af60..ce9e178f4 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryStatistics.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/planning/QueryStatistics.java @@ -3,7 +3,7 @@ import fr.inria.corese.core.next.data.api.term.IRI; import fr.inria.corese.core.next.query.impl.engine.model.Edge; import fr.inria.corese.core.next.query.impl.engine.model.Node; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.storage.api.model.PredicateStatistics; import fr.inria.corese.core.next.storage.api.model.StorageStatistics; @@ -28,7 +28,7 @@ public interface QueryStatistics { * @param edge triple pattern whose constants constrain the estimate * @return nonnegative cardinality, or {@link #UNKNOWN_CARDINALITY} if unavailable */ - default long estimateCardinality(Query query, Node graphNode, Edge edge) { + default long estimateCardinality(QueryPlan query, Node graphNode, Edge edge) { return UNKNOWN_CARDINALITY; } @@ -61,7 +61,7 @@ default int getCount(QueryPlanNode node, int type) { * @param predicate the predicate IRI to inspect * @return predicate statistics or {@code null} if unavailable */ - default PredicateStatistics getPredicateStatistics(Query query, Node graphNode, IRI predicate) { + default PredicateStatistics getPredicateStatistics(QueryPlan query, Node graphNode, IRI predicate) { return null; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/GroupAggregator.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/GroupAggregator.java index 42cd17968..9dac9bc0f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/GroupAggregator.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/GroupAggregator.java @@ -1,6 +1,6 @@ package fr.inria.corese.core.next.query.impl.engine.solution; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; /** * Strategy interface for direct group aggregation without general expression evaluation. @@ -15,5 +15,5 @@ public interface GroupAggregator { * @param mappings input mappings to reduce * @return {@code true} if aggregation succeeded, {@code false} if ordinary evaluation is required */ - boolean tryAggregate(Query query, Mappings mappings); + boolean tryAggregate(QueryPlan query, Mappings mappings); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mapping.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mapping.java index fc6d65363..cc239f828 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mapping.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mapping.java @@ -11,7 +11,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.PointerType; import fr.inria.corese.core.next.query.impl.engine.model.Pointerable; import fr.inria.corese.core.next.query.impl.engine.model.TripleStore; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.path.Path; import fr.inria.corese.core.next.query.impl.engine.eval.EnvironmentImpl; @@ -100,7 +100,7 @@ public Mapping(List q, List t) { init(q, t); } - static Mapping fake(Query q) { + static Mapping fake(QueryPlan q) { Mapping m = new Mapping(); m.setOrderBy(new Node[q.getOrderBy().size()]); m.setGroupBy(new Node[q.getGroupBy().size()]); @@ -192,7 +192,7 @@ public int size() { /** * Project on select variables of query Modify this Mapping */ - public void project(Query q) { + public void project(QueryPlan q) { ArrayList lqNodes = new ArrayList<>(); ArrayList ltNodes = new ArrayList<>(); @@ -217,11 +217,11 @@ void setMappings(Mappings l) { } @Override - public Query getQuery() { + public QueryPlan getQuery() { return query; } - public void setQuery(Query q) { + public void setQuery(QueryPlan q) { query = q; } @@ -384,7 +384,7 @@ public Mapping project(Node q) { } // Note: manage Node isPath - public void fixQueryNodes(Query q) { + public void fixQueryNodes(QueryPlan q) { for (int i = 0; i < getQueryNodes().length; i++) { Node node = getQueryNodes()[i]; Node qnode = q.getOuterNodeSelf(node); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mappings.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mappings.java index 218f47815..c9c947fd2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mappings.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Mappings.java @@ -12,7 +12,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.TripleStore; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.pattern.Group; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; import fr.inria.corese.core.next.query.impl.engine.spi.Evaluator; @@ -54,7 +54,7 @@ public final class Mappings extends PointerObject boolean isListGroup = false; boolean sortWithDesc = true; int count = 0; - private Query query; + private QueryPlan query; private final List list; // Original join Mappings // use case: union manage its own way @@ -104,16 +104,16 @@ public Mappings() { link = new ArrayList<>(); } - Mappings(Query q) { + Mappings(QueryPlan q) { this(); query = q; } - public static Mappings create(Query q) { + public static Mappings create(QueryPlan q) { return create(q, false); } - public static Mappings create(Query q, boolean subEval) { + public static Mappings create(QueryPlan q, boolean subEval) { Mappings lMap = new Mappings(q); lMap.init(q, subEval); return lMap; @@ -130,15 +130,15 @@ public String getDatatypeLabel() { return String.format("[Mappings: size=%s]", size()); } - void init(Query q, boolean subEval) { + void init(QueryPlan q, boolean subEval) { initiate(q, !subEval && q.isDistinct() && !q.isDistinctRedundantWithGroupBy()); } - void initiate(Query q, boolean b) { + void initiate(QueryPlan q, boolean b) { initiate(q, b, false); } - void initiate(Query q, boolean b, boolean all) { + void initiate(QueryPlan q, boolean b, boolean all) { this.setQuery(q); isDistinct = b; isListGroup = q.isListGroup(); @@ -157,7 +157,7 @@ void initiate(Query q, boolean b, boolean all) { // use case: service require distinct mappings for bindings // for variables in body of q, not for select (exp as var) - List getAllExpList(Query q) { + List getAllExpList(QueryPlan q) { // variables in body of q List nodesFromPattern = q.selectNodesFromPattern(); if (nodesFromPattern.isEmpty()) { @@ -246,11 +246,11 @@ public void clear() { } @Override - public Query getQuery() { + public QueryPlan getQuery() { return query; } - public Mappings setQuery(Query q) { + public Mappings setQuery(QueryPlan q) { query = q; return this; } @@ -636,7 +636,7 @@ public void aggregate(Evaluator evaluator, Memory memory, Producer p) { aggregate(getQuery(), evaluator, memory, p); } - public void aggregate(Query q, Evaluator evaluator, Memory memory, Producer p) { + public void aggregate(QueryPlan q, Evaluator evaluator, Memory memory, Producer p) { if (size() == 0) { if (q.isAggregate() && !q.hasGroupBy()) { // SPARQL semantics requires that aggregate empty result set return one empty result @@ -672,7 +672,7 @@ public void aggregate(Query q, Evaluator evaluator, Memory memory, Producer p) { * select (aggregate() as ?c) * order by aggregate() */ - void aggregateExpList(Query q, Evaluator evaluator, Memory memory, Producer p, List list, boolean isSelect) { + void aggregateExpList(QueryPlan q, Evaluator evaluator, Memory memory, Producer p, List list, boolean isSelect) { int n = 0; for (Exp exp : list) { if (exp.isAggregate()) { @@ -688,7 +688,7 @@ void aggregateExpList(Query q, Evaluator evaluator, Memory memory, Producer p, L /** * select count(?doc) as ?count group by ?person ?date order by ?count */ - private void aggregateSwitch(Query q, Evaluator eval, Exp exp, Memory mem, Producer p, int n) { + private void aggregateSwitch(QueryPlan q, Evaluator eval, Exp exp, Memory mem, Producer p, int n) { if (exp.isExpGroupBy()) { // min(?l, groupBy(?x, ?y)) as ?min evalGroupByExp(eval, exp, mem, p, n); @@ -780,7 +780,7 @@ private void aggregateGroupMembers(Group group, Evaluator eval, Exp exp, Memory } } - void finish(Query qq) { + void finish(QueryPlan qq) { if (qq.hasGroupBy() && !qq.isConstruct()) { // after group by (and aggregate), leave one Mapping for each group // with result of the group @@ -810,7 +810,7 @@ void clean() { } } - public void prepareAggregate(Mapping map, Query q, Map bn, int n) { + public void prepareAggregate(Mapping map, QueryPlan q, Map bn, int n) { setCount(n); // in case there is a nested aggregate, map will be an Environment // it must implement aggregate() and hence must know current Mappings group diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Memory.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Memory.java index c5a088915..101e48876 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Memory.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/Memory.java @@ -13,7 +13,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Filter; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; import fr.inria.corese.core.next.query.impl.engine.spi.Evaluator; import fr.inria.corese.core.next.query.impl.engine.spi.Matcher; @@ -60,7 +60,7 @@ public class Memory extends PointerObject implements Environment { // hence must clear bnodes after each solution Map bnode; // query or sub query - Query query; + QueryPlan query; Node gNode; // to evaluate aggregates such as count(?x) Mappings results; @@ -109,7 +109,7 @@ public Memory setResults(Mappings r) { } @Override - public Query getQuery() { + public QueryPlan getQuery() { return query; } @@ -151,7 +151,7 @@ public void init(Memory memory) { setEval(memory.getEval()); } - public Memory init(Query q) { + public Memory init(QueryPlan q) { // store (sub) query query = q; if (q.isSubQuery()) { @@ -235,7 +235,7 @@ Node getNode(String name, List list) { * Note: let ( .., exists pattern), * MUST push BGP solution and then push Bind */ - public void copyInto(Query sub, Memory mem, Exp exp) { + public void copyInto(QueryPlan sub, Memory mem, Exp exp) { if (sub == null) { // exists pattern copyInto(mem, exp); @@ -337,7 +337,7 @@ void copyInto(Node qNode, Memory mem) { * @param subEvaluation whether the solution belongs to an intermediate graph pattern * @return captured solution, or null when a projection conflicts with a binding */ - public Mapping store(Query query, Producer producer, boolean subEvaluation) { + public Mapping store(QueryPlan query, Producer producer, boolean subEvaluation) { return new SolutionMaterializer(this).materialize(query, producer, subEvaluation); } @@ -488,7 +488,7 @@ public boolean push(Node node, Node target, int n) { return true; } - // Query node already bound but target not equal to binding + // QueryPlan node already bound but target not equal to binding // also process use case: ?x ?p ?p return false; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/SolutionMaterializer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/SolutionMaterializer.java index 0b2665371..92eac9dd2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/SolutionMaterializer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/solution/SolutionMaterializer.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Filter; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Producer; import java.util.List; @@ -27,7 +27,7 @@ final class SolutionMaterializer { this.memory = Objects.requireNonNull(memory, "memory"); } - Mapping materialize(Query query, Producer producer, boolean subEvaluation) { + Mapping materialize(QueryPlan query, Producer producer, boolean subEvaluation) { Node reportNode = bindServiceReport(); int capacity = solutionNodeCapacity(query, subEvaluation); Edge[] queryEdgeCopies = memory.isEdge ? new Edge[memory.nbEdge] : EMPTY_EDGES; @@ -74,7 +74,7 @@ private Node bindServiceReport() { return reportNode; } - private int solutionNodeCapacity(Query query, boolean subEvaluation) { + private int solutionNodeCapacity(QueryPlan query, boolean subEvaluation) { int capacity = memory.nbNode; if (!subEvaluation) { for (Exp projection : query.getSelectFun()) { @@ -112,7 +112,7 @@ private int copySolutionNodes(Node[] queryNodeCopies, Node[] targetNodeCopies) { return targetIndex; } - private boolean projectSolution(Query query, Producer producer, Node[] queryNodeCopies, + private boolean projectSolution(QueryPlan query, Producer producer, Node[] queryNodeCopies, Node[] targetNodeCopies, int targetIndex) { int pushedBindings = 0; int currentIndex = targetIndex; @@ -159,7 +159,7 @@ private ProjectionResult applySingleProjection(Exp projection, Producer producer return new ProjectionResult(true, pushed, !previouslyBound, value); } - private void popProjectionPrefix(Query query, int count) { + private void popProjectionPrefix(QueryPlan query, int count) { int popped = 0; for (Exp projection : query.getSelectFun()) { if (popped >= count) { @@ -172,7 +172,7 @@ private void popProjectionPrefix(Query query, int count) { } } - private void popProjectionBindings(Query query) { + private void popProjectionBindings(QueryPlan query) { for (Exp projection : query.getSelectFun()) { if (projection.getFilter() != null && !projection.isAggregate()) { memory.pop(projection.getNode()); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Environment.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Environment.java index 5ff4a01b9..ee706f472 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Environment.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Environment.java @@ -3,7 +3,7 @@ import fr.inria.corese.core.next.query.impl.engine.eval.Eval; import fr.inria.corese.core.next.query.impl.engine.event.ProcessVisitor; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -29,7 +29,7 @@ public interface Environment { * Return current query * */ - Query getQuery(); + QueryPlan getQuery(); BindingContext getBind(); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Producer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Producer.java index 2ac319644..e3b58c028 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Producer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/spi/Producer.java @@ -8,7 +8,7 @@ import fr.inria.corese.core.next.data.api.model.DatatypeValue; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import java.util.List; @@ -27,14 +27,14 @@ public interface Producer { * KGRAM calls this method before executing a query. It enables to * initialize the Producer */ - default void init(Query q) { + default void init(QueryPlan q) { // Optional lifecycle hook for producer implementations. } - default void start(Query q) { + default void start(QueryPlan q) { } - default void finish(Query q) { + default void finish(QueryPlan q) { } int getMode(); @@ -134,7 +134,7 @@ default void closeEdges(Iterable edges) { Producer getProducer(Node node, Environment env); // use case: Producer created for a specific query - Query getQuery(); + QueryPlan getQuery(); // May return an object that implement the RDF graph Graph getGraph(); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/ProducerDefault.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/ProducerDefault.java index 40f7564f8..8a50c4157 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/ProducerDefault.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/ProducerDefault.java @@ -10,7 +10,7 @@ import fr.inria.corese.core.next.query.impl.engine.spi.Producer; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import java.util.ArrayList; import java.util.List; @@ -71,7 +71,7 @@ public Producer getProducer(Node node, Environment env) { } @Override - public Query getQuery() { + public QueryPlan getQuery() { return null; } @@ -122,12 +122,12 @@ public void close() { } @Override - public void start(Query q) { + public void start(QueryPlan q) { throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } @Override - public void finish(Query q) { + public void finish(QueryPlan q) { throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageBindingEnvironment.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageBindingEnvironment.java index e7f255235..45211be8a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageBindingEnvironment.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageBindingEnvironment.java @@ -9,7 +9,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.path.Path; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; @@ -48,7 +48,7 @@ public boolean isBound(Node queryNode) { } @Override - public Query getQuery() { + public QueryPlan getQuery() { return delegate == null ? null : delegate.getQuery(); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducer.java index ca228e26e..89f9acb18 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducer.java @@ -12,7 +12,7 @@ import fr.inria.corese.core.next.query.impl.engine.path.NativePropertyPathEvaluator; import fr.inria.corese.core.next.query.impl.engine.path.PropertyPathEdge; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.planning.QueryStatistics; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; @@ -78,7 +78,7 @@ public StorageManagerProducer(StorageManager storage) { * @return matching statement count, or unknown for paths and variable graphs */ @Override - public long estimateCardinality(Query query, Node graphNode, Edge edge) { + public long estimateCardinality(QueryPlan query, Node graphNode, Edge edge) { if (edge instanceof PropertyPathEdge || graphNode != null && graphNode.isVariable()) { return UNKNOWN_CARDINALITY; } @@ -99,7 +99,7 @@ public long estimateCardinality(Query query, Node graphNode, Edge edge) { } @Override - public PredicateStatistics getPredicateStatistics(Query query, Node graphNode, IRI predicate) { + public PredicateStatistics getPredicateStatistics(QueryPlan query, Node graphNode, IRI predicate) { if (predicate == null || closed) { return null; } @@ -169,7 +169,7 @@ public Iterator iterator() { synchronized (cursors) { checkInterrupted(); if (closed) { - throw new QueryEvaluationException("Query producer is closed"); + throw new QueryEvaluationException("QueryPlan producer is closed"); } cursor = new EdgeCursor(storage.queries().find(pattern), deduplicate); cursors.add(cursor); @@ -290,7 +290,7 @@ private static void closeAfterFailure(Runnable release, Throwable failure) { private static void checkInterrupted() { if (Thread.currentThread().isInterrupted()) { - throw new QueryEvaluationException("Query evaluation was interrupted"); + throw new QueryEvaluationException("QueryPlan evaluation was interrupted"); } } @@ -354,12 +354,12 @@ public Iterable getGraphNodes(Node graphNode, List from, Environment } @Override - public void start(Query query) { + public void start(QueryPlan query) { // Cursors are registered when their iterators are opened. } @Override - public void finish(Query query) { + public void finish(QueryPlan query) { closeCursors(false); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java index 19098eebf..3b2dd7ace 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java @@ -5,7 +5,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstructQueryAst; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstructTemplateAst; import fr.inria.corese.core.next.query.impl.sparql.ast.SolutionModifierAst; @@ -30,7 +30,7 @@ private ConstructQueryCompiler() { * @param constructQueryAst AST of the CONSTRUCT query * @param compiler where compiler carrying the query prologue */ - static void compile(Query query, ConstructQueryAst constructQueryAst, WhereCompiler compiler) { + static void compile(QueryPlan query, ConstructQueryAst constructQueryAst, WhereCompiler compiler) { Objects.requireNonNull(query, "query"); Objects.requireNonNull(constructQueryAst, "constructQueryAst"); Objects.requireNonNull(compiler, "compiler"); @@ -61,7 +61,7 @@ private static void rejectUnsupportedConstructClauses(ConstructQueryAst construc * from the {@code WHERE} body and carried by {@link Query#setConstruct(Exp)}. */ private static Exp compileConstructTemplate( - Query query, ConstructTemplateAst template, WhereCompiler compiler) { + QueryPlan query, ConstructTemplateAst template, WhereCompiler compiler) { Exp bgp = Exp.create(Type.BGP); for (TriplePatternAst triple : template.triplePatternAsts()) { Node subject = constructNode(query, triple.subject(), compiler); @@ -80,7 +80,7 @@ private static Exp compileConstructTemplate( * labels become existential (blank-variable) nodes that generate a fresh blank node per solution, * as required by the SPARQL specification. IRIs and literals become fresh constant nodes. */ - private static Node constructNode(Query query, TermAst term, WhereCompiler compiler) { + private static Node constructNode(QueryPlan query, TermAst term, WhereCompiler compiler) { if (term instanceof VarAst(String name)) { Node bound = visibleBodyNode(query, name); return bound != null ? bound : NodeImpl.forVariable(name); @@ -90,7 +90,7 @@ private static Node constructNode(Query query, TermAst term, WhereCompiler compi return compiler.termResolver().toPatternNode(term); } - private static Node visibleBodyNode(Query query, String name) { + private static Node visibleBodyNode(QueryPlan query, String name) { for (Node node : query.selectNodesFromPattern()) { if (node.getLabel().equals(name)) { return node; diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java index a016255c2..d36571dc7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java @@ -5,7 +5,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Filter; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.sparql.ast.AskQueryAst; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstructQueryAst; @@ -59,12 +59,12 @@ public CoreseAstQueryBuilder() { * {@code LIMIT}, {@code OFFSET}). Clauses that require dedicated aggregate or * values handling are rejected explicitly.

*/ - public Query toNextQuery(AskQueryAst askQueryAst) { + public QueryPlan toNextQuery(AskQueryAst askQueryAst) { Objects.requireNonNull(askQueryAst, "askQueryAst"); rejectUnsupportedAskClauses(askQueryAst); WhereCompiler compiler = whereCompiler.withPrologue(askQueryAst.prologue()); - Query query = createQuery( + QueryPlan query = createQuery( askQueryAst.whereClause(), askQueryAst.datasetClause(), askQueryAst.solutionModifier(), @@ -84,11 +84,11 @@ public Query toNextQuery(AskQueryAst askQueryAst) { * Clauses that require dedicated aggregate, alias, or values handling are rejected * explicitly.

*/ - public Query toNextQuery(SelectQueryAst selectQueryAst) { + public QueryPlan toNextQuery(SelectQueryAst selectQueryAst) { Objects.requireNonNull(selectQueryAst, "selectQueryAst"); WhereCompiler compiler = whereCompiler.withPrologue(selectQueryAst.prologue()); - Query query = createQuery( + QueryPlan query = createQuery( selectQueryAst.whereClause(), selectQueryAst.datasetClause(), selectQueryAst.solutionModifier(), @@ -116,12 +116,12 @@ public Query toNextQuery(SelectQueryAst selectQueryAst) { * nodes of the body, matching {@code SELECT *}. Clauses that require dedicated aggregate or * values handling are rejected explicitly.

*/ - public Query toNextQuery(DescribeQueryAst describeQueryAst) { + public QueryPlan toNextQuery(DescribeQueryAst describeQueryAst) { Objects.requireNonNull(describeQueryAst, "describeQueryAst"); rejectUnsupportedDescribeClauses(describeQueryAst); WhereCompiler compiler = whereCompiler.withPrologue(describeQueryAst.prologue()); - Query query = createQuery( + QueryPlan query = createQuery( describeQueryAst.whereClause(), describeQueryAst.datasetClause(), describeQueryAst.solutionModifier(), @@ -142,11 +142,11 @@ public Query toNextQuery(DescribeQueryAst describeQueryAst) { * valid SPARQL, its triple is simply skipped at instantiation time). Clauses that require * dedicated aggregate or values handling are rejected explicitly.

*/ - public Query toNextQuery(ConstructQueryAst constructQueryAst) { + public QueryPlan toNextQuery(ConstructQueryAst constructQueryAst) { Objects.requireNonNull(constructQueryAst, "constructQueryAst"); WhereCompiler compiler = whereCompiler.withPrologue(constructQueryAst.prologue()); - Query query = createQuery( + QueryPlan query = createQuery( constructQueryAst.whereClause(), constructQueryAst.datasetClause(), constructQueryAst.solutionModifier(), @@ -212,7 +212,7 @@ private static void rejectUnsupportedDescribeClauses(DescribeQueryAst describeQu * and limit/offset information, and finally collects visible nodes so later clauses * can resolve variables against the runtime body.

*/ - private Query createQuery( + private QueryPlan createQuery( GroupGraphPatternAst whereClause, DatasetClauseAst datasetClause, SolutionModifierAst solutionModifier, @@ -223,7 +223,7 @@ private Query createQuery( body = Exp.create(Type.JOIN, body, compiler.compileValues(valuesClause)); } - Query query = Query.create(body); + QueryPlan query = QueryPlan.create(body); // Collect visible nodes once so later clauses (projection, ORDER BY, DESCRIBE) // can resolve variables against the compiled runtime body. query.collect(); @@ -232,7 +232,7 @@ private Query createQuery( return query; } - private void applyDataset(Query query, DatasetClauseAst datasetClause, WhereCompiler compiler) { + private void applyDataset(QueryPlan query, DatasetClauseAst datasetClause, WhereCompiler compiler) { query.setFrom(toNodeList(datasetClause.graphs(), compiler)); query.setNamed(toNodeList(datasetClause.namedGraphs(), compiler)); query.setDatasetSpecified( diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DescribeQueryCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DescribeQueryCompiler.java index f4db7b23d..ea230c862 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DescribeQueryCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DescribeQueryCompiler.java @@ -4,7 +4,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.sparql.ast.DescribeQueryAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst; @@ -25,7 +25,7 @@ private DescribeQueryCompiler() { * @param compiler compiler carrying the query prologue * @throws IllegalArgumentException if a described variable is not visible */ - static void compile(Query query, DescribeQueryAst description, WhereCompiler compiler) { + static void compile(QueryPlan query, DescribeQueryAst description, WhereCompiler compiler) { lowerDescribeToConstructQuery(query, describeNodes(query, description, compiler)); } @@ -37,7 +37,7 @@ static void compile(Query query, DescribeQueryAst description, WhereCompiler com * fails fast when it is not visible; a described IRI becomes a fresh constant node.

*/ private static List describeNodes( - Query query, DescribeQueryAst describeQueryAst, WhereCompiler compiler) { + QueryPlan query, DescribeQueryAst describeQueryAst, WhereCompiler compiler) { if (describeQueryAst.isDescribeAll()) { return query.selectNodesFromPattern(); } @@ -66,7 +66,7 @@ private static List describeNodes( *

This keeps the current KGRAM contract, inherited from the historical pipeline: * {@code DESCRIBE} is executed through the construct runtime path.

*/ - private static void lowerDescribeToConstructQuery(Query query, List describedNodes) { + private static void lowerDescribeToConstructQuery(QueryPlan query, List describedNodes) { Exp constructTemplate = Exp.create(Type.BGP); int syntheticIndex = 0; for (Node describedNode : describedNodes) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregation.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregation.java index f06651f56..1a2b5df78 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregation.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregation.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.GroupAggregator; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -45,7 +45,7 @@ private DirectGroupAggregation() { } /** Returns whether the query can be reduced without evaluating expressions. */ - public static boolean isEligible(Query query) { + public static boolean isEligible(QueryPlan query) { if (!query.isSelect() || (query.isDistinct() && !query.isDistinctRedundantWithGroupBy()) || query.isListGroup() || query.getGroupBy().isEmpty() || query.getHaving() != null || !query.getOrderBy().isEmpty()) { @@ -62,7 +62,7 @@ private static boolean isPlainGroup(Exp expression) { && expression.getFilter() == null && !expression.isExpGroupBy(); } - private static boolean eligibleProjections(Query query) { + private static boolean eligibleProjections(QueryPlan query) { boolean hasAggregate = false; for (Exp projection : query.getSelectFun()) { if (projection.isExpGroupBy() || projection.getNode() == null) { @@ -102,7 +102,7 @@ private static AggregateAst simpleAggregate(Exp projection) { * @return false when ineligible, leaving input mappings untouched; true after * successful reduction, including an empty grouped input */ - public static boolean tryAggregate(Query query, Mappings mappings) { + public static boolean tryAggregate(QueryPlan query, Mappings mappings) { if (!isEligible(query) || mappings.isFake() || mappings.getGroup() != null) { return false; } @@ -122,7 +122,7 @@ public static boolean tryAggregate(Query query, Mappings mappings) { return true; } - private static List projections(Query query) { + private static List projections(QueryPlan query) { List projections = new ArrayList<>(); for (Exp expression : query.getSelectFun()) { if (expression.isAggregate()) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java index 2773e503b..a25fa035e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java @@ -5,7 +5,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.sparql.ast.ASTConstants; import fr.inria.corese.core.next.query.impl.sparql.ast.GroupByAst; import fr.inria.corese.core.next.query.impl.sparql.ast.HavingAst; @@ -41,7 +41,7 @@ private SolutionModifierCompiler() { * query body. An explicit projection reuses these same runtime nodes and fails * fast when a projected variable is not visible in the body.

*/ - static void applyProjection(Query query, ProjectionAst projection, WhereCompiler compiler) { + static void applyProjection(QueryPlan query, ProjectionAst projection, WhereCompiler compiler) { List selectExpressions = projection.selectAll() ? toNodeExpressions(query.selectNodesFromPattern()) : buildExplicitProjection(query, projection, compiler); @@ -52,7 +52,7 @@ static void applyProjection(Query query, ProjectionAst projection, WhereCompiler } static void applyGroupBy( - Query query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { + QueryPlan query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { if (!solutionModifier.hasGroupBy()) { return; } @@ -68,7 +68,7 @@ static void applyGroupBy( } static void applyHaving( - Query query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { + QueryPlan query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { if (!solutionModifier.hasHaving()) { return; } @@ -90,7 +90,7 @@ static void applyHaving( * filters and attached to synthetic internal nodes, just like the historical pipeline does.

*/ static void applyOrderBy( - Query query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { + QueryPlan query, SolutionModifierAst solutionModifier, WhereCompiler compiler) { if (!solutionModifier.hasOrderBy()) { return; } @@ -104,7 +104,7 @@ static void applyOrderBy( query.setOrderBy(orderByExpressions); } - static void applyLimitOffset(Query query, SolutionModifierAst solutionModifier) { + static void applyLimitOffset(QueryPlan query, SolutionModifierAst solutionModifier) { if (solutionModifier.hasLimit()) { query.setLimit(Math.toIntExact(solutionModifier.limit())); } @@ -114,7 +114,7 @@ static void applyLimitOffset(Query query, SolutionModifierAst solutionModifier) } private static List buildExplicitProjection( - Query query, ProjectionAst projection, WhereCompiler compiler) { + QueryPlan query, ProjectionAst projection, WhereCompiler compiler) { List selectExpressions = new ArrayList<>(); for (VarAst variable : projection.variables()) { TermAst expression = projection.expressionTerms().get(variable.name()); @@ -136,12 +136,12 @@ private static Exp buildProjectedExpression( return selected; } - private static Exp buildProjectedVariable(Query query, VarAst variable) { + private static Exp buildProjectedVariable(QueryPlan query, VarAst variable) { Node node = resolveProjectedNode(query, variable.name()); return Exp.create(Type.NODE, node); } - private static Node resolveProjectedNode(Query query, String name) { + private static Node resolveProjectedNode(QueryPlan query, String name) { Node node = visibleBodyNode(query, name); if (node == null) { node = groupByNode(query, name); @@ -180,7 +180,7 @@ private static boolean shouldMarkAsAggregate(Exp exp, List selectExpression } private static Exp toGroupByExpression( - Query query, + QueryPlan query, GroupByAst groupByAst, TermAst term, int syntheticIndex, @@ -221,7 +221,7 @@ private static Node createSyntheticGroupByNode(int syntheticIndex) { } private static Exp toOrderByExpression( - Query query, + QueryPlan query, OrderConditionAst orderCondition, int syntheticIndex, WhereCompiler compiler) { @@ -232,7 +232,7 @@ private static Exp toOrderByExpression( return toOrderBySyntheticExpression(query, expression, syntheticIndex, compiler); } - private static Exp toOrderByVarExpression(Query query, String name) { + private static Exp toOrderByVarExpression(QueryPlan query, String name) { Exp selectExpression = query.getSelectExp(name); Node node = selectExpression != null ? selectExpression.getNode() : resolveOrderByFallbackNode(query, name); if (node == null) { @@ -246,13 +246,13 @@ private static Exp toOrderByVarExpression(Query query, String name) { return orderExp; } - private static Node resolveOrderByFallbackNode(Query query, String name) { + private static Node resolveOrderByFallbackNode(QueryPlan query, String name) { Node groupNode = groupByNode(query, name); return groupNode != null ? groupNode : visibleBodyNode(query, name); } private static Exp toOrderBySyntheticExpression( - Query query, + QueryPlan query, TermAst expression, int syntheticIndex, WhereCompiler compiler) { @@ -265,7 +265,7 @@ private static Exp toOrderBySyntheticExpression( return exp; } - private static boolean isOrderByAggregate(Query query, TermAst expression, Filter filter) { + private static boolean isOrderByAggregate(QueryPlan query, TermAst expression, Filter filter) { if (new VariableScopeAnalyzer().containsAggregate(expression)) { return true; } @@ -302,7 +302,7 @@ private static List selectNodeList(List selectExpressions) { return new ArrayList<>(selectNodes); } - private static Node groupByNode(Query query, String name) { + private static Node groupByNode(QueryPlan query, String name) { if (query.getGroupBy() == null) { return null; } @@ -319,7 +319,7 @@ private static Node groupByNode(Query query, String name) { * excludes nodes collected from MINUS/EXISTS bodies, which KGRAM stores as query * nodes for internal evaluation but which are not projectable SPARQL bindings. */ - private static Node visibleBodyNode(Query query, String name) { + private static Node visibleBodyNode(QueryPlan query, String name) { for (Node node : query.selectNodesFromPattern()) { if (node.getLabel().equals(name)) { return node; diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java index 4e8760d1d..df1d4e95e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java @@ -31,7 +31,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Filter; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -296,7 +296,7 @@ Exp compileValues(ValuesAst values) { private Exp compileService(ServiceAst service) { Node endpoint = termResolver.toNode(service.endpoint()); Exp endpointNode = Exp.create(Type.NODE, endpoint); - Query body = Query.create(compile(service.pattern())); + QueryPlan body = QueryPlan.create(compile(service.pattern())); body.setService(true); body.setSilent(service.silent()); Exp exp = Exp.create(Type.SERVICE, endpointNode, body); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/PreparedQueryPlan.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/PreparedQueryPlan.java index 7daa6fb0c..d4817cd7d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/PreparedQueryPlan.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/PreparedQueryPlan.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Edge; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.CompiledQueryPlan; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerProducer; import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst; import fr.inria.corese.core.next.storage.api.StorageManager; @@ -31,7 +31,7 @@ public final class PreparedQueryPlan { this.ast = Objects.requireNonNull(ast, "ast"); } - Query resolve(SparqlQueryExecutor executor, StorageManager storage, Dataset dataset, + QueryPlan resolve(SparqlQueryExecutor executor, StorageManager storage, Dataset dataset, ExecutionDiagnostics diagnostics) { long version = storage.queries().getDataVersion(); CachedPlan previous = cached; @@ -39,7 +39,7 @@ Query resolve(SparqlQueryExecutor executor, StorageManager storage, Dataset data && sameDataset(previous.dataset(), dataset)) { return instantiate(previous.plan(), diagnostics); } - Query compiled = executor.compile(ast); + QueryPlan compiled = executor.compile(ast); if (dataset != null) executor.applyDataset(compiled, dataset); RecordingProducer statistics = new RecordingProducer(storage); long started = diagnostics == null ? 0 : System.nanoTime(); @@ -69,9 +69,9 @@ && sameDataset(previous.dataset(), dataset)) { return compiled; } - private static Query instantiate(CompiledQueryPlan image, ExecutionDiagnostics diagnostics) { + private static QueryPlan instantiate(CompiledQueryPlan image, ExecutionDiagnostics diagnostics) { long started = diagnostics == null ? 0 : System.nanoTime(); - Query query = image.newExecution(diagnostics); + QueryPlan query = image.newExecution(diagnostics); if (diagnostics != null) { diagnostics.executionSetupTime(System.nanoTime() - started); diagnostics.reusedPlan(true); @@ -105,7 +105,7 @@ private RecordingProducer(StorageManager storage) { } @Override - public long estimateCardinality(Query query, Node graph, Edge edge) { + public long estimateCardinality(QueryPlan query, Node graph, Edge edge) { long count = super.estimateCardinality(query, graph, edge); counts.put(edge, count); return count; diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java index d2504b2de..4023ddd60 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java @@ -32,7 +32,7 @@ import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.eval.RdfTermMatcher; import fr.inria.corese.core.next.query.impl.engine.eval.SparqlKgramEvaluator; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; @@ -221,7 +221,7 @@ private TupleQueryResult evaluateTuple(ExecutionRequest request, BindingSet bind private TupleQueryResult openTuple(ExecutionRequest request, BindingSet bindings, long timeoutMillis) { long started = System.nanoTime(); - Query query = resolveExecutionQuery(request); + QueryPlan query = resolveExecutionQuery(request); FallbackReason reason = SelectCursor.fallbackReason(query); boolean ordered = reason == FallbackReason.ORDER_BY && SelectCursor.supportsOrderedInput(query); if (reason == FallbackReason.NONE || ordered) { @@ -231,13 +231,13 @@ private TupleQueryResult openTuple(ExecutionRequest request, BindingSet bindings return materializedTuple(request, bindings, timeoutMillis, started); } - private Query resolveExecutionQuery(ExecutionRequest request) { + private QueryPlan resolveExecutionQuery(ExecutionRequest request) { if (request.prepared != null) { return resolve(request, null); } StorageManagerProducer planning = diagnostics == null ? new StorageManagerProducer(storage) : new DiagnosticProducer(storage, diagnostics); - Query query = resolve(request, planning); + QueryPlan query = resolve(request, planning); query.complete(planning); return query; } @@ -256,7 +256,7 @@ private TupleQueryResult snapshotTuple(ExecutionRequest request, BindingSet bind } @SuppressWarnings("java:S1181") // Snapshot ownership is released on fatal setup errors before rethrowing unchanged. - private TupleQueryResult evaluateSnapshotTuple(Query query, BindingSet bindings, + private TupleQueryResult evaluateSnapshotTuple(QueryPlan query, BindingSet bindings, long timeoutMillis, long started, StorageManager snapshot, boolean ordered) { ExecutionSession session = null; StreamingTupleQueryResult result; @@ -371,7 +371,7 @@ public GraphQueryResult evaluateGraph(QueryAst ast, BindingSet bindings, Dataset throw new IllegalArgumentException("Graph evaluation requires a CONSTRUCT or DESCRIBE query, got: " + ast.getClass().getSimpleName()); } - Query kgramQuery = compile(ast); + QueryPlan kgramQuery = compile(ast); Mappings mappings = evaluate(kgramQuery, bindings, dataset, timeoutMillis); List statements = buildConstructStatements(kgramQuery, mappings); return new CoreseGraphQueryResult(statements.iterator()); @@ -381,7 +381,7 @@ public GraphQueryResult evaluateGraph(QueryAst ast, BindingSet bindings, Dataset // Internal evaluation pipeline // ------------------------------------------------------------------------- - Query compile(QueryAst ast) { + QueryPlan compile(QueryAst ast) { if (diagnostics == null) return compileAst(ast); diagnostics.beginWork(); long started = System.nanoTime(); @@ -393,7 +393,7 @@ Query compile(QueryAst ast) { } } - private Query compileAst(QueryAst ast) { + private QueryPlan compileAst(QueryAst ast) { return switch (ast) { case SelectQueryAst select -> queryBuilder.toNextQuery(select); case AskQueryAst ask -> queryBuilder.toNextQuery(ask); @@ -403,7 +403,7 @@ private Query compileAst(QueryAst ast) { }; } - private Mappings evaluate(Query query, BindingSet bindings, Dataset dataset, long timeoutMillis) { + private Mappings evaluate(QueryPlan query, BindingSet bindings, Dataset dataset, long timeoutMillis) { return evaluate(new ExecutionRequest(query, dataset), bindings, timeoutMillis); } @@ -423,7 +423,7 @@ private Mappings evaluate(ExecutionRequest request, BindingSet bindings, long ti private Mappings evaluateCore(Eval eval, ExecutionRequest request, Mapping initialMapping) { try { - Query query = resolve(request, eval.getProducer()); + QueryPlan query = resolve(request, eval.getProducer()); if (diagnostics == null) { return eval.query(null, query, initialMapping); } @@ -436,7 +436,7 @@ private Mappings evaluateCore(Eval eval, ExecutionRequest request, Mapping initi } } - private Query resolve(ExecutionRequest request, fr.inria.corese.core.next.query.impl.engine.spi.Producer producer) { + private QueryPlan resolve(ExecutionRequest request, fr.inria.corese.core.next.query.impl.engine.spi.Producer producer) { if (request.resolved) return request.query; if (request.prepared != null) { request.query = request.prepared.resolve(this, storage, request.dataset, diagnostics); @@ -456,7 +456,7 @@ private Query resolve(ExecutionRequest request, fr.inria.corese.core.next.query. private static final class ExecutionRequest { private final PreparedQueryPlan prepared; private final Dataset dataset; - private Query query; + private QueryPlan query; private boolean resolved; private ExecutionRequest(PreparedQueryPlan prepared, Dataset dataset) { @@ -464,7 +464,7 @@ private ExecutionRequest(PreparedQueryPlan prepared, Dataset dataset) { this.dataset = dataset; } - private ExecutionRequest(Query query, Dataset dataset) { + private ExecutionRequest(QueryPlan query, Dataset dataset) { this.prepared = null; this.query = query; this.dataset = dataset; @@ -565,7 +565,7 @@ private static void finishWatchdog(Thread watchdog, boolean timedOut, boolean in * Triples where any component is unbound or cannot be converted to a valid * RDF term are silently skipped, matching standard SPARQL CONSTRUCT semantics.

*/ - private List buildConstructStatements(Query kgramQuery, Mappings mappings) { + private List buildConstructStatements(QueryPlan kgramQuery, Mappings mappings) { Exp constructTemplate = kgramQuery.getConstruct(); if (constructTemplate == null) { return List.of(); @@ -679,7 +679,7 @@ private Value kgramNodeToApiValue(Node node) { * sets remain significant: for example, a named-only dataset has an empty * default graph.

*/ - void applyDataset(Query kgramQuery, Dataset dataset) { + void applyDataset(QueryPlan kgramQuery, Dataset dataset) { kgramQuery.setFrom(irisToKgramNodes(dataset.getDefaultGraphs())); kgramQuery.setNamed(irisToKgramNodes(dataset.getNamedGraphs())); kgramQuery.setDatasetSpecified(true); @@ -701,7 +701,7 @@ private List irisToKgramNodes(Iterable iris) { /** * Converts an API {@link BindingSet} into a KGRAM {@link Mapping} that can be - * passed to {@link Eval#query(Node, Query, Mapping)} as initial variable bindings. + * passed to {@link Eval#query(Node, QueryPlan, Mapping)} as initial variable bindings. * *

Each binding entry becomes a (variable-node, value-node) pair. The variable * node carries the variable name as its label so that diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/StreamingTupleQueryResult.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/StreamingTupleQueryResult.java index c0956f620..c5ab4a6dd 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/StreamingTupleQueryResult.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/StreamingTupleQueryResult.java @@ -7,7 +7,7 @@ import fr.inria.corese.core.next.query.impl.engine.diagnostics.ExecutionDiagnostics; import fr.inria.corese.core.next.query.impl.engine.eval.SelectCursor; import fr.inria.corese.core.next.query.impl.engine.model.Node; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerProducer; import fr.inria.corese.core.next.storage.api.StorageManager; @@ -58,7 +58,7 @@ private static ScheduledThreadPoolExecutor deadlines() { private BindingSet delivered; private boolean unwound; - StreamingTupleQueryResult(SelectCursor cursor, Query query, + StreamingTupleQueryResult(SelectCursor cursor, QueryPlan query, StorageManagerProducer producer, StorageManager snapshot, ExecutionDiagnostics diagnostics, long timeoutMillis, long started) { this.cursor = cursor; @@ -162,7 +162,7 @@ private boolean beginAdvance() { if (timedOut) throw new QueryTimeoutException(timeoutMillis); if (closed) throw new IllegalStateException("This tuple query result is closed."); if (exhausted) return false; - if (owner.isInterrupted()) throw new QueryEvaluationException("Query interrupted"); + if (owner.isInterrupted()) throw new QueryEvaluationException("QueryPlan interrupted"); advancing = true; return true; } @@ -175,7 +175,7 @@ private void endAdvance() { Thread.interrupted(); throw new QueryTimeoutException(timeoutMillis); } - if (closed) throw new QueryEvaluationException("Query cursor was cancelled"); + if (closed) throw new QueryEvaluationException("QueryPlan cursor was cancelled"); } } @@ -202,7 +202,7 @@ public BindingSet next() { private void checkOwner() { if (Thread.currentThread() != owner) { - throw new IllegalStateException("Query results must be consumed on their creating thread"); + throw new IllegalStateException("QueryPlan results must be consumed on their creating thread"); } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelector.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelector.java index 33bdaea75..e6bd33679 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelector.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelector.java @@ -1,7 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.execution; import fr.inria.corese.core.next.query.impl.engine.eval.Eval; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -31,7 +31,7 @@ final class TopKSelector { * @param query completed eligible ordered SELECT with finite LIMIT plus OFFSET * @param eval evaluator supplying the official Corese ordering comparator */ - TopKSelector(Query query, Eval eval) { + TopKSelector(QueryPlan query, Eval eval) { capacity = Math.addExact(query.getLimit(), query.getOffset()); offset = query.getOffset(); needsInput = query.getLimit() != 0; diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/QueryDeliveryDiagnosticsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/QueryDeliveryDiagnosticsTest.java index dac93de70..a3840d98c 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/QueryDeliveryDiagnosticsTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/diagnostics/QueryDeliveryDiagnosticsTest.java @@ -9,7 +9,7 @@ import fr.inria.corese.core.next.query.impl.engine.eval.SelectCursor; import fr.inria.corese.core.next.query.impl.engine.model.ExpType.Type; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.sparql.execution.SparqlQueryExecutor; import fr.inria.corese.core.next.storage.api.StorageManager; import fr.inria.corese.core.next.storage.api.operations.QueryOperations; @@ -298,9 +298,9 @@ void aTraversalFailureBeforeAnyRowDoesNotClaimAnEmptyResult() { @Test void guardClassificationDoesNotExecuteAnUnsupportedServiceOrExtension() { - assertEquals(FallbackReason.SERVICE, SelectCursor.fallbackReason(Query.create(Exp.create(Type.SERVICE)))); + assertEquals(FallbackReason.SERVICE, SelectCursor.fallbackReason(QueryPlan.create(Exp.create(Type.SERVICE)))); var functional = Exp.create(Type.BIND); functional.setFunctional(true); - assertEquals(FallbackReason.UNSUPPORTED_OPERATOR, SelectCursor.fallbackReason(Query.create(functional))); + assertEquals(FallbackReason.UNSUPPORTED_OPERATOR, SelectCursor.fallbackReason(QueryPlan.create(functional))); } } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalTest.java index aa20102e4..b0d9d693c 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/eval/EvalTest.java @@ -14,7 +14,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.model.BindingContext; import fr.inria.corese.core.next.query.impl.engine.event.ResultListener; import org.junit.jupiter.api.BeforeEach; @@ -428,7 +428,7 @@ void testServiceWithoutProviderThrows() { Stack stack = new Stack(); stack.add(serviceExp); - Query q = Query.create(); + QueryPlan q = QueryPlan.create(); eval.init(q); assertThrows(QueryEvaluationException.class, () -> @@ -445,7 +445,7 @@ void testServiceSilentWithoutProviderBypasses() { Stack stack = new Stack(); stack.add(serviceExp); - Query q = Query.create(); + QueryPlan q = QueryPlan.create(); eval.init(q); assertDoesNotThrow(() -> eval.eval(mockProducer, null, stack, null, 0), diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlanTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlanTest.java index 3e211d0ac..394bb80b3 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlanTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlanTest.java @@ -26,10 +26,10 @@ class CompiledQueryPlanTest { @Test void captureDetachesTheCompilerAndEveryExecutionHasIndependentMutableState() { - Query compiler = query(); + QueryPlan compiler = query(); CompiledQueryPlan image = CompiledQueryPlan.capture(compiler, Map.of()); - Query first = image.newExecution(null); - Query second = image.newExecution(null); + QueryPlan first = image.newExecution(null); + QueryPlan second = image.newExecution(null); assertNotSame(first, second); assertEquals(first.getSelect().size(), second.getSelect().size()); Node firstVariable = first.getSelect().getFirst(); @@ -42,7 +42,7 @@ void captureDetachesTheCompilerAndEveryExecutionHasIndependentMutableState() { compiler.getSelect().clear(); compiler.setLimit(2); assertEquals(compiledIndex, secondVariable.getIndex()); - Query fresh = image.newExecution(null); + QueryPlan fresh = image.newExecution(null); assertEquals(2, fresh.getSelect().size()); assertEquals(Integer.MAX_VALUE, fresh.getLimit()); assertEquals(compiledIndex, fresh.getSelect().getFirst().getIndex()); @@ -52,8 +52,8 @@ void captureDetachesTheCompilerAndEveryExecutionHasIndependentMutableState() { @Test void valuesRowsAndFilterIndexesAreNotShared() { CompiledQueryPlan image = CompiledQueryPlan.capture(query(), Map.of()); - Query first = image.newExecution(null); - Query second = image.newExecution(null); + QueryPlan first = image.newExecution(null); + QueryPlan second = image.newExecution(null); Exp firstValues = operators(first).stream().filter(e -> e.type() == Exp.Type.VALUES).findFirst().orElseThrow(); Exp secondValues = operators(second).stream().filter(e -> e.type() == Exp.Type.VALUES).findFirst().orElseThrow(); assertNotSame(firstValues.getMappings(), secondValues.getMappings()); @@ -72,7 +72,7 @@ void valuesRowsAndFilterIndexesAreNotShared() { @Test void copiesPreserveIdentityWithinAFrameAndRejectUnknownMutablePayloads() { - Query first = CompiledQueryPlan.capture(query(), Map.of()).newExecution(null); + QueryPlan first = CompiledQueryPlan.capture(query(), Map.of()).newExecution(null); Exp values = operators(first).stream().filter(e -> e.type() == Exp.Type.VALUES).findFirst().orElseThrow(); Node variable = first.getSelect().getFirst(); assertSame(variable, values.getNodeList().getFirst()); @@ -80,9 +80,9 @@ void copiesPreserveIdentityWithinAFrameAndRejectUnknownMutablePayloads() { assertThrows(IllegalArgumentException.class, () -> new PlanCopy().copy(new StringBuilder())); } - private static Query query() { + private static QueryPlan query() { var ast = (SelectQueryAst) new SparqlParser().parse(TEXT); - Query query = new CoreseAstQueryBuilder().toNextQuery(ast); + QueryPlan query = new CoreseAstQueryBuilder().toNextQuery(ast); query.complete(new ProducerDefault()); return query; } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlanTest.java similarity index 90% rename from src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryTest.java rename to src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlanTest.java index 14a1cd1f8..805d6a9e8 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlanTest.java @@ -17,15 +17,15 @@ import static org.mockito.Mockito.when; /** - * Comprehensive unit tests for Query class. + * Comprehensive unit tests for QueryPlan class. * Tests KGRAM query structure including select, from, where, order by, * group by, having, filters, and various query types. * */ -@DisplayName("Query Tests") -class QueryTest { +@DisplayName("QueryPlan Tests") +class QueryPlanTest { - private Query query; + private QueryPlan query; private Node mockNode; private Filter mockFilter; @@ -33,18 +33,18 @@ class QueryTest { void setUp() { mockNode = mock(Node.class); mockFilter = mock(Filter.class); - query = new Query(); + query = new QueryPlan(); } @Nested - @DisplayName("Query Creation Tests") + @DisplayName("QueryPlan Creation Tests") class QueryCreationTests { @Test @DisplayName("Should create empty query") void testCreateEmptyQuery() { - Query q = new Query(); - assertNotNull(q, "Query should not be null"); + QueryPlan q = new QueryPlan(); + assertNotNull(q, "QueryPlan should not be null"); assertEquals(ExpType.Type.QUERY, q.type(), "Type should be QUERY"); } @@ -52,15 +52,15 @@ void testCreateEmptyQuery() { @DisplayName("Should create query using factory method") void testCreateQueryFactory() { Exp exp = Exp.create(ExpType.Type.AND); - Query q = Query.create(exp); - assertNotNull(q, "Query should not be null"); + QueryPlan q = QueryPlan.create(exp); + assertNotNull(q, "QueryPlan should not be null"); } @Test @DisplayName("Should create an empty query") void testCreateQueryWithType() { - Query q = Query.create(); - assertNotNull(q, "Query should not be null"); + QueryPlan q = QueryPlan.create(); + assertNotNull(q, "QueryPlan should not be null"); } } @@ -120,13 +120,13 @@ class DistinctTests { @DisplayName("Should set and check distinct") void testSetAndIsDistinct() { query.setDistinct(true); - assertTrue(query.isDistinct(), "Query should be distinct"); + assertTrue(query.isDistinct(), "QueryPlan should be distinct"); } @Test @DisplayName("Should not be distinct by default") void testDefaultDistinct() { - assertFalse(query.isDistinct(), "Query should not be distinct by default"); + assertFalse(query.isDistinct(), "QueryPlan should not be distinct by default"); } } @@ -194,7 +194,7 @@ void testIsSelect() { void testAskIsNotSelect() { query.setAsk(true); - assertTrue(query.isAsk(), "Query should be flagged as ASK"); + assertTrue(query.isAsk(), "QueryPlan should be flagged as ASK"); assertFalse(query.isSelect(), "ASK query should not be reported as SELECT"); } } @@ -276,7 +276,7 @@ void testIsOrderBy() { @Test @DisplayName("Should chain order by") void testOrderByChaining() { - Query result = query.orderBy(mockNode); + QueryPlan result = query.orderBy(mockNode); assertSame(query, result, "Should return same query for chaining"); } } @@ -329,7 +329,7 @@ void testHasGroupBy() { @Test @DisplayName("Should chain group by") void testGroupByChaining() { - Query result = query.groupBy(mockNode); + QueryPlan result = query.groupBy(mockNode); assertSame(query, result, "Should return same query for chaining"); } } @@ -355,7 +355,7 @@ class ConstructTests { @DisplayName("Should set and check if is construct") void testSetAndIsConstruct() { query.setConstruct(true); - assertTrue(query.isConstruct(), "Query should be construct"); + assertTrue(query.isConstruct(), "QueryPlan should be construct"); } @Test @@ -384,7 +384,7 @@ class DeleteTests { @DisplayName("Should set and check if is delete") void testSetAndIsDelete() { query.setDelete(true); - assertTrue(query.isDelete(), "Query should be delete"); + assertTrue(query.isDelete(), "QueryPlan should be delete"); } @Test @@ -404,14 +404,14 @@ class UpdateTests { @DisplayName("Should set and check if is update") void testSetAndIsUpdate() { query.setUpdate(true); - assertTrue(query.isUpdate(), "Query should be update"); + assertTrue(query.isUpdate(), "QueryPlan should be update"); } @Test @DisplayName("Should set and check if is insert") void testSetAndIsInsert() { query.setInsert(true); - assertTrue(query.isInsert(), "Query should be insert"); + assertTrue(query.isInsert(), "QueryPlan should be insert"); } } @@ -423,7 +423,7 @@ class AggregateTests { @DisplayName("Should set and check if is aggregate") void testSetAndIsAggregate() { query.setAggregate(true); - assertTrue(query.isAggregate(), "Query should be aggregate"); + assertTrue(query.isAggregate(), "QueryPlan should be aggregate"); } @Test @@ -469,7 +469,7 @@ void testGetPatternNodes() { @DisplayName("Should get query nodes") void testGetQueryNodes() { List nodes = query.getQueryNodes(); - assertNotNull(nodes, "Query nodes should not be null"); + assertNotNull(nodes, "QueryPlan nodes should not be null"); } @Test @@ -514,56 +514,56 @@ void testSetAndGetGraphNode() { } @Nested - @DisplayName("Query Flags Tests") + @DisplayName("QueryPlan Flags Tests") class QueryFlagsTests { @Test @DisplayName("Should set and check relax flag") void testSetAndIsRelax() { query.setRelax(true); - assertTrue(query.isRelax(), "Query should be relax"); + assertTrue(query.isRelax(), "QueryPlan should be relax"); } @Test @DisplayName("Should set and check optimize flag") void testSetAndIsOptimize() { query.setOptimize(true); - assertTrue(query.isOptimize(), "Query should be optimize"); + assertTrue(query.isOptimize(), "QueryPlan should be optimize"); } @Test @DisplayName("Should set and check test flag") void testSetAndIsTest() { query.setTest(true); - assertTrue(query.isTest(), "Query should be test"); + assertTrue(query.isTest(), "QueryPlan should be test"); } @Test @DisplayName("Should set and check new flag") void testSetAndIsNew() { query.setNew(false); - assertFalse(query.isNew(), "Query should not be new"); + assertFalse(query.isNew(), "QueryPlan should not be new"); } @Test @DisplayName("Should set and check correct flag") void testSetAndIsCorrect() { query.setCorrect(false); - assertFalse(query.isCorrect(), "Query should not be correct"); + assertFalse(query.isCorrect(), "QueryPlan should not be correct"); } @Test @DisplayName("Should set and check map flag") void testSetAndIsMap() { query.setMap(false); - assertFalse(query.isMap(), "Query should not be map"); + assertFalse(query.isMap(), "QueryPlan should not be map"); } @Test @DisplayName("Should set and check rule flag") void testSetAndIsRule() { query.setRule(true); - assertTrue(query.isRule(), "Query should be rule"); + assertTrue(query.isRule(), "QueryPlan should be rule"); } @Test @@ -590,7 +590,7 @@ class ServiceTests { @DisplayName("Should set and check if is service") void testSetAndIsService() { query.setService(true); - assertTrue(query.isService(), "Query should be service"); + assertTrue(query.isService(), "QueryPlan should be service"); } @Test @@ -603,20 +603,20 @@ void testSetAndGetService() { } @Nested - @DisplayName("Global Query Tests") + @DisplayName("Global QueryPlan Tests") class GlobalQueryTests { @Test @DisplayName("Should get global query") void testGetGlobalQuery() { - Query global = query.getGlobalQuery(); + QueryPlan global = query.getGlobalQuery(); assertSame(query, global, "Should return self when not subquery"); } @Test @DisplayName("Should set outer query") void testSetOuterQuery() { - Query outer = new Query(); + QueryPlan outer = new QueryPlan(); query.setOuterQuery(outer); assertEquals(outer, query.getOuterQuery(), "Outer query should match"); } @@ -624,7 +624,7 @@ void testSetOuterQuery() { @Test @DisplayName("Should get outer query") void testGetOuterQuery() { - Query outer = query.getOuterQuery(); + QueryPlan outer = query.getOuterQuery(); assertSame(query, outer, "Should return self when no outer query"); } } @@ -637,14 +637,14 @@ class FederateValidateTests { @DisplayName("Should set and check federate flag") void testSetAndIsFederate() { query.setFederate(true); - assertTrue(query.isFederate(), "Query should be federate"); + assertTrue(query.isFederate(), "QueryPlan should be federate"); } @Test @DisplayName("Should set and check validate flag") void testSetAndIsValidate() { query.setValidate(true); - assertTrue(query.isValidate(), "Query should be validate"); + assertTrue(query.isValidate(), "QueryPlan should be validate"); } } @@ -663,7 +663,7 @@ void testToString() { @DisplayName("Should get datatype label") void testGetDatatypeLabel() { String label = query.getDatatypeLabel(); - assertEquals("[Query]", label, "Datatype label should be [Query]"); + assertEquals("[QueryPlan]", label, "Datatype label should be [QueryPlan]"); } } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java new file mode 100644 index 000000000..41dbded89 --- /dev/null +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java @@ -0,0 +1,135 @@ +package fr.inria.corese.core.next.query.impl.engine.pattern; + +import fr.inria.corese.core.next.query.impl.engine.model.Node; +import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("VariableLayout Tests") +class VariableLayoutTest { + + @Test + @DisplayName("Should allocate sequential node and edge indexes") + void shouldAllocateIndexes() { + VariableLayout layout = new VariableLayout(); + + assertEquals(0, layout.getNodeIndex()); + assertEquals(0, layout.getEdgeIndex()); + + assertEquals(0, layout.allocateNodeIndex()); + assertEquals(1, layout.allocateNodeIndex()); + assertEquals(2, layout.getNodeIndex()); + + assertEquals(0, layout.allocateEdgeIndex()); + assertEquals(1, layout.allocateEdgeIndex()); + assertEquals(2, layout.getEdgeIndex()); + + layout.setNodeIndex(10); + assertEquals(10, layout.getNodeIndex()); + layout.setEdgeIndex(20); + assertEquals(20, layout.getEdgeIndex()); + } + + @Test + @DisplayName("Should store nodes in appropriate pattern and query collections") + void shouldStoreNodesCorrectly() { + VariableLayout layout = new VariableLayout(); + Node pNode = NodeImpl.forVariable("?p"); + Node psNode = NodeImpl.forVariable("?ps"); + Node qNode = NodeImpl.forVariable("?q"); + Node qsNode = NodeImpl.forVariable("?qs"); + + // Pattern regular node (exist = false, select = false) + layout.store(pNode, false, false); + // Pattern select node (exist = false, select = true) + layout.store(psNode, false, true); + // Query regular node (exist = true, select = false) + layout.store(qNode, true, false); + // Query select node (exist = true, select = true) + layout.store(qsNode, true, true); + + assertEquals(List.of(pNode), layout.getPatternNodes()); + assertEquals(List.of(psNode), layout.getPatternSelectNodes()); + assertEquals(List.of(qNode), layout.getQueryNodes()); + assertEquals(List.of(qsNode), layout.getQuerySelectNodes()); + + assertSame(pNode, layout.getPatternNode("?p")); + assertSame(psNode, layout.getPatternSelectNode("?ps")); + assertSame(qNode, layout.getQueryNode("?q")); + assertSame(qsNode, layout.getQuerySelectNode("?qs")); + + assertNull(layout.getPatternNode("?unknown")); + } + + @Test + @DisplayName("Should ignore non-variable and blank nodes when storing") + void shouldIgnoreNonVariableAndBlankNodes() { + VariableLayout layout = new VariableLayout(); + + Node blankNode = NodeImpl.forBlankVariable("_:b0"); + Node constantNode = NodeImpl.forIRI("http://example.org/item"); + + layout.store(blankNode, false, false); + layout.store(constantNode, false, false); + + assertTrue(layout.getPatternNodes().isEmpty()); + } + + @Test + @DisplayName("Should resolve external nodes in hierarchical precedence") + void shouldResolveExtNodeWithPrecedence() { + VariableLayout layout = new VariableLayout(); + Node pNode = NodeImpl.forVariable("?x"); + layout.store(pNode, false, false); + + Node selectNode = NodeImpl.forVariable("?selectX"); + + assertSame(pNode, layout.getExtNode("?x", false, null)); + assertSame(pNode, layout.getNode("?x", null)); + + assertSame(selectNode, layout.getExtNode("?y", true, selectNode)); + assertNull(layout.getExtNode("?y", false, selectNode)); + } + + @Test + @DisplayName("Should copy layout cleanly using PlanCopy") + void shouldCopyFromCleanly() { + VariableLayout source = new VariableLayout(); + Node n1 = NodeImpl.forVariable("?n1"); + Node n2 = NodeImpl.forVariable("?n2"); + source.store(n1, false, false); + source.store(n2, true, true); + source.allocateNodeIndex(); + source.allocateEdgeIndex(); + + PlanCopy copyContext = new PlanCopy(); + VariableLayout target = new VariableLayout(); + target.copyFrom(source, copyContext); + + assertEquals(source.getNodeIndex(), target.getNodeIndex()); + assertEquals(source.getEdgeIndex(), target.getEdgeIndex()); + assertEquals(1, target.getPatternNodes().size()); + assertEquals(1, target.getQuerySelectNodes().size()); + assertEquals("?n1", target.getPatternNodes().get(0).getLabel()); + assertEquals("?n2", target.getQuerySelectNodes().get(0).getLabel()); + } + + @Test + @DisplayName("Should manage binding, construct and arg node collections") + void shouldManageAuxiliaryNodeLists() { + VariableLayout layout = new VariableLayout(); + Node bNode = NodeImpl.forVariable("?b"); + Node cNode = NodeImpl.forVariable("?c"); + + layout.setBindingNodes(List.of(bNode)); + layout.setConstructNodes(List.of(cNode)); + + assertEquals(List.of(bNode), layout.getBindingNodes()); + assertEquals(List.of(cNode), layout.getConstructNodes()); + assertNotNull(layout.getArgList()); + } +} diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityQueryPlannerTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityQueryPlannerTest.java index e2f887152..66485e866 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityQueryPlannerTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/planning/CardinalityQueryPlannerTest.java @@ -8,7 +8,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.path.PropertyPathEdge; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.storage.ProducerDefault; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerProducer; import fr.inria.corese.core.next.query.impl.sparql.ast.SelectQueryAst; @@ -68,7 +68,7 @@ void close() { @Test void choosesSelectiveFirstPatternWithoutOpeningCursorsOrTransactions() { - Query query = query(BROAD_THEN_SELECTIVE); + QueryPlan query = query(BROAD_THEN_SELECTIVE); QueryOperations operations = mock(QueryOperations.class, delegatesTo(storage.queries())); StorageManager observed = mock(StorageManager.class); when(observed.queries()).thenReturn(operations); @@ -109,7 +109,7 @@ void executionStartsWithSelectivePatternAndReadsOnlyTwoStatements() { @Test void connectedJoinsPrecedeDisconnectedPatternsAfterSelectiveSeed() { - Query query = query("?s :link ?v . ?u :unrelated ?z . ?s :seed ?x"); + QueryPlan query = query("?s :link ?v . ?u :unrelated ?z . ?s :seed ?x"); query.complete(new StatisticsProducer(Map.of("urn:bench:link", 100L, "urn:bench:unrelated", 2L, "urn:bench:seed", 1L))); assertEquals(List.of("urn:bench:seed", "urn:bench:link", "urn:bench:unrelated"), predicates(query)); @@ -117,10 +117,10 @@ void connectedJoinsPrecedeDisconnectedPatternsAfterSelectiveSeed() { @Test void variablePredicatesParticipateInJoinConnectivity() { - Query query = query("?s ?p :seed . ?u :unrelated ?z . ?p :link ?x"); + QueryPlan query = query("?s ?p :seed . ?u :unrelated ?z . ?p :link ?x"); query.complete(new StatisticsProducer(Map.of("urn:bench:link", 100L, "urn:bench:unrelated", 2L)) { @Override - public long estimateCardinality(Query scope, Node graph, Edge edge) { + public long estimateCardinality(QueryPlan scope, Node graph, Edge edge) { return edge.getEdgeVariable() == null ? super.estimateCardinality(scope, graph, edge) : 1; } }); @@ -132,7 +132,7 @@ public long estimateCardinality(Query scope, Node graph, Edge edge) { @Test void cardinalitiesRetainLongPrecision() { - Query query = query("?s :large ?x . ?s :small ?y"); + QueryPlan query = query("?s :large ?x . ?s :small ?y"); query.complete(new StatisticsProducer(Map.of("urn:bench:large", Long.MAX_VALUE, "urn:bench:small", 3_000_000_000L))); assertEquals(List.of("urn:bench:small", "urn:bench:large"), predicates(query)); @@ -141,14 +141,14 @@ void cardinalitiesRetainLongPrecision() { @ParameterizedTest @ValueSource(longs = {0, QueryStatistics.UNKNOWN_CARDINALITY, 7}) void equalOrUnavailableStatisticsKeepStableSourceOrder(long count) { - Query query = query("?s :left ?x . ?s :right ?y"); + QueryPlan query = query("?s :left ?x . ?s :right ?y"); query.complete(new StatisticsProducer(Map.of("urn:bench:left", count, "urn:bench:right", count))); assertEquals(List.of("urn:bench:left", "urn:bench:right"), predicates(query)); } @Test void producerWithoutStatisticsRetainsConnectedFallback() { - Query query = query(BROAD_THEN_SELECTIVE); + QueryPlan query = query(BROAD_THEN_SELECTIVE); query.complete(new ProducerDefault()); assertEquals(List.of("urn:bench:type", "urn:bench:name"), predicates(query)); } @@ -180,7 +180,7 @@ void singlePatternAskDoesNotRequestStatistics() { @Test void emptyStorageProducesStablePlansAndEmptyResults() { storage.mutations().clear(); - Query query = query(BROAD_THEN_SELECTIVE); + QueryPlan query = query(BROAD_THEN_SELECTIVE); query.complete(new StorageManagerProducer(storage)); assertEquals(List.of("urn:bench:type", "urn:bench:name"), predicates(query)); try (var result = new SparqlQueryExecutor(storage).evaluateTuple( @@ -230,7 +230,7 @@ void valuesAndUnionPreserveSolutionBags() { @Test void pathsAreBarriersAndDoNotReceiveOrdinaryTripleCounts() { - Query query = query("?s :type :Person . ?s :knows/:knows ?friend . ?s :name \"name42\""); + QueryPlan query = query("?s :type :Person . ?s :knows/:knows ?friend . ?s :name \"name42\""); QueryOperations operations = mock(QueryOperations.class, delegatesTo(storage.queries())); StorageManager observed = mock(StorageManager.class); when(observed.queries()).thenReturn(operations); @@ -245,7 +245,7 @@ void estimatesHonorDefaultNamedAndExplicitEmptyDatasets() { storage.mutations().add(Values.factory().createStatement(iri("s42"), iri("name"), Values.factory().createLiteral("name42"), iri("g"))); StorageManagerProducer producer = new StorageManagerProducer(storage); - Query query = query("?s :name \"name42\""); + QueryPlan query = query("?s :name \"name42\""); Edge edge = edges(query.getBody()).getFirst(); assertEquals(1, producer.estimateCardinality(query, null, edge)); @@ -262,12 +262,12 @@ void estimatesHonorDefaultNamedAndExplicitEmptyDatasets() { @Test void graphScopeIsRestoredBeforePlanningDefaultGraphPatterns() { - Query query = query("GRAPH :g { ?s :type :Person . ?s :name \"name42\" } " + QueryPlan query = query("GRAPH :g { ?s :type :Person . ?s :name \"name42\" } " + "?x :type :Person . ?x :name \"name42\""); List graphs = new ArrayList<>(); StatisticsProducer producer = new StatisticsProducer(Map.of()) { @Override - public long estimateCardinality(Query scope, Node graph, Edge edge) { + public long estimateCardinality(QueryPlan scope, Node graph, Edge edge) { graphs.add(graph); return 1; } @@ -280,7 +280,7 @@ public long estimateCardinality(Query scope, Node graph, Edge edge) { @Test void statisticsUseTheExistingSessionSnapshot() { try (var reader = storage.openSession(); var transaction = reader.transactions().beginTransaction()) { - Query query = query("?s :name \"name42\""); + QueryPlan query = query("?s :name \"name42\""); Edge edge = edges(query.getBody()).getFirst(); StorageManagerProducer producer = new StorageManagerProducer(reader); assertEquals(1, producer.estimateCardinality(query, null, edge)); @@ -308,7 +308,7 @@ void countFailuresRemainQueryDomainErrorsWithOriginalCause() { @Test void selectiveFilterPushdownSeedsComparisonEdgeFirst() { String sparql = "?x :type :Teaching_Unit . ?e :type :Evaluation . ?e :evaluatesTeachingUnit ?x . ?e :hasMark ?y . FILTER (?y < 3)"; - Query query = query(sparql); + QueryPlan query = query(sparql); query.complete(new StorageManagerProducer(storage)); assertEquals(List.of("urn:bench:hasMark", "urn:bench:type", "urn:bench:evaluatesTeachingUnit", "urn:bench:type"), predicates(query)); @@ -358,10 +358,10 @@ void scaledCostsRetainAdjacentLongPrecision() { @Test void variablePredicateDoesNotBecomeSingleTripleProbe() { - Query query = query("?s ?p ?o . ?s :scan ?x . ?s :seed ?o"); + QueryPlan query = query("?s ?p ?o . ?s :scan ?x . ?s :seed ?o"); query.complete(new StatisticsProducer(Map.of("urn:bench:scan", 5000L, "urn:bench:seed", 1L)) { @Override - public long estimateCardinality(Query scope, Node graph, Edge edge) { + public long estimateCardinality(QueryPlan scope, Node graph, Edge edge) { return edge.getEdgeVariable() == null ? super.estimateCardinality(scope, graph, edge) : 1000000; } }); @@ -373,7 +373,7 @@ public long estimateCardinality(Query scope, Node graph, Edge edge) { @Test void enclosingScopeVariablesReduceLookupCost() { - Query query = query("?x :object ?s . ?s :subject ?y"); + QueryPlan query = query("?x :object ?s . ?s :subject ?y"); CardinalityPatternOrdering.sort(query, null, query.getBody(), List.of("s"), List.of(), new StatisticsProducer(Map.of("urn:bench:object", 500L, "urn:bench:subject", 5000L))); assertEquals(List.of("urn:bench:subject", "urn:bench:object"), predicates(query)); @@ -381,7 +381,7 @@ void enclosingScopeVariablesReduceLookupCost() { @Test void zeroCardinalityRemainsCheaperThanFullyBoundProbe() { - Query query = query("?s :probe ?o . ?s :empty ?o"); + QueryPlan query = query("?s :probe ?o . ?s :empty ?o"); CardinalityPatternOrdering.sort(query, null, query.getBody(), List.of("s", "o"), List.of(), new StatisticsProducer(Map.of("urn:bench:probe", 1L, "urn:bench:empty", 0L))); assertEquals(List.of("urn:bench:empty", "urn:bench:probe"), predicates(query)); @@ -390,12 +390,12 @@ void zeroCardinalityRemainsCheaperThanFullyBoundProbe() { private static void assertPlan(String body, Map counts, List expected) { Map qualified = new java.util.HashMap<>(); counts.forEach((key, value) -> qualified.put("urn:bench:" + key, value)); - Query query = query(body); + QueryPlan query = query(body); query.complete(new StatisticsProducer(qualified)); assertEquals(expected.stream().map(name -> "urn:bench:" + name).toList(), predicates(query)); } - private static Query query(String body) { + private static QueryPlan query(String body) { return new CoreseAstQueryBuilder().toNextQuery((SelectQueryAst) new SparqlParser() .parse(PREFIX + "SELECT * { " + body + " }")); } @@ -404,7 +404,7 @@ private static IRI iri(String local) { return Values.factory().createIRI("urn:bench:" + local); } - private static List predicates(Query query) { + private static List predicates(QueryPlan query) { return edges(query.getBody()).stream().map(edge -> edge.getEdgeLabel()).toList(); } @@ -434,7 +434,7 @@ void joinOrderingUsesPredicateStatisticsWhenAvailable() { lowDistinctIri.stringValue(), new PredicateStatistics(lowDistinctIri, 1000, 2, 100), highDistinctIri.stringValue(), new PredicateStatistics(highDistinctIri, 1000, 500, 100)); - Query query = query("?s :seed 1 . ?s :lowDistinct ?o1 . ?s :highDistinct ?o2"); + QueryPlan query = query("?s :seed 1 . ?s :lowDistinct ?o1 . ?s :highDistinct ?o2"); query.complete(new StatisticsProducer(counts, pStats)); List plan = predicates(query); @@ -458,7 +458,7 @@ void joinOrderingUsesPredicateStatisticsWhenObjectIsBound() { lowDistinctIri.stringValue(), new PredicateStatistics(lowDistinctIri, 1000, 100, 2), highDistinctIri.stringValue(), new PredicateStatistics(highDistinctIri, 1000, 100, 500)); - Query query = query("?x :seed ?shared . ?s1 :lowDistinctObj ?shared . ?s2 :highDistinctObj ?shared"); + QueryPlan query = query("?x :seed ?shared . ?s1 :lowDistinctObj ?shared . ?s2 :highDistinctObj ?shared"); query.complete(new StatisticsProducer(counts, pStats)); List plan = predicates(query); @@ -507,7 +507,7 @@ void joinOrderingWithIndexStatisticsAvoidsIntermediateCartesianExplosion() { assertEquals(10000, statsHigh.distinctObjects()); // High selectivity (high distinct objects = small match count per bound object) is placed first - Query plannedQuery = query("?x :seed ?t . ?s1 :lowSel ?t . ?s2 :highSel ?t"); + QueryPlan plannedQuery = query("?x :seed ?t . ?s1 :lowSel ?t . ?s2 :highSel ?t"); plannedQuery.complete(new StorageManagerProducer(benchStorage)); List optimalPlan = predicates(plannedQuery); assertEquals(List.of(seed.stringValue(), highSel.stringValue(), lowSel.stringValue()), optimalPlan); @@ -538,12 +538,12 @@ private StatisticsProducer(Map counts, Map()); when(mockQuery.getOrderBy()).thenReturn(new ArrayList<>()); when(mockQuery.getGroupBy()).thenReturn(new ArrayList<>()); @@ -63,7 +63,7 @@ void testCreateEmptyMappings() { void testCreateMappingsWithQuery() { Mappings m = Mappings.create(mockQuery); assertNotNull(m, "Mappings should not be null"); - assertEquals(mockQuery, m.getQuery(), "Query should match"); + assertEquals(mockQuery, m.getQuery(), "QueryPlan should match"); } @Test @@ -201,22 +201,22 @@ void testEmptyIterator() { } @Nested - @DisplayName("Query Management Tests") + @DisplayName("QueryPlan Management Tests") class QueryManagementTests { @Test @DisplayName("Should get query") void testGetQuery() { - Query result = mappings.getQuery(); + QueryPlan result = mappings.getQuery(); assertEquals(mockQuery, result, "Should return query"); } @Test @DisplayName("Should set query") void testSetQuery() { - Query newQuery = mock(Query.class); + QueryPlan newQuery = mock(QueryPlan.class); mappings.setQuery(newQuery); - assertEquals(newQuery, mappings.getQuery(), "Query should be updated"); + assertEquals(newQuery, mappings.getQuery(), "QueryPlan should be updated"); } } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/solution/MemoryTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/solution/MemoryTest.java index 738f678b3..8de1574bf 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/solution/MemoryTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/solution/MemoryTest.java @@ -2,7 +2,7 @@ import fr.inria.corese.core.next.query.impl.engine.eval.Eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.model.BindingContext; import fr.inria.corese.core.next.query.impl.engine.model.ExpType; @@ -34,7 +34,7 @@ class MemoryTest { private Matcher mockMatcher; private Evaluator mockEvaluator; private Node mockNode; - private Query mockQuery; + private QueryPlan mockQuery; private Eval mockEval; @BeforeEach @@ -42,7 +42,7 @@ void setUp() { mockMatcher = mock(Matcher.class); mockEvaluator = mock(Evaluator.class); mockNode = mock(Node.class); - mockQuery = mock(Query.class); + mockQuery = mock(QueryPlan.class); mockEval = mock(Eval.class); memory = new Memory(mockMatcher, mockEvaluator); @@ -115,7 +115,7 @@ void testGetVisitor() { } @Nested - @DisplayName("Query Management Tests") + @DisplayName("QueryPlan Management Tests") class QueryManagementTests { @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/ContextSelectionTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/ContextSelectionTest.java index bb8cc95e0..89bba8592 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/ContextSelectionTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/ContextSelectionTest.java @@ -1,6 +1,6 @@ package fr.inria.corese.core.next.query.impl.engine.storage; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,7 +24,7 @@ class ContextSelectionTest { private static Environment envWith(boolean datasetSpecified) { Environment env = mock(Environment.class); - Query query = mock(Query.class); + QueryPlan query = mock(QueryPlan.class); when(env.getQuery()).thenReturn(query); when(query.isDatasetSpecified()).thenReturn(datasetSpecified); return env; diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducerTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducerTest.java index 234723f21..560301399 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducerTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/storage/StorageManagerProducerTest.java @@ -19,7 +19,7 @@ import fr.inria.corese.core.next.query.impl.engine.eval.Eval; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.eval.RdfTermMatcher; import fr.inria.corese.core.next.query.impl.engine.eval.SparqlKgramEvaluator; import fr.inria.corese.core.next.storage.impl.memory.MemoryStorageManager; @@ -202,7 +202,7 @@ void evalExecutesSelectStarSpoOverStorageManagerProducer() throws Exception { Node s = variable("s"); Node p = variable("p"); Node o = variable("o"); - Query query = selectStarSpoQuery(s, p, o); + QueryPlan query = selectStarSpoQuery(s, p, o); Eval eval = Eval.create(producer, new SparqlKgramEvaluator(), new RdfTermMatcher()); Mappings mappings = eval.query(query); @@ -216,7 +216,7 @@ void evalExecutesSelectStarSpoOverStorageManagerProducer() throws Exception { void parserBridgeExecutesSelectStarSpoOverStorageManagerProducer() throws Exception { QueryAst ast = new SparqlParser().parse("SELECT * WHERE { ?s ?p ?o }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = new CoreseAstQueryBuilder().toNextQuery(select); + QueryPlan query = new CoreseAstQueryBuilder().toNextQuery(select); Eval eval = Eval.create(producer, new SparqlKgramEvaluator(), new RdfTermMatcher()); Mappings mappings = eval.query(query); @@ -231,7 +231,7 @@ void producerMaterializesBgpMappings() { Node s = variable("s"); Node p = variable("p"); Node o = variable("o"); - Query query = selectStarSpoQuery(s, p, o); + QueryPlan query = selectStarSpoQuery(s, p, o); Environment environment = mock(Environment.class); when(environment.getQuery()).thenReturn(query); @@ -251,7 +251,7 @@ void producerJoinsBgpMappingsAcrossRepeatedVariables() { Node s = variable("s"); Node o = variable("o"); Node name = variable("name"); - Query query = selectKnowsNameQuery(s, o, name); + QueryPlan query = selectKnowsNameQuery(s, o, name); Environment environment = mock(Environment.class); when(environment.getQuery()).thenReturn(query); @@ -314,23 +314,23 @@ private static Node literal(String label) { return NodeImpl.forLiteral(label, null, null); } - private static Query selectStarSpoQuery(Node s, Node p, Node o) { + private static QueryPlan selectStarSpoQuery(Node s, Node p, Node o) { Exp bgp = Exp.create(Type.BGP); bgp.add(Exp.create(Type.EDGE, new TestQueryEdge(s, KgramNodes.rootProperty(), p, o))); return selectQuery(bgp); } - private static Query selectKnowsNameQuery(Node s, Node o, Node name) { + private static QueryPlan selectKnowsNameQuery(Node s, Node o, Node name) { Exp bgp = Exp.create(Type.BGP); bgp.add(Exp.create(Type.EDGE, new TestQueryEdge(s, resource(KNOWS), null, o))); bgp.add(Exp.create(Type.EDGE, new TestQueryEdge(o, resource(NAME), null, name))); return selectQuery(bgp); } - private static Query selectQuery(Exp bgp) { + private static QueryPlan selectQuery(Exp bgp) { Exp body = Exp.create(Type.AND); body.add(bgp); - Query query = Query.create(body); + QueryPlan query = QueryPlan.create(body); query.collect(); List select = query.selectNodesFromPattern(); query.setSelect(select); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java index d4b4ab696..91fa1e3ec 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java @@ -20,7 +20,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.ExprType; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -46,11 +46,11 @@ private static GroupGraphPatternAst whereOneTriple() { } @Test - @DisplayName("Query body is the compiled WHERE and the query is flagged as ASK") + @DisplayName("QueryPlan body is the compiled WHERE and the query is flagged as ASK") void buildsBodyAndAskFlag() { AskQueryAst ask = new AskQueryAst(DatasetClauseAst.none(), whereOneTriple()); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertNotNull(query.getBody(), "body set from WHERE"); assertTrue(query.getBody().isAnd(), "group compiles to AND"); @@ -60,12 +60,12 @@ void buildsBodyAndAskFlag() { } @Test - @DisplayName("Parser -> AskQueryAst -> Query keeps the ASK form") + @DisplayName("Parser -> AskQueryAst -> QueryPlan keeps the ASK form") void buildsQueryFromParsedAsk() { SparqlParser parser = newParserDefault(); AskQueryAst ask = assertInstanceOf(AskQueryAst.class, parser.parse("ASK WHERE { ?s ?p ?o . }")); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.isAsk()); assertFalse(query.isSelect()); @@ -83,33 +83,33 @@ void buildsAskWithFilter() { filter)); AskQueryAst ask = new AskQueryAst(DatasetClauseAst.none(), where); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.isAsk()); assertTrue(query.getBody().get(1).isFilter(), "FILTER compiled into the body"); } @Test - @DisplayName("FROM graphs are copied onto the next Query dataset") + @DisplayName("FROM graphs are copied onto the next QueryPlan dataset") void appliesFromClause() { DatasetClauseAst dataset = new DatasetClauseAst( Set.of(new IriAst("http://example.org/g")), Set.of()); AskQueryAst ask = new AskQueryAst(dataset, whereOneTriple()); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertEquals(List.of("http://example.org/g"), labels(query.getFrom())); assertTrue(query.getNamed().isEmpty()); } @Test - @DisplayName("FROM NAMED graphs are copied onto the next Query dataset") + @DisplayName("FROM NAMED graphs are copied onto the next QueryPlan dataset") void appliesFromNamedClause() { DatasetClauseAst dataset = new DatasetClauseAst( Set.of(), Set.of(new IriAst("http://example.org/g"))); AskQueryAst ask = new AskQueryAst(dataset, whereOneTriple()); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.getFrom().isEmpty()); assertEquals(List.of("http://example.org/g"), labels(query.getNamed())); @@ -123,7 +123,7 @@ void compilesValuesClause() { AskQueryAst ask = new AskQueryAst( DatasetClauseAst.none(), whereOneTriple(), null, null, values); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.getBody().isJoin()); assertTrue(query.getBody().rest().isValues()); } @@ -140,7 +140,7 @@ void buildsAskWithEmptyWhere() { AskQueryAst ask = new AskQueryAst(DatasetClauseAst.none(), new GroupGraphPatternAst(List.of())); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertNotNull(query.getBody()); assertTrue(query.getBody().isAnd()); @@ -154,7 +154,7 @@ void appliesLimitAndOffset() { SolutionModifierAst mod = SolutionModifierAst.withoutGroupBy(false, false, List.of(), 10L, 3L); AskQueryAst ask = new AskQueryAst(DatasetClauseAst.none(), whereOneTriple(), mod, null, null); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertEquals(10, query.getLimit()); assertEquals(3, query.getOffset()); @@ -166,7 +166,7 @@ void appliesOrderBy() { AskQueryAst ask = assertInstanceOf(AskQueryAst.class, newParserDefault().parse("ASK WHERE { ?s ?p ?o . } ORDER BY ?s")); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertEquals(1, query.getOrderBy().size()); assertEquals("s", query.getOrderBy().getFirst().getNode().getLabel()); @@ -184,7 +184,7 @@ void filterExistsInAskWhere() { filter)); AskQueryAst ask = new AskQueryAst(DatasetClauseAst.none(), where); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.isAsk()); Exp filterExp = findFilter(query.getBody()); @@ -199,7 +199,7 @@ void parsedAskWithFilterNotExists() { AskQueryAst ask = assertInstanceOf(AskQueryAst.class, newParserDefault().parse("ASK WHERE { ?s ?p ?o . FILTER NOT EXISTS { ?s ?t } }")); - Query query = builder.toNextQuery(ask); + QueryPlan query = builder.toNextQuery(ask); assertTrue(query.isAsk()); Exp filterExp = findFilter(query.getBody()); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java index 3c8ac0d53..1c5392e1e 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java @@ -10,7 +10,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Expr; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ private static ConstructTemplateAst template(TriplePatternAst... triples) { void templateCompiledAsBgp() { ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), whereSPO()); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertFalse(query.getConstructNodes().isEmpty(), "construct nodes populated"); assertTrue(query.isConstruct(), "query flagged as CONSTRUCT"); assertFalse(query.isSelect(), "CONSTRUCT should not also report itself as SELECT"); @@ -56,12 +56,12 @@ void templateCompiledAsBgp() { } @Test - @DisplayName("Parser -> ConstructQueryAst -> Query keeps the CONSTRUCT form") + @DisplayName("Parser -> ConstructQueryAst -> QueryPlan keeps the CONSTRUCT form") void buildsQueryFromParsedConstruct() { SparqlParser parser = newParserDefault(); ConstructQueryAst construct = assertInstanceOf(ConstructQueryAst.class, parser.parse("CONSTRUCT { ?x ?p ?o } WHERE { ?x ?p ?o }")); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.isConstruct()); assertFalse(query.isSelect()); @@ -75,7 +75,7 @@ void buildsQueryFromParsedConstruct() { void templateWithTwoTriples() { ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new IriAst("http://example.org/p"), new VarAst("o")), new TriplePatternAst(new VarAst("x"), new IriAst("http://example.org/q"), new VarAst("o"))), whereSPO()); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertEquals(2, query.getConstruct().size()); } @@ -85,7 +85,7 @@ void templateWithTwoTriples() { void templateVariableResolvesToBodyNode() { ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), whereSPO()); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); Edge edge = query.getConstruct().first().getEdge(); assertSame(query.getExtNode("x"), edge.getNode(0), "template ?x is the body node"); @@ -97,7 +97,7 @@ void templateVariableResolvesToBodyNode() { void templateOnlyVariableStaysFresh() { ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("newVar"))), whereSPO()); - Query query = assertDoesNotThrow(() -> builder.toNextQuery(construct)); + QueryPlan query = assertDoesNotThrow(() -> builder.toNextQuery(construct)); assertNull(query.getExtNode("newVar"), "template-only variable is not injected into the body"); Node object = query.getConstruct().first().getEdge().getNode(1); @@ -111,7 +111,7 @@ void templateMinusOnlyVariableStaysFresh() { template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("z"))), whereWithMinusOnlyZ()); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); Node minusNode = query.getQueryNode("z"); Node templateNode = query.getConstruct().first().getEdge().getNode(1); @@ -125,7 +125,7 @@ void templateMinusOnlyVariableStaysFresh() { void templateWithFixedResources() { ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new IriAst("http://example.org/s"), new IriAst("http://example.org/p"), new VarAst("o"))), whereSPO()); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); Edge edge = query.getConstruct().first().getEdge(); assertFalse(edge.getNode(0).isVariable(), "fixed subject IRI"); @@ -140,7 +140,7 @@ void appliesDatasetLimitOffset() { SolutionModifierAst mod = SolutionModifierAst.withoutGroupBy(false, false, List.of(), 5L, 2L); ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), dataset, whereSPO(), mod); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertEquals(List.of("http://example.org/g"), query.getFrom().stream().map(Node::getLabel).toList(), "FROM applied"); assertEquals(List.of("http://example.org/n"), query.getNamed().stream().map(Node::getLabel).toList(), "FROM NAMED applied"); @@ -154,7 +154,7 @@ void appliesOrderBy() { SolutionModifierAst mod = SolutionModifierAst.withoutGroupBy(false, false, List.of(new OrderConditionAst(ASTConstants.OrderDirection.ASC, new VarAst("x"))), null, null); ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), DatasetClauseAst.none(), whereSPO(), mod); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertFalse(query.getOrderBy().isEmpty(), "ORDER BY applied"); } @@ -165,7 +165,7 @@ void compilesValuesClause() { ValuesAst values = new ValuesAst(List.of(new ValueMappingAst(Map.of(new VarAst("x"), new IriAst("http://example.org/v"))))); ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), DatasetClauseAst.none(), whereSPO(), null, null, values); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.getBody().isJoin()); assertTrue(query.getBody().rest().isValues()); } @@ -190,7 +190,7 @@ void filterExistsInConstructWhere() { template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), where); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.isConstruct(), "query is CONSTRUCT"); Exp filterExp = findFilter(query.getBody()); @@ -213,7 +213,7 @@ void filterNotExistsInConstructWhere() { template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), where); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.isConstruct(), "query is CONSTRUCT"); Exp filterExp = findFilter(query.getBody()); @@ -232,7 +232,7 @@ void parsedConstructWithFilterExists() { ConstructQueryAst construct = assertInstanceOf(ConstructQueryAst.class, parser.parse("CONSTRUCT { ?x ?p ?o } WHERE { ?x ?p ?o . FILTER EXISTS { ?x ?t } }")); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.isConstruct()); Exp filterExp = findFilter(query.getBody()); @@ -247,7 +247,7 @@ void parsedConstructWithFilterNotExists() { ConstructQueryAst construct = assertInstanceOf(ConstructQueryAst.class, parser.parse("CONSTRUCT { ?x ?p ?o } WHERE { ?x ?p ?o . FILTER NOT EXISTS { ?x ?t } }")); - Query query = builder.toNextQuery(construct); + QueryPlan query = builder.toNextQuery(construct); assertTrue(query.isConstruct()); Exp filterExp = findFilter(query.getBody()); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java index 641f5f772..28be0408b 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java @@ -9,7 +9,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.ExprType; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -39,13 +39,13 @@ private static GroupGraphPatternAst whereWithMinusOnlyZ() { } @Test - @DisplayName("Parser -> DescribeQueryAst -> Query lowers DESCRIBE to a construct-like query") + @DisplayName("Parser -> DescribeQueryAst -> QueryPlan lowers DESCRIBE to a construct-like query") void parserDescribeAstToQuery() { SparqlParser parser = new SparqlParser(); DescribeQueryAst describe = (DescribeQueryAst) parser.parse( "DESCRIBE ?x WHERE { ?x ?p ?o }"); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 1); assertTrue(query.getBody().isAnd()); @@ -59,7 +59,7 @@ void describesVariableResolvedAgainstBody() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX()); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 1); assertTrue(query.getBody().isAnd(), "WHERE compiled into the body"); @@ -75,7 +75,7 @@ void describesFixedResourceWithoutWhere() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new IriAst("")), null); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 1); assertTrue(query.getBody().isAnd(), "body remains an AND"); @@ -89,7 +89,7 @@ void describeAllUsesInScopeVariables() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(), whereBindingX()); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 3); assertEquals(3, describeOptionalCount(query)); @@ -129,7 +129,7 @@ void appliesDatasetClause() { DescribeQueryAst describe = new DescribeQueryAst( dataset, List.of(new VarAst("x")), whereBindingX()); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertEquals(1, query.getFrom().size(), "FROM applied"); assertEquals(1, query.getNamed().size(), "FROM NAMED applied"); @@ -143,7 +143,7 @@ void appliesLimitAndOffset() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX(), mod); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertEquals(5, query.getLimit(), "LIMIT applied"); assertEquals(2, query.getOffset(), "OFFSET applied"); @@ -159,7 +159,7 @@ void appliesOrderBy() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX(), mod); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertFalse(query.getOrderBy().isEmpty(), "ORDER BY applied"); } @@ -176,7 +176,7 @@ void filterExistsInDescribeWhere() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), where); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 1); Exp filterExp = findFilter(query.getBody()); @@ -198,7 +198,7 @@ void filterNotExistsInDescribeWhere() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), where); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertLoweredDescribeConstruct(query, 1); Exp filterExp = findFilter(query.getBody()); @@ -227,7 +227,7 @@ void compilesValuesClause() { DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX(), null, null, values); - Query query = builder.toNextQuery(describe); + QueryPlan query = builder.toNextQuery(describe); assertTrue(query.getBody().isJoin()); assertTrue(query.getBody().rest().isValues()); } @@ -249,7 +249,7 @@ void rejectsNull() { assertThrows(NullPointerException.class, () -> builder.toNextQuery((DescribeQueryAst) null)); } - private static void assertLoweredDescribeConstruct(Query query, int describedNodeCount) { + private static void assertLoweredDescribeConstruct(QueryPlan query, int describedNodeCount) { assertTrue(query.isConstruct(), "DESCRIBE is lowered to the construct runtime path"); assertFalse(query.isSelect(), "a lowered DESCRIBE must not report itself as SELECT"); assertNotNull(query.getConstruct(), "construct template created"); @@ -262,7 +262,7 @@ private static void assertLoweredDescribeConstruct(Query query, int describedNod * Counts the DESCRIBE-generated {@code OPTIONAL { outgoing UNION incoming }} patterns directly * under the body — independently of how the parser shaped the original WHERE. */ - private static long describeOptionalCount(Query query) { + private static long describeOptionalCount(QueryPlan query) { Exp body = query.getBody(); long count = 0; for (int i = 0; i < body.size(); i++) { diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderMinusScopeTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderMinusScopeTest.java index ab2b14e94..37b0f9143 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderMinusScopeTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderMinusScopeTest.java @@ -3,7 +3,7 @@ import fr.inria.corese.core.next.query.impl.sparql.ast.*; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -32,7 +32,7 @@ void minusRightSideVariablesStayOutOfOuterScope() { bgp("s", "p", "o"), new MinusAst(new GroupGraphPatternAst(List.of(bgp("s", "q", "z"))))))); - Query query = Query.create(body); + QueryPlan query = QueryPlan.create(body); query.collect(); // WHERE pattern variables are in scope (pattern nodes) @@ -55,7 +55,7 @@ void optionalVariablesAreInOuterScope() { bgp("s", "p", "o"), new OptionalAst(new GroupGraphPatternAst(List.of(bgp("s", "q", "z"))))))); - Query query = Query.create(body); + QueryPlan query = QueryPlan.create(body); query.collect(); assertTrue(hasLabel(query.getPatternNodes(), "s"), "?s from WHERE is a pattern node"); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderTest.java index f9697c309..0362e52ea 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderTest.java @@ -22,7 +22,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.ExprType; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -47,7 +47,7 @@ class CoreseAstQueryBuilderTest extends AbstractSparqlParserFeatureTest { void buildsMinimalSelectStarQuery() { SelectQueryAst select = new SelectQueryAst(group(singleTriple())); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertTrue(query.getBody().isAnd(), "the query body should be an AND group"); assertEquals(1, query.getBody().size(), "the WHERE should contain one compiled element"); @@ -59,12 +59,12 @@ void buildsMinimalSelectStarQuery() { } @Test - @DisplayName("Parser -> SelectQueryAst -> Query keeps the SELECT * path executable") + @DisplayName("Parser -> SelectQueryAst -> QueryPlan keeps the SELECT * path executable") void buildsQueryFromParsedSelectStar() { QueryAst ast = newParserDefault().parse("SELECT * WHERE { ?s ?p ?o . }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(List.of("s", "p", "o"), labels(query.getSelect())); assertTrue(query.getBody().get(0).isBGP()); @@ -78,7 +78,7 @@ void expandsPrefixesInQuery() { "PREFIX ex: " + "SELECT * WHERE { ?s :p ex:o . }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp bgp = query.getBody().get(0); Edge edge = bgp.get(0).getEdge(); @@ -112,7 +112,7 @@ void preservesAngleBracketedIrisWithoutPrefixExpansion() { "PREFIX rdf: " + "SELECT * WHERE { ?s ?o . }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp bgp = query.getBody().get(0); Edge edge = bgp.get(0).getEdge(); @@ -136,7 +136,7 @@ void preservesNormalizedDatatypesWithConflictingPrefix() { "PREFIX http: " + "SELECT * WHERE { ?s ?p true . }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp bgp = query.getBody().get(0); Edge edge = bgp.get(0).getEdge(); @@ -152,7 +152,7 @@ void expandsUrnAndFilePrefixes() { "PREFIX file: " + "SELECT * WHERE { ?s urn:p \"val\"^^file:type . }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp bgp = query.getBody().get(0); Edge edge = bgp.get(0).getEdge(); @@ -168,7 +168,7 @@ void buildsExplicitProjection() { null, group(singleTriple())); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(List.of("o", "s"), labels(query.getSelect())); } @@ -178,7 +178,7 @@ void buildsExplicitProjection() { void selectStarExcludesMinusOnlyVariables() { SelectQueryAst select = parseSelect("SELECT * WHERE { ?s ?p ?o . MINUS { ?s ?q ?z } }"); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(List.of("s", "p", "o"), labels(query.getSelect()), "MINUS-only variables are stored separately and must not be visible to SELECT *"); @@ -204,7 +204,7 @@ void explicitProjectionRejectsMinusOnlyVariable() { void selectStarIncludesOptionalVariables() { SelectQueryAst select = parseSelect("SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s ?q ?z } }"); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(List.of("s", "p", "o", "q", "z"), labels(query.getSelect()), "OPTIONAL variables remain visible in the outer query scope"); @@ -219,7 +219,7 @@ void appliesSimpleSolutionModifiers() { group(singleTriple()), SolutionModifierAst.withoutGroupBy(true, false, List.of(), 10L, 3L)); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertTrue(query.isDistinct()); assertEquals(10, query.getLimit()); @@ -238,7 +238,7 @@ void appliesVariableOrderBy() { null, null)); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(1, query.getOrderBy().size()); assertEquals("s", query.getOrderBy().getFirst().getNode().getLabel()); @@ -251,7 +251,7 @@ void appliesDescendingOrderBy() { QueryAst ast = newParserDefault().parse("SELECT * WHERE { ?s ?p ?o . } ORDER BY DESC(?o)"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(1, query.getOrderBy().size()); assertEquals("o", query.getOrderBy().getFirst().getNode().getLabel()); @@ -264,7 +264,7 @@ void appliesExpressionOrderBy() { QueryAst ast = newParserDefault().parse("SELECT * WHERE { ?s ?p ?o . } ORDER BY STR(?o)"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(1, query.getOrderBy().size()); assertNotNull(query.getOrderBy().getFirst().getFilter(), @@ -294,14 +294,14 @@ void orderByRejectsMinusOnlyVariable() { void orderByAcceptsOptionalVariable() { SelectQueryAst select = parseSelect("SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s ?q ?z } } ORDER BY ?z"); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(1, query.getOrderBy().size()); assertEquals("z", query.getOrderBy().getFirst().getNode().getLabel()); } @Test - @DisplayName("FROM and FROM NAMED are copied onto the next Query dataset") + @DisplayName("FROM and FROM NAMED are copied onto the next QueryPlan dataset") void appliesDatasetClauses() { DatasetClauseAst dataset = new DatasetClauseAst( Set.of(new IriAst("http://example.org/default")), @@ -311,7 +311,7 @@ void appliesDatasetClauses() { dataset, group(singleTriple())); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); assertEquals(List.of("http://example.org/default"), labels(query.getFrom())); assertEquals(List.of("http://example.org/named"), labels(query.getNamed())); @@ -360,7 +360,7 @@ void rejectsUnknownOrderByVariable() { void filterExistsInSelectWhere() { SelectQueryAst select = getSelectQueryAst(); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp filterExp = findFilter(query.getBody()); assertNotNull(filterExp, "FILTER is in the compiled body"); @@ -385,7 +385,7 @@ void parsedSelectWithFilterNotExists() { "SELECT * WHERE { ?s ?p ?o . FILTER NOT EXISTS { ?s ?t } }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp filterExp = findFilter(query.getBody()); assertNotNull(filterExp, "FILTER NOT EXISTS compiled into body"); @@ -402,7 +402,7 @@ void parsedSelectWithNegatedExists() { "SELECT * WHERE { ?s ?p ?o . FILTER(!EXISTS { ?s ?t }) }"); SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast); - Query query = builder.toNextQuery(select); + QueryPlan query = builder.toNextQuery(select); Exp filterExp = findFilter(query.getBody()); assertNotNull(filterExp, "FILTER !EXISTS compiled into body"); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregationTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregationTest.java index bbec4d74c..3e7628cb1 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregationTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/DirectGroupAggregationTest.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.model.ExpType.Type; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import fr.inria.corese.core.next.query.impl.engine.solution.Mappings; @@ -30,7 +30,7 @@ class DirectGroupAggregationTest { @Test void aggregatesAllScalarsOnFirstRepresentative() { - Query query = query(); + QueryPlan query = query(); Mappings mappings = Mappings.create(query); Mapping first = row("a", integer(10)); mappings.add(first); @@ -53,7 +53,7 @@ void aggregatesAllScalarsOnFirstRepresentative() { @Test void allUnboundValuesAndUnboundGroupKey() { - Query query = query(); + QueryPlan query = query(); Mappings mappings = Mappings.create(query); Mapping first = row(null, null); mappings.add(first); @@ -70,7 +70,7 @@ void allUnboundValuesAndUnboundGroupKey() { @Test void numericErrorDoesNotAffectOtherAggregates() { - Query query = query(); + QueryPlan query = query(); Mappings mappings = Mappings.create(query); Mapping first = row("a", integer(10)); mappings.add(first); @@ -84,7 +84,7 @@ void numericErrorDoesNotAffectOtherAggregates() { @Test void promotesMixedNumericTypesAndPreservesLargeIntegers() { - Query query = query(); + QueryPlan query = query(); Mappings mappings = Mappings.create(query); Mapping first = row("a", integer(1)); mappings.add(first); @@ -104,7 +104,7 @@ void promotesMixedNumericTypesAndPreservesLargeIntegers() { @Test void emptyGroupedInputProducesNoRepresentative() { - Query query = query(); + QueryPlan query = query(); Mappings mappings = Mappings.create(query); assertTrue(DirectGroupAggregation.tryAggregate(query, mappings)); assertEquals(0, mappings.size()); @@ -112,7 +112,7 @@ void emptyGroupedInputProducesNoRepresentative() { @Test void usesAllGroupKeysAndPreparedGroupValues() { - Query query = query(); + QueryPlan query = query(); Node secondKey = NodeImpl.forVariable("?second"); query.addGroupBy(secondKey); Mappings mappings = Mappings.create(query); @@ -134,7 +134,7 @@ void usesAllGroupKeysAndPreparedGroupValues() { @Test void rejectsDistinctWithoutChangingInput() { - Query query = query(); + QueryPlan query = query(); query.getSelectFun().add(projection("?distinct", AggregateFunction.COUNT, true, new VarAst("?v"))); Mappings mappings = Mappings.create(query); Mapping first = row("a", integer(1)); @@ -147,7 +147,7 @@ void rejectsDistinctWithoutChangingInput() { @Test void rejectsUnsupportedModifiersAndAggregateArguments() { - Query query = query(); + QueryPlan query = query(); query.addOrderBy(GROUP); assertFalse(DirectGroupAggregation.isEligible(query)); query = query(); @@ -161,8 +161,8 @@ void rejectsUnsupportedModifiersAndAggregateArguments() { assertFalse(DirectGroupAggregation.isEligible(query)); } - private static Query query() { - Query query = Query.create(); + private static QueryPlan query() { + QueryPlan query = QueryPlan.create(); query.addGroupBy(GROUP); query.addSelect(GROUP); query.getSelectFun().add(projection("?all", AggregateFunction.COUNT, false, null)); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerExistsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerExistsTest.java index a319e4c74..36534ad07 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerExistsTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerExistsTest.java @@ -8,7 +8,7 @@ import fr.inria.corese.core.next.query.impl.engine.model.Expr; import fr.inria.corese.core.next.query.impl.engine.model.ExprType; import fr.inria.corese.core.next.query.impl.engine.pattern.Exp; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -104,7 +104,7 @@ void existsVariablesAreCollectedInExistsScope() { FilterAst filter = new FilterAst(new ExistsAst(group(bgp("s", "q", "z")))); Exp body = compiler.compile(group(bgp("s", "p", "o"), filter)); - Query query = Query.create(body); + QueryPlan query = QueryPlan.create(body); query.collect(); assertTrue(query.getPatternNodes().stream().anyMatch(n -> "o".equals(n.getLabel()))); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelectorTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelectorTest.java index 15867d6a3..c78b202b9 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelectorTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/execution/TopKSelectorTest.java @@ -5,7 +5,7 @@ import fr.inria.corese.core.next.query.impl.engine.event.ProcessVisitor; import fr.inria.corese.core.next.query.impl.engine.model.Node; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.solution.Mapping; import org.junit.jupiter.api.Test; @@ -20,7 +20,7 @@ class TopKSelectorTest { @Test void theHeapNeverRetainsMoreThanLimitPlusOffsetAndReleasesDiscardedSlots() throws ReflectiveOperationException { - Query query = Query.create(); + QueryPlan query = QueryPlan.create(); query.setLimit(5); query.setOffset(2); query.addOrderBy(NodeImpl.forVariable("key")); @@ -42,7 +42,7 @@ void theHeapNeverRetainsMoreThanLimitPlusOffsetAndReleasesDiscardedSlots() throw @Test void officialComparatorVisitorOverridesAreUsedForSelectionAndFinalOrdering() { - Query query = Query.create(); + QueryPlan query = QueryPlan.create(); query.setLimit(2); query.addOrderBy(NodeImpl.forVariable("key")); Eval eval = mock(Eval.class); diff --git a/src/test/java/fr/inria/corese/core/next/storage/impl/memory/ProducerDeduplicationTest.java b/src/test/java/fr/inria/corese/core/next/storage/impl/memory/ProducerDeduplicationTest.java index 80fd98833..0f08dcde5 100644 --- a/src/test/java/fr/inria/corese/core/next/storage/impl/memory/ProducerDeduplicationTest.java +++ b/src/test/java/fr/inria/corese/core/next/storage/impl/memory/ProducerDeduplicationTest.java @@ -6,7 +6,7 @@ import fr.inria.corese.core.next.data.api.term.SimpleIRI; import fr.inria.corese.core.next.query.impl.engine.model.Edge; import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl; -import fr.inria.corese.core.next.query.impl.engine.pattern.Query; +import fr.inria.corese.core.next.query.impl.engine.pattern.QueryPlan; import fr.inria.corese.core.next.query.impl.engine.spi.Environment; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerEdge; import fr.inria.corese.core.next.query.impl.engine.storage.StorageManagerProducer; @@ -38,11 +38,11 @@ class ProducerDeduplicationTest { private static Statement row(int i, Resource graph) { return Values.factory().createStatement(new SimpleIRI("urn:s" + i), new SimpleIRI("urn:p"), new SimpleIRI("urn:o"), graph); } - private static Query query(String dataset) { + private static QueryPlan query(String dataset) { return new CoreseAstQueryBuilder().toNextQuery((SelectQueryAst) new SparqlParser() .parse("SELECT * " + dataset + " WHERE { ?s ?p ?o }")); } - private static Iterable edges(StorageManagerProducer producer, Query query) { + private static Iterable edges(StorageManagerProducer producer, QueryPlan query) { Environment env = mock(Environment.class); when(env.getQuery()).thenReturn(query); return producer.getEdges(null, query.getFrom(), query.getBody().first().first().getEdge(), env); } From 710580896088b5dc4dc3503436e1bbaf03020d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20C=C3=A9r=C3=A8s?= Date: Mon, 26 Oct 2026 15:36:30 +0100 Subject: [PATCH 2/2] refactor(engine): address review feedback on Javadoc links, layout isolation, and delegation (#643) --- .../impl/engine/filter/FilterOptimizer.java | 2 +- .../engine/pattern/CompiledQueryPlan.java | 2 +- .../query/impl/engine/pattern/QueryPlan.java | 26 +++---------------- .../impl/engine/pattern/VariableLayout.java | 22 +++++++++------- .../sparql/bridge/ConstructQueryCompiler.java | 4 +-- .../sparql/bridge/CoreseAstQueryBuilder.java | 12 ++++----- .../bridge/SolutionModifierCompiler.java | 2 +- .../impl/sparql/bridge/WhereCompiler.java | 2 +- .../sparql/execution/SparqlQueryExecutor.java | 2 +- .../engine/pattern/VariableLayoutTest.java | 3 +-- 10 files changed, 29 insertions(+), 48 deletions(-) diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java index a554b885b..092ca79cc 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/filter/FilterOptimizer.java @@ -16,7 +16,7 @@ * Filter Exp Compiler for Optimizations * If Filter leads to optimization, we tag the Filter Exp * with e.g. a BIND(?x = ?y) - * Query.bind() will handle later this tag BIND + * QueryPlan.bind() will handle later this tag BIND * (1) * x p t . y p z . filter(y = x) * -> diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java index 24ed380a9..cea74eb43 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/CompiledQueryPlan.java @@ -7,7 +7,7 @@ /** * Immutable compilation image, enforced by exclusive ownership rather than by - * reusing an executable Query. Capture detaches every mutable component from + * reusing an executable QueryPlan. Capture detaches every mutable component from * the compiler. The private image is never evaluated or exposed; each execution * receives another independent graph. Only immutable syntax, RDF values and * private read-only prologue lookups are shared. No producer, storage cursor, diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java index c635eb841..43c6027d1 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/QueryPlan.java @@ -153,8 +153,7 @@ private QueryPlan(QueryPlan source, PlanCopy copies) { super(Type.QUERY); copies.remember(source, this); source.copyPlanFields(this, copies); - layout = new VariableLayout(); - layout.copyFrom(source.layout, copies); + layout = source.layout.copyPlan(copies); querySorter = null; compiler = null; this.limit = source.limit; @@ -462,7 +461,7 @@ public boolean isDatasetSpecified() { return datasetSpecified; } - public VariableLayout getLayout() { + VariableLayout getLayout() { return layout; } @@ -1003,26 +1002,7 @@ public Node getExtNode(String name) { } public Node getExtNode(String name, boolean select) { - Node node = getPatternNode(name); - if (node != null) { - return node; - } - if (select) { - node = getSelectNode(name); - if (node != null) { - return node; - } - } - node = getQueryNode(name); - if (node != null) { - return node; - } - node = getPatternSelectNode(name); - if (node != null) { - return node; - } - node = getQuerySelectNode(name); - return node; + return layout.getExtNode(name, select, select ? getSelectNode(name) : null); } void store(Node node, boolean exist, boolean select) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java index e1185f710..d6bff2532 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayout.java @@ -25,16 +25,18 @@ public VariableLayout() { // Default constructor initializing empty variable collections and layout counters. } - public void copyFrom(VariableLayout source, PlanCopy copies) { - this.nodeIndex = source.nodeIndex; - this.edgeIndex = source.edgeIndex; - this.patternNodes = copies.copy(source.patternNodes); - this.patternSelectNodes = copies.copy(source.patternSelectNodes); - this.queryNodes = copies.copy(source.queryNodes); - this.querySelectNodes = copies.copy(source.querySelectNodes); - this.bindingNodes = copies.copy(source.bindingNodes); - this.constructNodes = copies.copy(source.constructNodes); - this.argList = copies.copy(source.argList); + VariableLayout copyPlan(PlanCopy copies) { + VariableLayout copy = new VariableLayout(); + copy.nodeIndex = this.nodeIndex; + copy.edgeIndex = this.edgeIndex; + copy.patternNodes = copies.copy(this.patternNodes); + copy.patternSelectNodes = copies.copy(this.patternSelectNodes); + copy.queryNodes = copies.copy(this.queryNodes); + copy.querySelectNodes = copies.copy(this.querySelectNodes); + copy.bindingNodes = copies.copy(this.bindingNodes); + copy.constructNodes = copies.copy(this.constructNodes); + copy.argList = copies.copy(this.argList); + return copy; } public int allocateNodeIndex() { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java index 3b2dd7ace..659edfb95 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/ConstructQueryCompiler.java @@ -16,7 +16,7 @@ import java.util.Objects; /** - * Compiles a {@link ConstructQueryAst} template and modifiers into a runtime {@link Query}. + * Compiles a {@link ConstructQueryAst} template and modifiers into a runtime {@link QueryPlan}. */ final class ConstructQueryCompiler { @@ -58,7 +58,7 @@ private static void rejectUnsupportedConstructClauses(ConstructQueryAst construc /** * Compiles a {@code CONSTRUCT} template into a KGRAM {@link Exp} (a BGP of edges), kept separate - * from the {@code WHERE} body and carried by {@link Query#setConstruct(Exp)}. + * from the {@code WHERE} body and carried by {@link QueryPlan#setConstruct(Exp)}. */ private static Exp compileConstructTemplate( QueryPlan query, ConstructTemplateAst template, WhereCompiler compiler) { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java index d36571dc7..80a990772 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java @@ -28,7 +28,7 @@ *

This bridge sits between the parsed SPARQL AST and the KGRAM runtime query model: * it does not execute queries, it translates syntax-level query forms ({@code ASK}, * {@code SELECT}, {@code DESCRIBE}, {@code CONSTRUCT}) into runtime-ready - * {@link Query}/{@link Exp} structures.

+ * {@link QueryPlan}/{@link Exp} structures.

*/ public final class CoreseAstQueryBuilder { @@ -52,7 +52,7 @@ public CoreseAstQueryBuilder() { } /** - * Builds a KGRAM {@link Query} from a SPARQL {@code ASK} query AST. + * Builds a KGRAM {@link QueryPlan} from a SPARQL {@code ASK} query AST. * *

The bridge maps the query body and the modifiers that already have a direct * runtime representation ({@code FROM}, {@code FROM NAMED}, {@code ORDER BY}, @@ -76,7 +76,7 @@ public QueryPlan toNextQuery(AskQueryAst askQueryAst) { } /** - * Builds a KGRAM {@link Query} from a {@link SelectQueryAst}. + * Builds a KGRAM {@link QueryPlan} from a {@link SelectQueryAst}. * *

The bridge maps the compiled {@code WHERE} body, plain projection, * dataset clauses, and solution modifiers that already have a direct runtime @@ -107,7 +107,7 @@ public QueryPlan toNextQuery(SelectQueryAst selectQueryAst) { } /** - * Builds a KGRAM {@link Query} from a {@link DescribeQueryAst}. + * Builds a KGRAM {@link QueryPlan} from a {@link DescribeQueryAst}. * *

Reuses the shared query shell (compiled {@code WHERE} body, dataset, LIMIT/OFFSET) and * {@code ORDER BY} like the other forms, then lowers {@code DESCRIBE} to the construct-like @@ -133,7 +133,7 @@ public QueryPlan toNextQuery(DescribeQueryAst describeQueryAst) { } /** - * Builds a KGRAM {@link Query} from a {@link ConstructQueryAst}. + * Builds a KGRAM {@link QueryPlan} from a {@link ConstructQueryAst}. * *

Reuses the shared query shell (compiled {@code WHERE} body, dataset, LIMIT/OFFSET) and * {@code ORDER BY} like the other forms, then compiles the {@code CONSTRUCT} template into a @@ -206,7 +206,7 @@ private static void rejectUnsupportedDescribeClauses(DescribeQueryAst describeQu } /** - * Creates the runtime {@link Query} shell shared by every query form handled here. + * Creates the runtime {@link QueryPlan} shell shared by every query form handled here. * *

The compiled {@code WHERE} body comes first, then the builder copies dataset * and limit/offset information, and finally collects visible nodes so later clauses diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java index a25fa035e..67d3f11eb 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SolutionModifierCompiler.java @@ -27,7 +27,7 @@ /** * Compiles SPARQL solution modifiers (projection, GROUP BY, HAVING, ORDER BY, LIMIT/OFFSET) - * onto a runtime {@link Query}. + * onto a runtime {@link QueryPlan}. */ final class SolutionModifierCompiler { diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java index df1d4e95e..9308b4a2c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java @@ -96,7 +96,7 @@ Set inScopeVariables() { /** * Compiles a full SPARQL {@code WHERE} clause into the runtime body carried by a - * KGRAM {@link Query}. + * KGRAM {@link QueryPlan}. * *

This is the main entry point of the compiler. It expects the root * {@link GroupGraphPatternAst} produced by the parser for a complete diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java index 4023ddd60..0f00ac096 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/execution/SparqlQueryExecutor.java @@ -705,7 +705,7 @@ private List irisToKgramNodes(Iterable iris) { * *

Each binding entry becomes a (variable-node, value-node) pair. The variable * node carries the variable name as its label so that - * {@link Query#getExtNode(String)} can look it up by name during evaluation. + * {@link QueryPlan#getExtNode(String)} can look it up by name during evaluation. * Bindings whose value cannot be converted to a KGRAM node are silently skipped.

* * @return a {@link Mapping} with the converted bindings, or {@code null} when the diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java index 41dbded89..56f916053 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/engine/pattern/VariableLayoutTest.java @@ -107,8 +107,7 @@ void shouldCopyFromCleanly() { source.allocateEdgeIndex(); PlanCopy copyContext = new PlanCopy(); - VariableLayout target = new VariableLayout(); - target.copyFrom(source, copyContext); + VariableLayout target = source.copyPlan(copyContext); assertEquals(source.getNodeIndex(), target.getNodeIndex()); assertEquals(source.getEdgeIndex(), target.getEdgeIndex());