From ac98cda22451f0aaf6e70ded9aca4e234449b0b7 Mon Sep 17 00:00:00 2001 From: Emmanuel Hugonnet Date: Thu, 20 Feb 2020 19:01:38 +0100 Subject: [PATCH] [ARTEMIS-2626]: Postgresql Journal implementation requires direct access to PostgeSQL driver internal classes. Issue: The BLOB manipulation is done using PostgreSQL internal classes starting from PGConnection. This leads to ClasCastExceptions if the connection is wrapped in a pool or if the driver is in a different classloader (WildFly). Fix: unwrap the connection and if the PostgreSQL classes are not directly available uses reflection to manipulate the BLOBs. Jira: https://issues.apache.org/jira/browse/ARTEMIS-2626 --- .../file/PostgresLargeObjectManager.java | 209 ++++++++++ ...ostgresSequentialSequentialFileDriver.java | 46 +-- .../file/JDBCSequentialFileFactoryTest.java | 4 +- .../file/PostgresLargeObjectManagerTest.java | 362 ++++++++++++++++++ 4 files changed, 592 insertions(+), 29 deletions(-) create mode 100644 artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java rename artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/{ => store}/file/JDBCSequentialFileFactoryTest.java (98%) create mode 100644 artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java new file mode 100644 index 0000000000..3167c54d7a --- /dev/null +++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java @@ -0,0 +1,209 @@ +/* + * Copyright 2019 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jdbc.store.file; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; +import org.postgresql.PGConnection; +import org.postgresql.largeobject.LargeObject; + +/** + * Helper class for when the postresql driver is not directly availalbe. + */ +public class PostgresLargeObjectManager { + + /** + * This mode indicates we want to write to an object + */ + public static final int WRITE = 0x00020000; + + /** + * This mode indicates we want to read an object + */ + public static final int READ = 0x00040000; + + /** + * This mode is the default. It indicates we want read and write access to + * a large object + */ + public static final int READWRITE = READ | WRITE; + + private final Connection realConnection; + private boolean shouldUseReflection; + + public PostgresLargeObjectManager(Connection connection) throws SQLException { + this.realConnection = unwrap(connection); + try { + this.getClass().getClassLoader().loadClass("org.postgresql.PGConnection"); + shouldUseReflection = false; + } catch (ClassNotFoundException ex) { + shouldUseReflection = true; + } + } + + public final Long createLO() throws SQLException { + if (shouldUseReflection) { + Object largeObjectManager = getLargeObjectManager(); + try { + Method method = largeObjectManager.getClass().getMethod("createLO"); + return (Long) method.invoke(largeObjectManager); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex); + } + } else { + return ((PGConnection) realConnection).getLargeObjectAPI().createLO(); + } + } + + public Object open(long oid, int mode) throws SQLException { + if (shouldUseReflection) { + Object largeObjectManager = getLargeObjectManager(); + try { + Method method = largeObjectManager.getClass().getMethod("open", long.class, int.class); + return method.invoke(largeObjectManager, oid, mode); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex); + } + } else { + return ((PGConnection) realConnection).getLargeObjectAPI().open(oid, mode); + } + } + + public int size(Object largeObject) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("size"); + return (int) method.invoke(largeObject); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + return ((LargeObject) largeObject).size(); + } + } + + public void close(Object largeObject) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("close"); + method.invoke(largeObject); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + ((LargeObject) largeObject).close(); + } + } + + public byte[] read(Object largeObject, int length) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("read", int.class); + return (byte[]) method.invoke(largeObject, length); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + return ((LargeObject) largeObject).read(length); + } + } + + public void write(Object largeObject, byte[] data) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("write", byte[].class); + method.invoke(largeObject, data); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + ((LargeObject) largeObject).write(data); + } + } + + public void seek(Object largeObject, int position) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("seek", Integer.class); + method.invoke(largeObject, position); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + ((LargeObject) largeObject).seek(position); + } + } + + public void truncate(Object largeObject, int position) throws SQLException { + if (shouldUseReflection) { + try { + Method method = largeObject.getClass().getMethod("truncate", Integer.class); + method.invoke(largeObject, position); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex); + } + } else { + ((LargeObject) largeObject).truncate(position); + } + } + + private Object getLargeObjectManager() throws SQLException { + if (shouldUseReflection) { + try { + Method method = realConnection.getClass().getMethod("getLargeObjectAPI"); + return method.invoke(realConnection); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex); + } + } else { + return ((PGConnection) realConnection).getLargeObjectAPI(); + } + } + + public final Connection unwrap(Connection connection) throws SQLException { + Connection conn = connection.unwrap(Connection.class); + return unwrapIronJacamar(unwrapDbcp(unwrapSpring(conn))); + } + + private Connection unwrapIronJacamar(Connection conn) { + try { + Method method = conn.getClass().getMethod("getUnderlyingConnection"); + return (Connection) method.invoke(conn); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + return conn; + } + } + + private Connection unwrapDbcp(Connection conn) { + try { + Method method = conn.getClass().getMethod("getDelegate"); + return (Connection) method.invoke(conn); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + return conn; + } + } + + private Connection unwrapSpring(Connection conn) { + try { + Method method = conn.getClass().getMethod("getTargetConnection"); + return (Connection) method.invoke(conn); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + return conn; + } + } +} diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java index 3c68781db6..7d439daec7 100644 --- a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java +++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java @@ -23,9 +23,6 @@ import java.sql.SQLException; import java.sql.Statement; import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider; -import org.postgresql.PGConnection; -import org.postgresql.largeobject.LargeObject; -import org.postgresql.largeobject.LargeObjectManager; import javax.sql.DataSource; @@ -33,6 +30,7 @@ import javax.sql.DataSource; public final class PostgresSequentialSequentialFileDriver extends JDBCSequentialFileFactoryDriver { private static final String POSTGRES_OID_KEY = "POSTGRES_OID_KEY"; + private PostgresLargeObjectManager largeObjectManager; public PostgresSequentialSequentialFileDriver() throws SQLException { super(); @@ -52,6 +50,7 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential @Override protected void prepareStatements() throws SQLException { + this.largeObjectManager = new PostgresLargeObjectManager(connection); this.deleteFile = connection.prepareStatement(sqlProvider.getDeleteFileSQL()); this.createFile = connection.prepareStatement(sqlProvider.getInsertFileSQL(), Statement.RETURN_GENERATED_KEYS); this.selectFileByFileName = connection.prepareStatement(sqlProvider.getSelectFileByFileName()); @@ -67,9 +66,7 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential synchronized (connection) { try { connection.setAutoCommit(false); - - LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI(); - long oid = lobjManager.createLO(); + Long oid = largeObjectManager.createLO(); createFile.setString(1, file.getFileName()); createFile.setString(2, file.getExtension()); @@ -109,20 +106,19 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential @Override public int writeToFile(JDBCSequentialFile file, byte[] data, boolean append) throws SQLException { synchronized (connection) { - LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI(); - LargeObject largeObject = null; + Object largeObject = null; Long oid = getOID(file); try { connection.setAutoCommit(false); - largeObject = lobjManager.open(oid, LargeObjectManager.WRITE); + largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.WRITE); if (append) { - largeObject.seek(largeObject.size()); + largeObjectManager.seek(largeObject, largeObjectManager.size(largeObject)); } else { - largeObject.truncate(0); + largeObjectManager.truncate(largeObject, 0); } - largeObject.write(data); - largeObject.close(); + largeObjectManager.write(largeObject, data); + largeObjectManager.close(largeObject); connection.commit(); } catch (Exception e) { connection.rollback(); @@ -134,23 +130,23 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential @Override public int readFromFile(JDBCSequentialFile file, ByteBuffer bytes) throws SQLException { - LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI(); - LargeObject largeObject = null; + Object largeObject = null; long oid = getOID(file); synchronized (connection) { try { connection.setAutoCommit(false); - largeObject = lobjManager.open(oid, LargeObjectManager.READ); - int readLength = (int) calculateReadLength(largeObject.size(), bytes.remaining(), file.position()); + largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.READ); + int readLength = (int) calculateReadLength(largeObjectManager.size(largeObject), bytes.remaining(), file.position()); if (readLength > 0) { - if (file.position() > 0) - largeObject.seek((int) file.position()); - byte[] data = largeObject.read(readLength); + if (file.position() > 0) { + largeObjectManager.seek(largeObject, (int) file.position()); + } + byte[] data = largeObjectManager.read(largeObject, readLength); bytes.put(data); } - largeObject.close(); + largeObjectManager.close(largeObject); connection.commit(); return readLength; @@ -185,17 +181,15 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential } private int getPostGresLargeObjectSize(JDBCSequentialFile file) throws SQLException { - LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI(); - int size = 0; Long oid = getOID(file); if (oid != null) { synchronized (connection) { try { connection.setAutoCommit(false); - LargeObject largeObject = lobjManager.open(oid, LargeObjectManager.READ); - size = largeObject.size(); - largeObject.close(); + Object largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.READ); + size = largeObjectManager.size(largeObject); + largeObjectManager.close(largeObject); connection.commit(); } catch (SQLException e) { connection.rollback(); diff --git a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java similarity index 98% rename from artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java rename to artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java index d74a76c214..fef665c641 100644 --- a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java +++ b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.jdbc.file; +package org.apache.activemq.artemis.jdbc.store.file; import java.nio.ByteBuffer; import java.sql.DriverManager; @@ -37,8 +37,6 @@ import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.jdbc.store.drivers.JDBCUtils; -import org.apache.activemq.artemis.jdbc.store.file.JDBCSequentialFile; -import org.apache.activemq.artemis.jdbc.store.file.JDBCSequentialFileFactory; import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider; import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; import org.apache.activemq.artemis.utils.ThreadLeakCheckRule; diff --git a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java new file mode 100644 index 0000000000..886ce105e8 --- /dev/null +++ b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java @@ -0,0 +1,362 @@ +/* + * Copyright 2020 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jdbc.store.file; + +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.junit.Test; + +public class PostgresLargeObjectManagerTest { + + @Test + public void testShouldNotUseReflection() throws SQLException { + PostgresLargeObjectManager manager = new PostgresLargeObjectManager(new MockConnection()); + try { + manager.createLO(); + fail("Shouldn't be using reflection"); + } catch (ClassCastException ex) { + } + } + + @Test + public void testShouldUseReflection() throws SQLException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + ClassLoader loader = new FunkyClassLoader(); + Class funkyClass = loader.loadClass("org.apache.activemq.artemis.jdbc.store.file.PostgresLargeObjectManager"); + Object manager = funkyClass.getConstructor(Connection.class).newInstance(new MockConnection()); + try { + funkyClass.getMethod("createLO").invoke(manager); + fail("Shouldn't be using reflection"); + } catch (java.lang.reflect.InvocationTargetException ex) { + assertEquals("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex.getCause().getMessage()); + } + } + + private static final class FunkyClassLoader extends URLClassLoader { + + private FunkyClassLoader() { + super(new URL[]{ + FunkyClassLoader.class.getProtectionDomain().getCodeSource().getLocation(), + PostgresLargeObjectManager.class.getProtectionDomain().getCodeSource().getLocation() + }, + ClassLoader.getSystemClassLoader()); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if ("org.postgresql.PGConnection".equals(name)) { + throw new ClassNotFoundException(name); + } + if ("org.apache.activemq.artemis.jdbc.store.file.PostgresLargeObjectManager".equals(name)) { + return this.findClass(name); + } + return super.loadClass(name); + } + } + + private static final class MockConnection implements Connection { + + @Override + public Statement createStatement() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String nativeSQL(String sql) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean getAutoCommit() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void commit() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void rollback() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void close() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isClosed() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isReadOnly() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setCatalog(String catalog) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getCatalog() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int getTransactionIsolation() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public SQLWarning getWarnings() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void clearWarnings() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Map> getTypeMap() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setHoldability(int holdability) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int getHoldability() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Savepoint setSavepoint() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Clob createClob() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Blob createBlob() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public NClob createNClob() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public SQLXML createSQLXML() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValid(int timeout) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getClientInfo(String name) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Properties getClientInfo() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setSchema(String schema) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getSchema() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void abort(Executor executor) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int getNetworkTimeout() throws SQLException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public T unwrap(Class iface) throws SQLException { + return (T) this; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + } +}