QL: Extract common Failure class (#52281)

Shared across SQL and EQL

(cherry picked from commit 1aeda20d3ec3d6c885de03c6043dd1e8eab9f230)
This commit is contained in:
Costin Leau 2020-02-13 14:14:42 +02:00 committed by Costin Leau
parent b0ad37126c
commit 5373a77fb9
20 changed files with 52 additions and 219 deletions

View File

@ -6,7 +6,7 @@
package org.elasticsearch.xpack.eql.analysis; package org.elasticsearch.xpack.eql.analysis;
import org.elasticsearch.xpack.eql.common.Failure; import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.Attribute;
import org.elasticsearch.xpack.ql.expression.NamedExpression; import org.elasticsearch.xpack.ql.expression.NamedExpression;
import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute;

View File

@ -7,7 +7,7 @@ package org.elasticsearch.xpack.eql.analysis;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.eql.EqlClientException; import org.elasticsearch.xpack.eql.EqlClientException;
import org.elasticsearch.xpack.eql.common.Failure; import org.elasticsearch.xpack.ql.common.Failure;
import java.util.Collection; import java.util.Collection;

View File

@ -6,8 +6,8 @@
package org.elasticsearch.xpack.eql.analysis; package org.elasticsearch.xpack.eql.analysis;
import org.elasticsearch.xpack.eql.common.Failure;
import org.elasticsearch.xpack.ql.capabilities.Unresolvable; import org.elasticsearch.xpack.ql.capabilities.Unresolvable;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.Attribute;
import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
@ -23,7 +23,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toMap;
import static org.elasticsearch.xpack.eql.common.Failure.fail; import static org.elasticsearch.xpack.ql.common.Failure.fail;
/** /**
* The verifier has the role of checking the analyzed tree for failures and build a list of failures following this check. * The verifier has the role of checking the analyzed tree for failures and build a list of failures following this check.

View File

@ -6,8 +6,8 @@
package org.elasticsearch.xpack.eql.planner; package org.elasticsearch.xpack.eql.planner;
import org.elasticsearch.xpack.eql.common.Failure;
import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
import java.util.List; import java.util.List;

View File

@ -7,7 +7,7 @@ package org.elasticsearch.xpack.eql.planner;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.eql.EqlClientException; import org.elasticsearch.xpack.eql.EqlClientException;
import org.elasticsearch.xpack.eql.common.Failure; import org.elasticsearch.xpack.ql.common.Failure;
import java.util.Collection; import java.util.Collection;

View File

@ -5,15 +5,15 @@
*/ */
package org.elasticsearch.xpack.eql.planner; package org.elasticsearch.xpack.eql.planner;
import org.elasticsearch.xpack.eql.common.Failure;
import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan;
import org.elasticsearch.xpack.eql.plan.physical.Unexecutable; import org.elasticsearch.xpack.eql.plan.physical.Unexecutable;
import org.elasticsearch.xpack.eql.plan.physical.UnplannedExec; import org.elasticsearch.xpack.eql.plan.physical.UnplannedExec;
import org.elasticsearch.xpack.ql.common.Failure;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.elasticsearch.xpack.eql.common.Failure.fail; import static org.elasticsearch.xpack.ql.common.Failure.fail;
abstract class Verifier { abstract class Verifier {

View File

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.xpack.eql.common; package org.elasticsearch.xpack.ql.common;
import org.elasticsearch.xpack.ql.tree.Location; import org.elasticsearch.xpack.ql.tree.Location;
import org.elasticsearch.xpack.ql.tree.Node; import org.elasticsearch.xpack.ql.tree.Node;
@ -36,7 +36,7 @@ public class Failure {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(message, node); return Objects.hash(node);
} }
@Override @Override
@ -50,7 +50,7 @@ public class Failure {
} }
Failure other = (Failure) obj; Failure other = (Failure) obj;
return Objects.equals(message, other.message) && Objects.equals(node, other.node); return Objects.equals(node, other.node);
} }
@Override @Override

View File

