This is an automated email from the ASF dual-hosted git repository.

richardstartin pushed a commit to branch debug-compatibility-verifier
in repository https://gitbox.apache.org/repos/asf/pinot.git

commit bf3e2487ee6615ab704851cdf1d546b83e539e75
Author: Richard Startin <richardstar...@apache.org>
AuthorDate: Thu Jan 5 18:35:31 2023 +0000

    output explain plan when compatibility verifier rejects change in query 
execution
---
 .../main/java/org/apache/pinot/compat/QueryOp.java | 27 ++++++---
 .../tests/ClusterIntegrationTestUtils.java         | 36 +-----------
 .../apache/pinot/tools/utils/ExplainPlanUtils.java | 67 ++++++++++++++++++++++
 3 files changed, 89 insertions(+), 41 deletions(-)

diff --git 
a/pinot-compatibility-verifier/src/main/java/org/apache/pinot/compat/QueryOp.java
 
b/pinot-compatibility-verifier/src/main/java/org/apache/pinot/compat/QueryOp.java
index 2489851d5d..931ad734d5 100644
--- 
a/pinot-compatibility-verifier/src/main/java/org/apache/pinot/compat/QueryOp.java
+++ 
b/pinot-compatibility-verifier/src/main/java/org/apache/pinot/compat/QueryOp.java
@@ -26,6 +26,7 @@ import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import org.apache.pinot.common.utils.SqlResultComparator;
 import org.apache.pinot.spi.utils.JsonUtils;
+import org.apache.pinot.tools.utils.ExplainPlanUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -126,27 +127,29 @@ public class QueryOp extends BaseOp {
           try {
             actualJson = Utils.postSqlQuery(query, 
ClusterDescriptor.getInstance().getBrokerUrl());
           } catch (Exception e) {
-            LOGGER.error("Comparison FAILED: Line: {} Exception caught while 
running query: '{}'", queryLineNum, query,
-                e);
+            LOGGER.error("Comparison FAILED: Line: {} Exception caught while 
running query: '{}', explain plan: {}",
+                queryLineNum, query, getExplainPlan(query), e);
           }
         }
 
         if (expectedJson != null && actualJson != null) {
           try {
-            boolean passed = SqlResultComparator
-                .areEqual(actualJson, expectedJson, query);
+            boolean passed = SqlResultComparator.areEqual(actualJson, 
expectedJson, query);
             if (passed) {
               succeededQueryCount++;
               LOGGER.debug("Comparison PASSED: Line: {}, query: '{}', actual 
response: {}, expected response: {}",
                   queryLineNum, query, actualJson, expectedJson);
             } else {
-              LOGGER.error("Comparison FAILED: Line: {}, query: '{}', actual 
response: {}, expected response: {}",
-                  queryLineNum, query, actualJson, expectedJson);
+              LOGGER.error(
+                  "Comparison FAILED: Line: {}, query: '{}', actual response: 
{}, expected response: {}, explain "
+                      + "plan: {}",
+                  queryLineNum, query, actualJson, expectedJson, 
getExplainPlan(query));
             }
           } catch (Exception e) {
             LOGGER.error(
                 "Comparison FAILED: Line: {} Exception caught while comparing 
query: '{}' actual response: {}, "
-                    + "expected response: {}", queryLineNum, query, 
actualJson, expectedJson, e);
+                    + "expected response: {}, explain plan: {}", queryLineNum, 
query, actualJson, expectedJson,
+                getExplainPlan(query), e);
           }
         }
         totalQueryCount++;
@@ -159,4 +162,14 @@ public class QueryOp extends BaseOp {
     }
     return testPassed;
   }
+
+  private static String getExplainPlan(String query) {
+    try {
+      JsonNode explainPlanResponse =
+          Utils.postSqlQuery("explain plan for " + query, 
ClusterDescriptor.getInstance().getBrokerUrl());
+      return ExplainPlanUtils.formatExplainPlan(explainPlanResponse);
+    } catch (Throwable error) {
+      return error.getMessage();
+    }
+  }
 }
diff --git 
a/pinot-integration-test-base/src/test/java/org/apache/pinot/integration/tests/ClusterIntegrationTestUtils.java
 
