Преглед на файлове

Forbid setting copy_to on scripted field mappers (#71621)

copy_to is currently implemented at document parse time, and does not
work with values generated from index-time scripts. We may want to add
this functionality in future, but for now this commit ensures that we throw
an exception if copy_to and script are both set on a field mapper.
Alan Woodward преди 4 години
родител
ревизия
78c79134b9

+ 1 - 8
server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java

@@ -89,14 +89,7 @@ public class BooleanFieldMapper extends FieldMapper {
             super(name);
             this.scriptCompiler = Objects.requireNonNull(scriptCompiler);
             this.script.precludesParameters(nullValue);
-            this.script.setValidator(s -> {
-                if (s != null && indexed.get() == false && docValues.get() == false) {
-                    throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
-                }
-                if (s != null && multiFieldsBuilder.hasMultiFields()) {
-                    throw new MapperParsingException("Cannot define multifields on a field with a script");
-                }
-            });
+            addScriptValidation(script, indexed, docValues);
         }
 
         @Override

+ 22 - 0
server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java

@@ -540,6 +540,10 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
                 return this;
             }
 
+            public boolean hasValues() {
+                return copyToBuilders.isEmpty() == false;
+            }
+
             public CopyTo build() {
                 if (copyToBuilders.isEmpty()) {
                     return EMPTY;
@@ -1071,6 +1075,24 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
             return contentPath.pathAsText(name);
         }
 
+        protected void addScriptValidation(
+            Parameter<Script> scriptParam,
+            Parameter<Boolean> indexParam,
+            Parameter<Boolean> docValuesParam
+        ) {
+            scriptParam.setValidator(s -> {
+                if (s != null && indexParam.get() == false && docValuesParam.get() == false) {
+                    throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
+                }
+                if (s != null && multiFieldsBuilder.hasMultiFields()) {
+                    throw new MapperParsingException("Cannot define multifields on a field with a script");
+                }
+                if (s != null && copyTo.hasValues()) {
+                    throw new MapperParsingException("Cannot define copy_to parameter on a field with a script");
+                }
+            });
+        }
+
         /**
          * Writes the current builder parameter values as XContent
          */

+ 1 - 8
server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java

@@ -85,14 +85,7 @@ public class IpFieldMapper extends FieldMapper {
             this.ignoreMalformed
                 = Parameter.boolParam("ignore_malformed", true, m -> toType(m).ignoreMalformed, ignoreMalformedByDefault);
             this.script.precludesParameters(nullValue, ignoreMalformed);
-            this.script.setValidator(s -> {
-                if (s != null && indexed.get() == false && hasDocValues.get() == false) {
-                    throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
-                }
-                if (s != null && multiFieldsBuilder.hasMultiFields()) {
-                    throw new MapperParsingException("Cannot define multifields on a field with a script");
-                }
-            });
+            addScriptValidation(script, indexed, hasDocValues);
         }
 
         Builder nullValue(String nullValue) {

+ 1 - 8
server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java

@@ -107,14 +107,7 @@ public final class KeywordFieldMapper extends FieldMapper {
             this.indexAnalyzers = indexAnalyzers;
             this.scriptCompiler = Objects.requireNonNull(scriptCompiler);
             this.script.precludesParameters(nullValue);
-            this.script.setValidator(s -> {
-                if (s != null && indexed.get() == false && hasDocValues.get() == false) {
-                    throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
-                }
-                if (s != null && multiFieldsBuilder.hasMultiFields()) {
-                    throw new MapperParsingException("Cannot define multifields on a field with a script");
-                }
-            });
+            addScriptValidation(script, indexed, hasDocValues);
         }
 
         public Builder(String name) {

+ 1 - 8
server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

@@ -110,14 +110,7 @@ public class NumberFieldMapper extends FieldMapper {
                 (n, c, o) -> o == null ? null : type.parse(o, false), m -> toType(m).nullValue).acceptsNull();
 
             this.script.precludesParameters(ignoreMalformed, coerce, nullValue);
-            this.script.setValidator(s -> {
-                if (s != null && indexed.get() == false && hasDocValues.get() == false) {
-                    throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
-                }
-                if (s != null && multiFieldsBuilder.hasMultiFields()) {
-                    throw new MapperParsingException("Cannot define multifields on a field with a script");
-                }
-            });
+            addScriptValidation(script, indexed, hasDocValues);
         }
 
         Builder nullValue(Number number) {

+ 9 - 0
test/framework/src/main/java/org/elasticsearch/index/mapper/MapperScriptTestCase.java

@@ -110,6 +110,15 @@ public abstract class MapperScriptTestCase<FactoryType> extends MapperServiceTes
         assertThat(e.getMessage(), containsString("Cannot define multifields on a field with a script"));
     }
 
+    public final void testCopyToNotPermitted() {
+        Exception e = expectThrows(MapperParsingException.class, () -> createDocumentMapper(fieldMapping(b -> {
+            b.field("type", type());
+            b.field("script", "serializer_test");
+            b.array("copy_to", "foo");
+        })));
+        assertThat(e.getMessage(), containsString("Cannot define copy_to parameter on a field with a script"));
+    }
+
     public final void testOnScriptErrorParameterRequiresScript() {
         Exception e = expectThrows(MapperParsingException.class, () -> createDocumentMapper(fieldMapping(b -> {
             b.field("type", type());