SQL: Ignore the _default_ type
It is allowed even in single type indices because it isn't real. We should ignore it entirely. Original commit: elastic/x-pack-elasticsearch@efc2cf80c8
This commit is contained in:
parent
764d802bef
commit
337e9f4d6e
|
@ -5,15 +5,20 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.analysis.catalog;
|
package org.elasticsearch.xpack.sql.analysis.catalog;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
|
||||||
|
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.MetaData;
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -43,10 +48,7 @@ public class EsCatalog implements Catalog {
|
||||||
if (idx == null) {
|
if (idx == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (false == indexHasOnlyOneType(idx)) {
|
return EsIndex.build(idx, singleType(idx, false));
|
||||||
throw new SqlIllegalArgumentException("index has more than one type");
|
|
||||||
}
|
|
||||||
return EsIndex.build(idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,16 +71,48 @@ public class EsCatalog implements Catalog {
|
||||||
// filter unsupported (indices with more than one type) indices
|
// filter unsupported (indices with more than one type) indices
|
||||||
while (indexMetadata.hasNext()) {
|
while (indexMetadata.hasNext()) {
|
||||||
IndexMetaData imd = indexMetadata.next();
|
IndexMetaData imd = indexMetadata.next();
|
||||||
if (indexHasOnlyOneType(imd)) {
|
MappingMetaData type = singleType(imd, true);
|
||||||
list.add(EsIndex.build(imd));
|
if (type != null) {
|
||||||
|
list.add(EsIndex.build(imd, type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean indexHasOnlyOneType(IndexMetaData index) {
|
/**
|
||||||
return index.getMappings().size() <= 1;
|
* Return the single type in the index of {@code null} if there
|
||||||
|
* are no types in the index.
|
||||||
|
* @param badIndicesAreNull if true then return null for indices with
|
||||||
|
* more than one type, if false throw an exception for such indices
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private MappingMetaData singleType(IndexMetaData index, boolean badIndicesAreNull) {
|
||||||
|
/* We actually ignore the _default_ mapping because it is still
|
||||||
|
* allowed but deprecated. */
|
||||||
|
MappingMetaData result = null;
|
||||||
|
List<String> typeNames = null;
|
||||||
|
for (ObjectObjectCursor<String, MappingMetaData> type : index.getMappings()) {
|
||||||
|
if ("_default_".equals(type.key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (result != null) {
|
||||||
|
if (badIndicesAreNull) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (typeNames == null) {
|
||||||
|
typeNames = new ArrayList<>();
|
||||||
|
typeNames.add(result.type());
|
||||||
|
}
|
||||||
|
typeNames.add(type.key);
|
||||||
|
}
|
||||||
|
result = type.value;
|
||||||
|
}
|
||||||
|
if (typeNames == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Collections.sort(typeNames);
|
||||||
|
throw new IllegalArgumentException("[" + index.getIndex().getName() + "] has more than one type " + typeNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] resolveIndex(String pattern) {
|
private String[] resolveIndex(String pattern) {
|
||||||
|
|
|
@ -7,16 +7,13 @@ package org.elasticsearch.xpack.sql.analysis.catalog;
|
||||||
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
|
||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.type.Types;
|
import org.elasticsearch.xpack.sql.type.Types;
|
||||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -56,24 +53,8 @@ public class EsIndex {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<EsIndex> build(Iterator<IndexMetaData> metadata) {
|
static EsIndex build(IndexMetaData metadata, @Nullable MappingMetaData type) {
|
||||||
if (metadata == null || !metadata.hasNext()) {
|
Map<String, DataType> mapping = type != null ? Types.fromEs(type.sourceAsMap()) : emptyMap();
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
List<EsIndex> list = new ArrayList<>();
|
|
||||||
while (metadata.hasNext()) {
|
|
||||||
build(metadata.next());
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EsIndex build(IndexMetaData metadata) {
|
|
||||||
ImmutableOpenMap<String, MappingMetaData> mappings = metadata.getMappings();
|
|
||||||
if (mappings.size() > 1) {
|
|
||||||
throw new SqlIllegalArgumentException("Cannot use index [%s] as it contains multiple types %s", metadata.getIndex().getName(), Arrays.toString(mappings.keys().toArray()));
|
|
||||||
}
|
|
||||||
MappingMetaData mm = mappings.isEmpty() ? null : mappings.valuesIt().next();
|
|
||||||
Map<String, DataType> mapping = mm != null ? Types.fromEs(mm.sourceAsMap()) : emptyMap();
|
|
||||||
|
|
||||||
List<String> aliases = Arrays.asList(metadata.getAliases().keys().toArray(String.class));
|
List<String> aliases = Arrays.asList(metadata.getAliases().keys().toArray(String.class));
|
||||||
return new EsIndex(metadata.getIndex().getName(), mapping, aliases, metadata.getSettings());
|
return new EsIndex(metadata.getIndex().getName(), mapping, aliases, metadata.getSettings());
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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.catalog;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.cluster.ClusterName;
|
||||||
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
|
||||||
|
public class EsCatalogTests extends ESTestCase {
|
||||||
|
public void testEmpty() {
|
||||||
|
EsCatalog catalog = catalog(ClusterState.builder(ClusterName.DEFAULT).build());
|
||||||
|
assertEquals(emptyList(), catalog.listIndices("*"));
|
||||||
|
assertNull(catalog.getIndex("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexExists() throws IOException {
|
||||||
|
EsCatalog catalog = catalog(ClusterState.builder(ClusterName.DEFAULT)
|
||||||
|
.metaData(MetaData.builder()
|
||||||
|
.put(index("test")
|
||||||
|
.putMapping("test", "{}"))
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
List<EsIndex> indices = catalog.listIndices("*");
|
||||||
|
assertThat(indices, hasSize(1));
|
||||||
|
assertEquals("test", indices.get(0).name());
|
||||||
|
assertEquals(emptyMap(), catalog.getIndex("test").mapping());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexWithDefaultType() throws IOException {
|
||||||
|
EsCatalog catalog = catalog(ClusterState.builder(ClusterName.DEFAULT)
|
||||||
|
.metaData(MetaData.builder()
|
||||||
|
.put(index("test")
|
||||||
|
.putMapping("test", "{}")
|
||||||
|
.putMapping("_default_", "{}"))
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
List<EsIndex> indices = catalog.listIndices("*");
|
||||||
|
assertThat(indices, hasSize(1));
|
||||||
|
assertEquals("test", indices.get(0).name());
|
||||||
|
assertEquals(emptyMap(), catalog.getIndex("test").mapping());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexWithTwoTypes() throws IOException {
|
||||||
|
EsCatalog catalog = catalog(ClusterState.builder(ClusterName.DEFAULT)
|
||||||
|
.metaData(MetaData.builder()
|
||||||
|
.put(index("test")
|
||||||
|
.putMapping("first_type", "{}")
|
||||||
|
.putMapping("second_type", "{}"))
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
assertEquals(emptyList(), catalog.listIndices("*"));
|
||||||
|
Exception e = expectThrows(IllegalArgumentException.class, () -> catalog.getIndex("test"));
|
||||||
|
assertEquals(e.getMessage(), "[test] has more than one type [first_type, second_type]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private EsCatalog catalog(ClusterState state) {
|
||||||
|
EsCatalog catalog = new EsCatalog(() -> state);
|
||||||
|
catalog.setIndexNameExpressionResolver(new IndexNameExpressionResolver(Settings.EMPTY));
|
||||||
|
return catalog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndexMetaData.Builder index(String name) throws IOException {
|
||||||
|
return IndexMetaData.builder("test")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put("index.version.created", Version.CURRENT)
|
||||||
|
.put("index.number_of_shards", 1)
|
||||||
|
.put("index.number_of_replicas", 1));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue