diff --git a/.gitignore b/.gitignore index d963c78..986e825 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ /web/modeshape-web-jcr-webdav-war/target/ /utils/modeshape-jdbc/target/ +/utils/modeshape-jdbc-local/target/ /utils/modeshape-jpa-ddl-gen/target/ /deploy/jbossas/target/ diff --git a/deploy/jbossas/assembly/kit.xml b/deploy/jbossas/assembly/kit.xml index a3b52bf..4bb03cd 100644 --- a/deploy/jbossas/assembly/kit.xml +++ b/deploy/jbossas/assembly/kit.xml @@ -77,7 +77,7 @@ org.modeshape:modeshape-jcr-api - org.modeshape:modeshape-jdbc + org.modeshape:modeshape-jdbc-local javax.jcr:jcr diff --git a/modeshape-integration-tests/pom.xml b/modeshape-integration-tests/pom.xml index e08cc7f..ffcf450 100644 --- a/modeshape-integration-tests/pom.xml +++ b/modeshape-integration-tests/pom.xml @@ -42,6 +42,10 @@ org.modeshape modeshape-jdbc + + org.modeshape + modeshape-jdbc-local + diff --git a/utils/modeshape-jdbc-local/.classpath b/utils/modeshape-jdbc-local/.classpath new file mode 100644 index 0000000..b9205b3 --- /dev/null +++ b/utils/modeshape-jdbc-local/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/utils/modeshape-jdbc-local/.project b/utils/modeshape-jdbc-local/.project new file mode 100644 index 0000000..3d10539 --- /dev/null +++ b/utils/modeshape-jdbc-local/.project @@ -0,0 +1,23 @@ + + + modeshape-jdbc-local + + + + + + org.maven.ide.eclipse.maven2Builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/utils/modeshape-jdbc-local/pom.xml b/utils/modeshape-jdbc-local/pom.xml new file mode 100644 index 0000000..ddd3590 --- /dev/null +++ b/utils/modeshape-jdbc-local/pom.xml @@ -0,0 +1,209 @@ + + + 4.0.0 + + org.modeshape + modeshape + 2.4-SNAPSHOT + ../.. + + + modeshape-jdbc-local + jar + ModeShape JDBC Driver (Local) + JDBC driver to allow clients to use JCR-SQL2 to query a ModeShape JCR repository within the same JVM process. + http://www.modeshape.org + + + + javax.jcr + jcr + + + org.modeshape + modeshape-jcr-api + ${project.version} + + + org.modeshape + modeshape-jcr + ${project.version} + test + + + org.modeshape + modeshape-common + ${project.version} + test-jar + test + + + + junit + junit + test + + + org.hamcrest + hamcrest-library + + + org.mockito + mockito-all + test + + + org.slf4j + slf4j-api + + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + + + + + cargo-1 + + true + + + + + + false + src/main/resources + + * + **/* + + + + + true + src/main/resources + + **/JdbcLocalI18n.properties + + + + + + + org.apache.maven.plugins + + maven-surefire-plugin + + + true + + + + surefire-it + integration-test + + test + + + false + + + + + + + + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.apache.felix + maven-bundle-plugin + + + bundle-manifest + process-classes + + manifest + + + + + + + + + assembly + + + + false + src/main/resources + + * + **/* + + + + + true + src/main/resources + + **/JdbcI18n.properties + + + + + + + + maven-assembly-plugin + + modeshape + + src/assembly/kit.xml + + + + true + + + + + + package + + single + + + + + + + + + + \ No newline at end of file diff --git a/utils/modeshape-jdbc-local/src/assembly/kit.xml b/utils/modeshape-jdbc-local/src/assembly/kit.xml new file mode 100644 index 0000000..a44f6f9 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/assembly/kit.xml @@ -0,0 +1,54 @@ + + + + jdbc-local-driver-${project.version} + + + jar + + false + / + + + true + + + + META-INF/LICENSE.txt + META-INF/NOTICE.txt + + + true + + org.modeshape:modeshape-jcr-api + org.slf4j:slf4j-api + + + + + + true + false + + org.modeshape:modeshape-jdbc-local + + + + \ No newline at end of file diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrBlob.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrBlob.java new file mode 100644 index 0000000..3eb9279 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrBlob.java @@ -0,0 +1,213 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Blob; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import javax.jcr.Binary; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Value; + +/** + * The JDBC {@link Blob} wrapper around a JCR binary {@link Value} object. + */ +public class JcrBlob implements Blob { + + private final Value value; + private final long length; + + /** + * Create a JDBC Blob object around the supplied JCR Value, specifying the length. Note the length can be determined from the + * {@link Property} via {@link Property#getLength()} or {@link Property#getLengths()}. + * + * @param value the JCR value; may not be null + * @param length the length + */ + protected JcrBlob( Value value, + long length ) { + this.value = value; + this.length = length; + assert this.value != null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#free() + */ + @Override + public void free() throws SQLException { + try { + // Get the binary value ... + Binary binary = value.getBinary(); + binary.dispose(); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#getBinaryStream() + */ + @Override + public InputStream getBinaryStream() throws SQLException { + try { + return value.getBinary().getStream(); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#getBinaryStream(long, long) + */ + @Override + public InputStream getBinaryStream( long pos, + long length ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#getBytes(long, int) + */ + @Override + public byte[] getBytes( long pos, + int length ) throws SQLException { + SQLException error = null; + try { + byte[] data = new byte[length]; + int numRead = 0; + // Get the binary value ... + Binary binary = value.getBinary(); + try { + numRead = binary.read(data, pos); + } finally { + binary.dispose(); + } + + // We may have read less than the desired length ... + if (numRead < length) { + // create a shortened array ... + byte[] shortData = new byte[numRead]; + System.arraycopy(data, 0, shortData, 0, numRead); + data = shortData; + } + return data; + } catch (IOException e) { + error = new SQLException(e.getLocalizedMessage(), e); + throw error; + } catch (RepositoryException e) { + error = new SQLException(e.getLocalizedMessage(), e); + throw error; + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#length() + */ + @Override + public long length() { + return length; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#position(byte[], long) + */ + @Override + public long position( byte[] pattern, + long start ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#position(java.sql.Blob, long) + */ + @Override + public long position( Blob pattern, + long start ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#setBinaryStream(long) + */ + @Override + public OutputStream setBinaryStream( long pos ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#setBytes(long, byte[]) + */ + @Override + public int setBytes( long pos, + byte[] bytes ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#setBytes(long, byte[], int, int) + */ + @Override + public int setBytes( long pos, + byte[] bytes, + int offset, + int len ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Blob#truncate(long) + */ + @Override + public void truncate( long len ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrConnection.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrConnection.java new file mode 100644 index 0000000..46667f0 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrConnection.java @@ -0,0 +1,692 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.ClientInfoStatus; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.query.Query; +import org.modeshape.jdbc.delegate.ConnectionInfo; +import org.modeshape.jdbc.delegate.DriverInfo; +import org.modeshape.jdbc.delegate.RepositoryDelegate; + +/** + * This driver's implementation of JDBC {@link Connection}. + */ +public class JcrConnection implements Connection { + + public static final String JCR_SQL2 = Query.JCR_SQL2; + @SuppressWarnings( "deprecation" ) + public static final String JCR_SQL = Query.SQL; + + private boolean closed; + private boolean autoCommit = true; + private int isolation = Connection.TRANSACTION_READ_COMMITTED; + private SQLWarning warning; + private Properties clientInfo = new Properties(); + private DatabaseMetaData metadata; + private final RepositoryDelegate jcrDelegate; + private final DriverInfo driverInfo; + + public JcrConnection( RepositoryDelegate jcrDelegate, + DriverInfo driverInfo ) { + this.jcrDelegate = jcrDelegate; + this.driverInfo = driverInfo; + assert this.jcrDelegate != null; + assert this.driverInfo != null; + } + + public ConnectionInfo info() { + return this.jcrDelegate.getConnectionInfo(); + } + + public DriverInfo driverInfo() { + return this.driverInfo; + } + + /** + * Returns the interface used to communicate to the Jcr Repository. + * + * @return RepositoryDelegate + */ + public RepositoryDelegate getRepositoryDelegate() { + return this.jcrDelegate; + } + + protected NodeType nodeType( String name ) throws SQLException { + try { + return getRepositoryDelegate().nodeType(name); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#isReadOnly() + */ + @Override + public boolean isReadOnly() throws SQLException { + notClosed(); + return true; // always read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setReadOnly(boolean) + */ + @Override + public void setReadOnly( boolean readOnly ) throws SQLException { + notClosed(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#isValid(int) + */ + @Override + public boolean isValid( int timeout ) throws SQLException { + if (closed) return false; + if (timeout < 0) throw new SQLException(JdbcLocalI18n.timeoutMayNotBeNegative.text()); + try { + return this.getRepositoryDelegate().isValid(timeout); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#close() + */ + @Override + public void close() { + if (!closed) { + try { + this.getRepositoryDelegate().close(); + } finally { + metadata = null; + closed = true; + } + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#isClosed() + */ + @Override + public boolean isClosed() { + return closed; + } + + protected final void notClosed() throws SQLException { + if (isClosed()) throw new SQLException(JdbcLocalI18n.connectionIsClosed.text()); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#commit() + */ + @Override + public void commit() throws SQLException { + notClosed(); + try { + this.getRepositoryDelegate().commit(); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#rollback() + */ + @Override + public void rollback() throws SQLException { + notClosed(); + try { + this.getRepositoryDelegate().rollback(); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#rollback(java.sql.Savepoint) + */ + @Override + public void rollback( Savepoint savepoint ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#clearWarnings() + */ + @Override + public void clearWarnings() throws SQLException { + notClosed(); + warning = null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getWarnings() + */ + @Override + public SQLWarning getWarnings() throws SQLException { + notClosed(); + return warning; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getAutoCommit() + */ + @Override + public boolean getAutoCommit() throws SQLException { + notClosed(); + return autoCommit; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setAutoCommit(boolean) + */ + @Override + public void setAutoCommit( boolean autoCommit ) throws SQLException { + notClosed(); + this.autoCommit = autoCommit; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getTransactionIsolation() + */ + @Override + public int getTransactionIsolation() throws SQLException { + notClosed(); + return isolation; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setTransactionIsolation(int) + */ + @Override + public void setTransactionIsolation( int level ) throws SQLException { + notClosed(); + // silently ignore + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setSavepoint() + */ + @Override + public Savepoint setSavepoint() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setSavepoint(java.lang.String) + */ + @Override + public Savepoint setSavepoint( String name ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#releaseSavepoint(java.sql.Savepoint) + */ + @Override + public void releaseSavepoint( Savepoint savepoint ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getCatalog() + */ + @Override + public String getCatalog() { + return this.info().getRepositoryName(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setCatalog(java.lang.String) + */ + @Override + public void setCatalog( String catalog ) { + // silently ignore + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getClientInfo() + */ + @Override + public Properties getClientInfo() /*throws SQLException*/{ + return clientInfo; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getClientInfo(java.lang.String) + */ + @Override + public String getClientInfo( String name ) /*throws SQLException*/{ + return clientInfo.getProperty(name); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setClientInfo(java.util.Properties) + */ + @Override + public void setClientInfo( Properties properties ) throws SQLClientInfoException { + Map status = new HashMap(); + Properties validProperties = new Properties(); + for (String name : properties.stringPropertyNames()) { + // Don't override the built-in properties ... + if (name == null || LocalJcrDriver.ALL_PROPERTY_NAMES.contains(name)) { + status.put(name, ClientInfoStatus.REASON_VALUE_INVALID); + } else { + String value = properties.getProperty(name); + validProperties.put(name, value); + } + } + if (validProperties.isEmpty()) { + if (!status.isEmpty()) { + String reason = JdbcLocalI18n.invalidClientInfo.text(); + throw new SQLClientInfoException(reason, status); + } + } else { + clientInfo.putAll(validProperties); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setClientInfo(java.lang.String, java.lang.String) + */ + @Override + public void setClientInfo( String name, + String value ) throws SQLClientInfoException { + Properties properties = new Properties(); + properties.put(name, value); + setClientInfo(properties); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getHoldability() + */ + @Override + public int getHoldability() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setHoldability(int) + */ + @Override + public void setHoldability( int holdability ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#getMetaData() + */ + @Override + public DatabaseMetaData getMetaData() throws SQLException { + notClosed(); + if (metadata == null) { + String descriptor = this.getRepositoryDelegate().getDescriptor(Repository.REP_NAME_DESC); + if (descriptor != null && descriptor.toLowerCase().contains("modeshape")) { + return new ModeShapeMetaData(this); + } + return new JcrMetaData(this); + } + return metadata; + } + + /** + * Retrieves the type map associated with this Connection object. The type map contains entries for undefined types. This + * method always returns an empty map since it is not possible to add entries to this type map {@inheritDoc} + * + * @see java.sql.Connection#getTypeMap() + */ + @Override + public Map> getTypeMap() { + return new HashMap>(1); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#setTypeMap(java.util.Map) + */ + @Override + public void setTypeMap( Map> map ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method pre-processes the supplied SQL-compatible query and returns the corresponding JCR-SQL2. + *

+ * + * @see java.sql.Connection#nativeSQL(java.lang.String) + */ + @Override + public String nativeSQL( String sql ) { + return sql; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createStatement() + */ + @Override + public Statement createStatement() { + return new JcrStatement(this); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createStatement(int, int) + */ + @Override + public Statement createStatement( int resultSetType, + int resultSetConcurrency ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createStatement(int, int, int) + */ + @Override + public Statement createStatement( int resultSetType, + int resultSetConcurrency, + int resultSetHoldability ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String) + */ + @Override + public PreparedStatement prepareStatement( String sql ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String, int) + */ + @Override + public PreparedStatement prepareStatement( String sql, + int autoGeneratedKeys ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String, int[]) + */ + @Override + public PreparedStatement prepareStatement( String sql, + int[] columnIndexes ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String, java.lang.String[]) + */ + @Override + public PreparedStatement prepareStatement( String sql, + String[] columnNames ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String, int, int) + */ + @Override + public PreparedStatement prepareStatement( String sql, + int resultSetType, + int resultSetConcurrency ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareStatement(java.lang.String, int, int, int) + */ + @Override + public PreparedStatement prepareStatement( String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareCall(java.lang.String) + */ + @Override + public CallableStatement prepareCall( String sql ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareCall(java.lang.String, int, int) + */ + @Override + public CallableStatement prepareCall( String sql, + int resultSetType, + int resultSetConcurrency ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#prepareCall(java.lang.String, int, int, int) + */ + @Override + public CallableStatement prepareCall( String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createArrayOf(java.lang.String, java.lang.Object[]) + */ + @Override + public Array createArrayOf( String typeName, + Object[] elements ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createBlob() + */ + @Override + public Blob createBlob() throws SQLException { + notClosed(); + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createClob() + */ + @Override + public Clob createClob() throws SQLException { + notClosed(); + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createNClob() + */ + @Override + public NClob createNClob() throws SQLException { + notClosed(); + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createSQLXML() + */ + @Override + public SQLXML createSQLXML() throws SQLException { + notClosed(); + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#createStruct(java.lang.String, java.lang.Object[]) + */ + @Override + public Struct createStruct( String typeName, + Object[] attributes ) throws SQLException { + notClosed(); + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) /*throws SQLException*/{ + if (iface.isInstance(this)) { + return true; + } + + return this.getRepositoryDelegate().isWrapperFor(iface); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (isWrapperFor(iface)) { + return iface.cast(this); + } + return getRepositoryDelegate().unwrap(iface); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrMetaData.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrMetaData.java new file mode 100644 index 0000000..9d95aee --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrMetaData.java @@ -0,0 +1,2963 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +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 java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.jcr.PropertyType; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.PropertyDefinition; +import javax.jcr.query.QueryResult; +import javax.jcr.version.OnParentVersionAction; +import org.modeshape.jdbc.metadata.JDBCColumnNames; +import org.modeshape.jdbc.metadata.JDBCColumnPositions; +import org.modeshape.jdbc.metadata.MetaDataQueryResult; +import org.modeshape.jdbc.metadata.MetadataProvider; +import org.modeshape.jdbc.metadata.ResultSetMetaDataImpl; +import org.modeshape.jdbc.metadata.ResultsMetadataConstants; + +/** + * This driver's implementation of JDBC {@link DatabaseMetaData}. + */ +public class JcrMetaData implements DatabaseMetaData { + + protected static final List PSEUDO_COLUMN_DEFNS; + + static { + List defns = new ArrayList(); + boolean auto = true; + boolean mand = false; + boolean prot = true; + boolean mult = false; + boolean search = true; + boolean order = true; + defns.add(new PseudoPropertyDefinition(null, "jcr:path", PropertyType.PATH, auto, mand, prot, mult, search, order)); + defns.add(new PseudoPropertyDefinition(null, "jcr:name", PropertyType.NAME, auto, mand, prot, mult, search, order)); + defns.add(new PseudoPropertyDefinition(null, "jcr:score", PropertyType.DOUBLE, auto, mand, prot, mult, search, order)); + defns.add(new PseudoPropertyDefinition(null, "mode:localName", PropertyType.STRING, auto, mand, prot, mult, search, order)); + defns.add(new PseudoPropertyDefinition(null, "mode:depth", PropertyType.LONG, auto, mand, prot, mult, search, order)); + PSEUDO_COLUMN_DEFNS = Collections.unmodifiableList(defns); + } + + /** CONSTANTS */ + protected static final String WILDCARD = "%"; //$NON-NLS-1$ + protected static final Integer DEFAULT_ZERO = new Integer(0); + protected static final int NO_LIMIT = 0; + + private final JcrConnection connection; + private final String catalogName; + + public JcrMetaData( JcrConnection connection ) { + this.connection = connection; + assert this.connection != null; + this.catalogName = connection.getCatalog(); + assert catalogName != null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDriverMajorVersion() + */ + @Override + public int getDriverMajorVersion() { + return connection.driverInfo().getMajorVersion(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDriverMinorVersion() + */ + @Override + public int getDriverMinorVersion() { + return connection.driverInfo().getMinorVersion(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDriverName() + */ + @Override + public String getDriverName() { + return connection.driverInfo().getName(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDriverVersion() + */ + @Override + public String getDriverVersion() { + return connection.driverInfo().getVersion(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDatabaseMajorVersion() + */ + @Override + public int getDatabaseMajorVersion() { + String[] parts = getDatabaseProductVersion().split("[.-]"); + return parts.length > 0 && parts[0] != null ? Integer.parseInt(parts[0]) : 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDatabaseMinorVersion() + */ + @Override + public int getDatabaseMinorVersion() { + String[] parts = getDatabaseProductVersion().split("[.-]"); + return parts.length > 1 && parts[1] != null ? Integer.parseInt(parts[1]) : 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDatabaseProductName() + */ + @Override + public String getDatabaseProductName() { + return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_NAME_DESC); + } + + public String getDatabaseProductUrl() { + return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VENDOR_URL_DESC); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDatabaseProductVersion() + */ + @Override + public String getDatabaseProductVersion() { + return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VERSION_DESC); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getJDBCMajorVersion() + */ + @Override + public int getJDBCMajorVersion() { + return 2; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getJDBCMinorVersion() + */ + @Override + public int getJDBCMinorVersion() { + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getConnection() + */ + @Override + public Connection getConnection() { + return connection; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#isReadOnly() + */ + @Override + public boolean isReadOnly() { + return true; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#allProceduresAreCallable() + */ + @Override + public boolean allProceduresAreCallable() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#allTablesAreSelectable() + */ + @Override + public boolean allTablesAreSelectable() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#autoCommitFailureClosesAllResultSets() + */ + @Override + public boolean autoCommitFailureClosesAllResultSets() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit() + */ + @Override + public boolean dataDefinitionCausesTransactionCommit() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#dataDefinitionIgnoredInTransactions() + */ + @Override + public boolean dataDefinitionIgnoredInTransactions() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#deletesAreDetected(int) + */ + @Override + public boolean deletesAreDetected( int type ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#doesMaxRowSizeIncludeBlobs() + */ + @Override + public boolean doesMaxRowSizeIncludeBlobs() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getAttributes( String catalog, + String schemaPattern, + String typeNamePattern, + String attributeNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getBestRowIdentifier(java.lang.String, java.lang.String, java.lang.String, int, boolean) + */ + @Override + public ResultSet getBestRowIdentifier( String catalog, + String schema, + String table, + int scope, + boolean nullable ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getCatalogSeparator() + */ + @Override + public String getCatalogSeparator() { + return null; + } + + /** + * {@inheritDoc} + *

+ * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns 'Repository' for the catalog + * term. + *

+ * + * @see java.sql.DatabaseMetaData#getCatalogTerm() + */ + @Override + public String getCatalogTerm() { + return "Repository"; + } + + /** + * {@inheritDoc} + *

+ * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns a result set containing only + * the repository's name. + *

+ * + * @see java.sql.DatabaseMetaData#getCatalogs() + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getCatalogs() throws SQLException { + List> records = new ArrayList>(1); + + List row = Arrays.asList(catalogName); + records.add(row); + + /*********************************************************************** + * Hardcoding JDBC column names for the columns returned in results object + ***********************************************************************/ + + Map[] metadataList = new Map[1]; + + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.CATALOGS.TABLE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + MetadataProvider provider = new MetadataProvider(metadataList); + + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + + JcrStatement stmt = new JcrStatement(this.connection); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData); + + return rs; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getClientInfoProperties() + */ + @Override + public ResultSet getClientInfoProperties() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getColumnPrivileges(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getColumnPrivileges( String catalog, + String schema, + String table, + String columnNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getColumns( String catalog, + String schemaPattern, + String tableNamePattern, + String columnNamePattern ) throws SQLException { + LocalJcrDriver.logger.trace("getcolumns: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + + columnNamePattern); + + // Get all tables if tableNamePattern is null + if (tableNamePattern == null) tableNamePattern = WILDCARD; + + Map[] metadataList = new Map[JDBCColumnPositions.COLUMNS.MAX_COLUMNS]; + + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.TABLE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.TABLE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.TABLE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.COLUMN_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.DATA_TYPE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.TYPE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.COLUMN_SIZE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.BUFFER_LENGTH, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.DECIMAL_DIGITS, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.NUM_PREC_RADIX, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + + metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.NULLABLE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.REMARKS, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.COLUMN_DEF, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[13] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SQL_DATA_TYPE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[14] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SQL_DATETIME_SUB, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[15] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.CHAR_OCTET_LENGTH, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[16] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.ORDINAL_POSITION, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[17] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.IS_NULLABLE, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[18] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SCOPE_CATLOG, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[19] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SCOPE_SCHEMA, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + metadataList[20] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SCOPE_TABLE, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[21] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.SOURCE_DATA_TYPE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + + MetadataProvider provider = new MetadataProvider(metadataList); + + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + + List> records = new ArrayList>(); + + try { + + List nodetypes = filterNodeTypes(tableNamePattern); + + Iterator nodeIt = nodetypes.iterator(); + // process each node + while (nodeIt.hasNext()) { + + NodeType type = nodeIt.next(); + + if (type.getPropertyDefinitions() == null) { + throw new SQLException("Program Error: missing propertydefintions for " + type.getName()); + } + + List defns = filterPropertyDefnitions(columnNamePattern, type); + + int ordinal = 0; + Iterator defnsIt = defns.iterator(); + // build the list of records. + while (defnsIt.hasNext()) { + + PropertyDefinition propDefn = defnsIt.next(); + + // list represents a record on the Results object. + List currentRow = new ArrayList(JDBCColumnPositions.COLUMNS.MAX_COLUMNS); + + JcrType jcrtype = JcrType.typeInfo(propDefn.getRequiredType()); + + currentRow.add(catalogName); // TABLE_CAT + currentRow.add("NULL"); // TABLE_SCHEM + currentRow.add(type.getName()); // TABLE_NAME + currentRow.add(propDefn.getName()); // COLUMN_NAME + currentRow.add(jcrtype.getJdbcType()); // DATA_TYPE + currentRow.add(jcrtype.getJdbcTypeName()); // TYPE_NAME + currentRow.add(jcrtype.getNominalDisplaySize()); // COLUMN_SIZE + currentRow.add("NULL"); // BUFFER_LENGTH + currentRow.add(JcrMetaData.DEFAULT_ZERO); // DECIMAL_DIGITS + currentRow.add(JcrMetaData.DEFAULT_ZERO); // NUM_PREC_RADIX + + currentRow.add((propDefn.isMandatory() ? ResultsMetadataConstants.NULL_TYPES.NOT_NULL : ResultsMetadataConstants.NULL_TYPES.NULLABLE)); // NULLABLE + currentRow.add(""); // REMARKS + currentRow.add("NULL"); // COLUMN_DEF + currentRow.add(JcrMetaData.DEFAULT_ZERO); // COLUMN_DEF + currentRow.add(JcrMetaData.DEFAULT_ZERO); // SQL_DATETIME_SUB + + currentRow.add(JcrMetaData.DEFAULT_ZERO); // CHAR_OCTET_LENGTH + currentRow.add(new Integer(ordinal + 1)); // ORDINAL_POSITION + currentRow.add(propDefn.isMandatory() ? "NO" : "YES"); // IS_NULLABLE + currentRow.add("NULL"); // SCOPE_CATLOG + currentRow.add("NULL"); // SCOPE_SCHEMA + + currentRow.add("NULL"); // SCOPE_TABLE + currentRow.add(JcrMetaData.DEFAULT_ZERO); // SOURCE_DATA_TYPE + + // add the current row to the list of records. + records.add(currentRow); + + ++ordinal; + } + + }// end of while + + JcrStatement jcrstmt = new JcrStatement(this.connection); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); + + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getCrossReference(java.lang.String, java.lang.String, java.lang.String, java.lang.String, + * java.lang.String, java.lang.String) + */ + @Override + public ResultSet getCrossReference( String parentCatalog, + String parentSchema, + String parentTable, + String foreignCatalog, + String foreignSchema, + String foreignTable ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getDefaultTransactionIsolation() + */ + @Override + public int getDefaultTransactionIsolation() { + return Connection.TRANSACTION_NONE; + } + + /** + * {@inheritDoc} + *

+ * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those REFERENCE properties on + * the type identified by the table name. + *

+ * + * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getExportedKeys( String catalog, + String schema, + String table ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getExtraNameCharacters() + */ + @Override + public String getExtraNameCharacters() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getFunctionColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getFunctionColumns( String catalog, + String schemaPattern, + String functionNamePattern, + String columnNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getFunctions(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getFunctions( String catalog, + String schemaPattern, + String functionNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * JCR-SQL2 allows identifiers to be surrounded by matching single quotes, double quotes, or opening and closing square + * brackets. Therefore, this method returns a single-quote character as the quote string. + *

+ * + * @see java.sql.DatabaseMetaData#getIdentifierQuoteString() + */ + @Override + public String getIdentifierQuoteString() { + return "\""; + } + + /** + * {@inheritDoc} + *

+ * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those properties on other types + * referencing the type identified by the table name. + *

+ * + * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getImportedKeys( String catalog, + String schema, + String table ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getIndexInfo(java.lang.String, java.lang.String, java.lang.String, boolean, boolean) + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getIndexInfo( String catalog, + String schema, + String tableNamePattern, + boolean unique, + boolean approximate ) throws SQLException { + + // Get index information for all tables if tableNamePattern is null + if (tableNamePattern == null) tableNamePattern = WILDCARD; + + Map[] metadataList = new Map[JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS]; + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.TABLE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.TABLE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.TABLE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.NON_UNIQUE, + JcrType.DefaultDataTypes.BOOLEAN, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.INDEX_QUALIFIER, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.INDEX_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.TYPE, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.ORDINAL_POSITION, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.COLUMN_NAME, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.ASC_OR_DESC, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.CARDINALITY, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.PAGES, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.INDEX_INFO.FILTER_CONDITION, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + try { + Boolean nonUnique = Boolean.FALSE; + List> records = new ArrayList>(); + for (NodeType type : filterNodeTypes(tableNamePattern)) { + // Create a unique key for each "jcr:uuid" property, so do this only for those node types + // that somehow extend "mix:referenceable" ... + if (!type.isNodeType("mix:referenceable")) continue; + + // Every table has a "jcr:path" pseudo-column that is the primary key ... + List currentRow = new ArrayList(JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS); + currentRow.add(catalogName); // TABLE_CAT + currentRow.add("NULL"); // TABLE_SCHEM + currentRow.add(type.getName()); // TABLE_NAME + currentRow.add(nonUnique); // NON_UNIQUE + currentRow.add(catalogName); // INDEX_QUALIFIER + currentRow.add(type.getName() + "_UK"); // INDEX_NAME + currentRow.add(DatabaseMetaData.tableIndexHashed); // TYPE + currentRow.add(new Short((short)1)); // ORDINAL_POSITION + currentRow.add(type.getName()); // COLUMN_NAME + currentRow.add("A"); // ASC_OR_DESC + currentRow.add(0); // CARDINALITY + currentRow.add(1); // PAGES + currentRow.add(null); // FILTER_CONDITION + + // add the current row to the list of records. + records.add(currentRow); + } + + JcrStatement jcrstmt = new JcrStatement(this.connection); + MetadataProvider provider = new MetadataProvider(metadataList); + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + *

+ * There is no maximum length of binary literals (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxBinaryLiteralLength() + */ + @Override + public int getMaxBinaryLiteralLength() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no maximum length of the catalog (repository) names - or the limit is not known. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxCatalogNameLength() + */ + @Override + public int getMaxCatalogNameLength() { + return JcrMetaData.NO_LIMIT; // none + } + + /** + * {@inheritDoc} + *

+ * There is no maximum length of character literals (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxCharLiteralLength() + */ + @Override + public int getMaxCharLiteralLength() { + return JcrMetaData.NO_LIMIT; + } + + /** + * {@inheritDoc} + *

+ * There is no maximum length of column names (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnNameLength() + */ + @Override + public int getMaxColumnNameLength() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * JCR-SQL2 does not support GROUP BY, so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnsInGroupBy() + */ + @Override + public int getMaxColumnsInGroupBy() { + return 0; + } + + /** + * {@inheritDoc} + *

+ * There is no limit to the number of columns in an index (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnsInIndex() + */ + @Override + public int getMaxColumnsInIndex() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no limit to the number of columns in an ORDER BY statement (or if there is a limit it is not known), so this + * method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnsInOrderBy() + */ + @Override + public int getMaxColumnsInOrderBy() { + return JcrMetaData.NO_LIMIT; // not known (technically there is no limit, but there would be a practical limit) + } + + /** + * {@inheritDoc} + *

+ * There is no limit to the number of columns in a select statement (or if there is a limit it is not known), so this method + * returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnsInSelect() + */ + @Override + public int getMaxColumnsInSelect() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no limit to the number of columns in a table (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxColumnsInTable() + */ + @Override + public int getMaxColumnsInTable() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no limit to the number of connections (or if there is a limit it is not known), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxConnections() + */ + @Override + public int getMaxConnections() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There are no cursors (or there is no limit), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxCursorNameLength() + */ + @Override + public int getMaxCursorNameLength() { + return 0; + } + + /** + * {@inheritDoc} + *

+ * There are no indexes (or there is no limit), so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxIndexLength() + */ + @Override + public int getMaxIndexLength() { + return 0; // no limit + } + + /** + * {@inheritDoc} + *

+ * There are no procedures, so this method returns 0. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxProcedureNameLength() + */ + @Override + public int getMaxProcedureNameLength() { + return 0; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no maximum row size. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxRowSize() + */ + @Override + public int getMaxRowSize() { + return JcrMetaData.NO_LIMIT; // no limit + } + + /** + * {@inheritDoc} + *

+ * There is no maximum length of the schema (workspace) names - or the limit is not known. + *

+ * + * @see java.sql.DatabaseMetaData#getMaxSchemaNameLength() + */ + @Override + public int getMaxSchemaNameLength() { + return JcrMetaData.NO_LIMIT; // none + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getMaxStatementLength() + */ + @Override + public int getMaxStatementLength() { + return 0; // no limit + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getMaxStatements() + */ + @Override + public int getMaxStatements() { + return 0; // no limit + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getMaxTableNameLength() + */ + @Override + public int getMaxTableNameLength() { + return 0; // no limit + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getMaxTablesInSelect() + */ + @Override + public int getMaxTablesInSelect() { + return 0; // not known (technically there is no limit, but there would be a practical limit) + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getMaxUserNameLength() + */ + @Override + public int getMaxUserNameLength() { + return 0; // no limit + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getNumericFunctions() + */ + @Override + public String getNumericFunctions() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String) + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getPrimaryKeys( String catalog, + String schema, + String tableNamePattern ) throws SQLException { + // Get primary keys for all tables if tableNamePattern is null + if (tableNamePattern == null) tableNamePattern = WILDCARD; + + Map[] metadataList = new Map[JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS]; + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.TABLE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.TABLE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.TABLE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.COLUMN_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.KEY_SEQ, + JcrType.DefaultDataTypes.LONG, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.PRIMARY_KEYS.PK_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + try { + List> records = new ArrayList>(); + for (NodeType type : filterNodeTypes(tableNamePattern)) { + // Every table has a "jcr:path" pseudo-column that is the primary key ... + List currentRow = new ArrayList(JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS); + currentRow.add(catalogName); // TABLE_CAT + currentRow.add("NULL"); // TABLE_SCHEM + currentRow.add(type.getName()); // TABLE_NAME + currentRow.add("jcr:path"); // COLUMN_NAME + currentRow.add(1); // KEY_SEQ + currentRow.add(type.getName() + "_PK"); // PK_NAME + + // add the current row to the list of records. + records.add(currentRow); + } + + JcrStatement jcrstmt = new JcrStatement(this.connection); + MetadataProvider provider = new MetadataProvider(metadataList); + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getProcedureColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getProcedureColumns( String catalog, + String schemaPattern, + String procedureNamePattern, + String columnNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getProcedureTerm() + */ + @Override + public String getProcedureTerm() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getProcedures(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getProcedures( String catalog, + String schemaPattern, + String procedureNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getResultSetHoldability() + */ + @Override + public int getResultSetHoldability() { + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getRowIdLifetime() + */ + @Override + public RowIdLifetime getRowIdLifetime() { + return RowIdLifetime.ROWID_UNSUPPORTED; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSQLKeywords() + */ + @Override + public String getSQLKeywords() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSQLStateType() + */ + @Override + public int getSQLStateType() { + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSchemaTerm() + */ + @Override + public String getSchemaTerm() { + return " "; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSchemas() + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getSchemas() throws SQLException { + List> records = new ArrayList>(1); + + /*********************************************************************** + * Hardcoding JDBC column names for the columns returned in results object + ***********************************************************************/ + + Map[] metadataList = new Map[1]; + + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.COLUMNS.TABLE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + MetadataProvider provider = new MetadataProvider(metadataList); + + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + + JcrStatement stmt = new JcrStatement(this.connection); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData); + + return rs; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSchemas(java.lang.String, java.lang.String) + */ + @Override + public ResultSet getSchemas( String catalog, + String schemaPattern ) throws SQLException { + return getSchemas(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSearchStringEscape() + */ + @Override + public String getSearchStringEscape() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getStringFunctions() + */ + @Override + public String getStringFunctions() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSuperTables(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getSuperTables( String catalog, + String schemaPattern, + String tableNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSuperTypes(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getSuperTypes( String catalog, + String schemaPattern, + String typeNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getSystemFunctions() + */ + @Override + public String getSystemFunctions() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getTablePrivileges(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getTablePrivileges( String catalog, + String schemaPattern, + String tableNamePattern ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getTableTypes() + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getTableTypes() throws SQLException { + + List> records = new ArrayList>(1); + List row = Arrays.asList(new String[] {ResultsMetadataConstants.TABLE_TYPES.VIEW}); + records.add(row); + + /*********************************************************************** + * Hardcoding JDBC column names for the columns returned in results object + ***********************************************************************/ + + Map[] metadataList = new Map[1]; + + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLE_TYPES.TABLE_TYPE, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + MetadataProvider provider = new MetadataProvider(metadataList); + + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + + JcrStatement stmt = new JcrStatement(this.connection); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData); + return rs; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) + */ + @SuppressWarnings( "unchecked" ) + @Override + public ResultSet getTables( String catalog, + String schemaPattern, + String tableNamePattern, + String[] types ) throws SQLException { + + LocalJcrDriver.logger.trace("getTables: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + types); + + // Get all tables if tableNamePattern is null + if (tableNamePattern == null) { + tableNamePattern = WILDCARD; + } + + Map[] metadataList = new Map[JDBCColumnPositions.TABLES.MAX_COLUMNS]; + + metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TABLE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TABLE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TABLE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TABLE_TYPE, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NOT_NULL, + this.connection); + metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.REMARKS, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TYPE_CAT, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TYPE_SCHEM, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.TYPE_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.SELF_REFERENCING_COL_NAME, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, + null, + JDBCColumnNames.TABLES.REF_GENERATION, + JcrType.DefaultDataTypes.STRING, + ResultsMetadataConstants.NULL_TYPES.NULLABLE, + this.connection); + + MetadataProvider provider = new MetadataProvider(metadataList); + + ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); + + List> records = new ArrayList>(); + + try { + List nodetypes = filterNodeTypes(tableNamePattern); + + Iterator nodeIt = nodetypes.iterator(); + // build the list of records from the nodetypes. + while (nodeIt.hasNext()) { + + NodeType type = nodeIt.next(); + if (!type.isQueryable()) continue; + + // list represents a record on the Results object. + List currentRow = new ArrayList(JDBCColumnPositions.TABLES.MAX_COLUMNS); + // add values in the current record on the Results object to the list + // number of values to be fetched from each row is MAX_COLUMNS. + + currentRow.add(catalogName); // TABLE_CAT + currentRow.add("NULL"); // TABLE_SCHEM + currentRow.add(type.getName()); // TABLE_NAME + currentRow.add(ResultsMetadataConstants.TABLE_TYPES.VIEW); // TABLE_TYPE + currentRow.add("Is Mixin: " + type.isMixin()); // REMARKS + currentRow.add("NULL"); // TYPE_CAT + currentRow.add("NULL"); // TYPE_SCHEM + currentRow.add("NULL"); // TYPE_NAME + currentRow.add(type.getPrimaryItemName()); // SELF_REF + currentRow.add("DERIVED"); // REF_GEN + + // add the current row to the list of records. + records.add(currentRow); + }// end of while + + JcrStatement jcrstmt = new JcrStatement(this.connection); + QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); + + return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); + + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage()); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getTimeDateFunctions() + */ + @Override + public String getTimeDateFunctions() { + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getTypeInfo() + */ + @Override + public ResultSet getTypeInfo() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getUDTs(java.lang.String, java.lang.String, java.lang.String, int[]) + */ + @Override + public ResultSet getUDTs( String catalog, + String schemaPattern, + String typeNamePattern, + int[] types ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method returns the effective URL of the connection, which includes all connection properties (even if those properties + * were passed in via the Properties argument). Note that each character in the password is replaced with a '*' character. + *

+ * + * @see java.sql.DatabaseMetaData#getURL() + */ + @Override + public String getURL() { + return connection.info().getEffectiveUrl(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getUserName() + */ + @Override + public String getUserName() { + return connection.info().getUsername(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#getVersionColumns(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public ResultSet getVersionColumns( String catalog, + String schema, + String table ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#insertsAreDetected(int) + */ + @Override + public boolean insertsAreDetected( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#isCatalogAtStart() + */ + @Override + public boolean isCatalogAtStart() { + return true; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#locatorsUpdateCopy() + */ + @Override + public boolean locatorsUpdateCopy() { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#nullPlusNonNullIsNull() + */ + @Override + public boolean nullPlusNonNullIsNull() { + return false; + } + + /** + * {@inheritDoc} + *

+ * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0 + * specification says ordering of null values is implementation-determined. + *

+ * + * @see java.sql.DatabaseMetaData#nullsAreSortedAtEnd() + */ + @Override + public boolean nullsAreSortedAtEnd() { + return false; + } + + /** + * {@inheritDoc} + *

+ * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0 + * specification says ordering of null values is implementation-determined. + *

+ * + * @see java.sql.DatabaseMetaData#nullsAreSortedAtStart() + */ + @Override + public boolean nullsAreSortedAtStart() { + return false; + } + + /** + * {@inheritDoc} + *

+ * Assumed to be false for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is + * implementation-determined. + *

+ * + * @see java.sql.DatabaseMetaData#nullsAreSortedHigh() + */ + @Override + public boolean nullsAreSortedHigh() { + return false; + } + + /** + * {@inheritDoc} + *

+ * Assumed to be true for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is + * implementation-determined. + *

+ * + * @see java.sql.DatabaseMetaData#nullsAreSortedLow() + */ + @Override + public boolean nullsAreSortedLow() { + return true; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#othersDeletesAreVisible(int) + */ + @Override + public boolean othersDeletesAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#othersInsertsAreVisible(int) + */ + @Override + public boolean othersInsertsAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#othersUpdatesAreVisible(int) + */ + @Override + public boolean othersUpdatesAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#ownDeletesAreVisible(int) + */ + @Override + public boolean ownDeletesAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#ownInsertsAreVisible(int) + */ + @Override + public boolean ownInsertsAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#ownUpdatesAreVisible(int) + */ + @Override + public boolean ownUpdatesAreVisible( int type ) { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesLowerCaseIdentifiers() + */ + @Override + public boolean storesLowerCaseIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesLowerCaseQuotedIdentifiers() + */ + @Override + public boolean storesLowerCaseQuotedIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesMixedCaseIdentifiers() + */ + @Override + public boolean storesMixedCaseIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesMixedCaseQuotedIdentifiers() + */ + @Override + public boolean storesMixedCaseQuotedIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesUpperCaseIdentifiers() + */ + @Override + public boolean storesUpperCaseIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#storesUpperCaseQuotedIdentifiers() + */ + @Override + public boolean storesUpperCaseQuotedIdentifiers() { + return false; // JCR node types are case-sensitive + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsANSI92EntryLevelSQL() + */ + @Override + public boolean supportsANSI92EntryLevelSQL() { + return false; // JCR-SQL2 is not entry-level ANSI92 SQL + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsANSI92FullSQL() + */ + @Override + public boolean supportsANSI92FullSQL() { + return false; // JCR-SQL2 is not full ANSI92 SQL + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsANSI92IntermediateSQL() + */ + @Override + public boolean supportsANSI92IntermediateSQL() { + return false; // JCR-SQL2 is not intermediate ANSI92 SQL + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsAlterTableWithAddColumn() + */ + @Override + public boolean supportsAlterTableWithAddColumn() { + // Not in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsAlterTableWithDropColumn() + */ + @Override + public boolean supportsAlterTableWithDropColumn() { + // Not in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsBatchUpdates() + */ + @Override + public boolean supportsBatchUpdates() { + // Not in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCatalogsInDataManipulation() + */ + @Override + public boolean supportsCatalogsInDataManipulation() { + // Not in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCatalogsInIndexDefinitions() + */ + @Override + public boolean supportsCatalogsInIndexDefinitions() { + // No such thing in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCatalogsInPrivilegeDefinitions() + */ + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() { + // No defining privileges in JCR 1.0 or 2.0 or JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCatalogsInProcedureCalls() + */ + @Override + public boolean supportsCatalogsInProcedureCalls() { + // No such thing in JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCatalogsInTableDefinitions() + */ + @Override + public boolean supportsCatalogsInTableDefinitions() { + // No defining tables in JCR 1.0 or 2.0 or JCR-SQL2 + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsColumnAliasing() + */ + @Override + public boolean supportsColumnAliasing() { + // JCR-SQL2 does support aliases on column names (section 6.7.39) + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsConvert() + */ + @Override + public boolean supportsConvert() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsConvert(int, int) + */ + @Override + public boolean supportsConvert( int fromType, + int toType ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCoreSQLGrammar() + */ + @Override + public boolean supportsCoreSQLGrammar() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsCorrelatedSubqueries() + */ + @Override + public boolean supportsCorrelatedSubqueries() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsDataDefinitionAndDataManipulationTransactions() + */ + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsDataManipulationTransactionsOnly() + */ + @Override + public boolean supportsDataManipulationTransactionsOnly() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsDifferentTableCorrelationNames() + */ + @Override + public boolean supportsDifferentTableCorrelationNames() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsExpressionsInOrderBy() + */ + @Override + public boolean supportsExpressionsInOrderBy() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsExtendedSQLGrammar() + */ + @Override + public boolean supportsExtendedSQLGrammar() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsFullOuterJoins() + */ + @Override + public boolean supportsFullOuterJoins() { + // JCR-SQL2 does not support FULL OUTER JOIN ... + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys() + */ + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsGroupBy() + */ + @Override + public boolean supportsGroupBy() { + return false; // not in JCR-SQL2; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsGroupByBeyondSelect() + */ + @Override + public boolean supportsGroupByBeyondSelect() { + return false; // not in JCR-SQL2; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsGroupByUnrelated() + */ + @Override + public boolean supportsGroupByUnrelated() { + return false; // not in JCR-SQL2; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsIntegrityEnhancementFacility() + */ + @Override + public boolean supportsIntegrityEnhancementFacility() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsLikeEscapeClause() + */ + @Override + public boolean supportsLikeEscapeClause() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsLimitedOuterJoins() + */ + @Override + public boolean supportsLimitedOuterJoins() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMinimumSQLGrammar() + */ + @Override + public boolean supportsMinimumSQLGrammar() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMixedCaseIdentifiers() + */ + @Override + public boolean supportsMixedCaseIdentifiers() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMixedCaseQuotedIdentifiers() + */ + @Override + public boolean supportsMixedCaseQuotedIdentifiers() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMultipleOpenResults() + */ + @Override + public boolean supportsMultipleOpenResults() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMultipleResultSets() + */ + @Override + public boolean supportsMultipleResultSets() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsMultipleTransactions() + */ + @Override + public boolean supportsMultipleTransactions() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsNamedParameters() + */ + @Override + public boolean supportsNamedParameters() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsNonNullableColumns() + */ + @Override + public boolean supportsNonNullableColumns() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOpenCursorsAcrossCommit() + */ + @Override + public boolean supportsOpenCursorsAcrossCommit() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOpenCursorsAcrossRollback() + */ + @Override + public boolean supportsOpenCursorsAcrossRollback() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOpenStatementsAcrossCommit() + */ + @Override + public boolean supportsOpenStatementsAcrossCommit() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOpenStatementsAcrossRollback() + */ + @Override + public boolean supportsOpenStatementsAcrossRollback() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOrderByUnrelated() + */ + @Override + public boolean supportsOrderByUnrelated() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsOuterJoins() + */ + @Override + public boolean supportsOuterJoins() { + return true; // JCR-SQL2 + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsPositionedDelete() + */ + @Override + public boolean supportsPositionedDelete() { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsPositionedUpdate() + */ + @Override + public boolean supportsPositionedUpdate() { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsResultSetConcurrency(int, int) + */ + @Override + public boolean supportsResultSetConcurrency( int type, + int concurrency ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsResultSetHoldability(int) + */ + @Override + public boolean supportsResultSetHoldability( int holdability ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsResultSetType(int) + */ + @Override + public boolean supportsResultSetType( int type ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSavepoints() + */ + @Override + public boolean supportsSavepoints() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSchemasInDataManipulation() + */ + @Override + public boolean supportsSchemasInDataManipulation() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSchemasInIndexDefinitions() + */ + @Override + public boolean supportsSchemasInIndexDefinitions() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSchemasInPrivilegeDefinitions() + */ + @Override + public boolean supportsSchemasInPrivilegeDefinitions() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSchemasInProcedureCalls() + */ + @Override + public boolean supportsSchemasInProcedureCalls() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSchemasInTableDefinitions() + */ + @Override + public boolean supportsSchemasInTableDefinitions() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSelectForUpdate() + */ + @Override + public boolean supportsSelectForUpdate() { + return false; // read-only + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsStatementPooling() + */ + @Override + public boolean supportsStatementPooling() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsStoredFunctionsUsingCallSyntax() + */ + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsStoredProcedures() + */ + @Override + public boolean supportsStoredProcedures() { + return false; // nope + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSubqueriesInComparisons() + */ + @Override + public boolean supportsSubqueriesInComparisons() { + return false; // no subqueries in JCR-SQL2 + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSubqueriesInExists() + */ + @Override + public boolean supportsSubqueriesInExists() { + return false; // no subqueries in JCR-SQL2 + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSubqueriesInIns() + */ + @Override + public boolean supportsSubqueriesInIns() { + return false; // no subqueries in JCR-SQL2 + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsSubqueriesInQuantifieds() + */ + @Override + public boolean supportsSubqueriesInQuantifieds() { + return false; // no subqueries in JCR-SQL2 + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsTableCorrelationNames() + */ + @Override + public boolean supportsTableCorrelationNames() { + // JCR-SQL2 does support table aliases that can be used as prefixes for column names + return true; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel(int) + */ + @Override + public boolean supportsTransactionIsolationLevel( int level ) { + return level == Connection.TRANSACTION_READ_COMMITTED; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsTransactions() + */ + @Override + public boolean supportsTransactions() { + // Generally, JCR does support transactions ... + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsUnion() + */ + @Override + public boolean supportsUnion() { + // JCR-SQL2 does not support UNION ... + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#supportsUnionAll() + */ + @Override + public boolean supportsUnionAll() { + // JCR-SQL2 does not support UNION ALL ... + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#updatesAreDetected(int) + */ + @Override + public boolean updatesAreDetected( int type ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#usesLocalFilePerTable() + */ + @Override + public boolean usesLocalFilePerTable() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.DatabaseMetaData#usesLocalFiles() + */ + @Override + public boolean usesLocalFiles() { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) { + return iface.isInstance(this); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (!isWrapperFor(iface)) { + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(DatabaseMetaData.class.getSimpleName(), + iface.getName())); + } + + return iface.cast(this); + } + + private List filterNodeTypes( String tableNamePattern ) throws RepositoryException { + List nodetypes = null; + + if (tableNamePattern.trim().equals(WILDCARD)) { + + nodetypes = this.connection.getRepositoryDelegate().nodeTypes(); + Iterator nodeIt = nodetypes.iterator(); + while (nodeIt.hasNext()) { + NodeType type = nodeIt.next(); + if (!hasColumnedDefined(type)) nodeIt.remove(); + } + + } else if (tableNamePattern.contains(WILDCARD)) { + nodetypes = new ArrayList(); + String partName = null; + boolean isLeading = false; + boolean isTrailing = false; + partName = tableNamePattern; + + if (partName.startsWith(WILDCARD)) { + partName = partName.substring(1); + isLeading = true; + } + if (partName.endsWith(WILDCARD) && partName.length() > 1) { + partName = partName.substring(0, partName.length() - 1); + isTrailing = true; + } + + List nts = this.connection.getRepositoryDelegate().nodeTypes(); + Iterator nodeIt = nts.iterator(); + // build the list of records from server's Results object. + while (nodeIt.hasNext()) { + + NodeType type = nodeIt.next(); + + if (!hasColumnedDefined(type)) continue; + + if (isLeading) { + if (isTrailing) { + if (type.getName().indexOf(partName, 1) > -1) { + nodetypes.add(type); + } + } else if (type.getName().endsWith(partName)) { + nodetypes.add(type); + } + + } else if (isTrailing) { + if (type.getName().startsWith(partName)) { + nodetypes.add(type); + } + } + } + + } else { + NodeType nt = this.connection.getRepositoryDelegate().nodeType(tableNamePattern); + nodetypes = new ArrayList(1); + if (nt != null && hasColumnedDefined(nt)) { + nodetypes.add(nt); + } + } + + if (nodetypes.size() > 1) { + final Comparator name_order = new Comparator() { + public int compare( NodeType e1, + NodeType e2 ) { + return e1.getName().compareTo(e2.getName()); + } + }; + Collections.sort(nodetypes, name_order); + } + + return nodetypes; + } + + private List filterPropertyDefnitions( String columnNamePattern, + NodeType nodeType ) { + + List allDefns = new ArrayList(); + addPropertyDefinitions(allDefns, nodeType); + + List resultDefns = null; + + if (columnNamePattern.trim().equals(WILDCARD)) { + resultDefns = allDefns; + } else if (columnNamePattern.contains(WILDCARD)) { + resultDefns = new ArrayList(); + String partName = null; + boolean isLeading = false; + boolean isTrailing = false; + partName = columnNamePattern; + + if (partName.startsWith(WILDCARD)) { + partName = partName.substring(1); + isLeading = true; + } + if (partName.endsWith(WILDCARD) && partName.length() > 1) { + partName = partName.substring(0, partName.length() - 1); + isTrailing = true; + } + + Iterator defnIt = allDefns.iterator(); + while (defnIt.hasNext()) { + PropertyDefinition defn = defnIt.next(); + + if (isLeading) { + if (isTrailing) { + if (defn.getName().indexOf(partName, 1) > -1) { + resultDefns.add(defn); + } + } else if (defn.getName().endsWith(partName)) { + resultDefns.add(defn); + } + + } else if (isTrailing) { + if (defn.getName().startsWith(partName)) { + resultDefns.add(defn); + } + } + } + + } else { + resultDefns = new ArrayList(); + + Iterator defnIt = allDefns.iterator(); + while (defnIt.hasNext()) { + PropertyDefinition defn = defnIt.next(); + if (defn.getName().equals(columnNamePattern)) { + resultDefns.add(defn); + } + } + + } + + if (resultDefns.size() > 1) { + final Comparator name_order = new Comparator() { + public int compare( PropertyDefinition e1, + PropertyDefinition e2 ) { + return e1.getName().compareTo(e2.getName()); + } + }; + Collections.sort(resultDefns, name_order); + } + + return resultDefns; + } + + /** + * isTableValid determines if the node type should be exposed as a table. A table must have at least one column, and the + * property definitions and superTypes provide the columns. As long as one is defined, then one table is valid for exposure. + * + * @param nodeType + * @return true if a column is defined for the table + */ + private boolean hasColumnedDefined( NodeType nodeType ) { + List allDefns = new ArrayList(); + addPropertyDefinitions(allDefns, nodeType); + return (allDefns.size() > 0 ? true : false); + + } + + private void addPropertyDefinitions( List mapDefns, + NodeType nodetype ) { + for (PropertyDefinition defn : nodetype.getPropertyDefinitions()) { + // Don't include residual (e.g., '*') properties as columns ... + if (defn.getName().equalsIgnoreCase("*")) continue; + // Don't include multi-valued properties as columns ... + if (defn.isMultiple()) continue; + // Don't include any properties defined in the "modeint" internal namespace ... + if (defn.getName().startsWith("modeint:")) continue; + mapDefns.add(defn); + } + // All tables have these pseudo-columns ... + mapDefns.addAll(PSEUDO_COLUMN_DEFNS); + } + + protected static class PseudoPropertyDefinition implements PropertyDefinition { + + private static final String[] NO_STRINGS = new String[] {}; + private static final Value[] NO_VALUES = new Value[] {}; + + private final String[] queryOps; + private final Value[] defaultValues; + private final int requiredType; + private final String[] constraints; + private final boolean isFullTextSearchable; + private final boolean isMultiple; + private final boolean isQueryOrderable; + private final boolean isAutoCreated; + private final boolean isMandatory; + private final boolean isProtected; + private final String name; + private final NodeType declaringNodeType; + private final int onParentVersioning; + + protected PseudoPropertyDefinition( NodeType declaringNodeType, + String name, + int requiredType, + boolean autoCreated, + boolean mandatory, + boolean isProtected, + boolean multiple, + boolean fullTextSearchable, + boolean queryOrderable, + Value[] defaultValues, + String[] constraints, + int onParentVersioning, + String[] queryOps ) { + this.declaringNodeType = declaringNodeType; + this.name = name; + this.queryOps = queryOps != null ? queryOps : NO_STRINGS; + this.defaultValues = defaultValues != null ? defaultValues : NO_VALUES; + this.requiredType = requiredType; + this.constraints = constraints != null ? constraints : NO_STRINGS; + this.isFullTextSearchable = fullTextSearchable; + this.isAutoCreated = autoCreated; + this.isMultiple = multiple; + this.isQueryOrderable = queryOrderable; + this.isMandatory = mandatory; + this.isProtected = isProtected; + this.onParentVersioning = onParentVersioning; + } + + protected PseudoPropertyDefinition( NodeType declaringNodeType, + String name, + int requiredType, + boolean autoCreated, + boolean mandatory, + boolean isProtected, + boolean multiple, + boolean fullTextSearchable, + boolean queryOrderable ) { + this(declaringNodeType, name, requiredType, autoCreated, mandatory, isProtected, multiple, fullTextSearchable, + queryOrderable, null, null, OnParentVersionAction.COPY, null); + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getAvailableQueryOperators() + */ + @Override + public String[] getAvailableQueryOperators() { + return queryOps; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getDefaultValues() + */ + @Override + public Value[] getDefaultValues() { + return defaultValues; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getRequiredType() + */ + @Override + public int getRequiredType() { + return requiredType; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#getValueConstraints() + */ + @Override + public String[] getValueConstraints() { + return constraints; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#isFullTextSearchable() + */ + @Override + public boolean isFullTextSearchable() { + return isFullTextSearchable; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#isMultiple() + */ + @Override + public boolean isMultiple() { + return isMultiple; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.PropertyDefinition#isQueryOrderable() + */ + @Override + public boolean isQueryOrderable() { + return isQueryOrderable; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getDeclaringNodeType() + */ + @Override + public NodeType getDeclaringNodeType() { + return declaringNodeType; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getName() + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#getOnParentVersion() + */ + @Override + public int getOnParentVersion() { + return onParentVersioning; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated() + */ + @Override + public boolean isAutoCreated() { + return isAutoCreated; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isMandatory() + */ + @Override + public boolean isMandatory() { + return isMandatory; + } + + /** + * {@inheritDoc} + * + * @see javax.jcr.nodetype.ItemDefinition#isProtected() + */ + @Override + public boolean isProtected() { + return isProtected; + } + + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java new file mode 100644 index 0000000..37032b9 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java @@ -0,0 +1,2946 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.NClob; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import javax.jcr.ItemNotFoundException; +import javax.jcr.PathNotFoundException; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.ValueFormatException; +import javax.jcr.query.QueryResult; +import javax.jcr.query.Row; +import javax.jcr.query.RowIterator; +import org.modeshape.jdbc.util.IoUtil; +import org.modeshape.jdbc.util.TimestampWithTimezone; + +/** + * + */ +public class JcrResultSet implements ResultSet { + + private boolean closed; + private JcrStatement statement; + private QueryResult jcrResults; + private ResultSetMetaData metadata; + private RowIterator rowIter; + private Row row; + + // the object which was last read from Results + private Object currentValue = null; + + private Map columnIndexesByName; + + private String[] columnIDs = null; + + protected JcrResultSet( JcrStatement statement, + QueryResult jcrResults, + ResultSetMetaData resultSetMetaData ) throws SQLException { + this.statement = statement; + this.jcrResults = jcrResults; + assert this.statement != null; + assert this.jcrResults != null; + + if (resultSetMetaData != null) { + this.metadata = resultSetMetaData; + } else { + this.metadata = new JcrResultSetMetaData(this.statement.connection(), this.jcrResults); + } + int index = 1; // not zero-based + int colCnt = this.metadata.getColumnCount(); + + // add 1 because using 1 based location, not zero based, JDBC spec + columnIDs = new String[colCnt + 1]; + columnIndexesByName = new HashMap(colCnt); + while (index <= colCnt) { + String name = this.metadata.getColumnName(index); + columnIndexesByName.put(name, index); + columnIDs[index] = name; + index++; + } + + assert !columnIndexesByName.isEmpty(); + this.columnIndexesByName = Collections.unmodifiableMap(columnIndexesByName); + + try { + this.rowIter = this.jcrResults.getRows(); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * no-arg CTOR is used to create an empty result set + * + * @see JcrStatement#getGeneratedKeys() + */ + protected JcrResultSet() { + closed = true; + columnIndexesByName = Collections.emptyMap(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#isClosed() + */ + @Override + public boolean isClosed() { + return closed || statement.isClosed(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#close() + */ + @Override + public void close() { + if (!closed) { + closed = true; + this.statement.close(); + } + } + + byte[] convertToByteArray( final Value value ) throws SQLException { + if (value == null) return null; + InputStream is = null; + boolean error = false; + try { + switch (value.getType()) { + case PropertyType.STRING: + case PropertyType.BOOLEAN: + case PropertyType.DOUBLE: + + String v = value.getString(); + return (v != null ? v.getBytes() : null); + + case PropertyType.BINARY: + is = value.getBinary().getStream(); + return IoUtil.readBytes(is); + default: + return null; + } + + } catch (IOException ioe) { + error = true; + throw new SQLException(ioe.getLocalizedMessage(), ioe); + } catch (IllegalStateException ie) { + error = true; + throw new SQLException(ie.getLocalizedMessage(), ie); + } catch (RepositoryException e) { + error = true; + throw new SQLException(e.getLocalizedMessage(), e); + } finally { + try { + if (is != null) is.close(); + } catch (Exception e) { + if (!error) throw new SQLException(e.getLocalizedMessage(), e); + } + } + } + + protected final void notClosed() throws SQLException { + if (isClosed()) throw new SQLException(JdbcLocalI18n.resultSetIsClosed.text()); + } + + protected final void noUpdates() throws SQLException { + throw new SQLFeatureNotSupportedException(JdbcLocalI18n.updatesNotSupported.text()); + } + + protected final void forwardOnly() throws SQLException { + throw new SQLException(JdbcLocalI18n.resultSetIsForwardOnly.text()); + } + + protected final void itemNotFoundUsingColunName( String columnName ) throws SQLException { + throw new SQLException(JdbcLocalI18n.noSuchColumn.text(columnName)); + } + + protected final void itemNotFoundUsingColunIndex( int idx ) throws SQLException { + throw new SQLException(JdbcLocalI18n.noSuchColumn.text(String.valueOf(idx))); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getMetaData() + */ + @Override + public ResultSetMetaData getMetaData() throws SQLException { + notClosed(); + return metadata; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getStatement() + */ + @Override + public Statement getStatement() throws SQLException { + notClosed(); + return statement; + } + + /** + * {@inheritDoc} + *

+ * This driver only supports {@link ResultSet#TYPE_FORWARD_ONLY}. + *

+ * + * @see java.sql.ResultSet#getType() + */ + @Override + public int getType() throws SQLException { + notClosed(); + return ResultSet.TYPE_FORWARD_ONLY; + } + + /** + * {@inheritDoc} + *

+ * This driver only supports {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#getFetchDirection() + */ + @Override + public int getFetchDirection() throws SQLException { + notClosed(); + return ResultSet.FETCH_FORWARD; + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, will have no effect on the fetch direction because this driver only + * supports {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#setFetchDirection(int) + */ + @Override + public void setFetchDirection( int direction ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#absolute(int) + */ + @Override + public boolean absolute( int row ) throws SQLException { + notClosed(); + forwardOnly(); + + return false; + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#afterLast() + */ + @Override + public void afterLast() throws SQLException { + notClosed(); + forwardOnly(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#beforeFirst() + */ + @Override + public void beforeFirst() throws SQLException { + notClosed(); + forwardOnly(); + + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#cancelRowUpdates() + */ + @Override + public void cancelRowUpdates() throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#clearWarnings() + */ + @Override + public void clearWarnings() throws SQLException { + notClosed(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#deleteRow() + */ + @Override + public void deleteRow() throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#findColumn(java.lang.String) + */ + @Override + public int findColumn( String columnLabel ) throws SQLException { + notClosed(); + final Integer result = columnLabel != null ? columnIndexesByName.get(columnLabel) : null; + + if (result == null) { + this.itemNotFoundUsingColunName(columnLabel); + } + assert result != null; + return result.intValue(); + } + + private String findColumn( int columnIndex ) throws SQLException { + if (columnIndex > 0 && columnIndex < this.columnIDs.length) { + return columnIDs[columnIndex]; + } + + throw new SQLException(JdbcLocalI18n.invalidColumnIndex.text(new Object[] {columnIndex, this.columnIDs.length})); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#first() + */ + @Override + public boolean first() throws SQLException { + notClosed(); + forwardOnly(); + + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getRow() + */ + @Override + public int getRow() throws SQLException { + notClosed(); + return (int)this.rowIter.getPosition(); + } + + /** + * {@inheritDoc} + *

+ * This method will always throw {@link SQLFeatureNotSupportedException} + *

+ * + * @see java.sql.ResultSet#getRowId(int) + */ + @Override + public RowId getRowId( final int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getRowId(java.lang.String) + */ + @Override + public RowId getRowId( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getCursorName() + */ + @Override + public String getCursorName() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getFetchSize() + */ + @Override + public int getFetchSize() throws SQLException { + notClosed(); + return statement.getFetchSize(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getArray(int) + */ + @Override + public Array getArray( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getArray(java.lang.String) + */ + @Override + public Array getArray( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getAsciiStream(int) + */ + @Override + public InputStream getAsciiStream( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getAsciiStream(java.lang.String) + */ + @Override + public InputStream getAsciiStream( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBigDecimal(int) + */ + @Override + public BigDecimal getBigDecimal( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBigDecimal(java.lang.String) + */ + @Override + public BigDecimal getBigDecimal( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBigDecimal(int, int) + */ + @Override + public BigDecimal getBigDecimal( int columnIndex, + int scale ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBigDecimal(java.lang.String, int) + */ + @Override + public BigDecimal getBigDecimal( String columnLabel, + int scale ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBinaryStream(int) + */ + @Override + public InputStream getBinaryStream( int columnIndex ) throws SQLException { + return getBinaryStream(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBinaryStream(java.lang.String) + */ + @Override + public InputStream getBinaryStream( String columnLabel ) throws SQLException { + Object o = getValueReturn(columnLabel, PropertyType.BINARY); + if (o != null) { + return (InputStream)o; + } + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBlob(int) + */ + @Override + public Blob getBlob( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBlob(java.lang.String) + */ + @Override + public Blob getBlob( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBoolean(int) + */ + @Override + public boolean getBoolean( int columnIndex ) throws SQLException { + return getBoolean(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBoolean(java.lang.String) + */ + @Override + public boolean getBoolean( String columnLabel ) throws SQLException { + + Object o = getValueReturn(columnLabel, PropertyType.BOOLEAN); + if (o != null) { + return ((Boolean)o).booleanValue(); + } + return Boolean.FALSE.booleanValue(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getByte(int) + */ + @Override + public byte getByte( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getByte(java.lang.String) + */ + @Override + public byte getByte( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBytes(int) + */ + @Override + public byte[] getBytes( int columnIndex ) throws SQLException { + return getBytes(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getBytes(java.lang.String) + */ + @Override + public byte[] getBytes( String columnLabel ) throws SQLException { + notClosed(); + isRowSet(); + + this.currentValue = null; + try { + Value value = row.getValue(columnLabel); + byte[] rtnbytes = convertToByteArray(value); + this.currentValue = rtnbytes; + return rtnbytes; + } catch (PathNotFoundException pnfe) { + // do nothing, return null + } catch (ItemNotFoundException e) { + itemNotFoundUsingColunName(columnLabel); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getCharacterStream(int) + */ + @Override + public Reader getCharacterStream( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getCharacterStream(java.lang.String) + */ + @Override + public Reader getCharacterStream( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getClob(int) + */ + @Override + public Clob getClob( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getClob(java.lang.String) + */ + @Override + public Clob getClob( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getConcurrency() + */ + @Override + public int getConcurrency() throws SQLException { + notClosed(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDate(int) + */ + @Override + public Date getDate( int columnIndex ) throws SQLException { + return getDate(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDate(java.lang.String) + */ + @Override + public Date getDate( String columnLabel ) throws SQLException { + Calendar calv = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + if (calv == null) return null; + + return TimestampWithTimezone.createDate(calv.getTime()); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDate(int, java.util.Calendar) + */ + @Override + public Date getDate( int columnIndex, + Calendar cal ) throws SQLException { + return getDate(findColumn(columnIndex), cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDate(java.lang.String, java.util.Calendar) + */ + @Override + public Date getDate( String columnLabel, + Calendar cal ) throws SQLException { + + Calendar actual = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + + if (actual == null) return null; + + java.util.Date actualDate = actual.getTime(); + java.util.TimeZone actualTz = actual.getTimeZone(); + + // if cal is null, it will be supplied in TimestampWithTimezone + return TimestampWithTimezone.createDate(actualDate, actualTz, cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDouble(int) + */ + @Override + public double getDouble( int columnIndex ) throws SQLException { + return getDouble(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getDouble(java.lang.String) + */ + @Override + public double getDouble( String columnLabel ) throws SQLException { + Object o = getValueReturn(columnLabel, PropertyType.DOUBLE); + if (o != null) { + return ((Double)o).doubleValue(); + } + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getFloat(int) + */ + @Override + public float getFloat( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getFloat(java.lang.String) + */ + @Override + public float getFloat( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * According to 1.6 javadocs, holdability should be set to either {@link ResultSet#CLOSE_CURSORS_AT_COMMIT} or + * {@link ResultSet#HOLD_CURSORS_OVER_COMMIT}. However, JDBC 4.0 spec says the default holdability is implementation defined. + * Therefore, the default value will be 0. + * + * @see java.sql.ResultSet#getHoldability() + */ + @Override + public int getHoldability() throws SQLException { + notClosed(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getInt(int) + */ + @Override + public int getInt( int columnIndex ) throws SQLException { + return getInt(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getInt(java.lang.String) + */ + @Override + public int getInt( String columnLabel ) throws SQLException { + notClosed(); + return (int)getLong(columnLabel); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getLong(int) + */ + @Override + public long getLong( int columnIndex ) throws SQLException { + return getLong(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getLong(java.lang.String) + */ + @Override + public long getLong( String columnLabel ) throws SQLException { + Object o = getValueReturn(columnLabel, PropertyType.LONG); + if (o != null) { + return ((Long)o).longValue(); + } + return 0L; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNCharacterStream(int) + */ + @Override + public Reader getNCharacterStream( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNCharacterStream(java.lang.String) + */ + @Override + public Reader getNCharacterStream( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNClob(int) + */ + @Override + public NClob getNClob( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNClob(java.lang.String) + */ + @Override + public NClob getNClob( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNString(int) + */ + @Override + public String getNString( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getNString(java.lang.String) + * @throws SQLFeatureNotSupportedException(); + */ + @Override + public String getNString( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getObject(int) + */ + @Override + public Object getObject( int columnIndex ) throws SQLException { + return getObject(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getObject(java.lang.String) + */ + @Override + public Object getObject( String columnLabel ) throws SQLException { + return getColumnTranslatedToJDBC(columnLabel); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getObject(int, java.util.Map) + */ + @Override + public Object getObject( int columnIndex, + Map> map ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getObject(java.lang.String, java.util.Map) + */ + @Override + public Object getObject( String columnLabel, + Map> map ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getRef(int) + */ + @Override + public Ref getRef( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getRef(java.lang.String) + */ + @Override + public Ref getRef( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getSQLXML(int) + */ + @Override + public SQLXML getSQLXML( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getSQLXML(java.lang.String) + */ + @Override + public SQLXML getSQLXML( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getShort(int) + */ + @Override + public short getShort( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getShort(java.lang.String) + */ + @Override + public short getShort( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getString(int) + */ + @Override + public String getString( int columnIndex ) throws SQLException { + return getString(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getString(java.lang.String) + */ + @Override + public String getString( String columnLabel ) throws SQLException { + Object o = getValueReturn(columnLabel, PropertyType.STRING); + if (o != null) { + return (String)o; + } + return null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTime(int) + */ + @Override + public Time getTime( int columnIndex ) throws SQLException { + return getTime(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTime(java.lang.String) + */ + @Override + public Time getTime( String columnLabel ) throws SQLException { + Calendar calv = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + if (calv == null) return null; + return TimestampWithTimezone.createTime(calv.getTime()); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTime(int, java.util.Calendar) + */ + @Override + public Time getTime( int columnIndex, + Calendar cal ) throws SQLException { + return getTime(findColumn(columnIndex), cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTime(java.lang.String, java.util.Calendar) + */ + @Override + public Time getTime( String columnLabel, + Calendar cal ) throws SQLException { + + Calendar actual = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + + if (actual == null) return null; + + java.util.Date actualDate = actual.getTime(); + java.util.TimeZone actualTz = actual.getTimeZone(); + + // if cal is null, it will be supplied in TimestampWithTimezone + return TimestampWithTimezone.createTime(actualDate, actualTz, cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTimestamp(int) + */ + @Override + public Timestamp getTimestamp( int columnIndex ) throws SQLException { + return getTimestamp(findColumn(columnIndex)); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTimestamp(java.lang.String) + */ + @Override + public Timestamp getTimestamp( String columnLabel ) throws SQLException { + Calendar calv = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + if (calv == null) return null; + return TimestampWithTimezone.createTimestamp(calv.getTime()); + + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTimestamp(int, java.util.Calendar) + */ + @Override + public Timestamp getTimestamp( int columnIndex, + Calendar cal ) throws SQLException { + return getTimestamp(findColumn(columnIndex), cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getTimestamp(java.lang.String, java.util.Calendar) + */ + @Override + public Timestamp getTimestamp( String columnLabel, + Calendar cal ) throws SQLException { + + Calendar actual = (Calendar)getValueReturn(columnLabel, PropertyType.DATE); + + if (actual == null) return null; + + java.util.Date actualDate = actual.getTime(); + java.util.TimeZone actualTz = actual.getTimeZone(); + + // if cal is null, it will be supplied in TimestampWithTimezone + return TimestampWithTimezone.createTimestamp(actualDate, actualTz, cal); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getURL(int) + */ + @Override + public URL getURL( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getURL(java.lang.String) + */ + @Override + public URL getURL( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getUnicodeStream(int) + */ + @Override + public InputStream getUnicodeStream( int columnIndex ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getUnicodeStream(java.lang.String) + */ + @Override + public InputStream getUnicodeStream( String columnLabel ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + public Value getValue( int columnIndex ) throws SQLException { + return getValue(findColumn(columnIndex)); + + } + + public Value getValue( String columnLabel ) throws SQLException { + notClosed(); + isRowSet(); + + try { + return row.getValue(columnLabel); + } catch (PathNotFoundException pnfe) { + return null; + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + + } + + /** + * This is called when the calling method controls what datatype to be returned. Another reason for centralizing this logic so + * that the {@link #currentValue} can be maintained + * + * @param columnName + * @param type is the {@link PropertyType datatype} to be returned + * @return Object + * @throws SQLException + */ + private Object getValueReturn( String columnName, + int type ) throws SQLException { + notClosed(); + isRowSet(); + + this.currentValue = null; + try { + + final Value value = row.getValue(columnName); + this.currentValue = getValueObject(value, type); + + } catch (PathNotFoundException pnfe) { + // do nothing + } catch (ItemNotFoundException e) { + itemNotFoundUsingColunName(columnName); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + return this.currentValue; + } + + /** + * Helper method for returning an object from value based on type + * + * @param value + * @param type indicates {@link PropertyType} used to derive return object type + * @return Object + * @throws SQLException + */ + private Object getValueObject( Value value, + int type ) throws SQLException { + if (value == null) return null; + + try { + switch (type) { + + case PropertyType.STRING: + return value.getString(); + case PropertyType.BOOLEAN: + return value.getBoolean(); + case PropertyType.DATE: + // return new java.sql.Date(value.getDate().getTime().getTime()); + return value.getDate(); + case PropertyType.DOUBLE: + return value.getDouble(); + case PropertyType.LONG: + return value.getLong(); + case PropertyType.BINARY: + return value.getBinary().getStream(); + } + + } catch (ValueFormatException ve) { + throw new SQLException(ve.getLocalizedMessage(), ve); + } catch (IllegalStateException ie) { + throw new SQLException(ie.getLocalizedMessage(), ie); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + return value.toString(); + } + + /** + * This method transforms a {@link Value} into a JDBC type based on {@link JcrType} mappings + * + * @param columnName + * @return Object + * @throws SQLException + */ + private Object getColumnTranslatedToJDBC( String columnName ) throws SQLException { + notClosed(); + isRowSet(); + + Value value = null; + this.currentValue = null; + + try { + value = row.getValue(columnName); + } catch (javax.jcr.PathNotFoundException pnf) { + // do nothing + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + + if (value == null) return null; + + this.currentValue = JcrType.translateValueToJDBC(value); + return this.currentValue; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#getWarnings() + */ + @Override + public SQLWarning getWarnings() /*throws SQLException*/{ + return null; + } + + protected boolean hasNext() { + return rowIter.hasNext(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#insertRow() + */ + @Override + public void insertRow() throws SQLException { + this.notClosed(); + this.noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#isAfterLast() + */ + @Override + public boolean isAfterLast() throws SQLException { + this.notClosed(); + if (this.row == null && !this.rowIter.hasNext() && this.rowIter.getPosition() == this.rowIter.getSize()) { + return true; + } + return false; + + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#isBeforeFirst() + */ + @Override + public boolean isBeforeFirst() throws SQLException { + this.notClosed(); + if (this.rowIter.getPosition() == 0) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#isFirst() + */ + @Override + public boolean isFirst() throws SQLException { + this.notClosed(); + if (this.rowIter.getPosition() == 1) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#isLast() + */ + @Override + public boolean isLast() throws SQLException { + this.notClosed(); + + if (this.row != null && !this.rowIter.hasNext() && this.rowIter.getPosition() == this.rowIter.getSize()) { + return true; + } + return false; + } + + protected final void isRowSet() throws SQLException { + if (this.row != null) return; + + throw new SQLException(JdbcLocalI18n.currentRowNotSet.text()); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#last() + */ + @Override + public boolean last() throws SQLException { + notClosed(); + forwardOnly(); + return false; + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#moveToCurrentRow() + */ + @Override + public void moveToCurrentRow() throws SQLException { + notClosed(); + forwardOnly(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#moveToInsertRow() + */ + @Override + public void moveToInsertRow() throws SQLException { + this.noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when cursor position is after the last row, will return false + *

+ * + * @see java.sql.ResultSet#next() + */ + @Override + public boolean next() throws SQLException { + notClosed(); + if (!this.hasNext()) { + this.row = null; + this.currentValue = null; + return false; + } + + this.row = rowIter.nextRow(); + return true; + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#previous() + */ + @Override + public boolean previous() throws SQLException { + notClosed(); + this.forwardOnly(); + return false; + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#refreshRow() + */ + @Override + public void refreshRow() throws SQLException { + notClosed(); + this.forwardOnly(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLException} because this driver only supports + * {@link ResultSet#FETCH_FORWARD}. + *

+ * + * @see java.sql.ResultSet#relative(int) + */ + @Override + public boolean relative( int rows ) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method always returns false since this JDBC driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#rowDeleted() + */ + @Override + public boolean rowDeleted() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method always returns false since this JDBC driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#rowInserted() + */ + @Override + public boolean rowInserted() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + *

+ * This method always returns false since this JDBC driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#rowUpdated() + */ + @Override + public boolean rowUpdated() throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#setFetchSize(int) + */ + @Override + public void setFetchSize( int rows ) /*throws SQLException*/{ + // does nothing + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateArray(int, java.sql.Array) + */ + @Override + public void updateArray( int columnIndex, + Array x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateArray(java.lang.String, java.sql.Array) + */ + @Override + public void updateArray( String columnLabel, + Array x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(int, java.io.InputStream) + */ + @Override + public void updateAsciiStream( int columnIndex, + InputStream x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(java.lang.String, java.io.InputStream) + */ + @Override + public void updateAsciiStream( String columnLabel, + InputStream x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(int, java.io.InputStream, int) + */ + @Override + public void updateAsciiStream( int columnIndex, + InputStream x, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(java.lang.String, java.io.InputStream, int) + */ + @Override + public void updateAsciiStream( String columnLabel, + InputStream x, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(int, java.io.InputStream, long) + */ + @Override + public void updateAsciiStream( int columnIndex, + InputStream x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateAsciiStream(java.lang.String, java.io.InputStream, long) + */ + @Override + public void updateAsciiStream( String columnLabel, + InputStream x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBigDecimal(int, java.math.BigDecimal) + */ + @Override + public void updateBigDecimal( int columnIndex, + BigDecimal x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBigDecimal(java.lang.String, java.math.BigDecimal) + */ + @Override + public void updateBigDecimal( String columnLabel, + BigDecimal x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(int, java.io.InputStream) + */ + @Override + public void updateBinaryStream( int columnIndex, + InputStream x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(java.lang.String, java.io.InputStream) + */ + @Override + public void updateBinaryStream( String columnLabel, + InputStream x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(int, java.io.InputStream, int) + */ + @Override + public void updateBinaryStream( int columnIndex, + InputStream x, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(java.lang.String, java.io.InputStream, int) + */ + @Override + public void updateBinaryStream( String columnLabel, + InputStream x, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(int, java.io.InputStream, long) + */ + @Override + public void updateBinaryStream( int columnIndex, + InputStream x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBinaryStream(java.lang.String, java.io.InputStream, long) + */ + @Override + public void updateBinaryStream( String columnLabel, + InputStream x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(int, java.sql.Blob) + */ + @Override + public void updateBlob( int columnIndex, + Blob x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(java.lang.String, java.sql.Blob) + */ + @Override + public void updateBlob( String columnLabel, + Blob x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(int, java.io.InputStream) + */ + @Override + public void updateBlob( int columnIndex, + InputStream inputStream ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(java.lang.String, java.io.InputStream) + */ + @Override + public void updateBlob( String columnLabel, + InputStream inputStream ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(int, java.io.InputStream, long) + */ + @Override + public void updateBlob( int columnIndex, + InputStream inputStream, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBlob(java.lang.String, java.io.InputStream, long) + */ + @Override + public void updateBlob( String columnLabel, + InputStream inputStream, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBoolean(int, boolean) + */ + @Override + public void updateBoolean( int columnIndex, + boolean x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBoolean(java.lang.String, boolean) + */ + @Override + public void updateBoolean( String columnLabel, + boolean x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateByte(int, byte) + */ + @Override + public void updateByte( int columnIndex, + byte x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateByte(java.lang.String, byte) + */ + @Override + public void updateByte( String columnLabel, + byte x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBytes(int, byte[]) + */ + @Override + public void updateBytes( int columnIndex, + byte[] x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateBytes(java.lang.String, byte[]) + */ + @Override + public void updateBytes( String columnLabel, + byte[] x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(int, java.io.Reader) + */ + @Override + public void updateCharacterStream( int columnIndex, + Reader x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(java.lang.String, java.io.Reader) + */ + @Override + public void updateCharacterStream( String columnLabel, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(int, java.io.Reader, int) + */ + @Override + public void updateCharacterStream( int columnIndex, + Reader x, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(java.lang.String, java.io.Reader, int) + */ + @Override + public void updateCharacterStream( String columnLabel, + Reader reader, + int length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(int, java.io.Reader, long) + */ + @Override + public void updateCharacterStream( int columnIndex, + Reader x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateCharacterStream(java.lang.String, java.io.Reader, long) + */ + @Override + public void updateCharacterStream( String columnLabel, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(int, java.sql.Clob) + */ + @Override + public void updateClob( int columnIndex, + Clob x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(java.lang.String, java.sql.Clob) + */ + @Override + public void updateClob( String columnLabel, + Clob x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(int, java.io.Reader) + */ + @Override + public void updateClob( int columnIndex, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(java.lang.String, java.io.Reader) + */ + @Override + public void updateClob( String columnLabel, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(int, java.io.Reader, long) + */ + @Override + public void updateClob( int columnIndex, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateClob(java.lang.String, java.io.Reader, long) + */ + @Override + public void updateClob( String columnLabel, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateDate(int, java.sql.Date) + */ + @Override + public void updateDate( int columnIndex, + Date x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateDate(java.lang.String, java.sql.Date) + */ + @Override + public void updateDate( String columnLabel, + Date x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateDouble(int, double) + */ + @Override + public void updateDouble( int columnIndex, + double x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateDouble(java.lang.String, double) + */ + @Override + public void updateDouble( String columnLabel, + double x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateFloat(int, float) + */ + @Override + public void updateFloat( int columnIndex, + float x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateFloat(java.lang.String, float) + */ + @Override + public void updateFloat( String columnLabel, + float x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateInt(int, int) + */ + @Override + public void updateInt( int columnIndex, + int x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateInt(java.lang.String, int) + */ + @Override + public void updateInt( String columnLabel, + int x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateLong(int, long) + */ + @Override + public void updateLong( int columnIndex, + long x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateLong(java.lang.String, long) + */ + @Override + public void updateLong( String columnLabel, + long x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNCharacterStream(int, java.io.Reader) + */ + @Override + public void updateNCharacterStream( int columnIndex, + Reader x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNCharacterStream(java.lang.String, java.io.Reader) + */ + @Override + public void updateNCharacterStream( String columnLabel, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNCharacterStream(int, java.io.Reader, long) + */ + @Override + public void updateNCharacterStream( int columnIndex, + Reader x, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNCharacterStream(java.lang.String, java.io.Reader, long) + */ + @Override + public void updateNCharacterStream( String columnLabel, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(int, java.sql.NClob) + */ + @Override + public void updateNClob( int columnIndex, + NClob clob ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(java.lang.String, java.sql.NClob) + */ + @Override + public void updateNClob( String columnLabel, + NClob clob ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(int, java.io.Reader) + */ + @Override + public void updateNClob( int columnIndex, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(java.lang.String, java.io.Reader) + */ + @Override + public void updateNClob( String columnLabel, + Reader reader ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(int, java.io.Reader, long) + */ + @Override + public void updateNClob( int columnIndex, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNClob(java.lang.String, java.io.Reader, long) + */ + @Override + public void updateNClob( String columnLabel, + Reader reader, + long length ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNString(int, java.lang.String) + */ + @Override + public void updateNString( int columnIndex, + String string ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNString(java.lang.String, java.lang.String) + */ + @Override + public void updateNString( String columnLabel, + String string ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNull(int) + */ + @Override + public void updateNull( int columnIndex ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateNull(java.lang.String) + */ + @Override + public void updateNull( String columnLabel ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateObject(int, java.lang.Object) + */ + @Override + public void updateObject( int columnIndex, + Object x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateObject(java.lang.String, java.lang.Object) + */ + @Override + public void updateObject( String columnLabel, + Object x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateObject(int, java.lang.Object, int) + */ + @Override + public void updateObject( int columnIndex, + Object x, + int scaleOrLength ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateObject(java.lang.String, java.lang.Object, int) + */ + @Override + public void updateObject( String columnLabel, + Object x, + int scaleOrLength ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateRef(int, java.sql.Ref) + */ + @Override + public void updateRef( int columnIndex, + Ref x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateRef(java.lang.String, java.sql.Ref) + */ + @Override + public void updateRef( String columnLabel, + Ref x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateRow() + */ + @Override + public void updateRow() throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateRowId(int, java.sql.RowId) + */ + @Override + public void updateRowId( int columnIndex, + RowId x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateRowId(java.lang.String, java.sql.RowId) + */ + @Override + public void updateRowId( String columnLabel, + RowId x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateSQLXML(int, java.sql.SQLXML) + */ + @Override + public void updateSQLXML( int columnIndex, + SQLXML xmlObject ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateSQLXML(java.lang.String, java.sql.SQLXML) + */ + @Override + public void updateSQLXML( String columnLabel, + SQLXML xmlObject ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateShort(int, short) + */ + @Override + public void updateShort( int columnIndex, + short x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateShort(java.lang.String, short) + */ + @Override + public void updateShort( String columnLabel, + short x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateString(int, java.lang.String) + */ + @Override + public void updateString( int columnIndex, + String x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateString(java.lang.String, java.lang.String) + */ + @Override + public void updateString( String columnLabel, + String x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateTime(int, java.sql.Time) + */ + @Override + public void updateTime( int columnIndex, + Time x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateTime(java.lang.String, java.sql.Time) + */ + @Override + public void updateTime( String columnLabel, + Time x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateTimestamp(int, java.sql.Timestamp) + */ + @Override + public void updateTimestamp( int columnIndex, + Timestamp x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + *

+ * This method, when called on an open result set, always throws {@link SQLFeatureNotSupportedException} since this JDBC + * driver does not support any updates. + *

+ * + * @see java.sql.ResultSet#updateTimestamp(java.lang.String, java.sql.Timestamp) + */ + @Override + public void updateTimestamp( String columnLabel, + Timestamp x ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSet#wasNull() + */ + @Override + public boolean wasNull() throws SQLException { + notClosed(); + + return currentValue == null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) { + return iface.isInstance(this); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text()); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSetMetaData.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSetMetaData.java new file mode 100644 index 0000000..1016b82 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSetMetaData.java @@ -0,0 +1,392 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Types; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.PropertyDefinition; +import javax.jcr.query.QueryResult; + +/** + * This driver's {@link ResultSetMetaData} implementation that obtains the metadata information from the JCR query result and + * (where possible) the column's corresponding property definitions. + */ +public class JcrResultSetMetaData implements ResultSetMetaData { + + private final JcrConnection connection; + private final QueryResult results; + private int[] nullable; + + protected JcrResultSetMetaData( JcrConnection connection, + QueryResult results ) { + this.connection = connection; + this.results = results; + } + + /** + * {@inheritDoc} + *

+ * All columns come from the same repository (i.e., catalog). + *

+ * + * @see java.sql.ResultSetMetaData#getCatalogName(int) + */ + @Override + public String getCatalogName( int column ) { + return connection.info().getRepositoryName(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnClassName(int) + */ + @Override + public String getColumnClassName( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + return typeInfo != null ? typeInfo.getRepresentationClass().getName() : String.class.getName(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnCount() + */ + @Override + public int getColumnCount() throws SQLException { + try { + return results.getColumnNames().length; + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + *

+ * This method returns the nominal display size based upon the column's type. Therefore, the value may not reflect the optimal + * display size for any given value. + *

+ * + * @see java.sql.ResultSetMetaData#getColumnDisplaySize(int) + */ + @Override + public int getColumnDisplaySize( int column ) { + return JcrType.typeInfo(getColumnTypeName(column)).getNominalDisplaySize(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnLabel(int) + */ + @Override + public String getColumnLabel( int column ) throws SQLException { + try { + return results.getColumnNames()[column - 1]; // column value is 1-based + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnName(int) + */ + @Override + public String getColumnName( int column ) throws SQLException { + return getColumnLabel(column); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnType(int) + */ + @Override + public int getColumnType( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + return typeInfo != null ? typeInfo.getJdbcType() : Types.VARCHAR; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getColumnTypeName(int) + */ + @Override + public String getColumnTypeName( int column ) { + if (results instanceof org.modeshape.jcr.api.query.QueryResult) { + return ((org.modeshape.jcr.api.query.QueryResult)results).getColumnTypes()[column - 1]; // column value is 1-based + } + return PropertyType.nameFromValue(PropertyType.STRING); + } + + /** + * {@inheritDoc} + *

+ * This method always returns the nominal display size for the type. + *

+ * + * @see java.sql.ResultSetMetaData#getPrecision(int) + */ + @Override + public int getPrecision( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + return typeInfo.getNominalDisplaySize(); + } + + /** + * {@inheritDoc} + *

+ * This method returns the number of digits behind the decimal point, which is assumed to be 3 if the type is + * {@link PropertyType#DOUBLE} or 0 otherwise. + *

+ * + * @see java.sql.ResultSetMetaData#getScale(int) + */ + @Override + public int getScale( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + if (typeInfo.getJcrType() == PropertyType.DOUBLE) { + return 3; // pulled from thin air + } + return 0; + } + + /** + * {@inheritDoc} + *

+ * This method always returns the workspace name. + *

+ * + * @see java.sql.ResultSetMetaData#getSchemaName(int) + */ + @Override + public String getSchemaName( int column ) { + return connection.info().getWorkspaceName(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#getTableName(int) + */ + @Override + public String getTableName( int column ) throws SQLException { + try { + return results.getSelectorNames()[column - 1]; // column value is 1-based + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + *

+ * This method always returns false, since this JCR property types don't represent auto-incremented values. + *

+ * + * @see java.sql.ResultSetMetaData#isAutoIncrement(int) + */ + @Override + public boolean isAutoIncrement( int column ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#isCaseSensitive(int) + */ + @Override + public boolean isCaseSensitive( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + return typeInfo.isCaseSensitive(); + } + + /** + * {@inheritDoc} + *

+ * This method always returns false, since no JCR property types (directly) represent currency. + *

+ * + * @see java.sql.ResultSetMetaData#isCurrency(int) + */ + @Override + public boolean isCurrency( int column ) { + return false; + } + + /** + * {@inheritDoc} + *

+ * This method always returns false, since this JDBC driver does not support writes. + *

+ * + * @see java.sql.ResultSetMetaData#isDefinitelyWritable(int) + */ + @Override + public boolean isDefinitelyWritable( int column ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.ResultSetMetaData#isNullable(int) + */ + @Override + public int isNullable( int column ) throws SQLException { + if (nullable == null) { + int length = getColumnCount(); + nullable = new int[length]; + for (int i = 0; i != length; ++i) { + nullable[i] = -1; + } + } else { + int result = nullable[column - 1]; + if (result != -1) { + // Already found this value, so return it ... + return result; + } + } + // Find the node type for the column (given that the column name is the property name and + // the table name is the node type), and determine if the property definition is multi-valued or not mandatory. + String nodeTypeName = getTableName(column); + if (nodeTypeName.length() == 0) { + // There is no table for the column, so therefore we don't know the node type ... + return ResultSetMetaData.columnNullableUnknown; + } + String propertyName = getColumnName(column); + boolean singleProp = false; + boolean singleResidual = false; + boolean multiResidual = false; + NodeType type = connection.nodeType(nodeTypeName); + for (PropertyDefinition defn : type.getPropertyDefinitions()) { + if (defn.getName().equals(propertyName)) { + if (defn.isMultiple() || defn.isMandatory()) { + // We know this IS nullable + return ResultSetMetaData.columnNullable; + } + // Otherwise this is a single-valued property that is mandatory, + // but we can't return columnNotNullable because we may not have found the multi-valued property ... + singleProp = true; + } else if (defn.getName().equals("*")) { // Residual + if (defn.isMultiple() || defn.isMandatory()) multiResidual = true; + else singleResidual = true; + } + } + int result = ResultSetMetaData.columnNullableUnknown; + if (multiResidual) result = ResultSetMetaData.columnNullable; + else if (singleProp || singleResidual) result = ResultSetMetaData.columnNoNulls; + nullable[column - 1] = result; + return result; + } + + /** + * {@inheritDoc} + *

+ * Even though the value may be writable in the JCR repository, this JDBC driver does not support writes. Therefore, this + * method always returns true. + *

+ * + * @see java.sql.ResultSetMetaData#isReadOnly(int) + */ + @Override + public boolean isReadOnly( int column ) { + return true; + } + + /** + * {@inheritDoc} + *

+ * In JCR-SQL2, every property can be used in a WHERE clause. Therefore, this method always returns true. + *

+ * + * @see java.sql.ResultSetMetaData#isSearchable(int) + */ + @Override + public boolean isSearchable( int column ) { + return true; + } + + /** + * {@inheritDoc} + *

+ * This method returns true if the column is a {@link PropertyType#DOUBLE}, {@link PropertyType#LONG} or + * {@link PropertyType#DATE}. + *

+ * + * @see java.sql.ResultSetMetaData#isSigned(int) + */ + @Override + public boolean isSigned( int column ) { + JcrType typeInfo = JcrType.typeInfo(getColumnTypeName(column)); + return typeInfo.isSigned(); + } + + /** + * {@inheritDoc} + *

+ * Even though the value may be writable in the JCR repository, this JDBC driver does not support writes. Therefore, this + * method always returns false. + *

+ * + * @see java.sql.ResultSetMetaData#isWritable(int) + */ + @Override + public boolean isWritable( int column ) { + return false; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) /*throws SQLException*/{ + return iface.isInstance(results); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (iface.isInstance(results)) { + return iface.cast(results); + } + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(ResultSetMetaData.class.getSimpleName(), + iface.getName())); + } +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrRowId.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrRowId.java new file mode 100644 index 0000000..b94b3e9 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrRowId.java @@ -0,0 +1,55 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.sql.RowId; + +/** + * + */ +public class JcrRowId implements RowId { + + private final String path; + private final byte[] bytes; + + public JcrRowId( String path ) { + this.path = path; + this.bytes = path.getBytes(); // don't make a copy + } + + public String getPath() { + return path; + } + + /** + * {@inheritDoc} + * + * @see java.sql.RowId#getBytes() + */ + @Override + public byte[] getBytes() { + return bytes; + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrStatement.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrStatement.java new file mode 100644 index 0000000..1bcf8e7 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrStatement.java @@ -0,0 +1,606 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +import java.sql.Statement; +import javax.jcr.RepositoryException; +import javax.jcr.query.QueryResult; +import org.modeshape.jdbc.delegate.RepositoryDelegate; + +/** + * + */ +class JcrStatement implements Statement { + + private final JcrConnection connection; + private ResultSet results; + private boolean closed; + private SQLWarning warning; + private int rowLimit = -1; + private int fetchDirection = ResultSet.FETCH_FORWARD; + private boolean poolable; + private int moreResults = 0; + + private String sqlLanguage = JcrConnection.JCR_SQL2; + + JcrStatement( JcrConnection connection ) { + this.connection = connection; + assert this.connection != null; + } + + JcrConnection connection() { + return this.connection; + } + + public void setJcrSqlLanguage( String jcrSQL ) { + this.sqlLanguage = (jcrSQL != null ? jcrSQL : JcrConnection.JCR_SQL2); + } + + /** + * {@inheritDoc} + *

+ * This driver doesn't have a way to set the fetch size, so this method always returns 0. + *

+ * + * @see java.sql.Statement#getFetchSize() + */ + @Override + public int getFetchSize() throws SQLException { + notClosed(); + return 0; + } + + /** + * {@inheritDoc} + *

+ * This driver doesn't have a way to set the fetch size, so this method is ignored and does nothing. + *

+ * + * @see java.sql.Statement#setFetchSize(int) + */ + @Override + public void setFetchSize( int rows ) throws SQLException { + notClosed(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getFetchDirection() + */ + @Override + public int getFetchDirection() throws SQLException { + notClosed(); + return fetchDirection; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setFetchDirection(int) + */ + @Override + public void setFetchDirection( int direction ) throws SQLException { + notClosed(); + if (direction != ResultSet.FETCH_FORWARD && direction != ResultSet.FETCH_REVERSE && direction != ResultSet.FETCH_UNKNOWN) { + throw new SQLException(JdbcLocalI18n.invalidArgument.text(direction, "" + ResultSet.FETCH_FORWARD + ", " + + ResultSet.FETCH_REVERSE + ", " + + ResultSet.FETCH_UNKNOWN)); + } + fetchDirection = direction; + } + + /** + * {@inheritDoc} + *

+ * This driver does not support limiting the field size, and always returns 0. + *

+ * + * @see java.sql.Statement#getMaxFieldSize() + */ + @Override + public int getMaxFieldSize() throws SQLException { + notClosed(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setMaxFieldSize(int) + */ + @Override + public void setMaxFieldSize( int max ) throws SQLException { + notClosed(); + if (max < 0) { + throw new SQLException(JdbcLocalI18n.argumentMayNotBeNegative.text("max", max)); + } + // ignored otherwise + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getMaxRows() + */ + @Override + public int getMaxRows() throws SQLException { + notClosed(); + // need to map ModeShapes -1 rowLimit to 0 + // because the jdbc spec indicate maxRows must be >= 0 + // or an exception should be thrown. + return (rowLimit == -1 ? 0 : rowLimit); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setMaxRows(int) + */ + @Override + public void setMaxRows( int max ) throws SQLException { + notClosed(); + if (max < 0) { + throw new SQLException(JdbcLocalI18n.argumentMayNotBeNegative.text("max", max)); + } + rowLimit = max; + } + + /** + * {@inheritDoc} + *

+ * This method returns 0 since there is currently no timeout with JCR 1.0 or JCR 2.0. + *

+ * + * @see java.sql.Statement#getQueryTimeout() + */ + @Override + public int getQueryTimeout() throws SQLException { + notClosed(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setQueryTimeout(int) + */ + @Override + public void setQueryTimeout( int seconds ) throws SQLException { + notClosed(); + if (seconds < 0) { + throw new SQLException(JdbcLocalI18n.argumentMayNotBeNegative.text("seconds", seconds)); + } + // Otherwise ignore + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#isPoolable() + */ + @Override + public boolean isPoolable() throws SQLException { + notClosed(); + return poolable; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setPoolable(boolean) + */ + @Override + public void setPoolable( boolean poolable ) throws SQLException { + notClosed(); + this.poolable = poolable; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getConnection() + */ + @Override + public Connection getConnection() throws SQLException { + notClosed(); + return connection; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#cancel() + */ + @Override + public void cancel() throws SQLException { + notClosed(); + close(); + // Unable to cancel a JCR query ... + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#clearWarnings() + */ + @Override + public void clearWarnings() throws SQLException { + notClosed(); + warning = null; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getWarnings() + */ + @Override + public SQLWarning getWarnings() throws SQLException { + notClosed(); + return warning; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#isClosed() + */ + @Override + public boolean isClosed() { + return closed || connection.isClosed(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#close() + */ + @Override + public void close() { + if (!closed) { + closed = true; + connection.getRepositoryDelegate().closeStatement(); + } + } + + protected final void notClosed() throws SQLException { + if (isClosed()) throw new SQLException(JdbcLocalI18n.statementIsClosed.text()); + } + + protected final void noUpdates() throws SQLException { + throw new SQLException(JdbcLocalI18n.updatesNotSupported.text()); + } + + // ---------------------------------------------------------------------------------------------------------------- + // Updates + // ---------------------------------------------------------------------------------------------------------------- + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeUpdate(java.lang.String) + */ + @Override + public int executeUpdate( String sql ) throws SQLException { + notClosed(); + noUpdates(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeUpdate(java.lang.String, int) + */ + @Override + public int executeUpdate( String sql, + int autoGeneratedKeys ) throws SQLException { + notClosed(); + noUpdates(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeUpdate(java.lang.String, int[]) + */ + @Override + public int executeUpdate( String sql, + int[] columnIndexes ) throws SQLException { + notClosed(); + noUpdates(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeUpdate(java.lang.String, java.lang.String[]) + */ + @Override + public int executeUpdate( String sql, + String[] columnNames ) throws SQLException { + notClosed(); + noUpdates(); + return 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setCursorName(java.lang.String) + */ + @Override + public void setCursorName( String name ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getUpdateCount() + */ + @Override + public int getUpdateCount() throws SQLException { + notClosed(); + return -1; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#addBatch(java.lang.String) + */ + @Override + public void addBatch( String sql ) throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#clearBatch() + */ + @Override + public void clearBatch() throws SQLException { + notClosed(); + noUpdates(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeBatch() + */ + @Override + public int[] executeBatch() throws SQLException { + notClosed(); + noUpdates(); + return null; + } + + // ---------------------------------------------------------------------------------------------------------------- + // Queries + // ---------------------------------------------------------------------------------------------------------------- + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#execute(java.lang.String) + */ + @Override + public boolean execute( String sql ) throws SQLException { + notClosed(); + warning = null; + moreResults = 0; + try { + // Convert the supplied SQL into JCR-SQL2 ... + String jcrSql2 = connection.nativeSQL(sql); + // Create the query ... + final QueryResult jcrResults = getJcrRepositoryDelegate().execute(jcrSql2, this.sqlLanguage); + results = new JcrResultSet(this, jcrResults, null); + moreResults = 1; + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + return true; // always a ResultSet + } + + protected RepositoryDelegate getJcrRepositoryDelegate() { + return this.connection.getRepositoryDelegate(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#execute(java.lang.String, int) + */ + @Override + public boolean execute( String sql, + int autoGeneratedKeys ) throws SQLException { + throw new SQLFeatureNotSupportedException(); } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#execute(java.lang.String, int[]) + */ + @Override + public boolean execute( String sql, + int[] columnIndexes ) throws SQLException { + throw new SQLFeatureNotSupportedException(); } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#execute(java.lang.String, java.lang.String[]) + */ + @Override + public boolean execute( String sql, + String[] columnNames ) throws SQLException { + throw new SQLFeatureNotSupportedException(); } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#executeQuery(java.lang.String) + */ + @Override + public ResultSet executeQuery( String sql ) throws SQLException { + execute(sql); + return getResultSet(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getGeneratedKeys() + */ + @Override + public ResultSet getGeneratedKeys() /*throws SQLException*/{ + // TODO: if and when ModeShape supports providing key information + // then a result set containing the metadata will need to be created. + return new JcrResultSet(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getMoreResults() + */ + @Override + public boolean getMoreResults() throws SQLException { + notClosed(); + return moreResults > 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getMoreResults(int) + */ + @Override + public boolean getMoreResults( int current ) throws SQLException { + notClosed(); + if (current != CLOSE_ALL_RESULTS && current != CLOSE_CURRENT_RESULT && current != KEEP_CURRENT_RESULT) { + throw new SQLException(JdbcLocalI18n.invalidArgument.text(current, "" + CLOSE_ALL_RESULTS + ", " + CLOSE_CURRENT_RESULT + + ", " + KEEP_CURRENT_RESULT)); + } + if (KEEP_CURRENT_RESULT != current) { + // Close (by nulling) the results ... +// jcrResults = null; + results = null; + } + if (moreResults > 0) --moreResults; + return moreResults > 0; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getResultSet() + */ + @Override + public ResultSet getResultSet() throws SQLException { + notClosed(); + return results; // may be null + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getResultSetConcurrency() + */ + @Override + public int getResultSetConcurrency() throws SQLException { + notClosed(); + return ResultSet.CONCUR_READ_ONLY; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getResultSetHoldability() + */ + @Override + public int getResultSetHoldability() throws SQLException { + notClosed(); + return ResultSet.CLOSE_CURSORS_AT_COMMIT; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#getResultSetType() + */ + @Override + public int getResultSetType() throws SQLException { + notClosed(); + return ResultSet.TYPE_SCROLL_INSENSITIVE; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Statement#setEscapeProcessing(boolean) + */ + @Override + public void setEscapeProcessing( boolean enable ) throws SQLException { + notClosed(); + // Ignore for now + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) /*throws SQLException*/{ + return iface.isInstance(this); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (!isWrapperFor(iface)) { + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(Statement.class.getSimpleName(), iface.getName())); + } + + return iface.cast(this); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrType.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrType.java new file mode 100644 index 0000000..3184e0f --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrType.java @@ -0,0 +1,279 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.math.BigDecimal; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.ValueFormatException; +import org.modeshape.jdbc.types.BlobTransform; +import org.modeshape.jdbc.types.BooleanTransform; +import org.modeshape.jdbc.types.DateTransform; +import org.modeshape.jdbc.types.DecimalTransform; +import org.modeshape.jdbc.types.DoubleTransform; +import org.modeshape.jdbc.types.LongTransform; +import org.modeshape.jdbc.types.StringTransform; +import org.modeshape.jdbc.types.UUIDTransform; + +/** + * Provides functionality to convert from JCR {@link PropertyType}s and JDBC types. + */ +public final class JcrType { + + private static final int UUID_LENGTH = UUID.randomUUID().toString().length(); + private static final Map TYPE_INFO; + + public static final class DefaultDataTypes { + public static final String STRING = PropertyType.TYPENAME_STRING; + public static final String BOOLEAN = PropertyType.TYPENAME_BOOLEAN; + public static final String LONG = PropertyType.TYPENAME_LONG; + public static final String DOUBLE = PropertyType.TYPENAME_DOUBLE; + public static final String DECIMAL = PropertyType.TYPENAME_DECIMAL; + public static final String DATE = PropertyType.TYPENAME_DATE; + public static final String URI = PropertyType.TYPENAME_URI; + public static final String WEAK_REF = PropertyType.TYPENAME_WEAKREFERENCE; + public static final String UNDEFINED = PropertyType.TYPENAME_UNDEFINED; + public static final String BINARY = PropertyType.TYPENAME_BINARY; + public static final String REFERENCE = PropertyType.TYPENAME_REFERENCE; + public static final String PATH = PropertyType.TYPENAME_PATH; + public static final String NAME = PropertyType.TYPENAME_NAME; + } + + static { + Map types = new HashMap(); + register(types, PropertyType.BINARY, Types.BLOB, "Blob", JcrBlob.class, 30, Integer.MAX_VALUE, new BlobTransform()); // assumed + register(types, PropertyType.BOOLEAN, Types.BOOLEAN, "Boolean", Boolean.class, 5, 1, new BooleanTransform()); // 'true' or 'false' + register(types, PropertyType.DATE, Types.TIMESTAMP, "Timestamp", Timestamp.class, 30, 10, new DateTransform()); // yyyy-MM-dd'T'HH:mm:ss.SSS+HH:mm + register(types, PropertyType.DOUBLE, Types.DOUBLE, "Double" ,Double.class, 20, 20, new DoubleTransform()); // assumed + register(types, PropertyType.DECIMAL, Types.DECIMAL, "Bigdecimal", BigDecimal.class, 20, 20, new DecimalTransform()); // assumed + register(types, PropertyType.LONG, Types.BIGINT, "Long", Long.class, 20, 19, new LongTransform()); // assumed + register(types, PropertyType.NAME, Types.VARCHAR, "String", String.class, 20, Integer.MAX_VALUE, new StringTransform()); // assumed + register(types, PropertyType.PATH, Types.VARCHAR, "String", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed + register(types, PropertyType.REFERENCE, Types.VARCHAR, "String", UUID.class, UUID_LENGTH, UUID_LENGTH, new UUIDTransform()); + register(types, PropertyType.WEAKREFERENCE, Types.VARCHAR, "String", UUID.class, UUID_LENGTH, UUID_LENGTH, new UUIDTransform()); + register(types, PropertyType.URI, Types.VARCHAR, "String", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed + register(types, PropertyType.STRING, Types.VARCHAR, "String", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed + register(types, PropertyType.UNDEFINED, Types.VARCHAR, "String", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // same + // as + // string + TYPE_INFO = Collections.unmodifiableMap(types); + } + + private static void register( Map types, + int jcrType, + int jdbcType, + String typeName, + Class clazz, + int displaySize, + int precision, + Transform transform ) { + JcrType type = new JcrType(jcrType, jdbcType, typeName, clazz, displaySize, precision, transform); + types.put(type.getJcrName(), type); + } + + private final int jcrType; + private final String jcrName; + private final Class clazz; + private final int jdbcType; + private final String typeName; + private final int displaySize; + private final int precision; + private final Transform transform; + + protected JcrType( int jcrType, + int jdbcType, + String typeName, + Class clazz, + int displaySize, + int precision, + Transform transform ) { + this.jcrType = jcrType; + this.jcrName = PropertyType.nameFromValue(jcrType); + this.clazz = clazz; + this.displaySize = displaySize; + this.jdbcType = jdbcType; + this.typeName = typeName; + this.precision = precision; + this.transform = transform; + assert this.jcrName != null; + assert this.clazz != null; + assert this.displaySize > 0; + assert this.transform != null; + } + + /** + * Get the name of the JCR type. + * + * @return the JCR type name; never null + */ + public String getJcrName() { + return jcrName; + } + + /** + * Get the JCR {@link PropertyType} value. + * + * @return the JCR property type; never null + */ + public int getJcrType() { + return jcrType; + } + + /** + * Get the JDBC {@link Types} value. + * + * @return the JDBC type; never null + */ + public int getJdbcType() { + return jdbcType; + } + + /** + * Get the native type name associated with the JDBC {@link Types} value. + * + * @return the native JDBC type name; never null + */ + public String getJdbcTypeName() { + return this.typeName; + } + + /** + * Get the default precision used for this JcrType + * + * @return the Integer form of the precision + */ + public Integer getDefaultPrecision() { + return new Integer(precision); + } + + /** + * Return the {@link Transform} object to use to transform the {@link Value} to the correct data type. + * + * @return Transform + */ + protected Transform getTransform() { + return this.transform; + } + + /** + * Get the indicator if the value is case sensitive + * + * @return boolean indicating if the value is case sensitive + */ + public boolean isCaseSensitive() { + switch (getJcrType()) { + case PropertyType.DOUBLE: + case PropertyType.LONG: + case PropertyType.DECIMAL: + case PropertyType.WEAKREFERENCE: + case PropertyType.REFERENCE: // conversion is case-insensitive + case PropertyType.BOOLEAN: // conversion is case-insensitive + return false; + } + return true; + } + + /** + * Get the indicator if the value is considered a signed value. + * + * @return boolean indicating if value is signed. + */ + public boolean isSigned() { + switch (getJcrType()) { + case PropertyType.DOUBLE: + case PropertyType.LONG: + case PropertyType.DECIMAL: + case PropertyType.DATE: + return true; + } + return false; + } + + /** + * Get the Java class used to represent values for this type. + * + * @return the representation class; never null + */ + public Class getRepresentationClass() { + return clazz; + } + + /** + * Get the nominal display size for the given type. This may not be large enough for certain string and binary values. + * + * @return the nominal display size; always positive + * @see ResultSetMetaData#getColumnDisplaySize(int) + */ + public int getNominalDisplaySize() { + return displaySize; + } + + public Object translateValue( Value value ) throws SQLException { + if (value == null) return null; + try { + return this.getTransform().transform(value); + + } catch (ValueFormatException ve) { + throw new SQLException(ve.getLocalizedMessage(), ve); + } catch (IllegalStateException ie) { + throw new SQLException(ie.getLocalizedMessage(), ie); + } catch (RepositoryException e) { + throw new SQLException(e.getLocalizedMessage(), e); + } + + } + + public static Object translateValueToJDBC( Value value ) throws SQLException { + String jcrName = PropertyType.nameFromValue(value.getType()); + JcrType jcrtype = typeInfo(jcrName); + return jcrtype.translateValue(value); + } + + /** + * Get the immutable built-in map from the type names to the Java representation class. + * + * @return the built-in type map + */ + public static Map builtInTypeMap() { + return TYPE_INFO; + } + + public static JcrType typeInfo( String typeName ) { + return TYPE_INFO.get(typeName); + } + + public static JcrType typeInfo( int jcrType ) { + return typeInfo(PropertyType.nameFromValue(jcrType)); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JdbcLocalI18n.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JdbcLocalI18n.java new file mode 100644 index 0000000..afd2023 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JdbcLocalI18n.java @@ -0,0 +1,117 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. +* See the AUTHORS.txt file in the distribution for a full listing of +* individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import org.modeshape.jdbc.util.I18n; + +/** + * The internationalized string constants for the org.modeshape.jdbc* packages. + */ +public final class JdbcLocalI18n { + + public static I18n i18nClassInterface; + public static I18n i18nClassNotPublic; + public static I18n i18nFieldFinal; + public static I18n i18nFieldInvalidType; + public static I18n i18nFieldNotPublic; + public static I18n i18nFieldNotStatic; + public static I18n i18nLocalizationFileNotFound; + public static I18n i18nLocalizationProblems; + public static I18n i18nPropertyDuplicate; + public static I18n i18nPropertyMissing; + public static I18n i18nPropertyUnused; + public static I18n i18nRequiredToSuppliedParameterMismatch; + + public static I18n driverName; + public static I18n driverVendor; + public static I18n driverVendorUrl; + public static I18n driverVersion; + + public static I18n driverErrorRegistering; + + /* + * ConnectionInfo related text info + */ + public static I18n usernamePropertyDescription; + public static I18n passwordPropertyDescription; + public static I18n workspaceNamePropertyDescription; + public static I18n repositoryNamePropertyDescription; + public static I18n urlPropertyDescription; + public static I18n urlPropertyName; + public static I18n usernamePropertyName; + public static I18n passwordPropertyName; + public static I18n workspaceNamePropertyName; + public static I18n repositoryNamePropertyName; + + public static I18n invalidUrl; + public static I18n invalidUrlPrefix; + public static I18n failedToReadPropertiesFromManifest; + public static I18n unableToFindNamedRepository; + public static I18n noRepositoryNamesFound; + public static I18n argumentMayNotBeNegative; + public static I18n argumentMayNotBeNull; + public static I18n requiredToSuppliedParameterMismatch; + + public static I18n connectionIsClosed; + public static I18n statementIsClosed; + public static I18n resultSetIsClosed; + public static I18n resultSetIsForwardOnly; + public static I18n noSuchColumn; + public static I18n updatesNotSupported; + public static I18n timeoutMayNotBeNegative; + public static I18n classDoesNotImplementInterface; + public static I18n invalidClientInfo; + public static I18n invalidArgument; + public static I18n invalidColumnIndex; + public static I18n currentRowNotSet; + public static I18n noJcrTypeMapped; + public static I18n unableToGetNodeTypes; + public static I18n noNodeTypesReturned; + public static I18n unableToGetNodeType; + public static I18n noSuchNodeType; + + public static I18n repositoryNameInUse; + + /* + * JNDI connection option related text info + */ + public static I18n objectInJndiMustBeRepositoryOrRepositories; + public static I18n unableToGetJndiContext; + public static I18n urlMustContainJndiNameOfRepositoryOrRepositoriesObject; + public static I18n unableToFindObjectInJndi; + public static I18n objectInJndiIsRepositories; + + /* + * File connection option relatd text info + */ + public static I18n configurationFileNotSpecified; + + static { + try { + I18n.initialize(JdbcLocalI18n.class); + } catch (final Exception err) { + System.err.println(err); + } + } +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/LocalJcrDriver.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/LocalJcrDriver.java new file mode 100644 index 0000000..7686375 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/LocalJcrDriver.java @@ -0,0 +1,250 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.Properties; +import java.util.Set; +import javax.jcr.Repository; +import javax.naming.Context; +import javax.naming.NamingException; +import org.modeshape.jdbc.delegate.ConnectionInfo; +import org.modeshape.jdbc.delegate.DriverInfo; +import org.modeshape.jdbc.delegate.LocalRepositoryDelegate; +import org.modeshape.jdbc.delegate.RepositoryDelegate; +import org.modeshape.jdbc.delegate.RepositoryDelegateFactory; +import org.modeshape.jdbc.util.Collections; +import org.modeshape.jdbc.util.Logger; + +/** + * A JDBC driver implementation that is able to access a JCR repository to query its contents using JCR-SQL2.

Connection URLs

+ *

+ * The driver accepts several URL formats based on how the repository is configured: + *

    + *
  1. configured for local access using JNDI + * + *
    + *     jdbc:jcr:jndi:{jndiName}
    + * 
    + * + * or + * + *
    + *     jdbc:jcr:jndi:{jndiName}?{firstProperty}&{secondProperty}&...
    + * 
    + * + * where + *
      + *
    • {jndiName} is the JNDI name where the {@link Repository} or {@literal org.modeshape.jcr.api.Repositories} + * instance can be found;
    • + *
    • {firstProperty} consists of the first property name followed by '=' followed by the property's value;
    • + *
    • {secondProperty} consists of the second property name followed by '=' followed by the property's value;
    • + *
    + * Note that any use of URL encoding ('%' followed by a two-digit hexadecimal value) will be decoded before being used. + *

    + *

    + * Here's an example of a URL that defines a {@link Repository} instance located at "jcr/local" with a repository + * name of "repository" and a user, password of "secret", and workspace name of "My Workspace": + * + *

    + *     jdbc:jcr:jndi:jcr/local?repositoryName=repository&user=jsmith&password=secret&workspace=My%20Workspace
    + * 
    + * + * The "repository" property is required only if the object in JNDI is a {@literal org.modeshape.jcr.api.Repositories} object. + *

    + *

    + * Note that any use of URL encoding ('%' followed by a two-digit hexadecimal value) will be decoded before being used. + *

    + * Note that any use of URL encoding ('%' followed by a two-digit hexadecimal value) will be decoded before being used. + */ + +public class LocalJcrDriver implements java.sql.Driver { + protected static Logger logger = Logger.getLogger("org.modeshape.jdbc"); //$NON-NLS-1$ + + public static final String WORKSPACE_PROPERTY_NAME = "workspace"; + public static final String REPOSITORY_PROPERTY_NAME = "repositoryName"; + public static final String USERNAME_PROPERTY_NAME = "user"; + public static final String PASSWORD_PROPERTY_NAME = "password"; + + protected static final Set ALL_PROPERTY_NAMES = Collections.unmodifiableSet(WORKSPACE_PROPERTY_NAME, + REPOSITORY_PROPERTY_NAME, + USERNAME_PROPERTY_NAME, + PASSWORD_PROPERTY_NAME); + + /* URL Prefix used for JNDI access */ + public static final String JNDI_URL_PREFIX = "jdbc:jcr:jndi:"; + + public JcrContextFactory contextFactory = null; + + private static LocalJcrDriver INSTANCE = new LocalJcrDriver(); + + static { + try { + DriverManager.registerDriver(INSTANCE); + } catch (SQLException e) { + logger.error(e, JdbcLocalI18n.driverErrorRegistering, e.getMessage()); + } + } + + public static LocalJcrDriver getInstance() { + return INSTANCE; + } + + protected final DriverInfo driverInfo; + protected final RepositoryDelegateFactory delegateFactory; + + /** + * No-arg constructor, required by the {@link DriverManager}. + */ + public LocalJcrDriver() { + this(LocalRepositoryDelegate.FACTORY, new DriverInfo(JdbcLocalI18n.driverName.text(), JdbcLocalI18n.driverVendor.text(), + JdbcLocalI18n.driverVendorUrl.text(), + JdbcLocalI18n.driverVersion.text())); + } + + /** + * Constructor for subclasses, that should be called by subclasses no-arg constructor. + * + * @param delegateFactory the factory that should be used to create {@link RepositoryDelegate} instances; may not be null + * @param driverInfo the information about the driver; may not be null + */ + protected LocalJcrDriver( RepositoryDelegateFactory delegateFactory, + DriverInfo driverInfo ) { + assert delegateFactory != null; + assert driverInfo != null; + this.delegateFactory = delegateFactory; + this.driverInfo = driverInfo; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Driver#acceptsURL(java.lang.String) + */ + @Override + public boolean acceptsURL( String url ) { + return delegateFactory.acceptUrl(url); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties) + */ + @Override + public DriverPropertyInfo[] getPropertyInfo( String url, + Properties info ) throws SQLException { + // Get the connection information ... + return delegateFactory.createRepositoryDelegate(url, info, this.contextFactory).getConnectionInfo().getPropertyInfos(); + } + + /** + * Get the information describing the connection. This method can be overridden to return a subclass of {@link ConnectionInfo} + * that implements {@link ConnectionInfo#getCredentials()} for a specific JCR implementation. + * + * @param url the JDBC URL + * @param info the JDBC connection properties + * @return the connection information, or null if the URL is null or not of the proper format + * @throws SQLException + */ + protected ConnectionInfo createConnectionInfo( String url, + Properties info ) throws SQLException { + return delegateFactory.createRepositoryDelegate(url, info, this.contextFactory).getConnectionInfo(); + } + + /** + * {@inheritDoc} + *

    + * Note that if the supplied properties and URL contain properties with the same name, the value from the supplied Properties + * object will take precedence. + *

    + * + * @see java.sql.Driver#connect(java.lang.String, java.util.Properties) + */ + @Override + public Connection connect( String url, + Properties info ) throws SQLException { + + return delegateFactory.createRepositoryDelegate(url, info, this.contextFactory).createConnection(getDriverInfo()); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Driver#getMajorVersion() + */ + @Override + public int getMajorVersion() { + return getDriverInfo().getMajorVersion(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Driver#getMinorVersion() + */ + @Override + public int getMinorVersion() { + return getDriverInfo().getMinorVersion(); + } + + public String getVendorName() { + return getDriverInfo().getVendorName(); + } + + public String getVendorUrl() { + return getDriverInfo().getVendorUrl(); + } + + public String getVersion() { + return getDriverInfo().getVersion(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Driver#jdbcCompliant() + */ + @Override + public boolean jdbcCompliant() { + return false; + } + + protected final DriverInfo getDriverInfo() { + return driverInfo; + } + + public void setContextFactory( JcrContextFactory factory ) { + assert factory != null; + this.contextFactory = factory; + } + + public interface JcrContextFactory { + Context createContext( Properties properties ) throws NamingException; + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/ModeShapeMetaData.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/ModeShapeMetaData.java new file mode 100644 index 0000000..cd64236 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/ModeShapeMetaData.java @@ -0,0 +1,143 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +/** + * Specialized implementation for ModeShape-specific features. + */ +public class ModeShapeMetaData extends JcrMetaData { + + public ModeShapeMetaData( JcrConnection connection ) { + super(connection); + } + + /** + * {@inheritDoc} + *

    + * ModeShape does support FULL OUTER JOIN, so this method returns true when this driver connects to a ModeShape + * JCR repository. + *

    + * + * @see java.sql.DatabaseMetaData#supportsFullOuterJoins() + */ + @Override + public boolean supportsFullOuterJoins() { + return true; + } + + /** + * {@inheritDoc} + *

    + * ModeShape does support UNION, so this method returns true when this driver connects to a ModeShape JCR + * repository. + *

    + * + * @see java.sql.DatabaseMetaData#supportsUnion() + */ + @Override + public boolean supportsUnion() { + return true; + } + + /** + * {@inheritDoc} + *

    + * ModeShape does support UNION ALL, so this method returns true when this driver connects to a ModeShape JCR + * repository. + *

    + * + * @see java.sql.DatabaseMetaData#supportsUnionAll() + */ + @Override + public boolean supportsUnionAll() { + return true; + } + + /** + * {@inheritDoc} + *

    + * ModeShape uses arithmetic operations in criteria, and in the current implementation if one operand is null then the + * operations returns the other. Therefore, 'null + X = X', so this method returns false. + *

    + * + * @see java.sql.DatabaseMetaData#nullPlusNonNullIsNull() + */ + @Override + public boolean nullPlusNonNullIsNull() { + return false; + } + + /** + * {@inheritDoc} + *

    + * ModeShape definitely uses sort order. Therefore, this method always returns false. + *

    + * + * @see java.sql.DatabaseMetaData#nullsAreSortedAtEnd() + */ + @Override + public boolean nullsAreSortedAtEnd() { + return false; + } + + /** + * {@inheritDoc} + *

    + * ModeShape definitely uses sort order. Therefore, this method always returns false. + *

    + * + * @see java.sql.DatabaseMetaData#nullsAreSortedAtStart() + */ + @Override + public boolean nullsAreSortedAtStart() { + return false; + } + + /** + * {@inheritDoc} + *

    + * ModeShape sorts null values to be lower than non-null values. Therefore, this method returns false. + *

    + * + * @see java.sql.DatabaseMetaData#nullsAreSortedHigh() + */ + @Override + public boolean nullsAreSortedHigh() { + return false; + } + + /** + * {@inheritDoc} + *

    + * ModeShape sorts null values to be lower than non-null values. Therefore, this method returns true. + *

    + * + * @see java.sql.DatabaseMetaData#nullsAreSortedLow() + */ + @Override + public boolean nullsAreSortedLow() { + return true; + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/Transform.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/Transform.java new file mode 100644 index 0000000..05baff5 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/Transform.java @@ -0,0 +1,46 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc; + +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.ValueFormatException; + +/** + * + */ +public interface Transform { + + /** + * This method transforms a value of the source type into a value + * of the target type. + * @param value Incoming value of source type + * @return Outgoing value of target type + * @throws ValueFormatException if value is an incorrect input type + * @throws RepositoryException if unable to obtain value from repository + * the transformation fails + */ + Object transform(Value value) throws ValueFormatException, RepositoryException; + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/AbstractRepositoryDelegate.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/AbstractRepositoryDelegate.java new file mode 100644 index 0000000..2786638 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/AbstractRepositoryDelegate.java @@ -0,0 +1,177 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.Set; +import javax.jcr.Repository; +import org.modeshape.jdbc.JcrConnection; +import org.modeshape.jdbc.JdbcLocalI18n; +import org.modeshape.jdbc.util.Logger; + +/** + * The AbstractRepositoryDelegate provides the common logic for the implementation of the {@link RepositoryDelegate} + */ +public abstract class AbstractRepositoryDelegate implements RepositoryDelegate { + protected static final Logger LOGGER = Logger.getLogger("org.modeshape.jdbc.delegate"); + + private Repository repository = null; + private Set repositoryNames = null; + private ConnectionInfo connInfo = null; + private String url; + private Properties propertiesInfo; + + public AbstractRepositoryDelegate( String url, + Properties info ) { + super(); + this.url = url; + this.propertiesInfo = info; + } + + /** + * The implementor must return a @link ConnectionInfo that provides the information that details r + * + * @param url + * @param info + * @return ConnectionInfo + */ + protected abstract ConnectionInfo createConnectionInfo( final String url, + final Properties info ); + + /** + * Implementor is responsible for creating the repository. + * + * @throws SQLException + */ + protected abstract void createRepository() throws SQLException; + + @Override + public synchronized ConnectionInfo getConnectionInfo() { + if (this.connInfo == null) { + this.connInfo = createConnectionInfo(url, propertiesInfo); + this.connInfo.init(); + } + return connInfo; + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jdbc.delegate.RepositoryDelegate#closeStatement() + */ + @Override + public void closeStatement() { + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#close() + */ + @Override + public void close() { + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jdbc.delegate.RepositoryDelegate#commit() + */ + @Override + public void commit() { + closeStatement(); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#rollback() + */ + @Override + public void rollback() { + closeStatement(); + } + + @Override + public Connection createConnection( DriverInfo info ) throws SQLException { + LOGGER.debug("Creating connection for RepositoryDelegte"); + if (this.repository == null) { + createRepository(); + } + + return new JcrConnection(this, info); + } + + public synchronized Repository getRepository() { + return this.repository; + } + + protected void setRepository( Repository repository ) { + this.repository = repository; + } + + public String getRepositoryName() { + return getConnectionInfo().getRepositoryName(); + } + + protected void setRepositoryName( String repositoryName ) { + this.getConnectionInfo().setRepositoryName(repositoryName); + } + + public Set getRepositoryNames() { + return this.repositoryNames; + } + + protected void setRepositoryNames( Set repositoryNames ) { + this.repositoryNames = repositoryNames; + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor( Class iface ) { + return iface.isInstance(this); + } + + /** + * {@inheritDoc} + * + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + if (!isWrapperFor(iface)) { + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(RepositoryDelegate.class.getSimpleName(), + iface.getName())); + } + + return iface.cast(this); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/ConnectionInfo.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/ConnectionInfo.java new file mode 100644 index 0000000..d13c615 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/ConnectionInfo.java @@ -0,0 +1,313 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import java.sql.DriverPropertyInfo; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import javax.jcr.Credentials; +import javax.jcr.SimpleCredentials; +import org.modeshape.jcr.api.Repositories; +import org.modeshape.jdbc.JdbcLocalI18n; +import org.modeshape.jdbc.LocalJcrDriver; +import org.modeshape.jdbc.util.StringUtil; +import org.modeshape.jdbc.util.TextDecoder; +import org.modeshape.jdbc.util.UrlEncoder; + +/** + * The ConnectionInfo contains the information used to connect to the Jcr Repository. + */ +public abstract class ConnectionInfo { + public static final TextDecoder URL_DECODER = new UrlEncoder(); + + protected String url; + protected String repositoryPath; + protected Properties properties; + private char propertyDelimiter = '?'; + + protected ConnectionInfo( String url, + Properties properties ) { + this.url = url; + this.properties = properties; + } + + protected void init() { + Properties props = getProperties() != null ? (Properties)getProperties().clone() : new Properties(); + repositoryPath = getUrl().substring(this.getUrlPrefix().length()); + + // Find any URL parameters ... + int questionMarkIndex = repositoryPath.indexOf('?'); + if (questionMarkIndex != -1) { + if (repositoryPath.length() > questionMarkIndex + 1) { + String paramStr = repositoryPath.substring(questionMarkIndex + 1); + for (String param : paramStr.split("&")) { + String[] pair = param.split("="); + if (pair.length > 1) { + String key = URL_DECODER.decode(pair[0] != null ? pair[0].trim() : null); + String value = URL_DECODER.decode(pair[1] != null ? pair[1].trim() : null); + if (!props.containsKey(key)) { + props.put(key, value); + } + } + } + } + repositoryPath = repositoryPath.substring(0, questionMarkIndex).trim(); + } + + Properties newprops = new Properties(); + newprops.putAll(props); + this.setProperties(newprops); + String url = getUrl(); + this.setUrl(url != null ? url.trim() : null); + + } + + /** + * Get the original URL of the connection. + * + * @return the URL; never null + */ + public String getUrl() { + return url; + } + + /** + * Get the part of the {@link #getUrl()} that indicates the path to connect to the Repository. This value should be prefixed + * by the {@link #getUrlPrefix()} in the {@link #getUrl()}. + * + * @return String + */ + public String getRepositoryPath() { + return this.repositoryPath; + } + + /** + * Get the immutable properties for the connection. + * + * @return the properties; never null + */ + public Properties getProperties() { + return properties; + } + + /** + * Get the name of the repository. This is required only if the {@link Repositories} instance is being used to obtain the + * Repository. + * + * @return the name of the repository, or null if no repository name was specified + */ + public String getRepositoryName() { + return properties.getProperty(LocalJcrDriver.REPOSITORY_PROPERTY_NAME); + } + + /** + * Call to set the repository name. This is called when no repository name is set on the URL, but there is only one repository + * in the list. + * + * @param repositoryName + */ + void setRepositoryName( String repositoryName ) { + this.properties.setProperty(LocalJcrDriver.REPOSITORY_PROPERTY_NAME, repositoryName); + } + + /** + * Get the name of the workspace. This is not required, and if abscent implies obtaining the JCR Repository's default + * workspace. + * + * @return the name of the workspace, or null if no workspace name was specified + */ + public String getWorkspaceName() { + return properties.getProperty(LocalJcrDriver.WORKSPACE_PROPERTY_NAME); + } + + /** + * Call to set the workspace name. This is not required, and if abscent implies obtaining the JCR Repository's default + * workspace. + * + * @param workSpaceName + */ + public void setWorkspaceName( String workSpaceName ) { + properties.setProperty(LocalJcrDriver.WORKSPACE_PROPERTY_NAME, workSpaceName); + } + + /** + * Get the JCR user name. This is not required, and if abscent implies that no credentials should be used when obtaining a JCR + * Session. + * + * @return the JCR user name, or null if no user name was specified + */ + public String getUsername() { + return properties.getProperty(LocalJcrDriver.USERNAME_PROPERTY_NAME); + } + + /** + * Get the JCR password. This is not required. + * + * @return the JCR password, or null if no password was specified + */ + public char[] getPassword() { + String result = properties.getProperty(LocalJcrDriver.PASSWORD_PROPERTY_NAME); + return result != null ? result.toCharArray() : null; + } + + void setUrl( String url ) { + this.url = url; + } + + void setProperties( Properties properties ) { + this.properties = properties; + } + + /** + * Get the effective URL of this connection, which places all properties on the URL (with a '*' for each character in the + * password property) + * + * @return the effective URL; never null + */ + public String getEffectiveUrl() { + StringBuilder url = new StringBuilder(this.getUrlPrefix()); + url.append(this.getRepositoryPath()); + char propertyDelim = getPropertyDelimiter(); + for (String propertyName : getProperties().stringPropertyNames()) { + String value = getProperties().getProperty(propertyName); + if (value == null) continue; + if (LocalJcrDriver.PASSWORD_PROPERTY_NAME.equals(propertyName)) { + value = StringUtil.createString('*', value.length()); + } + url.append(propertyDelim).append(propertyName).append('=').append(value); + propertyDelim = '&'; + } + return url.toString(); + } + + /** + * Return the starting property delimiter + * + * @return char property delimiter + */ + protected char getPropertyDelimiter() { + return propertyDelimiter; + } + + protected void setPropertyDelimiter( char delimiter ) { + this.propertyDelimiter = delimiter; + } + + /** + * Obtain the array of {@link DriverPropertyInfo} objects that describe the missing properties. + * + * @return DriverPropertyInfo the property infos; never null but possibly empty + */ + public DriverPropertyInfo[] getPropertyInfos() { + List results = new ArrayList(); + + addUrlPropertyInfo(results); + addUserNamePropertyInfo(results); + addPasswordPropertyInfo(results); + addWorkspacePropertyInfo(results); + addRepositoryNamePropertyInfo(results); + + return results.toArray(new DriverPropertyInfo[results.size()]); + } + + protected void addUrlPropertyInfo( List results ) { + if (getUrl() == null) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.urlPropertyName.text(), null); + info.description = JdbcLocalI18n.urlPropertyDescription.text(this.getEffectiveUrl(), getUrlExample()); + info.required = true; + info.choices = new String[] {getUrlExample()}; + results.add(info); + } + } + + protected void addUserNamePropertyInfo( List results ) { + if (getUsername() == null) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.usernamePropertyName.text(), null); + info.description = JdbcLocalI18n.usernamePropertyDescription.text(); + info.required = false; + info.choices = null; + results.add(info); + } + } + + protected void addPasswordPropertyInfo( List results ) { + if (getPassword() == null) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.passwordPropertyName.text(), null); + info.description = JdbcLocalI18n.passwordPropertyDescription.text(); + info.required = false; + info.choices = null; + results.add(info); + } + } + + protected void addWorkspacePropertyInfo( List results ) { + if (getWorkspaceName() == null) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.workspaceNamePropertyName.text(), null); + info.description = JdbcLocalI18n.workspaceNamePropertyDescription.text(); + info.required = false; + info.choices = null; + results.add(info); + } + } + + protected void addRepositoryNamePropertyInfo( List results ) { + if (getRepositoryName() == null) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.repositoryNamePropertyName.text(), null); + info.description = JdbcLocalI18n.repositoryNamePropertyDescription.text(); + info.required = true; + info.choices = null; + results.add(info); + } + } + + /** + * The delegate should provide an example of the URL to be used + * + * @return String url example + */ + public abstract String getUrlExample(); + + /** + * The delegate should provide the prefix defined by the {@link LocalJcrDriver} + * + * @return String url prefix + */ + public abstract String getUrlPrefix(); + + /** + * Return the credentials based on the user name and password. + * + * @return Credentials + */ + public Credentials getCredentials() { + String username = getUsername(); + char[] password = getPassword(); + if (username != null) { + return new SimpleCredentials(username, password); + } + return null; + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/DriverInfo.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/DriverInfo.java new file mode 100644 index 0000000..d890aa5 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/DriverInfo.java @@ -0,0 +1,74 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +/** + * Information about the driver. + */ +public final class DriverInfo { + + private final String name; + private final String vendorName; + private final String vendorUrl; + private final String version; + private final int majorVersion; + private final int minorVersion; + + public DriverInfo( String name, + String vendorName, + String vendorUrl, + String version ) { + this.name = name; + this.vendorName = vendorName; + this.vendorUrl = vendorUrl; + this.version = version; + String[] coords = getVersion().split("[.-]"); + this.majorVersion = coords.length > 0 && coords[0] != null ? Integer.parseInt(coords[0]) : 0; + this.minorVersion = coords.length > 1 && coords[1] != null ? Integer.parseInt(coords[1]) : 0; + } + + public String getVendorName() { + return vendorName; + } + + public String getVendorUrl() { + return vendorUrl; + } + + public String getVersion() { + return version; + } + + public int getMajorVersion() { + return majorVersion; + } + + public int getMinorVersion() { + return minorVersion; + } + + public String getName() { + return name; + } +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalRepositoryDelegate.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalRepositoryDelegate.java new file mode 100644 index 0000000..d5d8ce1 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalRepositoryDelegate.java @@ -0,0 +1,348 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import java.sql.Connection; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import javax.jcr.LoginException; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Workspace; +import javax.jcr.nodetype.NodeType; +import javax.jcr.nodetype.NodeTypeIterator; +import javax.jcr.query.Query; +import javax.jcr.query.QueryResult; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import org.modeshape.jcr.api.Repositories; +import org.modeshape.jdbc.JdbcLocalI18n; +import org.modeshape.jdbc.LocalJcrDriver; +import org.modeshape.jdbc.LocalJcrDriver.JcrContextFactory; + +/** + * The LocalRepositoryDelegate provides a local Repository implementation to access the Jcr layer via JNDI Lookup. + */ +public class LocalRepositoryDelegate extends AbstractRepositoryDelegate { + + public static final RepositoryDelegateFactory FACTORY = new RepositoryDelegateFactory() {}; + + private static final String JNDI_EXAMPLE_URL = LocalJcrDriver.JNDI_URL_PREFIX + "{jndiName}"; + + protected static final Set TRANSACTION_IDS = java.util.Collections.synchronizedSet(new HashSet()); + + private JcrContextFactory jcrContext = null; + + public LocalRepositoryDelegate( String url, + Properties info, + JcrContextFactory contextFactory ) { + super(url, info); + + if (contextFactory == null) { + jcrContext = new JcrContextFactory() { + public Context createContext( Properties properties ) throws NamingException { + InitialContext initContext = ((properties == null || properties.isEmpty()) ? new InitialContext() : new InitialContext( + properties)); + return initContext; + } + }; + } else { + this.jcrContext = contextFactory; + } + } + + @Override + protected ConnectionInfo createConnectionInfo( String url, + Properties info ) { + return new JNDIConnectionInfo(url, info); + } + + protected JcrContextFactory getJcrContext() { + return jcrContext; + } + + private LocalSession getLocalSession() throws LoginException, NoSuchWorkspaceException, RepositoryException { + return LocalSession.getLocalSessionInstance().bindTo(getRepository(), getConnectionInfo()); + } + + private LocalSession getCurrentLocalSession() { + return LocalSession.getLocalSessionInstance(); + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jdbc.delegate.RepositoryDelegate#getDescriptor(java.lang.String) + */ + @Override + public String getDescriptor( String descriptorKey ) { + return getRepository().getDescriptor(descriptorKey); + } + + @Override + public NodeType nodeType( String name ) throws RepositoryException { + LocalSession localSession = getLocalSession(); + return localSession.getSession().getWorkspace().getNodeTypeManager().getNodeType(name); + } + + @Override + public List nodeTypes() throws RepositoryException { + + LocalSession localSession = getLocalSession(); + List types = new ArrayList(); + NodeTypeIterator its = localSession.getSession().getWorkspace().getNodeTypeManager().getAllNodeTypes(); + while (its.hasNext()) { + types.add((NodeType)its.next()); + } + return types; + + } + + /** + * This execute method is used for redirection so that the JNDI implementation can control calling execute. + * + * @see java.sql.Statement#execute(java.lang.String) + */ + @Override + public QueryResult execute( String query, + String language ) throws RepositoryException { + LOGGER.trace("Executing query: {0}" + query); + + // Create the query ... + + final Query jcrQuery = getLocalSession().getSession().getWorkspace().getQueryManager().createQuery(query, language); + return jcrQuery.execute(); + } + + @Override + protected void createRepository() throws SQLException { + LOGGER.debug("Creating repository for LocalRepositoryDelegte"); + + Repository repository = null; + Set repositoryNames = null; + ConnectionInfo connInfo = this.getConnectionInfo(); + assert connInfo != null; + + // Look up the object in JNDI and find the JCR Repository object ... + String jndiName = connInfo.getRepositoryPath(); + if (jndiName == null) { + String msg = JdbcLocalI18n.urlMustContainJndiNameOfRepositoryOrRepositoriesObject.text(); + throw new SQLException(msg); + } + + Context context = null; + try { + context = this.jcrContext.createContext(connInfo.getProperties()); + } catch (NamingException e) { + throw new SQLException(JdbcLocalI18n.unableToGetJndiContext.text(e.getLocalizedMessage())); + } + if (context == null) { + throw new SQLException(JdbcLocalI18n.unableToFindObjectInJndi.text(jndiName)); + + } + String repositoryName = "NotAssigned"; + try { + + Object target = context.lookup(jndiName); + repositoryName = connInfo.getRepositoryName(); + + if (target instanceof Repositories) { + LOGGER.trace("JNDI Lookup found Repositories "); + Repositories repositories = (Repositories)target; + + if (repositoryName == null) { + repositoryNames = repositories.getRepositoryNames(); + if (repositoryNames == null || repositoryNames.isEmpty()) { + throw new SQLException(JdbcLocalI18n.noRepositoryNamesFound.text()); + } + if (repositoryNames.size() == 1) { + repositoryName = repositoryNames.iterator().next(); + connInfo.setRepositoryName(repositoryName); + LOGGER.trace("Setting Repository {0} as default", repositoryName); + + } else { + throw new SQLException(JdbcLocalI18n.objectInJndiIsRepositories.text(jndiName)); + } + } + try { + repository = repositories.getRepository(repositoryName); + } catch (RepositoryException e) { + throw new SQLException(JdbcLocalI18n.unableToFindNamedRepository.text(jndiName, repositoryName)); + } + } else if (target instanceof Repository) { + LOGGER.trace("JNDI Lookup found a Repository"); + repository = (Repository)target; + repositoryNames = new HashSet(1); + + if (repositoryName == null) { + repositoryName = ("DefaultRepository"); + connInfo.setRepositoryName(repositoryName); + } + + repositoryNames.add(repositoryName); + } else { + throw new SQLException(JdbcLocalI18n.objectInJndiMustBeRepositoryOrRepositories.text(jndiName)); + } + assert repository != null; + } catch (NamingException e) { + throw new SQLException(JdbcLocalI18n.unableToFindObjectInJndi.text(jndiName), e); + } + this.setRepository(repository); + this.setRepositoryName(repositoryName); + this.setRepositoryNames(repositoryNames); + + } + + /** + * @see java.sql.Connection#isValid(int) + */ + @Override + public boolean isValid( final int timeout ) throws RepositoryException { + + LocalSession ls = getLocalSession(); + if (!ls.getSession().isLive()) { + ls.remove(); + return false; + } + + return true; + } + + /** + * {@inheritDoc} + * + * @see org.modeshape.jdbc.delegate.RepositoryDelegate#closeStatement() + */ + @Override + public void closeStatement() { + LocalSession session = getCurrentLocalSession(); + try { + if (session != null) { + session.remove(); + } + } catch (Exception e) { + // do nothing + } + } + + /** + * {@inheritDoc} + * + * @see java.sql.Connection#close() + */ + @Override + public void close() { + for (Iterator it = TRANSACTION_IDS.iterator(); it.hasNext();) { + LocalSession id = it.next(); + id.remove(); + } + } + + /** + * @param iface + * @param + * @return T + * @throws SQLException + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + @Override + public T unwrap( Class iface ) throws SQLException { + + try { + if (iface.isInstance(this)) { + return iface.cast(this); + } + + if (iface.isInstance(Workspace.class)) { + Workspace workspace = getLocalSession().getSession().getWorkspace(); + return iface.cast(workspace); + } + } catch (RepositoryException re) { + throw new SQLException(re.getLocalizedMessage()); + } + + throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(Connection.class.getSimpleName(), iface.getName())); + } + + class JNDIConnectionInfo extends ConnectionInfo { + + /** + * @param url + * @param properties + */ + protected JNDIConnectionInfo( String url, + Properties properties ) { + super(url, properties); + } + + @Override + public String getUrlExample() { + return JNDI_EXAMPLE_URL; + } + + @Override + public String getUrlPrefix() { + return LocalJcrDriver.JNDI_URL_PREFIX; + } + + @Override + protected void addRepositoryNamePropertyInfo( List results ) { + boolean no_errors = results.size() == 0; + boolean nameRequired = false; + if (getRepositoryName() == null) { + boolean found = false; + if (no_errors) { + try { + Context context = getJcrContext().createContext(getProperties()); + Object obj = context.lookup(getRepositoryPath()); + if (obj instanceof Repositories) { + nameRequired = true; + found = true; + } else if (obj instanceof Repository) { + found = true; + } + } catch (NamingException e) { + // do nothing about it ... + } + } + if (nameRequired || !found) { + DriverPropertyInfo info = new DriverPropertyInfo(JdbcLocalI18n.repositoryNamePropertyName.text(), null); + info.description = JdbcLocalI18n.repositoryNamePropertyDescription.text(); + info.required = nameRequired; + info.choices = null; + results.add(info); + } + } + } + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalSession.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalSession.java new file mode 100644 index 0000000..77da951 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/LocalSession.java @@ -0,0 +1,95 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import javax.jcr.Credentials; +import javax.jcr.LoginException; +import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +/** + * A wrapper for a local JCR Sessions. + */ +public class LocalSession { + + private static ThreadLocal sessions = new ThreadLocal() { + @Override + protected LocalSession initialValue() { + LocalSession ls = new LocalSession(); + LocalRepositoryDelegate.TRANSACTION_IDS.add(ls); + return ls; + } + }; + + public static LocalSession getLocalSessionInstance() { + return sessions.get(); + } + + private Session session; + + public Session getSession() { + return session; + } + + private void setSession( Session localSession ) { + session = localSession; + } + + public LocalSession bindTo( final Repository repository, + final ConnectionInfo connInfo ) + throws LoginException, NoSuchWorkspaceException, RepositoryException { + LocalSession lsession = sessions.get(); + + Credentials credentials = connInfo.getCredentials(); + String workspaceName = connInfo.getWorkspaceName(); + Session session = null; + if (workspaceName != null) { + session = credentials != null ? repository.login(credentials, workspaceName) : repository.login(workspaceName); + } else { + session = credentials != null ? repository.login(credentials) : repository.login(); + } + // this shouldn't happen, but in testing it did occur only because of + // the repository not being setup correctly + assert session != null; + + lsession.setSession(session); + return lsession; + } + + public void remove() { + sessions.remove(); + LocalRepositoryDelegate.TRANSACTION_IDS.remove(this); + session.logout(); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer("Session:"); + sb.append(session.toString()); + return sb.toString(); + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegate.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegate.java new file mode 100644 index 0000000..d1b44d5 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegate.java @@ -0,0 +1,166 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.Set; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.query.QueryResult; + +/** + * Represents the communication interface thru which the JDBC logic will obtain a connection and issue commands to the Jcr layer. + */ + +public interface RepositoryDelegate { + + /** + * Call to get the connection information. + * + * @return ConnectionInfo + */ + ConnectionInfo getConnectionInfo(); + + /** + * Called to get all the repository names currently available in the JcrEngine. + * + * @return Set of repository names + * @throws RepositoryException + */ + Set getRepositoryNames() throws RepositoryException; + + /** + * Returns the value for the requested descriptorKey + * + * @param descriptorKey + * @return String descriptor value + */ + String getDescriptor( String descriptorKey ); + + /** + * Call to get {@link NodeType} based on specified name + * + * @param name + * @return NodeType + * @throws RepositoryException + */ + NodeType nodeType( String name ) throws RepositoryException; + + /** + * Call to get all the {@link NodeType}s defined. + * + * @return List of all the node types. + * @throws RepositoryException + */ + List nodeTypes() throws RepositoryException; + + /** + * Call to execute the sql query based on the specified Jcr language. + * + * @param query is the sql query to execute + * @param language is the JCR language the query should be executed based on. + * @return QueryResult is the JCR query result + * @throws RepositoryException + */ + QueryResult execute( String query, + String language ) throws RepositoryException; + + /** + * Call to create the connection based on the implementation of this interface. + * + * @param info the driver information + * @return Connection + * @throws SQLException + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + Connection createConnection( DriverInfo info ) throws SQLException; + + /** + * @see java.sql.Connection#commit() + * @throws RepositoryException + */ + void commit() throws RepositoryException; + + /** + * @see java.sql.Connection#rollback() + * @throws RepositoryException + */ + void rollback() throws RepositoryException; + + /** + * @see java.sql.Connection#isValid(int) + * @param timeout + * @return boolean indicating if timeout is valid + * @throws RepositoryException + */ + boolean isValid( int timeout ) throws RepositoryException; + + /** + * Returns true if this either implements the interface argument or is directly or indirectly a wrapper for an object that + * does. Returns false otherwise. If this implements the interface then return true, else if this is a wrapper then return the + * result of recursively calling isWrapperFor on the wrapped object. If this does not implement the interface and + * is not a wrapper, return false. This method should be implemented as a low-cost operation compared to unwrap + * so that callers can use this method to avoid expensive unwrap calls that may fail. If this method returns true + * then calling unwrap with the same argument should succeed. + * + * @param iface a Class defining an interface. + * @return true if this implements the interface or directly or indirectly wraps an object that does. for an object with the + * given interface. + * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) + */ + boolean isWrapperFor( Class iface ); + + /** + * Returns an object that implements the given interface to allow access to non-standard methods, or standard methods not + * exposed by the proxy. If the receiver implements the interface then the result is the receiver or a proxy for the receiver. + * If the receiver is a wrapper and the wrapped object implements the interface then the result is the wrapped object or a + * proxy for the wrapped object. Otherwise return the the result of calling unwrap recursively on the wrapped + * object or a proxy for that result. If the receiver is not a wrapper and does not implement the interface, then an + * SQLException is thrown. + * + * @param iface A Class defining an interface that the result must implement. + * @return an object that implements the interface. May be a proxy for the actual implementing object. + * @param the type of the Class + * @throws java.sql.SQLException If no object found that implements the interface + * @see java.sql.Wrapper#unwrap(java.lang.Class) + */ + T unwrap( Class iface ) throws SQLException; + + /** + * Called when the {@link Statement} the is closed. This enables the underlying connection to the JcrRepository remain open + * until the statement is finished using it. + */ + void closeStatement(); + + /** + * Call to close the delegate connection and any outstanding transactions will be closed. + * + * @see java.sql.Connection#close() + */ + void close(); + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegateFactory.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegateFactory.java new file mode 100644 index 0000000..d89c1f0 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/delegate/RepositoryDelegateFactory.java @@ -0,0 +1,96 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.delegate; + +import java.sql.SQLException; +import java.util.Properties; +import org.modeshape.jdbc.JdbcLocalI18n; +import org.modeshape.jdbc.LocalJcrDriver; +import org.modeshape.jdbc.LocalJcrDriver.JcrContextFactory; + +/** + * The RepositoryDelegateFactory is used to create the required type of {@link RepositoryDelegate} based upon the url + * provided. The url must be prefixed by {@value LocalJcrDriver#JNDI_URL_PREFIX}. + */ +public abstract class RepositoryDelegateFactory { + + protected static final int PROTOCOL_UNKNOWN = -1; + protected static final int PROTOCOL_JNDI = 1; + + protected RepositoryDelegateFactory() { + } + + /** + * Create a RepositoryDelegate instance, given the connection information. + * + * @param url the JDBC URL; may be null + * @param info the connection properties + * @param contextFactory the factory for a JCR context; may not be null + * @return the RepositoryDelegate for the supplied connection information + * @throws SQLException + */ + public RepositoryDelegate createRepositoryDelegate( String url, + Properties info, + JcrContextFactory contextFactory ) throws SQLException { + if (!acceptUrl(url)) { + throw new SQLException(JdbcLocalI18n.invalidUrlPrefix.text(LocalJcrDriver.JNDI_URL_PREFIX)); + } + return create(determineProtocol(url), url, info, contextFactory); + } + + /** + * Determine if this factory accepts the supplied URL. + * + * @param url the connection URL + * @return true if this factory accepts the supplied URL, or false otherwise + */ + public boolean acceptUrl( String url ) { + if (url == null) return false; + url = url.trim(); + if (url.length() == 0) return false; + return (determineProtocol(url) > 0 ? true : false); + } + + protected int determineProtocol( String url ) { + assert url != null; + assert url.length() != 0; + if (url.startsWith(LocalJcrDriver.JNDI_URL_PREFIX) && url.length() > LocalJcrDriver.JNDI_URL_PREFIX.length()) { + // This fits the pattern so far ... + return PROTOCOL_JNDI; + } + return -1; + } + + protected RepositoryDelegate create( int protocol, + String url, + Properties info, + JcrContextFactory contextFactory ) { + switch (protocol) { + case PROTOCOL_JNDI: + return new LocalRepositoryDelegate(url, info, contextFactory); + default: + return null; + } + } +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnNames.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnNames.java new file mode 100644 index 0000000..adc27f2 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnNames.java @@ -0,0 +1,380 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jdbc.metadata; + +/*

    This class contains constants indicating names of the columns in the + * result sets returned by methods on JcrMetaData. Each inner class represents + * a particular method and the class attributes give the names of the columns on + * methods ResultSet.

    + */ + +public interface JDBCColumnNames { + + /** + * This class contains constants representing column names on ResultSet + * returned by getCatalogs method on DatabaseMetaData. These constant values + * are be used for the column names used in constructing the ResultSet obj. + */ + interface CATALOGS { + // name of the column containing catalog or Virtual database name. + static final String TABLE_CAT = "TABLE_CAT"; //$NON-NLS-1$ + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getColumns method on DatabaseMetaData. These constant values + * are be used to hardcode the column names used in constructin the ResultSet obj. + */ + interface COLUMNS { + + // name of the column containing catalog or Virtual database name. + static final String TABLE_CAT = "TABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version. + static final String TABLE_SCHEM = "TABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name. + static final String TABLE_NAME = "TABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing column or element name. + static final String COLUMN_NAME = "COLUMN_NAME"; //$NON-NLS-1$ + + /** name of column that contains SQL type from java.sql.Types for column's data type. */ + static final String DATA_TYPE = "DATA_TYPE"; //$NON-NLS-1$ + + /** name of column that contains local type name used by the data source. */ + static final String TYPE_NAME = "TYPE_NAME"; //$NON-NLS-1$ + + // name of the column containing column size. + static final String COLUMN_SIZE = "COLUMN_SIZE"; //$NON-NLS-1$ + + /** name of column that is not used will contain nulls */ + static final String BUFFER_LENGTH = "BUFFER_LENGTH"; //$NON-NLS-1$ + + // name of the column containing number of digits to right of decimal + static final String DECIMAL_DIGITS = "DECIMAL_DIGITS"; //$NON-NLS-1$ + + // name of the column containing column's Radix. + static final String NUM_PREC_RADIX = "NUM_PREC_RADIX"; //$NON-NLS-1$ + + /** name of column that has an String value indicating nullablity */ + static final String NULLABLE = "NULLABLE"; //$NON-NLS-1$ + + /** name of column containing explanatory notes. */ + static final String REMARKS = "REMARKS"; //$NON-NLS-1$ + + /** name of column which contails default value for the column. */ + static final String COLUMN_DEF = "COLUMN_DEF"; //$NON-NLS-1$ + + /** name of column that not used will contain nulls */ + static final String SQL_DATA_TYPE = "SQL_DATA_TYPE"; //$NON-NLS-1$ + + /** name of column that not used will contain nulls */ + static final String SQL_DATETIME_SUB = "SQL_DATETIME_SUB"; //$NON-NLS-1$ + + /** name of column that stores the max number of bytes in the column */ + static final String CHAR_OCTET_LENGTH = "CHAR_OCTET_LENGTH"; //$NON-NLS-1$ + + /** name of column that stores the index of a column in the table */ + static final String ORDINAL_POSITION = "ORDINAL_POSITION"; //$NON-NLS-1$ + + /** name of column that has an String value indicating nullablity */ + static final String IS_NULLABLE = "IS_NULLABLE"; //$NON-NLS-1$ + + /** name of column that is the scope of a reference attribute (null if DATA_TYPE isn't REF)*/ + static final String SCOPE_CATLOG = "SCOPE_CATLOG"; //$NON-NLS-1$ + + /** name of column that is the scope of a reference attribute (null if the DATA_TYPE isn't REF) */ + static final String SCOPE_SCHEMA = "SCOPE_SCHEMA"; //$NON-NLS-1$ + + /** name of column that is the scope of a reference attribure (null if the DATA_TYPE isn't REF) */ + static final String SCOPE_TABLE = "SCOPE_TABLE"; //$NON-NLS-1$ + + /** + * name of column that is source type of a distinct type or user-generated Ref type, SQL type + * from java.sql.Types (null if DATA_TYPE isn't DISTINCT or user-generated REF) + */ + static final String SOURCE_DATA_TYPE = "SOURCE_DATA_TYPE"; //$NON-NLS-1$ + + /** name of column that has an String value indicating format */ + static final String FORMAT = "FORMAT"; //$NON-NLS-1$ + + /** name of column that has an String value indicating minimum range */ + static final String MIN_RANGE = "MIN_RANGE"; //$NON-NLS-1$ + + /** name of column that has an String value indicating maximum range */ + static final String MAX_RANGE = "MAX_RANGE"; //$NON-NLS-1$ + } + + + /** + * This class contains constants representing column names on ResultSet + * returned by getSchemas method on DatabaseMetaData. These constant values + * are be used to hardcode the column names used in constructin the ResultSet obj. + */ + interface SCHEMAS { + + // name of the column containing procedure catalog or Virtual database name. + static final String TABLE_SCHEM = "TABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version. + static final String TABLE_CATALOG = "TABLE_CATALOG"; //$NON-NLS-1$ + + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getTables and getTableTypes methods on DatabaseMetaData. These + * constant values are be used to hardcode the column names used in construction + * the ResultSet obj. + */ + interface TABLES { + + // name of the column containing catalog or Virtual database name. + static final String TABLE_CAT = "TABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version. + static final String TABLE_SCHEM = "TABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name. + static final String TABLE_NAME = "TABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing table or group type. + static final String TABLE_TYPE = "TABLE_TYPE"; //$NON-NLS-1$ + + /** name of column containing explanatory notes. */ + static final String REMARKS = "REMARKS"; //$NON-NLS-1$ + static final String TYPE_CAT = "TYPE_CAT"; //$NON-NLS-1$ + static final String TYPE_SCHEM = "TYPE_SCHEM"; //$NON-NLS-1$ + static final String TYPE_NAME = "TYPE_NAME"; //$NON-NLS-1$ + static final String SELF_REFERENCING_COL_NAME = "SELF_REFERENCING_COL_NAME"; //$NON-NLS-1$ + static final String REF_GENERATION = "REF_GENERATION"; //$NON-NLS-1$ + static final String ISPHYSICAL = "ISPHYSICAL"; //$NON-NLS-1$ + + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getTables and getTableTypes methods on DatabaseMetaData. These + * constant values are be used to hardcode the column names used in construction + * the ResultSet obj. + */ + interface TABLE_TYPES { + + // name of the column containing table or group type. + static final String TABLE_TYPE = "TABLE_TYPE"; //$NON-NLS-1$ + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getTypeInfo method on DatabaseMetaData. These constant values + * are be used to hard code the column names used in construction of the ResultSet obj. + */ + interface TYPE_INFO { + + /** name of column that contains local type name used by the data source. */ + static final String TYPE_NAME = "TYPE_NAME"; //$NON-NLS-1$ + + /** name of column that contains SQL type from java.sql.Types for column's data type. */ + static final String DATA_TYPE = "DATA_TYPE"; //$NON-NLS-1$ + + // name of the column containing number of digits to right of decimal + static final String PRECISION = "PRECISION"; //$NON-NLS-1$ + + // name of the column containing prefix used to quote a literal + static final String LITERAL_PREFIX = "LITERAL_PREFIX"; //$NON-NLS-1$ + + // name of the column containing suffix used to quote a literal + static final String LITERAL_SUFFIX = "LITERAL_SUFFIX"; //$NON-NLS-1$ + + // name of the column containing params used in creating the type + static final String CREATE_PARAMS = "CREATE_PARAMS"; //$NON-NLS-1$ + + /** name of column that has an String value indicating nullablity */ + static final String NULLABLE = "NULLABLE"; //$NON-NLS-1$ + + /** name of column that has an String value indicating case sensitivity */ + static final String CASE_SENSITIVE = "CASE_SENSITIVE"; //$NON-NLS-1$ + + /** name of column that has an String value indicating searchability */ + static final String SEARCHABLE = "SEARCHABLE"; //$NON-NLS-1$ + + /** name of column that has an String value indicating searchability */ + static final String UNSIGNED_ATTRIBUTE = "UNSIGNED_ATTRIBUTE"; //$NON-NLS-1$ + + /** name of column that contains info if the column is a currency value */ + static final String FIXED_PREC_SCALE = "FIXED_PREC_SCALE"; //$NON-NLS-1$ + + /** name of column that contains info whether the column is autoincrementable */ + static final String AUTOINCREMENT = "AUTO_INCREMENT"; //$NON-NLS-1$ + + /** name of column that localised version of type name */ + static final String LOCAL_TYPE_NAME = "LOCAL_TYPE_NAME"; //$NON-NLS-1$ + + /** name of column that gives the min scale supported */ + static final String MINIMUM_SCALE = "MINIMUM_SCALE"; //$NON-NLS-1$ + + /** name of column that gives the max scale supported */ + static final String MAXIMUM_SCALE = "MAXIMUM_SCALE"; //$NON-NLS-1$ + + /** name of column that not used will contain nulls */ + static final String SQL_DATA_TYPE = "SQL_DATA_TYPE"; //$NON-NLS-1$ + + /** name of column that not used will contain nulls */ + static final String SQL_DATETIME_SUB = "SQL_DATETIME_SUB"; //$NON-NLS-1$ + + // constant indiacting column's Radix. + static final String NUM_PREC_RADIX = "NUM_PREC_RADIX"; //$NON-NLS-1$ + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getCrossReference, getExportedKeys, and getImportedKeys methods + * on DatabaseMetaData. These constant values are be used to hard code the + * column names used in construction the ResultSet obj. + */ + interface REFERENCE_KEYS { + + // name of the column containing catalog or Virtual database name for primary key's table. + static final String PKTABLE_CAT = "PKTABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version for primary key's table. + static final String PKTABLE_SCHEM = "PKTABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name for primary key's table. + static final String PKTABLE_NAME = "PKTABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing column or element name of the primary key. + static final String PKCOLUMN_NAME = "PKCOLUMN_NAME"; //$NON-NLS-1$ + + // name of the column containing catalog or Virtual database name for foreign key's table. + static final String FKTABLE_CAT = "FKTABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version for foreign key's table. + static final String FKTABLE_SCHEM = "FKTABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name for foreign key's table. + static final String FKTABLE_NAME = "FKTABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing column or element name of the foreign key. + static final String FKCOLUMN_NAME = "FKCOLUMN_NAME"; //$NON-NLS-1$ + + // name of the column containing sequence number within the foreign key + static final String KEY_SEQ = "KEY_SEQ"; //$NON-NLS-1$ + + // name of the column containing effect on foreign key when PK is updated. + static final String UPDATE_RULE = "UPDATE_RULE"; //$NON-NLS-1$ + + // name of the column containing effect on foreign key when PK is deleted. + static final String DELETE_RULE = "DELETE_RULE"; //$NON-NLS-1$ + + // name of the column containing name of the foreign key. + static final String FK_NAME = "FK_NAME"; //$NON-NLS-1$ + + // name of the column containing name of the primary key. + static final String PK_NAME = "PK_NAME"; //$NON-NLS-1$ + + // name of the column containing deferability of foreign key constraStrings. + static final String DEFERRABILITY = "DEFERRABILITY"; //$NON-NLS-1$ + static final String FKPOSITION = "FKPOSITION"; //$NON-NLS-1$ + } + + + /** + * This class contains constants representing column names on ResultSet + * returned by getPrimaryKeys method on DatabaseMetaData. These constant values + * are be used to hard code the column names used in construction the ResultSet obj. + */ + interface PRIMARY_KEYS { + + // name of the column containing catalog or Virtual database name. + static final String TABLE_CAT = "TABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing schema or Virtual database version. + static final String TABLE_SCHEM = "TABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name. + static final String TABLE_NAME = "TABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing column or element name. + static final String COLUMN_NAME = "COLUMN_NAME"; //$NON-NLS-1$ + + // name of the column containing sequence number within the primary key + static final String KEY_SEQ = "KEY_SEQ"; //$NON-NLS-1$ + + // name of the column containing name of the primary key. + static final String PK_NAME = "PK_NAME"; //$NON-NLS-1$ + static final String POSITION = "POSITION"; //$NON-NLS-1$ + } + + /** + * This class contains constants representing column names on ResultSet + * returned by getIndexInfo method on DatabaseMetaData. These constant values + * are be used to hard code the column names used in construction the ResultSet obj. + */ + interface INDEX_INFO { + + // name of the column containing tables catalog name on which the index is present + static final String TABLE_CAT = "TABLE_CAT"; //$NON-NLS-1$ + + // name of the column containing tables schema name on which the index is present + static final String TABLE_SCHEM = "TABLE_SCHEM"; //$NON-NLS-1$ + + // name of the column containing table or group name. + static final String TABLE_NAME = "TABLE_NAME"; //$NON-NLS-1$ + + // name of the column containing name of column showing if an index in non-unique + static final String NON_UNIQUE = "NON_UNIQUE"; //$NON-NLS-1$ + + // name of the column containing name of column containing index_qualifier string + static final String INDEX_QUALIFIER = "INDEX_QUALIFIER"; //$NON-NLS-1$ + + // name of the column containing name of column containing index names + static final String INDEX_NAME = "INDEX_NAME"; //$NON-NLS-1$ + + // name of the column containing name of column containing index types + static final String TYPE = "TYPE"; //$NON-NLS-1$ + + // name of the column containing name of the column containing column position. + static final String ORDINAL_POSITION = "ORDINAL_POSITION"; //$NON-NLS-1$ + + // name of the column containing name of the column containing column names. + static final String COLUMN_NAME = "COLUMN_NAME"; //$NON-NLS-1$ + + // name of the column containing name of column containing info if the index is asc or desc. + static final String ASC_OR_DESC = "ASC_OR_DESC"; //$NON-NLS-1$ + + // name of the column containing name of the column containing number of unique values in index. + static final String CARDINALITY = "CARDINALITY"; //$NON-NLS-1$ + + // name of the column containing name of the column giving number od pages used for the current index. + static final String PAGES = "PAGES"; //$NON-NLS-1$ + + // name of the column containing name of the column giving filter condition. + static final String FILTER_CONDITION = "FILTER_CONDITION"; //$NON-NLS-1$ + } + + + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnPositions.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnPositions.java new file mode 100644 index 0000000..72bd16a --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCColumnPositions.java @@ -0,0 +1,578 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.modeshape.jdbc.metadata; + +/** + *

    This class provides constants indicating positions of columns in the + * ResultSets returned by methods on MMDatabaseMetaData + * object. The inner classes represent the methods while attributes represent the + * column positions. The name of the constant explains the column content.

    + *

    The constants in the inner classes could include column positions for columns + * that are hardcoded, columns positions of some columns on server's + * Results object.

    + *

    Each of the inner classes have a constant MAX_COLUMNS that + * represents the number of columns to be read from the server's Results + * object.

    + *

    All the column positions are one based. + */ + +public interface JDBCColumnPositions { + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface SCHEMAS { + /** Number of columns to be read from results returned getElements method. */ + static final int MAX_COLUMNS = 2; + static final int TABLE_CATALOG = 2; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface CATALOGS { + + /** Number of columns to be read from results returned getElements method. */ + static final int MAX_COLUMNS = 1; + } + + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface COLUMNS { + + /** Number of columns to be read from results returned getElements method. */ + static final int MAX_COLUMNS = 22; + + /** Position of column that contains catalog name in which the table for the column is present. */ + static final int TABLE_CAT = 1; + + static final int TABLE_SCHEM = 2; + + static final int TABLE_NAME = 3; + + static final int COLUMN_NAME = 4; + + /** Position of column that contains SQL type from java.sql.Types for column's data type. */ + static final int DATA_TYPE = 5; + + /** Position of column that contains local type name used by the data source. */ + static final int TYPE_NAME = 6; + + static final int COLUMN_SIZE = 7; + + /** Position of column that is not used will contain nulls */ + static final int BUFFER_LENGTH = 8; + + static final int DECIMAL_DIGITS = 9; + + static final int NUM_PREC_RADIX = 10; + + /** Position of column that has an int value indicating nullablity */ + static final int NULLABLE = 11; + + /** Position of column containing explanatory notes. */ + static final int REMARKS = 12; + + static final int COLUMN_DEF = 13; + + /** Position of column that not used will contain nulls */ + static final int SQL_DATA_TYPE = 14; + + /** Position of column that not used will contain nulls */ + static final int SQL_DATETIME_SUB = 15; + + static final int CHAR_OCTET_LENGTH = 16; + + static final int ORDINAL_POSITION = 17; + + /** Position of column that has an String value indicating nullablity */ + static final int IS_NULLABLE = 18; + + static final int SCOPE_CATALOG = 19; + + static final int SCOPE_SCHEMA = 20; + + static final int SCOPE_TABLE = 21; + + static final int SOURCE_DATA_TYPE = 22; + + static final int IS_AUTOINCREMENT = 23; + + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface TABLES { + + /** Number of columns to be read from results returned getTables method. */ + static final int MAX_COLUMNS = 10; + + /** Position of column that contains catalog name in which the table is present. */ + static final int TABLE_CAT = 1; + static final int TYPE_CAT = 6; + static final int TYPE_SCHEM = 7; + static final int TYPE_NAME = 8; + static final int SELF_REFERENCING_COL_NAME = 9; + static final int REF_GENERATION = 10; + static final int ISPHYSICAL = 11; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface TYPE_INFO { + + /** Number of columns to be read from results returned getElements method. */ + static final int MAX_COLUMNS = 18; + + /** Position of column that contains local type name used by the data source. */ + static final int TYPE_NAME = 1; + + /** Position of column that contains SQL type from java.sql.Types for column's data type. */ + static final int DATA_TYPE = 2; + + static final int PRECISION = 3; + /** Position of column that contains prefix used to quote a literal. */ + static final int LITERAL_PREFIX = 4; + + /** Position of column that contains suffix used to quote a literal. */ + static final int LITERAL_SUFFIX = 5; + + /** Position of column that contains params used in creating the type. */ + static final int CREATE_PARAMS = 6; + + /** Position of column that contains the nullable value. */ + static final int NULLABLE = 7; + + static final int CASE_SENSITIVE = 8; + + /** Position of column that contains the searchable value. */ + static final int SEARCHABLE = 9; + + /** Position of column that contains the unsigned value. */ + static final int UNSIGNED_ATTRIBUTE = 10; + + static final int FIXED_PREC_SCALE = 11; + + static final int AUTO_INCREMENT = 12; + + /** Position of column that contains local type name used by the data source. */ + static final int LOCAL_TYPE_NAME = 13; + + /** Position of column that contains the min scale value. */ + static final int MINIMUM_SCALE = 14; + + /** Position of column that contains the max scale value. */ + static final int MAXIMUM_SCALE = 15; + + /** Position of column that not used will contain nulls */ + static final int SQL_DATA_TYPE = 16; + + /** Position of column that not used will contain nulls */ + static final int SQL_DATETIME_SUB = 17; + + static final int NUM_PREC_RADIX = 18; + + /** Position of column in server's results containing name of the datatype.*/ + static final int NAME = 19; + + /** Position of column in server's results containing isSigned value.*/ + static final int IS_SIGNED = 20; + + /** Position of column in server's results containing nullType name.*/ + static final int NULL_TYPE_NAME = 21; + + /** Position of column in server's results containing search type name.*/ + static final int SEARCH_TYPE_NAME = 22; + } + + /** + * This class contains constants representing column positions on ResultSet + * returned by getUDTS method on DatabaseMetaData. These constant values + * are be used to hardcode the column values used in constructin the ResultSet obj. + */ + interface UDTS { + + /** Number of columns to be read from results returned getUserDefinedTypes method. */ + static final int MAX_COLUMNS = 7; + + // name of the column containing table or Groups name in which UDTS are present. + static final int TABLE_NAME = 3; + + // name of the column containing catalog or Virtual database name. + static final int TYPE_CAT = 1; + + // name of the column containing schema or Virtual database version. + static final int TYPE_SCHEM = 2; + + // name of the column containing name of type name column. + static final int TYPE_NAME = 9; + + // name of the column containing class name column. + static final int CLASS_NAME = 4; + + // name of the column containing name of sql datatype code column + static final int DATA_TYPE = 5; + + // name of the column containing comments column + static final int REMARKS = 6; + + static final int BASE_TYPE = 7; + /** Position of column in server's results containing java class name.*/ + static final int JAVA_CLASS = 8; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getIndexInfo method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from the query against System.KeyElements table.

    + */ + interface INDEX_INFO { + + /** Number of columns to be read from results returned by server results. */ + static final int MAX_COLUMNS = 13; + + /** Position of column that contains catalog name of the table. */ + static final int TABLE_CAT = 1; + + static final int TABLE_SCHEM = 2; + + static final int TABLE_NAME = 3; + + /** Position of column that contains non uniqueness of the index. */ + static final int NON_UNIQUE = 4; + + /** Position of column that contains qualifier for the index. */ + static final int INDEX_QUALIFIER = 5; + + static final int INDEX_NAME = 6; + + /** Position of column that contains type of index. */ + static final int TYPE = 7; + + static final int ORDINAL_POSITION = 8; + + static final int COLUMN_NAME = 9; + + /** Position of column that contains desc if index is ascending or descending. */ + static final int ASC_OR_DESC = 10; + + /** Position of column that contains cardinality of the index. */ + static final int CARDINALITY = 11; + + /** Position of column that contains pages oocupied by table. */ + static final int PAGES = 12; + + /** Position of column that contains any filter condition. */ + static final int FILTER_CONDITION = 13; + + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface PRIMARY_KEYS { + + /** Number of columns to be read from results returned by getPrimaryKeys. */ + static final int MAX_COLUMNS = 6; + + /** Position of column that contains catalog name of the primaryTable. */ + static final int TABLE_CAT = 1; + static final int TABLE_SCHEM = 2; + static final int TABLE_NAME = 3; + static final int COLUMN_NAME = 4; + static final int KEY_SEQ = 5; + static final int PK_NAME = 6; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getCrossReferences method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getCrossReferences method on server's Metadata object. + */ + interface REFERENCE_KEYS { + + /** Number of columns to be read from results returned any of the 3 methods. */ + static final int MAX_COLUMNS = 14; + + /** Position of column that contains catalog name of the primaryTable. */ + static final int PKTABLE_CAT = 1; + + /** Position of column that contains scheam name of the primaryTable. */ + static final int PKTABLE_SCHEM = 2; + + static final int PKTABLE_NAME = 3; + + static final int PKCOLUMN_NAME = 4; + + /** Position of column that contains catalog name of the foreignTable. */ + static final int FKTABLE_CAT = 5; + + /** Position of column that contains schema name of the foreignTable. */ + static final int FKTABLE_SCHEM = 6; + + static final int FKTABLE_NAME = 7; + + static final int FKCOLUMN_NAME = 8; + + static final int KEY_SEQ = 9; + + /** Position of column that determines how forein key changes if PK is updated. */ + static final int UPDATE_RULE = 10; + + /** Position of column that determines how forein key changes if PK is deleted. */ + static final int DELETE_RULE = 11; + + static final int FK_NAME = 12; + + static final int PK_NAME = 13; + + /** Position of column that determines if forein key constraints can be deffered until commit. */ + static final int DEFERRABILITY = 14; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getProcedures method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface PROCEDURES { + + /** Number of columns to be read from results returned getCrossReferences method. */ + static final int MAX_COLUMNS = 9; + + /** Position of column that contains catalog name of the procedure. */ + static final int PROCEDURE_CAT = 1; + static final int PROCEDURE_SCHEM = 2; + static final int PROCEDURE_NAME = 3; + + /** Position of column the is reserved for future use. */ + static final int RESERVED_1 = 4; + + /** Position of column the is reserved for future use. */ + static final int RESERVED_2 = 5; + + /** Position of column the is reserved for future use. */ + static final int RESERVED_3 = 6; + + static final int REMARKS = 7; + + /** Position of column Procedure type. */ + static final int PROCEDURE_TYPE = 8; + + static final int SPECIFIC_NAME = 9; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + * JAVA_CLASS is the column position for element data type on + * server's Results object. + */ + interface PROCEDURE_COLUMNS { + + /** Number of columns to be read from results returned getProcedureColumns method. */ + static final int MAX_COLUMNS = 20; + + /** Position of column that contains catalog name of the procedure. */ + static final int PROCEDURE_CAT = 1; + + static final int PROCEDURE_SCHEM = 2; + static final int PROCEDURE_NAME = 3; + static final int COLUMN_NAME = 4; + + /** Position of the column containing column or element type. */ + static final int COLUMN_TYPE = 5; + + /** Position of column that contains SQL type from java.sql.Types for column's data type. */ + static final int DATA_TYPE = 6; + + /** Position of column that contains local type name used by the data source. */ + static final int TYPE_NAME = 7; + + static final int PRECISION = 8; + static final int LENGTH = 9; + static final int SCALE = 10; + static final int RADIX = 11; + + /** Position of column that contains the nullable value. */ + static final int NULLABLE = 12; + + /** Position of column that contains comments. */ + static final int REMARKS = 13; + static final int COLUMN_DEF = 14; + + static final int SQL_DATA_TYPE = 15; + static final int SQL_DATETIME_SUB = 16; + static final int CHAR_OCTET_LENGTH = 17; + + static final int ORDINAL_POSITION = 18; + + static final int IS_NULLABLE = 19; + + static final int SPECIFIC_NAME = 20; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class also has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + */ + interface TABLE_PRIVILEGES { + + /** Number of columns to be read from results returned getGroupEntitlements method. */ + static final int MAX_COLUMNS = 6; + + /** Position of VirtualDatabaseName column in server's results object returned by + getGroupEntitlements method in User API */ + static final int VIRTUAL_DATABASE_NAME = 0; + + /** Position of VirtualDatabaseVersion column in server's results object returned by + getElementEntitlements method in User API */ + static final int VIRTUAL_DATABASE_VERSION = 1; + + /** Position of GroupName column in server's results object returned by + getGroupEntitlements method in User API */ + static final int GROUP_NAME = 2; + + /** Position of Grantor column in server's results object returned by + getGroupEntitlements method in User API */ + static final int GRANTOR = 3; + + /** Position of Grantee column in server's results object returned by + getGroupEntitlements method in User API */ + static final int GRANTEE = 4; + + /** Position of Permission column in server's results object returned by + getGroupEntitlements method in User API */ + static final int PERMISSION = 5; + + /** Position of the column containing catalog name info. */ + static final int TABLE_CAT = 0; + + /** Position of the column containing privilage grantable info. */ + static final int IS_GRANTABLE = 6; + } + + /** + *

    This class contains constants representing column positions on ResultSet + * returned by getColumns method on DatabaseMetaData. The class also has constants + * for columns whose values are to be hardcoded in MMDatabaseMetaData object. + * MAX_COLUMNS is the number of columns to be read from server's + * results from getElements method on Metadata object. + */ + interface COLUMN_PRIVILEGES { + + /** Number of columns to be read from results returned getElementEntitlements method. */ + static final int MAX_COLUMNS = 7; + + /** Position of VirtualDatabaseName column in server's results object returned by + getElementEntitlements method in User API */ + static final int VIRTUAL_DATABASE_NAME = 0; + + /** Position of VirtualDatabaseVersion column in server's results object returned by + getElementEntitlements method in User API */ + static final int VIRTUAL_DATABASE_VERSION = 1; + + /** Position of GroupName column in server's results object returned by + getElementEntitlements method in User API */ + static final int GROUP_NAME = 2; + + /** Position of ElementName column in server's results object returned by + getElementEntitlements method in User API */ + static final int ELEMENT_NAME = 3; + + /** Position of Grantor column in server's results object returned by + getElementEntitlements method in User API */ + static final int GRANTOR = 4; + + /** Position of Grantee column in server's results object returned by + getElementEntitlements method in User API */ + static final int GRANTEE = 5; + + /** Position of Permission column in server's results object returned by + getElementEntitlements method in User API */ + static final int PERMISSION = 6; + + /** Position of the column containing catalog name info. */ + static final int TABLE_CAT = 0; + + /** Position of the column containing privilage grantable info. */ + static final int IS_GRANTABLE = 7; + } + +} diff --git a/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCSQLTypeInfo.java b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCSQLTypeInfo.java new file mode 100644 index 0000000..3ce6459 --- /dev/null +++ b/utils/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/metadata/JDBCSQLTypeInfo.java @@ -0,0 +1,88 @@ +/* + * JBoss, Home of Professional Open Source. + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +package org.modeshape.jdbc.metadata; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; + +import javax.lang.model.type.NullType; + + +/** + *

    This is a helper class used to obtain SQL type information for java types. + * The SQL type information is obtained from java.sql.Types class. The integers and + * strings returned by methods in this class are based on constants in java.sql.Types. + */ + +public final class JDBCSQLTypeInfo { + + + // Prevent instantiation + private JDBCSQLTypeInfo() {} + + public static final class DefaultDataTypes { + public static final String STRING = "string"; //$NON-NLS-1$ + public static final String BOOLEAN = "boolean"; //$NON-NLS-1$ + public static final String BYTE = "byte"; //$NON-NLS-1$ + public static final String SHORT = "short"; //$NON-NLS-1$ + public static final String CHAR = "char"; //$NON-NLS-1$ + public static final String INTEGER = "integer"; //$NON-NLS-1$ + public static final String LONG = "long"; //$NON-NLS-1$ + public static final String BIG_INTEGER = "biginteger"; //$NON-NLS-1$ + public static final String FLOAT = "float"; //$NON-NLS-1$ + public static final String DOUBLE = "double"; //$NON-NLS-1$ + public static final String BIG_DECIMAL = "bigdecimal"; //$NON-NLS-1$ + public static final String DATE = "date"; //$NON-NLS-1$ + public static final String TIME = "time"; //$NON-NLS-1$ + public static final String TIMESTAMP = "timestamp"; //$NON-NLS-1$ + public static final String OBJECT = "object"; //$NON-NLS-1$ + public static final String NULL = "null"; //$NON-NLS-1$ + public static final String BLOB = "blob"; //$NON-NLS-1$ + public static final String CLOB = "clob"; //$NON-NLS-1$ + public static final String XML = "xml"; //$NON-NLS-1$ + } + + //java class names + public static final class DefaultDataClasses { + public static final Class STRING = String.class; + public static final Class BOOLEAN = Boolean.class; + public static final Class BYTE = Byte.class; + public static final Class SHORT = Short.class; + public static final Class CHAR = Character.class; + public static final Class INTEGER = Integer.class; + public static final Class LONG = Long.class; + public static final Class BIG_INTEGER = BigInteger.class; + public static final Class FLOAT = Float.class; + public static final Class DOUBLE = Double.class; + public static final Class BIG_DECIMAL = BigDecimal.class; + public static final Class DATE = java.sql.Date.class; + public static final Class