@ -106,6 +106,6 @@ public abstract class ErrorsTestCase extends CliIntegrationTestCase implements o
} }
public static void assertFoundOneProblem(String commandResult) { public static void assertFoundOneProblem(String commandResult) {
assertEquals(START + "Bad request [[3;33;22mFound 1 problem(s)", commandResult); assertEquals(START + "Bad request [[3;33;22mFound 1 problem", commandResult);
} }
} }

View File

@ -20,7 +20,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
public void testSelectInvalidSql() throws Exception { public void testSelectInvalidSql() throws Exception {
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FRO").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FRO").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Cannot determine columns for [*]", e.getMessage()); assertEquals("Found 1 problem\nline 1:8: Cannot determine columns for [*]", e.getMessage());
} }
} }
@ -28,7 +28,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
public void testSelectFromMissingIndex() throws SQLException { public void testSelectFromMissingIndex() throws SQLException {
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:15: Unknown index [test]", e.getMessage()); assertEquals("Found 1 problem\nline 1:15: Unknown index [test]", e.getMessage());
} }
} }
@ -42,8 +42,8 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery());
// see https://github.com/elastic/elasticsearch/issues/34719 // see https://github.com/elastic/elasticsearch/issues/34719
//assertEquals("Found 1 problem(s)\nline 1:15: [test] doesn't have any types so it is incompatible with sql", e.getMessage()); //assertEquals("Found 1 problem\nline 1:15: [test] doesn't have any types so it is incompatible with sql", e.getMessage());
assertEquals("Found 1 problem(s)\nline 1:15: Unknown index [test]", e.getMessage()); assertEquals("Found 1 problem\nline 1:15: Unknown index [test]", e.getMessage());
} }
} }
@ -52,7 +52,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
index("test", body -> body.field("test", "test")); index("test", body -> body.field("test", "test"));
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing FROM test").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Unknown column [missing]", e.getMessage()); assertEquals("Found 1 problem\nline 1:8: Unknown column [missing]", e.getMessage());
} }
} }
@ -61,7 +61,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
index("test", body -> body.field("foo", 1)); index("test", body -> body.field("foo", 1));
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing(foo) FROM test").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing(foo) FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Unknown function [missing]", e.getMessage()); assertEquals("Found 1 problem\nline 1:8: Unknown function [missing]", e.getMessage());
} }
} }
@ -71,7 +71,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> SQLException e = expectThrows(SQLException.class, () ->
c.prepareStatement("SELECT foo, SCORE(), COUNT(*) FROM test GROUP BY foo").executeQuery()); c.prepareStatement("SELECT foo, SCORE(), COUNT(*) FROM test GROUP BY foo").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:13: Cannot use non-grouped column [SCORE()], expected [foo]", e.getMessage()); assertEquals("Found 1 problem\nline 1:13: Cannot use non-grouped column [SCORE()], expected [foo]", e.getMessage());
} }
} }
@ -82,7 +82,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
SQLException e = expectThrows(SQLException.class, () -> SQLException e = expectThrows(SQLException.class, () ->
c.prepareStatement("SELECT foo, COUNT(*) FROM test GROUP BY foo ORDER BY SCORE()").executeQuery()); c.prepareStatement("SELECT foo, COUNT(*) FROM test GROUP BY foo ORDER BY SCORE()").executeQuery());
assertEquals( assertEquals(
"Found 1 problem(s)\nline 1:54: Cannot order by non-grouped column [SCORE()], expected [foo] or an aggregate function", "Found 1 problem\nline 1:54: Cannot order by non-grouped column [SCORE()], expected [foo] or an aggregate function",
e.getMessage()); e.getMessage());
} }
} }
@ -93,7 +93,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> SQLException e = expectThrows(SQLException.class, () ->
c.prepareStatement("SELECT COUNT(*) FROM test GROUP BY SCORE()").executeQuery()); c.prepareStatement("SELECT COUNT(*) FROM test GROUP BY SCORE()").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:36: Cannot use [SCORE()] for grouping", e.getMessage()); assertEquals("Found 1 problem\nline 1:36: Cannot use [SCORE()] for grouping", e.getMessage());
} }
} }
@ -113,7 +113,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> SQLException e = expectThrows(SQLException.class, () ->
c.prepareStatement("SELECT SIN(SCORE()) FROM test").executeQuery()); c.prepareStatement("SELECT SIN(SCORE()) FROM test").executeQuery());
assertThat(e.getMessage(), startsWith("Found 1 problem(s)\nline 1:12: [SCORE()] cannot be an argument to a function")); assertThat(e.getMessage(), startsWith("Found 1 problem\nline 1:12: [SCORE()] cannot be an argument to a function"));
} }
} }

