This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/kylin.git
commit 6bd5b43bb06b6bf19d1a096d99146396aab8d5b2 Author: Zhong, Yanghong <nju_y...@apache.org> AuthorDate: Mon Apr 13 16:35:07 2020 +0800 KYLIN-4422 Allow to change data type from varchar to datetime --- .../org/apache/kylin/common/KylinConfigBase.java | 8 ++ .../kylin/cube/gridtable/CubeCodeSystem.java | 21 +++++ .../org/apache/kylin/cube/model/RowKeyColDesc.java | 12 ++- .../org/apache/kylin/cube/model/RowKeyDesc.java | 4 + .../org/apache/kylin/dict/DictionaryGenerator.java | 104 ++------------------- .../kylin/dict/lookup/LookupStringTable.java | 8 +- .../apache/kylin/dict/DictionaryProviderTest.java | 26 +----- .../org/apache/kylin/metadata/tuple/Tuple.java | 19 ++-- .../org/apache/kylin/metadata/tuple/TupleInfo.java | 4 + .../kylin/storage/gtrecord/CubeTupleConverter.java | 42 ++++++++- .../test/resources/query/sql_casewhen/query58.sql | 22 +++++ .../rest/service/TableSchemaUpdateChecker.java | 4 + .../service/update/TableSchemaUpdaterTest.java | 1 - 13 files changed, 146 insertions(+), 129 deletions(-) diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java index 99123ec..13e73d9 100644 --- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java +++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java @@ -507,6 +507,10 @@ public abstract class KylinConfigBase implements Serializable { return Boolean.parseBoolean(getOptional("kylin.metadata.model-schema-updater-checker-enabled", "false")); } + public boolean isAbleChangeStringToDateTime() { + return Boolean.parseBoolean(getOptional("kylin.metadata.able-change-string-to-datetime", "false")); + } + // ============================================================================ // DICTIONARY & SNAPSHOT // ============================================================================ @@ -706,6 +710,10 @@ public abstract class KylinConfigBase implements Serializable { return getOptional("kylin.cube.cuboid-scheduler", "org.apache.kylin.cube.cuboid.DefaultCuboidScheduler"); } + public boolean isRowKeyEncodingAutoConvert() { + return Boolean.parseBoolean(getOptional("kylin.cube.kylin.cube.rowkey-encoding-auto-convert", "true")); + } + public String getSegmentAdvisor() { return getOptional("kylin.cube.segment-advisor", "org.apache.kylin.cube.CubeSegmentAdvisor"); } diff --git a/core-cube/src/main/java/org/apache/kylin/cube/gridtable/CubeCodeSystem.java b/core-cube/src/main/java/org/apache/kylin/cube/gridtable/CubeCodeSystem.java index 4c71fea..c049027 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/gridtable/CubeCodeSystem.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/gridtable/CubeCodeSystem.java @@ -18,12 +18,15 @@ package org.apache.kylin.cube.gridtable; +import static org.apache.kylin.metadata.filter.FilterOptimizeTransformer.logger; + import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Collections; import java.util.Map; import org.apache.kylin.common.util.Bytes; +import org.apache.kylin.common.util.DateFormat; import org.apache.kylin.common.util.ImmutableBitSet; import org.apache.kylin.dimension.DictionaryDimEnc; import org.apache.kylin.dimension.DictionaryDimEnc.DictionarySerializer; @@ -33,6 +36,7 @@ import org.apache.kylin.gridtable.GTInfo; import org.apache.kylin.gridtable.IGTCodeSystem; import org.apache.kylin.gridtable.IGTComparator; import org.apache.kylin.measure.MeasureAggregator; +import org.apache.kylin.metadata.datatype.DataType; import org.apache.kylin.metadata.datatype.DataTypeSerializer; import org.apache.kylin.metadata.datatype.DynamicDimSerializer; @@ -127,6 +131,23 @@ public class CubeCodeSystem implements IGTCodeSystem { if (dictEnc.getRoundingFlag() != roundingFlag) { serializer = dictEnc.copy(roundingFlag).asDataTypeSerializer(); } + + // Deal with data type change from string to datetime + DataType dataType = info.getColumnType(col); + if (dataType.isDateTimeFamily()) { + try { + long ts = DateFormat.stringToMillis((String) value); + if (dataType.isDate()) { + value = DateFormat.formatToDateStr(ts); + } else { + value = DateFormat.formatToTimeWithoutMilliStr(ts); + } + logger.info("Convert value from {} to {}", ts, value); + } catch (Exception e) { + logger.warn("Fail to convert value {} to string due to {}", value, e); + } + } + try { serializer.serialize(value, buf); } catch (IllegalArgumentException ex) { diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyColDesc.java b/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyColDesc.java index f1d5645..1e95f51 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyColDesc.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyColDesc.java @@ -45,6 +45,14 @@ import org.apache.kylin.shaded.com.google.common.base.Preconditions; public class RowKeyColDesc implements java.io.Serializable { private static final Logger logger = LoggerFactory.getLogger(RowKeyColDesc.class); + public static boolean isDateDimEnc(RowKeyColDesc rowKeyColDesc) { + return DateDimEnc.ENCODING_NAME.equals(rowKeyColDesc.getEncodingName()); + } + + public static boolean isTimeDimEnc(RowKeyColDesc rowKeyColDesc) { + return TimeDimEnc.ENCODING_NAME.equals(rowKeyColDesc.getEncodingName()); + } + @JsonProperty("column") private String column; @JsonProperty("encoding") @@ -81,12 +89,14 @@ public class RowKeyColDesc implements java.io.Serializable { // convert date/time dictionary on date/time column to DimensionEncoding implicitly // however date/time dictionary on varchar column is still required DataType type = colRef.getType(); - if (DictionaryDimEnc.ENCODING_NAME.equals(encodingName)) { + if (DictionaryDimEnc.ENCODING_NAME.equals(encodingName) && cubeDesc.getConfig().isRowKeyEncodingAutoConvert()) { if (type.isDate()) { encoding = encodingName = DateDimEnc.ENCODING_NAME; + logger.info("Implicitly convert encoding to {}", encodingName); } if (type.isTimeFamily()) { encoding = encodingName = TimeDimEnc.ENCODING_NAME; + logger.info("Implicitly convert encoding to {}", encodingName); } } diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyDesc.java b/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyDesc.java index c28c828..8934a3b 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyDesc.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/RowKeyDesc.java @@ -67,6 +67,10 @@ public class RowKeyDesc implements java.io.Serializable { return desc; } + public RowKeyColDesc getColDescUncheck(TblColRef col) { + return columnMap.get(col); + } + public boolean isUseDictionary(TblColRef col) { return getColDesc(col).isUsingDictionary(); } diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java b/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java index f4aaa45..a0730ff 100644 --- a/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java +++ b/core-dictionary/src/main/java/org/apache/kylin/dict/DictionaryGenerator.java @@ -22,19 +22,18 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import com.google.common.base.Function; -import com.google.common.collect.Lists; +import javax.annotation.Nullable; + import org.apache.commons.lang.StringUtils; import org.apache.kylin.common.KylinConfig; -import org.apache.kylin.common.util.DateFormat; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.metadata.datatype.DataType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Function; import com.google.common.base.Preconditions; - -import javax.annotation.Nullable; +import com.google.common.collect.Lists; /** * @author yangli9 @@ -49,18 +48,11 @@ public class DictionaryGenerator { // build dict, case by data type IDictionaryBuilder builder; - if (dataType.isDateTimeFamily()) { - if (dataType.isDate()) - builder = new DateDictBuilder(); - else - builder = new TimeDictBuilder(); - } else { - boolean useForest = KylinConfig.getInstanceFromEnv().isUseForestTrieDictionary(); - if (dataType.isNumberFamily()) - builder = useForest ? new NumberTrieDictForestBuilder() : new NumberTrieDictBuilder(); - else - builder = useForest ? new StringTrieDictForestBuilder() : new StringTrieDictBuilder(); - } + boolean useForest = KylinConfig.getInstanceFromEnv().isUseForestTrieDictionary(); + if (dataType.isNumberFamily()) + builder = useForest ? new NumberTrieDictForestBuilder() : new NumberTrieDictBuilder(); + else + builder = useForest ? new StringTrieDictForestBuilder() : new StringTrieDictBuilder(); return builder; } @@ -123,84 +115,6 @@ public class DictionaryGenerator { return buildDictionary(dataType, new MultipleDictionaryValueEnumerator(dataType, dictList)); } - private static class DateDictBuilder implements IDictionaryBuilder { - private static final String[] DATE_PATTERNS = new String[] { "yyyy-MM-dd", "yyyyMMdd" }; - - private int baseId; - private String datePattern; - - @Override - public void init(DictionaryInfo info, int baseId, String hdfsDir) throws IOException { - this.baseId = baseId; - } - - @Override - public boolean addValue(String value) { - if (StringUtils.isBlank(value)) // empty string is treated as null - return false; - - // detect date pattern on the first value - if (datePattern == null) { - for (String p : DATE_PATTERNS) { - try { - DateFormat.stringToDate(value, p); - datePattern = p; - break; - } catch (Exception e) { - // continue; - } - } - if (datePattern == null) - throw new IllegalArgumentException("Unknown date pattern for input value: " + value); - } - - // check the date format - DateFormat.stringToDate(value, datePattern); - return true; - } - - @Override - public Dictionary<String> build() throws IOException { - if (datePattern == null) - datePattern = DATE_PATTERNS[0]; - - return new DateStrDictionary(datePattern, baseId); - } - - - @Override - public void clear() { - // do nothing - } - } - - private static class TimeDictBuilder implements IDictionaryBuilder { - - @Override - public void init(DictionaryInfo info, int baseId, String hdfsDir) throws IOException { - } - - @Override - public boolean addValue(String value) { - if (StringUtils.isBlank(value)) // empty string is treated as null - return false; - - // check the time format - DateFormat.stringToMillis(value); - return true; - } - - @Override - public Dictionary<String> build() throws IOException { - return new TimeStrDictionary(); // base ID is always 0 - } - - @Override - public void clear() { - - } - } - private static class StringTrieDictBuilder implements IDictionaryBuilder { int baseId; TrieDictionaryBuilder builder; diff --git a/core-dictionary/src/main/java/org/apache/kylin/dict/lookup/LookupStringTable.java b/core-dictionary/src/main/java/org/apache/kylin/dict/lookup/LookupStringTable.java index 1d0348a..fae1cfb 100644 --- a/core-dictionary/src/main/java/org/apache/kylin/dict/lookup/LookupStringTable.java +++ b/core-dictionary/src/main/java/org/apache/kylin/dict/lookup/LookupStringTable.java @@ -84,8 +84,12 @@ public class LookupStringTable extends LookupTable<String> implements ILookupTab protected String[] convertRow(String[] cols) { for (int i = 0; i < cols.length; i++) { if (colIsDateTime[i]) { - if (cols[i] != null) - cols[i] = String.valueOf(DateFormat.stringToMillis(cols[i])); + if (cols[i] != null) { + if (cols[i].isEmpty()) + cols[i] = null; + else + cols[i] = String.valueOf(DateFormat.stringToMillis(cols[i])); + } } } return cols; diff --git a/core-dictionary/src/test/java/org/apache/kylin/dict/DictionaryProviderTest.java b/core-dictionary/src/test/java/org/apache/kylin/dict/DictionaryProviderTest.java index 7e2e218..82ce587 100644 --- a/core-dictionary/src/test/java/org/apache/kylin/dict/DictionaryProviderTest.java +++ b/core-dictionary/src/test/java/org/apache/kylin/dict/DictionaryProviderTest.java @@ -19,7 +19,6 @@ package org.apache.kylin.dict; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -37,7 +36,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -public class DictionaryProviderTest extends LocalFileMetadataTestCase{ +public class DictionaryProviderTest extends LocalFileMetadataTestCase { @Before public void setUp() throws Exception { @@ -52,28 +51,13 @@ public class DictionaryProviderTest extends LocalFileMetadataTestCase{ @Test public void testReadWrite() throws Exception { //string dict - Dictionary<String> dict = getDict(DataType.getType("string"), Arrays.asList(new String[] { "a", "b" }).iterator()); + Dictionary<String> dict = getDict(DataType.getType("string"), + Arrays.asList(new String[] { "a", "b" }).iterator()); readWriteTest(dict); //number dict - Dictionary<String> dict2 = getDict(DataType.getType("long"), Arrays.asList(new String[] { "1", "2" }).iterator()); + Dictionary<String> dict2 = getDict(DataType.getType("long"), + Arrays.asList(new String[] { "1", "2" }).iterator()); readWriteTest(dict2); - - //date dict - Dictionary<String> dict3 = getDict(DataType.getType("datetime"), Arrays.asList(new String[] { "20161122", "20161123" }).iterator()); - readWriteTest(dict3); - - //date dict - Dictionary<String> dict4 = getDict(DataType.getType("datetime"), Arrays.asList(new String[] { "2016-11-22", "2016-11-23" }).iterator()); - readWriteTest(dict4); - - //date dict - try { - Dictionary<String> dict5 = getDict(DataType.getType("date"), Arrays.asList(new String[] { "2016-11-22", "20161122" }).iterator()); - readWriteTest(dict5); - fail("Date format not correct.Should throw exception"); - } catch (IllegalArgumentException e) { - //correct - } } @Test diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/Tuple.java b/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/Tuple.java index 6a0cda9..506e7ca 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/Tuple.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/Tuple.java @@ -103,6 +103,10 @@ public class Tuple implements ITuple { values[idx] = objectValue; } + public void setDimensionValueDirectly(int idx, Object objectValue) { + values[idx] = objectValue; + } + public void setMeasureValue(String fieldName, Object fieldValue) { setMeasureValue(info.getFieldIndex(fieldName), fieldValue); } @@ -182,10 +186,14 @@ public class Tuple implements ITuple { } } - private static long epicDaysToMillis(int days) { + public static long epicDaysToMillis(int days) { return 1L * days * (1000 * 3600 * 24); } + public static int millisToEpicDays(long millis) { + return (int) (millis / (1000 * 3600 * 24)); + } + public static Object convertOptiqCellValue(String strValue, String dataTypeName) { if (strValue == null) return null; @@ -197,10 +205,10 @@ public class Tuple implements ITuple { switch (dataTypeName) { case "date": // convert epoch time - return Integer.valueOf(dateToEpicDays(strValue));// Optiq expects Integer instead of Long. by honma + return millisToEpicDays(DateFormat.stringToMillis(strValue));// Optiq expects Integer instead of Long. by honma case "datetime": case "timestamp": - return Long.valueOf(DateFormat.stringToMillis(strValue)); + return DateFormat.stringToMillis(strValue); case "tinyint": return Byte.valueOf(strValue); case "smallint": @@ -222,9 +230,4 @@ public class Tuple implements ITuple { } } - private static int dateToEpicDays(String strValue) { - long millis = DateFormat.stringToMillis(strValue); - return (int) (millis / (1000 * 3600 * 24)); - } - } diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/TupleInfo.java b/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/TupleInfo.java index c3e88b5..213688d 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/TupleInfo.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/tuple/TupleInfo.java @@ -52,6 +52,10 @@ public class TupleInfo { return columns.get(idx); } + public TblColRef getColumn(int idx) { + return columns.get(idx); + } + public int getColumnIndex(TblColRef col) { return columnMap.get(col); } diff --git a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/CubeTupleConverter.java b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/CubeTupleConverter.java index ddf2a5a..5d6f750 100644 --- a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/CubeTupleConverter.java +++ b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/CubeTupleConverter.java @@ -28,11 +28,14 @@ import java.util.TimeZone; import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.util.Array; +import org.apache.kylin.common.util.DateFormat; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.cube.CubeManager; import org.apache.kylin.cube.CubeSegment; import org.apache.kylin.cube.cuboid.Cuboid; import org.apache.kylin.cube.model.CubeDesc.DeriveInfo; +import org.apache.kylin.cube.model.RowKeyColDesc; +import org.apache.kylin.cube.model.RowKeyDesc; import org.apache.kylin.dict.lookup.ILookupTable; import org.apache.kylin.dimension.TimeDerivedColumnType; import org.apache.kylin.measure.MeasureType; @@ -75,6 +78,8 @@ public class CubeTupleConverter implements ITupleConverter { public final int nSelectedDims; + private final RowKeyDesc rowKeyDesc; + public CubeTupleConverter(CubeSegment cubeSeg, Cuboid cuboid, // Set<TblColRef> selectedDimensions, Set<FunctionDesc> selectedMetrics, int[] gtColIdx, TupleInfo returnTupleInfo) { this.cubeSeg = cubeSeg; @@ -148,6 +153,8 @@ public class CubeTupleConverter implements ITupleConverter { } } } + + rowKeyDesc = cubeSeg.getCubeDesc().getRowkey(); } // load only needed dictionaries @@ -169,6 +176,7 @@ public class CubeTupleConverter implements ITupleConverter { if (ti >= 0) { // add offset to return result according to timezone if (autoJustByTimezone && timestampColumn.contains(ti)) { + // For streaming try { String v = toString(gtValues[i]); if (v != null) { @@ -179,7 +187,8 @@ public class CubeTupleConverter implements ITupleConverter { tuple.setDimensionValue(ti, toString(gtValues[i])); } } else { - tuple.setDimensionValue(ti, toString(gtValues[i])); + // For batch + setDimensionValue(tuple, ti, toString(gtValues[i])); } } } @@ -209,6 +218,33 @@ public class CubeTupleConverter implements ITupleConverter { } } + private void setDimensionValue(Tuple tuple, int idx, String valueStr) { + if (valueStr == null) { + tuple.setDimensionValueDirectly(idx, valueStr); + return; + } + + Object valueConvert = null; + TblColRef col = tupleInfo.getColumn(idx); + RowKeyColDesc rowKeyColDesc = rowKeyDesc.getColDescUncheck(col); + if (rowKeyColDesc != null) { + // convert value if inconsistency exists between rowkey col encoding & col data type + if (col.getType().isDate() && !RowKeyColDesc.isDateDimEnc(rowKeyColDesc)) { + long tmpValue = (Long) Tuple.convertOptiqCellValue(valueStr, "timestamp"); + valueConvert = Tuple.millisToEpicDays(tmpValue); + } else if (col.getType().isDatetime() && !RowKeyColDesc.isTimeDimEnc(rowKeyColDesc)) { + int tmpValue = (Integer) Tuple.convertOptiqCellValue(valueStr, "date"); + valueConvert = Tuple.epicDaysToMillis(tmpValue); + } + } + + if (valueConvert != null) { + tuple.setDimensionValueDirectly(idx, valueConvert); + } else { + tuple.setDimensionValue(idx, valueStr); + } + } + @Override public void close() throws IOException { for (ILookupTable usedLookupTable : usedLookupTables) { @@ -262,6 +298,10 @@ public class CubeTupleConverter implements ITupleConverter { public void fillDerivedColumns(Object[] gtValues, Tuple tuple) { for (int i = 0; i < hostTmpIdx.length; i++) { lookupKey.data[i] = CubeTupleConverter.toString(gtValues[hostTmpIdx[i]]); + // if the primary key of lookup table is date time type, do this change in case of data type inconsistency + if (deriveInfo.join.getPrimaryKeyColumns()[i].getType().isDateTimeFamily()) { + lookupKey.data[i] = String.valueOf(DateFormat.stringToMillis(lookupKey.data[i])); + } } String[] lookupRow = lookupTable.getRow(lookupKey); diff --git a/kylin-it/src/test/resources/query/sql_casewhen/query58.sql b/kylin-it/src/test/resources/query/sql_casewhen/query58.sql new file mode 100644 index 0000000..c65c911 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_casewhen/query58.sql @@ -0,0 +1,22 @@ +-- +-- 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. +-- + +SELECT (CASE WHEN ("TEST_KYLIN_FACT"."LSTG_FORMAT_NAME" = 'Auction') THEN 'Auction2' ELSE 'Auction1' END) AS "LSTG_FORMAT_NAME__group_", + SUM("TEST_KYLIN_FACT"."PRICE") AS "sum_PRICE_ok" +FROM "TEST_KYLIN_FACT" "TEST_KYLIN_FACT" +GROUP BY (CASE WHEN ("TEST_KYLIN_FACT"."LSTG_FORMAT_NAME" = 'Auction') THEN 'Auction2' ELSE 'Auction1' END) \ No newline at end of file diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/TableSchemaUpdateChecker.java b/server-base/src/main/java/org/apache/kylin/rest/service/TableSchemaUpdateChecker.java index 84cc19b..c0acff4 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/TableSchemaUpdateChecker.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/TableSchemaUpdateChecker.java @@ -128,6 +128,10 @@ public class TableSchemaUpdateChecker { } else if (column.getType().isNumberFamily()) { // Both are float/double should be fine. return newCol.getType().isNumberFamily(); + } else if ((column.getType().isStringFamily() && newCol.getType().isDateTimeFamily()) + && metadataManager.getConfig().isAbleChangeStringToDateTime()) { + // String can be converted to Date or Time + return true; } else { // only compare base type name, changing precision or scale should be fine return column.getTypeName().equals(newCol.getTypeName()); diff --git a/server-base/src/test/java/org/apache/kylin/rest/service/update/TableSchemaUpdaterTest.java b/server-base/src/test/java/org/apache/kylin/rest/service/update/TableSchemaUpdaterTest.java index 7b8eecb..288877c 100644 --- a/server-base/src/test/java/org/apache/kylin/rest/service/update/TableSchemaUpdaterTest.java +++ b/server-base/src/test/java/org/apache/kylin/rest/service/update/TableSchemaUpdaterTest.java @@ -24,7 +24,6 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files;