implementation of MARMOTTA-536 (BIND) and a large number of additional functions for postgres
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/5be6ef2e Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/5be6ef2e Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/5be6ef2e Branch: refs/heads/ldp Commit: 5be6ef2eb2ad43407a1d82b787e209fcb0af56c1 Parents: 8429f69 Author: Sebastian Schaffert <[email protected]> Authored: Tue Sep 16 15:45:35 2014 +0200 Committer: Sebastian Schaffert <[email protected]> Committed: Tue Sep 16 15:45:35 2014 +0200 ---------------------------------------------------------------------- .../marmotta/kiwi/sparql/builder/OPTypes.java | 2 +- .../kiwi/sparql/builder/ProjectionType.java | 27 ++++ .../kiwi/sparql/builder/SQLBuilder.java | 136 +++++++++++++++++-- .../evaluation/KiWiEvaluationStrategyImpl.java | 5 +- .../kiwi/sparql/function/FunctionUtil.java | 85 ++++++++++++ .../persistence/KiWiSparqlConnection.java | 33 ++++- .../persistence/pgsql/PostgreSQLDialect.java | 65 +++++++++ .../marmotta/kiwi/vocabulary/FN_MARMOTTA.java | 38 ++++++ .../persistence/pgsql/create_base_tables.sql | 2 + 9 files changed, 374 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/OPTypes.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/OPTypes.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/OPTypes.java index 9139e79..db307b2 100644 --- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/OPTypes.java +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/OPTypes.java @@ -23,5 +23,5 @@ package org.apache.marmotta.kiwi.sparql.builder; * @author Sebastian Schaffert ([email protected]) */ public enum OPTypes { - STRING, DOUBLE, INT, DATE, BOOL, VALUE, ANY + STRING, DOUBLE, INT, DATE, BOOL, VALUE, ANY, URI } http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/ProjectionType.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/ProjectionType.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/ProjectionType.java new file mode 100644 index 0000000..0c6c9fa --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/builder/ProjectionType.java @@ -0,0 +1,27 @@ +/* + * 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; + +/** + * Add file description here! + * + * @author Sebastian Schaffert ([email protected]) + */ +public enum ProjectionType { + NODE, URI, STRING, INT, DOUBLE, DATE +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/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 8ed4781..cdee921 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 @@ -21,12 +21,14 @@ import com.google.common.base.Preconditions; import org.apache.commons.lang3.StringUtils; import org.apache.marmotta.commons.collections.CollectionUtils; import org.apache.marmotta.commons.util.DateUtils; +import org.apache.marmotta.commons.vocabulary.XSD; import org.apache.marmotta.kiwi.model.rdf.KiWiNode; import org.apache.marmotta.kiwi.persistence.KiWiDialect; import org.apache.marmotta.kiwi.sail.KiWiValueFactory; import org.apache.marmotta.kiwi.sparql.exception.UnsatisfiableQueryException; +import org.apache.marmotta.kiwi.sparql.function.FunctionUtil; +import org.apache.marmotta.kiwi.vocabulary.FN_MARMOTTA; import org.openrdf.model.*; -import org.openrdf.model.impl.URIImpl; import org.openrdf.model.vocabulary.FN; import org.openrdf.model.vocabulary.SESAME; import org.openrdf.model.vocabulary.XMLSchema; @@ -82,6 +84,22 @@ public class SQLBuilder { functionParameterTypes.put(FN.NUMERIC_FLOOR, OPTypes.DOUBLE); functionParameterTypes.put(FN.NUMERIC_ROUND, OPTypes.DOUBLE); + + functionParameterTypes.put(FN_MARMOTTA.YEAR, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.MONTH, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.DAY, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.HOURS, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.MINUTES, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.SECONDS, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.TIMEZONE, OPTypes.DATE); + functionParameterTypes.put(FN_MARMOTTA.TZ, OPTypes.DATE); + + functionParameterTypes.put(FN_MARMOTTA.MD5, OPTypes.STRING); + functionParameterTypes.put(FN_MARMOTTA.SHA1, OPTypes.STRING); + functionParameterTypes.put(FN_MARMOTTA.SHA256, OPTypes.STRING); + functionParameterTypes.put(FN_MARMOTTA.SHA384, OPTypes.STRING); + functionParameterTypes.put(FN_MARMOTTA.SHA512, OPTypes.STRING); + } /** @@ -106,6 +124,24 @@ public class SQLBuilder { functionReturnTypes.put(FN.NUMERIC_FLOOR, OPTypes.INT); functionReturnTypes.put(FN.NUMERIC_ROUND, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.UUID, OPTypes.URI); + functionReturnTypes.put(FN_MARMOTTA.STRUUID, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.RAND, OPTypes.DOUBLE); + functionReturnTypes.put(FN_MARMOTTA.NOW, OPTypes.DATE); + functionReturnTypes.put(FN_MARMOTTA.YEAR, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.MONTH, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.DAY, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.HOURS, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.MINUTES, OPTypes.INT); + functionReturnTypes.put(FN_MARMOTTA.SECONDS, OPTypes.DOUBLE); + functionReturnTypes.put(FN_MARMOTTA.TIMEZONE, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.TZ, OPTypes.STRING); + + functionReturnTypes.put(FN_MARMOTTA.MD5, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.SHA1, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.SHA256, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.SHA384, OPTypes.STRING); + functionReturnTypes.put(FN_MARMOTTA.SHA512, OPTypes.STRING); } @@ -138,7 +174,7 @@ public class SQLBuilder { * depending on the number of patterns it occurs in; will look like * { ?x -> ["P1_V1", "P2_V1"], ?y -> ["P2_V2"], ... } */ - private Map<Var,List<String>> queryVariables = new HashMap<>(); + private Map<String,List<String>> queryVariables = new HashMap<>(); /** @@ -148,6 +184,8 @@ public class SQLBuilder { private Map<Var,List<String>> queryVariableIds = new HashMap<>(); + private Map<Var, ProjectionType> variableTypes = new HashMap<>(); + /** * The triple patterns collected from the query. @@ -238,6 +276,17 @@ public class SQLBuilder { return variableNames.get(v); } + + /** + * Return the type of a projected variable. Usually this is a node id to be resolved in the next step, but some + * projections also create literal values of various types. + * @param v + * @return + */ + public ProjectionType getVariableType(Var v) { + return variableTypes.get(v); + } + private void prepareBuilder() throws UnsatisfiableQueryException { Preconditions.checkArgument(query instanceof Extension || query instanceof Order || query instanceof Group || query instanceof LeftJoin ||query instanceof Join || query instanceof Filter || query instanceof StatementPattern || query instanceof Distinct || query instanceof Slice || query instanceof Reduced); @@ -274,13 +323,14 @@ public class SQLBuilder { Var v = fields[i]; if (variableNames.get(v) == null) { variableNames.put(v, "V" + (++variableCount)); - queryVariables.put(v, new LinkedList<String>()); + variableTypes.put(v, ProjectionType.NODE); + queryVariables.put(v.getName(), new LinkedList<String>()); queryVariableIds.put(v, new LinkedList<String>()); } String pName = p.getName(); String vName = variableNames.get(v); if (hasNodeCondition(fields[i], query)) { - queryVariables.get(v).add(pName + "_" + positions[i] + "_" + vName); + queryVariables.get(v.getName()).add(pName + "_" + positions[i] + "_" + vName); } // if the variable has been used before, add a join condition to the first occurrence @@ -299,11 +349,14 @@ public class SQLBuilder { Var v = new Var(ext.getName()); if (variableNames.get(v) == null) { variableNames.put(v, "V" + (++variableCount)); - queryVariables.put(v, new LinkedList<String>()); + + // set variable type according to expression; we need this later to decide what kind of node to construct + variableTypes.put(v, getProjectionType(ext.getExpr())); + queryVariables.put(v.getName(), new LinkedList<String>()); queryVariableIds.put(v, new LinkedList<String>()); } if (hasNodeCondition(v, query)) { - queryVariables.get(v).add(evaluateExpression(ext.getExpr(), OPTypes.ANY)); + queryVariables.get(v.getName()).add(evaluateExpression(ext.getExpr(), OPTypes.ANY)); } queryVariableIds.get(v).add(evaluateExpression(ext.getExpr(), OPTypes.ANY)); @@ -704,7 +757,7 @@ public class SQLBuilder { Lang lang = (Lang)expr; if(lang.getArg() instanceof Var) { - return queryVariables.get(lang.getArg()).get(0) + ".lang"; + return queryVariables.get(((Var) lang.getArg()).getName()).get(0) + ".lang"; } } else if(expr instanceof Compare) { Compare cmp = (Compare)expr; @@ -749,7 +802,7 @@ public class SQLBuilder { if(arg instanceof ValueConstant) { return Boolean.toString(((ValueConstant) arg).getValue() instanceof URI || ((ValueConstant) arg).getValue() instanceof BNode); } else if(arg instanceof Var) { - String var = queryVariables.get(arg).get(0); + String var = queryVariables.get(((Var) arg).getName()).get(0); return "(" + var + ".ntype = 'uri' OR " + var + ".ntype = 'bnode')"; } @@ -760,7 +813,7 @@ public class SQLBuilder { if(arg instanceof ValueConstant) { return Boolean.toString(((ValueConstant) arg).getValue() instanceof URI); } else if(arg instanceof Var) { - String var = queryVariables.get(arg).get(0); + String var = queryVariables.get(((Var) arg).getName()).get(0); return var + ".ntype = 'uri'"; } @@ -771,7 +824,7 @@ public class SQLBuilder { if(arg instanceof ValueConstant) { return Boolean.toString(((ValueConstant) arg).getValue() instanceof BNode); } else if(arg instanceof Var) { - String var = queryVariables.get(arg).get(0); + String var = queryVariables.get(((Var) arg).getName()).get(0); return var + ".ntype = 'bnode'"; } @@ -782,12 +835,12 @@ public class SQLBuilder { if(arg instanceof ValueConstant) { return Boolean.toString(((ValueConstant) arg).getValue() instanceof Literal); } else if(arg instanceof Var) { - String var = queryVariables.get(arg).get(0); + String var = queryVariables.get(((Var) arg).getName()).get(0); return "(" + var + ".ntype = 'string' OR " + var + ".ntype = 'int' OR " + var + ".ntype = 'double' OR " + var + ".ntype = 'date' OR " + var + ".ntype = 'boolean')"; } } else if(expr instanceof Var) { - String var = queryVariables.get(expr).get(0); + String var = queryVariables.get(((Var) expr).getName()).get(0); if(optype == null) { return var + ".svalue"; @@ -798,6 +851,7 @@ public class SQLBuilder { case DOUBLE: return var + ".dvalue"; case DATE: return var + ".tvalue"; case VALUE: return var + ".svalue"; + case URI: return var + ".svalue"; case ANY: return var + ".id"; } } @@ -810,9 +864,11 @@ public class SQLBuilder { switch (optype) { case STRING: return "'" + val + "'"; case VALUE: return "'" + val + "'"; + case URI: return "'" + val + "'"; case INT: return "" + Integer.parseInt(val); case DOUBLE: return "" + Double.parseDouble(val); case DATE: return "'" + sqlDateFormat.format(DateUtils.parseDate(val)) + "'"; + case ANY: return "'" + val + "'"; default: throw new IllegalArgumentException("unsupported value type: " + optype); } } @@ -838,7 +894,7 @@ public class SQLBuilder { return evaluateExpression(fc.getArgs().get(0), OPTypes.DATE); } - URI fnUri = new URIImpl(fc.getURI()); + URI fnUri = FunctionUtil.getFunctionUri(fc.getURI());; String[] args = new String[fc.getArgs().size()]; @@ -928,7 +984,7 @@ public class SQLBuilder { private boolean hasNodeCondition(Var v, ValueExpr expr) { if(expr instanceof Var) { - return v.equals(expr); + return v.getName().equals(((Var) expr).getName()); } else if(expr instanceof UnaryValueOperator) { return hasNodeCondition(v, ((UnaryValueOperator) expr).getArg()); } else if(expr instanceof BinaryValueOperator) { @@ -1045,6 +1101,58 @@ public class SQLBuilder { } + private ProjectionType getProjectionType(ValueExpr expr) { + if(expr instanceof FunctionCall) { + return opTypeToProjection(functionReturnTypes.get(FunctionUtil.getFunctionUri(((FunctionCall) expr).getURI()))); + } else if(expr instanceof NAryValueOperator) { + return getProjectionType(((NAryValueOperator) expr).getArguments().get(0)); + } else if(expr instanceof ValueConstant) { + if (((ValueConstant) expr).getValue() instanceof URI) { + return ProjectionType.URI; + } else if (((ValueConstant) expr).getValue() instanceof Literal) { + Literal l = (Literal) ((ValueConstant) expr).getValue(); + if (XSD.Integer.equals(l.getDatatype()) || XSD.Int.equals(l.getDatatype())) { + return ProjectionType.INT; + } else if (XSD.Double.equals(l.getDatatype()) || XSD.Float.equals(l.getDatatype())) { + return ProjectionType.DOUBLE; + } else { + return ProjectionType.STRING; + } + + } else { + return ProjectionType.STRING; + } + } else if(expr instanceof Var) { + return ProjectionType.NODE; + } else if(expr instanceof MathExpr) { + MathExpr cmp = (MathExpr)expr; + + return opTypeToProjection(new OPTypeFinder(cmp).coerce()); + } else { + return ProjectionType.STRING; + } + + } + + private ProjectionType opTypeToProjection(OPTypes t) { + switch (t) { + case ANY: + return ProjectionType.NODE; + case URI: + return ProjectionType.URI; + case DOUBLE: + return ProjectionType.DOUBLE; + case INT: + return ProjectionType.INT; + case DATE: + return ProjectionType.DATE; + case STRING: + return ProjectionType.STRING; + default: + log.warn("optype {} cannot be projected!",t); + return ProjectionType.STRING; + } + } /** * Construct the SQL query for the given SPARQL query part. http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/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 index 8cd1a15..201cccb 100644 --- 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 @@ -19,9 +19,9 @@ package org.apache.marmotta.kiwi.sparql.evaluation; import info.aduna.iteration.CloseableIteration; import info.aduna.iteration.ExceptionConvertingIteration; +import org.apache.marmotta.kiwi.sparql.function.FunctionUtil; import org.apache.marmotta.kiwi.sparql.persistence.KiWiSparqlConnection; import org.openrdf.model.URI; -import org.openrdf.model.impl.URIImpl; import org.openrdf.query.BindingSet; import org.openrdf.query.Dataset; import org.openrdf.query.QueryEvaluationException; @@ -384,10 +384,11 @@ public class KiWiEvaluationStrategyImpl extends EvaluationStrategyImpl{ } private boolean isFunctionSupported(FunctionCall fc) { - URI fnUri = new URIImpl(fc.getURI()); + URI fnUri = FunctionUtil.getFunctionUri(fc.getURI()); return connection.getDialect().isFunctionSupported(fnUri); } + private static boolean isAtomic(ValueExpr expr) { return expr instanceof Var || expr instanceof ValueConstant; } http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/function/FunctionUtil.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/function/FunctionUtil.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/function/FunctionUtil.java new file mode 100644 index 0000000..b1cc900 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/function/FunctionUtil.java @@ -0,0 +1,85 @@ +/* + * 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.function; + +import org.apache.marmotta.kiwi.vocabulary.FN_MARMOTTA; +import org.openrdf.model.URI; +import org.openrdf.model.impl.URIImpl; +import org.openrdf.model.vocabulary.FN; + +/** + * Add file description here! + * + * @author Sebastian Schaffert ([email protected]) + */ +public class FunctionUtil { + + /** + * Map function call (internal or proper URI) to the proper SPARQL function URI + * @param uri + * @return + */ + public static URI getFunctionUri(String uri) { + if(uri.equalsIgnoreCase("RAND")) { + return FN_MARMOTTA.RAND; + } else if(uri.equalsIgnoreCase("UUID")) { + return FN_MARMOTTA.UUID; + } else if(uri.equalsIgnoreCase("STRUUID")) { + return FN_MARMOTTA.STRUUID; + } else if(uri.equalsIgnoreCase("MD5")) { + return FN_MARMOTTA.MD5; + } else if(uri.equalsIgnoreCase("SHA1")) { + return FN_MARMOTTA.SHA1; + } else if(uri.equalsIgnoreCase("SHA256")) { + return FN_MARMOTTA.SHA256; + } else if(uri.equalsIgnoreCase("SHA384")) { + return FN_MARMOTTA.SHA384; + } else if(uri.equalsIgnoreCase("SHA512")) { + return FN_MARMOTTA.SHA512; + } else if(uri.equalsIgnoreCase("NOW")) { + return FN_MARMOTTA.NOW; + } else if(uri.equalsIgnoreCase("YEAR")) { + return FN_MARMOTTA.YEAR; + } else if(uri.equalsIgnoreCase("MONTH")) { + return FN_MARMOTTA.MONTH; + } else if(uri.equalsIgnoreCase("DAY")) { + return FN_MARMOTTA.DAY; + } else if(uri.equalsIgnoreCase("HOURS")) { + return FN_MARMOTTA.HOURS; + } else if(uri.equalsIgnoreCase("MINUTES")) { + return FN_MARMOTTA.MINUTES; + } else if(uri.equalsIgnoreCase("SECONDS")) { + return FN_MARMOTTA.SECONDS; + } else if(uri.equalsIgnoreCase("TIMEZONE")) { + return FN_MARMOTTA.TIMEZONE; + } else if(uri.equalsIgnoreCase("TZ")) { + return FN_MARMOTTA.TZ; + } else if(uri.equalsIgnoreCase("ABS")) { + return FN.NUMERIC_ABS; + } else if(uri.equalsIgnoreCase("CEIL")) { + return FN.NUMERIC_CEIL; + } else if(uri.equalsIgnoreCase("FLOOR")) { + return FN.NUMERIC_FLOOR; + } else if(uri.equalsIgnoreCase("ROUND")) { + return FN.NUMERIC_ROUND; + } + + return new URIImpl(uri); + } + +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/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 3c9d288..a662e40 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 @@ -21,14 +21,18 @@ 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.exception.UnsatisfiableQueryException; +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; @@ -118,14 +122,39 @@ public class KiWiSparqlConnection { long[] nodeIds = new long[vars.size()]; for(int i=0; i<vars.size(); i++) { - nodeIds[i] = row.getLong(builder.getVariableName(vars.get(i))); + if(builder.getVariableType(vars.get(i)) == ProjectionType.NODE) { + nodeIds[i] = row.getLong(builder.getVariableName(vars.get(i))); + } } KiWiNode[] nodes = parent.loadNodesByIds(nodeIds); for (int i = 0; i < vars.size(); i++) { + Var v = vars.get(i); if(nodes[i] != null) { - Var v = vars.get(i); + // resolved node resultRow.addBinding(v.getName(), nodes[i]); + } else { + // literal value + String value = row.getString(builder.getVariableName(v)); + if(value != null) { + switch (builder.getVariableType(v)) { + case URI: + resultRow.addBinding(v.getName(), new URIImpl(value)); + break; + case INT: + resultRow.addBinding(v.getName(), new LiteralImpl(value, XSD.Integer)); + break; + case DOUBLE: + resultRow.addBinding(v.getName(), new LiteralImpl(value, XSD.Double)); + break; + case STRING: + resultRow.addBinding(v.getName(), new LiteralImpl(value)); + break; + default: + resultRow.addBinding(v.getName(), new LiteralImpl(value)); + break; + } + } } } http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java index 556a5d5..42940ea 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java @@ -66,6 +66,17 @@ public class PostgreSQLDialect extends KiWiDialect { supportedFunctions.put(FN_MARMOTTA.SEARCH_FULLTEXT); supportedFunctions.put(FN_MARMOTTA.QUERY_FULLTEXT); + + supportedFunctions.put(FN_MARMOTTA.NOW); + + supportedFunctions.put(FN_MARMOTTA.RAND); + supportedFunctions.put(FN_MARMOTTA.UUID); + supportedFunctions.put(FN_MARMOTTA.STRUUID); + supportedFunctions.put(FN_MARMOTTA.MD5); + supportedFunctions.put(FN_MARMOTTA.SHA1); + supportedFunctions.put(FN_MARMOTTA.SHA256); + supportedFunctions.put(FN_MARMOTTA.SHA384); + supportedFunctions.put(FN_MARMOTTA.SHA512); } /** @@ -246,6 +257,60 @@ public class PostgreSQLDialect extends KiWiDialect { } else { throw new IllegalArgumentException("invalid number of arguments"); } + } else if(FN_MARMOTTA.NOW.equals(fnUri)) { + if(args.length == 0) { + return "now()"; + } else { + throw new IllegalArgumentException("NOW() does not take arguments"); + } + } else if(FN_MARMOTTA.RAND.equals(fnUri)) { + if(args.length == 0) { + return "random()"; + } else { + throw new IllegalArgumentException("RAND() does not take arguments"); + } + } else if(FN_MARMOTTA.UUID.equals(fnUri)) { + if(args.length == 0) { + return "'urn:uuid:' || gen_random_uuid()"; + } else { + throw new IllegalArgumentException("UUID() does not take arguments"); + } + } else if(FN_MARMOTTA.STRUUID.equals(fnUri)) { + if(args.length == 0) { + return "CAST(gen_random_uuid() AS text)"; + } else { + throw new IllegalArgumentException("STRUUID() does not take arguments"); + } + } else if(FN_MARMOTTA.MD5.equals(fnUri)) { + if(args.length == 1) { + return String.format("encode(digest('%s', 'md5'), 'hex')", args[0]); + } else { + throw new IllegalArgumentException("MD5() takes exactly 1 argument"); + } + } else if(FN_MARMOTTA.SHA1.equals(fnUri)) { + if(args.length == 1) { + return String.format("encode(digest('%s', 'sha1'), 'hex')", args[0]); + } else { + throw new IllegalArgumentException("SHA1() takes exactly 1 argument"); + } + } else if(FN_MARMOTTA.SHA256.equals(fnUri)) { + if(args.length == 1) { + return String.format("encode(digest('%s', 'sha256'), 'hex')", args[0]); + } else { + throw new IllegalArgumentException("SHA256() takes exactly 1 argument"); + } + } else if(FN_MARMOTTA.SHA384.equals(fnUri)) { + if(args.length == 1) { + return String.format("encode(digest('%s', 'sha384'), 'hex')", args[0]); + } else { + throw new IllegalArgumentException("SHA384() takes exactly 1 argument"); + } + } else if(FN_MARMOTTA.SHA512.equals(fnUri)) { + if(args.length == 1) { + return String.format("encode(digest('%s', 'sha512'), 'hex')", args[0]); + } else { + throw new IllegalArgumentException("SHA512() takes exactly 1 argument"); + } } throw new UnsupportedOperationException("operation "+fnUri+" not supported"); } http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/vocabulary/FN_MARMOTTA.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/vocabulary/FN_MARMOTTA.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/vocabulary/FN_MARMOTTA.java index 47c3b8a..89f2b41 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/vocabulary/FN_MARMOTTA.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/vocabulary/FN_MARMOTTA.java @@ -48,10 +48,48 @@ public class FN_MARMOTTA { public static final URI QUERY_FULLTEXT; + // URIs for SPARQL built-in functions, used internally by marmotta + public static final URI RAND; + public static final URI UUID; + public static final URI STRUUID; + public static final URI NOW; + public static final URI YEAR; + public static final URI MONTH; + public static final URI DAY; + public static final URI HOURS; + public static final URI MINUTES; + public static final URI SECONDS; + public static final URI TIMEZONE; + public static final URI TZ; + public static final URI MD5; + public static final URI SHA1; + public static final URI SHA256; + public static final URI SHA384; + public static final URI SHA512; + + static { ValueFactory f = new ValueFactoryImpl(); SEARCH_FULLTEXT = f.createURI(NAMESPACE,"fulltext-search"); QUERY_FULLTEXT = f.createURI(NAMESPACE,"fulltext-query"); + + RAND = f.createURI(NAMESPACE,"rand"); + UUID = f.createURI(NAMESPACE,"uuid"); + STRUUID = f.createURI(NAMESPACE,"struuid"); + NOW = f.createURI(NAMESPACE,"now"); + YEAR = f.createURI(NAMESPACE,"year"); + MONTH = f.createURI(NAMESPACE,"month"); + DAY = f.createURI(NAMESPACE,"day"); + HOURS = f.createURI(NAMESPACE,"hours"); + MINUTES = f.createURI(NAMESPACE,"minutes"); + SECONDS = f.createURI(NAMESPACE,"seconds"); + TIMEZONE = f.createURI(NAMESPACE,"timezone"); + TZ = f.createURI(NAMESPACE,"tz"); + MD5 = f.createURI(NAMESPACE,"md5"); + SHA1 = f.createURI(NAMESPACE,"sha1"); + SHA256 = f.createURI(NAMESPACE,"sha256"); + SHA384 = f.createURI(NAMESPACE,"sha384"); + SHA512 = f.createURI(NAMESPACE,"sha512"); } } http://git-wip-us.apache.org/repos/asf/marmotta/blob/5be6ef2e/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/create_base_tables.sql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/create_base_tables.sql b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/create_base_tables.sql index 1936a6b..844005f 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/create_base_tables.sql +++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/create_base_tables.sql @@ -14,6 +14,8 @@ -- limitations under the License. CREATE TYPE nodetype AS ENUM ('uri','bnode','string','int','double','date','boolean'); +CREATE EXTENSION IF NOT EXISTS pgcrypto; + CREATE TABLE nodes ( id bigint NOT NULL, ntype nodetype NOT NULL,
