/* * Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com> * * Licensed 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 com.obidea.semantika.queryanswer.internal; import java.net.URI; import java.net.URISyntaxException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.obidea.semantika.exception.SemantikaException; import com.obidea.semantika.queryanswer.AbstractQueryEngine; import com.obidea.semantika.queryanswer.internal.QueryMetadata.Column; import com.obidea.semantika.queryanswer.paging.SqlPaging; import com.obidea.semantika.queryanswer.paging.SqlPagingStrategy; import com.obidea.semantika.queryanswer.result.IQueryResult; import com.obidea.semantika.queryanswer.result.IValue; import com.obidea.semantika.queryanswer.result.Literal; import com.obidea.semantika.queryanswer.result.QueryResult; import com.obidea.semantika.queryanswer.result.QueryResultBuilder; import com.obidea.semantika.queryanswer.result.Uri; import com.obidea.semantika.queryanswer.result.ValueArray; import com.obidea.semantika.util.TemplateStringHelper; public abstract class QueryResultLoader { protected AbstractQueryEngine mQueryEngine; public QueryResultLoader(final AbstractQueryEngine queryEngine) { mQueryEngine = queryEngine; } protected IQueryResult evaluate(QueryModifiers modifiers, UserStatementSettings userSettings) throws SQLException, SemantikaException { String sql = preprocessSql(getSqlString(), modifiers); final PreparedStatement ps = preparedStatement(sql, userSettings); final ResultSet rs = doQuery(ps); IQueryResult result = null; try { result = buildQueryResult(rs, getQueryMetadata()); } finally { mQueryEngine.getQueryEvaluator().closeQueryStatement(ps, rs); } return result; } protected ResultSet doQuery(PreparedStatement ps) throws SQLException, SemantikaException { ResultSet rs = null; try { rs = mQueryEngine.getQueryEvaluator().getResultSet(ps); } catch (SQLException e) { mQueryEngine.getQueryEvaluator().closeQueryStatement(ps, rs); throw e; } return rs; } /** * Returns the produced SQL query string. */ protected abstract String getSqlString(); /** * Returns the query metadata to rebuild the result header (i.e., column names). */ protected abstract QueryMetadata getQueryMetadata(); /* * Private utility methods */ private String preprocessSql(String sql, QueryModifiers modifiers) { if (modifiers.isSet()) { int limit = modifiers.getLimit(); int offset = modifiers.getOffset(); final List<String> ascOrder = modifiers.getAscendingOrder(); final List<String> descOrder = modifiers.getDescendingOrder(); SqlPaging paging = getPaging(); sql = paging.createPaging(sql, limit, offset, ascOrder, descOrder); } return sql; } private PreparedStatement preparedStatement(String sql, UserStatementSettings settings) throws SQLException, SemantikaException { PreparedStatement ps = null; try { ps = mQueryEngine.getQueryEvaluator().prepareQueryStatement(sql); /* * These settings come from user code in SelectQuery class and they will override the * global JDBC statement parameters in the configuration file, if any. */ if (settings.getQueryTimeout() != null) { ps.setQueryTimeout(settings.getQueryTimeout().intValue()); } if (settings.getFetchSize() != null) { ps.setFetchSize(settings.getFetchSize().intValue()); } if (settings.getMaxRows() != null) { ps.setMaxRows(settings.getMaxRows().intValue()); } } catch (SQLException e) { mQueryEngine.getQueryEvaluator().closeQueryStatement(ps, null); throw e; } catch (SemantikaException e) { mQueryEngine.getQueryEvaluator().closeQueryStatement(ps, null); throw e; } return ps; } private static QueryResult buildQueryResult(ResultSet rs, QueryMetadata metadata) throws SQLException { final List<String> selectLabels = new ArrayList<String>(); QueryResultBuilder builder = new QueryResultBuilder(); builder.start(metadata.getSelectNames()); while (rs.next()) { ValueArray valueArray = getValueArrayFromResultSet(rs, metadata, selectLabels); builder.handleResultFragment(valueArray); } return builder.getQueryResult(); } private static ValueArray getValueArrayFromResultSet(ResultSet rs, QueryMetadata metadata, List<String> selectLabels) throws SQLException { List<IValue> values = getSelectValues(rs, metadata, selectLabels); return new ValueArray(selectLabels, values); } private static List<IValue> getSelectValues(ResultSet rs, QueryMetadata metadata, List<String> selectLabels) throws SQLException { boolean needAdd = selectLabels.isEmpty(); List<IValue> values = new ArrayList<IValue>(); for (int i = 1; i <= metadata.size(); i++) { if (needAdd) { String label = getLabel(metadata, i); selectLabels.add(label); } IValue value = getValue(rs, metadata, i); values.add(value); } return values; } private static String getLabel(QueryMetadata metadata, int position) throws SQLException { return metadata.getColumn(position).getLabel(); } private static IValue getValue(ResultSet resultSet, QueryMetadata metadata, int position) throws SQLException { String value = resultSet.getString(position); /* * If the JDBC ResultSet gives null, then this method returns null as well. */ if (value == null) { return null; } Column c = metadata.getColumn(position); if (c.isLiteral()) { return new Literal(value, URI.create(c.getDatatype())); } else { if (!validUri(value)) { /* * We assume if the URI string is invalid it means the given value is a * URI template construction, i.e., <template> : <value1> <value2> etc. */ value = TemplateStringHelper.buildUri(value); } return new Uri(value); } } private static boolean validUri(String uriString) { try { new URI(uriString); } catch (URISyntaxException e) { return false; } return true; } private SqlPaging getPaging() { return SqlPagingStrategy.buildPaging(mQueryEngine.getTargetDatabase().getDatabaseProduct()); } }