fix(agent): cache JDBC column metadata

This commit is contained in:
t8y2 committed 2026-07-03 02:26:01 +08:00
1 parent c1d3f9423d
commit fb4bce90d6
3 files changed
+154 -13

No files matched your search

@@ -113,24 +113,28 @@ public final class JdbcExecutor {
return unchecked(() -> {
ResultSetMetaData meta = rs.getMetaData();
int colCount = meta.getColumnCount();
List<String> columns = new ArrayList<>();
List<String> columnTypes = new ArrayList<>();
List<String> columns = new ArrayList<>(colCount);
List<String> columnTypes = new ArrayList<>(colCount);
// Cache JDBC column metadata once; some drivers resolve it lazily,
// and row reading is the hot path.
int[] sqlTypeByIndex = new int[colCount];
String[] typeNameByIndex = new String[colCount];
for (int i = 1; i <= colCount; i++) {
columns.add(meta.getColumnLabel(i));
sqlTypeByIndex[i - 1] = safeColumnSqlType(meta, i);
String typeName = safeColumnTypeName(meta, i);
columnTypes.add(typeName);
typeNameByIndex[i - 1] = typeName;
}
List<List<Object>> rows = new ArrayList<>();
List<List<Object>> rows = new ArrayList<>(initialRowCapacity(maxRows));
boolean truncated = false;
while (rs.next()) {
if (rows.size() >= maxRows) {
truncated = true;
break;
}
rows.add(rowValues(rs, valueReader, typeNameByIndex));
rows.add(rowValues(rs, valueReader, sqlTypeByIndex, typeNameByIndex));
}
return new QueryResult(columns, columnTypes, rows, 0L, executionTimeMs, truncated);
@@ -221,9 +225,12 @@ public final class JdbcExecutor {
int colCount = meta.getColumnCount();
List<String> columns = new ArrayList<>(colCount);
List<String> columnTypes = new ArrayList<>(colCount);
// Cache JDBC column metadata once; fetching a page should only read row values.
int[] sqlTypeByIndex = new int[colCount];
String[] typeNameByIndex = new String[colCount];
for (int i = 1; i <= colCount; i++) {
columns.add(meta.getColumnLabel(i));
sqlTypeByIndex[i - 1] = safeColumnSqlType(meta, i);
String typeName = safeColumnTypeName(meta, i);
columnTypes.add(typeName);
typeNameByIndex[i - 1] = typeName;
@@ -234,6 +241,7 @@ public final class JdbcExecutor {
rs,
columns,
columnTypes,
sqlTypeByIndex,
typeNameByIndex,
Math.max(options.getMaxRows(), 1),
valueReader
@@ -449,7 +457,7 @@ public final class JdbcExecutor {
return unchecked(() -> {
session.lastAccessedAtMillis = System.currentTimeMillis();
int effectivePageSize = Math.max(pageSize, 1);
List<List<Object>> rows = new ArrayList<>();
List<List<Object>> rows = new ArrayList<>(initialRowCapacity(effectivePageSize));
if (session.pendingRow != null) {
rows.add(session.pendingRow);
@@ -461,7 +469,7 @@ public final class JdbcExecutor {
closeSession(targetSessions, session.id);
return new QueryPageResult(session.columns, session.columnTypes, rows, 0L, executionTimeMs, false, null, false);
}
rows.add(rowValues(session.resultSet, session.valueReader, session.typeNameByIndex));
rows.add(rowValues(session.resultSet, session.valueReader, session.sqlTypeByIndex, session.typeNameByIndex));
session.rowsRead += 1;
}
@@ -477,7 +485,7 @@ public final class JdbcExecutor {
return new QueryPageResult(session.columns, session.columnTypes, rows, 0L, executionTimeMs, false, null, false);
}
session.pendingRow = rowValues(session.resultSet, session.valueReader, session.typeNameByIndex);
session.pendingRow = rowValues(session.resultSet, session.valueReader, session.sqlTypeByIndex, session.typeNameByIndex);
session.rowsRead += 1;
return new QueryPageResult(session.columns, session.columnTypes, rows, 0L, executionTimeMs, false, session.id, true);
});
@@ -517,17 +525,29 @@ public final class JdbcExecutor {
}
}
private List<Object> rowValues(ResultSet rs, ResultValueReader valueReader, String[] typeNameByIndex) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int colCount = meta.getColumnCount();
static int safeColumnSqlType(ResultSetMetaData meta, int columnIndex) {
try {
return meta.getColumnType(columnIndex);
} catch (SQLException ignored) {
return Types.OTHER;
}
}
private List<Object> rowValues(
ResultSet rs,
ResultValueReader valueReader,
int[] sqlTypeByIndex,
String[] typeNameByIndex
) throws SQLException {
int colCount = sqlTypeByIndex.length;
List<Object> row = new ArrayList<>(colCount);
for (int i = 1; i <= colCount; i++) {
int sqlType = meta.getColumnType(i);
int sqlType = sqlTypeByIndex[i - 1];
Object value;
if (valueReader instanceof ColumnAwareResultValueReader) {
String typeName = typeNameByIndex != null && i - 1 < typeNameByIndex.length
? typeNameByIndex[i - 1]
: safeColumnTypeName(meta, i);
: "";
value = ((ColumnAwareResultValueReader) valueReader).read(rs, i, sqlType, typeName);
} else {
value = valueReader.read(rs, i, sqlType);
@@ -537,6 +557,13 @@ public final class JdbcExecutor {
return row;
}
private static int initialRowCapacity(int requestedRows) {
if (requestedRows <= 0) {
return 0;
}
return Math.min(requestedRows, 1024);
}
private void applySchema(Connection conn, String schema, Function<String, String> setSchemaSql) throws SQLException {
if (schema == null || schema.trim().isEmpty()) {
return;
@@ -664,6 +691,7 @@ public final class JdbcExecutor {
private final ResultSet resultSet;
private final List<String> columns;
private final List<String> columnTypes;
private final int[] sqlTypeByIndex;
private final String[] typeNameByIndex;
private final int maxRows;
private final ResultValueReader valueReader;
@@ -677,6 +705,7 @@ public final class JdbcExecutor {
ResultSet resultSet,
List<String> columns,
List<String> columnTypes,
int[] sqlTypeByIndex,
String[] typeNameByIndex,
int maxRows,
ResultValueReader valueReader
@@ -686,6 +715,7 @@ public final class JdbcExecutor {
this.resultSet = resultSet;
this.columns = columns;
this.columnTypes = columnTypes;
this.sqlTypeByIndex = sqlTypeByIndex;
this.typeNameByIndex = typeNameByIndex;
this.maxRows = maxRows;
this.valueReader = valueReader;
@@ -99,7 +99,7 @@ public final class QueryResult {
if (input == null) {
return Collections.emptyList();
}
List<List<Object>> normalized = new ArrayList<>();
List<List<Object>> normalized = new ArrayList<>(input.size());
for (List<?> row : input) {
normalized.add(row == null ? Collections.emptyList() : new ArrayList<Object>(row));
}