b/pinot-integration-test-base/src/test/java/org/apache/pinot/integration/tests/ClusterIntegrationTestUtils.java
index e8f4d143e2..5f30e0c5a5 100644
--- 
a/pinot-integration-test-base/src/test/java/org/apache/pinot/integration/tests/ClusterIntegrationTestUtils.java
+++ 
b/pinot-integration-test-base/src/test/java/org/apache/pinot/integration/tests/ClusterIntegrationTestUtils.java
@@ -76,6 +76,7 @@ import org.apache.pinot.spi.stream.StreamDataProvider;
 import org.apache.pinot.spi.utils.JsonUtils;
 import org.apache.pinot.spi.utils.StringUtil;
 import org.apache.pinot.sql.parsers.CalciteSqlParser;
+import org.apache.pinot.tools.utils.ExplainPlanUtils;
 import org.apache.pinot.tools.utils.KafkaStarterUtils;
 import org.testng.Assert;
 
@@ -691,40 +692,7 @@ public class ClusterIntegrationTestUtils {
       throws Exception {
     JsonNode explainPlanForResponse =
         ClusterTest.postQuery("explain plan for " + pinotQuery, brokerUrl, 
headers, extraJsonProperties);
-    Map<Integer, String> nodesById = new TreeMap<>();
-    JsonNode rows = explainPlanForResponse.get("resultTable").get("rows");
-    int[] parentMapping = new int[rows.size()];
-    for (int i = 0; i < rows.size(); i++) {
-      JsonNode row = rows.get(i);
-      int id = row.get(1).asInt();
-      if (id > 0) {
-        parentMapping[id] = row.get(2).asInt();
-      }
-      nodesById.put(id, row.get(0).asText());
-    }
-    int[] depths = new int[rows.size()];
-    for (Map.Entry<Integer, String> pair : nodesById.entrySet()) {
-      int depth = 0;
-      int id = pair.getKey();
-      int parentId = id;
-      while (parentId > 0) {
-        depth++;
-        parentId = parentMapping[parentId];
-      }
-      if (id > 0) {
-        depths[id] = depth;
-      }
-    }
-    StringBuilder explainPlan = new StringBuilder();
-    for (Map.Entry<Integer, String> pair : nodesById.entrySet()) {
-      explainPlan.append('\n');
-      int id = pair.getKey();
-      for (int i = 0; id > 0 && i < depths[id]; i++) {
-        explainPlan.append('\t');
-      }
-      explainPlan.append(pair.getValue());
-    }
-    return explainPlan.toString();
+    return ExplainPlanUtils.formatExplainPlan(explainPlanForResponse);
   }
 
   private static int getH2ExpectedValues(Set<String> expectedValues, 
List<String> expectedOrderByValues,
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/utils/ExplainPlanUtils.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/ExplainPlanUtils.java
new file mode 100644
index 0000000000..74da8b45a5
--- /dev/null
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/utils/ExplainPlanUtils.java
@@ -0,0 +1,67 @@
+/**
+ * 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.pinot.tools.utils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.util.Map;
+import java.util.TreeMap;
+
+
+public class ExplainPlanUtils {
+
+  private ExplainPlanUtils() {
+  }
+
+  public static String formatExplainPlan(JsonNode explainPlanJson) {
+    Map<Integer, String> nodesById = new TreeMap<>();
+    JsonNode rows = explainPlanJson.get("resultTable").get("rows");
+    int[] parentMapping = new int[rows.size()];
+    for (int i = 0; i < rows.size(); i++) {
+      JsonNode row = rows.get(i);
+      int id = row.get(1).asInt();
+      if (id > 0) {
+        parentMapping[id] = row.get(2).asInt();
+      }
+      nodesById.put(id, row.get(0).asText());
+    }
+    int[] depths = new int[rows.size()];
+    for (Map.Entry<Integer, String> pair : nodesById.entrySet()) {
+      int depth = 0;
+      int id = pair.getKey();
+      int parentId = id;
+      while (parentId > 0) {
+        depth++;
+        parentId = parentMapping[parentId];
+      }
+      if (id > 0) {
+        depths[id] = depth;
+      }
+    }
+    StringBuilder explainPlan = new StringBuilder();
+    for (Map.Entry<Integer, String> pair : nodesById.entrySet()) {
+      explainPlan.append('\n');
+      int id = pair.getKey();
+      for (int i = 0; id > 0 && i < depths[id]; i++) {
+        explainPlan.append('\t');
+      }
+      explainPlan.append(pair.getValue());
+    }
+    return explainPlan.toString();
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to