/* * 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.sql.SQLException; import java.util.List; import com.obidea.semantika.database.sql.base.SqlSelectItem; import com.obidea.semantika.database.sql.deparser.SqlDeparser; import com.obidea.semantika.exception.SemantikaException; import com.obidea.semantika.expression.base.IQueryExt; import com.obidea.semantika.expression.base.QuerySet; import com.obidea.semantika.mapping.base.IMappingTerm; import com.obidea.semantika.mapping.base.TermType; import com.obidea.semantika.mapping.base.sql.SqlQuery; import com.obidea.semantika.queryanswer.AbstractQueryEngine; import com.obidea.semantika.queryanswer.parser.SparqlFactory; import com.obidea.semantika.queryanswer.parser.SparqlParserException; import com.obidea.semantika.queryanswer.processor.QueryOptimizationException; import com.obidea.semantika.queryanswer.processor.QueryReformulationException; import com.obidea.semantika.queryanswer.processor.QueryUnfoldingException; import com.obidea.semantika.queryanswer.result.IQueryResult; public class QueryTranslator extends QueryResultLoader implements IQueryTranslator { private String mQueryString; private String mSqlString; private QueryMetadata mQueryMetadata; public QueryTranslator(String queryString, AbstractQueryEngine queryEngine) throws QueryTranslationException { super(queryEngine); try { /* * Parse the SPARQL string into a set of query objects. */ QuerySet<IQueryExt> parsedQuery = SparqlFactory.create(queryString); /* * Process the input query set by expanding it using a query reformulator. */ QuerySet<IQueryExt> reformulatedQuery = applyQueryReformulation(parsedQuery); /* * Process the "expanded" query set by unfolding each query to a proper SQL query. */ QuerySet<SqlQuery> unfoldedQuery = applyQueryUnfolding(reformulatedQuery); if (!unfoldedQuery.isEmpty()) { /* * Optimize the "unfolded" SQL query to increase the query performance. */ unfoldedQuery = applyQueryOptimization(unfoldedQuery); /* * Translate the "unfolded" <code>QueryExt</code> objects into SQL string. */ renderSql(unfoldedQuery); /* * Construct the query meta-information from taking one query sample */ buildQueryMetadata(unfoldedQuery.get(0)); } else { throw new QueryTranslationException("No SQL was produced for input query:\n" + queryString); //$NON-NLS-1$ } } catch (SparqlParserException e) { throw new QueryTranslationException("Exception while parsing input query:\n" + queryString, e); //$NON-NLS-1$ } catch (QueryReformulationException e) { throw new QueryTranslationException("Exception while performing query reformulation:\n" + queryString, e); //$NON-NLS-1$ } catch (QueryUnfoldingException e) { throw new QueryTranslationException("Exception while performing query unfolding:\n" + queryString, e); //$NON-NLS-1$ } catch (QueryOptimizationException e) { throw new QueryTranslationException("Exception while performing query optimization:\n" + queryString, e); //$NON-NLS-1$ } } private QuerySet<IQueryExt> applyQueryReformulation(QuerySet<IQueryExt> querySet) throws QueryReformulationException { return mQueryEngine.getQueryReformulator().reformulate(querySet); } private QuerySet<SqlQuery> applyQueryUnfolding(QuerySet<IQueryExt> querySet) throws QueryUnfoldingException { return mQueryEngine.getQueryUnfolder().unfold(querySet); } private QuerySet<SqlQuery> applyQueryOptimization(QuerySet<SqlQuery> querySet) throws QueryOptimizationException { return mQueryEngine.getQueryOptimizers().optimize(querySet); } private void renderSql(QuerySet<SqlQuery> inputQuery) { SqlDeparser deparser = new SqlDeparser(mQueryEngine.getTargetDatabase().getDialect()); mSqlString = deparser.deparse(inputQuery); } private void buildQueryMetadata(SqlQuery sqlQuery) { List<SqlSelectItem> selectItems = sqlQuery.getSelectItems(); int selectSize = selectItems.size(); String[] selectNames = new String[selectSize]; String[] selectTypes = new String[selectSize]; for (int i = 0; i < selectSize; i++) { final SqlSelectItem selectItem = selectItems.get(i); /* * Get the select name from the SQL projection labels. */ selectNames[i] = selectItem.getLabelName(); /* * Get the select type from the SQL expression. However, we need to * be able to determine if the expression has a semantic as a * literal-value or object-value. This can be obtained by casting the * object as a mapping term expression. */ IMappingTerm mt = (IMappingTerm) selectItem.getExpression(); switch (mt.getTermType()) { case TermType.LITERAL_TYPE: selectTypes[i] = mt.getDatatype(); break; case TermType.URI_TYPE: selectTypes[i] = null; break; } } mQueryMetadata = new QueryMetadata(selectNames, selectTypes); } @Override public QueryMetadata getQueryMetadata() { return mQueryMetadata; } @Override public String getQueryString() { return mQueryString; } @Override public String getSqlString() { return mSqlString; } public IQueryResult evaluate() throws QueryEvaluationException { return evaluate(new QueryModifiers(), new UserStatementSettings()); } public IQueryResult evaluate(QueryModifiers modifiers, UserStatementSettings userSettings) throws QueryEvaluationException { try { return super.evaluate(modifiers, userSettings); } catch (SQLException e) { throw new QueryEvaluationException(e); } catch (SemantikaException e) { throw new QueryEvaluationException(e); } } }