Mapping With a `null` Default Timestamp Causes NullPointerException on Merge
I have a field with a `null` [default `_timestamp` value](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-timestamp-field.html#mapping-timestamp-field-default) and when I try to update the mapping I get a server error caused by a `NullPointerException` ``` [2015-01-08 17:28:56,040][DEBUG][action.admin.indices.mapping.put] [...] failed to put mappings on indices [[feed_170_v1, feed_204_v1, feed_229_v1, feed_232_v1, feed_239_v1, feed_248_v1, feed_268_v1, feed_256_v1, feed_272_v1, feed_159_v1, feed_255_v1, feed_164_v1, feed_259_v1, feed_266_v1, feed_188_v1, feed_240_v1, feed_233_v1, feed_13_v1, feed_184_v1, feed_261_v1, feed_267_v1, feed_271_v1, feed_257_v1, feed_172_v1, feed_238_v1, feed_254_v1, feed_223_v1, feed_274_v1, feed_203_v1, feed_269_v1, feed_262_v1, feed_205_v1, feed_168_v1, feed_219_v1, feed_253_v1, feed_251_v1, feed_173_v1, feed_252_v1, feed_210_v1, feed_216_v1, feed_218_v1, feed_118_v1, feed_273_v1, feed_227_v1, feed_166_v1, feed_213_v1, feed_226_v1]], type [history] java.lang.NullPointerException at org.elasticsearch.index.mapper.internal.TimestampFieldMapper.merge(TimestampFieldMapper.java:287) at org.elasticsearch.index.mapper.object.ObjectMapper.merge(ObjectMapper.java:936) at org.elasticsearch.index.mapper.DocumentMapper.merge(DocumentMapper.java:693) at org.elasticsearch.cluster.metadata.MetaDataMappingService$4.execute(MetaDataMappingService.java:508) at org.elasticsearch.cluster.service.InternalClusterService$UpdateTask.run(InternalClusterService.java:329) at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:153) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) ``` https://github.com/elasticsearch/elasticsearch/blob/v1.4.2/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java#L286 Looks like the existence of default timestamp is not checked before use. The next line also has the same issue -- uses of default timestamp without checked to see if it's not null. To reproduce: ``` $ curl -XPUT localhost:9200/twitter2 $ curl -XPUT localhost:9200/twitter2/tweet/_mapping -d '{ "tweet" : { "_timestamp" : { "enabled" : true, "default" : null } } }' $ curl -XPUT localhost:9200/twitter2/tweet/_mapping -d '{ "tweet" : { "_timestamp" : { "enabled" : true, "default" : null }, "properties": { "user": {"type": "string"} } } }' ``` Closes #9204. (cherry picked from commit 62c6d63)
This commit is contained in:
parent
7f9ffea97c
commit
6d58db8868
|
@ -305,7 +305,14 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap
|
|||
this.enabledState = timestampFieldMapperMergeWith.enabledState;
|
||||
}
|
||||
} else {
|
||||
if (!timestampFieldMapperMergeWith.defaultTimestamp().equals(defaultTimestamp)) {
|
||||
if (timestampFieldMapperMergeWith.defaultTimestamp() == null && defaultTimestamp == null) {
|
||||
return;
|
||||
}
|
||||
if (defaultTimestamp == null) {
|
||||
mergeContext.addConflict("Cannot update default in _timestamp value. Value is null now encountering " + timestampFieldMapperMergeWith.defaultTimestamp());
|
||||
} else if (timestampFieldMapperMergeWith.defaultTimestamp() == null) {
|
||||
mergeContext.addConflict("Cannot update default in _timestamp value. Value is \" + defaultTimestamp.toString() + \" now encountering null");
|
||||
} else if (!timestampFieldMapperMergeWith.defaultTimestamp().equals(defaultTimestamp)) {
|
||||
mergeContext.addConflict("Cannot update default in _timestamp value. Value is " + defaultTimestamp.toString() + " now encountering " + timestampFieldMapperMergeWith.defaultTimestamp());
|
||||
}
|
||||
if (this.path != null) {
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.mapper.timestamp;
|
|||
import org.apache.lucene.index.IndexOptions;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.TimestampParsingException;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||
|
@ -541,6 +542,87 @@ public class TimestampMappingTests extends ElasticsearchSingleNodeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for #9204
|
||||
*/
|
||||
@Test
|
||||
public void testMergingNullValues() throws Exception {
|
||||
// From trying to add another field with default = null
|
||||
String mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", (String) null)
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
|
||||
|
||||
DocumentMapper docMapper = parser.parse(mapping);
|
||||
mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", (String) null)
|
||||
.endObject()
|
||||
.startObject("properties")
|
||||
.startObject("foo")
|
||||
.field("type", "string")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
DocumentMapper.MergeResult mergeResult = docMapper.merge(parser.parse(mapping), DocumentMapper.MergeFlags.mergeFlags().simulate(true));
|
||||
assertThat(mergeResult.hasConflicts(), is(false));
|
||||
|
||||
client().admin().indices().delete(new DeleteIndexRequest("test")).get();
|
||||
|
||||
// From trying to update from null to non null
|
||||
mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", (String) null)
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
parser = createIndex("test").mapperService().documentMapperParser();
|
||||
|
||||
docMapper = parser.parse(mapping);
|
||||
mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", "now")
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
mergeResult = docMapper.merge(parser.parse(mapping), DocumentMapper.MergeFlags.mergeFlags().simulate(true));
|
||||
assertThat(mergeResult.hasConflicts(), is(true));
|
||||
|
||||
client().admin().indices().delete(new DeleteIndexRequest("test")).get();
|
||||
|
||||
// From trying to update from non null to null
|
||||
mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", "now")
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
parser = createIndex("test").mapperService().documentMapperParser();
|
||||
|
||||
docMapper = parser.parse(mapping);
|
||||
mapping = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("type")
|
||||
.startObject("_timestamp")
|
||||
.field("enabled", true)
|
||||
.field("default", (String) null)
|
||||
.endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
mergeResult = docMapper.merge(parser.parse(mapping), DocumentMapper.MergeFlags.mergeFlags().simulate(true));
|
||||
assertThat(mergeResult.hasConflicts(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergePaths() throws Exception {
|
||||
String[] possiblePathValues = {"some_path", "anotherPath", null};
|
||||
|
|
Loading…
Reference in New Issue