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/04 17:00:18 UTC
git commit: SPARQL: try preserving the type of string literals when
applying functions that return string
Repository: marmotta
Updated Branches:
refs/heads/develop 7a73135e0 -> 4bc783a95
SPARQL: try preserving the type of string literals when applying functions that return string
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/4bc783a9
Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/4bc783a9
Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/4bc783a9
Branch: refs/heads/develop
Commit: 4bc783a95f2a7d0849bd00696cd49d1d3d0ead44
Parents: 7a73135
Author: Sebastian Schaffert <ss...@apache.org>
Authored: Tue Nov 4 17:00:56 2014 +0100
Committer: Sebastian Schaffert <ss...@apache.org>
Committed: Tue Nov 4 17:00:56 2014 +0100
----------------------------------------------------------------------
.../builder/LiteralTypeExpressionFinder.java | 68 +++++++++++++++++
.../kiwi/sparql/builder/SQLBuilder.java | 43 ++++++++++-
.../kiwi/sparql/builder/SQLVariable.java | 28 +++++++
.../persistence/KiWiSparqlConnection.java | 79 +++++++++++++-------
4 files changed, 189 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4bc783a9/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/LiteralTypeExpressionFinder.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/LiteralTypeExpressionFinder.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/LiteralTypeExpressionFinder.java
new file mode 100644
index 0000000..020657b
--- /dev/null
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/LiteralTypeExpressionFinder.java
@@ -0,0 +1,68 @@
+/*
+ * 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.builder;
+
+import org.apache.marmotta.kiwi.sparql.function.NativeFunction;
+import org.apache.marmotta.kiwi.sparql.function.NativeFunctionRegistry;
+import org.openrdf.query.algebra.FunctionCall;
+import org.openrdf.query.algebra.QueryModelNode;
+import org.openrdf.query.algebra.ValueExpr;
+import org.openrdf.query.algebra.Var;
+import org.openrdf.query.algebra.helpers.QueryModelVisitorBase;
+
+/**
+ * Functions that return a string literal do so with the string literal of the same kind as the first
+ * argument (simple literal, plain literal with same language tag, xsd:string). This visitor
+ * tries finding the relevant subexpression in a complex value expression.
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class LiteralTypeExpressionFinder extends QueryModelVisitorBase<RuntimeException> {
+
+ protected Var expr = null;
+
+ public LiteralTypeExpressionFinder(ValueExpr expr) {
+ expr.visit(this);
+ }
+
+ @Override
+ public void meet(FunctionCall node) throws RuntimeException {
+ NativeFunction nf = NativeFunctionRegistry.getInstance().get(node.getURI());
+ if(node.getArgs().size() > 0 && nf.getReturnType() == OPTypes.STRING) {
+ node.getArgs().get(0).visit(this);
+ }
+ // otherwise stop here, the function call hides the type and language anyways
+ }
+
+ @Override
+ public void meet(Var node) throws RuntimeException {
+ expr = node;
+ }
+
+ /**
+ * Method called by all of the other <tt>meet</tt> methods that are not
+ * overridden in subclasses. This method can be overridden in subclasses to
+ * define default behaviour when visiting nodes. The default behaviour of
+ * this method is to visit the node's children.
+ *
+ * @param node The node that is being visited.
+ */
+ @Override
+ protected void meetNode(QueryModelNode node) throws RuntimeException {
+ }
+}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4bc783a9/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLBuilder.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLBuilder.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLBuilder.java
index 20899c2..fd01c1a 100644
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLBuilder.java
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLBuilder.java
@@ -273,6 +273,11 @@ public class SQLBuilder {
sv.setProjectionType(getProjectionType(ext.getExpr()));
}
+ // Functions that return a string literal do so with the string literal of the same kind as the first
+ // argument (simple literal, plain literal with same language tag, xsd:string).
+ sv.setLiteralTypeExpression(getLiteralTypeExpression(ext.getExpr()));
+ sv.setLiteralLangExpression(getLiteralLangExpression(ext.getExpr()));
+
addVariable(sv);
}
@@ -400,6 +405,7 @@ public class SQLBuilder {
}
+
private void prepareConditions() throws UnsatisfiableQueryException {
// build the where clause as follows:
// 1. iterate over all patterns and for each resource and literal field in subject,
@@ -525,6 +531,13 @@ public class SQLBuilder {
String fromName = v.getExpressions().get(0);
projections.add(fromName + " AS " + projectedName);
+
+ if(v.getLiteralTypeExpression() != null) {
+ projections.add(v.getLiteralTypeExpression() + " AS " + projectedName + "_TYPE");
+ }
+ if(v.getLiteralLangExpression() != null) {
+ projections.add(v.getLiteralLangExpression() + " AS " + projectedName + "_LANG");
+ }
}
}
@@ -967,8 +980,7 @@ public class SQLBuilder {
FunctionCall fc = (FunctionCall)expr;
// special optimizations for frequent cases with variables
- if((XMLSchema.DOUBLE.toString().equals(fc.getURI()) || XMLSchema.FLOAT.toString().equals(fc.getURI()) ) &&
- fc.getArgs().size() == 1) {
+ if((XMLSchema.DOUBLE.toString().equals(fc.getURI()) || XMLSchema.FLOAT.toString().equals(fc.getURI()) ) && fc.getArgs().size() == 1) {
return evaluateExpression(fc.getArgs().get(0), OPTypes.DOUBLE);
} else if((XMLSchema.INTEGER.toString().equals(fc.getURI()) || XMLSchema.INT.toString().equals(fc.getURI())) && fc.getArgs().size() == 1) {
return evaluateExpression(fc.getArgs().get(0), OPTypes.INT);
@@ -1204,6 +1216,33 @@ public class SQLBuilder {
}
}
+
+ private String getLiteralLangExpression(ValueExpr expr) {
+ Var langVar = new LiteralTypeExpressionFinder(expr).expr;
+
+ if(langVar != null) {
+ SQLVariable sqlVar = variables.get(langVar.getName());
+ if(sqlVar != null) {
+ return sqlVar.getAlias() + ".lang";
+ }
+ }
+ return null;
+
+ }
+
+ private String getLiteralTypeExpression(ValueExpr expr) {
+ Var typeVar = new LiteralTypeExpressionFinder(expr).expr;
+
+ if(typeVar != null) {
+ SQLVariable sqlVar = variables.get(typeVar.getName());
+ if(sqlVar != null) {
+ return sqlVar.getAlias() + ".ltype";
+ }
+ }
+ return null;
+ }
+
+
/**
* Construct the SQL query for the given SPARQL query part.
*
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4bc783a9/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLVariable.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLVariable.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLVariable.java
index bbcd153..921a2f1 100644
--- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLVariable.java
+++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/SQLVariable.java
@@ -68,6 +68,18 @@ public class SQLVariable implements Cloneable{
*/
private ProjectionType projectionType = ProjectionType.NONE;
+ /**
+ * The expression to project the type for the literal that will be bound to this variable, e.g. in case
+ * the main expression is a function call and the type should be preserved.
+ */
+ private String literalTypeExpression = null;
+
+ /**
+ * The expression to project the language for the literal that will be bound to this variable, e.g. in case
+ * the main expression is a function call and the language should be preserved.
+ */
+ private String literalLangExpression = null;
+
public SQLVariable(String name, String sparqlName) {
this.name = name;
this.sparqlName = sparqlName;
@@ -112,6 +124,22 @@ public class SQLVariable implements Cloneable{
this.projectionType = projectionType;
}
+ public String getLiteralTypeExpression() {
+ return literalTypeExpression;
+ }
+
+ public void setLiteralTypeExpression(String literalTypeExpression) {
+ this.literalTypeExpression = literalTypeExpression;
+ }
+
+ public String getLiteralLangExpression() {
+ return literalLangExpression;
+ }
+
+ public void setLiteralLangExpression(String literalLangExpression) {
+ this.literalLangExpression = literalLangExpression;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
http://git-wip-us.apache.org/repos/asf/marmotta/blob/4bc783a9/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
index 0c85daa..7d91d6b 100644
--- 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
@@ -32,6 +32,8 @@ import org.apache.marmotta.kiwi.sparql.builder.ProjectionType;
import org.apache.marmotta.kiwi.sparql.builder.SQLBuilder;
import org.apache.marmotta.kiwi.sparql.builder.SQLVariable;
import org.apache.marmotta.kiwi.sparql.exception.UnsatisfiableQueryException;
+import org.openrdf.model.Literal;
+import org.openrdf.model.URI;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.query.Binding;
@@ -138,35 +140,58 @@ public class KiWiSparqlConnection {
} 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 INT:
- if(row.getObject(sv.getName()) != null) {
- svalue = Integer.toString(row.getInt(sv.getName()));
- resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, XSD.Integer));
+ switch (sv.getProjectionType()) {
+ case URI:
+ svalue = row.getString(sv.getName());
+ if(svalue != null)
+ resultRow.addBinding(sv.getSparqlName(), new URIImpl(svalue));
+ break;
+ case INT:
+ if(row.getObject(sv.getName()) != null) {
+ svalue = Integer.toString(row.getInt(sv.getName()));
+ resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, XSD.Integer));
+ }
+ break;
+ case DOUBLE:
+ if(row.getObject(sv.getName()) != null) {
+ svalue = Double.toString(row.getDouble(sv.getName()));
+ resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, XSD.Double));
+ }
+ break;
+ case STRING:
+ default:
+ svalue = row.getString(sv.getName());
+
+ if(svalue != null) {
+
+ // retrieve optional type and language information
+ String lang = null;
+ URI type = null;
+ try {
+ lang = row.getString(sv.getName() + "_LANG");
+ } catch (SQLException ex) {
}
- break;
- case DOUBLE:
- if(row.getObject(sv.getName()) != null) {
- svalue = Double.toString(row.getDouble(sv.getName()));
- resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue, XSD.Double));
+
+ try {
+ long typeId = row.getLong(sv.getName() + "_TYPE");
+ if (typeId > 0)
+ type = (URI) parent.loadNodeById(typeId);
+ } catch (SQLException ex) {
+ }
+
+ Literal v;
+ if(lang != null) {
+ v = new LiteralImpl(svalue,lang);
+ } else if(type != null) {
+ v = new LiteralImpl(svalue,type);
+ } else {
+ v = new LiteralImpl(svalue);
}
- break;
- case STRING:
- svalue = row.getString(sv.getName());
- if(svalue != null)
- resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue));
- break;
- default:
- svalue = row.getString(sv.getName());
- if(svalue != null)
- resultRow.addBinding(sv.getSparqlName(), new LiteralImpl(svalue));
- break;
- }
+
+ resultRow.addBinding(sv.getSparqlName(), v);
+ }
+ break;
+ }
}
}