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

gortiz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 4b5bd217e4 Return relevant error message when a v2 / multi-stage query 
is run on the v1 query engine (#13554)
4b5bd217e4 is described below

commit 4b5bd217e4a70bc76f60d73897a0484f19955ed5
Author: Yash Mayya <[email protected]>
AuthorDate: Mon Jul 8 14:47:55 2024 +0530

    Return relevant error message when a v2 / multi-stage query is run on the 
v1 query engine (#13554)
---
 .../BaseSingleStageBrokerRequestHandler.java       | 16 ++++-
 .../api/resources/PinotQueryResource.java          | 24 +++----
 .../api/resources/PinotQueryResourceTest.java      | 76 ++++++++++++++++++++++
 .../pinot/query/parser/utils/ParserUtils.java      | 54 +++++++++++++++
 4 files changed, 155 insertions(+), 15 deletions(-)

diff --git 
a/pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java
 
b/pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java
index f2aa21c645..ff3cce80ae 100644
--- 
a/pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java
+++ 
b/pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java
@@ -52,6 +52,7 @@ import org.apache.pinot.broker.broker.AccessControlFactory;
 import org.apache.pinot.broker.querylog.QueryLogger;
 import org.apache.pinot.broker.queryquota.QueryQuotaManager;
 import org.apache.pinot.broker.routing.BrokerRoutingManager;
+import org.apache.pinot.calcite.jdbc.CalciteSchemaBuilder;
 import org.apache.pinot.common.config.provider.TableCache;
 import org.apache.pinot.common.exception.QueryException;
 import org.apache.pinot.common.http.MultiHttpRequest;
@@ -83,6 +84,8 @@ import org.apache.pinot.core.routing.RoutingTable;
 import org.apache.pinot.core.routing.TimeBoundaryInfo;
 import org.apache.pinot.core.transport.ServerInstance;
 import org.apache.pinot.core.util.GapfillUtils;
+import org.apache.pinot.query.catalog.PinotCatalog;
+import org.apache.pinot.query.parser.utils.ParserUtils;
 import org.apache.pinot.spi.auth.AuthorizationResult;
 import org.apache.pinot.spi.config.table.FieldConfig;
 import org.apache.pinot.spi.config.table.QueryConfig;
@@ -258,7 +261,18 @@ public abstract class BaseSingleStageBrokerRequestHandler 
extends BaseBrokerRequ
         LOGGER.info("Caught exception while compiling SQL request {}: {}, {}", 
requestId, query, e.getMessage());
         
_brokerMetrics.addMeteredGlobalValue(BrokerMeter.REQUEST_COMPILATION_EXCEPTIONS,
 1);
         requestContext.setErrorCode(QueryException.SQL_PARSING_ERROR_CODE);
-        return new 
BrokerResponseNative(QueryException.getException(QueryException.SQL_PARSING_ERROR,
 e));
+        // Check if the query is a v2 supported query
+        Map<String, String> queryOptions = sqlNodeAndOptions.getOptions();
+        String database = 
DatabaseUtils.extractDatabaseFromQueryRequest(queryOptions, httpHeaders);
+        if (ParserUtils.canCompileQueryUsingV2Engine(query, 
CalciteSchemaBuilder.asRootSchema(
+            new PinotCatalog(database, _tableCache), database))) {
+          return new 
BrokerResponseNative(QueryException.getException(QueryException.SQL_PARSING_ERROR,
 new Exception(
+              "It seems that the query is only supported by the multi-stage 
query engine, please retry the query using "
+                  + "the multi-stage query engine "
+                  + 
"(https://docs.pinot.apache.org/developers/advanced/v2-multi-stage-query-engine)")));
+        } else {
+          return new 
BrokerResponseNative(QueryException.getException(QueryException.SQL_PARSING_ERROR,
 e));
+        }
       }
 
       if (isLiteralOnlyQuery(pinotQuery)) {
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotQueryResource.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotQueryResource.java
index 48d195ad2a..8bcbf96b48 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotQueryResource.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotQueryResource.java
@@ -70,6 +70,7 @@ import org.apache.pinot.core.auth.ManualAuthorization;
 import org.apache.pinot.core.query.executor.sql.SqlQueryExecutor;
 import org.apache.pinot.query.QueryEnvironment;
 import org.apache.pinot.query.catalog.PinotCatalog;
+import org.apache.pinot.query.parser.utils.ParserUtils;
 import org.apache.pinot.query.type.TypeFactory;
 import org.apache.pinot.query.type.TypeSystem;
 import org.apache.pinot.spi.config.table.TableConfig;
@@ -275,22 +276,17 @@ public class PinotQueryResource {
       tableName = 
_pinotHelixResourceManager.getActualTableName(inputTableName, database);
     } catch (Exception e) {
       LOGGER.error("Caught exception while compiling query: {}", query, e);
-      try {
-        // try to compile the query using multi-stage engine and suggest using 
it if it succeeds.
-        LOGGER.info("Trying to compile query {} using multi-stage engine", 
query);
-        QueryEnvironment queryEnvironment = new QueryEnvironment(new 
TypeFactory(new TypeSystem()),
-            CalciteSchemaBuilder.asRootSchema(new PinotCatalog(database, 
_pinotHelixResourceManager.getTableCache()),
-                database), null, null);
-        queryEnvironment.getTableNamesForQuery(query);
-        LOGGER.info("Successfully compiled query using multi-stage engine: 
{}", query);
+
+      // Check if the query is a v2 supported query
+      if (ParserUtils.canCompileQueryUsingV2Engine(query, 
CalciteSchemaBuilder.asRootSchema(
+          new PinotCatalog(database, 
_pinotHelixResourceManager.getTableCache()), database))) {
         return QueryException.getException(QueryException.SQL_PARSING_ERROR, 
new Exception(
-            "It seems that the query is only supported by the multi-stage 
engine, please try it by checking the "
-                + "\"Use Multi-Stage Engine\" box above")).toString();
-      } catch (Exception multipleTablesPassingException) {
-        LOGGER.error("Caught exception while compiling query using multi-stage 
engine: {}",
-            query, multipleTablesPassingException);
+            "It seems that the query is only supported by the multi-stage 
query engine, please retry the query using "
+                + "the multi-stage query engine "
+                + 
"(https://docs.pinot.apache.org/developers/advanced/v2-multi-stage-query-engine)")).toString();
+      } else {
+        return QueryException.getException(QueryException.SQL_PARSING_ERROR, 
e).toString();
       }
-      return QueryException.getException(QueryException.SQL_PARSING_ERROR, 
e).toString();
     }
     String rawTableName = TableNameBuilder.extractRawTableName(tableName);
 
diff --git 
a/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotQueryResourceTest.java
 
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotQueryResourceTest.java
new file mode 100644
index 0000000000..b80dd15fc3
--- /dev/null
+++ 
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotQueryResourceTest.java
@@ -0,0 +1,76 @@
+/**
+ * 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.controller.api.resources;
+
+import org.apache.pinot.common.config.provider.TableCache;
+import org.apache.pinot.common.exception.QueryException;
+import org.apache.pinot.controller.ControllerConf;
+import org.apache.pinot.controller.api.access.AccessControlFactory;
+import org.apache.pinot.controller.helix.core.PinotHelixResourceManager;
+import org.apache.pinot.spi.data.Schema;
+import org.mockito.AdditionalAnswers;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+
+public class PinotQueryResourceTest {
+
+  @Mock
+  PinotHelixResourceManager _resourceManager;
+  @Mock
+  TableCache _tableCache;
+  @Mock
+  Schema _schema;
+  @Mock
+  AccessControlFactory _accessControlFactory;
+  @Mock
+  ControllerConf _controllerConf;
+  @InjectMocks
+  PinotQueryResource _pinotQueryResource;
+
+  @BeforeMethod
+  public void setup() {
+    MockitoAnnotations.openMocks(this);
+    
when(_tableCache.getActualTableName(any())).then(AdditionalAnswers.returnsFirstArg());
+    when(_resourceManager.getTableCache()).thenReturn(_tableCache);
+    when(_tableCache.getSchema(any())).thenReturn(_schema);
+  }
+
+  @Test
+  public void testV2QueryOnV1() {
+    String response =
+        _pinotQueryResource.handleGetSql("WITH tmp AS (SELECT * FROM a) SELECT 
* FROM tmp", null, null, null);
+    
Assert.assertTrue(response.contains(String.valueOf(QueryException.SQL_PARSING_ERROR_CODE)));
+    Assert.assertTrue(response.contains("retry the query using the multi-stage 
query engine"));
+  }
+
+  @Test
+  public void testInvalidQuery() {
+    String response = _pinotQueryResource.handleGetSql("INVALID QUERY", null, 
null, null);
+    
Assert.assertTrue(response.contains(String.valueOf(QueryException.SQL_PARSING_ERROR_CODE)));
+    Assert.assertFalse(response.contains("retry the query using the 
multi-stage query engine"));
+  }
+}
diff --git 
a/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/utils/ParserUtils.java
 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/utils/ParserUtils.java
new file mode 100644
index 0000000000..9e897483a4
--- /dev/null
+++ 
b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/utils/ParserUtils.java
@@ -0,0 +1,54 @@
+/**
+ * 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.query.parser.utils;
+
+import org.apache.calcite.jdbc.CalciteSchema;
+import org.apache.pinot.query.QueryEnvironment;
+import org.apache.pinot.query.type.TypeFactory;
+import org.apache.pinot.query.type.TypeSystem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ParserUtils {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ParserUtils.class);
+
+  private ParserUtils() {
+  }
+
+  /**
+   * @param query the query string to be parsed and compiled
+   * @param calciteSchema the Calcite schema to be used for compilation
+   * @return true if the query can be parsed and compiled using the v2 
multi-stage query engine
+   */
+  public static boolean canCompileQueryUsingV2Engine(String query, 
CalciteSchema calciteSchema) {
+    // try to parse and compile the query with the Calcite planner used by the 
multi-stage query engine
+    try {
+      LOGGER.info("Trying to compile query `{}` using the multi-stage query 
engine", query);
+      QueryEnvironment queryEnvironment =
+          new QueryEnvironment(new TypeFactory(new TypeSystem()), 
calciteSchema, null, null);
+      queryEnvironment.getTableNamesForQuery(query);
+      LOGGER.info("Successfully compiled query using the multi-stage query 
engine: `{}`", query);
+      return true;
+    } catch (Exception e) {
+      LOGGER.error("Encountered an error while compiling query `{}` using the 
multi-stage query engine", query, e);
+      return false;
+    }
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to