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]