diff --git a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java index 7bcfbc053b65..387bbcaf96d4 100644 --- a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java +++ b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java @@ -209,6 +209,8 @@ private static void validateCompatibilityWithTableConfig(Schema schema, TableCon private static void validateTimeFieldSpec(TimeFieldSpec timeFieldSpec) { TimeGranularitySpec incomingGranularitySpec = timeFieldSpec.getIncomingGranularitySpec(); TimeGranularitySpec outgoingGranularitySpec = timeFieldSpec.getOutgoingGranularitySpec(); + validateEpochTimeUnitSize(incomingGranularitySpec); + validateEpochTimeUnitSize(outgoingGranularitySpec); if (!incomingGranularitySpec.equals(outgoingGranularitySpec)) { Preconditions.checkState(!incomingGranularitySpec.getName().equals(outgoingGranularitySpec.getName()), @@ -222,6 +224,15 @@ private static void validateTimeFieldSpec(TimeFieldSpec timeFieldSpec) { } } + private static void validateEpochTimeUnitSize(TimeGranularitySpec timeGranularitySpec) { + Preconditions.checkState( + !timeGranularitySpec.getTimeFormat().equals(TimeGranularitySpec.TimeFormat.EPOCH.toString()) + || timeGranularitySpec.getTimeUnitSize() == 1, + "TimeFieldSpec with EPOCH time format only supports timeUnitSize 1. Use DateTimeFieldSpec for bucketed epoch " + + "values. TimeGranularitySpec: %s", + timeGranularitySpec); + } + /** * Checks for valid format and granularity string in dateTimeFieldSpec */ diff --git a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/SchemaUtilsTest.java b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/SchemaUtilsTest.java new file mode 100644 index 000000000000..de7e070adeee --- /dev/null +++ b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/SchemaUtilsTest.java @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pinot.segment.local.utils; + +import java.util.concurrent.TimeUnit; +import org.apache.pinot.spi.data.FieldSpec.DataType; +import org.apache.pinot.spi.data.Schema; +import org.apache.pinot.spi.data.TimeGranularitySpec; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + + +@SuppressWarnings("deprecation") +public class SchemaUtilsTest { + @Test + public void testValidateRejectsBucketedEpochIncomingTimeFieldSpec() { + Schema schema = new Schema.SchemaBuilder() + .setSchemaName("testSchema") + .addSingleValueDimension("dimension", DataType.STRING) + .addTime(new TimeGranularitySpec(DataType.LONG, 5, TimeUnit.MINUTES, "eventTime"), null) + .build(); + + IllegalStateException exception = Assert.expectThrows(IllegalStateException.class, + () -> SchemaUtils.validate(schema)); + + assertThat(exception).hasMessageContaining("only supports timeUnitSize 1") + .hasMessageContaining("Use DateTimeFieldSpec"); + } + + @Test + public void testValidateRejectsBucketedEpochOutgoingTimeFieldSpec() { + Schema schema = new Schema.SchemaBuilder() + .setSchemaName("testSchema") + .addSingleValueDimension("dimension", DataType.STRING) + .addTime(new TimeGranularitySpec(DataType.LONG, TimeUnit.MILLISECONDS, "incomingTime"), + new TimeGranularitySpec(DataType.LONG, 5, TimeUnit.MINUTES, "eventTime")) + .build(); + + IllegalStateException exception = Assert.expectThrows(IllegalStateException.class, + () -> SchemaUtils.validate(schema)); + + assertThat(exception).hasMessageContaining("only supports timeUnitSize 1") + .hasMessageContaining("Use DateTimeFieldSpec"); + } + + @Test + public void testValidateAcceptsEpochTimeUnitSizeOneTimeFieldSpec() { + Schema schema = new Schema.SchemaBuilder() + .setSchemaName("testSchema") + .addSingleValueDimension("dimension", DataType.STRING) + .addTime(new TimeGranularitySpec(DataType.LONG, TimeUnit.MILLISECONDS, "eventTime"), null) + .build(); + + SchemaUtils.validate(schema); + } +}