Skip to content

Commit eebbd7e

Browse files
committed
Prevent crash in SQL Server JDBC when tracing execute methods with generated keys
When tracing the JDBC statement execute methods, we prepend a comment to the SQL query used for DBM trace propagation. However, there is a bug in the SQL Server JDBC driver that prevents the generated keys from being returned when the SQL comment is prepended to the SQL query. I decided to only append the comment in this specific case to avoid the comment from being truncated. @see microsoft/mssql-jdbc#2729
1 parent d6b43cb commit eebbd7e

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DECORATE;
1111
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.INJECT_COMMENT;
1212
import static java.util.Collections.singletonMap;
13+
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;
1314
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
1415
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
1516

@@ -75,6 +76,7 @@ public static class StatementAdvice {
7576
@Advice.OnMethodEnter(suppress = Throwable.class)
7677
public static AgentScope onEnter(
7778
@Advice.Argument(value = 0, readOnly = false) String sql,
79+
@Advice.AllArguments(typing = DYNAMIC) Object[] args,
7880
@Advice.This final Statement statement) {
7981
// TODO consider matching known non-wrapper implementations to avoid this check
8082
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Statement.class);
@@ -127,6 +129,21 @@ public static AgentScope onEnter(
127129
// context_info and v$session.action respectively.
128130
// we should not also inject it into SQL comments to avoid duplication
129131
final boolean injectTraceInComment = injectTraceContext && !isSqlServer && !isOracle;
132+
133+
boolean appendComment = StatementInstrumentation.appendComment;
134+
135+
// There is a bug in the SQL Server JDBC driver that prevents
136+
// the generated keys from being returned when the
137+
// SQL comment is prepended to the SQL query.
138+
// We only append in this case to avoid the comment from being truncated.
139+
// @see https://github.com/microsoft/mssql-jdbc/issues/2729
140+
if (isSqlServer
141+
&& args.length == 2
142+
&& args[1] instanceof Integer
143+
&& (Integer) args[1] == Statement.RETURN_GENERATED_KEYS) {
144+
appendComment = true;
145+
}
146+
130147
sql =
131148
SQLCommenter.inject(
132149
sql,

dd-java-agent/instrumentation/jdbc/src/test/groovy/DBMInjectionForkedTest.groovy

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,16 @@ class DBMInjectionForkedTest extends AgentTestRunner {
4747
then:
4848
assert statement.sql == "/*${fullInjection}*/ ${query}"
4949
}
50+
51+
def "single query with generated keys"() {
52+
setup:
53+
def connection = new TestConnection(false)
54+
55+
when:
56+
def statement = connection.createStatement() as TestStatement
57+
statement.executeUpdate(query, 1)
58+
59+
then:
60+
assert statement.sql == "${query} /*${fullInjection}*/"
61+
}
5062
}

0 commit comments

Comments
 (0)