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/04/04 00:01:28 UTC

svn commit: r1464215 [1/3] - in /jena/Experimental/jena-jdbc: jena-jdbc-core/src/main/java/org/apache/jena/jdbc/ jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/ jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/ jena-jdbc-core/s...

Author: rvesse
Date: Wed Apr  3 22:01:26 2013
New Revision: 1464215

URL: http://svn.apache.org/r1464215
Log:
Plumb in transactions properly, rename stuff to remove unecessary junk from class names

Added:
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaDriver.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/metadata/JenaMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/JenaResultSet.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/metadata/JenaResultsMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/AbstractJenaDriverTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/connections/AbstractJenaConnectionTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/TestMemDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/connections/
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/connections/DebugMemConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/connections/TestDatasetConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/results/
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/results/AbstractMemResultSetTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/results/TestResultSets.java
Removed:
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaJdbcDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaJdbcConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/JenaJdbcMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/JenaJdbcResultSet.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/metadata/JenaJdbcResultsMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/AbstractJenaJdbcConnectionTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/AbstractJenaJdbcDriverTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/AbstractMemResultSetTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/DebugMemConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/TestJenaJdbcDatasetConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/TestJenaJdbcMemDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/test/java/org/apache/jena/jdbc/mem/TestResultSets.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/metadata/DatasetMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/AskResults.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/QueryExecutionResults.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/metadata/AskResultsMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/metadata/SelectResultsMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/metadata/TripleResultsMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/statements/JenaJdbcStatement.java
    jena/Experimental/jena-jdbc/jena-jdbc-core/src/test/java/org/apache/jena/jdbc/results/AbstractResultSetTests.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/main/java/org/apache/jena/jdbc/mem/MemDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-mem/src/main/java/org/apache/jena/jdbc/mem/connections/MemConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/main/java/org/apache/jena/jdbc/remote/RemoteEndpointDriver.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/metadata/RemoteEndpointMetadata.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/test/java/org/apache/jena/jdbc/remote/TestRemoteEndpointConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/test/java/org/apache/jena/jdbc/remote/TestRemoteEndpointDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-remote/src/test/java/org/apache/jena/jdbc/remote/results/TestRemoteEndpointResults.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/pom.xml
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/main/java/org/apache/jena/jdbc/tdb/TDBDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/main/java/org/apache/jena/jdbc/tdb/connections/TDBConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/DebugTdbConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/TestJenaJdbcTdbDiskConnection.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/TestJenaJdbcTdbDriver.java
    jena/Experimental/jena-jdbc/jena-jdbc-driver-tdb/src/test/java/org/apache/jena/jdbc/tdb/TestJenaJdbcTdbMemConnection.java

