From 33024dcc64c900fd5cb82d3143b3b23facb3e553 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 10 Apr 2025 02:28:17 +0300 Subject: [PATCH] Add result set wrapping for jdbc library instrumentation (#13646) --- .../PreparedStatementInstrumentation.java | 3 +- .../jdbc/StatementInstrumentation.java | 3 +- .../jdbc/test/JdbcInstrumentationTest.java | 112 +- instrumentation/jdbc/library/build.gradle.kts | 9 + .../jdbc/OpenTelemetryDriver.java | 2 +- .../datasource/OpenTelemetryDataSource.java | 4 +- .../OpenTelemetryCallableStatement.java | 56 +- .../internal/OpenTelemetryConnection.java | 70 +- .../OpenTelemetryPreparedStatement.java | 30 +- .../jdbc/internal/OpenTelemetryResultSet.java | 1031 +++++++++++++++++ .../jdbc/internal/OpenTelemetryStatement.java | 78 +- .../jdbc/OpenTelemetryDriverTest.java | 4 +- .../OpenTelemetryDataSourceTest.java | 4 +- .../internal/OpenTelemetryConnectionTest.java | 28 + .../jdbc/internal/WrapperTest.java | 41 + 15 files changed, 1441 insertions(+), 34 deletions(-) create mode 100644 instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryResultSet.java create mode 100644 instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/WrapperTest.java diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java index 57174d4233..a822ab9807 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -12,6 +12,7 @@ import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.sta import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; @@ -45,7 +46,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation { public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( nameStartsWith("execute") - .and(not(named("executeBatch"))) + .and(not(namedOneOf("executeBatch", "executeLargeBatch"))) .and(takesArguments(0)) .and(isPublic()), PreparedStatementInstrumentation.class.getName() + "$PreparedStatementAdvice"); diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java index 92ca126861..d0dfd77845 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java @@ -12,6 +12,7 @@ import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.sta import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; @@ -52,7 +53,7 @@ public class StatementInstrumentation implements TypeInstrumentation { named("clearBatch").and(isPublic()), StatementInstrumentation.class.getName() + "$ClearBatchAdvice"); transformer.applyAdviceToMethod( - named("executeBatch").and(takesNoArguments()).and(isPublic()), + namedOneOf("executeBatch", "executeLargeBatch").and(takesNoArguments()).and(isPublic()), StatementInstrumentation.class.getName() + "$ExecuteBatchAdvice"); } diff --git a/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java b/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java index f22e9ad1a2..369a09f31f 100644 --- a/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java +++ b/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java @@ -25,6 +25,7 @@ import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYST import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM_NAME; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; @@ -61,6 +62,7 @@ import java.util.stream.Stream; import javax.sql.DataSource; import org.apache.derby.jdbc.EmbeddedDataSource; import org.apache.derby.jdbc.EmbeddedDriver; +import org.assertj.core.api.ThrowingConsumer; import org.h2.jdbcx.JdbcDataSource; import org.hsqldb.jdbc.JDBCDriver; import org.junit.jupiter.api.AfterAll; @@ -803,10 +805,81 @@ class JdbcInstrumentationTest { String url, String table) throws SQLException { + testPreparedStatementUpdateImpl( + system, + connection, + username, + query, + spanName, + url, + table, + statement -> assertThat(statement.executeUpdate()).isEqualTo(0)); + } + + static Stream preparedStatementLargeUpdateStream() throws SQLException { + return Stream.of( + Arguments.of( + "h2", + new org.h2.Driver().connect(jdbcUrls.get("h2"), null), + null, + "CREATE TABLE PS_LARGE_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))", + "CREATE TABLE jdbcunittest.PS_LARGE_H2", + "h2:mem:", + "PS_LARGE_H2"), + Arguments.of( + "h2", + cpDatasources.get("tomcat").get("h2").getConnection(), + null, + "CREATE TABLE PS_LARGE_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))", + "CREATE TABLE jdbcunittest.PS_LARGE_H2_TOMCAT", + "h2:mem:", + "PS_LARGE_H2_TOMCAT"), + Arguments.of( + "h2", + cpDatasources.get("hikari").get("h2").getConnection(), + null, + "CREATE TABLE PS_LARGE_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))", + "CREATE TABLE jdbcunittest.PS_LARGE_H2_HIKARI", + "h2:mem:", + "PS_LARGE_H2_HIKARI")); + } + + @ParameterizedTest + @MethodSource("preparedStatementLargeUpdateStream") + void testPreparedStatementLargeUpdate( + String system, + Connection connection, + String username, + String query, + String spanName, + String url, + String table) + throws SQLException { + testPreparedStatementUpdateImpl( + system, + connection, + username, + query, + spanName, + url, + table, + statement -> assertThat(statement.executeLargeUpdate()).isEqualTo(0)); + } + + void testPreparedStatementUpdateImpl( + String system, + Connection connection, + String username, + String query, + String spanName, + String url, + String table, + ThrowingConsumer action) + throws SQLException { String sql = connection.nativeSQL(query); PreparedStatement statement = connection.prepareStatement(sql); cleanup.deferCleanup(statement); - testing.runWithSpan("parent", () -> assertThat(statement.executeUpdate()).isEqualTo(0)); + testing.runWithSpan("parent", () -> action.accept(statement)); testing.waitAndAssertTraces( trace -> @@ -1333,7 +1406,39 @@ class JdbcInstrumentationTest { @MethodSource("batchStream") void testBatch(String system, Connection connection, String username, String url) throws SQLException { - String tableName = "simple_batch_test"; + testBatchImpl( + system, + connection, + username, + url, + "simple_batch_test", + statement -> assertThat(statement.executeBatch()).isEqualTo(new int[] {1, 1})); + } + + @ParameterizedTest + @MethodSource("batchStream") + void testLargeBatch(String system, Connection connection, String username, String url) + throws SQLException { + // derby and hsqldb used in this test don't support executeLargeBatch + assumeTrue("h2".equals(system)); + + testBatchImpl( + system, + connection, + username, + url, + "simple_batch_test_large", + statement -> assertThat(statement.executeLargeBatch()).isEqualTo(new long[] {1, 1})); + } + + private static void testBatchImpl( + String system, + Connection connection, + String username, + String url, + String tableName, + ThrowingConsumer action) + throws SQLException { Statement createTable = connection.createStatement(); createTable.execute("CREATE TABLE " + tableName + " (id INTEGER not NULL, PRIMARY KEY ( id ))"); cleanup.deferCleanup(createTable); @@ -1347,8 +1452,7 @@ class JdbcInstrumentationTest { statement.clearBatch(); statement.addBatch("INSERT INTO " + tableName + " VALUES(1)"); statement.addBatch("INSERT INTO " + tableName + " VALUES(2)"); - testing.runWithSpan( - "parent", () -> assertThat(statement.executeBatch()).isEqualTo(new int[] {1, 1})); + testing.runWithSpan("parent", () -> action.accept(statement)); testing.waitAndAssertTraces( trace -> diff --git a/instrumentation/jdbc/library/build.gradle.kts b/instrumentation/jdbc/library/build.gradle.kts index 63116006a6..e61a0cbacb 100644 --- a/instrumentation/jdbc/library/build.gradle.kts +++ b/instrumentation/jdbc/library/build.gradle.kts @@ -16,6 +16,15 @@ dependencies { } tasks { + // We cannot use "--release" javac option here because that will forbid using apis that were added + // in later versions. In JDBC wrappers we wish to implement delegation for methods that are not + // present in jdk8. + compileJava { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + options.release.set(null as Int?) + } + shadowJar { dependencies { // including only current module excludes its transitive dependencies diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java index 8f0e32d63f..d50039ca9b 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java @@ -244,7 +244,7 @@ public final class OpenTelemetryDriver implements Driver { Instrumenter statementInstrumenter = JdbcInstrumenterFactory.createStatementInstrumenter(openTelemetry); - return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter); + return OpenTelemetryConnection.create(connection, dbInfo, statementInstrumenter); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java index 232d28b7aa..deb0425ff2 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java @@ -93,14 +93,14 @@ public class OpenTelemetryDataSource implements DataSource, AutoCloseable { public Connection getConnection() throws SQLException { Connection connection = wrapCall(delegate::getConnection); DbInfo dbInfo = getDbInfo(connection); - return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter); + return OpenTelemetryConnection.create(connection, dbInfo, statementInstrumenter); } @Override public Connection getConnection(String username, String password) throws SQLException { Connection connection = wrapCall(() -> delegate.getConnection(username, password)); DbInfo dbInfo = getDbInfo(connection); - return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter); + return OpenTelemetryConnection.create(connection, dbInfo, statementInstrumenter); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java index 2d829ffa3a..f2c25b172d 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java @@ -35,17 +35,15 @@ import java.sql.NClob; import java.sql.Ref; import java.sql.RowId; import java.sql.SQLException; +import java.sql.SQLType; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class OpenTelemetryCallableStatement +@SuppressWarnings("OverloadMethodsDeclarationOrder") +class OpenTelemetryCallableStatement extends OpenTelemetryPreparedStatement implements CallableStatement { public OpenTelemetryCallableStatement( @@ -489,6 +487,7 @@ public class OpenTelemetryCallableStatement delegate.setBinaryStream(parameterName, x); } + @SuppressWarnings("UngroupedOverloads") @Override public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException { @@ -710,4 +709,51 @@ public class OpenTelemetryCallableStatement public Reader getCharacterStream(String parameterName) throws SQLException { return delegate.getCharacterStream(parameterName); } + + // JDBC 4.2 + + @Override + public void setObject(String parameterName, Object x, SQLType targetSqlType, int scaleOrLength) + throws SQLException { + delegate.setObject(parameterName, x, targetSqlType, scaleOrLength); + } + + @Override + public void setObject(String parameterName, Object x, SQLType targetSqlType) throws SQLException { + delegate.setObject(parameterName, x, targetSqlType); + } + + @Override + public void registerOutParameter(int parameterIndex, SQLType sqlType) throws SQLException { + delegate.registerOutParameter(parameterIndex, sqlType); + } + + @Override + public void registerOutParameter(int parameterIndex, SQLType sqlType, int scale) + throws SQLException { + delegate.registerOutParameter(parameterIndex, sqlType, scale); + } + + @Override + public void registerOutParameter(int parameterIndex, SQLType sqlType, String typeName) + throws SQLException { + delegate.registerOutParameter(parameterIndex, sqlType, typeName); + } + + @Override + public void registerOutParameter(String parameterName, SQLType sqlType) throws SQLException { + delegate.registerOutParameter(parameterName, sqlType); + } + + @Override + public void registerOutParameter(String parameterName, SQLType sqlType, int scale) + throws SQLException { + delegate.registerOutParameter(parameterName, sqlType, scale); + } + + @Override + public void registerOutParameter(String parameterName, SQLType sqlType, String typeName) + throws SQLException { + delegate.registerOutParameter(parameterName, sqlType, typeName); + } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java index ad1a8a09f8..8fe5ca26ab 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java @@ -35,6 +35,7 @@ import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; +import java.sql.ShardingKey; import java.sql.Statement; import java.sql.Struct; import java.util.Map; @@ -47,17 +48,36 @@ import java.util.concurrent.Executor; */ public class OpenTelemetryConnection implements Connection { - private final Connection delegate; + private static final boolean hasJdbc43 = hasJdbc43(); + protected final Connection delegate; private final DbInfo dbInfo; protected final Instrumenter statementInstrumenter; - public OpenTelemetryConnection( + protected OpenTelemetryConnection( Connection delegate, DbInfo dbInfo, Instrumenter statementInstrumenter) { this.delegate = delegate; this.dbInfo = dbInfo; this.statementInstrumenter = statementInstrumenter; } + // visible for testing + static boolean hasJdbc43() { + try { + Class.forName("java.sql.ShardingKey"); + return true; + } catch (ClassNotFoundException exception) { + return false; + } + } + + public static Connection create( + Connection delegate, DbInfo dbInfo, Instrumenter statementInstrumenter) { + if (hasJdbc43) { + return new OpenTelemetryConnectionJdbc43(delegate, dbInfo, statementInstrumenter); + } + return new OpenTelemetryConnection(delegate, dbInfo, statementInstrumenter); + } + @Override public Statement createStatement() throws SQLException { Statement statement = delegate.createStatement(); @@ -369,4 +389,50 @@ public class OpenTelemetryConnection implements Connection { public DbInfo getDbInfo() { return dbInfo; } + + // JDBC 4.3 + static class OpenTelemetryConnectionJdbc43 extends OpenTelemetryConnection { + OpenTelemetryConnectionJdbc43( + Connection delegate, DbInfo dbInfo, Instrumenter statementInstrumenter) { + super(delegate, dbInfo, statementInstrumenter); + } + + @SuppressWarnings("Since15") + @Override + public void beginRequest() throws SQLException { + delegate.beginRequest(); + } + + @SuppressWarnings("Since15") + @Override + public void endRequest() throws SQLException { + delegate.endRequest(); + } + + @SuppressWarnings("Since15") + @Override + public boolean setShardingKeyIfValid( + ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException { + return delegate.setShardingKeyIfValid(shardingKey, superShardingKey, timeout); + } + + @SuppressWarnings("Since15") + @Override + public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException { + return delegate.setShardingKeyIfValid(shardingKey, timeout); + } + + @SuppressWarnings("Since15") + @Override + public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) + throws SQLException { + delegate.setShardingKey(shardingKey, superShardingKey); + } + + @SuppressWarnings("Since15") + @Override + public void setShardingKey(ShardingKey shardingKey) throws SQLException { + delegate.setShardingKey(shardingKey); + } + } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java index ac7f024511..8cd6582888 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java @@ -38,17 +38,15 @@ import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; +import java.sql.SQLType; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class OpenTelemetryPreparedStatement - extends OpenTelemetryStatement implements PreparedStatement { +@SuppressWarnings("OverloadMethodsDeclarationOrder") +class OpenTelemetryPreparedStatement extends OpenTelemetryStatement + implements PreparedStatement { public OpenTelemetryPreparedStatement( S delegate, @@ -61,7 +59,7 @@ public class OpenTelemetryPreparedStatement @Override public ResultSet executeQuery() throws SQLException { - return wrapCall(query, delegate::executeQuery); + return new OpenTelemetryResultSet(wrapCall(query, delegate::executeQuery), this); } @Override @@ -374,4 +372,22 @@ public class OpenTelemetryPreparedStatement DbRequest request = DbRequest.create(dbInfo, query, batchSize); return wrapCall(request, callable); } + + // JDBC 4.2 + + @Override + public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength) + throws SQLException { + delegate.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + @Override + public void setObject(int parameterIndex, Object x, SQLType targetSqlType) throws SQLException { + delegate.setObject(parameterIndex, x, targetSqlType); + } + + @Override + public long executeLargeUpdate() throws SQLException { + return wrapCall(query, delegate::executeLargeUpdate); + } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryResultSet.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryResultSet.java new file mode 100644 index 0000000000..d653210364 --- /dev/null +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryResultSet.java @@ -0,0 +1,1031 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jdbc.internal; + +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.SQLType; +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.Map; + +@SuppressWarnings({"UngroupedOverloads", "OverloadMethodsDeclarationOrder"}) +class OpenTelemetryResultSet implements ResultSet { + + private final ResultSet delegate; + private final Statement statement; + + OpenTelemetryResultSet(ResultSet delegate, Statement statement) { + this.delegate = delegate; + this.statement = statement; + } + + @Override + public boolean next() throws SQLException { + return delegate.next(); + } + + @Override + public void close() throws SQLException { + delegate.close(); + } + + @Override + public boolean wasNull() throws SQLException { + return delegate.wasNull(); + } + + @Override + public String getString(int columnIndex) throws SQLException { + return delegate.getString(columnIndex); + } + + @Override + public boolean getBoolean(int columnIndex) throws SQLException { + return delegate.getBoolean(columnIndex); + } + + @Override + public byte getByte(int columnIndex) throws SQLException { + return delegate.getByte(columnIndex); + } + + @Override + public short getShort(int columnIndex) throws SQLException { + return delegate.getShort(columnIndex); + } + + @Override + public int getInt(int columnIndex) throws SQLException { + return delegate.getInt(columnIndex); + } + + @Override + public long getLong(int columnIndex) throws SQLException { + return delegate.getLong(columnIndex); + } + + @Override + public float getFloat(int columnIndex) throws SQLException { + return delegate.getFloat(columnIndex); + } + + @Override + public double getDouble(int columnIndex) throws SQLException { + return delegate.getDouble(columnIndex); + } + + @Override + @SuppressWarnings("deprecation") // deprecated since 1.2 + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { + return delegate.getBigDecimal(columnIndex, scale); + } + + @Override + public byte[] getBytes(int columnIndex) throws SQLException { + return delegate.getBytes(columnIndex); + } + + @Override + public Date getDate(int columnIndex) throws SQLException { + return delegate.getDate(columnIndex); + } + + @Override + public Time getTime(int columnIndex) throws SQLException { + return delegate.getTime(columnIndex); + } + + @Override + public Timestamp getTimestamp(int columnIndex) throws SQLException { + return delegate.getTimestamp(columnIndex); + } + + @Override + public InputStream getAsciiStream(int columnIndex) throws SQLException { + return delegate.getAsciiStream(columnIndex); + } + + @Override + @SuppressWarnings("deprecation") // deprecated since 1.2 + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + return delegate.getUnicodeStream(columnIndex); + } + + @Override + public InputStream getBinaryStream(int columnIndex) throws SQLException { + return delegate.getBinaryStream(columnIndex); + } + + @Override + public String getString(String columnLabel) throws SQLException { + return delegate.getString(columnLabel); + } + + @Override + public boolean getBoolean(String columnLabel) throws SQLException { + return delegate.getBoolean(columnLabel); + } + + @Override + public byte getByte(String columnLabel) throws SQLException { + return delegate.getByte(columnLabel); + } + + @Override + public short getShort(String columnLabel) throws SQLException { + return delegate.getShort(columnLabel); + } + + @Override + public int getInt(String columnLabel) throws SQLException { + return delegate.getInt(columnLabel); + } + + @Override + public long getLong(String columnLabel) throws SQLException { + return delegate.getLong(columnLabel); + } + + @Override + public float getFloat(String columnLabel) throws SQLException { + return delegate.getFloat(columnLabel); + } + + @Override + public double getDouble(String columnLabel) throws SQLException { + return delegate.getDouble(columnLabel); + } + + @Override + @SuppressWarnings("deprecation") // deprecated since 1.2 + public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { + return delegate.getBigDecimal(columnLabel, scale); + } + + @Override + public byte[] getBytes(String columnLabel) throws SQLException { + return delegate.getBytes(columnLabel); + } + + @Override + public Date getDate(String columnLabel) throws SQLException { + return delegate.getDate(columnLabel); + } + + @Override + public Time getTime(String columnLabel) throws SQLException { + return delegate.getTime(columnLabel); + } + + @Override + public Timestamp getTimestamp(String columnLabel) throws SQLException { + return delegate.getTimestamp(columnLabel); + } + + @Override + public InputStream getAsciiStream(String columnLabel) throws SQLException { + return delegate.getAsciiStream(columnLabel); + } + + @Override + @SuppressWarnings("deprecation") // deprecated since 1.2 + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + return delegate.getUnicodeStream(columnLabel); + } + + @Override + public InputStream getBinaryStream(String columnLabel) throws SQLException { + return delegate.getBinaryStream(columnLabel); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return delegate.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + delegate.clearWarnings(); + } + + @Override + public String getCursorName() throws SQLException { + return delegate.getCursorName(); + } + + @Override + public ResultSetMetaData getMetaData() throws SQLException { + return delegate.getMetaData(); + } + + @Override + public Object getObject(int columnIndex) throws SQLException { + return delegate.getObject(columnIndex); + } + + @Override + public Object getObject(String columnLabel) throws SQLException { + return delegate.getObject(columnLabel); + } + + @Override + public int findColumn(String columnLabel) throws SQLException { + return delegate.findColumn(columnLabel); + } + + @Override + public Reader getCharacterStream(int columnIndex) throws SQLException { + return delegate.getCharacterStream(columnIndex); + } + + @Override + public Reader getCharacterStream(String columnLabel) throws SQLException { + return delegate.getCharacterStream(columnLabel); + } + + @Override + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + return delegate.getBigDecimal(columnIndex); + } + + @Override + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + return delegate.getBigDecimal(columnLabel); + } + + @Override + public boolean isBeforeFirst() throws SQLException { + return delegate.isBeforeFirst(); + } + + @Override + public boolean isAfterLast() throws SQLException { + return delegate.isAfterLast(); + } + + @Override + public boolean isFirst() throws SQLException { + return delegate.isFirst(); + } + + @Override + public boolean isLast() throws SQLException { + return delegate.isLast(); + } + + @Override + public void beforeFirst() throws SQLException { + delegate.beforeFirst(); + } + + @Override + public void afterLast() throws SQLException { + delegate.afterLast(); + } + + @Override + public boolean first() throws SQLException { + return delegate.first(); + } + + @Override + public boolean last() throws SQLException { + return delegate.last(); + } + + @Override + public int getRow() throws SQLException { + return delegate.getRow(); + } + + @Override + public boolean absolute(int row) throws SQLException { + return delegate.absolute(row); + } + + @Override + public boolean relative(int rows) throws SQLException { + return delegate.relative(rows); + } + + @Override + public boolean previous() throws SQLException { + return delegate.previous(); + } + + @Override + public void setFetchDirection(int direction) throws SQLException { + delegate.setFetchDirection(direction); + } + + @Override + public int getFetchDirection() throws SQLException { + return delegate.getFetchDirection(); + } + + @Override + public void setFetchSize(int rows) throws SQLException { + delegate.setFetchSize(rows); + } + + @Override + public int getFetchSize() throws SQLException { + return delegate.getFetchSize(); + } + + @Override + public int getType() throws SQLException { + return delegate.getType(); + } + + @Override + public int getConcurrency() throws SQLException { + return delegate.getConcurrency(); + } + + @Override + public boolean rowUpdated() throws SQLException { + return delegate.rowUpdated(); + } + + @Override + public boolean rowInserted() throws SQLException { + return delegate.rowInserted(); + } + + @Override + public boolean rowDeleted() throws SQLException { + return delegate.rowDeleted(); + } + + @Override + public void updateNull(int columnIndex) throws SQLException { + delegate.updateNull(columnIndex); + } + + @Override + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + delegate.updateBoolean(columnIndex, x); + } + + @Override + public void updateByte(int columnIndex, byte x) throws SQLException { + delegate.updateByte(columnIndex, x); + } + + @Override + public void updateShort(int columnIndex, short x) throws SQLException { + delegate.updateShort(columnIndex, x); + } + + @Override + public void updateInt(int columnIndex, int x) throws SQLException { + delegate.updateInt(columnIndex, x); + } + + @Override + public void updateLong(int columnIndex, long x) throws SQLException { + delegate.updateLong(columnIndex, x); + } + + @Override + public void updateFloat(int columnIndex, float x) throws SQLException { + delegate.updateFloat(columnIndex, x); + } + + @Override + public void updateDouble(int columnIndex, double x) throws SQLException { + delegate.updateDouble(columnIndex, x); + } + + @Override + public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + delegate.updateBigDecimal(columnIndex, x); + } + + @Override + public void updateString(int columnIndex, String x) throws SQLException { + delegate.updateString(columnIndex, x); + } + + @Override + public void updateBytes(int columnIndex, byte[] x) throws SQLException { + delegate.updateBytes(columnIndex, x); + } + + @Override + public void updateDate(int columnIndex, Date x) throws SQLException { + delegate.updateDate(columnIndex, x); + } + + @Override + public void updateTime(int columnIndex, Time x) throws SQLException { + delegate.updateTime(columnIndex, x); + } + + @Override + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + delegate.updateTimestamp(columnIndex, x); + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + delegate.updateAsciiStream(columnIndex, x, length); + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + delegate.updateBinaryStream(columnIndex, x, length); + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + delegate.updateCharacterStream(columnIndex, x, length); + } + + @Override + public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + delegate.updateObject(columnIndex, x, scaleOrLength); + } + + @Override + public void updateObject(int columnIndex, Object x) throws SQLException { + delegate.updateObject(columnIndex, x); + } + + @Override + public void updateNull(String columnLabel) throws SQLException { + delegate.updateNull(columnLabel); + } + + @Override + public void updateBoolean(String columnLabel, boolean x) throws SQLException { + delegate.updateBoolean(columnLabel, x); + } + + @Override + public void updateByte(String columnLabel, byte x) throws SQLException { + delegate.updateByte(columnLabel, x); + } + + @Override + public void updateShort(String columnLabel, short x) throws SQLException { + delegate.updateShort(columnLabel, x); + } + + @Override + public void updateInt(String columnLabel, int x) throws SQLException { + delegate.updateInt(columnLabel, x); + } + + @Override + public void updateLong(String columnLabel, long x) throws SQLException { + delegate.updateLong(columnLabel, x); + } + + @Override + public void updateFloat(String columnLabel, float x) throws SQLException { + delegate.updateFloat(columnLabel, x); + } + + @Override + public void updateDouble(String columnLabel, double x) throws SQLException { + delegate.updateDouble(columnLabel, x); + } + + @Override + public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + delegate.updateBigDecimal(columnLabel, x); + } + + @Override + public void updateString(String columnLabel, String x) throws SQLException { + delegate.updateString(columnLabel, x); + } + + @Override + public void updateBytes(String columnLabel, byte[] x) throws SQLException { + delegate.updateBytes(columnLabel, x); + } + + @Override + public void updateDate(String columnLabel, Date x) throws SQLException { + delegate.updateDate(columnLabel, x); + } + + @Override + public void updateTime(String columnLabel, Time x) throws SQLException { + delegate.updateTime(columnLabel, x); + } + + @Override + public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + delegate.updateTimestamp(columnLabel, x); + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + delegate.updateAsciiStream(columnLabel, x, length); + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x, int length) + throws SQLException { + delegate.updateBinaryStream(columnLabel, x, length); + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader, int length) + throws SQLException { + delegate.updateCharacterStream(columnLabel, reader, length); + } + + @Override + public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + delegate.updateObject(columnLabel, x, scaleOrLength); + } + + @Override + public void updateObject(String columnLabel, Object x) throws SQLException { + delegate.updateObject(columnLabel, x); + } + + @Override + public void insertRow() throws SQLException { + delegate.insertRow(); + } + + @Override + public void updateRow() throws SQLException { + delegate.updateRow(); + } + + @Override + public void deleteRow() throws SQLException { + delegate.deleteRow(); + } + + @Override + public void refreshRow() throws SQLException { + delegate.refreshRow(); + } + + @Override + public void cancelRowUpdates() throws SQLException { + delegate.cancelRowUpdates(); + } + + @Override + public void moveToInsertRow() throws SQLException { + delegate.moveToInsertRow(); + } + + @Override + public void moveToCurrentRow() throws SQLException { + delegate.moveToCurrentRow(); + } + + @Override + public Statement getStatement() throws SQLException { + return statement; + } + + @Override + public Object getObject(int columnIndex, Map> map) throws SQLException { + return delegate.getObject(columnIndex, map); + } + + @Override + public Ref getRef(int columnIndex) throws SQLException { + return delegate.getRef(columnIndex); + } + + @Override + public Blob getBlob(int columnIndex) throws SQLException { + return delegate.getBlob(columnIndex); + } + + @Override + public Clob getClob(int columnIndex) throws SQLException { + return delegate.getClob(columnIndex); + } + + @Override + public Array getArray(int columnIndex) throws SQLException { + return delegate.getArray(columnIndex); + } + + @Override + public Object getObject(String columnLabel, Map> map) throws SQLException { + return delegate.getObject(columnLabel, map); + } + + @Override + public Ref getRef(String columnLabel) throws SQLException { + return delegate.getRef(columnLabel); + } + + @Override + public Blob getBlob(String columnLabel) throws SQLException { + return delegate.getBlob(columnLabel); + } + + @Override + public Clob getClob(String columnLabel) throws SQLException { + return delegate.getClob(columnLabel); + } + + @Override + public Array getArray(String columnLabel) throws SQLException { + return delegate.getArray(columnLabel); + } + + @Override + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + return delegate.getDate(columnIndex, cal); + } + + @Override + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + return delegate.getDate(columnLabel, cal); + } + + @Override + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + return delegate.getTime(columnIndex, cal); + } + + @Override + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + return delegate.getTime(columnLabel, cal); + } + + @Override + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + return delegate.getTimestamp(columnIndex, cal); + } + + @Override + public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { + return delegate.getTimestamp(columnLabel, cal); + } + + @Override + public URL getURL(int columnIndex) throws SQLException { + return delegate.getURL(columnIndex); + } + + @Override + public URL getURL(String columnLabel) throws SQLException { + return delegate.getURL(columnLabel); + } + + @Override + public void updateRef(int columnIndex, Ref x) throws SQLException { + delegate.updateRef(columnIndex, x); + } + + @Override + public void updateRef(String columnLabel, Ref x) throws SQLException { + delegate.updateRef(columnLabel, x); + } + + @Override + public void updateBlob(int columnIndex, Blob x) throws SQLException { + delegate.updateBlob(columnIndex, x); + } + + @Override + public void updateBlob(String columnLabel, Blob x) throws SQLException { + delegate.updateBlob(columnLabel, x); + } + + @Override + public void updateClob(int columnIndex, Clob x) throws SQLException { + delegate.updateClob(columnIndex, x); + } + + @Override + public void updateClob(String columnLabel, Clob x) throws SQLException { + delegate.updateClob(columnLabel, x); + } + + @Override + public void updateArray(int columnIndex, Array x) throws SQLException { + delegate.updateArray(columnIndex, x); + } + + @Override + public void updateArray(String columnLabel, Array x) throws SQLException { + delegate.updateArray(columnLabel, x); + } + + @Override + public RowId getRowId(int columnIndex) throws SQLException { + return delegate.getRowId(columnIndex); + } + + @Override + public RowId getRowId(String columnLabel) throws SQLException { + return delegate.getRowId(columnLabel); + } + + @Override + public void updateRowId(int columnIndex, RowId x) throws SQLException { + delegate.updateRowId(columnIndex, x); + } + + @Override + public void updateRowId(String columnLabel, RowId x) throws SQLException { + delegate.updateRowId(columnLabel, x); + } + + @Override + public int getHoldability() throws SQLException { + return delegate.getHoldability(); + } + + @Override + public boolean isClosed() throws SQLException { + return delegate.isClosed(); + } + + @Override + public void updateNString(int columnIndex, String string) throws SQLException { + delegate.updateNString(columnIndex, string); + } + + @Override + public void updateNString(String columnLabel, String string) throws SQLException { + delegate.updateNString(columnLabel, string); + } + + @Override + public void updateNClob(int columnIndex, NClob clob) throws SQLException { + delegate.updateNClob(columnIndex, clob); + } + + @Override + public void updateNClob(String columnLabel, NClob clob) throws SQLException { + delegate.updateNClob(columnLabel, clob); + } + + @Override + public NClob getNClob(int columnIndex) throws SQLException { + return delegate.getNClob(columnIndex); + } + + @Override + public NClob getNClob(String columnLabel) throws SQLException { + return delegate.getNClob(columnLabel); + } + + @Override + public SQLXML getSQLXML(int columnIndex) throws SQLException { + return delegate.getSQLXML(columnIndex); + } + + @Override + public SQLXML getSQLXML(String columnLabel) throws SQLException { + return delegate.getSQLXML(columnLabel); + } + + @Override + public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { + delegate.updateSQLXML(columnIndex, xmlObject); + } + + @Override + public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { + delegate.updateSQLXML(columnLabel, xmlObject); + } + + @Override + public String getNString(int columnIndex) throws SQLException { + return delegate.getNString(columnIndex); + } + + @Override + public String getNString(String columnLabel) throws SQLException { + return delegate.getNString(columnLabel); + } + + @Override + public Reader getNCharacterStream(int columnIndex) throws SQLException { + return delegate.getNCharacterStream(columnIndex); + } + + @Override + public Reader getNCharacterStream(String columnLabel) throws SQLException { + return delegate.getNCharacterStream(columnLabel); + } + + @Override + public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + delegate.updateNCharacterStream(columnIndex, x, length); + } + + @Override + public void updateNCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + delegate.updateNCharacterStream(columnLabel, reader, length); + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + delegate.updateAsciiStream(columnIndex, x, length); + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + delegate.updateBinaryStream(columnIndex, x, length); + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + delegate.updateCharacterStream(columnIndex, x, length); + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x, long length) + throws SQLException { + delegate.updateAsciiStream(columnLabel, x, length); + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x, long length) + throws SQLException { + delegate.updateBinaryStream(columnLabel, x, length); + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + delegate.updateCharacterStream(columnLabel, reader, length); + } + + @Override + public void updateBlob(int columnIndex, InputStream inputStream, long length) + throws SQLException { + delegate.updateBlob(columnIndex, inputStream, length); + } + + @Override + public void updateBlob(String columnLabel, InputStream inputStream, long length) + throws SQLException { + delegate.updateBlob(columnLabel, inputStream, length); + } + + @Override + public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { + delegate.updateClob(columnIndex, reader, length); + } + + @Override + public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { + delegate.updateClob(columnLabel, reader, length); + } + + @Override + public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { + delegate.updateNClob(columnIndex, reader, length); + } + + @Override + public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { + delegate.updateNClob(columnLabel, reader, length); + } + + @Override + public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + delegate.updateNCharacterStream(columnIndex, x); + } + + @Override + public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { + delegate.updateNCharacterStream(columnLabel, reader); + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + delegate.updateAsciiStream(columnIndex, x); + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + delegate.updateBinaryStream(columnIndex, x); + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + delegate.updateCharacterStream(columnIndex, x); + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + delegate.updateAsciiStream(columnLabel, x); + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + delegate.updateBinaryStream(columnLabel, x); + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { + delegate.updateCharacterStream(columnLabel, reader); + } + + @Override + public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { + delegate.updateBlob(columnIndex, inputStream); + } + + @Override + public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { + delegate.updateBlob(columnLabel, inputStream); + } + + @Override + public void updateClob(int columnIndex, Reader reader) throws SQLException { + delegate.updateClob(columnIndex, reader); + } + + @Override + public void updateClob(String columnLabel, Reader reader) throws SQLException { + delegate.updateClob(columnLabel, reader); + } + + @Override + public void updateNClob(int columnIndex, Reader reader) throws SQLException { + delegate.updateNClob(columnIndex, reader); + } + + @Override + public void updateNClob(String columnLabel, Reader reader) throws SQLException { + delegate.updateNClob(columnLabel, reader); + } + + @Override + public T getObject(int columnIndex, Class type) throws SQLException { + return delegate.getObject(columnIndex, type); + } + + @Override + public T getObject(String columnLabel, Class type) throws SQLException { + return delegate.getObject(columnLabel, type); + } + + @Override + public void updateObject(int columnIndex, Object x, SQLType targetSqlType, int scaleOrLength) + throws SQLException { + delegate.updateObject(columnIndex, x, targetSqlType, scaleOrLength); + } + + @Override + public void updateObject(String columnLabel, Object x, SQLType targetSqlType, int scaleOrLength) + throws SQLException { + delegate.updateObject(columnLabel, x, targetSqlType, scaleOrLength); + } + + @Override + public void updateObject(int columnIndex, Object x, SQLType targetSqlType) throws SQLException { + delegate.updateObject(columnIndex, x, targetSqlType); + } + + @Override + public void updateObject(String columnLabel, Object x, SQLType targetSqlType) + throws SQLException { + delegate.updateObject(columnLabel, x, targetSqlType); + } + + @Override + public T unwrap(Class iface) throws SQLException { + return delegate.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return delegate.isWrapperFor(iface); + } +} diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java index 3cb62cebd6..bd3558016d 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java @@ -32,11 +32,7 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class OpenTelemetryStatement implements Statement { +class OpenTelemetryStatement implements Statement { protected final S delegate; protected final OpenTelemetryConnection connection; @@ -180,7 +176,7 @@ public class OpenTelemetryStatement implements Statement { @Override public ResultSet getResultSet() throws SQLException { - return delegate.getResultSet(); + return new OpenTelemetryResultSet(delegate.getResultSet(), this); } @Override @@ -250,7 +246,7 @@ public class OpenTelemetryStatement implements Statement { @Override public ResultSet getGeneratedKeys() throws SQLException { - return delegate.getGeneratedKeys(); + return new OpenTelemetryResultSet(delegate.getGeneratedKeys(), this); } @Override @@ -293,6 +289,74 @@ public class OpenTelemetryStatement implements Statement { return delegate.isWrapperFor(iface); } + // JDBC 4.2 + + @Override + public long getLargeUpdateCount() throws SQLException { + return delegate.getLargeUpdateCount(); + } + + @Override + public void setLargeMaxRows(long max) throws SQLException { + delegate.setLargeMaxRows(max); + } + + @Override + public long getLargeMaxRows() throws SQLException { + return delegate.getLargeMaxRows(); + } + + @Override + public long[] executeLargeBatch() throws SQLException { + return wrapBatchCall(delegate::executeLargeBatch); + } + + @Override + public long executeLargeUpdate(String sql) throws SQLException { + return wrapCall(sql, () -> delegate.executeLargeUpdate(sql)); + } + + @Override + public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + return wrapCall(sql, () -> delegate.executeLargeUpdate(sql, autoGeneratedKeys)); + } + + @Override + public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException { + return wrapCall(sql, () -> delegate.executeLargeUpdate(sql, columnIndexes)); + } + + @Override + public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException { + return wrapCall(sql, () -> delegate.executeLargeUpdate(sql, columnNames)); + } + + // JDBC 4.3 + + @SuppressWarnings("Since15") + @Override + public String enquoteLiteral(String val) throws SQLException { + return delegate.enquoteLiteral(val); + } + + @SuppressWarnings("Since15") + @Override + public String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException { + return delegate.enquoteIdentifier(identifier, alwaysQuote); + } + + @SuppressWarnings("Since15") + @Override + public boolean isSimpleIdentifier(String identifier) throws SQLException { + return delegate.isSimpleIdentifier(identifier); + } + + @SuppressWarnings("Since15") + @Override + public String enquoteNCharLiteral(String val) throws SQLException { + return delegate.enquoteNCharLiteral(val); + } + protected T wrapCall(String sql, ThrowingSupplier callable) throws E { DbRequest request = DbRequest.create(dbInfo, sql); diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriverTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriverTest.java index 3d0ba8e558..68fd7e7d7d 100644 --- a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriverTest.java +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriverTest.java @@ -128,7 +128,7 @@ public class OpenTelemetryDriverTest { Connection connection = OpenTelemetryDriver.INSTANCE.connect("jdbc:otel:test:", null); OpenTelemetryDriver.removeDriverCandidate(driver); - assertThat(connection).isExactlyInstanceOf(OpenTelemetryConnection.class); + assertThat(connection).isInstanceOf(OpenTelemetryConnection.class); } @DisplayName("verify remove driver candidate") @@ -220,7 +220,7 @@ public class OpenTelemetryDriverTest { Connection connection2 = OpenTelemetryDriver.INSTANCE.connect("jdbc:otel:test:", null); assertThat(connection2).isNotNull(); - assertThat(connection2).isExactlyInstanceOf(OpenTelemetryConnection.class); + assertThat(connection2).isInstanceOf(OpenTelemetryConnection.class); } @DisplayName("Verify get property info with test driver url") diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.java index 017913ac49..c1091b460c 100644 --- a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.java +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.java @@ -67,7 +67,7 @@ class OpenTelemetryDataSourceTest { ? null : "postgresql://127.0.0.1:5432")))); - assertThat(connection).isExactlyInstanceOf(OpenTelemetryConnection.class); + assertThat(connection).isInstanceOf(OpenTelemetryConnection.class); DbInfo dbInfo = ((OpenTelemetryConnection) connection).getDbInfo(); assertDbInfo(dbInfo); } @@ -83,7 +83,7 @@ class OpenTelemetryDataSourceTest { assertThat(testing.waitForTraces(0)).isEmpty(); - assertThat(connection).isExactlyInstanceOf(OpenTelemetryConnection.class); + assertThat(connection).isInstanceOf(OpenTelemetryConnection.class); DbInfo dbInfo = ((OpenTelemetryConnection) connection).getDbInfo(); assertDbInfo(dbInfo); } diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java index e8620fe7ca..a5d5eeea5f 100644 --- a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java @@ -30,6 +30,7 @@ import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.jupiter.api.Test; @@ -93,6 +94,33 @@ class OpenTelemetryConnectionTest { "parent", () -> { assertThat(statement.execute()).isTrue(); + ResultSet resultSet = statement.getResultSet(); + assertThat(resultSet).isInstanceOf(OpenTelemetryResultSet.class); + assertThat(resultSet.getStatement()).isEqualTo(statement); + }); + + jdbcTraceAssertion(dbInfo, query); + + statement.close(); + connection.close(); + } + + @Test + void testVerifyPrepareStatementQuery() throws SQLException { + Instrumenter instrumenter = + createStatementInstrumenter(testing.getOpenTelemetry()); + DbInfo dbInfo = getDbInfo(); + OpenTelemetryConnection connection = + new OpenTelemetryConnection(new TestConnection(), dbInfo, instrumenter); + String query = "SELECT * FROM users"; + PreparedStatement statement = connection.prepareStatement(query); + + testing.runWithSpan( + "parent", + () -> { + ResultSet resultSet = statement.executeQuery(); + assertThat(resultSet).isInstanceOf(OpenTelemetryResultSet.class); + assertThat(resultSet.getStatement()).isEqualTo(statement); }); jdbcTraceAssertion(dbInfo, query); diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/WrapperTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/WrapperTest.java new file mode 100644 index 0000000000..89d93f1335 --- /dev/null +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/WrapperTest.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jdbc.internal; + +import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryConnection.OpenTelemetryConnectionJdbc43; +import java.lang.reflect.Method; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class WrapperTest { + + @Test + void wrapperImplementsAllMethods() throws Exception { + validate(Statement.class, OpenTelemetryStatement.class); + validate(PreparedStatement.class, OpenTelemetryPreparedStatement.class); + validate(CallableStatement.class, OpenTelemetryCallableStatement.class); + validate( + Connection.class, + OpenTelemetryConnection.hasJdbc43() + ? OpenTelemetryConnectionJdbc43.class + : OpenTelemetryConnection.class); + validate(ResultSet.class, OpenTelemetryResultSet.class); + } + + void validate(Class jdbcClass, Class wrapperClass) throws Exception { + for (Method method : jdbcClass.getMethods()) { + Method result = wrapperClass.getMethod(method.getName(), method.getParameterTypes()); + if (!result.getDeclaringClass().getName().startsWith("io.opentelemetry")) { + Assertions.fail(wrapperClass.getName() + " does not override " + method); + } + } + } +}