You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2014/11/07 15:41:29 UTC

marmotta git commit: SPARQL: code simplification

Repository: marmotta
Updated Branches:
  refs/heads/develop da96706ce -> 89df9e039


SPARQL: code simplification


Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/89df9e03
Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/89df9e03
Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/89df9e03

Branch: refs/heads/develop
Commit: 89df9e039b8a5168d7277e51cd84469be6254466
Parents: da96706
Author: Sebastian Schaffert <ss...@apache.org>
Authored: Fri Nov 7 15:42:08 2014 +0100
Committer: Sebastian Schaffert <ss...@apache.org>
Committed: Fri Nov 7 15:42:08 2014 +0100

----------------------------------------------------------------------
 .../evaluation/KiWiEvaluationStrategy.java      | 409 +++++++++++++++++++
 .../evaluation/KiWiEvaluationStrategyImpl.java  | 202 ---------
 .../persistence/KiWiSparqlConnection.java       | 274 -------------
 .../kiwi/sparql/sail/KiWiSparqlSail.java        |   7 +-
 .../sparql/sail/KiWiSparqlSailConnection.java   |  10 +-
 5 files changed, 415 insertions(+), 487 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/marmotta/blob/89df9e03/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategy.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategy.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategy.java
new file mode 100644
index 0000000..122edfa
--- /dev/null
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategy.java
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.sparql.evaluation;
+
+import info.aduna.iteration.*;
+import org.apache.marmotta.commons.vocabulary.XSD;
+import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
+import org.apache.marmotta.kiwi.persistence.KiWiConnection;
+import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration;
+import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction;
+import org.apache.marmotta.kiwi.sail.KiWiValueFactory;
+import org.apache.marmotta.kiwi.sparql.builder.ProjectionType;
+import org.apache.marmotta.kiwi.sparql.builder.SQLBuilder;
+import org.apache.marmotta.kiwi.sparql.builder.collect.SupportedFinder;
+import org.apache.marmotta.kiwi.sparql.builder.model.SQLVariable;
+import org.apache.marmotta.kiwi.sparql.exception.UnsatisfiableQueryException;
+import org.openrdf.model.URI;
+import org.openrdf.model.impl.BNodeImpl;
+import org.openrdf.model.impl.LiteralImpl;
+import org.openrdf.model.impl.URIImpl;
+import org.openrdf.query.*;
+import org.openrdf.query.algebra.*;
+import org.openrdf.query.algebra.evaluation.TripleSource;
+import org.openrdf.query.algebra.evaluation.impl.EvaluationStrategyImpl;
+import org.openrdf.query.impl.MapBindingSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+
+/**
+ * An implementation of the SPARQL query evaluation strategy with specific extensions and optimizations. The KiWi
+ * evaluation strategy is able to apply optimizations to certain frequently found query patterns by directly translating
+ * them into SQL queries. Currently, the following constructs are supported:
+ * <ul>
+ *     <li>JOINs of statement patterns are translated into SQL joins (no OPTIONAL and no path expressions supporterd)</li>
+ *     <li>FILTERs are translated to SQL where conditions, in case the FILTER conditions are supported (no aggregation constructs are supported)</li>
+ * </ul>
+ * In case a query is not completely supported by the optimizer, the optimizer might still improve performance by
+ * evaluating the optimizable components of the query and then letting the in-memory implementation take over
+ * (e.g. for aggregation constructs, distinct, path expressions, optional).
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class KiWiEvaluationStrategy extends EvaluationStrategyImpl{
+
+    private static Logger log = LoggerFactory.getLogger(KiWiEvaluationStrategy.class);
+
+
+    /**
+     * The database connection offering specific SPARQL-SQL optimizations.
+     */
+    private KiWiConnection connection;
+    private KiWiValueFactory valueFactory;
+    private ExecutorService executorService;
+
+
+    private Set<String> projectedVars = new HashSet<>();
+
+    public KiWiEvaluationStrategy(TripleSource tripleSource, KiWiConnection connection, KiWiValueFactory valueFactory) {
+        super(tripleSource);
+        this.connection = connection;
+        this.valueFactory = valueFactory;
+
+        // interruptible queries run in a separate thread
+        this.executorService = Executors.newCachedThreadPool();
+    }
+
+    public KiWiEvaluationStrategy(TripleSource tripleSource, Dataset dataset, KiWiConnection connection, KiWiValueFactory valueFactory) {
+        super(tripleSource, dataset);
+        this.connection = connection;
+        this.valueFactory = valueFactory;
+
+        // interruptible queries run in a separate thread
+        this.executorService = Executors.newCachedThreadPool();
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Projection projection, BindingSet bindings) throws QueryEvaluationException {
+        // count projected variables
+        if(isSupported(projection.getArg())) {
+            for (ProjectionElem elem : projection.getProjectionElemList().getElements()) {
+                projectedVars.add(elem.getSourceName());
+            }
+        }
+
+        return super.evaluate(projection, bindings);
+    }
+
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Union union, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(union)) {
+            return evaluateNative(union, bindings);
+        } else {
+            return super.evaluate(union, bindings);
+        }
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Extension order, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(order)) {
+            return evaluateNative(order, bindings);
+        } else {
+            return super.evaluate(order, bindings);
+        }
+    }
+
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Order order, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(order)) {
+            return evaluateNative(order, bindings);
+        } else {
+            return super.evaluate(order, bindings);
+        }
+    }
+
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(LeftJoin join, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(join)) {
+            return evaluateNative(join, bindings);
+        } else {
+            return super.evaluate(join, bindings);
+        }
+    }
+
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Join join, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(join)) {
+            return evaluateNative(join, bindings);
+        } else {
+            return super.evaluate(join, bindings);
+        }
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Filter join, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(join)) {
+            return evaluateNative(join, bindings);
+        } else {
+            return super.evaluate(join, bindings);
+        }
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Slice slice, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(slice)) {
+            return evaluateNative(slice, bindings);
+        } else {
+            return super.evaluate(slice, bindings);
+        }
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Reduced reduced, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(reduced)) {
+            return evaluateNative(reduced, bindings);
+        } else {
+            return super.evaluate(reduced, bindings);
+        }
+    }
+
+    @Override
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Distinct distinct, BindingSet bindings) throws QueryEvaluationException {
+        if(isSupported(distinct)) {
+            return evaluateNative(distinct, bindings);
+        } else {
+            return super.evaluate(distinct, bindings);
+        }
+    }
+
+    /**
+     * Evaluate a statement pattern join or filter on the database by translating it into an appropriate SQL statement.
+     * Copied and adapted from KiWiReasoningConnection.query()
+     *
+     * @param join
+     * @return
+     */
+    public CloseableIteration<BindingSet, QueryEvaluationException> evaluateNative(TupleExpr join, final BindingSet bindings) throws QueryEvaluationException {
+        log.debug("applying KiWi native optimizations on SPARQL query ...");
+
+        try {
+            final SQLBuilder builder = new SQLBuilder(join, bindings, dataset, valueFactory, connection.getDialect(), projectedVars);
+
+            final PreparedStatement queryStatement = connection.getJDBCConnection().prepareStatement(builder.build().toString());
+            if (connection.getDialect().isCursorSupported()) {
+                queryStatement.setFetchSize(connection.getConfiguration().getCursorSize());
+            }
+
+            Future<ResultSet> queryFuture =
+                    executorService.submit(new Callable<ResultSet>() {
+                                               @Override
+                                               public ResultSet call() throws Exception {
+                                                   try {
+                                                       return queryStatement.executeQuery();
+                                                   } catch (SQLException ex) {
+                                                       if (Thread.interrupted()) {
+                                                           log.info("SQL query execution cancelled; not returning result (Thread={})", Thread.currentThread());
+                                                           throw new InterruptedException("SPARQL query execution cancelled");
+                                                       } else {
+                                                           throw ex;
+                                                       }
+                                                   }
+                                               }
+                                           }
+                    );
+
+            try {
+                ResultSet result = queryFuture.get();
+
+                ResultSetIteration<BindingSet> it = new ResultSetIteration<BindingSet>(result, true, new ResultTransformerFunction<BindingSet>() {
+                    @Override
+                    public BindingSet apply(ResultSet row) throws SQLException {
+                        MapBindingSet resultRow = new MapBindingSet();
+
+                        List<SQLVariable> vars = new ArrayList<>(builder.getVariables().values());
+
+                        long[] nodeIds = new long[vars.size()];
+                        for(int i=0; i<vars.size(); i++) {
+                            SQLVariable sv = vars.get(i);
+                            if(sv.getProjectionType() == ProjectionType.NODE && (builder.getProjectedVars().isEmpty() || builder.getProjectedVars().contains(sv.getSparqlName()))) {
+                                nodeIds[i] = row.getLong(sv.getName());
+                            }
+                        }
+                        KiWiNode[] nodes = connection.loadNodesByIds(nodeIds);
+
+                        for (int i = 0; i < vars.size(); i++) {
+                            SQLVariable sv = vars.get(i);
+                            if(nodes[i] != null) {
+                                // resolved node
+                                resultRow.addBinding(sv.getSparqlName(), nodes[i]);
+                            } else if(sv.getProjectionType() != ProjectionType.NONE && (builder.getProjectedVars().isEmpty() || builder.getProjectedVars().contains(sv.getSparqlName()))) {
+                                // literal value
+                                String svalue;
+                                switch (sv.getProjectionType()) {
+                                    case URI:
+                                        svalue = row.getString(sv.getName());
+                                        if(svalue != null)
+                                            resultRow.addBinding(sv.getSparqlName(), new URIImpl(svalue));
+                                        break;
+                                    case BNODE:
+                                        svalue = row.getString(sv.getName());
+                                        if(svalue != null)
+                                            resultRow.addBinding(sv.getSparqlName(), new BNodeImpl(svalue));
+                                        break;
+                                    case INT:
+                                        if(row.getObject(sv.getName()) != null) {
+                                            svalue = Integer.toString(row.getInt(sv.getName()));
+                                            URI type = XSD.Integer;
+                                            try {
+                                                long typeId = row.getLong(sv.getName() + "_TYPE");
+                                                if (typeId > 0)
+                                                    type = (URI) connection.loadNodeById(typeId);
+                                            } catch (SQLException ex) {
+                                            }
+
+                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
+                                        }
+                                        break;
+                                    case DOUBLE:
+                                        if(row.getObject(sv.getName()) != null) {
+                                            svalue = Double.toString(row.getDouble(sv.getName()));
+                                            URI type = XSD.Double;
+                                            try {
+                                                long typeId = row.getLong(sv.getName() + "_TYPE");
+                                                if (typeId > 0)
+                                                    type = (URI) connection.loadNodeById(typeId);
+                                            } catch (SQLException ex) {
+                                            }
+
+                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
+                                        }
+                                        break;
+                                    case BOOL:
+                                        if(row.getObject(sv.getName()) != null) {
+                                            svalue = Boolean.toString(row.getBoolean(sv.getName()));
+                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue.toLowerCase(), XSD.Boolean));
+                                        }
+                                        break;
+                                    case STRING:
+                                    default:
+                                        svalue = row.getString(sv.getName());
+
+                                        if(svalue != null) {
+
+                                            // retrieve optional type and language information, because string functions
+                                            // need to preserve this in certain cases, even when constructing new literals
+                                            String lang = null;
+                                            try {
+                                                lang = row.getString(sv.getName() + "_LANG");
+                                            } catch (SQLException ex) {
+                                            }
+
+                                            URI type = null;
+                                            try {
+                                                long typeId = row.getLong(sv.getName() + "_TYPE");
+                                                if (typeId > 0)
+                                                    type = (URI) connection.loadNodeById(typeId);
+                                            } catch (SQLException ex) {
+                                            }
+
+                                            if (lang != null) {
+                                                if (svalue.length() > 0) {
+                                                    resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, lang));
+                                                } else {
+                                                    // string functions that return empty literal should yield no type or language
+                                                    resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(""));
+                                                }
+                                            } else if (type != null) {
+                                                if(type.stringValue().equals(XSD.String.stringValue())) {
+                                                    // string functions on other datatypes than string should yield no binding
+                                                    if (svalue.length() > 0) {
+                                                        resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
+                                                    } else {
+                                                        // string functions that return empty literal should yield no type or language
+                                                        resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(""));
+                                                    }
+                                                }
+                                            } else {
+                                                resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue));
+                                            }
+
+                                        }
+                                        break;
+                                }
+                            }
+                        }
+
+
+                        if (bindings != null) {
+                            for (Binding binding : bindings) {
+                                resultRow.addBinding(binding);
+                            }
+                        }
+                        return resultRow;
+                    }
+                });
+
+
+                return new ExceptionConvertingIteration<BindingSet, QueryEvaluationException>(new CloseableIteratorIteration<BindingSet, SQLException>(Iterations.asList(it).iterator())) {
+                    @Override
+                    protected QueryEvaluationException convert(Exception e) {
+                        return new QueryEvaluationException(e);
+                    }
+                };
+
+            } catch (InterruptedException | CancellationException e) {
+                log.info("SPARQL query execution cancelled");
+                queryFuture.cancel(true);
+                queryStatement.cancel();
+                queryStatement.close();
+
+                throw new QueryInterruptedException("SPARQL query execution cancelled");
+            } catch (ExecutionException e) {
+                log.error("error executing SPARQL query", e.getCause());
+                if (e.getCause() instanceof SQLException) {
+                    throw new QueryEvaluationException(e.getCause());
+                } else if (e.getCause() instanceof InterruptedException) {
+                    throw new QueryInterruptedException(e.getCause());
+                } else {
+                    throw new QueryEvaluationException("error executing SPARQL query", e);
+                }
+            }
+        } catch (SQLException e) {
+            throw new QueryEvaluationException(e);
+        } catch (IllegalArgumentException e) {
+            throw new QueryEvaluationException(e);
+        } catch (UnsatisfiableQueryException ex) {
+            return new EmptyIteration<>();
+        }
+    }
+
+
+    /**
+     * Test if a tuple expression is supported nby the optimized evaluation; in this case we can apply a specific optimization.
+     *
+     * @param expr
+     * @return
+     */
+    private boolean isSupported(TupleExpr expr) {
+        return new SupportedFinder(expr, connection.getDialect()).isSupported();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/89df9e03/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java
deleted file mode 100644
index 7e6d7bb..0000000
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.marmotta.kiwi.sparql.evaluation;
-
-import info.aduna.iteration.CloseableIteration;
-import info.aduna.iteration.ExceptionConvertingIteration;
-import org.apache.marmotta.kiwi.sparql.builder.collect.SupportedFinder;
-import org.apache.marmotta.kiwi.sparql.persistence.KiWiSparqlConnection;
-import org.openrdf.query.BindingSet;
-import org.openrdf.query.Dataset;
-import org.openrdf.query.QueryEvaluationException;
-import org.openrdf.query.QueryInterruptedException;
-import org.openrdf.query.algebra.*;
-import org.openrdf.query.algebra.evaluation.TripleSource;
-import org.openrdf.query.algebra.evaluation.impl.EvaluationStrategyImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * An implementation of the SPARQL query evaluation strategy with specific extensions and optimizations. The KiWi
- * evaluation strategy is able to apply optimizations to certain frequently found query patterns by directly translating
- * them into SQL queries. Currently, the following constructs are supported:
- * <ul>
- *     <li>JOINs of statement patterns are translated into SQL joins (no OPTIONAL and no path expressions supporterd)</li>
- *     <li>FILTERs are translated to SQL where conditions, in case the FILTER conditions are supported (no aggregation constructs are supported)</li>
- * </ul>
- * In case a query is not completely supported by the optimizer, the optimizer might still improve performance by
- * evaluating the optimizable components of the query and then letting the in-memory implementation take over
- * (e.g. for aggregation constructs, distinct, path expressions, optional).
- *
- * @author Sebastian Schaffert (sschaffert@apache.org)
- */
-public class KiWiEvaluationStrategyImpl extends EvaluationStrategyImpl{
-
-    private static Logger log = LoggerFactory.getLogger(KiWiEvaluationStrategyImpl.class);
-
-
-    /**
-     * The database connection offering specific SPARQL-SQL optimizations.
-     */
-    private KiWiSparqlConnection connection;
-
-    private Set<String> projectedVars = new HashSet<>();
-
-    public KiWiEvaluationStrategyImpl(TripleSource tripleSource, KiWiSparqlConnection connection) {
-        super(tripleSource);
-        this.connection = connection;
-    }
-
-    public KiWiEvaluationStrategyImpl(TripleSource tripleSource, Dataset dataset, KiWiSparqlConnection connection) {
-        super(tripleSource, dataset);
-        this.connection = connection;
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Projection projection, BindingSet bindings) throws QueryEvaluationException {
-        // count projected variables
-        if(isSupported(projection.getArg())) {
-            for (ProjectionElem elem : projection.getProjectionElemList().getElements()) {
-                projectedVars.add(elem.getSourceName());
-            }
-        }
-
-        return super.evaluate(projection, bindings);
-    }
-
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Union union, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(union)) {
-            return evaluateNative(union, bindings);
-        } else {
-            return super.evaluate(union, bindings);
-        }
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Extension order, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(order)) {
-            return evaluateNative(order, bindings);
-        } else {
-            return super.evaluate(order, bindings);
-        }
-    }
-
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Order order, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(order)) {
-            return evaluateNative(order, bindings);
-        } else {
-            return super.evaluate(order, bindings);
-        }
-    }
-
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(LeftJoin join, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(join)) {
-            return evaluateNative(join, bindings);
-        } else {
-            return super.evaluate(join, bindings);
-        }
-    }
-
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Join join, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(join)) {
-            return evaluateNative(join, bindings);
-        } else {
-            return super.evaluate(join, bindings);
-        }
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Filter join, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(join)) {
-            return evaluateNative(join, bindings);
-        } else {
-            return super.evaluate(join, bindings);
-        }
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Slice slice, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(slice)) {
-            return evaluateNative(slice, bindings);
-        } else {
-            return super.evaluate(slice, bindings);
-        }
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Reduced reduced, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(reduced)) {
-            return evaluateNative(reduced, bindings);
-        } else {
-            return super.evaluate(reduced, bindings);
-        }
-    }
-
-    @Override
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Distinct distinct, BindingSet bindings) throws QueryEvaluationException {
-        if(isSupported(distinct)) {
-            return evaluateNative(distinct, bindings);
-        } else {
-            return super.evaluate(distinct, bindings);
-        }
-    }
-
-    public CloseableIteration<BindingSet, QueryEvaluationException> evaluateNative(TupleExpr expr, BindingSet bindings) throws QueryEvaluationException {
-        log.debug("applying KiWi native optimizations on SPARQL query ...");
-
-        try {
-            return new ExceptionConvertingIteration<BindingSet, QueryEvaluationException>(connection.evaluateNative(expr, bindings, dataset, projectedVars)) {
-                @Override
-                protected QueryEvaluationException convert(Exception e) {
-                    return new QueryEvaluationException(e);
-                }
-            };
-        } catch (SQLException e) {
-            throw new QueryEvaluationException(e);
-        } catch (IllegalArgumentException e) {
-            throw new QueryEvaluationException(e);
-        } catch (InterruptedException e) {
-            throw new QueryInterruptedException(e);
-        }
-    }
-
-
-
-    /**
-     * Test if a tuple expression is supported nby the optimized evaluation; in this case we can apply a specific optimization.
-     *
-     * @param expr
-     * @return
-     */
-    private boolean isSupported(TupleExpr expr) {
-        return new SupportedFinder(expr, connection.getDialect()).isSupported();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/89df9e03/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java
deleted file mode 100644
index 822f510..0000000
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.marmotta.kiwi.sparql.persistence;
-
-import info.aduna.iteration.CloseableIteration;
-import info.aduna.iteration.CloseableIteratorIteration;
-import info.aduna.iteration.EmptyIteration;
-import info.aduna.iteration.Iterations;
-import org.apache.marmotta.commons.vocabulary.XSD;
-import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
-import org.apache.marmotta.kiwi.persistence.KiWiConnection;
-import org.apache.marmotta.kiwi.persistence.KiWiDialect;
-import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration;
-import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction;
-import org.apache.marmotta.kiwi.sail.KiWiValueFactory;
-import org.apache.marmotta.kiwi.sparql.builder.ProjectionType;
-import org.apache.marmotta.kiwi.sparql.builder.SQLBuilder;
-import org.apache.marmotta.kiwi.sparql.builder.model.SQLVariable;
-import org.apache.marmotta.kiwi.sparql.exception.UnsatisfiableQueryException;
-import org.openrdf.model.URI;
-import org.openrdf.model.impl.BNodeImpl;
-import org.openrdf.model.impl.LiteralImpl;
-import org.openrdf.model.impl.URIImpl;
-import org.openrdf.query.Binding;
-import org.openrdf.query.BindingSet;
-import org.openrdf.query.Dataset;
-import org.openrdf.query.algebra.TupleExpr;
-import org.openrdf.query.impl.MapBindingSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.*;
-
-/**
- * Provide improved SPARQL support by evaluating certain common compley SPARQL constructs directly on the
- * database (e.g. JOIN over pattern queries).
- * <p/>
- * Implemented using a decorator pattern (i.e. wrapping the KiWiConnection).
- *
- * @author Sebastian Schaffert (sschaffert@apache.org)
- */
-public class KiWiSparqlConnection {
-
-    private static Logger log = LoggerFactory.getLogger(KiWiSparqlConnection.class);
-
-    private KiWiConnection parent;
-    private KiWiValueFactory valueFactory;
-
-    private ExecutorService executorService;
-
-    public KiWiSparqlConnection(KiWiConnection parent, KiWiValueFactory valueFactory) throws SQLException {
-        this.parent = parent;
-        this.valueFactory = valueFactory;
-
-        // interruptible queries run in a separate thread
-        this.executorService = Executors.newCachedThreadPool();
-    }
-
-    /**
-     * Evaluate a statement pattern join or filter on the database by translating it into an appropriate SQL statement.
-     * Copied and adapted from KiWiReasoningConnection.query()
-     *
-     * @param join
-     * @param dataset
-     * @return
-     */
-    public CloseableIteration<BindingSet, SQLException> evaluateNative(TupleExpr join, final BindingSet bindings, final Dataset dataset, Set<String> projectedVars) throws SQLException, InterruptedException {
-
-        try {
-            final SQLBuilder builder = new SQLBuilder(join, bindings, dataset, valueFactory, parent.getDialect(), projectedVars);
-
-            final PreparedStatement queryStatement = parent.getJDBCConnection().prepareStatement(builder.build().toString());
-            if (parent.getDialect().isCursorSupported()) {
-                queryStatement.setFetchSize(parent.getConfiguration().getCursorSize());
-            }
-
-            Future<ResultSet> queryFuture =
-                    executorService.submit(new Callable<ResultSet>() {
-                                               @Override
-                                               public ResultSet call() throws Exception {
-                                                   try {
-                                                       return queryStatement.executeQuery();
-                                                   } catch (SQLException ex) {
-                                                       if (Thread.interrupted()) {
-                                                           log.info("SQL query execution cancelled; not returning result (Thread={})", Thread.currentThread());
-                                                           throw new InterruptedException("SPARQL query execution cancelled");
-                                                       } else {
-                                                           throw ex;
-                                                       }
-                                                   }
-                                               }
-                                           }
-                    );
-
-            try {
-                ResultSet result = queryFuture.get();
-
-                ResultSetIteration<BindingSet> it = new ResultSetIteration<BindingSet>(result, true, new ResultTransformerFunction<BindingSet>() {
-                    @Override
-                    public BindingSet apply(ResultSet row) throws SQLException {
-                        MapBindingSet resultRow = new MapBindingSet();
-
-                        List<SQLVariable> vars = new ArrayList<>(builder.getVariables().values());
-
-                        long[] nodeIds = new long[vars.size()];
-                        for(int i=0; i<vars.size(); i++) {
-                            SQLVariable sv = vars.get(i);
-                            if(sv.getProjectionType() == ProjectionType.NODE && (builder.getProjectedVars().isEmpty() || builder.getProjectedVars().contains(sv.getSparqlName()))) {
-                                nodeIds[i] = row.getLong(sv.getName());
-                            }
-                        }
-                        KiWiNode[] nodes = parent.loadNodesByIds(nodeIds);
-
-                        for (int i = 0; i < vars.size(); i++) {
-                            SQLVariable sv = vars.get(i);
-                            if(nodes[i] != null) {
-                                // resolved node
-                                resultRow.addBinding(sv.getSparqlName(), nodes[i]);
-                            } else if(sv.getProjectionType() != ProjectionType.NONE && (builder.getProjectedVars().isEmpty() || builder.getProjectedVars().contains(sv.getSparqlName()))) {
-                                // literal value
-                                String svalue;
-                                switch (sv.getProjectionType()) {
-                                    case URI:
-                                        svalue = row.getString(sv.getName());
-                                        if(svalue != null)
-                                            resultRow.addBinding(sv.getSparqlName(), new URIImpl(svalue));
-                                        break;
-                                    case BNODE:
-                                        svalue = row.getString(sv.getName());
-                                        if(svalue != null)
-                                            resultRow.addBinding(sv.getSparqlName(), new BNodeImpl(svalue));
-                                        break;
-                                    case INT:
-                                        if(row.getObject(sv.getName()) != null) {
-                                            svalue = Integer.toString(row.getInt(sv.getName()));
-                                            URI type = XSD.Integer;
-                                            try {
-                                                long typeId = row.getLong(sv.getName() + "_TYPE");
-                                                if (typeId > 0)
-                                                    type = (URI) parent.loadNodeById(typeId);
-                                            } catch (SQLException ex) {
-                                            }
-
-                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
-                                        }
-                                        break;
-                                    case DOUBLE:
-                                        if(row.getObject(sv.getName()) != null) {
-                                            svalue = Double.toString(row.getDouble(sv.getName()));
-                                            URI type = XSD.Double;
-                                            try {
-                                                long typeId = row.getLong(sv.getName() + "_TYPE");
-                                                if (typeId > 0)
-                                                    type = (URI) parent.loadNodeById(typeId);
-                                            } catch (SQLException ex) {
-                                            }
-
-                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
-                                        }
-                                        break;
-                                    case BOOL:
-                                        if(row.getObject(sv.getName()) != null) {
-                                            svalue = Boolean.toString(row.getBoolean(sv.getName()));
-                                            resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue.toLowerCase(), XSD.Boolean));
-                                        }
-                                        break;
-                                    case STRING:
-                                    default:
-                                        svalue = row.getString(sv.getName());
-
-                                        if(svalue != null) {
-
-                                            // retrieve optional type and language information, because string functions
-                                            // need to preserve this in certain cases, even when constructing new literals
-                                            String lang = null;
-                                            try {
-                                                lang = row.getString(sv.getName() + "_LANG");
-                                            } catch (SQLException ex) {
-                                            }
-
-                                            URI type = null;
-                                            try {
-                                                long typeId = row.getLong(sv.getName() + "_TYPE");
-                                                if (typeId > 0)
-                                                    type = (URI) parent.loadNodeById(typeId);
-                                            } catch (SQLException ex) {
-                                            }
-
-                                            if (lang != null) {
-                                                if (svalue.length() > 0) {
-                                                    resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, lang));
-                                                } else {
-                                                    // string functions that return empty literal should yield no type or language
-                                                    resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(""));
-                                                }
-                                            } else if (type != null) {
-                                                if(type.stringValue().equals(XSD.String.stringValue())) {
-                                                    // string functions on other datatypes than string should yield no binding
-                                                    if (svalue.length() > 0) {
-                                                        resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, type));
-                                                    } else {
-                                                        // string functions that return empty literal should yield no type or language
-                                                        resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(""));
-                                                    }
-                                                }
-                                            } else {
-                                                resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue));
-                                            }
-
-                                        }
-                                        break;
-                                }
-                            }
-                        }
-
-
-                        if (bindings != null) {
-                            for (Binding binding : bindings) {
-                                resultRow.addBinding(binding);
-                            }
-                        }
-                        return resultRow;
-                    }
-                });
-
-                // materialize result to avoid having more than one result set open at the same time
-                return new CloseableIteratorIteration<BindingSet, SQLException>(Iterations.asList(it).iterator());
-            } catch (InterruptedException | CancellationException e) {
-                log.info("SPARQL query execution cancelled");
-                queryFuture.cancel(true);
-                queryStatement.cancel();
-                queryStatement.close();
-
-                throw new InterruptedException("SPARQL query execution cancelled");
-            } catch (ExecutionException e) {
-                log.error("error executing SPARQL query", e.getCause());
-                if (e.getCause() instanceof SQLException) {
-                    throw (SQLException) e.getCause();
-                } else if (e.getCause() instanceof InterruptedException) {
-                    throw (InterruptedException) e.getCause();
-                } else {
-                    throw new SQLException("error executing SPARQL query", e);
-                }
-            }
-        } catch (UnsatisfiableQueryException ex) {
-            return new EmptyIteration<>();
-        }
-    }
-
-    public KiWiDialect getDialect() {
-        return parent.getDialect();
-    }
-}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/89df9e03/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSail.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSail.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSail.java
index 4ce504e..ba19159 100644
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSail.java
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSail.java
@@ -24,7 +24,6 @@ import org.apache.marmotta.kiwi.persistence.pgsql.PostgreSQLDialect;
 import org.apache.marmotta.kiwi.persistence.util.ScriptRunner;
 import org.apache.marmotta.kiwi.sail.KiWiSailConnection;
 import org.apache.marmotta.kiwi.sail.KiWiStore;
