package org.aksw.sparqlify.core.sparql;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.aksw.jena_sparql_api.core.QueryExecutionAdapter;
import org.aksw.sparqlify.core.domain.input.SparqlSqlStringRewrite;
import org.aksw.sparqlify.core.interfaces.SparqlSqlStringRewriter;
import org.apache.jena.query.Query;
import org.apache.jena.query.ResultSet;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.iterator.QueryIterNullIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Multimap;
/**
* A query execution that can only do execSelect
* on a SparqlSqlRewriter and a Connection
*
* @author raven
*
*/
public class QueryExecutionSelect
extends QueryExecutionAdapter //Timeout//Decorator // TODO Replace with QueryExecutionAdapter
{
private static final Logger logger = LoggerFactory.getLogger(QueryExecutionSelect.class);
private SparqlSqlStringRewriter rewriter;
private final Connection conn;
private boolean closeConnWhenDone;
private Query query;
private Statement stmt;
private ResultSet rs;
public QueryExecutionSelect(SparqlSqlStringRewriter rewriter, Connection conn, Query query, boolean closeConnWhenDone) {
this.rewriter = rewriter;
this.conn = conn;
this.query = query;
this.closeConnWhenDone = closeConnWhenDone;
}
public ResultSet execSelect() {
try {
return _execSelect();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void write(PrintStream out, Map<?, ?> map)
{
for(Entry<?, ?> entry : map.entrySet()) {
out.println(entry.getKey() + ": " + entry.getValue());
}
}
public static String spaces(int n) {
String result = "";
for(int i = 0; i < n; ++i) {
result += " ";
}
return result;
}
public static <K, V >void write(PrintStream out, Multimap<K, V> map)
{
for(Entry<K, Collection<V>> entry : map.asMap().entrySet()) {
boolean keyPrint = false;
String key = entry.getKey() == null ? "(null)" : entry.getKey().toString();
String sp = spaces(key.length());
for(V value : entry.getValue()) {
if(!keyPrint) {
out.println(key + ": " + value);
keyPrint = true;
} else {
out.println(sp + " " + value);
}
}
if(!keyPrint) {
out.println(key + ": (empty)");
}
}
}
// For streaming large result sets with postgres, it seems to only option is to set
// the fetch size
public static Statement createStatement(Connection conn)
throws SQLException
{
Statement stmt = conn.createStatement();
stmt.setFetchSize(50000);
return stmt;
}
private ResultSet createEmptyResultSet() {
List<String> vars = new ArrayList<String>();
for(Var v : query.getProjectVars()) {
vars.add(v.getName());
}
return org.apache.jena.query.ResultSetFactory.create(new QueryIterNullIterator(null), vars);
}
public ResultSet _execSelect() throws SQLException {
/*
if (!query.isSelectType()) {
throw new RuntimeException("SELECT query expected. Got: ["
+ query.toString() + "]");
}
*/
SparqlSqlStringRewrite rewrite = rewriter.rewrite(query);
/*
if(logger.isInfoEnabled()) {
logger.info("Final sparql var mapping:");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
write(ps, sqlNode.getSparqlVarToExprs());
logger.info(baos.toString());
}
*/
/*
boolean enableCostChecking = false;
if(enableCostChecking) {
double cost = RdfViewDatabase.getCostPostgres(conn, sqlQuery);
if (cost > 4000) {
System.out.println("TODO abort due to high query cost: " + cost);
//System.out.println("Aborted due to high query cost: " + cost);
//return null;
}
logger.debug("Query cost ok (" + cost + ")");
} else {
logger.info("Cost estimates disabled.");
}
synchronized(this) {
// Statements may be cancelled asynchronously
*
} */
stmt = createStatement(conn);
logger.debug("My connection: " + conn + " Query is " + query);
//timeoutHelper.startExecutionTimer();
String queryString = rewrite.isEmptyResult() ? null : rewrite.getSqlQueryString();
rs = ResultSetFactory.create(
conn,
stmt, queryString,
rewrite.getVarDefinition().getMap(), rewrite.getProjectionOrder());
//final QueryExecutionSelect self = this;
// ResultSetClosable result = new ResultSetClosable(rs, new IClosable() {
//
// @Override
// public void close() {
// self.close();
// }
// });
return rs;
}
@Override
public void abort() {
synchronized(this) {
if(stmt != null) {
try {
stmt.cancel();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
close();
}
@Override
public void close() {
synchronized(this) {
if(closeConnWhenDone) {
try {
conn.close();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
if(stmt != null) {
try {
stmt.close();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
}
}