Skip to content

Commit 0a8f95f

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 0a8f95f

File tree

2 files changed

+26
-0
lines changed

2 files changed

+26
-0
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import static java.util.Collections.singletonMap;
1313
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
1414
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
15+
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;
1516

1617
import com.google.auto.service.AutoService;
1718
import datadog.appsec.api.blocking.BlockingException;
@@ -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,18 @@ 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 && args.length == 2 && args[1] instanceof Integer && (Integer) args[1] == Statement.RETURN_GENERATED_KEYS) {
141+
appendComment = true;
142+
}
143+
130144
sql =
131145
SQLCommenter.inject(
132146
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)