diff --git a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexProviderCompatibilityTestSuite.java b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexProviderCompatibilityTestSuite.java index 28da94ef25c11..a01349868bfc8 100644 --- a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexProviderCompatibilityTestSuite.java +++ b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexProviderCompatibilityTestSuite.java @@ -25,7 +25,13 @@ import org.junit.runners.Suite; import java.io.File; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -111,9 +117,14 @@ public Compatibility( IndexProviderCompatibilityTestSuite testSuite, IndexDescri Values.of( "string1" ), Values.of( 42 ), Values.of( true ), + Values.of( new char[]{'a', 'z'} ), Values.of( new String[]{"arrayString1", "arraysString2"} ), - Values.of( new long[]{314, 1337} ), // todo add the other number array types - Values.of( new boolean[]{false, true} ) ), + Values.of( new byte[]{(byte) 1, (byte) 12} ), + Values.of( new short[]{314, 1337} ), + Values.of( new int[]{3140, 13370} ), + Values.of( new long[]{31400, 133700} ), + Values.of( new boolean[]{false, true} ) + ), Arrays.asList( DateValue.epochDate( 2 ), LocalTimeValue.localTime( 100000 ), @@ -141,23 +152,83 @@ public Compatibility( IndexProviderCompatibilityTestSuite testSuite, IndexDescri DurationValue.duration( 11, 20, 30, 40 ), DurationValue.duration( 10, 21, 30, 40 ), DurationValue.duration( 10, 20, 31, 40 ), - DurationValue.duration( 10, 20, 30, 41 ) ), + DurationValue.duration( 10, 20, 30, 41 ), + Values.dateTimeArray( new ZonedDateTime[]{ + ZonedDateTime.of( 2018, 10, 9, 8, 7, 6, 5, ZoneId.of( "UTC" ) ), + ZonedDateTime.of( 2017, 9, 8, 7, 6, 5, 4, ZoneId.of( "UTC" ) ) + } ), + Values.localDateTimeArray( new LocalDateTime[]{ + LocalDateTime.of( 2018, 10, 9, 8, 7, 6, 5 ), + LocalDateTime.of( 2018, 10, 9, 8, 7, 6, 5 ) + } ), + Values.timeArray( new OffsetTime[]{ + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ), + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ) + } ), + Values.dateArray( new LocalDate[]{ + LocalDate.of( 1, 12, 28 ), + LocalDate.of( 1, 12, 28 ) + } ), + Values.localTimeArray( new LocalTime[]{ + LocalTime.of( 9, 28 ), + LocalTime.of( 9, 28 ) + } ), + Values.durationArray( new DurationValue[]{ + DurationValue.duration( 12, 10, 10, 10 ), + DurationValue.duration( 12, 10, 10, 10 ) + }) + ), Arrays.asList( Values.pointValue( CoordinateReferenceSystem.Cartesian, 0, 0 ), - Values.pointValue( CoordinateReferenceSystem.WGS84, 12.78, 56.7 ) ) ); + Values.pointValue( CoordinateReferenceSystem.WGS84, 12.78, 56.7 ) + ) ); this.valueSet2 = allValues( testSuite.supportsSpatial(), testSuite.supportsTemporal(), - Arrays.asList( Values.of( "string2" ), Values.of( 1337 ), Values.of( false ) ), + Arrays.asList( Values.of( "string2" ), Values.of( 1337 ), Values.of( false ), + Values.of( new char[]{'a', 'z'} ), + Values.of( new String[]{"someString1", "someString2"} ), + Values.of( new byte[]{(byte) 9, (byte) 9} ), + Values.of( new short[]{99, 999} ), + Values.of( new int[]{99999, 99999} ), + Values.of( new long[]{999999, 999999} ), + Values.of( new boolean[]{false, true} ) + ), Arrays.asList( DateValue.epochDate( 42 ), LocalTimeValue.localTime( 2000 ), TimeValue.time( 100L, ZoneOffset.UTC ), // Just around midnight LocalDateTimeValue.localDateTime( 2018, 2, 28, 11, 5, 1, 42 ), DateTimeValue.datetime( 1999, 12, 31, 23, 59, 59, 123456789, "Europe/London" ), - DurationValue.duration( 4, 3, 2, 1 ) ), - Arrays.asList( Values.pointValue( CoordinateReferenceSystem.Cartesian, 10, 10 ), - Values.pointValue( CoordinateReferenceSystem.WGS84, 87.21, 7.65 ) ) ); + DurationValue.duration( 4, 3, 2, 1 ), + Values.dateTimeArray( new ZonedDateTime[]{ + ZonedDateTime.of( 2000, 10, 9, 8, 7, 6, 5, ZoneId.of( "UTC" ) ), + ZonedDateTime.of( 2000, 9, 8, 7, 6, 5, 4, ZoneId.of( "UTC" ) ) + } ), + Values.localDateTimeArray( new LocalDateTime[]{ + LocalDateTime.of( 2000, 10, 9, 8, 7, 6, 5 ), + LocalDateTime.of( 2000, 10, 9, 8, 7, 6, 5 ) + } ), + Values.timeArray( new OffsetTime[]{ + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ), + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ) + } ), + Values.dateArray( new LocalDate[]{ + LocalDate.of( 2000, 12, 28 ), + LocalDate.of( 2000, 12, 28 ) + } ), + Values.localTimeArray( new LocalTime[]{ + LocalTime.of( 20, 28 ), + LocalTime.of( 20, 28 ) + } ), + Values.durationArray( new DurationValue[]{ + DurationValue.duration( 20, 10, 10, 10 ), + DurationValue.duration( 20, 10, 10, 10 ) + }) + ), + Arrays.asList( Values.pointValue( CoordinateReferenceSystem.Cartesian, 90, 90 ), + Values.pointValue( CoordinateReferenceSystem.WGS84, 9.21, 9.65 ) + ) ); pageCacheAndDependenciesRule = new PageCacheAndDependenciesRule( DefaultFileSystemRule::new, testSuite.getClass() ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java index 96f1adc347695..0e6e55ac94771 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java @@ -39,6 +39,7 @@ import org.neo4j.values.storable.LocalDateTimeValue; import org.neo4j.values.storable.LocalTimeValue; import org.neo4j.values.storable.NumberValue; +import org.neo4j.values.storable.PrimitiveArrayWriting; import org.neo4j.values.storable.TimeValue; import org.neo4j.values.storable.TimeZones; import org.neo4j.values.storable.Value; @@ -878,7 +879,7 @@ boolean read( PageCursor cursor, int size ) case DATE_ARRAY: return readArray( cursor, ArrayType.DATE, this::readDate ); case ZONED_TIME_ARRAY: - return readArray( cursor, ArrayType.ZONED_DATE_TIME, this::readZonedDateTime ); + return readArray( cursor, ArrayType.ZONED_TIME, this::readZonedTime ); case LOCAL_TIME_ARRAY: return readArray( cursor, ArrayType.LOCAL_TIME, this::readLocalTime ); case DURATION_ARRAY: @@ -1135,22 +1136,7 @@ protected void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeEx @Override protected void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException { - if ( !isArray ) - { - type = Type.ZONED_DATE_TIME; - long0 = epochSecondUTC; - long1 = nano; - long2 = -1; - long3 = offsetSeconds; - } - else - { - long0Array[currentArrayOffset] = epochSecondUTC; - long1Array[currentArrayOffset] = nano; - long2Array[currentArrayOffset] = -1; - long3Array[currentArrayOffset] = offsetSeconds; - currentArrayOffset++; - } + writeDateTime( epochSecondUTC, nano, (short) -1, offsetSeconds ); } @Override @@ -1160,6 +1146,11 @@ protected void writeDateTime( long epochSecondUTC, int nano, String zoneId ) } protected void writeDateTime( long epochSecondUTC, int nano, short zoneId ) throws RuntimeException + { + writeDateTime( epochSecondUTC, nano, zoneId, 0 ); + } + + private void writeDateTime( long epochSecondUTC, int nano, short zoneId, int offsetSeconds ) { if ( !isArray ) { @@ -1167,14 +1158,14 @@ protected void writeDateTime( long epochSecondUTC, int nano, short zoneId ) thro long0 = epochSecondUTC; long1 = nano; long2 = zoneId; - long3 = 0; + long3 = offsetSeconds; } else { long0Array[currentArrayOffset] = epochSecondUTC; long1Array[currentArrayOffset] = nano; long2Array[currentArrayOffset] = zoneId; - long3Array[currentArrayOffset] = 0; + long3Array[currentArrayOffset] = offsetSeconds; currentArrayOffset++; } } @@ -1343,6 +1334,17 @@ private void writeDurationWithTotalAvgSeconds( long months, long days, long tota } /* */ + + // Write byte array is a special case, + // instead of calling beginArray and writing the bytes one-by-one + // writeByteArray is called so that the bytes can be written in batches. + // We don't care about that though so just delegate. + @Override + public void writeByteArray( byte[] value ) throws RuntimeException + { + PrimitiveArrayWriting.writeTo( this, value ); + } + @Override public void beginArray( int size, ArrayType arrayType ) throws RuntimeException { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateCompareTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateCompareTest.java index e742a86d4bb9c..cb5bf5f6f5664 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateCompareTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateCompareTest.java @@ -21,7 +21,13 @@ import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -49,8 +55,12 @@ void compareGenericKeyState() Values.of( "string1" ), Values.of( 42 ), Values.of( true ), + Values.of( new char[]{'a', 'z'} ), Values.of( new String[]{"arrayString1", "arraysString2"} ), - Values.of( new long[]{314, 1337} ), // todo add the other number array types + Values.of( new byte[]{(byte) 1, (byte) 12} ), + Values.of( new short[]{314, 1337} ), + Values.of( new int[]{3140, 13370} ), + Values.of( new long[]{31400, 133700} ), Values.of( new boolean[]{false, true} ), DateValue.epochDate( 2 ), LocalTimeValue.localTime( 100000 ), @@ -78,9 +88,34 @@ void compareGenericKeyState() DurationValue.duration( 11, 20, 30, 40 ), DurationValue.duration( 10, 21, 30, 40 ), DurationValue.duration( 10, 20, 31, 40 ), - DurationValue.duration( 10, 20, 30, 41 ) ); + DurationValue.duration( 10, 20, 30, 41 ), + Values.dateTimeArray( new ZonedDateTime[]{ + ZonedDateTime.of( 2018, 10, 9, 8, 7, 6, 5, ZoneId.of( "UTC" ) ), + ZonedDateTime.of( 2017, 9, 8, 7, 6, 5, 4, ZoneId.of( "UTC" ) ) + } ), + Values.localDateTimeArray( new LocalDateTime[]{ + LocalDateTime.of( 2018, 10, 9, 8, 7, 6, 5 ), + LocalDateTime.of( 2018, 10, 9, 8, 7, 6, 5 ) + } ), + Values.timeArray( new OffsetTime[]{ + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ), + OffsetTime.of( 20, 8, 7, 6, ZoneOffset.UTC ) + } ), + Values.dateArray( new LocalDate[]{ + LocalDate.of( 2018, 12, 28 ), + LocalDate.of( 2018, 12, 28 ) + } ), + Values.localTimeArray( new LocalTime[]{ + LocalTime.of( 9, 28 ), + LocalTime.of( 9, 28 ) + } ), + Values.durationArray( new DurationValue[]{ + DurationValue.duration( 12, 10, 10, 10 ), + DurationValue.duration( 12, 10, 10, 10 ) + } ) // Values.pointValue( CoordinateReferenceSystem.Cartesian, 0, 0 ), // Values.pointValue( CoordinateReferenceSystem.WGS84, 12.78, 56.7 ) // todo add when spatial is supported + ); allValues.sort( Values.COMPARATOR ); List states = new ArrayList<>();