diff --git a/docs/routing-rules.md b/docs/routing-rules.md index 7c407ad72..3b144d148 100644 --- a/docs/routing-rules.md +++ b/docs/routing-rules.md @@ -180,9 +180,10 @@ added to the list of tables in all contexts, including statements such as A routing rule can call the following methods on the `trinoQueryProperties` object: +* `String errorMessage()`: the error message only if there was any error while + creating `trinoQueryProperties` object. * `boolean isNewQuerySubmission()`: is the request a POST to the `v1/statement` - query endpoint. -* `boolean isQueryParsingSuccessful()`: was the request successfully parsed. + query endpoint. * `String getQueryType()`: the class name of the `Statement`, e.g. `ShowCreate`. Note that these are not mapped to the `ResourceGroup` query types. For a full list of potential query types, see the classes in diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/router/TrinoQueryProperties.java b/gateway-ha/src/main/java/io/trino/gateway/ha/router/TrinoQueryProperties.java index ae4738099..2ee7367ae 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/router/TrinoQueryProperties.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/router/TrinoQueryProperties.java @@ -96,7 +96,9 @@ public class TrinoQueryProperties private Set schemas = ImmutableSet.of(); private Set catalogSchemas = ImmutableSet.of(); private boolean isNewQuerySubmission; + @SuppressWarnings("unused") private boolean isQueryParsingSuccessful; + private Optional errorMessage; public static final String TRINO_CATALOG_HEADER_NAME = "X-Trino-Catalog"; public static final String TRINO_SCHEMA_HEADER_NAME = "X-Trino-Schema"; @@ -114,7 +116,8 @@ public TrinoQueryProperties( @JsonProperty("schemas") Set schemas, @JsonProperty("catalogSchemas") Set catalogSchemas, @JsonProperty("isNewQuerySubmission") boolean isNewQuerySubmission, - @JsonProperty("isQueryParsingSuccessful") boolean isQueryParsingSuccessful) + @JsonProperty("isQueryParsingSuccessful") boolean isQueryParsingSuccessful, + @JsonProperty("errorMessage") Optional errorMessage) { this.body = requireNonNullElse(body, ""); this.queryType = requireNonNullElse(queryType, ""); @@ -127,6 +130,7 @@ public TrinoQueryProperties( this.catalogSchemas = requireNonNullElse(catalogSchemas, ImmutableSet.of()); this.isNewQuerySubmission = isNewQuerySubmission; this.isQueryParsingSuccessful = isQueryParsingSuccessful; + this.errorMessage = requireNonNullElse(errorMessage, Optional.empty()); isClientsUseV2Format = false; } @@ -208,19 +212,18 @@ else if (statement instanceof ExecuteImmediate executeImmediate) { catalogSchemaBuilder.addAll( tables.stream().map(qualifiedName -> format("%s.%s", qualifiedName.getParts().getFirst(), qualifiedName.getParts().get(1))).iterator()); catalogSchemas = catalogSchemaBuilder.build(); - isQueryParsingSuccessful = true; } catch (IOException e) { log.warn("Error extracting request body for rules processing: %s", e.getMessage()); - isQueryParsingSuccessful = false; + errorMessage = Optional.of(e.getMessage()); } catch (ParsingException e) { log.info("Could not parse request body as SQL: %s; Message: %s", body, e.getMessage()); - isQueryParsingSuccessful = false; + errorMessage = Optional.of(e.getMessage()); } catch (RequestParsingException e) { log.warn(e, "Error parsing request for rules"); - isQueryParsingSuccessful = false; + errorMessage = Optional.of(e.getMessage()); } } @@ -291,7 +294,7 @@ private void getNames(Node node, ImmutableSet.Builder tableBuilde targetSchema = QualifiedName.of(defaultCatalog.orElseThrow(), s.getTarget().getValue()); } else { - isQueryParsingSuccessful = false; + errorMessage = Optional.of("defaultCatalog is not present"); return; } } @@ -379,7 +382,6 @@ private void setCatalogAndSchemaNameFromSchemaQualifiedName( private RequestParsingException unsetDefaultExceptionSupplier() { - isQueryParsingSuccessful = false; return new RequestParsingException("Name not fully qualified"); } @@ -513,7 +515,13 @@ public boolean isNewQuerySubmission() @JsonProperty("isQueryParsingSuccessful") public boolean isQueryParsingSuccessful() { - return isQueryParsingSuccessful; + return errorMessage.isEmpty(); + } + + @JsonProperty + public Optional getErrorMessage() + { + return errorMessage; } public static class AlternateStatementRequestBodyFormat diff --git a/gateway-ha/src/test/java/io/trino/gateway/ha/router/TestTrinoQueryProperties.java b/gateway-ha/src/test/java/io/trino/gateway/ha/router/TestTrinoQueryProperties.java index a8a63efcc..e77ddd86b 100644 --- a/gateway-ha/src/test/java/io/trino/gateway/ha/router/TestTrinoQueryProperties.java +++ b/gateway-ha/src/test/java/io/trino/gateway/ha/router/TestTrinoQueryProperties.java @@ -38,7 +38,8 @@ void testJsonCreator() ImmutableSet.of("s"), ImmutableSet.of("c.s"), true, - true); + true, + Optional.empty()); String trinoQueryPropertiesJson = codec.toJson(trinoQueryProperties); TrinoQueryProperties deserializedTrinoQueryProperties = codec.fromJson(trinoQueryPropertiesJson); @@ -53,6 +54,7 @@ void testJsonCreator() assertThat(deserializedTrinoQueryProperties.getCatalogs()).isEqualTo(trinoQueryProperties.getCatalogs()); assertThat(deserializedTrinoQueryProperties.getCatalogSchemas()).isEqualTo(trinoQueryProperties.getCatalogSchemas()); assertThat(deserializedTrinoQueryProperties.isNewQuerySubmission()).isEqualTo(trinoQueryProperties.isNewQuerySubmission()); - assertThat(deserializedTrinoQueryProperties.isQueryParsingSuccessful()).isEqualTo(trinoQueryProperties.isQueryParsingSuccessful()); + assertThat(deserializedTrinoQueryProperties.isQueryParsingSuccessful()).isEqualTo(trinoQueryProperties.isQueryParsingSuccessful());; + assertThat(deserializedTrinoQueryProperties.getErrorMessage()).isEqualTo(trinoQueryProperties.getErrorMessage()); } }