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 (?)");
+    }
+}

Reply via email to