/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.common/src/com/ibm/adtech/boca/rdb/graph/Attic/BocaSolutionGenerator.java,v $
* Created by: Lee Feigenbaum (<a href="mailto:feigenbl@us.ibm.com">feigenbl@us.ibm.com</a>)
* Created on: 10/27/06
* Revision: $Id: RdbSolutionGenerator.java 229 2007-08-07 15:22:00Z mroy $
*
* Contributors: IBM Corporation - initial API and implementation
* Cambridge Semantics Incorporated - Fork to Anzo
*******************************************************************************/
package org.openanzo.jdbc.container.query;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.glitter.exception.GlitterException;
import org.openanzo.glitter.exception.GlitterRuntimeException;
import org.openanzo.glitter.exception.UnknownGraphException;
import org.openanzo.glitter.query.QueryController;
import org.openanzo.glitter.query.SolutionGenerator;
import org.openanzo.glitter.query.SolutionList;
import org.openanzo.glitter.query.SolutionSet;
import org.openanzo.glitter.syntax.abstrakt.Expression;
import org.openanzo.glitter.syntax.abstrakt.Graph;
import org.openanzo.glitter.syntax.abstrakt.GraphPattern;
import org.openanzo.glitter.syntax.abstrakt.TreeNode;
import org.openanzo.glitter.syntax.abstrakt.TriplePatternNode;
import org.openanzo.glitter.syntax.abstrakt.Union;
import org.openanzo.glitter.util.Glitter;
import org.openanzo.jdbc.container.CoreDBConfiguration;
import org.openanzo.jdbc.container.RDBQuadStore;
import org.openanzo.jdbc.container.sql.BaseSQL;
import org.openanzo.jdbc.container.sql.GlitterSQL;
import org.openanzo.jdbc.layout.CompositeNodeLayout;
import org.openanzo.jdbc.query.NoSolutionsException;
import org.openanzo.jdbc.query.NodeConverter;
import org.openanzo.jdbc.query.SQLQueryConstants;
import org.openanzo.jdbc.utils.PreparedStatementProvider;
import org.openanzo.jdbc.utils.RdbException;
import org.openanzo.ontologies.openanzo.NamedGraph;
import org.openanzo.rdf.TriplePatternComponent;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Variable;
import org.openanzo.rdf.Constants.GRAPHS;
import org.openanzo.rdf.vocabulary.RDF;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RdbSolutionGenerator implements the core of the Anzo backend; it translates SPARQL queries into SQL queries against the node centric container schema.
*/
public class RdbSolutionGenerator extends AnzoSolutionGeneratorBase implements SolutionGenerator {
private static final Logger log = LoggerFactory.getLogger(RdbSolutionGenerator.class);
protected RDBQuadStore rdbQuadStore = null;
protected boolean myLock = false;
/**
* Create a new RdbSolutionGenerator for data contained in the provided container
*
* @param container
* connection to database that contains data
*/
public RdbSolutionGenerator(RDBQuadStore container) {
this.rdbQuadStore = container;
this.noDefaultGraphs = false;
this.noNamedGraphs = false;
}
public String getQueryId() {
return null;
}
@Override
protected CompositeNodeLayout getNodeLayout() {
return this.rdbQuadStore.getNodeLayout();
}
@Override
protected String getDefaultGraphsTempTable() {
return SQLQueryConstants.defaultGraphsTempTable;
}
@Override
protected String getNamedGraphsTempTable() {
return SQLQueryConstants.namedGraphsTempTable;
}
@Override
protected String getTemporaryTempTable() {
return SQLQueryConstants.tempGraphsTempTable;
}
@Override
protected Logger getLogger() {
return log;
}
@Override
protected CoreDBConfiguration getConfiguration() {
return this.rdbQuadStore.getConfiguration();
}
@Override
protected String getSessionPrefix() {
return this.rdbQuadStore.getConfiguration().getSessionPrefix();
}
@Override
protected void clearTempTable() throws RdbException, SQLException {
BaseSQL.truncateTableWithSessionMayCommit(this.rdbQuadStore.getPreparedStatementProvider(), rdbQuadStore.getConnection(), this.rdbQuadStore.getConfiguration().getSessionPrefix(), "TEMP_COLUMNS");
}
@Override
protected void setGraphsType(boolean defaults, GraphSetType type) {
}
@Override
public void initialize() throws GlitterException {
this.nodeConverter = new NodeConverter(rdbQuadStore.getNodeLayout());
// start a transaction (if necessary), create a temp table with OK named graph IDs
Glitter.getLog().debug("Creating temporary graph tables and indexes");
/* try {
this.rdbQuadStore.begin();
} catch (AnzoException be) {
throw new GlitterException(be);
}*/
populateDatasetTables(this.rdbQuadStore.getNodeLayout(), this.rdbQuadStore.getConnection(), SQLQueryConstants.defaultGraphsTempTable, SQLQueryConstants.namedGraphsTempTable, log);
}
public void cleanup() throws GlitterException {
if (!myLock) {
try {
BaseSQL.truncateTableWithSessionMayCommit(this.rdbQuadStore.getPreparedStatementProvider(), rdbQuadStore.getConnection(), rdbQuadStore.getConfiguration().getSessionPrefix(), SQLQueryConstants.defaultGraphsTempTable);
BaseSQL.truncateTableWithSessionMayCommit(this.rdbQuadStore.getPreparedStatementProvider(), rdbQuadStore.getConnection(), rdbQuadStore.getConfiguration().getSessionPrefix(), SQLQueryConstants.namedGraphsTempTable);
} catch (RdbException sqle) {
log.error(LogUtils.RDB_MARKER, "Error clearing temporary tables", sqle);
}
}
/* if (myLock) {
try {
this.rdbQuadStore.commit();
} catch (AnzoException be) {
throw new GlitterException(be);
}
}*/
}
@SuppressWarnings("unchecked")
final private Class<GraphPattern>[] notHandled = new Class[] { Graph.class, Union.class };
public SolutionSet generateSolutions(TreeNode node, org.openanzo.rdf.URI namedGraph, Variable namedGraphVariable, SolutionSet requiredBindings, QueryController controller) {
// we don't do anything which is a UNION
// or anything that is an ancestor of a node type that we don't handle (UNION, GRAPH)
if (node instanceof Union || containsNodeType(node, notHandled))
return null;
// if this is a graph node, update our graph context and replace the node with the
// GRAPH's graph pattern (we recurse this for the strange nested GRAPH cases)
while (node instanceof Graph) {
// If this is a graph, we process the graph variable or URI and
// continue with the child GraphPattern as our operative node.
TriplePatternComponent context = ((Graph) node).getGraphContext();
if (context instanceof Variable) {
namedGraphVariable = (Variable) context;
} else if (context instanceof URI) {
namedGraph = (URI) context;
} else {
throw new GlitterRuntimeException(ExceptionConstants.GLITTER.GRAPH_NOT_VAR, context.toString());
}
node = ((Graph) node).getGraphPattern();
}
// At this point, we know that node is not a GRAPH node and not a UNION node and contains
// neither.
try {
// Short-circuit if:
// (1) we're querying the default graph which is empty (zero or unit solution)
// (2) we're querying the named graphs which are empty (zero or unit solution)
// (3) we're querying a specific named graph which is not in our dataset (zero or unit solution)
boolean queryingDefaultGraph = namedGraphVariable == null && namedGraph == null;
if ((queryingDefaultGraph && noDefaultGraphs) || (!queryingDefaultGraph && noNamedGraphs)) {
if (isNonVacuous(node))
throw new NoSolutionsException();
else
return unitSolution();
}
if (!rdbQuadStore.getConfiguration().getSupportsTempOnFind() && !(node instanceof TriplePatternNode)) {
return null;
}
AnzoBGPQuery query = getAnzoBGPQuery(node, namedGraph, namedGraphVariable, requiredBindings);
SolutionSet solutions = getBindingsForQuery(query, node, null, controller);
return solutions;
} catch (NoSolutionsException e) {
return new SolutionList();
} catch (SQLException e) {
log.error(LogUtils.RDB_MARKER, "SQL Error generating solutions", e);
throw new GlitterRuntimeException(ExceptionConstants.GLITTER.SQL_EXCEPTION, e);
} catch (AnzoException e) {
log.error(LogUtils.RDB_MARKER, "Anzo exception generating solutions", e);
throw new GlitterRuntimeException(e);
}
}
@Override
protected AnzoBGPQuery createAnzoBGPQuery(TreeNode node) {
return new RdbBGPQuery(this.rdbQuadStore, Glitter.getMostSpecificController(node, information), this.validGraphsInDefaultGraph);
}
@Override
protected Connection getConnection() {
return this.rdbQuadStore.getConnection();
}
/**
* Get the RDBQuadStore for this solution generator
*
* @return the RDBQuadStore for this solution generator
*/
public RDBQuadStore getContainer() {
return rdbQuadStore;
}
@Override
protected PreparedStatementProvider getPreparedStatementProvider() {
return this.rdbQuadStore.getPreparedStatementProvider();
}
public boolean sortedSolutions() {
return false;
}
public boolean canHandleSimultaneousRequests() {
return false;
}
public boolean canBindGraphVariables() {
return true;
}
public boolean usesRequiredBindings() {
return false;
}
public boolean willHandleFilters(Set<Expression> filters) {
return false;
}
@Override
protected int insertGraphByIdIfValid(Long graphId, String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
return GlitterSQL.insertGraphIfValid(getPreparedStatementProvider(), getConnection(), graphId, getSessionPrefix(), insertTable, this.rdbQuadStore.getContainerName());
}
@Override
protected boolean insertGraphsIfValid(Set<URI> graphsSet, String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
Map<URI, Long> graphIds = resolveSet(getNodeLayout(), getConnection(), graphsSet, false);
for (Map.Entry<URI, Long> graphId : graphIds.entrySet()) {
int count = insertGraphByIdIfValid(graphId.getValue(), insertTable, defaults);
if (count == 0)
throw new UnknownGraphException(graphId.getKey());
}
return true;
}
@Override
protected int insertAllGraphsIfValid(String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
Long ngDatasetId = getNodeLayout().fetchId(GRAPHS.GRAPHS_DATASET, getConnection());
Long ngDatasetMetadataId = getNodeLayout().fetchId(GRAPHS.GRAPHS_DATASET_META, getConnection());
Long mgDatasetId = getNodeLayout().fetchId(GRAPHS.METADATA_GRAPHS_DATASET, getConnection());
Long mgDatasetMetadataId = getNodeLayout().fetchId(GRAPHS.METADATA_GRAPHS_DATASET_META, getConnection());
return GlitterSQL.insertAllValidGraphs(getPreparedStatementProvider(), getConnection(), ngDatasetId, ngDatasetMetadataId, mgDatasetId, mgDatasetMetadataId, getSessionPrefix(), insertTable, this.rdbQuadStore.getContainerName());
}
@Override
protected int insertAllNamedGraphsIfValid(String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
Long rdfTypeId = getNodeLayout().fetchId(RDF.TYPE, getConnection());
Long namedGraphTypeId = getNodeLayout().fetchId(NamedGraph.TYPE, getConnection());
Long ngDatasetId = getNodeLayout().fetchId(GRAPHS.GRAPHS_DATASET, getConnection());
Long mgDatasetId = getNodeLayout().fetchId(GRAPHS.METADATA_GRAPHS_DATASET, getConnection());
return GlitterSQL.insertAllValidNamedGraphs(getPreparedStatementProvider(), getConnection(), rdfTypeId, namedGraphTypeId, ngDatasetId, mgDatasetId, getSessionPrefix(), insertTable, this.rdbQuadStore.getContainerName());
}
@Override
protected int insertAllMetadataGraphsIfValid(String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
Long hasMetadataGraphId = getNodeLayout().fetchId(NamedGraph.hasMetadataGraphProperty, getConnection());
Long ngDatasetMetadataId = getNodeLayout().fetchId(GRAPHS.GRAPHS_DATASET_META, getConnection());
Long mgDatasetMetadataId = getNodeLayout().fetchId(GRAPHS.METADATA_GRAPHS_DATASET_META, getConnection());
return GlitterSQL.insertAllValidMetadataGraphs(getPreparedStatementProvider(), getConnection(), hasMetadataGraphId, ngDatasetMetadataId, mgDatasetMetadataId, getSessionPrefix(), insertTable, this.rdbQuadStore.getContainerName());
}
@Override
protected int insertDatasetGraphsIfValid(Long datasetId, Long datasetGraphPropertyId, String insertTable, boolean defaults) throws SQLException, GlitterException, AnzoException {
return GlitterSQL.insertValidDatasetGraphs(getPreparedStatementProvider(), getConnection(), datasetId, datasetId, datasetGraphPropertyId, getSessionPrefix(), insertTable, this.rdbQuadStore.getContainerName());
}
}