/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.jena.jdbc.results;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Iterator;
import org.apache.jena.atlas.iterator.PeekIterator;
import org.apache.jena.atlas.lib.Closeable;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.jdbc.results.metadata.TripleResultsMetadata;
import org.apache.jena.jdbc.statements.JenaStatement;
import org.apache.jena.query.QueryCancelledException ;
import org.apache.jena.query.QueryExecution ;
/**
* Represents results of a CONSTRUCT/DESCRIBE query where the results are
* streamed
*
*/
public class TripleIteratorResults extends StreamedResults<Triple> {
private TripleResultsMetadata metadata;
private PeekIterator<Triple> triples;
private String subjColumn, predColumn, objColumn;
private int numColumns;
/**
* Creates a new result set which is backed by a triple iterator
*
* @param statement
* Statement
* @param qe
* Query Execution
* @param ts
* Triple Iterator
* @param commit
* Whether a commit is necessary when the result set is closed
* @throws SQLException
* Thrown if there is a problem creating the results
*/
public TripleIteratorResults(JenaStatement statement, QueryExecution qe, Iterator<Triple> ts, boolean commit)
throws SQLException {
super(statement, qe, commit);
if (ts == null)
throw new SQLException("Triple Iterator cannot be null");
this.triples = PeekIterator.create(ts);
this.metadata = statement.getJenaConnection().applyPostProcessors(new TripleResultsMetadata(this, this.triples));
this.numColumns = this.metadata.getColumnCount();
this.subjColumn = this.metadata.getSubjectColumnLabel();
this.predColumn = this.metadata.getPredicateColumnLabel();
this.objColumn = this.metadata.getObjectColumnLabel();
}
@Override
public int findColumn(String columnLabel) throws SQLException {
if (this.subjColumn != null && this.subjColumn.equals(columnLabel)) {
return TripleResultsMetadata.COLUMN_INDEX_SUBJECT;
} else if (this.predColumn != null && this.predColumn.equals(columnLabel)) {
return this.subjColumn == null ? TripleResultsMetadata.COLUMN_INDEX_SUBJECT
: TripleResultsMetadata.COLUMN_INDEX_PREDICATE;
} else if (this.objColumn != null && this.objColumn.equals(columnLabel)) {
return this.subjColumn == null && this.predColumn == null ? TripleResultsMetadata.COLUMN_INDEX_SUBJECT
: (this.subjColumn == null || this.predColumn == null ? TripleResultsMetadata.COLUMN_INDEX_PREDICATE
: TripleResultsMetadata.COLUMN_INDEX_OBJECT);
} else {
throw new SQLException("Column " + columnLabel + " does not exist in these results");
}
}
@Override
protected boolean hasNext() throws SQLException {
// No null check here because superclass will not call us after we are
// closed and set to null
try {
return this.triples.hasNext();
} catch (QueryCancelledException e) {
throw new SQLException("Query was cancelled, it is likely that your query exceeded the specified execution timeout",
e);
} catch (Throwable e) {
// Wrap as SQL exception
throw new SQLException("Unexpected error while moving through results", e);
}
}
@Override
protected Triple moveNext() throws SQLException {
try {
return this.triples.next();
} catch (QueryCancelledException e) {
throw new SQLException("Query was cancelled, it is likely that your query exceeded the specified execution timeout",
e);
} catch (Throwable e) {
// Wrap as SQL exception
throw new SQLException("Unexpected error while moving through results", e);
}
}
@Override
protected void closeStreamInternal() {
if (this.triples != null) {
if (this.triples instanceof Closeable) {
((Closeable) this.triples).close();
}
this.triples = null;
}
}
@Override
public ResultSetMetaData getMetaData() {
return metadata;
}
@Override
protected String findColumnLabel(int columnIndex) throws SQLException {
if (this.isClosed())
throw new SQLException("Result Set is closed");
if (columnIndex >= 1 && columnIndex <= this.numColumns) {
switch (columnIndex) {
case TripleResultsMetadata.COLUMN_INDEX_SUBJECT:
return this.subjColumn != null ? this.subjColumn : (this.predColumn != null ? this.predColumn : this.objColumn);
case TripleResultsMetadata.COLUMN_INDEX_PREDICATE:
return this.subjColumn != null && this.predColumn != null ? this.predColumn : this.objColumn;
case TripleResultsMetadata.COLUMN_INDEX_OBJECT:
return this.objColumn;
default:
throw new SQLException("Column Index is out of bounds");
}
} else {
throw new SQLException("Column Index is out of bounds");
}
}
@Override
protected Node getNode(String columnLabel) throws SQLException {
if (this.isClosed())
throw new SQLException("Result Set is closed");
if (this.getCurrentRow() == null)
throw new SQLException("Not currently at a row");
Triple t = this.getCurrentRow();
if (this.subjColumn != null && this.subjColumn.equals(columnLabel)) {
return t.getSubject();
} else if (this.predColumn != null && this.predColumn.equals(columnLabel)) {
return t.getPredicate();
} else if (this.objColumn != null && this.objColumn.equals(columnLabel)) {
return t.getObject();
} else {
throw new SQLException("Unknown column label");
}
}
}