This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 3bb501fd5f Fix missing parentheses around OR conditions in
JDBCZipkinQueryDAO.getTraces() (#13790)
3bb501fd5f is described below
commit 3bb501fd5f1b74c36c2258a1cf798df7db5ebce4
Author: Hyunjin-Jeong <[email protected]>
AuthorDate: Sat Apr 4 10:36:58 2026 +0900
Fix missing parentheses around OR conditions in
JDBCZipkinQueryDAO.getTraces() (#13790)
Fix incorrect trace ID filter (OR chain without parentheses) in
JDBCZipkinQueryDAO.getTraces(), replaced with IN clause.
---
docs/en/changes/changes.md | 1 +
.../plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java | 14 +--
.../jdbc/common/dao/JDBCZipkinQueryDAOTest.java | 111 +++++++++++++++++++++
3 files changed, 116 insertions(+), 10 deletions(-)
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index e01dc9c12f..5bc21825bf 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -8,6 +8,7 @@
* Fix missing `taskId` filter and incorrect `IN` clause parameter binding in
`JDBCJFRDataQueryDAO` and `JDBCPprofDataQueryDAO`.
* Remove deprecated `GroupBy.field_name` from BanyanDB `MeasureQuery` request
building (Phase 1 of staged removal across repos).
* Push `taskId` filter down to the storage layer in
`IAsyncProfilerTaskLogQueryDAO`, removing in-memory filtering from
`AsyncProfilerQueryService`.
+* Fix missing parentheses around OR conditions in
`JDBCZipkinQueryDAO.getTraces()`, which caused the table filter to be bypassed
for all but the first trace ID. Replaced with a proper `IN` clause.
#### UI
diff --git
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
index 5bfd6fc572..a35eb46399 100644
---
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
+++
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
@@ -42,6 +42,7 @@ import zipkin2.storage.QueryRequest;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -286,16 +287,9 @@ public class JDBCZipkinQueryDAO implements IZipkinQueryDAO
{
sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
condition.add(ZipkinSpanRecord.INDEX_NAME);
- int i = 0;
- sql.append(" and ");
- for (final String traceId : traceIds) {
- sql.append(ZipkinSpanRecord.TRACE_ID).append(" = ?");
- condition.add(traceId);
- if (i != traceIds.size() - 1) {
- sql.append(" or ");
- }
- i++;
- }
+ sql.append(" and ").append(ZipkinSpanRecord.TRACE_ID)
+ .append(" in (").append(String.join(",",
Collections.nCopies(traceIds.size(), "?"))).append(")");
+ condition.addAll(traceIds);
sql.append(" order by
").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" desc");
diff --git
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAOTest.java
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAOTest.java
new file mode 100644
index 0000000000..ec2111e80e
--- /dev/null
+++
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAOTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
+
+import org.apache.skywalking.oap.server.core.zipkin.ZipkinSpanRecord;
+import
org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import
org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class JDBCZipkinQueryDAOTest {
+
+ @Mock
+ private JDBCClient jdbcClient;
+ @Mock
+ private TableHelper tableHelper;
+
+ private JDBCZipkinQueryDAO dao;
+
+ @BeforeEach
+ void setUp() {
+ dao = new JDBCZipkinQueryDAO(jdbcClient, tableHelper);
+ }
+
+ @Test
+ void getTraces_shouldUseInClauseForMultipleTraceIds() throws Exception {
+ when(tableHelper.getTablesWithinTTL(ZipkinSpanRecord.INDEX_NAME))
+ .thenReturn(Collections.singletonList("zipkin_span"));
+
+ final AtomicReference<String> capturedSql = new AtomicReference<>();
+ final AtomicReference<Object[]> capturedParams = new
AtomicReference<>();
+ doAnswer(invocation -> {
+ capturedSql.set(invocation.getArgument(0));
+ final Object[] allArgs = invocation.getArguments();
+ capturedParams.set(Arrays.copyOfRange(allArgs, 2, allArgs.length));
+ return new ArrayList<>();
+ }).when(jdbcClient).executeQuery(anyString(), any(),
any(Object[].class));
+
+ final Set<String> traceIds = new
LinkedHashSet<>(Arrays.asList("abc123", "def456", "ghi789"));
+ dao.getTraces(traceIds, null);
+
+ final String sql = capturedSql.get();
+ assertThat(sql).contains(ZipkinSpanRecord.TRACE_ID + " in (?,?,?)");
+ assertThat(sql).doesNotContain(" or ");
+
+ assertThat(capturedParams.get())
+ .contains("abc123", "def456", "ghi789");
+ }
+
+ @Test
+ void getTraces_shouldReturnEmptyListWhenTraceIdsEmpty() throws Exception {
+ final Set<String> traceIds = Collections.emptySet();
+ assertThat(dao.getTraces(traceIds, null)).isEmpty();
+ }
+
+ @Test
+ void getTraces_singleTraceIdShouldProduceInClauseWithOnePlaceholder()
throws Exception {
+ when(tableHelper.getTablesWithinTTL(ZipkinSpanRecord.INDEX_NAME))
+ .thenReturn(Collections.singletonList("zipkin_span"));
+
+ final AtomicReference<String> capturedSql = new AtomicReference<>();
+ doAnswer(invocation -> {
+ capturedSql.set(invocation.getArgument(0));
+ return new ArrayList<>();
+ }).when(jdbcClient).executeQuery(anyString(), any(),
any(Object[].class));
+
+ final Set<String> traceIds = Collections.singleton("abc123");
+ dao.getTraces(traceIds, null);
+
+ final String sql = capturedSql.get();
+ assertThat(sql).contains(JDBCTableInstaller.TABLE_COLUMN + " = ?");
+ assertThat(sql).contains(ZipkinSpanRecord.TRACE_ID + " in (?)");
+ }
+}