-import org.apache.marmotta.kiwi.sparql.persistence.KiWiSparqlConnection;
 import org.openrdf.sail.*;
 import org.openrdf.sail.helpers.NotifyingSailWrapper;
 import org.openrdf.sail.helpers.SailConnectionWrapper;
@@ -201,11 +200,7 @@ public class KiWiSparqlSail extends NotifyingSailWrapper {
         NotifyingSailConnection connection = super.getConnection();
         KiWiSailConnection root   = getRootConnection(connection);
 
-        try {
-            return new KiWiSparqlSailConnection(connection, new KiWiSparqlConnection(root.getDatabaseConnection(), root.getValueFactory()), root.getValueFactory());
-        } catch (SQLException e) {
-            throw new SailException(e);
-        }
+        return new KiWiSparqlSailConnection(connection, root.getDatabaseConnection(), root.getValueFactory());
     }
 
 

http://git-wip-us.apache.org/repos/asf/marmotta/blob/89df9e03/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java
index 1006ebb..09333e7 100644
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java
@@ -18,13 +18,13 @@
 package org.apache.marmotta.kiwi.sparql.sail;
 
 import info.aduna.iteration.CloseableIteration;
+import org.apache.marmotta.kiwi.persistence.KiWiConnection;
 import org.apache.marmotta.kiwi.sail.KiWiValueFactory;
 import org.apache.marmotta.kiwi.sparql.evaluation.KiWiEvaluationStatistics;
