This is an automated email from the ASF dual-hosted git repository.
chengzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 85685817795 Fix wrong merge sharding condition logic caused by
different type sharding value (#37528)
85685817795 is described below
commit 85685817795d51de06ea771e8befec4977d9dcb6
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Fri Dec 26 11:51:08 2025 +0800
Fix wrong merge sharding condition logic caused by different type sharding
value (#37528)
---
RELEASE-NOTES.md | 1 +
.../engine/WhereClauseShardingConditionEngine.java | 13 +-
.../util/ShardingValueTypeConvertUtils.java | 478 +++++++++++
.../util/ShardingValueTypeConvertUtilsTest.java | 885 +++++++++++++++++++++
.../dml/expression/type/ColumnSegmentBinder.java | 7 +-
.../segment/expression/ExpressionConverter.java | 5 +
.../impl/IntervalUnitExpressionConverter.java | 64 ++
.../impl/LiteralExpressionConverter.java | 51 +-
.../impl/ParameterMarkerExpressionConverter.java | 16 +-
.../impl/LiteralExpressionConverterTest.java | 30 +-
.../ParameterMarkerExpressionConverterTest.java | 7 +-
.../src/main/antlr4/imports/mysql/BaseRule.g4 | 2 +-
.../visitor/statement/MySQLStatementVisitor.java | 14 +-
.../dml/interval/IntervalUnitExpression.java | 34 +-
.../src/test/resources/converted-sql/insert.xml | 4 +-
.../src/test/resources/converted-sql/select.xml | 4 +-
.../segment/expression/ExpressionAssert.java | 13 +
.../jaxb/segment/impl/expr/ExpectedExpression.java | 3 +
.../impl/expr/ExpectedIntervalUnitExpression.java | 26 +-
.../resources/case/dml/select-special-function.xml | 8 +-
.../parser/src/main/resources/case/dml/select.xml | 4 +-
.../sql/supported/dml/select-special-function.xml | 2 +-
22 files changed, 1567 insertions(+), 104 deletions(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 9da11c887cc..9543c38c63c 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -110,6 +110,7 @@
1. Sharding: Fix mod sharding algorithm judgement
-[#36386](https://github.com/apache/shardingsphere/pull/36386)
1. Sharding: Fix check inline sharding algorithms in table rules -
[#36999](https://github.com/apache/shardingsphere/pull/36999)
1. Sharding: Fix wrong sharding condition merge when sharding column in
case-sensitive - [#37389](https://github.com/apache/shardingsphere/pull/37389)
+1. Sharding: Fix wrong merge sharding condition logic caused by different type
sharding value - [#37528](https://github.com/apache/shardingsphere/pull/37528)
1. Pipeline: Recover value of migration incremental importer batch size -
[#34670](https://github.com/apache/shardingsphere/pull/34670)
1. Pipeline: Fix InventoryDumper first time dump SQL without ORDER BY on
multiple columns unique key table -
[#34736](https://github.com/apache/shardingsphere/pull/34736)
1. Pipeline: Fix MySQL JDBC query properties extension when SSL is required on
server - [#36581](https://github.com/apache/shardingsphere/pull/36581)
diff --git
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java
index 0196ee612c2..04a4203ff8c 100644
---
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java
+++
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java
@@ -38,6 +38,7 @@ import
org.apache.shardingsphere.sharding.route.engine.condition.value.ListShard
import
org.apache.shardingsphere.sharding.route.engine.condition.value.RangeShardingConditionValue;
import
org.apache.shardingsphere.sharding.route.engine.condition.value.ShardingConditionValue;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.util.ShardingValueTypeConvertUtils;
import
org.apache.shardingsphere.sql.parser.statement.core.extractor.ColumnExtractor;
import
org.apache.shardingsphere.sql.parser.statement.core.extractor.ExpressionExtractor;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
@@ -180,16 +181,24 @@ public final class WhereClauseShardingConditionEngine {
if (null == value2) {
return value1;
}
+ Collection<Comparable<?>> convertedValue2 = value2;
+ if (!value1.isEmpty() && !value2.isEmpty() && isDifferentType(value1,
value2)) {
+ convertedValue2 =
ShardingValueTypeConvertUtils.convertCollectionType(value2,
value1.iterator().next().getClass());
+ }
if (column.isCaseSensitive()) {
- value1.retainAll(value2);
+ value1.retainAll(convertedValue2);
return value1;
}
Collection<Comparable<?>> caseInSensitiveValue1 = new
CaseInsensitiveSet<>(value1);
- Collection<Comparable<?>> caseInSensitiveValue2 = new
CaseInsensitiveSet<>(value2);
+ Collection<Comparable<?>> caseInSensitiveValue2 = new
CaseInsensitiveSet<>(convertedValue2);
caseInSensitiveValue1.retainAll(caseInSensitiveValue2);
return caseInSensitiveValue1;
}
+ private boolean isDifferentType(final Collection<Comparable<?>> value1,
final Collection<Comparable<?>> value2) {
+ return value1.iterator().next().getClass() !=
value2.iterator().next().getClass();
+ }
+
private Range<Comparable<?>> mergeRangeShardingValues(final
Range<Comparable<?>> value1, final Range<Comparable<?>> value2) {
return null == value2 ? value1 :
SafeNumberOperationUtils.safeIntersection(value1, value2);
}
diff --git
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtils.java
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtils.java
new file mode 100644
index 00000000000..f4df58f7a2c
--- /dev/null
+++
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtils.java
@@ -0,0 +1,478 @@
+/*
+ * 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.shardingsphere.sharding.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+
+/**
+ * Data type convert utility for sharding value.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ShardingValueTypeConvertUtils {
+
+ /**
+ * Convert collection to target type.
+ *
+ * @param sourceCollection source collection
+ * @param targetType target type
+ * @return converted collection
+ */
+ public static Collection<Comparable<?>> convertCollectionType(final
Collection<Comparable<?>> sourceCollection, final Class<?> targetType) {
+ Collection<Comparable<?>> result = new LinkedList<>();
+ for (Comparable<?> value : sourceCollection) {
+ result.add(convertToTargetType(value, targetType));
+ }
+ return result;
+ }
+
+ /**
+ * Convert value to target type.
+ *
+ * @param <T> type of exception
+ * @param value source value
+ * @param targetType target type class
+ * @return converted value
+ * @throws ClassCastException if conversion is not supported
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T convertToTargetType(final Comparable<?> value, final
Class<?> targetType) {
+ if (null == value) {
+ return null;
+ }
+ if (targetType.isInstance(value)) {
+ return (T) value;
+ }
+ if (Integer.class == targetType) {
+ return (T) convertToInteger(value);
+ } else if (Long.class == targetType) {
+ return (T) convertToLong(value);
+ } else if (Short.class == targetType) {
+ return (T) convertToShort(value);
+ } else if (Byte.class == targetType) {
+ return (T) convertToByte(value);
+ } else if (Double.class == targetType) {
+ return (T) convertToDouble(value);
+ } else if (Float.class == targetType) {
+ return (T) convertToFloat(value);
+ } else if (BigDecimal.class == targetType) {
+ return (T) convertToBigDecimal(value);
+ } else if (BigInteger.class == targetType) {
+ return (T) convertToBigInteger(value);
+ } else if (Boolean.class == targetType) {
+ return (T) convertToBoolean(value);
+ } else if (Character.class == targetType) {
+ return (T) convertToCharacter(value);
+ } else if (String.class == targetType) {
+ return (T) value.toString();
+ } else if (Date.class == targetType) {
+ return (T) convertToDate(value);
+ } else if (java.sql.Date.class == targetType) {
+ return (T) convertToSqlDate(value);
+ } else if (java.sql.Time.class == targetType) {
+ return (T) convertToSqlTime(value);
+ } else if (java.sql.Timestamp.class == targetType) {
+ return (T) convertToTimestamp(value);
+ } else if (LocalDate.class == targetType) {
+ return (T) convertToLocalDate(value);
+ } else if (LocalTime.class == targetType) {
+ return (T) convertToLocalTime(value);
+ } else if (LocalDateTime.class == targetType) {
+ return (T) convertToLocalDateTime(value);
+ } else if (Instant.class == targetType) {
+ return (T) convertToInstant(value);
+ } else if (Year.class == targetType) {
+ return (T) convertToYear(value);
+ } else if (YearMonth.class == targetType) {
+ return (T) convertToYearMonth(value);
+ } else if (MonthDay.class == targetType) {
+ return (T) convertToMonthDay(value);
+ } else if (Duration.class == targetType) {
+ return (T) convertToDuration(value);
+ }
+ throw new ClassCastException("Unsupported type conversion from " +
value.getClass().getName() + " to " + targetType.getName());
+ }
+
+ private static Integer convertToInteger(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).intValue();
+ }
+ return Integer.parseInt(value.toString());
+ }
+
+ private static Long convertToLong(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).longValue();
+ }
+ return Long.parseLong(value.toString());
+ }
+
+ private static Short convertToShort(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).shortValue();
+ }
+ return Short.parseShort(value.toString());
+ }
+
+ private static Byte convertToByte(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).byteValue();
+ }
+ return Byte.parseByte(value.toString());
+ }
+
+ private static Double convertToDouble(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).doubleValue();
+ }
+ return Double.parseDouble(value.toString());
+ }
+
+ private static Float convertToFloat(final Comparable<?> value) {
+ if (value instanceof Number) {
+ return ((Number) value).floatValue();
+ }
+ return Float.parseFloat(value.toString());
+ }
+
+ private static BigDecimal convertToBigDecimal(final Comparable<?> value) {
+ if (value instanceof BigDecimal) {
+ return (BigDecimal) value;
+ }
+ if (value instanceof BigInteger) {
+ return new BigDecimal((BigInteger) value);
+ }
+ if (value instanceof Number) {
+ return BigDecimal.valueOf(((Number) value).doubleValue());
+ }
+ return new BigDecimal(value.toString());
+ }
+
+ private static BigInteger convertToBigInteger(final Comparable<?> value) {
+ if (value instanceof BigInteger) {
+ return (BigInteger) value;
+ }
+ if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).toBigInteger();
+ }
+ if (value instanceof Number) {
+ return BigInteger.valueOf(((Number) value).longValue());
+ }
+ return new BigInteger(value.toString());
+ }
+
+ private static Boolean convertToBoolean(final Comparable<?> value) {
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+ if (value instanceof Number) {
+ return ((Number) value).intValue() != 0;
+ }
+ String strValue = value.toString().trim();
+ if ("true".equalsIgnoreCase(strValue) || "1".equals(strValue)) {
+ return Boolean.TRUE;
+ }
+ if ("false".equalsIgnoreCase(strValue) || "0".equals(strValue)) {
+ return Boolean.FALSE;
+ }
+ return Boolean.parseBoolean(strValue);
+ }
+
+ private static Character convertToCharacter(final Comparable<?> value) {
+ if (value instanceof Character) {
+ return (Character) value;
+ }
+ if (value instanceof Number) {
+ return (char) ((Number) value).intValue();
+ }
+ String strValue = value.toString();
+ return strValue.isEmpty() ? '\0' : strValue.charAt(0);
+ }
+
+ private static Date convertToDate(final Comparable<?> value) {
+ if (value instanceof Date) {
+ return (Date) value;
+ }
+ if (value instanceof LocalDateTime) {
+ return Date.from(((LocalDateTime)
value).atZone(ZoneId.systemDefault()).toInstant());
+ }
+ if (value instanceof LocalDate) {
+ return Date.from(((LocalDate)
value).atStartOfDay(ZoneId.systemDefault()).toInstant());
+ }
+ if (value instanceof Instant) {
+ return Date.from((Instant) value);
+ }
+ if (value instanceof Number) {
+ return new Date(((Number) value).longValue());
+ }
+ return Date.from(parseInstant(value.toString()));
+ }
+
+ private static java.sql.Date convertToSqlDate(final Comparable<?> value) {
+ if (value instanceof java.sql.Date) {
+ return (java.sql.Date) value;
+ }
+ if (value instanceof Date) {
+ return new java.sql.Date(((Date) value).getTime());
+ }
+ if (value instanceof LocalDate) {
+ return java.sql.Date.valueOf((LocalDate) value);
+ }
+ if (value instanceof LocalDateTime) {
+ return java.sql.Date.valueOf(((LocalDateTime)
value).toLocalDate());
+ }
+ if (value instanceof Number) {
+ return new java.sql.Date(((Number) value).longValue());
+ }
+ return new
java.sql.Date(parseInstant(value.toString()).toEpochMilli());
+ }
+
+ private static java.sql.Time convertToSqlTime(final Comparable<?> value) {
+ if (value instanceof java.sql.Time) {
+ return (java.sql.Time) value;
+ }
+ if (value instanceof Date) {
+ return new java.sql.Time(((Date) value).getTime());
+ }
+ if (value instanceof LocalTime) {
+ return java.sql.Time.valueOf((LocalTime) value);
+ }
+ if (value instanceof LocalDateTime) {
+ return java.sql.Time.valueOf(((LocalDateTime)
value).toLocalTime());
+ }
+ if (value instanceof Number) {
+ return new java.sql.Time(((Number) value).longValue());
+ }
+ return java.sql.Time.valueOf(parseLocalTime(value.toString()));
+ }
+
+ private static java.sql.Timestamp convertToTimestamp(final Comparable<?>
value) {
+ if (value instanceof java.sql.Timestamp) {
+ return (java.sql.Timestamp) value;
+ }
+ if (value instanceof Date) {
+ return new java.sql.Timestamp(((Date) value).getTime());
+ }
+ if (value instanceof LocalDateTime) {
+ return java.sql.Timestamp.valueOf((LocalDateTime) value);
+ }
+ if (value instanceof Instant) {
+ return java.sql.Timestamp.from((Instant) value);
+ }
+ if (value instanceof Number) {
+ return new java.sql.Timestamp(((Number) value).longValue());
+ }
+ return java.sql.Timestamp.from(parseInstant(value.toString()));
+ }
+
+ private static LocalDate convertToLocalDate(final Comparable<?> value) {
+ if (value instanceof LocalDate) {
+ return (LocalDate) value;
+ }
+ if (value instanceof LocalDateTime) {
+ return ((LocalDateTime) value).toLocalDate();
+ }
+ if (value instanceof java.sql.Date) {
+ return ((java.sql.Date) value).toLocalDate();
+ }
+ if (value instanceof Date) {
+ return ((Date)
value).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+ if (value instanceof Instant) {
+ return ((Instant)
value).atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+ if (value instanceof Number) {
+ return Instant.ofEpochMilli(((Number)
value).longValue()).atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+ return parseLocalDate(value.toString());
+ }
+
+ private static LocalTime convertToLocalTime(final Comparable<?> value) {
+ if (value instanceof LocalTime) {
+ return (LocalTime) value;
+ }
+ if (value instanceof LocalDateTime) {
+ return ((LocalDateTime) value).toLocalTime();
+ }
+ if (value instanceof java.sql.Time) {
+ return ((java.sql.Time) value).toLocalTime();
+ }
+ if (value instanceof Date) {
+ return ((Date)
value).toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
+ }
+ if (value instanceof Number) {
+ return Instant.ofEpochMilli(((Number)
value).longValue()).atZone(ZoneId.systemDefault()).toLocalTime();
+ }
+ return LocalTime.parse(value.toString());
+ }
+
+ private static LocalDateTime convertToLocalDateTime(final Comparable<?>
value) {
+ if (value instanceof LocalDateTime) {
+ return (LocalDateTime) value;
+ }
+ if (value instanceof LocalDate) {
+ return ((LocalDate) value).atStartOfDay();
+ }
+ if (value instanceof Date) {
+ return ((Date)
value).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+ }
+ if (value instanceof java.sql.Timestamp) {
+ return ((java.sql.Timestamp) value).toLocalDateTime();
+ }
+ if (value instanceof Instant) {
+ return LocalDateTime.ofInstant((Instant) value,
ZoneId.systemDefault());
+ }
+ if (value instanceof Number) {
+ return Instant.ofEpochMilli(((Number)
value).longValue()).atZone(ZoneId.systemDefault()).toLocalDateTime();
+ }
+ return parseLocalDateTime(value.toString());
+ }
+
+ private static Instant convertToInstant(final Comparable<?> value) {
+ if (value instanceof Instant) {
+ return (Instant) value;
+ }
+ if (value instanceof Date) {
+ return ((Date) value).toInstant();
+ }
+ if (value instanceof LocalDateTime) {
+ return ((LocalDateTime)
value).atZone(ZoneId.systemDefault()).toInstant();
+ }
+ if (value instanceof Number) {
+ return Instant.ofEpochMilli(((Number) value).longValue());
+ }
+ return parseInstant(value.toString());
+ }
+
+ private static Year convertToYear(final Comparable<?> value) {
+ if (value instanceof Year) {
+ return (Year) value;
+ }
+ if (value instanceof Number) {
+ return Year.of(((Number) value).intValue());
+ }
+ if (value instanceof LocalDate) {
+ return Year.of(((LocalDate) value).getYear());
+ }
+ if (value instanceof LocalDateTime) {
+ return Year.of(((LocalDateTime) value).getYear());
+ }
+ return Year.parse(value.toString());
+ }
+
+ private static YearMonth convertToYearMonth(final Comparable<?> value) {
+ if (value instanceof YearMonth) {
+ return (YearMonth) value;
+ }
+ if (value instanceof LocalDate) {
+ return YearMonth.of(((LocalDate) value).getYear(), ((LocalDate)
value).getMonth());
+ }
+ if (value instanceof LocalDateTime) {
+ return YearMonth.of(((LocalDateTime) value).getYear(),
((LocalDateTime) value).getMonth());
+ }
+ return YearMonth.parse(value.toString());
+ }
+
+ private static MonthDay convertToMonthDay(final Comparable<?> value) {
+ if (value instanceof MonthDay) {
+ return (MonthDay) value;
+ }
+ if (value instanceof LocalDate) {
+ return MonthDay.of(((LocalDate) value).getMonth(), ((LocalDate)
value).getDayOfMonth());
+ }
+ if (value instanceof LocalDateTime) {
+ return MonthDay.of(((LocalDateTime) value).getMonth(),
((LocalDateTime) value).getDayOfMonth());
+ }
+ return MonthDay.parse(value.toString());
+ }
+
+ private static Instant parseInstant(final String value) {
+ try {
+ return Instant.parse(value);
+ // CHECKSTYLE:OFF
+ } catch (final Exception ignored) {
+ // CHECKSTYLE:ON
+ return parseInstantByLocalDateTime(value);
+ }
+ }
+
+ private static Instant parseInstantByLocalDateTime(final String value) {
+ try {
+ return
LocalDateTime.parse(value).atZone(ZoneId.systemDefault()).toInstant();
+ // CHECKSTYLE:OFF
+ } catch (final Exception ignored) {
+ // CHECKSTYLE:ON
+ return
LocalDate.parse(value).atStartOfDay(ZoneId.systemDefault()).toInstant();
+ }
+ }
+
+ private static LocalDate parseLocalDate(final String value) {
+ try {
+ return LocalDate.parse(value);
+ // CHECKSTYLE:OFF
+ } catch (final Exception ignored) {
+ // CHECKSTYLE:ON
+ return LocalDateTime.parse(value).toLocalDate();
+ }
+ }
+
+ private static LocalDateTime parseLocalDateTime(final String value) {
+ try {
+ return LocalDateTime.parse(value);
+ // CHECKSTYLE:OFF
+ } catch (final Exception ignored) {
+ // CHECKSTYLE:ON
+ return
Instant.parse(value).atZone(ZoneId.systemDefault()).toLocalDateTime();
+ }
+ }
+
+ private static LocalTime parseLocalTime(final String value) {
+ try {
+ return LocalTime.parse(value);
+ // CHECKSTYLE:OFF
+ } catch (final Exception ignored) {
+ // CHECKSTYLE:ON
+ return LocalDateTime.parse(value).toLocalTime();
+ }
+ }
+
+ private static Duration convertToDuration(final Comparable<?> value) {
+ if (value instanceof Duration) {
+ return (Duration) value;
+ }
+ if (value instanceof Number) {
+ return Duration.ofMillis(((Number) value).longValue());
+ }
+ return Duration.parse(value.toString());
+ }
+}
diff --git
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtilsTest.java
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtilsTest.java
new file mode 100644
index 00000000000..7033daebbb9
--- /dev/null
+++
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/util/ShardingValueTypeConvertUtilsTest.java
@@ -0,0 +1,885 @@
+/*
+ * 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.shardingsphere.sharding.util;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+class ShardingValueTypeConvertUtilsTest {
+
+ @Test
+ void assertConvertToTargetTypeWhenValueIsNull() {
+ assertThat(ShardingValueTypeConvertUtils.convertToTargetType(null,
Integer.class), is(equalTo(null)));
+ }
+
+ @Test
+ void assertConvertToTargetTypeWhenTypesMatch() {
+ Integer value = 100;
+ assertThat(ShardingValueTypeConvertUtils.convertToTargetType(value,
Integer.class), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToIntegerFromLong() {
+ Long value = 123L;
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(123)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromShort() {
+ Short value = 45;
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(45)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromByte() {
+ Byte value = 10;
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(10)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromDouble() {
+ Double value = 123.45;
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(123)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromFloat() {
+ Float value = 67.89f;
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(67)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromBigDecimal() {
+ BigDecimal value = new BigDecimal("999");
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(999)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromBigInteger() {
+ BigInteger value = BigInteger.valueOf(777);
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(777)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToIntegerFromString() {
+ String value = "555";
+ Integer result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Integer.class);
+ assertThat(result, is(equalTo(555)));
+ assertThat(result, instanceOf(Integer.class));
+ }
+
+ @Test
+ void assertConvertToLongFromInteger() {
+ Integer value = 123456;
+ Long result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Long.class);
+ assertThat(result, is(equalTo(123456L)));
+ assertThat(result, instanceOf(Long.class));
+ }
+
+ @Test
+ void assertConvertToLongFromShort() {
+ Short value = 789;
+ Long result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Long.class);
+ assertThat(result, is(equalTo(789L)));
+ assertThat(result, instanceOf(Long.class));
+ }
+
+ @Test
+ void assertConvertToLongFromDouble() {
+ Double value = 12345.67;
+ Long result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Long.class);
+ assertThat(result, is(equalTo(12345L)));
+ assertThat(result, instanceOf(Long.class));
+ }
+
+ @Test
+ void assertConvertToLongFromBigDecimal() {
+ BigDecimal value = new BigDecimal("9876543210");
+ Long result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Long.class);
+ assertThat(result, is(equalTo(9876543210L)));
+ assertThat(result, instanceOf(Long.class));
+ }
+
+ @Test
+ void assertConvertToShortFromInteger() {
+ Integer value = 123;
+ Short result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Short.class);
+ assertThat(result, is(equalTo((short) 123)));
+ assertThat(result, instanceOf(Short.class));
+ }
+
+ @Test
+ void assertConvertToShortFromLong() {
+ Long value = 456L;
+ Short result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Short.class);
+ assertThat(result, is(equalTo((short) 456)));
+ assertThat(result, instanceOf(Short.class));
+ }
+
+ @Test
+ void assertConvertToByteFromInteger() {
+ Integer value = 100;
+ Byte result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Byte.class);
+ assertThat(result, is(equalTo((byte) 100)));
+ assertThat(result, instanceOf(Byte.class));
+ }
+
+ @Test
+ void assertConvertToByteFromShort() {
+ Short value = 50;
+ Byte result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Byte.class);
+ assertThat(result, is(equalTo((byte) 50)));
+ assertThat(result, instanceOf(Byte.class));
+ }
+
+ @Test
+ void assertConvertToDoubleFromInteger() {
+ Integer value = 123;
+ Double result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Double.class);
+ assertThat(result, is(equalTo(123.0)));
+ assertThat(result, instanceOf(Double.class));
+ }
+
+ @Test
+ void assertConvertToDoubleFromLong() {
+ Long value = 456L;
+ Double result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Double.class);
+ assertThat(result, is(equalTo(456.0)));
+ assertThat(result, instanceOf(Double.class));
+ }
+
+ @Test
+ void assertConvertToDoubleFromFloat() {
+ Float value = 78.9f;
+ Double result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Double.class);
+ assertThat(result, is(equalTo(78.9000015258789)));
+ assertThat(result, instanceOf(Double.class));
+ }
+
+ @Test
+ void assertConvertToDoubleFromBigDecimal() {
+ BigDecimal value = new BigDecimal("123.456");
+ Double result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Double.class);
+ assertThat(result, is(equalTo(123.456)));
+ assertThat(result, instanceOf(Double.class));
+ }
+
+ @Test
+ void assertConvertToFloatFromInteger() {
+ Integer value = 234;
+ Float result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Float.class);
+ assertThat(result, is(equalTo(234.0f)));
+ assertThat(result, instanceOf(Float.class));
+ }
+
+ @Test
+ void assertConvertToFloatFromDouble() {
+ Double value = 56.78;
+ Float result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Float.class);
+ assertThat(result, is(equalTo(56.78f)));
+ assertThat(result, instanceOf(Float.class));
+ }
+
+ @Test
+ void assertConvertToBigDecimalFromInteger() {
+ Integer value = 999;
+ BigDecimal result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigDecimal.class);
+ assertThat(result.compareTo(new BigDecimal("999")), is(equalTo(0)));
+ assertThat(result, instanceOf(BigDecimal.class));
+ }
+
+ @Test
+ void assertConvertToBigDecimalFromLong() {
+ Long value = 888L;
+ BigDecimal result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigDecimal.class);
+ assertThat(result.compareTo(new BigDecimal("888")), is(equalTo(0)));
+ assertThat(result, instanceOf(BigDecimal.class));
+ }
+
+ @Test
+ void assertConvertToBigDecimalFromDouble() {
+ Double value = 123.456;
+ BigDecimal result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigDecimal.class);
+ assertThat(result, is(equalTo(BigDecimal.valueOf(123.456))));
+ assertThat(result, instanceOf(BigDecimal.class));
+ }
+
+ @Test
+ void assertConvertToBigDecimalFromBigInteger() {
+ BigInteger value = BigInteger.valueOf(12345);
+ BigDecimal result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigDecimal.class);
+ assertThat(result, is(equalTo(new BigDecimal("12345"))));
+ assertThat(result, instanceOf(BigDecimal.class));
+ }
+
+ @Test
+ void assertConvertToBigDecimalFromString() {
+ String value = "999.888";
+ BigDecimal result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigDecimal.class);
+ assertThat(result, is(equalTo(new BigDecimal("999.888"))));
+ assertThat(result, instanceOf(BigDecimal.class));
+ }
+
+ @Test
+ void assertConvertToBigIntegerFromInteger() {
+ Integer value = 777;
+ BigInteger result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigInteger.class);
+ assertThat(result, is(equalTo(BigInteger.valueOf(777))));
+ assertThat(result, instanceOf(BigInteger.class));
+ }
+
+ @Test
+ void assertConvertToBigIntegerFromLong() {
+ Long value = 666L;
+ BigInteger result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigInteger.class);
+ assertThat(result, is(equalTo(BigInteger.valueOf(666))));
+ assertThat(result, instanceOf(BigInteger.class));
+ }
+
+ @Test
+ void assertConvertToBigIntegerFromBigDecimal() {
+ BigDecimal value = new BigDecimal("555");
+ BigInteger result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigInteger.class);
+ assertThat(result, is(equalTo(BigInteger.valueOf(555))));
+ assertThat(result, instanceOf(BigInteger.class));
+ }
+
+ @Test
+ void assertConvertToStringFromInteger() {
+ Integer value = 123;
+ String result =
ShardingValueTypeConvertUtils.convertToTargetType(value, String.class);
+ assertThat(result, is(equalTo("123")));
+ assertThat(result, instanceOf(String.class));
+ }
+
+ @Test
+ void assertConvertToStringFromLong() {
+ Long value = 456L;
+ String result =
ShardingValueTypeConvertUtils.convertToTargetType(value, String.class);
+ assertThat(result, is(equalTo("456")));
+ assertThat(result, instanceOf(String.class));
+ }
+
+ @Test
+ void assertConvertToStringFromDouble() {
+ Double value = 78.9;
+ String result =
ShardingValueTypeConvertUtils.convertToTargetType(value, String.class);
+ assertThat(result, is(equalTo("78.9")));
+ assertThat(result, instanceOf(String.class));
+ }
+
+ @Test
+ void assertConvertToStringFromBigDecimal() {
+ BigDecimal value = new BigDecimal("123.456");
+ String result =
ShardingValueTypeConvertUtils.convertToTargetType(value, String.class);
+ assertThat(result, is(equalTo("123.456")));
+ assertThat(result, instanceOf(String.class));
+ }
+
+ @Test
+ void assertConvertCollectionTypeToIntegers() {
+ Collection<Comparable<?>> source = Arrays.asList(1L, 2L, 3L, 4L);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Integer.class);
+ assertThat(result.size(), is(4));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Integer.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToLongs() {
+ Collection<Comparable<?>> source = Arrays.asList(100, 200, 300);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Long.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Long.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToDoubles() {
+ Collection<Comparable<?>> source = Arrays.asList(10, 20, 30);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Double.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Double.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToStrings() {
+ Collection<Comparable<?>> source = Arrays.asList(123, 456, 789);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, String.class);
+ assertThat(result.size(), is(3));
+ assertThat(new LinkedList<>(result).get(0), is(equalTo("123")));
+ assertThat(new LinkedList<>(result).get(1), is(equalTo("456")));
+ assertThat(new LinkedList<>(result).get(2), is(equalTo("789")));
+ }
+
+ @Test
+ void assertConvertCollectionTypeWithMixedNumericTypes() {
+ Collection<Comparable<?>> source = Arrays.asList(1, 2L, 3.0, 4.0f);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Integer.class);
+ assertThat(result.size(), is(4));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Integer.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeEmptyCollection() {
+ Collection<Comparable<?>> source = new HashSet<>();
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Integer.class);
+ assertThat(result.isEmpty(), is(true));
+ }
+
+ @Test
+ void assertConvertCollectionTypeToBigDecimal() {
+ Collection<Comparable<?>> source = Arrays.asList(100, 200L, 300.5);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, BigDecimal.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(BigDecimal.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToBigInteger() {
+ Collection<Comparable<?>> source = Arrays.asList(100, 200L, 300);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, BigInteger.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(BigInteger.class));
+ }
+ }
+
+ @Test
+ void assertConvertToBooleanFromInteger() {
+ Integer value = 1;
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(true)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromIntegerZero() {
+ Integer value = 0;
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(false)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromStringTrue() {
+ String value = "true";
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(true)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromStringFalse() {
+ String value = "false";
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(false)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromStringOne() {
+ String value = "1";
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(true)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromStringZero() {
+ String value = "0";
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(false)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToCharacterFromInteger() {
+ Integer value = 65;
+ Character result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Character.class);
+ assertThat(result, is(equalTo('A')));
+ assertThat(result, instanceOf(Character.class));
+ }
+
+ @Test
+ void assertConvertToCharacterFromString() {
+ String value = "X";
+ Character result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Character.class);
+ assertThat(result, is(equalTo('X')));
+ assertThat(result, instanceOf(Character.class));
+ }
+
+ @Test
+ void assertConvertToCharacterFromEmptyString() {
+ String value = "";
+ Character result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Character.class);
+ assertThat(result, is(equalTo('\0')));
+ assertThat(result, instanceOf(Character.class));
+ }
+
+ @Test
+ void assertConvertToDateFromLong() {
+ Long value = 1704067200000L;
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ assertThat(result.getTime(), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToDateFromLocalDateTime() {
+ LocalDateTime value = LocalDateTime.of(2024, 1, 1, 0, 0);
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ }
+
+ @Test
+ void assertConvertToDateFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 1, 1);
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ }
+
+ @Test
+ void assertConvertToDateFromInstant() {
+ Instant value = Instant.parse("2024-01-01T00:00:00Z");
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ assertThat(result.toInstant(), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToSqlDateFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 1, 1);
+ java.sql.Date result =
ShardingValueTypeConvertUtils.convertToTargetType(value, java.sql.Date.class);
+ assertThat(result, instanceOf(java.sql.Date.class));
+ assertThat(result.toLocalDate(), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToSqlDateFromDate() {
+ Date value = new Date();
+ java.sql.Date result =
ShardingValueTypeConvertUtils.convertToTargetType(value, java.sql.Date.class);
+ assertThat(result, instanceOf(java.sql.Date.class));
+ }
+
+ @Test
+ void assertConvertToSqlTimeFromLocalTime() {
+ LocalTime value = LocalTime.of(12, 30, 45);
+ java.sql.Time result =
ShardingValueTypeConvertUtils.convertToTargetType(value, java.sql.Time.class);
+ assertThat(result, instanceOf(java.sql.Time.class));
+ assertThat(result.toLocalTime(), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToTimestampFromLocalDateTime() {
+ LocalDateTime value = LocalDateTime.of(2024, 1, 1, 12, 30, 45);
+ java.sql.Timestamp result =
ShardingValueTypeConvertUtils.convertToTargetType(value,
java.sql.Timestamp.class);
+ assertThat(result, instanceOf(java.sql.Timestamp.class));
+ assertThat(result.toLocalDateTime(), is(equalTo(value)));
+ }
+
+ @Test
+ void assertConvertToTimestampFromInstant() {
+ Instant value = Instant.parse("2024-01-01T12:30:45Z");
+ java.sql.Timestamp result =
ShardingValueTypeConvertUtils.convertToTargetType(value,
java.sql.Timestamp.class);
+ assertThat(result, instanceOf(java.sql.Timestamp.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateFromDate() {
+ Date value = new Date();
+ LocalDate result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDate.class);
+ assertThat(result, instanceOf(LocalDate.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateFromLocalDateTime() {
+ LocalDateTime value = LocalDateTime.of(2024, 1, 1, 12, 30, 45);
+ LocalDate result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDate.class);
+ assertThat(result, is(equalTo(LocalDate.of(2024, 1, 1))));
+ assertThat(result, instanceOf(LocalDate.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateFromSqlDate() {
+ java.sql.Date value = java.sql.Date.valueOf("2024-01-01");
+ LocalDate result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDate.class);
+ assertThat(result, is(equalTo(LocalDate.of(2024, 1, 1))));
+ assertThat(result, instanceOf(LocalDate.class));
+ }
+
+ @Test
+ void assertConvertToLocalTimeFromSqlTime() {
+ java.sql.Time value = java.sql.Time.valueOf("12:30:45");
+ LocalTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalTime.class);
+ assertThat(result, is(equalTo(LocalTime.of(12, 30, 45))));
+ assertThat(result, instanceOf(LocalTime.class));
+ }
+
+ @Test
+ void assertConvertToLocalTimeFromLocalDateTime() {
+ LocalDateTime value = LocalDateTime.of(2024, 1, 1, 12, 30, 45);
+ LocalTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalTime.class);
+ assertThat(result, is(equalTo(LocalTime.of(12, 30, 45))));
+ assertThat(result, instanceOf(LocalTime.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateTimeFromDate() {
+ Date value = new Date();
+ LocalDateTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDateTime.class);
+ assertThat(result, instanceOf(LocalDateTime.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateTimeFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 1, 1);
+ LocalDateTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDateTime.class);
+ assertThat(result, is(equalTo(LocalDateTime.of(2024, 1, 1, 0, 0))));
+ assertThat(result, instanceOf(LocalDateTime.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateTimeFromTimestamp() {
+ java.sql.Timestamp value = java.sql.Timestamp.valueOf("2024-01-01
12:30:45");
+ LocalDateTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDateTime.class);
+ assertThat(result, is(equalTo(LocalDateTime.of(2024, 1, 1, 12, 30,
45))));
+ assertThat(result, instanceOf(LocalDateTime.class));
+ }
+
+ @Test
+ void assertConvertToInstantFromDate() {
+ Date value = new Date();
+ Instant result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Instant.class);
+ assertThat(result, is(equalTo(value.toInstant())));
+ assertThat(result, instanceOf(Instant.class));
+ }
+
+ @Test
+ void assertConvertToInstantFromLong() {
+ Long value = 1704067200000L;
+ Instant result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Instant.class);
+ assertThat(result, is(equalTo(Instant.ofEpochMilli(value))));
+ assertThat(result, instanceOf(Instant.class));
+ }
+
+ @Test
+ void assertConvertToYearFromInteger() {
+ Integer value = 2024;
+ Year result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Year.class);
+ assertThat(result, is(equalTo(Year.of(2024))));
+ assertThat(result, instanceOf(Year.class));
+ }
+
+ @Test
+ void assertConvertToYearFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 6, 15);
+ Year result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Year.class);
+ assertThat(result, is(equalTo(Year.of(2024))));
+ assertThat(result, instanceOf(Year.class));
+ }
+
+ @Test
+ void assertConvertToYearMonthFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 6, 15);
+ YearMonth result =
ShardingValueTypeConvertUtils.convertToTargetType(value, YearMonth.class);
+ assertThat(result, is(equalTo(YearMonth.of(2024, 6))));
+ assertThat(result, instanceOf(YearMonth.class));
+ }
+
+ @Test
+ void assertConvertToMonthDayFromLocalDate() {
+ LocalDate value = LocalDate.of(2024, 6, 15);
+ MonthDay result =
ShardingValueTypeConvertUtils.convertToTargetType(value, MonthDay.class);
+ assertThat(result, is(equalTo(MonthDay.of(6, 15))));
+ assertThat(result, instanceOf(MonthDay.class));
+ }
+
+ @Test
+ void assertConvertToDurationFromLong() {
+ Long value = 5000L;
+ Duration result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Duration.class);
+ assertThat(result, is(equalTo(Duration.ofMillis(5000L))));
+ assertThat(result, instanceOf(Duration.class));
+ }
+
+ @Test
+ void assertConvertToDurationFromString() {
+ String value = "PT60S";
+ Duration result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Duration.class);
+ assertThat(result, is(equalTo(Duration.ofSeconds(60))));
+ assertThat(result, instanceOf(Duration.class));
+ }
+
+ @Test
+ void assertConvertCollectionTypeToLocalDates() {
+ Collection<Comparable<?>> source = Arrays.asList(
+ LocalDate.of(2024, 1, 1),
+ LocalDate.of(2024, 2, 1),
+ LocalDate.of(2024, 3, 1));
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Year.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Year.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToBooleans() {
+ Collection<Comparable<?>> source = Arrays.asList(1, 0, 2, "true");
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Boolean.class);
+ assertThat(result.size(), is(4));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Boolean.class));
+ }
+ }
+
+ @Test
+ void assertConvertCollectionTypeToDurations() {
+ Collection<Comparable<?>> source = Arrays.asList(1000L, 2000L, 3000L);
+ Collection<Comparable<?>> result =
ShardingValueTypeConvertUtils.convertCollectionType(source, Duration.class);
+ assertThat(result.size(), is(3));
+ for (Comparable<?> value : result) {
+ assertThat(value, instanceOf(Duration.class));
+ }
+ }
+
+ // ========== String to Type Conversion Tests (non-duplicate) ==========
+
+ @Test
+ void assertConvertToLongFromString() {
+ String value = "123456789";
+ Long result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Long.class);
+ assertThat(result, is(equalTo(123456789L)));
+ assertThat(result, instanceOf(Long.class));
+ }
+
+ @Test
+ void assertConvertToShortFromString() {
+ String value = "123";
+ Short result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Short.class);
+ assertThat(result, is(equalTo((short) 123)));
+ assertThat(result, instanceOf(Short.class));
+ }
+
+ @Test
+ void assertConvertToByteFromString() {
+ String value = "100";
+ Byte result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Byte.class);
+ assertThat(result, is(equalTo((byte) 100)));
+ assertThat(result, instanceOf(Byte.class));
+ }
+
+ @Test
+ void assertConvertToDoubleFromString() {
+ String value = "123.456";
+ Double result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Double.class);
+ assertThat(result, is(equalTo(123.456)));
+ assertThat(result, instanceOf(Double.class));
+ }
+
+ @Test
+ void assertConvertToFloatFromString() {
+ String value = "78.9";
+ Float result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Float.class);
+ assertThat(result, is(equalTo(78.9f)));
+ assertThat(result, instanceOf(Float.class));
+ }
+
+ @Test
+ void assertConvertToBigIntegerFromString() {
+ String value = "123456789";
+ BigInteger result =
ShardingValueTypeConvertUtils.convertToTargetType(value, BigInteger.class);
+ assertThat(result, is(equalTo(BigInteger.valueOf(123456789))));
+ assertThat(result, instanceOf(BigInteger.class));
+ }
+
+ @Test
+ void assertConvertToBooleanFromStringUpperCase() {
+ String value = "TRUE";
+ Boolean result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Boolean.class);
+ assertThat(result, is(equalTo(true)));
+ assertThat(result, instanceOf(Boolean.class));
+ }
+
+ @Test
+ void assertConvertToDateFromStringLocalDate() {
+ String value = "2024-08-05";
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ }
+
+ @Test
+ void assertConvertToDateFromStringLocalDateTime() {
+ String value = "2024-08-05T12:30:45";
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ }
+
+ @Test
+ void assertConvertToDateFromStringInstant() {
+ String value = "2024-08-05T12:30:45Z";
+ Date result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Date.class);
+ assertThat(result, instanceOf(Date.class));
+ }
+
+ @Test
+ void assertConvertToSqlDateFromStringLocalDate() {
+ String value = "2024-08-05";
+ java.sql.Date result =
ShardingValueTypeConvertUtils.convertToTargetType(value, java.sql.Date.class);
+ assertThat(result, instanceOf(java.sql.Date.class));
+ assertThat(result.toLocalDate(), is(equalTo(LocalDate.of(2024, 8,
5))));
+ }
+
+ @Test
+ void assertConvertToSqlTimeFromString() {
+ String value = "12:30:45";
+ java.sql.Time result =
ShardingValueTypeConvertUtils.convertToTargetType(value, java.sql.Time.class);
+ assertThat(result, instanceOf(java.sql.Time.class));
+ assertThat(result.toLocalTime(), is(equalTo(LocalTime.of(12, 30,
45))));
+ }
+
+ @Test
+ void assertConvertToTimestampFromString() {
+ String value = "2024-08-05T12:30:45";
+ java.sql.Timestamp result =
ShardingValueTypeConvertUtils.convertToTargetType(value,
java.sql.Timestamp.class);
+ assertThat(result, instanceOf(java.sql.Timestamp.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateFromString() {
+ String value = "2024-08-05";
+ LocalDate result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDate.class);
+ assertThat(result, is(equalTo(LocalDate.of(2024, 8, 5))));
+ assertThat(result, instanceOf(LocalDate.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateFromStringDateTime() {
+ String value = "2024-08-05T12:30:45";
+ LocalDate result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDate.class);
+ assertThat(result, is(equalTo(LocalDate.of(2024, 8, 5))));
+ assertThat(result, instanceOf(LocalDate.class));
+ }
+
+ @Test
+ void assertConvertToLocalTimeFromString() {
+ String value = "12:30:45";
+ LocalTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalTime.class);
+ assertThat(result, is(equalTo(LocalTime.of(12, 30, 45))));
+ assertThat(result, instanceOf(LocalTime.class));
+ }
+
+ @Test
+ void assertConvertToLocalDateTimeFromString() {
+ String value = "2024-08-05T12:30:45";
+ LocalDateTime result =
ShardingValueTypeConvertUtils.convertToTargetType(value, LocalDateTime.class);
+ assertThat(result, is(equalTo(LocalDateTime.of(2024, 8, 5, 12, 30,
45))));
+ assertThat(result, instanceOf(LocalDateTime.class));
+ }
+
+ @Test
+ void assertConvertToInstantFromString() {
+ String value = "2024-08-05T12:30:45Z";
+ Instant result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Instant.class);
+ assertThat(result, instanceOf(Instant.class));
+ }
+
+ @Test
+ void assertConvertToInstantFromStringLocalDate() {
+ String value = "2024-08-05";
+ Instant result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Instant.class);
+ assertThat(result, instanceOf(Instant.class));
+ assertThat(result.atZone(ZoneId.systemDefault()).toLocalDate(),
is(equalTo(LocalDate.of(2024, 8, 5))));
+ }
+
+ @Test
+ void assertConvertToYearFromString() {
+ String value = "2024";
+ Year result = ShardingValueTypeConvertUtils.convertToTargetType(value,
Year.class);
+ assertThat(result, is(equalTo(Year.of(2024))));
+ assertThat(result, instanceOf(Year.class));
+ }
+
+ @Test
+ void assertConvertToYearMonthFromString() {
+ String value = "2024-08";
+ YearMonth result =
ShardingValueTypeConvertUtils.convertToTargetType(value, YearMonth.class);
+ assertThat(result, is(equalTo(YearMonth.of(2024, 8))));
+ assertThat(result, instanceOf(YearMonth.class));
+ }
+
+ @Test
+ void assertConvertToMonthDayFromString() {
+ String value = "--08-05";
+ MonthDay result =
ShardingValueTypeConvertUtils.convertToTargetType(value, MonthDay.class);
+ assertThat(result, is(equalTo(MonthDay.of(8, 5))));
+ assertThat(result, instanceOf(MonthDay.class));
+ }
+
+ @Test
+ void assertConvertToDurationFromStringSeconds() {
+ String value = "PT60S";
+ Duration result =
ShardingValueTypeConvertUtils.convertToTargetType(value, Duration.class);
+ assertThat(result, is(equalTo(Duration.ofSeconds(60))));
+ assertThat(result, instanceOf(Duration.class));
+ }
+}
diff --git
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
index 4ed7d042722..b7641548bee 100644
---
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
+++
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
@@ -284,10 +284,11 @@ public final class ColumnSegmentBinder {
List<ColumnSegmentInfo> result = new
ArrayList<>(tableBinderContexts.size());
for (TableSegmentBinderContext each : tableBinderContexts) {
Optional<ProjectionSegment> projectionSegment =
each.findProjectionSegmentByColumnLabel(columnName);
- if (projectionSegment.isPresent() && projectionSegment.get()
instanceof ColumnProjectionSegment) {
- ColumnSegment columnSegment = ((ColumnProjectionSegment)
projectionSegment.get()).getColumn();
- result.add(new ColumnSegmentInfo(columnSegment,
each.getTableSourceType()));
+ if (!projectionSegment.isPresent()) {
+ continue;
}
+ ColumnSegment columnSegment = projectionSegment.get() instanceof
ColumnProjectionSegment ? ((ColumnProjectionSegment)
projectionSegment.get()).getColumn() : null;
+ result.add(new ColumnSegmentInfo(columnSegment,
each.getTableSourceType()));
}
return result;
}
diff --git
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/ExpressionConverter.java
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/ExpressionConverter.java
index a2329f481b7..e37cd761d8c 100644
---
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/ExpressionConverter.java
+++
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/ExpressionConverter.java
@@ -43,6 +43,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.comp
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalUnitExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.DataTypeSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.match.MatchAgainstExpression;
@@ -57,6 +58,7 @@ import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segmen
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.FunctionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.InExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.IntervalExpressionConverter;
+import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.IntervalUnitExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.ListExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.LiteralExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl.MatchExpressionConverter;
@@ -159,6 +161,9 @@ public final class ExpressionConverter {
if (segment instanceof IntervalExpression) {
return
Optional.of(IntervalExpressionConverter.convert((IntervalExpression) segment));
}
+ if (segment instanceof IntervalUnitExpression) {
+ return
IntervalUnitExpressionConverter.convert((IntervalUnitExpression) segment);
+ }
if (segment instanceof QuantifySubqueryExpression) {
return
Optional.of(QuantifySubqueryExpressionConverter.convert((QuantifySubqueryExpression)
segment));
}
diff --git
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/IntervalUnitExpressionConverter.java
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/IntervalUnitExpressionConverter.java
new file mode 100644
index 00000000000..fa11ea34378
--- /dev/null
+++
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/IntervalUnitExpressionConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import com.cedarsoftware.util.CaseInsensitiveSet;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.calcite.avatica.util.TimeUnit;
+import org.apache.calcite.sql.SqlIntervalQualifier;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalUnitExpression;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Interval unit expression converter.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class IntervalUnitExpressionConverter {
+
+ private static final Collection<String> TIME_UNIT_NAMES = new
CaseInsensitiveSet<>(7, 1F);
+
+ static {
+ TIME_UNIT_NAMES.add("YEAR");
+ TIME_UNIT_NAMES.add("MONTH");
+ TIME_UNIT_NAMES.add("WEEK");
+ TIME_UNIT_NAMES.add("DAY");
+ TIME_UNIT_NAMES.add("HOUR");
+ TIME_UNIT_NAMES.add("MINUTE");
+ TIME_UNIT_NAMES.add("SECOND");
+ }
+
+ /**
+ * Convert interval unit expression to SQL node.
+ *
+ * @param segment interval unit expression
+ * @return SQL node
+ */
+ public static Optional<SqlNode> convert(final IntervalUnitExpression
segment) {
+ String intervalUnit = segment.getIntervalUnit().name();
+ if (TIME_UNIT_NAMES.contains(intervalUnit)) {
+ return Optional.of(new
SqlIntervalQualifier(TimeUnit.valueOf(intervalUnit), null, SqlParserPos.ZERO));
+ }
+ return Optional.of(SqlLiteral.createCharString(intervalUnit,
SqlParserPos.ZERO));
+ }
+}
diff --git
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverter.java
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverter.java
index 478cb99bf66..4e8160365b8 100644
---
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverter.java
+++
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverter.java
@@ -17,14 +17,10 @@
package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
-import com.cedarsoftware.util.CaseInsensitiveSet;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
-import org.apache.calcite.avatica.util.TimeUnit;
-import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.fun.SqlTrimFunction.Flag;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.DateString;
@@ -32,10 +28,9 @@ import org.apache.calcite.util.NlsString;
import org.apache.calcite.util.TimeString;
import org.apache.calcite.util.TimestampString;
import org.apache.calcite.util.TimestampWithTimeZoneString;
+import org.apache.shardingsphere.infra.util.datetime.DateTimeFormatterFactory;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
@@ -43,7 +38,6 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
-import java.util.Collection;
import java.util.Date;
import java.util.Optional;
@@ -53,23 +47,6 @@ import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class LiteralExpressionConverter {
- private static final Collection<String> TRIM_FUNCTION_FLAGS = new
CaseInsensitiveSet<>(3, 1F);
-
- private static final Collection<String> TIME_UNIT_NAMES = new
CaseInsensitiveSet<>(7, 1F);
-
- static {
- TRIM_FUNCTION_FLAGS.add("BOTH");
- TRIM_FUNCTION_FLAGS.add("LEADING");
- TRIM_FUNCTION_FLAGS.add("TRAILING");
- TIME_UNIT_NAMES.add("YEAR");
- TIME_UNIT_NAMES.add("MONTH");
- TIME_UNIT_NAMES.add("WEEK");
- TIME_UNIT_NAMES.add("DAY");
- TIME_UNIT_NAMES.add("HOUR");
- TIME_UNIT_NAMES.add("MINUTE");
- TIME_UNIT_NAMES.add("SECOND");
- }
-
/**
* Convert literal expression segment to SQL node.
*
@@ -81,12 +58,6 @@ public final class LiteralExpressionConverter {
return Optional.of(SqlLiteral.createNull(SqlParserPos.ZERO));
}
String literalValue = String.valueOf(segment.getLiterals());
- if (TRIM_FUNCTION_FLAGS.contains(literalValue)) {
- return
Optional.of(SqlLiteral.createSymbol(Flag.valueOf(literalValue.toUpperCase()),
SqlParserPos.ZERO));
- }
- if (TIME_UNIT_NAMES.contains(literalValue)) {
- return Optional.of(new
SqlIntervalQualifier(TimeUnit.valueOf(literalValue.toUpperCase()), null,
SqlParserPos.ZERO));
- }
if (segment.getLiterals() instanceof Number) {
return Optional.of(convertNumber(segment, literalValue));
}
@@ -112,10 +83,12 @@ public final class LiteralExpressionConverter {
return
Optional.of(SqlLiteral.createDate(DateString.fromDaysSinceEpoch((int)
((LocalDate) segment.getLiterals()).toEpochDay()), SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof LocalTime) {
- return Optional.of(SqlLiteral.createTime(new
TimeString(literalValue), 1, SqlParserPos.ZERO));
+ String formatedValue =
DateTimeFormatterFactory.getFullTimeFormatter().format((LocalTime)
segment.getLiterals());
+ return Optional.of(SqlLiteral.createTime(new
TimeString(formatedValue), 1, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof LocalDateTime) {
- return
Optional.of(SqlLiteral.createTimestamp(SqlTypeName.TIMESTAMP, new
TimestampString(literalValue), 1, SqlParserPos.ZERO));
+ String formatedValue = ((LocalDateTime)
segment.getLiterals()).format(DateTimeFormatterFactory.getDatetimeFormatter());
+ return
Optional.of(SqlLiteral.createTimestamp(SqlTypeName.TIMESTAMP, new
TimestampString(formatedValue), 1, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof ZonedDateTime) {
return Optional.of(SqlLiteral.createTimestamp(new
TimestampWithTimeZoneString(literalValue), 1, SqlParserPos.ZERO));
@@ -130,16 +103,18 @@ public final class LiteralExpressionConverter {
}
private static SqlNode convertNumber(final LiteralExpressionSegment
segment, final String literalValue) {
- return segment.getLiterals() instanceof BigDecimal ||
segment.getLiterals() instanceof BigInteger
- ? SqlLiteral.createApproxNumeric(literalValue,
SqlParserPos.ZERO)
- : SqlLiteral.createExactNumeric(literalValue,
SqlParserPos.ZERO);
+ if (segment.getLiterals() instanceof Float || segment.getLiterals()
instanceof Double) {
+ return SqlLiteral.createApproxNumeric(literalValue,
SqlParserPos.ZERO);
+ }
+ return SqlLiteral.createExactNumeric(literalValue, SqlParserPos.ZERO);
}
private static SqlNode convertCalendar(final LiteralExpressionSegment
segment) {
Calendar calendar = (Calendar) segment.getLiterals();
- return hasTimePart(calendar)
- ? SqlLiteral.createTimestamp(SqlTypeName.TIMESTAMP,
TimestampString.fromCalendarFields(calendar), 1, SqlParserPos.ZERO)
- :
SqlLiteral.createDate(DateString.fromCalendarFields(calendar),
SqlParserPos.ZERO);
+ if (hasTimePart(calendar)) {
+ return SqlLiteral.createTimestamp(SqlTypeName.TIMESTAMP,
TimestampString.fromCalendarFields(calendar), 1, SqlParserPos.ZERO);
+ }
+ return SqlLiteral.createDate(DateString.fromCalendarFields(calendar),
SqlParserPos.ZERO);
}
private static boolean hasTimePart(final Calendar calendar) {
diff --git
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverter.java
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverter.java
index 0f2f8d67860..71360fc6cfd 100644
---
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverter.java
+++
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverter.java
@@ -19,10 +19,17 @@ package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segme
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.apache.calcite.sql.SqlBasicCall;
import org.apache.calcite.sql.SqlDynamicParam;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
+import java.util.Arrays;
+import java.util.Collections;
+
/**
* Parameter marker expression converter.
*/
@@ -35,7 +42,12 @@ public final class ParameterMarkerExpressionConverter {
* @param segment parameter marker expression segment
* @return SQL node
*/
- public static SqlDynamicParam convert(final
ParameterMarkerExpressionSegment segment) {
- return new SqlDynamicParam(segment.getParameterMarkerIndex(),
SqlParserPos.ZERO);
+ public static SqlNode convert(final ParameterMarkerExpressionSegment
segment) {
+ SqlDynamicParam result = new
SqlDynamicParam(segment.getParameterMarkerIndex(), SqlParserPos.ZERO);
+ if (segment.getAliasName().isPresent()) {
+ SqlIdentifier sqlIdentifier = new
SqlIdentifier(Collections.singletonList(segment.getAliasName().get()),
SqlParserPos.ZERO);
+ return new SqlBasicCall(SqlStdOperatorTable.AS,
Arrays.asList(result, sqlIdentifier), SqlParserPos.ZERO);
+ }
+ return result;
}
}
diff --git
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverterTest.java
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverterTest.java
index 2020e454556..83007cf6180 100644
---
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverterTest.java
+++
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/LiteralExpressionConverterTest.java
@@ -17,17 +17,14 @@
package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
-import org.apache.calcite.sql.SqlIntervalQualifier;
+import org.apache.calcite.runtime.CalciteException;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNumericLiteral;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.TimeString;
-import org.apache.calcite.runtime.CalciteException;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
import org.junit.jupiter.api.Test;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
@@ -42,8 +39,8 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
class LiteralExpressionConverterTest {
@@ -62,25 +59,25 @@ class LiteralExpressionConverterTest {
void assertConvertTrimFlags() {
SqlLiteral actual = (SqlLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
"both")).orElse(null);
assertNotNull(actual);
- assertThat(actual.getValueAs(Enum.class).toString(), is("BOTH"));
+ assertThat(actual.getValueAs(String.class), is("both"));
SqlLiteral leading = (SqlLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
"LEADING")).orElse(null);
assertNotNull(leading);
- assertThat(leading.getValueAs(Enum.class).toString(), is("LEADING"));
+ assertThat(leading.getValueAs(String.class), is("LEADING"));
SqlLiteral trailing = (SqlLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
"trailing")).orElse(null);
assertNotNull(trailing);
- assertThat(trailing.getValueAs(Enum.class).toString(), is("TRAILING"));
+ assertThat(trailing.getValueAs(String.class), is("trailing"));
}
@Test
void assertConvertTimeUnitName() {
- SqlIntervalQualifier actual = (SqlIntervalQualifier)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
"year")).orElse(null);
+ SqlLiteral actual = (SqlLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
"year")).orElse(null);
assertNotNull(actual);
- assertThat(actual.getStartUnit().name(), is("YEAR"));
+ assertThat(actual.getValueAs(String.class), is("year"));
}
@Test
void assertConvertApproximateNumber() {
- SqlNumericLiteral actual = (SqlNumericLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0, new
BigDecimal("1.5"))).orElse(null);
+ SqlNumericLiteral actual = (SqlNumericLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0, new
Float("1.5"))).orElse(null);
assertNotNull(actual);
assertFalse(actual.isExact());
}
@@ -166,7 +163,9 @@ class LiteralExpressionConverterTest {
@Test
void assertConvertLocalDateTime() {
- assertThrows(IllegalArgumentException.class, () ->
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
LocalDateTime.of(2020, 1, 1, 1, 1, 1))));
+ SqlLiteral actual = (SqlLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0,
LocalDateTime.of(2020, 1, 1, 1, 1, 1))).orElse(null);
+ assertNotNull(actual);
+ assertThat(actual.getTypeName(), is(SqlTypeName.TIMESTAMP));
}
@Test
@@ -194,11 +193,4 @@ class LiteralExpressionConverterTest {
Optional<?> actual = LiteralExpressionConverter.convert(new
LiteralExpressionSegment(0, 0, new Object()));
assertFalse(actual.isPresent());
}
-
- @Test
- void assertConvertBigIntegerUsesApproximateNumeric() {
- SqlNumericLiteral actual = (SqlNumericLiteral)
LiteralExpressionConverter.convert(new LiteralExpressionSegment(0, 0, new
BigInteger("12345678901234567890"))).orElse(null);
- assertNotNull(actual);
- assertFalse(actual.isExact());
- }
}
diff --git
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
index c1885ba40c3..e40e2c3ad80 100644
---
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
+++
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
@@ -18,7 +18,9 @@
package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
import org.apache.calcite.sql.SqlDynamicParam;
+import org.apache.calcite.sql.SqlNode;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
@@ -28,7 +30,8 @@ class ParameterMarkerExpressionConverterTest {
@Test
void assertConvertParameterMarker() {
- SqlDynamicParam actual =
ParameterMarkerExpressionConverter.convert(new
ParameterMarkerExpressionSegment(0, 0, 5));
- assertThat(actual.getIndex(), is(5));
+ SqlNode actual = ParameterMarkerExpressionConverter.convert(new
ParameterMarkerExpressionSegment(0, 0, 5));
+ Assertions.assertInstanceOf(SqlDynamicParam.class, actual);
+ assertThat(((SqlDynamicParam) actual).getIndex(), is(5));
}
}
diff --git
a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
index 920c50a3dce..fb814cec894 100644
--- a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
+++ b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
@@ -672,7 +672,7 @@ castType
| castTypeName = DECIMAL (fieldLength | precision)?
| castTypeName = JSON
| castTypeName = REAL
- | castTypeName = DOUBLE PRECISION
+ | castTypeName = DOUBLE PRECISION?
| castTypeName = FLOAT precision?
| castTypeName = YEAR
;
diff --git
a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
index dcf94f84892..e0f5a16da27 100644
---
a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
+++
b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
@@ -118,7 +118,6 @@ import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Replace
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceValuesClauseContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowAliasContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowConstructorListContext;
-import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValueReferenceContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectSpecificationContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext;
@@ -153,6 +152,7 @@ import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TypeDat
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UdfFunctionContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UpdateContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UserVariableContext;
+import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValueReferenceContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValuesFunctionContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.VariableContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNameContext;
@@ -174,8 +174,8 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.Ind
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.ReturningSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ColumnAssignmentSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.InsertValuesSegment;
-import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.RowAliasSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment;
@@ -204,6 +204,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simp
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.SimpleExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalUnitExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationDistinctProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
@@ -1210,7 +1211,8 @@ public abstract class MySQLStatementVisitor extends
MySQLStatementBaseVisitor<AS
public final ASTNode visitExtractFunction(final ExtractFunctionContext
ctx) {
calculateParameterCount(Collections.singleton(ctx.expr()));
FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.EXTRACT().getText(), getOriginalText(ctx));
- result.getParameters().add(new
LiteralExpressionSegment(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(), ctx.intervalUnit().getText()));
+ result.getParameters().add(new
IntervalUnitExpression(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(),
+
IntervalUnit.valueOf(ctx.intervalUnit().getText().toUpperCase())));
result.getParameters().add((ExpressionSegment) visit(ctx.expr()));
return result;
}
@@ -1273,7 +1275,8 @@ public abstract class MySQLStatementVisitor extends
MySQLStatementBaseVisitor<AS
@Override
public ASTNode visitTimeStampAddFunction(final TimeStampAddFunctionContext
ctx) {
FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.TIMESTAMPADD().getText(), getOriginalText(ctx));
- result.getParameters().add(new
LiteralExpressionSegment(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(), ctx.intervalUnit().getText()));
+ result.getParameters().add(new
IntervalUnitExpression(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(),
+
IntervalUnit.valueOf(ctx.intervalUnit().getText().toUpperCase())));
result.getParameters().addAll(getExpressions(ctx.expr()));
return result;
}
@@ -1281,7 +1284,8 @@ public abstract class MySQLStatementVisitor extends
MySQLStatementBaseVisitor<AS
@Override
public ASTNode visitTimeStampDiffFunction(final
TimeStampDiffFunctionContext ctx) {
FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.TIMESTAMPDIFF().getText(), getOriginalText(ctx));
- result.getParameters().add(new
LiteralExpressionSegment(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(), ctx.intervalUnit().getText()));
+ result.getParameters().add(new
IntervalUnitExpression(ctx.intervalUnit().getStart().getStartIndex(),
ctx.intervalUnit().getStop().getStopIndex(),
+
IntervalUnit.valueOf(ctx.intervalUnit().getText().toUpperCase())));
result.getParameters().addAll(getExpressions(ctx.expr()));
return result;
}
diff --git
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/interval/IntervalUnitExpression.java
similarity index 57%
copy from
kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
copy to
parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/interval/IntervalUnitExpression.java
index c1885ba40c3..eeca54f8fc9 100644
---
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
+++
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/interval/IntervalUnitExpression.java
@@ -15,20 +15,30 @@
* limitations under the License.
*/
-package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+package
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval;
-import org.apache.calcite.sql.SqlDynamicParam;
-import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
-import org.junit.jupiter.api.Test;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.IntervalUnit;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-class ParameterMarkerExpressionConverterTest {
+/**
+ * Interval unit expression.
+ */
+@RequiredArgsConstructor
+@Getter
+@Setter
+public final class IntervalUnitExpression implements ExpressionSegment {
+
+ private final int startIndex;
+
+ private final int stopIndex;
+
+ private final IntervalUnit intervalUnit;
- @Test
- void assertConvertParameterMarker() {
- SqlDynamicParam actual =
ParameterMarkerExpressionConverter.convert(new
ParameterMarkerExpressionSegment(0, 0, 5));
- assertThat(actual.getIndex(), is(5));
+ @Override
+ public String getText() {
+ return intervalUnit.name();
}
}
diff --git a/test/it/optimizer/src/test/resources/converted-sql/insert.xml
b/test/it/optimizer/src/test/resources/converted-sql/insert.xml
index c46396648f8..9139add9145 100644
--- a/test/it/optimizer/src/test/resources/converted-sql/insert.xml
+++ b/test/it/optimizer/src/test/resources/converted-sql/insert.xml
@@ -49,7 +49,7 @@
<test-cases
sql-case-id="insert_with_batch_and_without_generate_key_column"
expected-sql="INSERT INTO [t_order_item] ([order_id], [user_id], [status],
[creation_date]) VALUES (?, ?, 'insert', '2017-08-08', ?, ?, 'insert',
'2017-08-08')" db-types="SQLServer" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="insert_with_multiple_values" expected-sql="INSERT
INTO `t_order` (`order_id`, `user_id`, `status`) VALUES (1, 1, 'insert'), (2,
2, 'insert2')" db-types="MySQL" sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_one_auto_increment_column"
expected-sql="INSERT INTO `t_auto_increment_table` VALUES ()" db-types="MySQL"
sql-case-types="LITERAL" />
- <test-cases sql-case-id="insert_with_double_value" expected-sql="INSERT
INTO `t_double_test` (`col1`) VALUES (1.22E0)" db-types="MySQL"
sql-case-types="LITERAL" />
+ <test-cases sql-case-id="insert_with_double_value" expected-sql="INSERT
INTO `t_double_test` (`col1`) VALUES (1.22)" db-types="MySQL"
sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_null_value" expected-sql="INSERT INTO
`t_null_value_test` (`col1`) VALUES (NULL)" db-types="MySQL"
sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_function" expected-sql="INSERT INTO
`t_order` (`present_date`, `order_id`, `user_id`) VALUES (`curdate`(), ?, ?)"
db-types="MySQL" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="insert_with_unix_timestamp_function"
expected-sql="INSERT INTO `t_order` (`status`, `order_id`, `user_id`) VALUES
(`unix_timestamp`(?), ?, ?)" db-types="MySQL" sql-case-types="PLACEHOLDER" />
@@ -65,7 +65,7 @@
<test-cases sql-case-id="insert_without_into_keyword" expected-sql="INSERT
INTO `t_order` (`order_id`, `user_id`, `status`) VALUES (?, ?, ?)"
db-types="MySQL" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="insert_with_uuid_column" expected-sql="INSERT
INTO "t_order" ("id", "uuid") VALUES (?, ?)"
db-types="PostgreSQL,openGauss" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="insert_without_columns" expected-sql="INSERT INTO
"departments" VALUES (280, 'Recreation', 121, 1700)"
db-types="Oracle" sql-case-types="LITERAL" />
- <test-cases sql-case-id="insert_with_select_subquery" expected-sql="INSERT
INTO "bonuses" SELECT "employee_id", "salary" *
1.1E0 FROM "employees" WHERE "commission_pct" > 2.5E-1"
db-types="Oracle" sql-case-types="LITERAL" />
+ <test-cases sql-case-id="insert_with_select_subquery" expected-sql="INSERT
INTO "bonuses" SELECT "employee_id", "salary" *
1.1 FROM "employees" WHERE "commission_pct" > 0.25"
db-types="Oracle" sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_rank_column" expected-sql="INSERT
INTO "sales" ("rank") VALUES (1)" db-types="Oracle"
sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_schema" expected-sql="INSERT INTO
`db1`.`t_order` VALUES (1, 2, 3)" db-types="MySQL" sql-case-types="LITERAL" />
<test-cases sql-case-id="insert_with_schema" expected-sql="INSERT INTO
"db1"."t_order" VALUES (1, 2, 3)"
db-types="PostgreSQL,openGauss,Oracle" sql-case-types="LITERAL" />
diff --git a/test/it/optimizer/src/test/resources/converted-sql/select.xml
b/test/it/optimizer/src/test/resources/converted-sql/select.xml
index 6e7ae260a47..593686849ae 100644
--- a/test/it/optimizer/src/test/resources/converted-sql/select.xml
+++ b/test/it/optimizer/src/test/resources/converted-sql/select.xml
@@ -20,7 +20,7 @@
<test-cases sql-case-id="select_string_constant_type_cast"
expected-sql="SELECT CAST('1' AS INTEGER), CAST('2' AS DECIMAL)"
db-types="openGauss,PostgreSQL" />
<test-cases
sql-case-id="select_with_database_name_and_schema_name_in_table"
expected-sql="SELECT "order_id" FROM
"sharding_db"."public"."t_order" WHERE
"user_id" = ? AND "order_id" = ?"
db-types="PostgreSQL,openGauss" sql-case-types="PLACEHOLDER" parameters="1, 1"
/>
<test-cases
sql-case-id="select_with_database_name_and_schema_name_in_table"
expected-sql="SELECT "order_id" FROM
"sharding_db"."public"."t_order" WHERE
"user_id" = 1 AND "order_id" = 1"
db-types="PostgreSQL,openGauss" sql-case-types="LITERAL" parameters="1, 1" />
- <test-cases sql-case-id="select_with_spatial_function"
expected-sql="SELECT * FROM `t_order` WHERE
`ST_DISTANCE_SPHERE`(`POINT`(1.13358772E2, 2.31273723E1), `POINT`(`user_id`,
`order_id`)) <> 0" db-types="MySQL" />
+ <test-cases sql-case-id="select_with_spatial_function"
expected-sql="SELECT * FROM `t_order` WHERE
`ST_DISTANCE_SPHERE`(`POINT`(113.358772, 23.1273723), `POINT`(`user_id`,
`order_id`)) <> 0" db-types="MySQL" />
<test-cases sql-case-id="select_with_function_name" expected-sql="SELECT
CURRENT_TIMESTAMP" db-types="MySQL" />
<test-cases sql-case-id="select_with_date_format_function"
expected-sql="SELECT * FROM `t_order` WHERE `DATE_FORMAT`(CURRENT_DATE,
'%Y-%m-%d') = '2019-12-18'" db-types="MySQL" />
<test-cases sql-case-id="select_with_schema_name_in_shorthand_projection"
expected-sql="SELECT `sharding_db`.`t_order`.* FROM `t_order` WHERE `user_id` =
? AND `order_id` = ?" db-types="MySQL" sql-case-types="PLACEHOLDER"
parameters="1, 1" />
@@ -33,7 +33,7 @@
<test-cases sql-case-id="select_with_assignment_operator"
expected-sql="SELECT `rn` := 1, `now_code` := '' FROM `t_order`"
db-types="MySQL" />
<test-cases sql-case-id="select_with_assignment_operator_and_keyword"
expected-sql="SELECT `KEY` := '', `num` := 123 FROM `t_order`" db-types="MySQL"
/>
<test-cases sql-case-id="select_with_json_value_return_type"
expected-sql="SELECT * FROM `t_order` WHERE JSON_VALUE(`items`, '''$.name'''
'RETURNING' VARCHAR(100)) = 'jack'" db-types="MySQL" />
- <test-cases sql-case-id="select_projection_with_parameter"
expected-sql="SELECT 1 "id", ?, "SYSDATE"
"create_time", "TRUNC"("SYSDATE")
"create_date"" db-types="Oracle" sql-case-types="PLACEHOLDER"
parameters="'OK'" />
+ <test-cases sql-case-id="select_projection_with_parameter"
expected-sql="SELECT 1 "id", ? "status",
"SYSDATE" "create_time",
"TRUNC"("SYSDATE") "create_date""
db-types="Oracle" sql-case-types="PLACEHOLDER" parameters="'OK'" />
<test-cases sql-case-id="select_projection_with_parameter"
expected-sql="SELECT 1 "id", 'OK' "status",
"SYSDATE" "create_time",
"TRUNC"("SYSDATE") "create_date""
db-types="Oracle" sql-case-types="LITERAL" parameters="'OK'" />
<test-cases sql-case-id="select_with_not_operator_number"
expected-sql="SELECT NOT 0, NOT 1, NOT 2" db-types="MySQL" />
<test-cases sql-case-id="select_with_not_operator_boolean"
expected-sql="SELECT NOT TRUE, NOT FALSE" db-types="MySQL" />
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
index a4900ce4a99..9ea1a24d6ad 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
@@ -46,6 +46,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simp
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalDayToSecondExpression;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalUnitExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.interval.IntervalYearToMonthExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
@@ -76,6 +77,7 @@ import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalDayToSecondExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalExpressionProjection;
+import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalUnitExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalYearToMonthExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedKeyValueSegment;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedListExpression;
@@ -481,6 +483,15 @@ public final class ExpressionAssert {
}
}
+ private static void assertIntervalUnitExpression(final
SQLCaseAssertContext assertContext, final IntervalUnitExpression actual, final
ExpectedIntervalUnitExpression expected) {
+ if (null == expected) {
+ assertNull(actual, assertContext.getText("Actual interval unit
expression should not exist."));
+ } else {
+ assertNotNull(actual, assertContext.getText("Actual interval unit
expression should exist"));
+ assertThat(assertContext.getText("Actual interval unit is
different with expected interval unit."), actual.getIntervalUnit(),
is(expected.getIntervalUnit()));
+ }
+ }
+
private static void assertQuantifySubqueryExpression(final
SQLCaseAssertContext assertContext, final QuantifySubqueryExpression actual,
final ExpectedQuantifySubqueryExpression expected) {
if (null == expected) {
assertNull(actual, assertContext.getText("Actual quantify subquery
expression should not exist."));
@@ -721,6 +732,8 @@ public final class ExpressionAssert {
assertJsonNullClauseSegment(assertContext, (JsonNullClauseSegment)
actual, expected.getJsonNullClauseSegment());
} else if (actual instanceof IntervalExpression) {
assertIntervalExpression(assertContext, (IntervalExpression)
actual, expected.getIntervalExpression());
+ } else if (actual instanceof IntervalUnitExpression) {
+ assertIntervalUnitExpression(assertContext,
(IntervalUnitExpression) actual, expected.getIntervalUnitExpression());
} else if (actual instanceof QuantifySubqueryExpression) {
assertQuantifySubqueryExpression(assertContext,
(QuantifySubqueryExpression) actual, expected.getQuantifySubqueryExpression());
} else {
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
index c320167320f..8a1ed72d895 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
@@ -116,6 +116,9 @@ public final class ExpectedExpression extends
AbstractExpectedSQLSegment {
@XmlElement(name = "interval-expression")
private ExpectedIntervalExpression intervalExpression;
+ @XmlElement(name = "interval-unit-expression")
+ private ExpectedIntervalUnitExpression intervalUnitExpression;
+
@XmlElement(name = "quantify-subquery-expression")
private ExpectedQuantifySubqueryExpression quantifySubqueryExpression;
diff --git
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalUnitExpression.java
similarity index 59%
copy from
kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
copy to
test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalUnitExpression.java
index c1885ba40c3..06b0e77133b 100644
---
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ParameterMarkerExpressionConverterTest.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalUnitExpression.java
@@ -15,20 +15,22 @@
* limitations under the License.
*/
-package
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+package
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
-import org.apache.calcite.sql.SqlDynamicParam;
-import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
-import org.junit.jupiter.api.Test;
+import lombok.Getter;
+import lombok.Setter;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.IntervalUnit;
+import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import javax.xml.bind.annotation.XmlElement;
-class ParameterMarkerExpressionConverterTest {
+/**
+ * Expected interval unit expression.
+ */
+@Getter
+@Setter
+public class ExpectedIntervalUnitExpression extends AbstractExpectedSQLSegment
implements ExpectedExpressionSegment {
- @Test
- void assertConvertParameterMarker() {
- SqlDynamicParam actual =
ParameterMarkerExpressionConverter.convert(new
ParameterMarkerExpressionSegment(0, 0, 5));
- assertThat(actual.getIndex(), is(5));
- }
+ @XmlElement(name = "interval-unit")
+ private IntervalUnit intervalUnit;
}
diff --git
a/test/it/parser/src/main/resources/case/dml/select-special-function.xml
b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
index 980c53490c4..627bbb0e417 100644
--- a/test/it/parser/src/main/resources/case/dml/select-special-function.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
@@ -239,7 +239,9 @@
<expr>
<function function-name="EXTRACT" start-index="7"
stop-index="37" text="EXTRACT(YEAR FROM '2019-07-02')" >
<parameter>
- <literal-expression value="YEAR" start-index="15"
stop-index="18" />
+ <interval-unit-expression start-index="15"
stop-index="18">
+ <interval-unit>YEAR</interval-unit>
+ </interval-unit-expression>
</parameter>
<parameter>
<literal-expression value="2019-07-02"
start-index="25" stop-index="36" />
@@ -255,7 +257,9 @@
<expr>
<function function-name="EXTRACT" start-index="7"
stop-index="40" text="EXTRACT(YEAR FROM o.creation_date)" >
<parameter>
- <literal-expression value="YEAR" start-index="15"
stop-index="18" />
+ <interval-unit-expression start-index="15"
stop-index="18">
+ <interval-unit>YEAR</interval-unit>
+ </interval-unit-expression>
</parameter>
<parameter>
<column name="creation_date" start-index="25"
stop-index="39">
diff --git a/test/it/parser/src/main/resources/case/dml/select.xml
b/test/it/parser/src/main/resources/case/dml/select.xml
index a5bb4cca31b..97e12ebaa3c 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -103,7 +103,9 @@
<expr>
<function start-index="7" stop-index="50"
text="extract(DAY_HOUR FROM "1999-01-02 10:11:12")"
function-name="extract">
<parameter>
- <literal-expression start-index="15"
stop-index="22" value="DAY_HOUR" />
+ <interval-unit-expression start-index="15"
stop-index="22" value="DAY_HOUR">
+ <interval-unit>DAY_HOUR</interval-unit>
+ </interval-unit-expression>
</parameter>
<parameter>
<literal-expression start-index="29"
stop-index="49" value="1999-01-02 10:11:12" />
diff --git
a/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
b/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
index 3944d08c6e2..85cc26abb43 100644
---
a/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
+++
b/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
@@ -29,7 +29,7 @@
<sql-case id="select_substring" value="SELECT SUBSTRING('foobarbar' from
-4 for 2)" db-types="MySQL" />
<sql-case id="select_substr" value="SELECT SUBSTR('foobarbar' from 4)"
db-types="MySQL" />
<sql-case id="select_extract" value="SELECT EXTRACT(YEAR FROM
'2019-07-02')" db-types="MySQL" />
- <sql-case id="select_extract_from_column" value="SELECT EXTRACT(YEAR FROM
o.creation_date) FROM t_order o" db-types="MySQL,Presto" />
+ <sql-case id="select_extract_from_column" value="SELECT EXTRACT(YEAR FROM
o.creation_date) FROM t_order o" db-types="MySQL" />
<sql-case id="select_char" value="SELECT CHAR(77,121,83,81,'76')"
db-types="MySQL" />
<sql-case id="select_chr_using_nchar_cs" value="SELECT CHR (196 USING
NCHAR_CS) FROM DUAL;" db-types="Oracle" />
<sql-case id="select_trim" value="SELECT TRIM(' bar ')"
db-types="MySQL" />