SQL: Properly handle indices with no/empty mapping (#46775)

When encountering only indices with empty mapping, the IndexResolver
throws an exception as it expects to find at least one entry.
This commit fixes this case so that an empty mapping is returned.

Fix #46757

(cherry picked from commit 5f4f5807acb93b5fab36718c092c328977a396b6)
This commit is contained in:
Costin Leau 2019-09-17 15:29:23 +03:00 committed by Costin Leau
parent 65dc888623
commit 92e518e789
8 changed files with 114 additions and 4 deletions

View File

@ -43,6 +43,27 @@ public class DataLoader {
loadEmpDatasetIntoEs(client);
}
public static void createEmptyIndex(RestClient client, String index) throws Exception {
Request request = new Request("PUT", "/" + index);
XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
createIndex.startObject("settings");
{
createIndex.field("number_of_shards", 1);
createIndex.field("number_of_replicas", 1);
}
createIndex.endObject();
createIndex.startObject("mappings");
{
createIndex.startObject("properties");
{
}
createIndex.endObject();
}
createIndex.endObject().endObject();
request.setJsonEntity(Strings.toString(createIndex));
client.performRequest(request);
}
protected static void loadEmpDatasetIntoEs(RestClient client) throws Exception {
loadEmpDatasetIntoEs(client, "test_emp", "employees");
loadEmpDatasetWithExtraIntoEs(client, "test_emp_copy", "employees");

View File

@ -71,6 +71,24 @@ public class DatabaseMetaDataTestCase extends JdbcIntegrationTestCase {
}
}
public void testGetTablesForEmptyIndices() throws Exception {
DataLoader.createEmptyIndex(client(), "test_empty");
DataLoader.createEmptyIndex(client(), "test_empty_again");
try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) {
h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_tables_empty.sql'");
CheckedSupplier<ResultSet, SQLException> all = () -> h2.createStatement()
.executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT, * FROM mock");
assertResultSets(all.get(), es.getMetaData().getTables("%", "%", "%", null));
assertResultSets(all.get(), es.getMetaData().getTables("%", "%", "te%", null));
assertResultSets(
h2.createStatement()
.executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT, * FROM mock WHERE TABLE_NAME = 'test_empty'"),
es.getMetaData().getTables("%", "%", "test_empty", null));
}
}
public void testGetTypeOfTables() throws Exception {
index("test1", body -> body.field("name", "bob"));
index("test2", body -> body.field("name", "bob"));
@ -121,4 +139,13 @@ public class DatabaseMetaDataTestCase extends JdbcIntegrationTestCase {
assertResultSets(expected, es.getMetaData().getColumns(null, "%", "%", null));
}
}
public void testColumnsForEmptyTable() throws Exception {
try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) {
h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_columns_empty.sql'");
ResultSet expected = h2.createStatement().executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT, * FROM mock");
assertResultSets(expected, es.getMetaData().getColumns(null, "%", "%", null));
}
}
}

View File

@ -37,4 +37,18 @@ public class ShowTablesTestCase extends JdbcIntegrationTestCase {
assertResultSets(expected, es.createStatement().executeQuery("SHOW TABLES"));
}
}
public void testEmptyIndex() throws Exception {
DataLoader.createEmptyIndex(client(), "test_empty");
DataLoader.createEmptyIndex(client(), "test_empty_again");
try (Connection h2 = LocalH2.anonymousDb(); Connection es = esJdbc()) {
h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_show_tables.sql'");
h2.createStatement().executeUpdate("INSERT INTO mock VALUES ('test_empty', 'BASE TABLE', 'INDEX');");
h2.createStatement().executeUpdate("INSERT INTO mock VALUES ('test_empty_again', 'BASE TABLE', 'INDEX');");
ResultSet expected = h2.createStatement().executeQuery("SELECT * FROM mock");
assertResultSets(expected, es.createStatement().executeQuery("SHOW TABLES"));
}
}
}

View File

@ -66,7 +66,7 @@ public abstract class SpecBaseIntegrationTestCase extends JdbcIntegrationTestCas
}
protected void loadDataset(RestClient client) throws Exception {
DataLoader.loadEmpDatasetIntoEs(client);
DataLoader.loadDatasetIntoEs(client);
}
@Override

View File

@ -0,0 +1,25 @@
CREATE TABLE mock (
TABLE_SCHEM VARCHAR,
TABLE_NAME VARCHAR,
COLUMN_NAME VARCHAR,
DATA_TYPE INTEGER,
TYPE_NAME VARCHAR,
COLUMN_SIZE INTEGER,
BUFFER_LENGTH INTEGER,
DECIMAL_DIGITS INTEGER,
NUM_PREC_RADIX INTEGER,
NULLABLE INTEGER,
REMARKS VARCHAR,
COLUMN_DEF VARCHAR,
SQL_DATA_TYPE INTEGER,
SQL_DATETIME_SUB INTEGER,
CHAR_OCTET_LENGTH INTEGER,
ORDINAL_POSITION INTEGER,
IS_NULLABLE VARCHAR,
SCOPE_CATALOG VARCHAR,
SCOPE_SCHEMA VARCHAR,
SCOPE_TABLE VARCHAR,
SOURCE_DATA_TYPE SMALLINT,
IS_AUTOINCREMENT VARCHAR,
IS_GENERATEDCOLUMN VARCHAR
);

View File

@ -0,0 +1,15 @@
CREATE TABLE mock (
TABLE_SCHEM VARCHAR,
TABLE_NAME VARCHAR,
TABLE_TYPE VARCHAR,
REMARKS VARCHAR,
TYPE_CAT VARCHAR,
TYPE_SCHEM VARCHAR,
TYPE_NAME VARCHAR,
SELF_REFERENCING_COL_NAME VARCHAR,
REF_GENERATION VARCHAR
) AS
SELECT null, 'test_empty', 'BASE TABLE', '', null, null, null, null, null FROM DUAL
UNION ALL
SELECT null, 'test_empty_again', 'BASE TABLE', '', null, null, null, null, null FROM DUAL
;

View File

@ -338,12 +338,13 @@ public class IndexResolver {
return null;
});
if (indices.size() != 1) {
throw new SqlIllegalArgumentException("Incorrect merging of mappings (likely due to a bug) - expect 1 but found [{}]",
if (indices.size() > 1) {
throw new SqlIllegalArgumentException(
"Incorrect merging of mappings (likely due to a bug) - expect at most one but found [{}]",
indices.size());
}
return IndexResolution.valid(indices.get(0));
return IndexResolution.valid(indices.isEmpty() ? new EsIndex(indexNames[0], emptyMap()) : indices.get(0));
}
private static EsField createField(String fieldName, Map<String, Map<String, FieldCapabilities>> globalCaps,

View File

@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
public class IndexResolverTests extends ESTestCase {
@ -211,6 +212,12 @@ public class IndexResolverTests extends ESTestCase {
}
}
public void testIndexWithNoMapping() {
Map<String, Map<String, FieldCapabilities>> versionFC = singletonMap("_version",
singletonMap("_index", new FieldCapabilities("_version", "_version", false, false)));
assertTrue(IndexResolver.mergedMappings("*", new String[] { "empty" }, versionFC).isValid());
}
public static IndexResolution merge(EsIndex... indices) {
return IndexResolver.mergedMappings("*", Stream.of(indices).map(EsIndex::name).toArray(String[]::new), fromMappings(indices));
}