View File

@ -1,59 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.sql.analysis;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.ql.tree.Location;
import org.elasticsearch.xpack.ql.tree.Node;
import org.elasticsearch.xpack.sql.SqlClientException;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
public class AnalysisException extends SqlClientException {
private final int line;
private final int column;
public AnalysisException(Node<?> source, String message, Object... args) {
super(message, args);
Location loc = Location.EMPTY;
if (source != null && source.source() != null) {
loc = source.source().source();
}
this.line = loc.getLineNumber();
this.column = loc.getColumnNumber();
}
public AnalysisException(Node<?> source, String message, Throwable cause) {
super(message, cause);
Location loc = Location.EMPTY;
if (source != null && source.source() != null) {
loc = source.source().source();
}
this.line = loc.getLineNumber();
this.column = loc.getColumnNumber();
}
public int getLineNumber() {
return line;
}
public int getColumnNumber() {
return column;
}
@Override
public RestStatus status() {
return RestStatus.BAD_REQUEST;
}
@Override
public String getMessage() {
return format("line {}:{}: {}", getLineNumber(), getColumnNumber(), super.getMessage());
}
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.analysis.analyzer;
import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.xpack.ql.capabilities.Resolvables; import org.elasticsearch.xpack.ql.capabilities.Resolvables;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.expression.Alias; import org.elasticsearch.xpack.ql.expression.Alias;
import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.Attribute;
import org.elasticsearch.xpack.ql.expression.AttributeMap; import org.elasticsearch.xpack.ql.expression.AttributeMap;
@ -45,7 +46,6 @@ import org.elasticsearch.xpack.ql.type.InvalidMappedField;
import org.elasticsearch.xpack.ql.type.UnsupportedEsField; import org.elasticsearch.xpack.ql.type.UnsupportedEsField;
import org.elasticsearch.xpack.ql.util.CollectionUtils; import org.elasticsearch.xpack.ql.util.CollectionUtils;
import org.elasticsearch.xpack.ql.util.Holder; import org.elasticsearch.xpack.ql.util.Holder;
import org.elasticsearch.xpack.sql.analysis.analyzer.Verifier.Failure;
import org.elasticsearch.xpack.sql.expression.Foldables; import org.elasticsearch.xpack.sql.expression.Foldables;
import org.elasticsearch.xpack.sql.expression.SubQueryExpression; import org.elasticsearch.xpack.sql.expression.SubQueryExpression;
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast; import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;

View File

@ -5,31 +5,20 @@
*/ */
package org.elasticsearch.xpack.sql.analysis.analyzer; package org.elasticsearch.xpack.sql.analysis.analyzer;
import org.elasticsearch.xpack.ql.tree.Location; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.ql.util.StringUtils; import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.sql.analysis.AnalysisException; import org.elasticsearch.xpack.sql.SqlClientException;
import org.elasticsearch.xpack.sql.analysis.analyzer.Verifier.Failure;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors;
public class VerificationException extends SqlClientException {
public class VerificationException extends AnalysisException {
private final Collection<Failure> failures;
protected VerificationException(Collection<Failure> sources) { protected VerificationException(Collection<Failure> sources) {
super(null, StringUtils.EMPTY); super(Failure.failMessage(sources));
failures = sources;
} }
@Override @Override
public String getMessage() { public RestStatus status() {
return failures.stream() return RestStatus.BAD_REQUEST;
.map(f -> {
Location l = f.node().source().source();
return "line " + l.getLineNumber() + ":" + l.getColumnNumber() + ": " + f.message();
})
.collect(Collectors.joining(StringUtils.NEW_LINE, "Found " + failures.size() + " problem(s)\n", StringUtils.EMPTY));
} }
} }

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.sql.analysis.analyzer; package org.elasticsearch.xpack.sql.analysis.analyzer;
import org.elasticsearch.xpack.ql.capabilities.Unresolvable; import org.elasticsearch.xpack.ql.capabilities.Unresolvable;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.expression.Alias; import org.elasticsearch.xpack.ql.expression.Alias;
import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.Attribute;
import org.elasticsearch.xpack.ql.expression.AttributeMap; import org.elasticsearch.xpack.ql.expression.AttributeMap;
@ -61,12 +62,11 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toMap;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format; import static org.elasticsearch.xpack.ql.common.Failure.fail;
import static org.elasticsearch.xpack.ql.util.CollectionUtils.combine; import static org.elasticsearch.xpack.ql.util.CollectionUtils.combine;
import static org.elasticsearch.xpack.sql.stats.FeatureMetric.COMMAND; import static org.elasticsearch.xpack.sql.stats.FeatureMetric.COMMAND;
import static org.elasticsearch.xpack.sql.stats.FeatureMetric.GROUPBY; import static org.elasticsearch.xpack.sql.stats.FeatureMetric.GROUPBY;
@ -89,52 +89,6 @@ public final class Verifier {
this.metrics = metrics; this.metrics = metrics;
} }
static class Failure {
private final Node<?> node;
private final String message;
Failure(Node<?> node, String message) {
this.node = node;
this.message = message;
}
Node<?> node() {
return node;
}
String message() {
return message;
}
@Override
public int hashCode() {
return Objects.hash(node);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Verifier.Failure other = (Verifier.Failure) obj;
return Objects.equals(node, other.node);
}
@Override
public String toString() {
return message;
}
}
private static Failure fail(Node<?> source, String message, Object... args) {
return new Failure(source, format(message, args));
}
public Map<Node<?>, String> verifyFailures(LogicalPlan plan) { public Map<Node<?>, String> verifyFailures(LogicalPlan plan) {
Collection<Failure> failures = verify(plan); Collection<Failure> failures = verify(plan);
return failures.stream().collect(toMap(Failure::node, Failure::message)); return failures.stream().collect(toMap(Failure::node, Failure::message));

View File

@ -5,10 +5,10 @@
*/ */
package org.elasticsearch.xpack.sql.planner; package org.elasticsearch.xpack.sql.planner;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.ql.tree.Node; import org.elasticsearch.xpack.ql.tree.Node;
import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan;
import org.elasticsearch.xpack.sql.planner.Verifier.Failure;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -49,7 +49,7 @@ public class Planner {
public Map<Node<?>, String> verifyMappingPlanFailures(PhysicalPlan plan) { public Map<Node<?>, String> verifyMappingPlanFailures(PhysicalPlan plan) {
List<Failure> failures = Verifier.verifyMappingPlan(plan); List<Failure> failures = Verifier.verifyMappingPlan(plan);
return failures.stream().collect(toMap(Failure::source, Failure::message)); return failures.stream().collect(toMap(Failure::node, Failure::message));
} }
public PhysicalPlan verifyExecutingPlan(PhysicalPlan plan) { public PhysicalPlan verifyExecutingPlan(PhysicalPlan plan) {
@ -62,6 +62,6 @@ public class Planner {
public Map<Node<?>, String> verifyExecutingPlanFailures(PhysicalPlan plan) { public Map<Node<?>, String> verifyExecutingPlanFailures(PhysicalPlan plan) {
List<Failure> failures = Verifier.verifyExecutingPlan(plan); List<Failure> failures = Verifier.verifyExecutingPlan(plan);
return failures.stream().collect(toMap(Failure::source, Failure::message)); return failures.stream().collect(toMap(Failure::node, Failure::message));
} }
} }

View File

@ -6,12 +6,10 @@
package org.elasticsearch.xpack.sql.planner; package org.elasticsearch.xpack.sql.planner;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.ql.tree.Location; import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.sql.SqlClientException; import org.elasticsearch.xpack.sql.SqlClientException;
import org.elasticsearch.xpack.sql.planner.Verifier.Failure;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors;
public class PlanningException extends SqlClientException { public class PlanningException extends SqlClientException {
public PlanningException(String message, Object... args) { public PlanningException(String message, Object... args) {
@ -19,20 +17,11 @@ public class PlanningException extends SqlClientException {
} }
public PlanningException(Collection<Failure> sources) { public PlanningException(Collection<Failure> sources) {
super(extractMessage(sources)); super(Failure.failMessage(sources));
} }
@Override @Override
public RestStatus status() { public RestStatus status() {
return RestStatus.BAD_REQUEST; return RestStatus.BAD_REQUEST;
} }
private static String extractMessage(Collection<Failure> failures) {
return failures.stream()
.map(f -> {
Location l = f.source().source().source();
return "line " + l.getLineNumber() + ":" + l.getColumnNumber() + ": " + f.message();
})
.collect(Collectors.joining("\n", "Found " + failures.size() + " problem(s)\n", ""));
}
} }

View File

@ -5,8 +5,8 @@
*/ */
package org.elasticsearch.xpack.sql.planner; package org.elasticsearch.xpack.sql.planner;
import org.elasticsearch.xpack.ql.common.Failure;
import org.elasticsearch.xpack.ql.expression.function.aggregate.InnerAggregate; import org.elasticsearch.xpack.ql.expression.function.aggregate.InnerAggregate;
import org.elasticsearch.xpack.ql.tree.Node;
import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan;
import org.elasticsearch.xpack.sql.plan.physical.PivotExec; import org.elasticsearch.xpack.sql.plan.physical.PivotExec;
import org.elasticsearch.xpack.sql.plan.physical.Unexecutable; import org.elasticsearch.xpack.sql.plan.physical.Unexecutable;
@ -14,53 +14,11 @@ import org.elasticsearch.xpack.sql.plan.physical.UnplannedExec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format; import static org.elasticsearch.xpack.ql.common.Failure.fail;
abstract class Verifier { abstract class Verifier {
static class Failure {
private final Node<?> source;
private final String message;
Failure(Node<?> source, String message) {
this.source = source;
this.message = message;
}
Node<?> source() {
return source;
}
String message() {
return message;
}
@Override
public int hashCode() {
return source.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Verifier.Failure other = (Verifier.Failure) obj;
return Objects.equals(source, other.source);
}
}
private static Failure fail(Node<?> source, String message, Object... args) {
return new Failure(source, format(null, message, args));
}
static List<Failure> verifyMappingPlan(PhysicalPlan plan) { static List<Failure> verifyMappingPlan(PhysicalPlan plan) {
List<Failure> failures = new ArrayList<>(); List<Failure> failures = new ArrayList<>();

View File

@ -144,17 +144,17 @@ public class FieldAttributeTests extends ESTestCase {
} }
public void testDottedFieldPath() { public void testDottedFieldPath() {
assertThat(error("some"), is("Found 1 problem(s)\nline 1:8: Cannot use field [some] type [object] only its subfields")); assertThat(error("some"), is("Found 1 problem\nline 1:8: Cannot use field [some] type [object] only its subfields"));
} }
public void testDottedFieldPathDeeper() { public void testDottedFieldPathDeeper() {
assertThat(error("some.dotted"), assertThat(error("some.dotted"),
is("Found 1 problem(s)\nline 1:8: Cannot use field [some.dotted] type [object] only its subfields")); is("Found 1 problem\nline 1:8: Cannot use field [some.dotted] type [object] only its subfields"));
} }
public void testDottedFieldPathTypo() { public void testDottedFieldPathTypo() {
assertThat(error("some.dotted.fild"), assertThat(error("some.dotted.fild"),
is("Found 1 problem(s)\nline 1:8: Unknown column [some.dotted.fild], did you mean [some.dotted.field]?")); is("Found 1 problem\nline 1:8: Unknown column [some.dotted.fild], did you mean [some.dotted.field]?"));
} }
public void testStarExpansionExcludesObjectAndUnsupportedTypes() { public void testStarExpansionExcludesObjectAndUnsupportedTypes() {
@ -177,13 +177,13 @@ public class FieldAttributeTests extends ESTestCase {
VerificationException ex = expectThrows(VerificationException.class, () -> plan("SELECT test.bar FROM test")); VerificationException ex = expectThrows(VerificationException.class, () -> plan("SELECT test.bar FROM test"));
assertEquals( assertEquals(
"Found 1 problem(s)\nline 1:8: Reference [test.bar] is ambiguous (to disambiguate use quotes or qualifiers); " "Found 1 problem\nline 1:8: Reference [test.bar] is ambiguous (to disambiguate use quotes or qualifiers); "
+ "matches any of [\"test\".\"bar\", \"test\".\"test.bar\"]", + "matches any of [\"test\".\"bar\", \"test\".\"test.bar\"]",
ex.getMessage()); ex.getMessage());
ex = expectThrows(VerificationException.class, () -> plan("SELECT test.test FROM test")); ex = expectThrows(VerificationException.class, () -> plan("SELECT test.test FROM test"));
assertEquals( assertEquals(
"Found 1 problem(s)\nline 1:8: Reference [test.test] is ambiguous (to disambiguate use quotes or qualifiers); " "Found 1 problem\nline 1:8: Reference [test.test] is ambiguous (to disambiguate use quotes or qualifiers); "
+ "matches any of [\"test\".\"test\", \"test\".\"test.test\"]", + "matches any of [\"test\".\"test\", \"test\".\"test.test\"]",
ex.getMessage()); ex.getMessage());

View File

@ -50,9 +50,11 @@ public class VerifierErrorMessagesTests extends ESTestCase {
private String error(IndexResolution getIndexResult, String sql) { private String error(IndexResolution getIndexResult, String sql) {
Analyzer analyzer = new Analyzer(SqlTestUtils.TEST_CFG, new SqlFunctionRegistry(), getIndexResult, new Verifier(new Metrics())); Analyzer analyzer = new Analyzer(SqlTestUtils.TEST_CFG, new SqlFunctionRegistry(), getIndexResult, new Verifier(new Metrics()));
VerificationException e = expectThrows(VerificationException.class, () -> analyzer.analyze(parser.createStatement(sql), true)); VerificationException e = expectThrows(VerificationException.class, () -> analyzer.analyze(parser.createStatement(sql), true));
assertTrue(e.getMessage().startsWith("Found ")); String message = e.getMessage();
String header = "Found 1 problem(s)\nline "; assertTrue(message.startsWith("Found "));
return e.getMessage().substring(header.length()); String pattern = "\nline ";
int index = message.indexOf(pattern);
return message.substring(index + pattern.length());
} }
private LogicalPlan accept(String sql) { private LogicalPlan accept(String sql) {

View File

@ -87,7 +87,7 @@ public class QuerierTests extends ESTestCase {
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public void testAggSorting_FourFields() { public void testAggSorting_FourFields() {
List<Comparator> comparators = Arrays.asList( List<Comparator> comparators = Arrays.<Comparator> asList(
Comparator.naturalOrder(), Comparator.naturalOrder(),
Comparator.naturalOrder(), Comparator.naturalOrder(),
Comparator.reverseOrder(), Comparator.reverseOrder(),

View File

@ -61,7 +61,7 @@ public class PostOptimizerVerifierTests extends ESTestCase {
private String error(IndexResolution getIndexResult, String sql) { private String error(IndexResolution getIndexResult, String sql) {
PlanningException e = expectThrows(PlanningException.class, () -> plan(sql)); PlanningException e = expectThrows(PlanningException.class, () -> plan(sql));
assertTrue(e.getMessage().startsWith("Found ")); assertTrue(e.getMessage().startsWith("Found "));
String header = "Found 1 problem(s)\nline "; String header = "Found 1 problem\nline ";
return e.getMessage().substring(header.length()); return e.getMessage().substring(header.length());
} }