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 <[email protected]>
Authored: Tue Nov 4 17:00:56 2014 +0100
Committer: Sebastian Schaffert <[email protected]>
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 ([email protected])
+ */
+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;
+                                }
                             }
                         }
 

Reply via email to