Added: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaDriver.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaDriver.java?rev=1464215&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaDriver.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/JenaDriver.java Wed Apr  3 22:01:26 2013
@@ -0,0 +1,201 @@
+/**
+ * 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;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+/**
+ * Abstract implementation of a Jena JDBC driver
+ * 
+ */
+public abstract class JenaDriver implements Driver {
+
+    /**
+     * Constant for the primary Jena JDBC Driver prefix, implementations supply
+     * an additional prefix which will form the next portion of the JDBC URL
+     */
+    public static final String DRIVER_PREFIX = "jdbc:jena:";
+
+    private int majorVer, minorVer;
+    private String implPrefix;
+
+    /**
+     * Creates a new driver
+     * 
+     * @param majorVer
+     *            Major Version
+     * @param minorVer
+     *            Minor Version
+     * @param prefix
+     *            Implementation specific prefix
+     */
+    public JenaDriver(int majorVer, int minorVer, String prefix) {
+        this.majorVer = majorVer;
+        this.minorVer = minorVer;
+
+        if (prefix == null)
+            throw new IllegalArgumentException("Implementation specific prefix cannot be null");
+        if (!prefix.endsWith(":"))
+            throw new IllegalArgumentException("Implementation specific prefix must end with a :");
+        // Validate that implPrefix is a valid scheme i.e. [A-Za-z\d\-_]+
+        if (!prefix.matches("[A-Za-z\\d\\-_]+:"))
+            throw new IllegalArgumentException(
+                    "Implementation specific prefix must conform to the regular expression [A-Za-z\\d\\-_]+:");
+        this.implPrefix = prefix;
+    }
+
+    public boolean acceptsURL(String url) throws SQLException {
+        if (url.startsWith(DRIVER_PREFIX + this.implPrefix)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public Connection connect(String url, Properties props) throws SQLException {
+        // Create new empty properties if necessary
+        Properties ps = new Properties();
+
+        // Parse out the key value pairs from the connection URL
+        url = url.substring(DRIVER_PREFIX.length() + this.implPrefix.length());
+        String[] kvps = url.split("&|;");
+        for (int i = 0; i < kvps.length; i++) {
+            String kvp = kvps[i];
+            if (kvp.length() == 0)
+                continue;
+
+            // Try to split into key and value
+            String key, value;
+            if (kvp.contains("=")) {
+                String[] temp = kvp.split("=", 2);
+                key = temp[0];
+                value = temp[1];
+            } else {
+                key = kvp;
+                value = null;
+            }
+
+            // All keys are normalized to lower case using the English Locale
+            key = key.toLowerCase(Locale.ENGLISH);
+
+            // Put into properties appropriately
+            if (!ps.containsKey(key)) {
+                // Doesn't yet exist, add a string/list as appropriate
+                if (this.allowsMultipleValues(key)) {
+                    List<String> values = new ArrayList<String>();
+                    values.add(value);
+                    ps.put(key, values);
+                } else {
+                    ps.put(key, value);
+                }
+            } else if (this.allowsMultipleValues(key)) {
+                // If it allows multiple values append to those existing
+                Object currValue = ps.get(key);
+                if (currValue instanceof List<?>) {
+                    // Can just append to existing list
+                    ((List<Object>) currValue).add(value);
+                } else {
+                    // Convert to list
+                    List<String> values = new ArrayList<String>();
+                    values.add(currValue.toString());
+                    values.add(value);
+                    ps.put(key, values);
+                }
+            }
+        }
+
+        // Overwrite connection URL parameters with code provided parameters
+        // if applicable
+        if (props != null) {
+            // Copy across normalizing keys to lower case in the English Locale
+            for (Entry<Object, Object> e : props.entrySet()) {
+                ps.put(e.getKey().toString().toLowerCase(Locale.ENGLISH), e.getValue());
+            }
+        }
+
+        // Try to create the connection
+        return this.connect(ps);
+    }
+
+    /**
+     * Gets whether a parameter is allowed to have multiple values
+     * 
+     * @param key
+     *            Key
+     * @return True if multiple values are allowed, false otherwise
+     */
+    protected boolean allowsMultipleValues(String key) {
+        return false;
+    }
+
+    /**
+     * Method which derived classes must implement to create their actual
+     * connections
+     * <p>
+     * The driver will already have parsed the connection URL to extract out any
+     * connection parameters and has added them to the parameters provided in
+     * the Properties object. Parameters which the implementation has indicated
+     * allow multiple values will be present as {@link List} in the properties,
+     * all other parameters will be either strings or the original values as
+     * injected by the calling code. Properties specified in the
+     * {@link Properties} object by the calling code have precedence over the
+     * connection URL parameters.
+     * </p>
+     * 
+     * @param props
+     *            Properties
+     * @return Connection
+     * @throws SQLException
+     *             Thrown if a connection cannot be created for any reason
+     */
+    protected abstract Connection connect(Properties props) throws SQLException;
+
+    public int getMajorVersion() {
+        return this.minorVer;
+    }
+
+    public int getMinorVersion() {
+        return this.majorVer;
+    }
+
+    public DriverPropertyInfo[] getPropertyInfo(String arg0, Properties arg1) throws SQLException {
+        return new DriverPropertyInfo[0];
+    }
+
+    /**
+     * Returns that a Jena JDBC driver is not JDBC compliant since strict JDBC
+     * compliance requires support for SQL-92 and since we are using SPARQL we
+     * don't meet that criteria
+     */
+    public final boolean jdbcCompliant() {
+        // This has to be false since we are not JDBC compliant in that
+        // we use SPARQL in place of SQL-92
+        return false;
+    }
+
+}

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=1464215&r1=1464214&r2=1464215&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 Apr  3 22:01:26 2013
@@ -31,7 +31,7 @@ import com.hp.hpl.jena.query.Dataset;
  * Represents a connection to a {@link Dataset} instance
  * 
  */
-public abstract class DatasetConnection extends JenaJdbcConnection {
+public abstract class DatasetConnection extends JenaConnection {
 
     protected Dataset ds;
     private boolean readonly = false;
@@ -75,7 +75,7 @@ public abstract class DatasetConnection 
             throws SQLException {
         if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) throw new SQLException("Dataset backed connections currently only supports forward-only result sets");
         if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) throw new SQLException("Database backed connections currently only supports read-only result sets");
-        return new DatasetStatement(this);
+        return new DatasetStatement(this, ResultSet.FETCH_FORWARD, 0, resultSetHoldability, this.getAutoCommit(), this.getTransactionIsolation());
     }
 
     @Override
@@ -135,9 +135,11 @@ public abstract class DatasetConnection 
     protected void checkTransactionIsolation(int level) throws SQLException {
         switch (level) {
         case TRANSACTION_NONE:
-        case TRANSACTION_SERIALIZABLE:
-            // No transactions or serializable are the only supported transaction levels
             return;
+        case TRANSACTION_SERIALIZABLE:
+            // Serializable is supported if the dataset supports transactions
+            if (this.ds.supportsTransactions()) return;
+            // Otherwise we'll drop through and throw the error
         default:
             throw new SQLException(String.format("The Transaction level %d is not supported by this connection", level));
         }

Added: 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=1464215&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/connections/JenaConnection.java Wed Apr  3 22:01:26 2013
@@ -0,0 +1,406 @@
+/**
+ * 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.connections;
+
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLRecoverableException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.jena.jdbc.metadata.JenaMetadata;
+
+/**
+ * Abstract base implementation of a Jena JDBC connection
+ * 
+ */
+public abstract class JenaConnection implements Connection {
+
+    /**
+     * Constant for default cursor holdability for Jena JDBC connections
+     */
+    public static final int DEFAULT_HOLDABILITY = ResultSet.CLOSE_CURSORS_AT_COMMIT;
+    /**
+     * Constant for default auto-commit for Jena JDBC connections
+     */
+    public final static boolean DEFAULT_AUTO_COMMIT = true;
+    /**
+     * Constant for default transaction isolation level for Jena JDBC
+     * connections
+     */
+    public final static int DEFAULT_ISOLATION_LEVEL = TRANSACTION_NONE;
+
+    private Properties clientInfo = new Properties();
+    private int holdability = DEFAULT_HOLDABILITY;
+    private SQLWarning warnings = null;
+    private boolean autoCommit = DEFAULT_AUTO_COMMIT;
+    private int isolationLevel = DEFAULT_ISOLATION_LEVEL;
+    private List<Statement> statements = new ArrayList<Statement>();
+
+    /**
+     * Creates a new connection
+     * 
+     * @throws SQLException
+     *             Thrown if the arguments are invalid
+     */
+    public JenaConnection() throws SQLException {
+        this(DEFAULT_HOLDABILITY);
+    }
+
+    /**
+     * Creates a new connection
+     * 
+     * @param holdability
+     *            Cursor holdability
+     * @throws SQLException
+     *             Thrown if the arguments are invalid
+     */
+    public JenaConnection(int holdability) throws SQLException {
+        this.checkHoldability(holdability);
+        this.holdability = holdability;
+    }
+
+    public boolean isWrapperFor(Class<?> arg0) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public <T> T unwrap(Class<T> arg0) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public void clearWarnings() throws SQLException {
+        this.warnings = null;
+    }
+
+    public final void close() throws SQLException {
+        try {
+            // Close any open statements
+            this.closeStatements();
+        } finally {
+            this.closeInternal();
+        }
+    }
+
+    private void closeStatements() throws SQLException {
+
+        for (Statement stmt : this.statements) {
+            stmt.close();
+        }
+        this.statements.clear();
+    }
+
+    protected abstract void closeInternal() throws SQLException;
+
+    public void commit() throws SQLException {
+        if (this.isClosed())
+            throw new SQLException("Cannot commit on a closed connection");
+        try {
+            // Get the implementation to do the actual commit
+            this.commitInternal();
+
+            // If applicable close cursors
+            if (this.holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
+                this.closeStatements();
+            }
+        } catch (SQLException e) {
+            // Throw as-is
+            throw e;
+        } catch (Exception e) {
+            // Wrap as SQLException
+            throw new SQLException("Unexpected error committing transaction", e);
+        }
+    }
+
+    protected abstract void commitInternal() throws SQLException;
+
+    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public Blob createBlob() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public Clob createClob() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public NClob createNClob() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public SQLXML createSQLXML() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public final Statement createStatement() throws SQLException {
+        if (this.isClosed())
+            throw new SQLException("Cannot create a statement after the connection was closed");
+        return this.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+    }
+
+    public final Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+        if (this.isClosed())
+            throw new SQLException("Cannot create a statement after the connection was closed");
+        return this.createStatement(resultSetType, resultSetConcurrency, this.getHoldability());
+    }
+
+    public final Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException {
+        if (this.isClosed())
+            throw new SQLException("Cannot create a statement after the connection was closed");
+        Statement stmt = this.createStatementInternal(resultSetType, resultSetConcurrency, resultSetHoldability);
+        this.statements.add(stmt);
+        return stmt;
+    }
+
+    protected abstract Statement createStatementInternal(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException;
+
+    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public boolean getAutoCommit() throws SQLException {
+        return this.autoCommit;
+    }
+
+    public String getCatalog() throws SQLException {
+        return JenaMetadata.DEFAULT_CATALOG;
+    }
+
+    public Properties getClientInfo() throws SQLException {
+        return this.clientInfo;
+    }
+
+    public String getClientInfo(String name) throws SQLException {
+        return this.clientInfo.getProperty(name);
+    }
+
+    public int getHoldability() throws SQLException {
+        return this.holdability;
+    }
+
+    public abstract DatabaseMetaData getMetaData() throws SQLException;
+
+    public int getTransactionIsolation() throws SQLException {
+        return this.isolationLevel;
+    }
+
+    public Map<String, Class<?>> getTypeMap() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public SQLWarning getWarnings() throws SQLException {
+        return this.warnings;
+    }
+
+    public abstract boolean isClosed() throws SQLException;
+
+    public abstract boolean isReadOnly() throws SQLException;
+
+    public abstract boolean isValid(int timeout) throws SQLException;
+
+    public String nativeSQL(String sql) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public CallableStatement prepareCall(String sql) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public abstract PreparedStatement prepareStatement(String sql) throws SQLException;
+
+    public abstract PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
+
+    public abstract PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException;
+
+    public abstract PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException;
+
+    public abstract PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
+            throws SQLException;
+
+    public abstract PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
+            int resultSetHoldability) throws SQLException;
+
+    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public void rollback() throws SQLException {
+        if (this.isClosed())
+            throw new SQLException("Cannot rollback on a closed connection");
+        try {
+            // Get the implementation to do the actual rollback
+            this.rollbackInternal();
+            
+            // Close any open statements if applicable
+            if (this.holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
+                this.closeStatements();
+            }
+        } catch (SQLException e) {
+            // Throw as-is
+            throw e;
+        } catch (Exception e) {
+            throw new SQLException("Unexpected error rolling back transaction", e);
+        }
+    }
+
+    protected abstract void rollbackInternal() throws SQLException;
+
+    public void rollback(Savepoint savepoint) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public void setAutoCommit(boolean autoCommit) throws SQLException {
+        this.autoCommit = autoCommit;
+    }
+
+    public void setCatalog(String catalog) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public void setClientInfo(Properties properties) throws SQLClientInfoException {
+        this.clientInfo = properties;
+    }
+
+    public void setClientInfo(String name, String value) throws SQLClientInfoException {
+        this.clientInfo.put(name, value);
+    }
+
+    public void setHoldability(int holdability) throws SQLException {
+        this.checkHoldability(holdability);
+        this.holdability = holdability;
+    }
+
+    /**
+     * Helper method that checks whether the given holdability setting is valid,
+     * throws an error if it is not
+     * 
+     * @param h
+     *            Holdability Setting
+     * @throws SQLException
+     *             Thrown if the setting is not valid
+     */
+    protected void checkHoldability(int h) throws SQLException {
+        switch (h) {
+        case ResultSet.CLOSE_CURSORS_AT_COMMIT:
+        case ResultSet.HOLD_CURSORS_OVER_COMMIT:
+            return;
+        default:
+            throw new SQLRecoverableException(String.format("%d is not a valid holdability setting", h));
+        }
+    }
+
+    public abstract void setReadOnly(boolean readOnly) throws SQLException;
+
+    public Savepoint setSavepoint() throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public Savepoint setSavepoint(String name) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public void setTransactionIsolation(int level) throws SQLException {
+        this.checkTransactionIsolation(level);
+        this.isolationLevel = level;
+    }
+
+    /**
+     * Helper method which checks that a transaction isolation level is valid,
+     * should throw an exception if the given level is not valid for the
+     * connection
+     * 
+     * @param level
+     *            Isolation Level
+     * @throws SQLException
+     *             Thrown if the isolation level is not valid
+     */
+    protected abstract void checkTransactionIsolation(int level) throws SQLException;
+
+    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    /**
+     * Helper method that derived classes may use to set warnings
+     * 
+     * @param warning
+     *            Warning
+     */
+    protected void setWarning(SQLWarning warning) {
+        if (this.warnings == null) {
+            this.warnings = warning;
+        } else {
+            // Chain with existing warnings
+            warning.setNextWarning(this.warnings);
+            this.warnings = warning;
+        }
+    }
+
+    /**
+     * Helper method that derived classes may use to set warnings
+     * 
+     * @param warning
+     *            Warning
+     */
+    protected void setWarning(String warning) {
+        this.setWarning(new SQLWarning(warning));
+    }
+
+    /**
+     * Helper method that derived classes may use to set warnings
+     * 
+     * @param warning
+     *            Warning
+     * @param cause
+     *            Cause
+     */
+    protected void setWarning(String warning, Throwable cause) {
+        this.setWarning(new SQLWarning(warning, cause));
+    }
+
+}

Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/DatasetMetadata.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/DatasetMetadata.java?rev=1464215&r1=1464214&r2=1464215&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/DatasetMetadata.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/DatasetMetadata.java Wed Apr  3 22:01:26 2013
@@ -26,7 +26,7 @@ import org.apache.jena.jdbc.connections.
  * Abstract implementation of metadata for dataset connections
  *
  */
-public abstract class DatasetMetadata extends JenaJdbcMetadata {
+public abstract class DatasetMetadata extends JenaMetadata {
 
     /**
      * Creates new metadata

Added: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/JenaMetadata.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/JenaMetadata.java?rev=1464215&view=auto
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/JenaMetadata.java (added)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/metadata/JenaMetadata.java Wed Apr  3 22:01:26 2013
@@ -0,0 +1,944 @@
+/**
+ * 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.metadata;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.RowIdLifetime;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+
+import org.apache.jena.jdbc.connections.JenaConnection;
+
+/**
+ * Database metadata for Jena JDBC connections
+ */
+public abstract class JenaMetadata implements DatabaseMetaData {
+
+    /**
+     * Constant for the term used for catalogues
+     */
+    public static final String CATALOG_TERM = "RDF Store";
+
+    /**
+     * Constant for the term used for schemas
+     */
+    public static final String SCHEMA_TERM = "Dataset";
+
+    /**
+     * Constant for the default catalog which is the only catalog we report as
+     * existing by default
+     */
+    public static final String DEFAULT_CATALOG = "RDF";
+
+    /**
+     * Constant for the default schema which is the only schema we report as
+     * existing by default
+     */
+    public static final String DEFAULT_SCHEMA = "Dataset";
+
+    protected static final int NO_LIMIT = 0;
+
+    protected static final int UNKNOWN_LIMIT = 0;
+
+    private JenaConnection connection;
+
+    /**
+     * Creates new connection metadata
+     * 
+     * @param connection
+     *            Connection
+     * @throws SQLException
+     */
+    public JenaMetadata(JenaConnection connection) throws SQLException {
+        if (connection == null)
+            throw new SQLException("Connection cannot be null");
+        this.connection = connection;
+    }
+
+    public boolean isWrapperFor(Class<?> arg0) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public <T> T unwrap(Class<T> arg0) throws SQLException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    public boolean allProceduresAreCallable() throws SQLException {
+        // Callable procedures not supported in SPARQL
+        return false;
+    }
+
+    public boolean allTablesAreSelectable() throws SQLException {
+        // There is a single table in RDF (the quads table) and it is selectable
+        return true;
+    }
+
+    public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
+        // Auto-commit failure does not close all result sets
+        return false;
+    }
+
+    public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
+        // SPARQL Update causes a commit by default for non-transactional
+        // connections
+        return true;
+    }
+
+    public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
+        // SPARQL Update is not ignored for non-transactional connections
+        return false;
+    }
+
+    public boolean deletesAreDetected(int arg0) throws SQLException {
+        // Since modification of result sets is not supported we can report
+        // true for the ability to detect row deletes
+        return true;
+    }
+
+    public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
+        // There is no max row size in RDF/SPARQL
+        return true;
+    }
+
+    public ResultSet getAttributes(String arg0, String arg1, String arg2, String arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getBestRowIdentifier(String arg0, String arg1, String arg2, int arg3, boolean arg4) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getCatalogSeparator() throws SQLException {
+        // Use a . since that's what SQL would use AFAIK
+        return ".";
+    }
+
+    public String getCatalogTerm() throws SQLException {
+        return CATALOG_TERM;
+    }
+
+    public ResultSet getCatalogs() throws SQLException {
+        // TODO Requires a result set implementation that can be appropriately
+        // configured
+
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getClientInfoProperties() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getColumnPrivileges(String arg0, String arg1, String arg2, String arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getColumns(String arg0, String arg1, String arg2, String arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public final Connection getConnection() throws SQLException {
+        return this.connection;
+    }
+
+    public ResultSet getCrossReference(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5)
+            throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public abstract int getDatabaseMajorVersion() throws SQLException;
+
+    public abstract int getDatabaseMinorVersion() throws SQLException;
+
+    public abstract String getDatabaseProductName() throws SQLException;
+
+    public abstract String getDatabaseProductVersion() throws SQLException;
+
+    public int getDefaultTransactionIsolation() throws SQLException {
+        return Connection.TRANSACTION_NONE;
+    }
+
+    public abstract int getDriverMajorVersion();
+
+    public abstract int getDriverMinorVersion();
+
+    public abstract String getDriverName() throws SQLException;
+
+    public abstract String getDriverVersion() throws SQLException;
+
+    public ResultSet getExportedKeys(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getExtraNameCharacters() throws SQLException {
+        // Since SPARQL doesn't really have a notion of identifiers like SQL
+        // does
+        // we return that there are no extra name characters
+        return "";
+    }
+
+    public ResultSet getFunctionColumns(String arg0, String arg1, String arg2, String arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getFunctions(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getIdentifierQuoteString() throws SQLException {
+        // Not supported in SPARQL so return space per the JDBC javadoc
+        return " ";
+    }
+
+    public ResultSet getImportedKeys(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getIndexInfo(String arg0, String arg1, String arg2, boolean arg3, boolean arg4) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public final int getJDBCMajorVersion() throws SQLException {
+        return 4;
+    }
+
+    public final int getJDBCMinorVersion() throws SQLException {
+        return 0;
+    }
+
+    public int getMaxBinaryLiteralLength() throws SQLException {
+        // No limit on RDF term sizes
+        return NO_LIMIT;
+    }
+
+    public int getMaxCatalogNameLength() throws SQLException {
+        // No limit on catalog name lengths because we don't
+        // really support catalogs
+        return NO_LIMIT;
+    }
+
+    public int getMaxCharLiteralLength() throws SQLException {
+        // No limit on RDF term sizes
+        return NO_LIMIT;
+    }
+
+    public int getMaxColumnNameLength() throws SQLException {
+        // No limit on column name lengths
+        return NO_LIMIT;
+    }
+
+    public int getMaxColumnsInGroupBy() throws SQLException {
+        // SPARQL allows arbitrarily many columns in a GROUP BY
+        return NO_LIMIT;
+    }
+
+    public int getMaxColumnsInIndex() throws SQLException {
+        // RDF stores typically index on up to 3 columns since there are only 4
+        // columns
+        return 3;
+    }
+
+    public int getMaxColumnsInOrderBy() throws SQLException {
+        // SPARQL allows arbitrarily many columns in ORDER BY
+        return NO_LIMIT;
+    }
+
+    public int getMaxColumnsInSelect() throws SQLException {
+        // SPARQL allows arbitrarily many columns in SELECT clause
+        return NO_LIMIT;
+    }
+
+    public int getMaxColumnsInTable() throws SQLException {
+        // RDF stores have up to 4 columns
+        return 4;
+    }
+
+    public int getMaxConnections() throws SQLException {
+        // Max connections will typically be unlimited
+        return NO_LIMIT;
+    }
+
+    public int getMaxCursorNameLength() throws SQLException {
+        // Named cursors aren't supported so there is no limit
+        return UNKNOWN_LIMIT;
+    }
+
+    public int getMaxIndexLength() throws SQLException {
+        // RDF stores typically have no limit on index size, they are as big as
+        // they need to be
+        return NO_LIMIT;
+    }
+
+    public int getMaxProcedureNameLength() throws SQLException {
+        // Procedures aren't supported so unknown
+        return UNKNOWN_LIMIT;
+    }
+
+    public int getMaxRowSize() throws SQLException {
+        // No limit on triple size
+        return NO_LIMIT;
+    }
+
+    public int getMaxSchemaNameLength() throws SQLException {
+        // We don't really support schemas so there is no limit
+        return NO_LIMIT;
+    }
+
+    public int getMaxStatementLength() throws SQLException {
+        // SPARQL Queries/Updates may be arbitrarily large
+        return NO_LIMIT;
+    }
+
+    public int getMaxStatements() throws SQLException {
+        // We don't impose any limit on this
+        return NO_LIMIT;
+    }
+
+    public int getMaxTableNameLength() throws SQLException {
+        // We don't support tables so there is no limit
+        return NO_LIMIT;
+    }
+
+    public int getMaxTablesInSelect() throws SQLException {
+        // No limit
+        return NO_LIMIT;
+    }
+
+    public int getMaxUserNameLength() throws SQLException {
+        // Authentication is an implementation specific detail so unknown
+        return UNKNOWN_LIMIT;
+    }
+
+    public String getNumericFunctions() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getPrimaryKeys(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getProcedureColumns(String arg0, String arg1, String arg2, String arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getProcedureTerm() throws SQLException {
+        // Not supported
+        return null;
+    }
+
+    public ResultSet getProcedures(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public int getResultSetHoldability() throws SQLException {
+        return JenaConnection.DEFAULT_HOLDABILITY;
+    }
+
+    public RowIdLifetime getRowIdLifetime() throws SQLException {
+        // Not supported
+        return RowIdLifetime.ROWID_UNSUPPORTED;
+    }
+
+    public String getSQLKeywords() throws SQLException {
+        // TODO Use http://developer.mimer.com/validator/sql-reserved-words.tml
+        // as a reference to implement this
+        return null;
+    }
+
+    public int getSQLStateType() throws SQLException {
+        return sqlStateXOpen;
+    }
+
+    public String getSchemaTerm() throws SQLException {
+        return SCHEMA_TERM;
+    }
+
+    public ResultSet getSchemas() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getSchemas(String arg0, String arg1) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getSearchStringEscape() throws SQLException {
+        // Does not apply to SPARQL
+        return "";
+    }
+
+    public String getStringFunctions() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getSuperTables(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getSuperTypes(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getSystemFunctions() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getTablePrivileges(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getTableTypes() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getTables(String arg0, String arg1, String arg2, String[] arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getTimeDateFunctions() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getTypeInfo() throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ResultSet getUDTs(String arg0, String arg1, String arg2, int[] arg3) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public abstract String getURL() throws SQLException;
+
+    public String getUserName() throws SQLException {
+        // No authentication used by default
+        return null;
+    }
+
+    public ResultSet getVersionColumns(String arg0, String arg1, String arg2) throws SQLException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean insertsAreDetected(int arg0) throws SQLException {
+        // We can't detect inserts that happen while streaming results
+        return false;
+    }
+
+    public boolean isCatalogAtStart() throws SQLException {
+        // We don't really support catalogs so we'll say yes
+        return true;
+    }
+
+    public boolean isReadOnly() throws SQLException {
+        return this.connection.isReadOnly();
+    }
+
+    public boolean locatorsUpdateCopy() throws SQLException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public boolean nullPlusNonNullIsNull() throws SQLException {
+        // Concatenating nulls (i.e. unbound/type error) in SPARQL results
+        // leads to nulls
+        return true;
+    }
+
+    public boolean nullsAreSortedAtEnd() throws SQLException {
+        // SPARQL sort order puts nulls (i.e. unbound) first
+        return false;
+    }
+
+    public boolean nullsAreSortedAtStart() throws SQLException {
+        // SPARQL sort order puts nulls (i.e. unbound) first
+        return true;
+    }
+
+    public boolean nullsAreSortedHigh() throws SQLException {
+        // SPARQL sort order puts nulls (i.e. unbound) first
+        return false;
+    }
+
+    public boolean nullsAreSortedLow() throws SQLException {
+        // SPARQL sort order puts nulls (i.e. unbound) first
+        return true;
+    }
+
+    public boolean othersDeletesAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see deletes from
+        // others depending on the underlying implementation
+        return true;
+    }
+
+    public boolean othersInsertsAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see inserts from
+        // others depending on the underlying implementation
+        return true;
+    }
+
+    public boolean othersUpdatesAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see updates from
+        // others depending on the underlying implementation
+        return true;
+    }
+
+    public boolean ownDeletesAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see deletes from
+        // ourselves depending on the underlying implementation
+        return true;
+    }
+
+    public boolean ownInsertsAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see inserts from
+        // ourselves depending on the underlying implementation
+        return true;
+    }
+
+    public boolean ownUpdatesAreVisible(int arg0) throws SQLException {
+        // Since results are streamed it may be possible to see deletes from
+        // others depending on the underlying implementation
+        return true;
+    }
+
+    public boolean storesLowerCaseIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean storesMixedCaseIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean storesUpperCaseIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
+        // We don't support identifiers in the way that JDBC means so we say
+        // false
+        return false;
+    }
+
+    public boolean supportsANSI92EntryLevelSQL() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsANSI92FullSQL() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsANSI92IntermediateSQL() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsAlterTableWithAddColumn() throws SQLException {
+        // Schema alteration is not supported
+        return false;
+    }
+
+    public boolean supportsAlterTableWithDropColumn() throws SQLException {
+        // Schema alteration is not supported
+        return false;
+    }
+
+    public boolean supportsBatchUpdates() throws SQLException {
+        // Batch updates are implemented
+        return true;
+    }
+
+    public boolean supportsCatalogsInDataManipulation() throws SQLException {
+        // We don't really support catalogs so using them in SPARQL Update is
+        // not permitted
+        return false;
+    }
+
+    public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
+        // Custom indexes are not supported
+        return false;
+    }
+
+    public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
+        // SPARQL has no privilege definition statements
+        return false;
+    }
+
+    public boolean supportsCatalogsInProcedureCalls() throws SQLException {
+        // SPARQL has no procedure calls
+        return false;
+    }
+
+    public boolean supportsCatalogsInTableDefinitions() throws SQLException {
+        // SPARQL has no table definition statements
+        return false;
+    }
+
+    public boolean supportsColumnAliasing() throws SQLException {
+        // SPARQL requires aliasing for computed columns
+        return true;
+    }
+
+    public boolean supportsConvert() throws SQLException {
+        // JDBC convert is not supported
+        return false;
+    }
+
+    public boolean supportsConvert(int arg0, int arg1) throws SQLException {
+        // JDBC convert is not supported
+        return false;
+    }
+
+    public boolean supportsCoreSQLGrammar() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsCorrelatedSubqueries() throws SQLException {
+        // SPARQL supports sub-queries
+        return true;
+    }
+
+    public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
+        // SPARQL update may be used within a transaction
+        return true;
+    }
+
+    public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
+        // Transactions may consist only of SPARQL updates
+        return true;
+    }
+
+    public boolean supportsDifferentTableCorrelationNames() throws SQLException {
+        // We don't support tables as such so no
+        return false;
+    }
+
+    public boolean supportsExpressionsInOrderBy() throws SQLException {
+        // SPARQL allows expressions in ORDER BY
+        return true;
+    }
+
+    public boolean supportsExtendedSQLGrammar() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsFullOuterJoins() throws SQLException {
+        // SPARQL supports all sorts of joins
+        return true;
+    }
+
+    public boolean supportsGetGeneratedKeys() throws SQLException {
+        // SPARQL has no notion of auto-generated keys (you can argue that
+        // UUID() counts) but we certainly can't return them
+        return true;
+    }
+
+    public boolean supportsGroupBy() throws SQLException {
+        // SPARQL supports GROUP BY
+        return true;
+    }
+
+    public boolean supportsGroupByBeyondSelect() throws SQLException {
+        // You can GROUP BY a column that you don't select in SPARQL
+        return true;
+    }
+
+    public boolean supportsGroupByUnrelated() throws SQLException {
+        // You can GROUP BY a column that you don't select in SPARQL
+        return true;
+    }
+
+    public boolean supportsIntegrityEnhancementFacility() throws SQLException {
+        // Integrity Enhancement SQL is not supported
+        return false;
+    }
+
+    public boolean supportsLikeEscapeClause() throws SQLException {
+        // No LIKE in SPARQL
+        return false;
+    }
+
+    public boolean supportsLimitedOuterJoins() throws SQLException {
+        // SPARQL supports all kinds of joins
+        return true;
+    }
+
+    public boolean supportsMinimumSQLGrammar() throws SQLException {
+        // We don't support SQL
+        return false;
+    }
+
+    public boolean supportsMixedCaseIdentifiers() throws SQLException {
+        // We have no direct equivalent to SQL identifiers
+        return false;
+    }
+
+    public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
+        // We have no direct equivalent to SQL identifiers
+        return false;
+    }
+
+    public boolean supportsMultipleOpenResults() throws SQLException {
+        // We support multiple open results
+        return true;
+    }
+
+    public boolean supportsMultipleResultSets() throws SQLException {
+        // We don't support multiple result sets from a single execute() call,
+        // we do support this from executeBatch()
+        return false;
+    }
+
+    public boolean supportsMultipleTransactions() throws SQLException {
+        // In principle yes this is possible though exact behaviour may vary by
+        // underlying implementation
+        return true;
+    }
+
+    public boolean supportsNamedParameters() throws SQLException {
+        // We don't support callable statements
+        return false;
+    }
+
+    public boolean supportsNonNullableColumns() throws SQLException {
+        // All columns in a RDF store are non-nullable
+        return true;
+    }
+
+    public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
+        // Cursors may be closed depending on the type of commit
+        return false;
+    }
+
+    public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
+        // Cursors may be closed depending on the type of commit
+        return false;
+    }
+
+    public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
+        // Statements remain open across commits
+        return true;
+    }
+
+    public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
+        // Statements remain open across rollbacks
+        return true;
+    }
+
+    public boolean supportsOrderByUnrelated() throws SQLException {
+        // SPARQL allows ORDER BY on a column that you don't SELECT
+        return true;
+    }
+
+    public boolean supportsOuterJoins() throws SQLException {
+        // SPARQL supports all kinds of joins
+        return true;
+    }
+
+    public boolean supportsPositionedDelete() throws SQLException {
+        // We don't support deleting from result set
+        return false;
+    }
+
+    public boolean supportsPositionedUpdate() throws SQLException {
+        // We don't support updating from result set
+        return false;
+    }
+
+    public boolean supportsResultSetConcurrency(int arg0, int arg1) throws SQLException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public boolean supportsResultSetHoldability(int arg0) throws SQLException {
+        // Both kinds of holdability are supported
+        return true;
+    }
+
+    public boolean supportsResultSetType(int arg0) throws SQLException {
+        // Currently only FORWARD_ONLY is supported
+        switch (arg0) {
+        case ResultSet.TYPE_FORWARD_ONLY:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public boolean supportsSavepoints() throws SQLException {
+        // No notion of savepoints
+        return false;
+    }
+
+    public boolean supportsSchemasInDataManipulation() throws SQLException {
+        // We don't really support schemas
+        return false;
+    }
+
+    public boolean supportsSchemasInIndexDefinitions() throws SQLException {
+        // RDF stores don't allow custom indices
+        return false;
+    }
+
+    public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
+        // SPARQL has no privilege definition statements
+        return false;
+    }
+
+    public boolean supportsSchemasInProcedureCalls() throws SQLException {
+        // SPARQL has no procedure calls
+        return false;
+    }
+
+    public boolean supportsSchemasInTableDefinitions() throws SQLException {
+        // We don't really support schemas
+        return false;
+    }
+
+    public boolean supportsSelectForUpdate() throws SQLException {
+        // No SPARQL equivalent
+        return false;
+    }
+
+    public boolean supportsStatementPooling() throws SQLException {
+        // We don't do pooling
+        return false;
+    }
+
+    public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
+        // Stored procedures are not supported in SPARQL
+        return false;
+    }
+
+    public boolean supportsStoredProcedures() throws SQLException {
+        // Stored procedures are not supported in SPARQL
+        return false;
+    }
+
+    public boolean supportsSubqueriesInComparisons() throws SQLException {
+        // Can't use subqueries in this way in SPARQL
+        return false;
+    }
+
+    public boolean supportsSubqueriesInExists() throws SQLException {
+        // SPARQL does allow sub-queries in EXISTS though strictly speaking our
+        // EXISTS has no relation to the SQL equivalent
+        return true;
+    }
+
+    public boolean supportsSubqueriesInIns() throws SQLException {
+        // Can't use subqueries in this way in SPARQL
+        return false;
+    }
+
+    public boolean supportsSubqueriesInQuantifieds() throws SQLException {
+        // I have no idea what this mean so assume we can't use sub-queries this
+        // way in SPARQL
+        return false;
+    }
+
+    public boolean supportsTableCorrelationNames() throws SQLException {
+        // We don't really support tables
+        return false;
+    }
+
+    public boolean supportsTransactionIsolationLevel(int arg0) throws SQLException {
+        // Currently only None or Serializable is supported
+        switch (arg0) {
+        case Connection.TRANSACTION_NONE:
+        case Connection.TRANSACTION_SERIALIZABLE:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public boolean supportsTransactions() throws SQLException {
+        // Currently transactions are not supported
+        return false;
+    }
+
+    public boolean supportsUnion() throws SQLException {
+        // SPARQL supports UNION
+        return true;
+    }
+
+    public boolean supportsUnionAll() throws SQLException {
+        // No SPARQL equivalent of UNION ALL
+        return false;
+    }
+
+    public boolean updatesAreDetected(int arg0) throws SQLException {
+        // Updates are never detectable
+        return false;
+    }
+
+    public abstract boolean usesLocalFilePerTable() throws SQLException;
+
+    public abstract boolean usesLocalFiles() throws SQLException;
+
+}

Modified: jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/AskResults.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/AskResults.java?rev=1464215&r1=1464214&r2=1464215&view=diff
==============================================================================
--- jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/AskResults.java (original)
+++ jena/Experimental/jena-jdbc/jena-jdbc-core/src/main/java/org/apache/jena/jdbc/results/AskResults.java Wed Apr  3 22:01:26 2013
@@ -34,20 +34,23 @@ import com.hp.hpl.jena.graph.NodeFactory
  * Represents an ASK result
  *
  */
-public class AskResults extends JenaJdbcResultSet {
+public class AskResults extends JenaResultSet {
     
     private boolean result, closed = false;
     private int currRow = 0;
+    private boolean needsCommit = false;
 
     /**
      * Creates a new ASK result
      * @param statement Statement
      * @param result Boolean result
+     * @param commit Whether a commit is required when the results are closed
      * @throws SQLException Thrown if the arguments are invalid
      */
-    public AskResults(Statement statement, boolean result) throws SQLException {
+    public AskResults(Statement statement, boolean result, boolean commit) throws SQLException {
         super(statement);
         this.result = result;
+        this.needsCommit = commit;
     }
 
     public boolean absolute(int row) throws SQLException {
@@ -75,7 +78,11 @@ public class AskResults extends JenaJdbc
     }
 
     public void close() throws SQLException {
+        if (this.closed) return;
         this.closed = true;
+        if (this.needsCommit) {
+            this.getStatement().getConnection().commit();
+        }
     }
 
     public int findColumn(String columnLabel) throws SQLException {