/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.rdf.sail; import org.apache.log4j.Logger; import org.openrdf.model.Resource; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.query.MalformedQueryException; import org.openrdf.query.QueryLanguage; import org.openrdf.query.Update; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.sail.SailQuery; import org.openrdf.repository.sail.SailRepositoryConnection; import org.openrdf.sail.SailConnection; import org.openrdf.sail.SailException; import com.bigdata.journal.ITx; import com.bigdata.journal.TimestampUtility; import com.bigdata.rdf.changesets.IChangeLog; import com.bigdata.rdf.changesets.IChangeRecord; import com.bigdata.rdf.model.BigdataValueFactory; import com.bigdata.rdf.sail.BigdataSail.BigdataSailConnection; import com.bigdata.rdf.sail.sparql.Bigdata2ASTSPARQLParser; import com.bigdata.rdf.sparql.ast.ASTContainer; import com.bigdata.rdf.sparql.ast.QueryType; import com.bigdata.rdf.store.AbstractTripleStore; /** * Class with support for a variety of bigdata specific extensions, * <p> * {@inheritDoc} * * @author mrpersonick */ public class BigdataSailRepositoryConnection extends SailRepositoryConnection { private static transient final Logger log = Logger .getLogger(BigdataSailRepositoryConnection.class); @Override public String toString() { return getClass().getName() + "{timestamp=" + TimestampUtility.toString(getTripleStore().getTimestamp()) + "}"; } public BigdataSailRepositoryConnection(BigdataSailRepository repository, SailConnection sailConnection) { super(repository, sailConnection); } @Override public BigdataSailRepository getRepository() { return (BigdataSailRepository) super.getRepository(); } @Override public BigdataSailConnection getSailConnection() { return (BigdataSailConnection) super.getSailConnection(); } @Override public BigdataValueFactory getValueFactory() { return (BigdataValueFactory) super.getValueFactory(); } /** * {@inheritDoc} * <p> * This code path is optimized for cases where isolatable indices are not in * use and where inferences can not appear. * * @see <a href="http://trac.bigdata.com/ticket/1178" > Optimize * hasStatement() </a> * * TODO This should be using * {@link BigdataSailConnection#hasStatement(Resource, URI, Value, boolean, Resource...)} * for improved performance. See #1178. */ @Override public boolean hasStatement(final Resource s, final URI p, final Value o, final boolean includeInferred, final Resource... contexts) throws RepositoryException { return super.hasStatement(s,p,o, includeInferred, contexts); // try { // // return getSailConnection().hasStatement(s, p, o, includeInferred, contexts); // // } catch (SailException e) { // // throw new RepositoryException(e); // // } } @Override public BigdataSailGraphQuery prepareGraphQuery(final QueryLanguage ql, final String qs, final String baseURI) throws MalformedQueryException { return (BigdataSailGraphQuery) prepareQuery(ql, qs, baseURI); } @Override public BigdataSailTupleQuery prepareTupleQuery(final QueryLanguage ql, final String qs, final String baseURI) throws MalformedQueryException { return (BigdataSailTupleQuery) prepareQuery(ql, qs, baseURI); } @Override public BigdataSailBooleanQuery prepareBooleanQuery(final QueryLanguage ql, final String qs, final String baseURI) throws MalformedQueryException { return (BigdataSailBooleanQuery) prepareQuery(ql, qs, baseURI); } @Override public SailQuery prepareQuery(final QueryLanguage ql, final String qs, final String baseURI) throws MalformedQueryException { if (ql == QueryLanguage.SPARQL) { return (SailQuery) prepareNativeSPARQLQuery(ql, qs, baseURI); } throw new MalformedQueryException("Unsupported language: " + ql); } /** * {@inheritDoc} * * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/448"> * SPARQL 1.1 Update </a> */ @Override public Update prepareUpdate(final QueryLanguage ql, final String update, final String baseURI) throws RepositoryException, MalformedQueryException { if (ql == QueryLanguage.SPARQL) { return (Update) prepareNativeSPARQLUpdate(ql, update, baseURI); } throw new MalformedQueryException("Unsupported language: " + ql); } /** * Parse a SPARQL query * * @param ql * The {@link QueryLanguage}. * @param queryStr * The query. * @param baseURI * The base URI. * * @return An object wrapping the bigdata AST model for that query. * * @throws MalformedQueryException * @throws UnsupportedOperationException * if the query language is not SPARQL. */ public BigdataSailQuery prepareNativeSPARQLQuery(final QueryLanguage ql, final String queryStr, final String baseURI) throws MalformedQueryException { if (ql != QueryLanguage.SPARQL) throw new UnsupportedOperationException(ql.toString()); if (log.isDebugEnabled()) { log.debug(queryStr); } // Flush buffers since we are about to resolve Values to IVs. getSailConnection() .flushStatementBuffers(true/* assertions */, true/* retractions */); final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final QueryType queryType = astContainer.getOriginalAST() .getQueryType(); switch (queryType) { case SELECT: return new BigdataSailTupleQuery(astContainer, this); case DESCRIBE: case CONSTRUCT: return new BigdataSailGraphQuery(astContainer, this); case ASK: { return new BigdataSailBooleanQuery(astContainer, this); } default: throw new RuntimeException("Unknown query type: " + queryType); } } /** * Parse a SPARQL UPDATE request. * * @param ql * The {@link QueryLanguage}. * @param updateStr * The update request. * @param baseURI * The base URI. * * @return An object wrapping the bigdata AST model for that request. * * @throws MalformedQueryException * @throws UnsupportedOperationException * if the {@link QueryLanguage} is not SPARQL. */ public BigdataSailUpdate prepareNativeSPARQLUpdate(final QueryLanguage ql, final String updateStr, final String baseURI) throws MalformedQueryException { if (getTripleStore().isReadOnly()) throw new UnsupportedOperationException("Read only"); if (ql != QueryLanguage.SPARQL) throw new UnsupportedOperationException(ql.toString()); if (log.isDebugEnabled()) { log.debug(updateStr); } // Flush buffers since we are about to resolve Values to IVs. getSailConnection() .flushStatementBuffers(true/* assertions */, true/* retractions */); // Parse the UPDATE request. final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseUpdate2(updateStr, baseURI); return new BigdataSailUpdate(astContainer, this); } /** * Return <code>true</code> if the connection does not permit mutation. */ public final boolean isReadOnly() { return getSailConnection().isReadOnly(); } /** * Return <code>true</code> if this is the {@link ITx#UNISOLATED} * connection. */ public final boolean isUnisolated() { return getSailConnection().isUnisolated(); } /** * Commit, returning the timestamp associated with the new commit point. * <p> * Note: auto-commit is an EXTREMELY bad idea. Performance will be terrible. * The database will swell to an outrageous size. TURN OFF AUTO COMMIT. * * @return The timestamp associated with the new commit point. This will be * <code>0L</code> if the write set was empty such that nothing was * committed. * * @see BigdataSail.Options#ALLOW_AUTO_COMMIT */ public long commit2() throws RepositoryException { // auto-commit is heinously inefficient if (isAutoCommit() && !((BigdataSailConnection) getSailConnection()).getAllowAutoCommit()) { throw new RepositoryException("please set autoCommit to false"); } // Note: Just invokes sailConnection.commit() // super.commit(); try { // sailConnection.commit(); return getSailConnection().commit2(); } catch (SailException e) { throw new RepositoryException(e); } } /** * {@inheritDoc} * <p> * Note: auto-commit is an EXTREMELY bad idea. Performance will be terrible. * The database will swell to an outrageous size. TURN OFF AUTO COMMIT. * * @see BigdataSail.Options#ALLOW_AUTO_COMMIT */ @Override public void commit() throws RepositoryException { commit2(); } /** * Flush the statement buffers. The {@link BigdataSailConnection} heavily * buffers assertions and retractions. Either a {@link #flush()} or a * {@link #commit()} is required before executing any operations directly * against the backing {@link AbstractTripleStore} so that the buffered * assertions or retractions will be written onto the KB and become visible * to other methods. This is not a transaction issue -- just a buffer issue. * The public methods on the {@link BigdataSailConnection} all flush the * buffers before performing any queries against the underlying * {@link AbstractTripleStore}. * * @throws RepositoryException */ public void flush() throws RepositoryException { try { ((BigdataSailConnection) getSailConnection()).flush(); } catch (Exception ex) { throw new RepositoryException(ex); } } /** * Return the backing {@link AbstractTripleStore} object. Caution MUST be * used when accessing this object as the access goes around the SAIL API. */ public AbstractTripleStore getTripleStore() { return ((BigdataSailConnection) getSailConnection()).getTripleStore(); } /** * Computes the closure of the triple store for RDF(S)+ entailments. * <p> * This computes the closure of the database. This can be used if you do * NOT enable truth maintenance and choose instead to load up all of * your data first and then compute the closure of the database. Note * that some rules may be computed by eager closure while others are * computed at query time. * <p> * Note: If there are already entailments in the database AND you have * retracted statements since the last time the closure was computed * then you MUST delete all entailments from the database before * re-computing the closure. * <p> * Note: This method does NOT commit the database. See * {@link AbstractTripleStore#commit()} and {@link #getTripleStore()}. * * @see #removeAllEntailments() */ public void computeClosure() throws RepositoryException { try { ((BigdataSailConnection) getSailConnection()).computeClosure(); } catch(Exception ex) { throw new RepositoryException(ex); } } /** * Removes all "inferred" statements from the database (does NOT commit the * database). * * @throws RepositoryException */ public void removeAllEntailments() throws SailException, RepositoryException { try { ((BigdataSailConnection) getSailConnection()) .removeAllEntailments(); } catch (Exception ex) { throw new RepositoryException(ex); } } /** * Set the change log on the SAIL connection. See {@link IChangeLog} and * {@link IChangeRecord}. * * @param log * the change log */ public void addChangeLog(final IChangeLog log) { getSailConnection().addChangeLog(log); } /** * Remove a change log from the SAIL connection. See {@link IChangeLog} and * {@link IChangeRecord}. * * @param log * the change log */ public void removeChangeLog(final IChangeLog log) { getSailConnection().removeChangeLog(log); } }