diff --git a/community/cypher/runtime-util/src/main/java/org/neo4j/cypher/operations/CypherCoercions.java b/community/cypher/runtime-util/src/main/java/org/neo4j/cypher/operations/CypherCoercions.java index 4f4463fdd9fe..665148b82fb6 100644 --- a/community/cypher/runtime-util/src/main/java/org/neo4j/cypher/operations/CypherCoercions.java +++ b/community/cypher/runtime-util/src/main/java/org/neo4j/cypher/operations/CypherCoercions.java @@ -72,6 +72,7 @@ import static org.neo4j.internal.kernel.api.procs.Neo4jTypes.NTString; import static org.neo4j.internal.kernel.api.procs.Neo4jTypes.NTTime; import static org.neo4j.values.SequenceValue.IterationPreference.RANDOM_ACCESS; +import static org.neo4j.values.storable.Values.NO_VALUE; @SuppressWarnings( {"unused", "WeakerAccess"} ) public final class CypherCoercions @@ -385,7 +386,8 @@ public ListValue apply( AnyValue value, Neo4jTypes.AnyType innerType, DbAccess a { for ( int i = 0; i < coercedValues.length; i++ ) { - coercedValues[i] = innerCoercer.apply( listValue.value( i ), nextInner, access ); + AnyValue nextItem = listValue.value( i ); + coercedValues[i] = nextItem == NO_VALUE ? NO_VALUE : innerCoercer.apply( nextItem, nextInner, access ); } } else @@ -393,7 +395,8 @@ public ListValue apply( AnyValue value, Neo4jTypes.AnyType innerType, DbAccess a int i = 0; for ( AnyValue anyValue : listValue ) { - coercedValues[i++] = innerCoercer.apply( anyValue, nextInner, access ); + AnyValue nextItem = listValue.value( i ); + coercedValues[i++] = nextItem == NO_VALUE ? NO_VALUE : innerCoercer.apply( anyValue, nextInner, access ); } } return VirtualValues.list( coercedValues ); diff --git a/enterprise/cypher/compiled-expressions/src/main/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/IntermediateCodeGeneration.scala b/enterprise/cypher/compiled-expressions/src/main/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/IntermediateCodeGeneration.scala index 5fd98bde3969..039712481b98 100644 --- a/enterprise/cypher/compiled-expressions/src/main/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/IntermediateCodeGeneration.scala +++ b/enterprise/cypher/compiled-expressions/src/main/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/IntermediateCodeGeneration.scala @@ -297,79 +297,79 @@ class IntermediateCodeGeneration(slots: SlotConfiguration) { case CTString => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, TextValue, AnyValue]("asTextValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTNode => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, NodeValue, AnyValue]("asNodeValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTRelationship => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, RelationshipValue, AnyValue]("asRelationshipValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTPath => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, PathValue, AnyValue]("asPathValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTInteger => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, IntegralValue, AnyValue]("asIntegralValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTFloat => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, FloatingPointValue, AnyValue]("asFloatingPointValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTMap => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, MapValue, AnyValue, DbAccess]("asMapValue"), e.ir, DB_ACCESS)), - nullable = false, e.fields) + e.nullable, e.fields) case l: ListType => val typ = asNeoType(l.innerType) IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, ListValue, AnyValue, AnyType, DbAccess]("asList"), e.ir, typ, DB_ACCESS)), - nullable = false, e.fields) + e.nullable, e.fields) case CTBoolean => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, BooleanValue, AnyValue]("asBooleanValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTNumber => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, NumberValue, AnyValue]("asNumberValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTPoint => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, PointValue, AnyValue]("asPointValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTGeometry => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, PointValue, AnyValue]("asPointValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTDate => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, DateValue, AnyValue]("asDateValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTLocalTime => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, LocalTimeValue, AnyValue]("asLocalTimeValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTTime => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, TimeValue, AnyValue]("asTimeValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTLocalDateTime => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, LocalDateTimeValue, AnyValue]("asLocalDateTimeValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTDateTime => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, DateTimeValue, AnyValue]("asDateTimeValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case CTDuration => IntermediateExpression( noValueCheck(e)(invokeStatic(method[CypherCoercions, DurationValue, AnyValue]("asDurationValue"), e.ir)), - nullable = false, e.fields) + e.nullable, e.fields) case _ => throw new CypherTypeException(s"Can't coerce to $typ") } } diff --git a/enterprise/cypher/compiled-expressions/src/test/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/CodeGenerationTest.scala b/enterprise/cypher/compiled-expressions/src/test/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/CodeGenerationTest.scala index b5ce34b13198..d764850006cf 100644 --- a/enterprise/cypher/compiled-expressions/src/test/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/CodeGenerationTest.scala +++ b/enterprise/cypher/compiled-expressions/src/test/scala/org/neo4j/cypher/internal/runtime/compiled/expressions/CodeGenerationTest.scala @@ -1341,6 +1341,8 @@ class CodeGenerationTest extends CypherFunSuite with AstConstructionTestSupport ListType(symbols.CTFloat)) should equal(list(doubleValue(1.2), doubleValue(2), doubleValue(3.1))) coerce(list(list(doubleValue(1.2), longValue(2)), list(doubleValue(3.1))), ListType(ListType(symbols.CTInteger))) should equal(list(list(longValue(1), longValue(2)), list(longValue(3)))) + coerce(list(longValue(42), NO_VALUE, longValue(43)), ListType(symbols.CTInteger)) should equal( + list(longValue(42), NO_VALUE, longValue(43))) a [CypherTypeException] should be thrownBy coerce(path(11), ListType(symbols.CTNode)) a [CypherTypeException] should be thrownBy coerce(path(11), ListType(symbols.CTRelationship))