You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2013/05/01 23:05:15 UTC
svn commit: r1478189 [1/2] - in /jena/Experimental/jena-jdbc:
jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/
jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/
jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/ jena-j...
Author: rvesse
Date: Wed May 1 21:05:13 2013
New Revision: 1478189
URL: http://svn.apache.org/r1478189
Log:
Lots of improvements and bug fixes
Adds ability to have TYPE_SCROLL_INSENSITIVE result sets
Improves handling of transactions to share transactions on single threads where appropriate
Improves PreparedStatement support
Starts adding unit tests for prepared statements and executeBatch()
Added:
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedResults.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedSelectResults.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/TripleListResults.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/connections/TestTdbDiskConnection.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/connections/TestTdbMemConnection.java
Removed:
jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/connections/TestJenaJdbcTdbDiskConnection.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/connections/TestJenaJdbcTdbMemConnection.java
Modified:
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/DatasetConnection.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/StreamedResults.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetPreparedStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaPreparedStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/connections/RemoteEndpointConnection.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointPreparedStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointStatement.java
jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/test/java/org/apache/jena/jdbc/remote/connections/TestRemoteEndpointConnectionWithGraphUris.java
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/DatasetConnection.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/DatasetConnection.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/DatasetConnection.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/DatasetConnection.java Wed May 1 21:05:13 2013
@@ -27,6 +27,7 @@ import org.apache.jena.jdbc.statements.J
import org.apache.jena.jdbc.statements.JenaStatement;
import com.hp.hpl.jena.query.Dataset;
+import com.hp.hpl.jena.query.ReadWrite;
/**
* Represents a connection to a {@link Dataset} instance
@@ -37,6 +38,9 @@ public abstract class DatasetConnection
protected Dataset ds;
private boolean readonly = false;
+ private ThreadLocal<ReadWrite> transactionType = new ThreadLocal<ReadWrite>();
+ private ThreadLocal<Integer> transactionParticipants = new ThreadLocal<Integer>();
+
/**
* Creates a new dataset connection
*
@@ -84,32 +88,37 @@ public abstract class DatasetConnection
@Override
protected JenaStatement createStatementInternal(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
- if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
- throw new SQLException("Dataset backed connections currently only supports forward-only result sets");
+ if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)
+ throw new SQLException("Dataset backed connections do not support scroll sensitive result sets");
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
throw new SQLException("Dataset backed connections only supports read-only result sets");
- return new DatasetStatement(this, ResultSet.FETCH_FORWARD, 0, resultSetHoldability, this.getAutoCommit(),
+ return new DatasetStatement(this, resultSetType, ResultSet.FETCH_FORWARD, 0, resultSetHoldability, this.getAutoCommit(),
this.getTransactionIsolation());
}
-
+
@Override
- protected JenaPreparedStatement createPreparedStatementInternal(String sparql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
- throw new SQLException("Dataset backed connections currently only supports forward-only result sets");
+ protected JenaPreparedStatement createPreparedStatementInternal(String sparql, int resultSetType, int resultSetConcurrency,
+ int resultSetHoldability) throws SQLException {
+ if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)
+ throw new SQLException("Dataset backed connections do not support scroll sensitive result sets");
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
throw new SQLException("Dataset backed connections only supports read-only result sets");
- return new DatasetPreparedStatement(sparql, this, ResultSet.FETCH_FORWARD, 0, resultSetHoldability, this.getAutoCommit(), this.getTransactionIsolation());
+ return new DatasetPreparedStatement(sparql, this, resultSetType, ResultSet.FETCH_FORWARD, 0, resultSetHoldability,
+ this.getAutoCommit(), this.getTransactionIsolation());
}
- @Override public boolean isClosed() throws SQLException {
+ @Override
+ public boolean isClosed() throws SQLException {
return this.ds == null;
}
- @Override public boolean isReadOnly() throws SQLException {
+ @Override
+ public boolean isReadOnly() throws SQLException {
return this.readonly;
}
- @Override public boolean isValid(int timeout) throws SQLException {
+ @Override
+ public boolean isValid(int timeout) throws SQLException {
return !this.isClosed();
}
@@ -135,29 +144,88 @@ public abstract class DatasetConnection
}
}
+ /**
+ * Begins a new transaction
+ * <p>
+ * Transactions are typically thread scoped and are shared by each thread so
+ * if there is an existing read transaction and another thread tries to
+ * start a read transaction it will join the existing read transaction.
+ * Trying to join a transaction not of the same type will produce an error.
+ * </p>
+ *
+ * @param type
+ * @throws SQLException
+ */
+ public synchronized void begin(ReadWrite type) throws SQLException {
+ try {
+ if (ds.supportsTransactions()) {
+ if (ds.isInTransaction()) {
+ // Additional participant in existing transaction
+ ReadWrite currType = this.transactionType.get();
+ if (currType.equals(type)) {
+ this.transactionParticipants.set(this.transactionParticipants.get() + 1);
+ } else {
+ throw new SQLException(
+ "Unable to start a transaction of a different type on the same thread as an existing transaction, please retry your operation on a different thread");
+ }
+ } else {
+ // Starting a new transaction
+ this.transactionType.set(type);
+ this.transactionParticipants.set(1);
+ this.ds.begin(type);
+ }
+ }
+ } catch (SQLException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new SQLException("Unexpected error starting a transaction", e);
+ }
+ }
+
@Override
- protected void commitInternal() throws SQLException {
+ protected synchronized void commitInternal() throws SQLException {
try {
if (ds.supportsTransactions()) {
if (ds.isInTransaction()) {
- ds.commit();
- ds.end();
+ // How many participants are there in this transaction?
+ int participants = this.transactionParticipants.get();
+ if (participants > 1) {
+ // Transaction should remain active
+ this.transactionParticipants.set(participants - 1);
+ } else {
+ // Now safe to commit
+ ds.commit();
+ ds.end();
+ this.transactionParticipants.remove();
+ this.transactionType.remove();
+ }
+ } else {
+ throw new SQLException("Attempted to commit a transaction when there was no active transaction");
}
}
+ } catch (SQLException e) {
+ throw e;
} catch (Exception e) {
throw new SQLException("Unexpected error committing the transaction", e);
}
}
@Override
- protected void rollbackInternal() throws SQLException {
+ protected synchronized void rollbackInternal() throws SQLException {
try {
if (ds.supportsTransactions()) {
if (ds.isInTransaction()) {
+ // Regardless of participants a rollback is always immediate
ds.abort();
ds.end();
+ this.transactionType.remove();
+ this.transactionParticipants.remove();
+ } else {
+ throw new SQLException("Attempted to rollback a transaction when there was no active transaction");
}
}
+ } catch (SQLException e) {
+ throw e;
} catch (Exception e) {
throw new SQLException("Unexpected error rolling back the transaction", e);
}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java Wed May 1 21:05:13 2013
@@ -294,13 +294,15 @@ public abstract class JenaConnection imp
}
private void closeStatements() throws SQLException {
- if (this.statements.size() > 0) {
- LOGGER.info("Attempting to close " + this.statements.size() + " open statements");
- for (Statement stmt : this.statements) {
- stmt.close();
+ synchronized (this.statements) {
+ if (this.statements.size() > 0) {
+ LOGGER.info("Attempting to close " + this.statements.size() + " open statements");
+ for (Statement stmt : this.statements) {
+ stmt.close();
+ }
+ LOGGER.info("All open statements were closed");
+ this.statements.clear();
}
- LOGGER.info("All open statements were closed");
- this.statements.clear();
}
}
@@ -380,7 +382,9 @@ public abstract class JenaConnection imp
if (this.isClosed())
throw new SQLException("Cannot create a statement after the connection was closed");
JenaStatement stmt = this.createStatementInternal(resultSetType, resultSetConcurrency, resultSetHoldability);
- this.statements.add(stmt);
+ synchronized (this.statements) {
+ this.statements.add(stmt);
+ }
return stmt;
}
@@ -507,18 +511,24 @@ public abstract class JenaConnection imp
throw new SQLException("Cannot create a statement after the connection was closed");
return this.createPreparedStatementInternal(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
-
+
/**
- * Helper method which derived implementations must implement to provide an actual prepared statement implementation
- * @param sql SPARQL command
- * @param resultSetType Desired result set type
- * @param resultSetConcurrency Result set concurrency
- * @param resultSetHoldability Result set holdability
+ * Helper method which derived implementations must implement to provide an
+ * actual prepared statement implementation
+ *
+ * @param sql
+ * SPARQL command
+ * @param resultSetType
+ * Desired result set type
+ * @param resultSetConcurrency
+ * Result set concurrency
+ * @param resultSetHoldability
+ * Result set holdability
* @return Prepared statement
* @throws SQLException
*/
- protected abstract JenaPreparedStatement createPreparedStatementInternal(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
- throws SQLException;
+ protected abstract JenaPreparedStatement createPreparedStatementInternal(String sql, int resultSetType,
+ int resultSetConcurrency, int resultSetHoldability) throws SQLException;
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
Added: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedResults.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedResults.java?rev=1478189&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedResults.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedResults.java Wed May 1 21:05:13 2013
@@ -0,0 +1,354 @@
+/**
+ * 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.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import org.apache.jena.jdbc.statements.JenaStatement;
+
+import com.hp.hpl.jena.query.QueryExecution;
+
+/**
+ * Represents a set of streamed results backed by some {@link QueryExecution},
+ * streamed results are considered to be forward only
+ *
+ * @param <T>
+ * Type of the underlying result rows
+ *
+ */
+public abstract class MaterializedResults<T> extends QueryExecutionResults {
+
+ private T currItem;
+ private int currRow = 0;
+
+ /**
+ * Creates new materialized results
+ *
+ * @param statement
+ * Statement that created the result set
+ * @param qe
+ * Query Execution
+ * @param commit
+ * Whether a commit is necessary when the results are closed
+ * @throws SQLException
+ * Thrown if the arguments are invalid
+ */
+ public MaterializedResults(JenaStatement statement, QueryExecution qe, boolean commit) throws SQLException {
+ super(statement, qe, commit);
+ }
+
+ /**
+ * Gets the current result row (if any)
+ *
+ * @return Result row, null if not at a row
+ * @throws SQLException
+ * Thrown if the result set is closed
+ */
+ protected T getCurrentRow() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result set is closed");
+ return this.currItem;
+ }
+
+ /**
+ * Method which derived classes must implement to indicate whether they have
+ * further rows available to move forwards to
+ *
+ * @return True if further rows are available, false otherwise
+ * @throws SQLException
+ * Thrown if an error determining whether rows are available
+ */
+ protected abstract boolean hasNext() throws SQLException;
+
+ /**
+ * Method which derived classes must implement to indicate whether they have
+ * further rows available to move backwards to
+ *
+ * @return True if further rows are available, false otherwise
+ * @throws SQLException
+ * Thrown if an error determining whether rows are available
+ */
+ protected abstract boolean hasPrevious() throws SQLException;
+
+ /**
+ * Method which derived classes must implement to provide the next row
+ * available
+ *
+ * @return Next row available
+ * @throws SQLException
+ * Thrown if this method is invoked when no further rows are
+ * available
+ */
+ protected abstract T moveNext() throws SQLException;
+
+ /**
+ * Method which derived classes must implement to provide the previous row
+ * available
+ *
+ * @return Previous row available
+ * @throws SQLException
+ * Thrown if this method is invoked when no previous rows are
+ * available
+ */
+ protected abstract T movePrevious() throws SQLException;
+
+ protected abstract int getTotalRows() throws SQLException;
+
+ @Override
+ public final boolean absolute(int row) throws SQLException {
+ if (this.isClosed()) {
+ throw new SQLException("Cannot move to a row after the result set has been closed");
+ } else if (row == 1) {
+ // Try and move to the first row
+ return this.first();
+ } else if (row == -1) {
+ // Try and move to the last row
+ return this.last();
+ } else if (row == 0) {
+ // Try and move to before first row
+ this.beforeFirst();
+ return false;
+ } else if (row >= this.getTotalRows()) {
+ // Try and move to after last row
+ this.afterLast();
+ return false;
+ } else if (row <= 0) {
+ // Move to a row relative to the end of the result set
+ int destRow = this.getTotalRows() + row;
+ if (destRow < 1) {
+ // Move to before first
+ this.beforeFirst();
+ return false;
+ } else {
+ // Call ourselves to avoid repeating logic
+ return this.absolute(destRow);
+ }
+ } else if (row == this.currRow) {
+ // Already at the desired row
+ return true;
+ } else if (row < this.currRow) {
+ // After the desired row
+ while (this.hasPrevious() && row < this.currRow) {
+ this.currItem = this.movePrevious();
+ this.currRow--;
+ }
+ // Since we already checked that the desired row is a valid absolute
+ // row it is always possible to move backwards to the desired row
+ return true;
+ } else {
+ // Before the desired row
+ while (this.hasNext() && this.currRow < row) {
+ this.currItem = this.moveNext();
+ this.currRow++;
+ }
+ // Since we already checked that the desired row is a valid absolute
+ // row it is always possible to move forwards to the desired row
+ return true;
+ }
+ }
+
+ @Override
+ public final void afterLast() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+
+ // Move to end of results if necessary
+ while (this.hasNext()) {
+ this.currItem = this.moveNext();
+ this.currRow++;
+ }
+ this.currItem = null;
+ this.currRow = this.getTotalRows() + 1;
+ }
+
+ @Override
+ public final void beforeFirst() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+
+ // Move to start of results if necessary
+ while (this.hasPrevious()) {
+ this.currItem = this.movePrevious();
+ this.currRow--;
+ }
+ this.currItem = null;
+ this.currRow = 0;
+ }
+
+ @Override
+ protected final void closeInternal() throws SQLException {
+ this.currItem = null;
+ this.closeStreamInternal();
+ }
+
+ protected abstract void closeStreamInternal() throws SQLException;
+
+ @Override
+ public final boolean first() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+
+ // If no rows this should always return false
+ if (this.getTotalRows() == 0)
+ return false;
+
+ // Are we already at the first row?
+ if (this.currRow == 1)
+ return true;
+
+ // Otherwise move backwards to it
+ while (this.hasPrevious()) {
+ this.currItem = this.movePrevious();
+ this.currRow--;
+ }
+ return true;
+ }
+
+ @Override
+ public final int getFetchDirection() throws SQLException {
+ return ResultSet.FETCH_FORWARD;
+ }
+
+ @Override
+ public final int getFetchSize() throws SQLException {
+ // TODO Need a buffering wrapper around ResultSet to make this
+ // configurable
+ return 0;
+ }
+
+ @Override
+ public final int getRow() throws SQLException {
+ return this.currRow;
+ }
+
+ @Override
+ public final int getType() throws SQLException {
+ return ResultSet.TYPE_SCROLL_INSENSITIVE;
+ }
+
+ @Override
+ public final boolean isAfterLast() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ return this.currRow > this.getTotalRows();
+ }
+
+ @Override
+ public final boolean isBeforeFirst() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ return this.currRow == 0;
+ }
+
+ @Override
+ public final boolean isFirst() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ return this.currRow == 1;
+ }
+
+ @Override
+ public final boolean isLast() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ return this.currRow == this.getTotalRows();
+ }
+
+ @Override
+ public final boolean last() throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Jena JDBC Result Sets are forward-only");
+
+ // If no rows this should always return false
+ if (this.getTotalRows() == 0)
+ return false;
+
+ // Are we already at the last row?
+ if (this.currRow == this.getTotalRows())
+ return true;
+
+ // Otherwise move forwards to the last row
+ while (this.hasNext()) {
+ this.currItem = this.moveNext();
+ this.currRow++;
+ }
+ return true;
+
+ }
+
+ @Override
+ public final boolean next() throws SQLException {
+ if (this.isClosed()) {
+ throw new SQLException("Cannot move to the next row in a closed result set");
+ } else {
+ if (this.hasNext()) {
+ this.currItem = this.moveNext();
+ this.currRow++;
+ return true;
+ } else {
+ this.currItem = null;
+ this.currRow = this.getTotalRows() + 1;
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public final boolean relative(int rows) throws SQLException {
+ if (this.isClosed()) {
+ throw new SQLException("Cannot move to a row after the result set has been closed");
+ } else if (rows == 0) {
+ // Already at the desired row
+ return true;
+ } else if (rows < 0) {
+ // Calculate destination row and use absolute() to move there
+ int destRow = this.currRow + rows;
+ return this.absolute(destRow);
+ } else if (this.currRow + rows > this.getTotalRows()) {
+ // Would result in moving beyond the end of the results
+ this.afterLast();
+ return false;
+ } else {
+ // Before the desired row
+ int moved = 0;
+ while (this.hasNext() && moved < rows) {
+ this.currItem = this.moveNext();
+ this.currRow++;
+ moved++;
+ }
+ // Since we already checked if the move would take us beyond the end
+ // of the results we will always have reached the desired row
+ return true;
+ }
+ }
+
+ @Override
+ public final void setFetchDirection(int direction) throws SQLException {
+ if (direction != ResultSet.FETCH_FORWARD)
+ throw new SQLFeatureNotSupportedException("Jena JDBC Result Sets only support forward fetch");
+ }
+
+ @Override
+ public final void setFetchSize(int rows) throws SQLException {
+ // TODO Need to provide some buffering wrapper over a ResultSet to make
+ // this possible
+ throw new SQLFeatureNotSupportedException();
+ }
+}
Added: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedSelectResults.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedSelectResults.java?rev=1478189&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedSelectResults.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/MaterializedSelectResults.java Wed May 1 21:05:13 2013
@@ -0,0 +1,157 @@
+/**
+ * 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.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.jena.atlas.lib.Closeable;
+import org.apache.jena.jdbc.results.metadata.SelectResultsMetadata;
+import org.apache.jena.jdbc.statements.JenaStatement;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.QueryExecution;
+import com.hp.hpl.jena.query.ResultSetRewindable;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+
+/**
+ * Represents SPARQL SELECT results
+ *
+ */
+public class MaterializedSelectResults extends MaterializedResults<Binding> {
+
+ private ResultSetRewindable innerResults;
+ private Stack<Binding> previousResults = new Stack<Binding>();
+ private List<String> columns;
+ private SelectResultsMetadata metadata;
+
+ /**
+ * Creates new select results
+ *
+ * @param statement
+ * Statement that created the result set
+ * @param qe
+ * Query Execution
+ * @param results
+ * SPARQL Results
+ * @param commit
+ * Whether a commit is necessary when the results are closed
+ * @throws SQLException
+ * Thrown if the arguments are invalid
+ */
+ public MaterializedSelectResults(JenaStatement statement, QueryExecution qe, ResultSetRewindable results, boolean commit)
+ throws SQLException {
+ super(statement, qe, commit);
+ if (results == null)
+ throw new SQLException("SPARQL Results cannot be null");
+ this.innerResults = results;
+ this.columns = new ArrayList<String>(this.innerResults.getResultVars());
+ this.metadata = new SelectResultsMetadata(this, this.innerResults);
+ }
+
+ @Override
+ public void closeStreamInternal() throws SQLException {
+ if (this.innerResults != null) {
+ if (this.innerResults instanceof Closeable) {
+ ((Closeable) this.innerResults).close();
+ }
+ this.innerResults = null;
+ }
+ }
+
+ public int findColumn(String columnLabel) throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ for (int i = 0; i < this.columns.size(); i++) {
+ if (this.columns.get(i).equals(columnLabel)) {
+ // Remember that JDBC uses a 1 based index
+ return i + 1;
+ }
+ }
+ throw new SQLException("The given column does not exist in this result set");
+ }
+
+ @Override
+ protected String findColumnLabel(int columnIndex) throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ if (columnIndex >= 1 && columnIndex <= this.columns.size()) {
+ // Remember that JDBC uses a 1 based index
+ return this.columns.get(columnIndex - 1);
+ } 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");
+ if (!this.columns.contains(columnLabel))
+ throw new SQLException("The given column does not exist in the result set");
+ return this.getCurrentRow().get(Var.alloc(columnLabel));
+ }
+
+ @Override
+ public ResultSetMetaData getMetaData() throws SQLException {
+ return this.metadata;
+ }
+
+ /**
+ * Gets whether there are further rows in the underlying SELECT 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
+ return this.innerResults.hasNext();
+ }
+
+ /**
+ * Gets the next row from the underlying SELECT results
+ */
+ @Override
+ protected Binding moveNext() throws SQLException {
+ // No null check here because superclass will not call us after we are
+ // closed and set to null
+ this.previousResults.push(this.innerResults.nextBinding());
+ return this.previousResults.peek();
+ }
+
+ @Override
+ protected boolean hasPrevious() throws SQLException {
+ return this.previousResults.size() > 0;
+ }
+
+ @Override
+ protected Binding movePrevious() throws SQLException {
+ return this.previousResults.pop();
+ }
+
+ @Override
+ protected int getTotalRows() {
+ return this.innerResults.size();
+ }
+}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/StreamedResults.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/StreamedResults.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/StreamedResults.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/StreamedResults.java Wed May 1 21:05:13 2013
@@ -41,7 +41,7 @@ public abstract class StreamedResults<T>
private int currRow = 0;
/**
- * Creates new select results
+ * Creates new streamed results
*
* @param statement
* Statement that created the result set
Added: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/TripleListResults.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/TripleListResults.java?rev=1478189&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/TripleListResults.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/TripleListResults.java Wed May 1 21:05:13 2013
@@ -0,0 +1,154 @@
+/**
+ * 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.List;
+
+import org.apache.jena.atlas.iterator.PeekIterator;
+import org.apache.jena.jdbc.results.metadata.TripleResultsMetadata;
+import org.apache.jena.jdbc.statements.JenaStatement;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.query.QueryExecution;
+
+/**
+ * Represents results of a CONSTRUCT/DESCRIBE query where the results are
+ * materialized
+ *
+ */
+public class TripleListResults extends MaterializedResults<Triple> {
+
+ private TripleResultsMetadata metadata;
+ private List<Triple> triples;
+
+ /**
+ * 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 TripleListResults(JenaStatement statement, QueryExecution qe, List<Triple> ts, boolean commit) throws SQLException {
+ super(statement, qe, commit);
+ if (ts == null)
+ throw new SQLException("Triple Iterator cannot be null");
+ this.triples = ts;
+ this.metadata = new TripleResultsMetadata(this, new PeekIterator<Triple>(ts.iterator()));
+ }
+
+ @Override
+ public int findColumn(String columnLabel) throws SQLException {
+ if (TripleResultsMetadata.COLUMN_LABEL_SUBJECT.equals(columnLabel)) {
+ return 1;
+ } else if (TripleResultsMetadata.COLUMN_LABEL_PREDICATE.equals(columnLabel)) {
+ return 2;
+ } else if (TripleResultsMetadata.COLUMN_LABEL_OBJECT.equals(columnLabel)) {
+ return 3;
+ } 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
+ return this.getRow() < this.triples.size();
+ }
+
+ @Override
+ protected Triple moveNext() throws SQLException {
+ return this.triples.get(this.getRow());
+ }
+
+ @Override
+ protected boolean hasPrevious() throws SQLException {
+ return this.getRow() > 1;
+ }
+
+ @Override
+ protected Triple movePrevious() throws SQLException {
+ return this.triples.get(this.getRow() - 1);
+ }
+
+ @Override
+ protected int getTotalRows() {
+ return this.triples.size();
+ }
+
+ @Override
+ protected void closeStreamInternal() throws SQLException {
+ if (this.triples != null) {
+ this.triples = null;
+ }
+ }
+
+ @Override
+ public ResultSetMetaData getMetaData() throws SQLException {
+ return metadata;
+ }
+
+ @Override
+ protected String findColumnLabel(int columnIndex) throws SQLException {
+ if (this.isClosed())
+ throw new SQLException("Result Set is closed");
+ if (columnIndex >= 1 && columnIndex <= TripleResultsMetadata.NUM_COLUMNS) {
+ switch (columnIndex) {
+ case 1:
+ return TripleResultsMetadata.COLUMN_LABEL_SUBJECT;
+ case 2:
+ return TripleResultsMetadata.COLUMN_LABEL_PREDICATE;
+ case 3:
+ return TripleResultsMetadata.COLUMN_LABEL_OBJECT;
+ 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 (TripleResultsMetadata.COLUMN_LABEL_SUBJECT.equals(columnLabel)) {
+ return t.getSubject();
+ } else if (TripleResultsMetadata.COLUMN_LABEL_PREDICATE.equals(columnLabel)) {
+ return t.getPredicate();
+ } else if (TripleResultsMetadata.COLUMN_LABEL_OBJECT.equals(columnLabel)) {
+ return t.getObject();
+ } else {
+ throw new SQLException("Unknown column label");
+ }
+ }
+}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetPreparedStatement.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetPreparedStatement.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetPreparedStatement.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetPreparedStatement.java Wed May 1 21:05:13 2013
@@ -51,8 +51,8 @@ public class DatasetPreparedStatement ex
* Thrown if there is an error with the statement parameters
*/
public DatasetPreparedStatement(String sparql, DatasetConnection connection) throws SQLException {
- this(sparql, connection, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY, DEFAULT_AUTO_COMMIT,
- DEFAULT_TRANSACTION_LEVEL);
+ this(sparql, connection, DEFAULT_TYPE, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY,
+ DEFAULT_AUTO_COMMIT, DEFAULT_TRANSACTION_LEVEL);
}
/**
@@ -62,6 +62,8 @@ public class DatasetPreparedStatement ex
* SPARQL command
* @param connection
* Connection
+ * @param type
+ * Result Set type for result sets produced by this statement
* @param fetchDir
* Fetch Direction
* @param fetchSize
@@ -76,9 +78,9 @@ public class DatasetPreparedStatement ex
* Thrown if there is an error with the statement parameters
*
*/
- public DatasetPreparedStatement(String sparql, DatasetConnection connection, int fetchDir, int fetchSize, int holdability,
- boolean autoCommit, int transactionLevel) throws SQLException {
- super(sparql, connection, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
+ public DatasetPreparedStatement(String sparql, DatasetConnection connection, int type, int fetchDir, int fetchSize,
+ int holdability, boolean autoCommit, int transactionLevel) throws SQLException {
+ super(sparql, connection, type, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
this.dsConn = connection;
}
@@ -101,7 +103,7 @@ public class DatasetPreparedStatement ex
@Override
protected void beginTransaction(ReadWrite type) throws SQLException {
try {
- this.dsConn.getJenaDataset().begin(type);
+ this.dsConn.begin(type);
} catch (Exception e) {
throw new SQLException("Unexpected error starting a transaction", e);
}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetStatement.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetStatement.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetStatement.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/DatasetStatement.java Wed May 1 21:05:13 2013
@@ -49,7 +49,7 @@ public class DatasetStatement extends Je
* Thrown if there is an error with the statement parameters
*/
public DatasetStatement(DatasetConnection connection) throws SQLException {
- this(connection, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY, DEFAULT_AUTO_COMMIT,
+ this(connection, DEFAULT_TYPE, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY, DEFAULT_AUTO_COMMIT,
DEFAULT_TRANSACTION_LEVEL);
}
@@ -58,6 +58,8 @@ public class DatasetStatement extends Je
*
* @param connection
* Connection
+ * @param type
+ * Result Set type for result sets produced by this statement
* @param fetchDir
* Fetch Direction
* @param fetchSize
@@ -72,9 +74,9 @@ public class DatasetStatement extends Je
* Thrown if there is an error with the statement parameters
*
*/
- public DatasetStatement(DatasetConnection connection, int fetchDir, int fetchSize, int holdability, boolean autoCommit,
+ public DatasetStatement(DatasetConnection connection, int type, int fetchDir, int fetchSize, int holdability, boolean autoCommit,
int transactionLevel) throws SQLException {
- super(connection, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
+ super(connection, type, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
this.dsConn = connection;
}
@@ -97,7 +99,7 @@ public class DatasetStatement extends Je
@Override
protected void beginTransaction(ReadWrite type) throws SQLException {
try {
- this.dsConn.getJenaDataset().begin(type);
+ this.dsConn.begin(type);
} catch (Exception e) {
throw new SQLException("Unexpected error starting a transaction", e);
}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaPreparedStatement.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaPreparedStatement.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaPreparedStatement.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaPreparedStatement.java Wed May 1 21:05:13 2013
@@ -65,6 +65,8 @@ public abstract class JenaPreparedStatem
* @param sparql
* @param connection
* Connection
+ * @param type
+ * Result Set type for result sets produced by this statement
* @param fetchDir
* Fetch Direction
* @param fetchSize
@@ -78,9 +80,9 @@ public abstract class JenaPreparedStatem
* @throws SQLException
* Thrown if there is a problem preparing the statement
*/
- public JenaPreparedStatement(String sparql, JenaConnection connection, int fetchDir, int fetchSize, int holdability,
- boolean autoCommit, int transactionLevel) throws SQLException {
- super(connection, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
+ public JenaPreparedStatement(String sparql, JenaConnection connection, int type, int fetchDir, int fetchSize,
+ int holdability, boolean autoCommit, int transactionLevel) throws SQLException {
+ super(connection, type, fetchDir, fetchSize, holdability, autoCommit, transactionLevel);
this.sparqlStr.setCommandText(sparql);
this.paramMetadata = new JenaParameterMetadata(this.sparqlStr);
@@ -110,7 +112,7 @@ public abstract class JenaPreparedStatem
public int executeUpdate() throws SQLException {
return this.executeUpdate(this.sparqlStr.toString());
}
-
+
@Override
public ResultSetMetaData getMetaData() throws SQLException {
// Return null because we don't know in advance the column types
@@ -305,7 +307,7 @@ public abstract class JenaPreparedStatem
@Override
public void setObject(int parameterIndex, Object value) throws SQLException {
if (value instanceof Node) {
- this.setParameter(parameterIndex, (Node)value);
+ this.setParameter(parameterIndex, (Node) value);
} else {
throw new SQLException("Calls to setObject() must pass an object of type Node");
}
@@ -338,8 +340,7 @@ public abstract class JenaPreparedStatem
@Override
public void setShort(int parameterIndex, short value) throws SQLException {
- this.setParameter(parameterIndex,
- NodeFactory.createLiteral(Short.toString(value), XSDDatatype.XSDshort));
+ this.setParameter(parameterIndex, NodeFactory.createLiteral(Short.toString(value), XSDDatatype.XSDshort));
}
@Override
@@ -356,20 +357,17 @@ public abstract class JenaPreparedStatem
@Override
public void setTime(int parameterIndex, Time value, Calendar arg2) throws SQLException {
- // TODO Auto-generated method stub
-
+ throw new SQLFeatureNotSupportedException();
}
@Override
public void setTimestamp(int parameterIndex, Timestamp value) throws SQLException {
- // TODO Auto-generated method stub
-
+ throw new SQLFeatureNotSupportedException();
}
@Override
public void setTimestamp(int parameterIndex, Timestamp value, Calendar arg2) throws SQLException {
- // TODO Auto-generated method stub
-
+ throw new SQLFeatureNotSupportedException();
}
@Override
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaStatement.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaStatement.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaStatement.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaStatement.java Wed May 1 21:05:13 2013
@@ -30,10 +30,13 @@ import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
+import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.jdbc.connections.JenaConnection;
import org.apache.jena.jdbc.results.AskResults;
+import org.apache.jena.jdbc.results.MaterializedSelectResults;
import org.apache.jena.jdbc.results.SelectResults;
import org.apache.jena.jdbc.results.TripleIteratorResults;
+import org.apache.jena.jdbc.results.TripleListResults;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +44,7 @@ import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ReadWrite;
+import com.hp.hpl.jena.query.ResultSetFactory;
import com.hp.hpl.jena.update.UpdateFactory;
import com.hp.hpl.jena.update.UpdateProcessor;
import com.hp.hpl.jena.update.UpdateRequest;
@@ -51,7 +55,7 @@ import com.hp.hpl.jena.update.UpdateRequ
*
*/
public abstract class JenaStatement implements Statement {
-
+
private static final Logger LOGGER = LoggerFactory.getLogger(JenaStatement.class);
protected static final int DEFAULT_HOLDABILITY = ResultSet.CLOSE_CURSORS_AT_COMMIT;
@@ -60,6 +64,7 @@ public abstract class JenaStatement impl
protected static final boolean DEFAULT_AUTO_COMMIT = JenaConnection.DEFAULT_AUTO_COMMIT;
protected static final int DEFAULT_TRANSACTION_LEVEL = JenaConnection.DEFAULT_ISOLATION_LEVEL;
protected static final int NO_LIMIT = 0;
+ protected static final int DEFAULT_TYPE = ResultSet.TYPE_FORWARD_ONLY;
private List<String> commands = new ArrayList<String>();
private SQLWarning warnings = null;
@@ -68,6 +73,7 @@ public abstract class JenaStatement impl
private Queue<ResultSet> results = new LinkedList<ResultSet>();
private List<ResultSet> openResults = new ArrayList<ResultSet>();
private boolean closed = false;
+ private int type = DEFAULT_TYPE;
private int fetchDirection = DEFAULT_FETCH_DIRECTION;
private int fetchSize = DEFAULT_FETCH_SIZE;
private int holdability = DEFAULT_HOLDABILITY;
@@ -88,7 +94,7 @@ public abstract class JenaStatement impl
* Thrown if the arguments are invalid
*/
public JenaStatement(JenaConnection connection) throws SQLException {
- this(connection, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY, DEFAULT_AUTO_COMMIT,
+ this(connection, DEFAULT_TYPE, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY, DEFAULT_AUTO_COMMIT,
DEFAULT_TRANSACTION_LEVEL);
}
@@ -97,6 +103,8 @@ public abstract class JenaStatement impl
*
* @param connection
* Connection
+ * @param type
+ * Result Set type for result sets produced by this statement
* @param fetchDir
* Fetch Direction
* @param fetchSize
@@ -111,12 +119,13 @@ public abstract class JenaStatement impl
* Thrown if there is an error with the statement parameters
*
*/
- public JenaStatement(JenaConnection connection, int fetchDir, int fetchSize, int holdability, boolean autoCommit,
+ public JenaStatement(JenaConnection connection, int type, int fetchDir, int fetchSize, int holdability, boolean autoCommit,
int transactionLevel) throws SQLException {
if (connection == null)
throw new SQLException("Cannot create a Statement with a null connection");
this.connection = connection;
this.checkFetchDirection(fetchDir);
+ this.type = type;
this.fetchDirection = fetchDir;
this.fetchSize = fetchSize;
this.checkHoldability(holdability);
@@ -192,7 +201,7 @@ public abstract class JenaStatement impl
public final boolean execute(String sql) throws SQLException {
if (this.isClosed())
throw new SQLException("The Statement is closed");
-
+
// Pre-process the command text
LOGGER.info("Received input command text:\n {}", sql);
sql = this.connection.applyPreProcessors(sql);
@@ -230,12 +239,15 @@ public abstract class JenaStatement impl
private boolean executeQuery(Query q) throws SQLException {
if (this.isClosed())
throw new SQLException("The Statement is closed");
-
+
// Do we need transactions?
boolean needsBegin = (!this.autoCommit && this.transactionLevel != Connection.TRANSACTION_NONE && !this
.hasActiveTransaction());
boolean needsCommit = (this.autoCommit && this.transactionLevel != Connection.TRANSACTION_NONE);
+ // Do this first in a separate try catch so if we fail to start a
+ // transaction we don't then try to roll it back which can mask the
+ // actual cause of the error
try {
// Start a transaction if necessary
if (needsCommit) {
@@ -245,7 +257,12 @@ public abstract class JenaStatement impl
LOGGER.info("Starting a new transaction to run query, transaction will not be auto-committed");
this.beginTransaction(ReadWrite.WRITE);
}
-
+ } catch (Exception e) {
+ LOGGER.error("Starting the new transaction failed", e);
+ throw new SQLException("Failed to start a new query transaction", e);
+ }
+
+ try {
// Pre-process the query
q = this.connection.applyPreProcessors(q);
@@ -270,26 +287,68 @@ public abstract class JenaStatement impl
// Return the appropriate result set type
if (q.isSelectType()) {
- this.currResults = new SelectResults(this, qe, qe.execSelect(), needsCommit);
- return true;
+ switch (this.type) {
+ case ResultSet.TYPE_SCROLL_INSENSITIVE:
+ this.currResults = new MaterializedSelectResults(this, qe, ResultSetFactory.makeRewindable(qe.execSelect()),
+ false);
+ break;
+ case ResultSet.TYPE_FORWARD_ONLY:
+ default:
+ this.currResults = new SelectResults(this, qe, qe.execSelect(), needsCommit);
+ break;
+ }
} else if (q.isAskType()) {
boolean askRes = qe.execAsk();
qe.close();
this.currResults = new AskResults(this, askRes, needsCommit);
- return true;
} else if (q.isDescribeType()) {
- this.currResults = new TripleIteratorResults(this, qe, qe.execDescribeTriples(), needsCommit);
- return true;
+ switch (this.type) {
+ case ResultSet.TYPE_SCROLL_INSENSITIVE:
+ this.currResults = new TripleListResults(this, qe, Iter.toList(qe.execDescribeTriples()), false);
+ break;
+ case ResultSet.TYPE_FORWARD_ONLY:
+ default:
+ this.currResults = new TripleIteratorResults(this, qe, qe.execDescribeTriples(), needsCommit);
+ break;
+ }
} else if (q.isConstructType()) {
- this.currResults = new TripleIteratorResults(this, qe, qe.execConstructTriples(), needsCommit);
- return true;
+ switch (this.type) {
+ case ResultSet.TYPE_SCROLL_INSENSITIVE:
+ this.currResults = new TripleListResults(this, qe, Iter.toList(qe.execConstructTriples()), false);
+ break;
+ case ResultSet.TYPE_FORWARD_ONLY:
+ default:
+ this.currResults = new TripleIteratorResults(this, qe, qe.execConstructTriples(), needsCommit);
+ break;
+ }
} else {
throw new SQLException("Unknown SPARQL Query type");
}
+
+ // Can immediately commit when type is
+ // TYPE_SCROLL_INSENSITIVE and auto-committing since we have
+ // already materialized results so don't need the read
+ // transaction
+ if (this.type == ResultSet.TYPE_SCROLL_INSENSITIVE && needsCommit) {
+ LOGGER.info("Auto-committing query transaction since results have been materialized");
+ this.commitTransaction();
+ }
+
+ return true;
} catch (SQLException e) {
+ if (needsCommit) {
+ // When auto-committing and query fails roll back immediately
+ LOGGER.warn("Rolling back failed query transaction");
+ this.rollbackTransaction();
+ }
throw e;
- } catch (Exception e) {
+ } catch (Throwable e) {
LOGGER.error("SPARQL Query evaluation failed", e);
+ if (needsCommit) {
+ // When auto-committing and query fails roll back immediately
+ LOGGER.warn("Rolling back failed query transaction");
+ this.rollbackTransaction();
+ }
throw new SQLException("Error occurred during SPARQL query evaluation", e);
}
}
@@ -317,7 +376,6 @@ public abstract class JenaStatement impl
.hasActiveTransaction());
boolean needsCommit = (this.autoCommit && this.transactionLevel != Connection.TRANSACTION_NONE);
- boolean commit = false;
try {
// Start a Transaction if necessary
if (needsCommit || needsBegin) {
@@ -328,30 +386,39 @@ public abstract class JenaStatement impl
}
this.beginTransaction(ReadWrite.WRITE);
}
-
+ } catch (Exception e) {
+ LOGGER.error("Starting the new transaction failed", e);
+ throw new SQLException("Failed to start a new query transaction", e);
+ }
+
+ try {
// Pre-process the update
u = this.connection.applyPreProcessors(u);
// Execute updates
UpdateProcessor processor = this.createUpdateProcessor(u);
processor.execute();
- commit = true;
+
+ // If auto-committing can commit immediately
+ if (needsCommit) {
+ LOGGER.info("Auto-committing update transaction");
+ this.commitTransaction();
+ }
+
return 0;
} catch (SQLException e) {
+ if (needsCommit) {
+ LOGGER.warn("Rolling back failed update transaction");
+ this.rollbackTransaction();
+ }
throw e;
} catch (Exception e) {
LOGGER.error("SPARQL Update evaluation failed", e);
- throw new SQLException("Error occurred during SPARQL update evaluation", e);
- } finally {
if (needsCommit) {
- if (commit) {
- LOGGER.info("Committing update transaction");
- this.commitTransaction();
- } else {
- LOGGER.warn("Rolling back failed update transaction");
- this.rollbackTransaction();
- }
+ LOGGER.warn("Rolling back failed update transaction");
+ this.rollbackTransaction();
}
+ throw new SQLException("Error occurred during SPARQL update evaluation", e);
}
}
@@ -375,19 +442,17 @@ public abstract class JenaStatement impl
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
- throw new SQLFeatureNotSupportedException("Use the single argument form of execute()");
+ return this.execute(sql);
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
- throw new SQLFeatureNotSupportedException("Use the single argument form of execute()");
+ return this.execute(sql);
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
- // TODO: Assuming a SELECT * or DESCRIBE * could replace the * with the
- // specific column names
- throw new SQLFeatureNotSupportedException("Use the single argument form of execute()");
+ return this.execute(sql);
}
@Override
@@ -395,6 +460,12 @@ public abstract class JenaStatement impl
if (this.isClosed())
throw new SQLException("The Statement is closed");
+ // Issue warning where appropriate
+ if (this.commands.size() > 1 && this.autoCommit && this.holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
+ this.setWarning("Executing this batch of commands may lead to unexpectedly closed result sets because auto-commit is enabled and commit behaviour is set to close cursors at commit");
+ }
+
+ // Go ahead and process the batch
int[] rets = new int[this.commands.size()];
ResultSet curr = this.currResults;
for (int i = 0; i < this.commands.size(); i++) {
@@ -402,8 +473,11 @@ public abstract class JenaStatement impl
// True means it returned a ResultSet
this.results.add(this.getResultSet());
this.currResults = null;
- rets[i] = 0;
+ rets[i] = SUCCESS_NO_INFO;
} else {
+ // Need to add a null to getMoreResults() to produce correct
+ // behavior across subsequent calls to getMoreResults()
+ this.results.add(null);
rets[i] = this.getUpdateCount();
}
}
@@ -420,7 +494,7 @@ public abstract class JenaStatement impl
public final ResultSet executeQuery(String sql) throws SQLException {
if (this.isClosed())
throw new SQLException("The Statement is closed");
-
+
// Pre-process the command text
LOGGER.info("Received input command text:\n {}", sql);
sql = this.connection.applyPreProcessors(sql);
@@ -449,12 +523,12 @@ public abstract class JenaStatement impl
throw new SQLException("The Statement is closed");
if (this.connection.isReadOnly())
throw new SQLException("The JDBC connection is currently in read-only mode, updates are not permitted");
-
+
// Pre-process the command text
LOGGER.info("Received input command text:\n {}", sql);
sql = this.connection.applyPreProcessors(sql);
LOGGER.info("Command text after pre-processing:\n {}", sql);
-
+
UpdateRequest u = null;
try {
u = UpdateFactory.create(sql);
Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java Wed May 1 21:05:13 2013
@@ -17,7 +17,11 @@
*/
package org.apache.jena.jdbc.connections;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.sql.Connection;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
@@ -26,6 +30,7 @@ import java.sql.Types;
import org.apache.jena.jdbc.JdbcCompatibility;
import org.apache.jena.jdbc.connections.JenaConnection;
+import org.apache.jena.jdbc.results.metadata.AskResultsMetadata;
import org.apache.jena.jdbc.results.metadata.TripleResultsMetadata;
import org.apache.jena.jdbc.utils.TestUtils;
import org.apache.log4j.BasicConfigurator;
@@ -77,6 +82,33 @@ public abstract class AbstractJenaConnec
protected abstract JenaConnection getConnection(Dataset ds) throws SQLException;
/**
+ * Method which indicates whether a named graph is being used as the default
+ * graph since some tests need to know this in order to adjust SPARQL
+ * Updates issued appropriately
+ * <p>
+ * By default assumed to be false, override if you need to make it true for
+ * your connection
+ * </p>
+ *
+ * @return
+ */
+ protected boolean usesNamedGraphAsDefault() {
+ return false;
+ }
+
+ /**
+ * Method which returns the name of the default graph when a named graph is
+ * being used as the default graph
+ *
+ * @return Named Graph being used as the default graph
+ * @throws SQLException Thrown if this feature is not being used
+ */
+ protected String getDefaultGraphName() throws SQLException {
+ throw new SQLException(
+ "Named Default Graph not used by these tests, please override getDefaultGraphName() if your connection uses this feature");
+ }
+
+ /**
* Create and close a connection to an empty database
*
* @throws SQLException
@@ -320,6 +352,153 @@ public abstract class AbstractJenaConnec
}
/**
+ * Tests use of prepared statements
+ *
+ * @throws SQLException
+ * @throws MalformedURLException
+ */
+ @Test
+ public void connection_prepared_statement_select_01() throws SQLException, MalformedURLException {
+ // Prepare a dataset
+ Dataset ds = DatasetFactory.createMem();
+ ds.asDatasetGraph().add(
+ new Quad(NodeFactory.createURI("http://example/graph"), NodeFactory.createURI("http://example/subject"),
+ NodeFactory.createURI("http://example/predicate"), NodeFactory.createURI("http://example/object")));
+
+ // Work with the connection
+ JenaConnection conn = this.getConnection(ds);
+ conn.setJdbcCompatibilityLevel(JdbcCompatibility.HIGH);
+ PreparedStatement stmt = conn.prepareStatement("SELECT * WHERE { GRAPH ? { ?s ?p ?o } }");
+ ParameterMetaData metadata = stmt.getParameterMetaData();
+ Assert.assertEquals(1, metadata.getParameterCount());
+ stmt.setURL(1, new URL("http://example/graph"));
+
+ ResultSet rset = stmt.executeQuery();
+ Assert.assertNotNull(rset);
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Should have a row
+ Assert.assertTrue(rset.next());
+ Assert.assertTrue(rset.isFirst());
+ Assert.assertEquals(1, rset.getRow());
+
+ // Should be no further rows
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(rset.isClosed());
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
+
+ /**
+ * Tests use of prepared statements
+ *
+ * @throws SQLException
+ * @throws MalformedURLException
+ */
+ @Test
+ public void connection_prepared_statement_select_02() throws SQLException, MalformedURLException {
+ // Prepare a dataset
+ Dataset ds = DatasetFactory.createMem();
+ ds.asDatasetGraph().add(
+ new Quad(NodeFactory.createURI("http://example/graph"), NodeFactory.createURI("http://example/subject"),
+ NodeFactory.createURI("http://example/predicate"), NodeFactory.createLiteral("value")));
+
+ // Work with the connection
+ JenaConnection conn = this.getConnection(ds);
+ conn.setJdbcCompatibilityLevel(JdbcCompatibility.HIGH);
+ PreparedStatement stmt = conn.prepareStatement("SELECT * WHERE { GRAPH ?g { ?s ?p ? } }");
+ ParameterMetaData metadata = stmt.getParameterMetaData();
+ Assert.assertEquals(1, metadata.getParameterCount());
+ stmt.setString(1, "value");
+
+ ResultSet rset = stmt.executeQuery();
+ Assert.assertNotNull(rset);
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Should have a row
+ Assert.assertTrue(rset.next());
+ Assert.assertTrue(rset.isFirst());
+ Assert.assertEquals(1, rset.getRow());
+
+ // Should be no further rows
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(rset.isClosed());
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
+
+ /**
+ * Tests use of prepared statements
+ *
+ * @throws SQLException
+ * @throws MalformedURLException
+ */
+ @Test
+ public void connection_prepared_statement_select_03() throws SQLException, MalformedURLException {
+ // Prepare a dataset
+ Dataset ds = DatasetFactory.createMem();
+ ds.asDatasetGraph().add(
+ new Quad(NodeFactory.createURI("http://example/graph"), NodeFactory.createURI("http://example/subject"),
+ NodeFactory.createURI("http://example/predicate"), NodeFactory.createLiteral("value")));
+
+ // Work with the connection
+ JenaConnection conn = this.getConnection(ds);
+ conn.setJdbcCompatibilityLevel(JdbcCompatibility.HIGH);
+ PreparedStatement stmt = conn.prepareStatement("SELECT * WHERE { GRAPH ?g { ?s ?p ? } }");
+ ParameterMetaData metadata = stmt.getParameterMetaData();
+ Assert.assertEquals(1, metadata.getParameterCount());
+ stmt.setNString(1, "value");
+
+ ResultSet rset = stmt.executeQuery();
+ Assert.assertNotNull(rset);
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Should have a row
+ Assert.assertTrue(rset.next());
+ Assert.assertTrue(rset.isFirst());
+ Assert.assertEquals(1, rset.getRow());
+
+ // Should be no further rows
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(rset.isClosed());
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
+
+ /**
* Runs a SELECT query on a non-empty database with max rows set and checks
* that the appropriate number of rows are returned
*
@@ -794,4 +973,183 @@ public abstract class AbstractJenaConnec
conn.close();
Assert.assertTrue(conn.isClosed());
}
+
+ /**
+ * Runs a batch of operations and checks the results results
+ *
+ * @throws SQLException
+ */
+ @Test
+ public void connection_statement_batch_01() throws SQLException {
+ JenaConnection conn = this.getConnection();
+ conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ Statement stmt = conn.createStatement();
+
+ // Create and execute a batch
+ stmt.addBatch("SELECT * WHERE { ?s ?p ?o }");
+ int[] batchResults = stmt.executeBatch();
+ Assert.assertEquals(1, batchResults.length);
+
+ // Expect first result set returned to be SELECT results
+ Assert.assertEquals(batchResults[0], Statement.SUCCESS_NO_INFO);
+ ResultSet rset = stmt.getResultSet();
+ Assert.assertNotNull(rset);
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Check result set
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(stmt.isClosed());
+
+ // Expect there to be no further results
+ Assert.assertFalse(stmt.getMoreResults());
+ Assert.assertTrue(rset.isClosed()); // Should cause previous result set
+ // to be closed
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
+
+ /**
+ * Runs a batch of operations and checks the results results
+ *
+ * @throws SQLException
+ */
+ @Test
+ public void connection_statement_batch_02() throws SQLException {
+ JenaConnection conn = this.getConnection();
+ conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ Statement stmt = conn.createStatement();
+
+ // Create and execute a batch
+ stmt.addBatch("SELECT * WHERE { ?s ?p ?o }");
+ stmt.addBatch("ASK WHERE { }");
+ int[] batchResults = stmt.executeBatch();
+ Assert.assertEquals(2, batchResults.length);
+
+ // Expect first result set returned to be SELECT results
+ Assert.assertEquals(batchResults[0], Statement.SUCCESS_NO_INFO);
+ ResultSet rset = stmt.getResultSet();
+ Assert.assertNotNull(rset);
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Check result set
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(stmt.isClosed());
+
+ // Expect there to be a further ASK result set
+ Assert.assertEquals(batchResults[1], Statement.SUCCESS_NO_INFO);
+ Assert.assertTrue(stmt.getMoreResults());
+ Assert.assertTrue(rset.isClosed()); // Should close the previous result
+ // set
+ rset = stmt.getResultSet();
+ Assert.assertNotNull(rset);
+
+ // Check result set metadata
+ checkAskMetadata(rset);
+
+ // Check result set
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+ Assert.assertTrue(rset.next());
+ Assert.assertTrue(rset.getBoolean(AskResultsMetadata.COLUMN_LABEL_ASK));
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
+
+ /**
+ * Runs a batch of operations and checks the results results
+ *
+ * @throws SQLException
+ */
+ @Test
+ public void connection_statement_batch_03() throws SQLException {
+ JenaConnection conn = this.getConnection();
+ conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+
+ // This test needs scroll insensitive result sets as otherwise the first
+ // SELECT may see data from the update if the underlying connection does
+ // not have suitable transaction isolation
+ Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
+
+ // Create and execute a batch
+ stmt.addBatch("SELECT * WHERE { ?s ?p ?o }");
+ if (this.usesNamedGraphAsDefault()) {
+ stmt.addBatch("INSERT DATA { GRAPH <" + this.getDefaultGraphName() + "> { <http://x> <http://y> <http://z> } }");
+ } else {
+ stmt.addBatch("INSERT DATA { <http://x> <http://y> <http://z> }");
+ }
+ stmt.addBatch("SELECT * WHERE { ?s ?p ?o }");
+ int[] batchResults = stmt.executeBatch();
+ Assert.assertEquals(3, batchResults.length);
+
+ // Expect first result set returned to be SELECT results
+ Assert.assertEquals(batchResults[0], Statement.SUCCESS_NO_INFO);
+ ResultSet rset = stmt.getResultSet();
+ Assert.assertNotNull(rset);
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Check result set
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+ Assert.assertFalse(stmt.isClosed());
+
+ // Next results should be for the update so should return null for the
+ // result set
+ Assert.assertTrue(batchResults[1] >= 0);
+ Assert.assertTrue(stmt.getMoreResults());
+ rset = stmt.getResultSet();
+ Assert.assertNull(rset);
+
+ // Expect there to be a further SELECT result set
+ Assert.assertEquals(batchResults[2], Statement.SUCCESS_NO_INFO);
+ Assert.assertTrue(stmt.getMoreResults());
+ rset = stmt.getResultSet();
+ Assert.assertNotNull(rset);
+
+ // Check result set metadata
+ checkSelectMetadata(rset, 3);
+
+ // Check result set
+ Assert.assertFalse(rset.isClosed());
+ Assert.assertTrue(rset.isBeforeFirst());
+ Assert.assertTrue(rset.next()); // Should now be a row because previous
+ // command in batch inserted data
+ Assert.assertFalse(rset.next());
+ Assert.assertTrue(rset.isAfterLast());
+
+ // Close things
+ rset.close();
+ Assert.assertTrue(rset.isClosed());
+ stmt.close();
+ Assert.assertTrue(stmt.isClosed());
+ conn.close();
+ Assert.assertTrue(conn.isClosed());
+ }
}
Modified: jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/connections/RemoteEndpointConnection.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/connections/RemoteEndpointConnection.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/connections/RemoteEndpointConnection.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/connections/RemoteEndpointConnection.java Wed May 1 21:05:13 2013
@@ -20,7 +20,6 @@ package org.apache.jena.jdbc.remote.conn
import java.sql.Connection;
import java.sql.DatabaseMetaData;
-import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
@@ -178,22 +177,22 @@ public class RemoteEndpointConnection ex
throws SQLException {
if (this.isClosed())
throw new SQLException("Cannot create a statement after the connection was closed");
- if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
- throw new SQLException("Remote endpoint backed connection currently only support forward-only result sets");
+ if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)
+ throw new SQLException("Remote endpoint backed connection do not support scroll sensitive result sets");
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
throw new SQLException("Remote endpoint backed connections only support read-only result sets");
- return new RemoteEndpointStatement(this, this.username, this.password, ResultSet.FETCH_FORWARD, 0, resultSetHoldability);
+ return new RemoteEndpointStatement(this, this.username, this.password, resultSetType, ResultSet.FETCH_FORWARD, 0, resultSetHoldability);
}
@Override
protected JenaPreparedStatement createPreparedStatementInternal(String sparql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
if (this.isClosed())
throw new SQLException("Cannot create a statement after the connection was closed");
- if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
- throw new SQLException("Remote endpoint backed connection currently only support forward-only result sets");
+ if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)
+ throw new SQLException("Remote endpoint backed connection do not support scroll sensitive result sets");
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
throw new SQLException("Remote endpoint backed connections only support read-only result sets");
- return new RemoteEndpointPreparedStatement(sparql, this, this.username, this.password, ResultSet.FETCH_FORWARD, 0, resultSetHoldability);
+ return new RemoteEndpointPreparedStatement(sparql, this, this.username, this.password, resultSetType, ResultSet.FETCH_FORWARD, 0, resultSetHoldability);
}
@Override
@@ -212,37 +211,6 @@ public class RemoteEndpointConnection ex
}
@Override
- public PreparedStatement prepareStatement(String sql) throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
- throws SQLException {
- throw new SQLFeatureNotSupportedException("Prepared statements are not yet supported for Jena JDBC");
- }
-
- @Override
public void setReadOnly(boolean readOnly) throws SQLException {
if (this.isClosed())
throw new SQLException("Cannot set read-only mode on a closed connection");
Modified: jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointPreparedStatement.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointPreparedStatement.java?rev=1478189&r1=1478188&r2=1478189&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointPreparedStatement.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/statements/RemoteEndpointPreparedStatement.java Wed May 1 21:05:13 2013
@@ -55,20 +55,22 @@ public class RemoteEndpointPreparedState
* Thrown if there is an error with the statement parameters
*/
public RemoteEndpointPreparedStatement(String sparql, RemoteEndpointConnection connection) throws SQLException {
- this(sparql, connection, null, null, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY);
+ this(sparql, connection, null, null, DEFAULT_TYPE, DEFAULT_FETCH_DIRECTION, DEFAULT_FETCH_SIZE, DEFAULT_HOLDABILITY);
}
/**
* Creates a new statement
*
* @param sparql
- * SPARQL command
+ * SPARQL command
* @param connection
* Connection
* @param username
* Username for HTTP Basic Authentication
* @param password
* Username for HTTP Basic Authentication
+ * @param type
+ * Result Set type for result sets produced by this statement
* @param fetchDir
* Fetch Direction
* @param fetchSize
@@ -79,9 +81,9 @@ public class RemoteEndpointPreparedState
* Thrown if there is an error with the statement parameters
*
*/
- public RemoteEndpointPreparedStatement(String sparql, RemoteEndpointConnection connection, String username, char[] password, int fetchDir,
- int fetchSize, int holdability) throws SQLException {
- super(sparql, connection, fetchDir, fetchSize, holdability, false, Connection.TRANSACTION_NONE);
+ public RemoteEndpointPreparedStatement(String sparql, RemoteEndpointConnection connection, String username, char[] password,
+ int type, int fetchDir, int fetchSize, int holdability) throws SQLException {
+ super(sparql, connection, type, fetchDir, fetchSize, holdability, false, Connection.TRANSACTION_NONE);
this.remoteConn = connection;
this.username = username;
this.password = password;