From fd96d457705b05e6db35f5413520e7d961c5fb1e Mon Sep 17 00:00:00 2001 From: Jey Puget Gil Date: Thu, 31 Oct 2024 18:29:53 +0100 Subject: [PATCH] QuaQue is now on Iterator --- .github/workflows/integration-test.yml | 2 +- .../jpugetgil/converg/BindingIterator.java | 154 ++++++++++++++++++ .../converg/SPARQLLanguageTranslator.java | 2 + .../converg/SPARQLtoSQLTranslator.java | 87 +--------- 4 files changed, 165 insertions(+), 80 deletions(-) create mode 100644 quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/BindingIterator.java diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 5898709..4b5c758 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -4,7 +4,7 @@ on: push: branches: - '*' - - '!master' + - '!main' jobs: test: diff --git a/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/BindingIterator.java b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/BindingIterator.java new file mode 100644 index 0000000..4530848 --- /dev/null +++ b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/BindingIterator.java @@ -0,0 +1,154 @@ +package fr.cnrs.liris.jpugetgil.converg; + +import org.apache.jena.datatypes.xsd.XSDDatatype; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.binding.BindingBuilder; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; +import java.util.*; +import java.util.function.Consumer; + +public class BindingIterator implements Iterator { + private final ResultSet resultSet; + private final ResultSetMetaData rsmd; + private final List allVariables = new ArrayList<>(); + private final List variables = new ArrayList<>(); + private final Set vars = new HashSet<>(); + + public BindingIterator(ResultSet resultSet) throws SQLException { + this.resultSet = resultSet; + this.rsmd = resultSet.getMetaData(); + buildAllVariablesAndVariables(); + } + + public Set getVars() { + return vars; + } + + @Override + public Binding next() { + try { + resultSet.next(); + + BindingBuilder bindingBuilder = Binding.builder(); + + for (String v : variables) { + Var variable = Var.alloc(v); + Node variableValue; + + try { + if (hasColumn(resultSet, "name$" + v) && resultSet.getString("name$" + v) != null) { + String value = resultSet.getString("name$" + v); + String valueType; + if (allVariables.contains("type$" + v)) { + valueType = resultSet.getString("type$" + v); + } else { + valueType = getAssociatedRDFType(rsmd.getColumnType(resultSet.findColumn("name$" + v))); + } + variableValue = valueType == null ? + NodeFactory.createURI(value) : NodeFactory.createLiteral(value, NodeFactory.getType(valueType)); + } else if (hasColumn(resultSet, v) && resultSet.getString(v) != null) { + String value = resultSet.getString(v); + String valueType = getAssociatedRDFType(rsmd.getColumnType(resultSet.findColumn(v))); + variableValue = NodeFactory.createLiteral(value, NodeFactory.getType(valueType)); + } else { + variableValue = null; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + + if (variableValue != null) { + bindingBuilder.add(variable, variableValue); + } + } + + return bindingBuilder.build(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * @return true if the iteration has more elements + */ + @Override + public boolean hasNext() { + try { + boolean hasNext = !resultSet.isLast(); + + if (!hasNext) { + resultSet.close(); + } + return hasNext; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * + */ + @Override + public void remove() { + Iterator.super.remove(); + } + + /** + * @param action The action to be performed for each element + */ + @Override + public void forEachRemaining(Consumer action) { + while (hasNext()) { + action.accept(next()); + } + } + + private void buildAllVariablesAndVariables() throws SQLException { + int nbColumns = rsmd.getColumnCount(); + for (int i = 1; i <= nbColumns; i++) { + String columnName = rsmd.getColumnName(i); + allVariables.add(columnName); + + if (columnName.startsWith("name$")) { + String variableName = columnName.substring(5); + variables.add(variableName); + Var var = Var.alloc(variableName); + vars.add(var); + } else if (!columnName.startsWith("type$")) { + variables.add(columnName); + Var var = Var.alloc(columnName); + vars.add(var); + } + } + } + + private boolean hasColumn(java.sql.ResultSet rs, String columnName) { + try { + rs.findColumn(columnName); + return true; + } catch (SQLException e) { + return false; + } + } + + private String getAssociatedRDFType(int sqlType) { + // Implement this method to map SQL types to RDF types + // For example: + switch (sqlType) { + case Types.INTEGER: + return XSDDatatype.XSDinteger.getURI(); + case Types.VARCHAR: + return XSDDatatype.XSDstring.getURI(); + // Add more cases as needed + default: + return null; + } + } +} diff --git a/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLLanguageTranslator.java b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLLanguageTranslator.java index 48a69bf..bfb9b5a 100644 --- a/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLLanguageTranslator.java +++ b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLLanguageTranslator.java @@ -6,6 +6,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.SQLException; + public abstract class SPARQLLanguageTranslator { diff --git a/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLtoSQLTranslator.java b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLtoSQLTranslator.java index b8ce7bc..a0a9a2f 100644 --- a/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLtoSQLTranslator.java +++ b/quads-query/src/main/java/fr/cnrs/liris/jpugetgil/converg/SPARQLtoSQLTranslator.java @@ -67,68 +67,20 @@ public ResultSet translateAndExecSelect(Query query) { log.info("[Measure] (Query translation duration): {} ns for query: {};", end - start, query); log.info("Query result: {};", qu.getSql()); - Long startExec = System.nanoTime(); - try (java.sql.ResultSet rs = jdbcConnection.executeSQL(qu.getSql())) { + try { + Long startExec = System.nanoTime(); + java.sql.ResultSet rs = jdbcConnection.executeSQL(qu.getSql()); Long endExec = System.nanoTime(); log.info("[Measure] (Query execution duration): {} ns for query: {};", endExec - startExec, query); - // Change the List implementation to the Iterator one (heap space) - Set vars = new HashSet<>(); - List bindings = new ArrayList<>(); - - while (Objects.requireNonNull(rs).next()) { - ResultSetMetaData rsmd = rs.getMetaData(); - List allVariables = new ArrayList<>(); - List variables = new ArrayList<>(); - int nbColumns = rsmd.getColumnCount(); - for (int i = 1; i <= nbColumns; i++) { - String columnName = rsmd.getColumnName(i); - allVariables.add(columnName); - if (columnName.startsWith("name$")) { - variables.add(columnName.substring(5)); - } else if (!columnName.startsWith("type$")) { - variables.add(columnName); - } - } - - BindingBuilder bindingBuilder = Binding.builder(); - for (String v : variables) { - Var variable = Var.alloc(v); - Node variableValue; - - if (hasColumn(rs, "name$" + v) && rs.getString("name$" + v) != null) { - String value = rs.getString("name$" + v); - String valueType; - if (allVariables.contains("type$" + v)) { - valueType = rs.getString("type$" + v); - } else { - valueType = getAssociatedRDFType(rsmd.getColumnType(rs.findColumn("name$" + v))); - } - variableValue = valueType == null ? - NodeFactory.createURI(value) : NodeFactory.createLiteral(value, NodeFactory.getType(valueType)); - } else if (hasColumn(rs, v) && rs.getString(v) != null) { - String value = rs.getString(v); - String valueType = getAssociatedRDFType(rsmd.getColumnType(rs.findColumn(v))); - variableValue = NodeFactory.createLiteral(value, NodeFactory.getType(valueType)); - } else { - variableValue = null; - } - - vars.add(variable); - - if (variableValue != null) { - bindingBuilder.add(variable, variableValue); - } - } - - bindings.add(bindingBuilder.build()); - } + BindingIterator bindingIterator = new BindingIterator(rs); - return ResultSetStream.create(new ArrayList<>(vars), bindings.iterator()); + Set vars = bindingIterator + .getVars(); + return ResultSetStream.create(new ArrayList<>(vars), bindingIterator); } catch (SQLException e) { - log.error(e.getMessage()); - throw new ARQException(e); + throw new RuntimeException(e); } } @@ -260,27 +212,4 @@ private SQLContext addURIsToContext(OpBGP opBGP, SQLContext context) { return context; } - - private boolean hasColumn(java.sql.ResultSet rs, String columnName) throws SQLException { - try { - rs.findColumn(columnName); - return true; - } catch (SQLException e) { - return false; - } - } - - private String getAssociatedRDFType(int sqlType) { - // Implement this method to map SQL types to RDF types - // For example: - switch (sqlType) { - case Types.INTEGER: - return XSDDatatype.XSDinteger.getURI(); - case Types.VARCHAR: - return XSDDatatype.XSDstring.getURI(); - // Add more cases as needed - default: - return null; - } - } }