SQL: Fix error message on bad index (elastic/x-pack-elasticsearch#3312)

Fixes the error message that SQL produces when it sees unsupported
indexes. It was always returning all broken indexes as "unknown" even
though we have much better error messages. It was just throwing them
away.

I caught this originally when backporting to 6.x where we had a test
that we produced a useful error message when the user attempted to run
SQL on an index with more than one type. We couldn't run that in the
feature/sql branch because it is inside the full cluster restart tests
and the "old" version of Elasticsearch used in those tests in
feature/sql is 6.x which doesn't allow indexes with multiple types. When
I backported to 6.x the test failed because it hadn't been run before.

In addition to fixing that test and the problem, this adds another test
that will reveal the problem when run in the feature/sql and master
branch.

Original commit: elastic/x-pack-elasticsearch@c7b787baee
This commit is contained in:
Nik Everett 2017-12-14 09:56:36 -05:00 committed by GitHub
parent e170021037
commit f5af60c7cf
8 changed files with 90 additions and 7 deletions

View File

@ -290,7 +290,8 @@ public class FullClusterRestartIT extends ESRestTestCase {
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest("POST", "/_xpack/sql", emptyMap(),
new StringEntity("{\"query\":\"SELECT * FROM testsqlfailsonindexwithtwotypes\"}", ContentType.APPLICATION_JSON)));
assertEquals(400, e.getResponse().getStatusLine().getStatusCode());
assertThat(e.getMessage(), containsString("Invalid index testsqlfailsonindexwithtwotypes; contains more than one type"));
assertThat(e.getMessage(), containsString(
"[testsqlfailsonindexwithtwotypes] contains more than one type [type1, type2] so it is incompatible with sql"));
}
private String loadWatch(String watch) throws IOException {

View File

@ -13,6 +13,7 @@ package org.elasticsearch.xpack.qa.sql;
public interface ErrorsTestCase {
void testSelectInvalidSql() throws Exception;
void testSelectFromMissingIndex() throws Exception;
void testSelectFromIndexWithoutTypes() throws Exception;
void testSelectMissingField() throws Exception;
void testSelectMissingFunction() throws Exception;
}

View File

@ -6,6 +6,10 @@
package org.elasticsearch.xpack.qa.sql.cli;
import java.io.IOException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import static java.util.Collections.emptyMap;
/**
* Tests for error messages.
@ -23,6 +27,15 @@ public abstract class ErrorsTestCase extends CliIntegrationTestCase implements o
assertEquals("line 1:15: Unknown index [test][1;23;31m][0m", readLine());
}
@Override
public void testSelectFromIndexWithoutTypes() throws Exception {
// Create an index without any types
client().performRequest("PUT", "/test", emptyMap(), new StringEntity("{}", ContentType.APPLICATION_JSON));
assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT * FROM test"));
assertEquals("line 1:15: [test] doesn't have any types so it is incompatible with sql[1;23;31m][0m", readLine());
}
@Override
public void testSelectMissingField() throws IOException {
index("test", body -> body.field("test", "test"));

View File

@ -7,6 +7,10 @@ package org.elasticsearch.xpack.qa.sql.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import static java.util.Collections.emptyMap;
/**
* Tests for exceptions and their messages.
@ -28,6 +32,17 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
}
}
@Override
public void testSelectFromIndexWithoutTypes() throws Exception {
// Create an index without any types
client().performRequest("PUT", "/test", emptyMap(), new StringEntity("{}", ContentType.APPLICATION_JSON));
try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:15: [test] doesn't have any types so it is incompatible with sql", e.getMessage());
}
}
@Override
public void testSelectMissingField() throws Exception {
index("test", body -> body.field("test", "test"));

View File

@ -30,6 +30,7 @@ import java.util.Map;
import java.util.TreeMap;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.Collections.unmodifiableMap;
@ -137,6 +138,15 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
expectBadRequest(() -> runSql("SELECT * FROM missing"), containsString("1:15: Unknown index [missing]"));
}
@Override
public void testSelectFromIndexWithoutTypes() throws Exception {
// Create an index without any types
client().performRequest("PUT", "/test", emptyMap(), new StringEntity("{}", ContentType.APPLICATION_JSON));
expectBadRequest(() -> runSql("SELECT * FROM test"),
containsString("1:15: [test] doesn't have any types so it is incompatible with sql"));
}
@Override
public void testSelectMissingField() throws IOException {
StringBuilder bulk = new StringBuilder();

View File

@ -20,7 +20,7 @@ public final class GetIndexResult {
}
public static GetIndexResult notFound(String name) {
Objects.requireNonNull(name, "name must not be null");
return invalid("Index '" + name + "' does not exist");
return invalid("Unknown index [" + name + "]");
}
private final EsIndex index;

View File

@ -61,7 +61,7 @@ public class UnresolvedRelation extends LeafPlan implements Unresolvable {
@Override
public int hashCode() {
return Objects.hash(table);
return Objects.hash(location(), table, alias, unresolvedMsg);
}
@Override
@ -69,12 +69,15 @@ public class UnresolvedRelation extends LeafPlan implements Unresolvable {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
UnresolvedRelation other = (UnresolvedRelation) obj;
return Objects.equals(table, other.table);
return location().equals(other.location())
&& table.equals(other.table)
&& Objects.equals(alias, other.alias)
&& unresolvedMsg.equals(other.unresolvedMsg);
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.plan.logical;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.sql.plan.TableIdentifier;
import org.elasticsearch.xpack.sql.tree.Location;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
public class UnresolvedRelationTests extends ESTestCase {
public void testEqualsAndHashCode() {
Location location = new Location(between(1, 1000), between(1, 1000));
TableIdentifier table = new TableIdentifier(location, randomAlphaOfLength(5));
String alias = randomBoolean() ? null : randomAlphaOfLength(5);
String unresolvedMessage = randomAlphaOfLength(5);
UnresolvedRelation relation = new UnresolvedRelation(location, table, alias, unresolvedMessage);
List<Function<UnresolvedRelation, UnresolvedRelation>> mutators = new ArrayList<>();
mutators.add(r -> new UnresolvedRelation(
new Location(r.location().getLineNumber() + 1, r.location().getColumnNumber()), r.table(), r.alias(), r.unresolvedMessage()));
mutators.add(r -> new UnresolvedRelation(
r.location(), new TableIdentifier(r.location(), r.table().index() + "m"), r.alias(), r.unresolvedMessage()));
mutators.add(r -> new UnresolvedRelation(
r.location(),
r.table(),
randomValueOtherThan(r.alias(), () -> randomBoolean() ? null : randomAlphaOfLength(5)),
r.unresolvedMessage()));
mutators.add(r -> new UnresolvedRelation(
r.location(), r.table(), r.alias(), randomValueOtherThan(r.unresolvedMessage(), () -> randomAlphaOfLength(5))));
checkEqualsAndHashCode(relation,
r -> new UnresolvedRelation(r.location(), r.table(), r.alias(), r.unresolvedMessage()),
r -> randomFrom(mutators).apply(r));
}
}