Skip to content

Commit 00afec4

Browse files
committed
Add more SQL handling
1 parent 5ee0d50 commit 00afec4

File tree

2 files changed

+81
-17
lines changed

2 files changed

+81
-17
lines changed

agent/src/main/java/com/appland/appmap/process/hooks/SqlQuery.java

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
public class SqlQuery {
2525
private static final Recorder recorder = Recorder.getInstance();
2626
private static final Map<Statement, String> statementSql = Collections.synchronizedMap(new WeakHashMap<>());
27+
private static final Map<Statement, java.util.List<String>> statementBatchSql = Collections.synchronizedMap(new WeakHashMap<>());
2728

2829
public static void recordSql(Event event, String databaseType, String sql) {
2930
event.setSqlQuery(databaseType, sql);
@@ -101,47 +102,87 @@ private static String getDbName(Statement s) {
101102
}
102103

103104
// ================================================================================================
104-
// nativeSQL
105+
// addBatch
105106
// ================================================================================================
106107

107-
@HookClass("java.sql.Connection")
108-
public static void nativeSQL(Event event, Connection c, String sql) {
109-
recordSql(event, c, sql);
108+
@HookClass(value = "java.sql.PreparedStatement", methodEvent = MethodEvent.METHOD_RETURN)
109+
public static void addBatch(Event event, Statement s) {
110+
String sql = statementSql.get(s);
111+
if (sql != null) {
112+
statementBatchSql.computeIfAbsent(s, k -> new java.util.ArrayList<>()).add(sql);
113+
}
110114
}
111115

112-
@HookClass(value = "java.sql.Connection", methodEvent = MethodEvent.METHOD_RETURN)
113-
public static void nativeSQL(Event event, Connection c, Object returnValue, String sql) {
116+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
117+
public static void addBatch(Event event, Statement s, String sql) {
118+
statementBatchSql.computeIfAbsent(s, k -> new java.util.ArrayList<>()).add(sql);
119+
}
120+
121+
// ================================================================================================
122+
// clearBatch
123+
// ================================================================================================
124+
125+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
126+
public static void clearBatch(Event event, Statement s) {
127+
statementBatchSql.remove(s);
128+
}
129+
130+
// ================================================================================================
131+
// executeBatch
132+
// ================================================================================================
133+
134+
@HookClass("java.sql.Statement")
135+
public static void executeBatch(Event event, Statement s) {
136+
recordSqlBatch(event, s);
137+
}
138+
139+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
140+
public static void executeBatch(Event event, Statement s, Object returnValue) {
114141
recorder.add(event);
115142
}
116143

117-
@ArgumentArray
118-
@HookClass(value = "java.sql.Connection", methodEvent = MethodEvent.METHOD_EXCEPTION)
119-
public static void nativeSQL(Event event, Connection c, Throwable exception, Object[] args) {
144+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_EXCEPTION)
145+
public static void executeBatch(Event event, Statement s, Throwable exception) {
120146
event.setException(exception);
121147
recorder.add(event);
122148
}
123149

124150
// ================================================================================================
125-
// addBatch
151+
// executeLargeBatch
126152
// ================================================================================================
127153

128-
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
129-
public static void addBatch(Event event, Statement s, String sql) {
130-
recordSql(event, s, sql);
154+
@HookClass("java.sql.Statement")
155+
public static void executeLargeBatch(Event event, Statement s) {
156+
recordSqlBatch(event, s);
131157
}
132158

133159
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
134-
public static void addBatch(Event event, Statement s, Object returnValue, String sql) {
160+
public static void executeLargeBatch(Event event, Statement s, Object returnValue) {
135161
recorder.add(event);
136162
}
137163

138-
@ArgumentArray
139164
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_EXCEPTION)
140-
public static void addBatch(Event event, Statement s, Throwable exception, Object[] args) {
165+
public static void executeLargeBatch(Event event, Statement s, Throwable exception) {
141166
event.setException(exception);
142167
recorder.add(event);
143168
}
144169

170+
private static void recordSqlBatch(Event event, Statement s) {
171+
// According to the JDBC spec, calling executeBatch clears the batch
172+
// on the statement. So, we'll remove our copy of it.
173+
java.util.List<String> sqls = statementBatchSql.remove(s);
174+
String sqlToRecord;
175+
176+
if (sqls != null && !sqls.isEmpty()) {
177+
// In order to represent the batch as a single query, we'll join
178+
// the SQL statements together.
179+
sqlToRecord = String.join(";\n", sqls);
180+
} else {
181+
sqlToRecord = "[empty batch]";
182+
}
183+
recordSql(event, s, sqlToRecord);
184+
}
185+
145186
// ================================================================================================
146187
// execute
147188
// ================================================================================================
@@ -211,6 +252,29 @@ public static void executeUpdate(Event event, Statement s, Throwable exception,
211252
recorder.add(event);
212253
}
213254

255+
// ================================================================================================
256+
// executeLargeUpdate
257+
// ================================================================================================
258+
259+
@ArgumentArray
260+
@HookClass("java.sql.Statement")
261+
public static void executeLargeUpdate(Event event, Statement s, Object[] args) {
262+
recordSql(event, s, args);
263+
}
264+
265+
@ArgumentArray
266+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_RETURN)
267+
public static void executeLargeUpdate(Event event, Statement s, Object returnValue, Object[] args) {
268+
recorder.add(event);
269+
}
270+
271+
@ArgumentArray
272+
@HookClass(value = "java.sql.Statement", methodEvent = MethodEvent.METHOD_EXCEPTION)
273+
public static void executeLargeUpdate(Event event, Statement s, Throwable exception, Object[] args) {
274+
event.setException(exception);
275+
recorder.add(event);
276+
}
277+
214278
// ================================================================================================
215279
// prepareCall
216280
// ================================================================================================

agent/test/jdbc/jdbc.bats

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
load '../helper'
66

77
setup_file() {
8-
cd "$BATS_TEST_DIR" || true
8+
cd "$BATS_TEST_DIRNAME" || exit 1
99
_configure_logging
1010

1111
./gradlew -q clean

0 commit comments

Comments
 (0)