-import org.apache.marmotta.kiwi.sparql.evaluation.KiWiEvaluationStrategyImpl;
+import org.apache.marmotta.kiwi.sparql.evaluation.KiWiEvaluationStrategy;
 import org.apache.marmotta.kiwi.sparql.evaluation.KiWiTripleSource;
 import org.apache.marmotta.kiwi.sparql.optimizer.DifferenceOptimizer;
 import org.apache.marmotta.kiwi.sparql.optimizer.DistinctLimitOptimizer;
-import org.apache.marmotta.kiwi.sparql.persistence.KiWiSparqlConnection;
 import org.openrdf.query.BindingSet;
 import org.openrdf.query.Dataset;
 import org.openrdf.query.QueryEvaluationException;
@@ -48,10 +48,10 @@ public class KiWiSparqlSailConnection extends NotifyingSailConnectionWrapper {
 
     private static Logger log = LoggerFactory.getLogger(KiWiSparqlSailConnection.class);
 
-    private KiWiSparqlConnection connection;
+    private KiWiConnection connection;
     private KiWiValueFactory valueFactory;
 
-    public KiWiSparqlSailConnection(NotifyingSailConnection parent, KiWiSparqlConnection connection, KiWiValueFactory valueFactory) {
+    public KiWiSparqlSailConnection(NotifyingSailConnection parent, KiWiConnection connection, KiWiValueFactory valueFactory) {
         super(parent);
         this.connection = connection;
         this.valueFactory = valueFactory;
@@ -70,7 +70,7 @@ public class KiWiSparqlSailConnection extends NotifyingSailConnectionWrapper {
 
         try {
             KiWiTripleSource tripleSource = new KiWiTripleSource(this,valueFactory,includeInferred);
-            EvaluationStrategy strategy = new KiWiEvaluationStrategyImpl(tripleSource, dataset, connection);
+            EvaluationStrategy strategy = new KiWiEvaluationStrategy(tripleSource, dataset, connection, valueFactory);
 
             new BindingAssigner().optimize(tupleExpr, dataset, bindings);
             //new ConstantOptimizer(strategy).optimize(tupleExpr, dataset, bindings);