提交 7ae35403 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Implement casts between INTERVAL and VARCHAR

上级 326b51e6
......@@ -1490,6 +1490,157 @@ public class DateTimeUtils {
return b.toString();
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
* @param qualifier the default qualifier to use if string does not have one
* @param s the string with type information to parse
* @return the interval value.
* Type of value can be different from the specified qualifier.
*/
public static ValueInterval parseFormattedInterval(IntervalQualifier qualifier, String s) {
int i = 0;
i = skipWS(s, i);
if (!s.regionMatches(true, i, "INTERVAL", 0, 8)) {
return parseInterval(qualifier, false, s);
}
i = skipWS(s, i + 8);
boolean negative = false;
char ch = s.charAt(i);
if (ch == '-') {
negative = true;
i = skipWS(s, i + 1);
ch = s.charAt(i);
} else if (ch == '+') {
i = skipWS(s, i + 1);
ch = s.charAt(i);
}
if (ch != '\'') {
throw new IllegalArgumentException(s);
}
int start = ++i;
int l = s.length();
for (;;) {
if (i == l) {
throw new IllegalArgumentException(s);
}
if (s.charAt(i) == '\'') {
break;
}
i++;
}
String v = s.substring(start, i);
i = skipWS(s, i + 1);
if (s.regionMatches(true, i, "YEAR", 0, 4)) {
i += 4;
int j = skipWSEnd(s, i);
if (j == l) {
return parseInterval(IntervalQualifier.YEAR, negative, v);
}
if (j > i && s.regionMatches(true, j, "TO", 0, 2)) {
j += 2;
i = skipWS(s, j);
if (i > j && s.regionMatches(true, i, "MONTH", 0, 5)) {
if (skipWSEnd(s, i + 5) == l) {
return parseInterval(IntervalQualifier.YEAR_TO_MONTH, negative, v);
}
}
}
} else if (s.regionMatches(true, i, "MONTH", 0, 5)) {
if (skipWSEnd(s, i + 5) == l) {
return parseInterval(IntervalQualifier.MONTH, negative, v);
}
} if (s.regionMatches(true, i, "DAY", 0, 3)) {
i += 3;
int j = skipWSEnd(s, i);
if (j == l) {
return parseInterval(IntervalQualifier.DAY, negative, v);
}
if (j > i && s.regionMatches(true, j, "TO", 0, 2)) {
j += 2;
i = skipWS(s, j);
if (i > j) {
if (s.regionMatches(true, i, "HOUR", 0, 4)) {
if (skipWSEnd(s, i + 4) == l) {
return parseInterval(IntervalQualifier.DAY_TO_HOUR, negative, v);
}
} else if (s.regionMatches(true, i, "MINUTE", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.DAY_TO_MINUTE, negative, v);
}
} else if (s.regionMatches(true, i, "SECOND", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.DAY_TO_SECOND, negative, v);
}
}
}
}
} if (s.regionMatches(true, i, "HOUR", 0, 4)) {
i += 4;
int j = skipWSEnd(s, i);
if (j == l) {
return parseInterval(IntervalQualifier.HOUR, negative, v);
}
if (j > i && s.regionMatches(true, j, "TO", 0, 2)) {
j += 2;
i = skipWS(s, j);
if (i > j) {
if (s.regionMatches(true, i, "MINUTE", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.HOUR_TO_MINUTE, negative, v);
}
} else if (s.regionMatches(true, i, "SECOND", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.HOUR_TO_SECOND, negative, v);
}
}
}
}
} if (s.regionMatches(true, i, "MINUTE", 0, 6)) {
i += 6;
int j = skipWSEnd(s, i);
if (j == l) {
return parseInterval(IntervalQualifier.MINUTE, negative, v);
}
if (j > i && s.regionMatches(true, j, "TO", 0, 2)) {
j += 2;
i = skipWS(s, j);
if (i > j && s.regionMatches(true, i, "SECOND", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.MINUTE_TO_SECOND, negative, v);
}
}
}
} if (s.regionMatches(true, i, "SECOND", 0, 6)) {
if (skipWSEnd(s, i + 6) == l) {
return parseInterval(IntervalQualifier.SECOND, negative, v);
}
}
throw new IllegalArgumentException(s);
}
private static int skipWS(String s, int i) {
for (int l = s.length(); ; i++) {
if (i == l) {
throw new IllegalArgumentException(s);
}
if (!Character.isWhitespace(s.charAt(i))) {
return i;
}
}
}
private static int skipWSEnd(String s, int i) {
for (int l = s.length(); ; i++) {
if (i == l) {
return i;
}
if (!Character.isWhitespace(s.charAt(i))) {
return i;
}
}
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
......
......@@ -1153,6 +1153,18 @@ public abstract class Value {
case Value.INTERVAL_MONTH:
case Value.INTERVAL_YEAR_TO_MONTH:
switch (getType()) {
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED: {
String s = getString();
try {
return DateTimeUtils.parseFormattedInterval(
IntervalQualifier.valueOf(targetType - Value.INTERVAL_YEAR), s)
.convertTo(targetType);
} catch (Exception e) {
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2, e, "INTERVAL", s);
}
}
case Value.INTERVAL_YEAR:
case Value.INTERVAL_MONTH:
case Value.INTERVAL_YEAR_TO_MONTH:
......@@ -1172,6 +1184,18 @@ public abstract class Value {
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND:
switch (getType()) {
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED: {
String s = getString();
try {
return DateTimeUtils.parseFormattedInterval(
IntervalQualifier.valueOf(targetType - Value.INTERVAL_YEAR), s)
.convertTo(targetType);
} catch (Exception e) {
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2, e, "INTERVAL", s);
}
}
case Value.INTERVAL_DAY:
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE:
......
......@@ -433,6 +433,148 @@ SELECT CAST(INTERVAL '-1803:4.123456789' MINUTE TO SECOND AS INTERVAL HOUR TO SE
SELECT CAST(INTERVAL '10:11.123456789' MINUTE TO SECOND AS INTERVAL SECOND(3, 9));
>> INTERVAL '611.123456789' SECOND
-- Casts with strings
SELECT CAST(INTERVAL '10' YEAR AS VARCHAR);
>> INTERVAL '10' YEAR
SELECT CAST('INTERVAL ''10'' YEAR' AS INTERVAL YEAR);
>> INTERVAL '10' YEAR
SELECT CAST('10' AS INTERVAL YEAR);
>> INTERVAL '10' YEAR
SELECT CAST(INTERVAL '10' MONTH AS VARCHAR);
>> INTERVAL '10' MONTH
SELECT CAST('INTERVAL ''10'' MONTH' AS INTERVAL MONTH);
>> INTERVAL '10' MONTH
SELECT CAST('10' AS INTERVAL MONTH);
>> INTERVAL '10' MONTH
SELECT CAST(INTERVAL '10' DAY AS VARCHAR);
>> INTERVAL '10' DAY
SELECT CAST('INTERVAL ''10'' DAY' AS INTERVAL DAY);
>> INTERVAL '10' DAY
SELECT CAST('10' AS INTERVAL DAY);
>> INTERVAL '10' DAY
SELECT CAST(INTERVAL '10' HOUR AS VARCHAR);
>> INTERVAL '10' HOUR
SELECT CAST('INTERVAL ''10'' HOUR' AS INTERVAL HOUR);
>> INTERVAL '10' HOUR
SELECT CAST('10' AS INTERVAL HOUR);
>> INTERVAL '10' HOUR
SELECT CAST(INTERVAL '10' MINUTE AS VARCHAR);
>> INTERVAL '10' MINUTE
SELECT CAST('INTERVAL ''10'' MINUTE' AS INTERVAL MINUTE);
>> INTERVAL '10' MINUTE
SELECT CAST('10' AS INTERVAL MINUTE);
>> INTERVAL '10' MINUTE
SELECT CAST(INTERVAL '10.123456789' SECOND AS VARCHAR);
>> INTERVAL '10.123456789' SECOND
SELECT CAST('INTERVAL ''10.123456789'' SECOND' AS INTERVAL SECOND(2, 9));
>> INTERVAL '10.123456789' SECOND
SELECT CAST('10.123456789' AS INTERVAL SECOND(2, 9));
>> INTERVAL '10.123456789' SECOND
SELECT CAST(INTERVAL '10-11' YEAR TO MONTH AS VARCHAR);
>> INTERVAL '10-11' YEAR TO MONTH
SELECT CAST('INTERVAL ''10-11'' YEAR TO MONTH' AS INTERVAL YEAR TO MONTH);
>> INTERVAL '10-11' YEAR TO MONTH
SELECT CAST('10-11' AS INTERVAL YEAR TO MONTH);
>> INTERVAL '10-11' YEAR TO MONTH
SELECT CAST(INTERVAL '10 11' DAY TO HOUR AS VARCHAR);
>> INTERVAL '10 11' DAY TO HOUR
SELECT CAST('INTERVAL ''10 11'' DAY TO HOUR' AS INTERVAL DAY TO HOUR);
>> INTERVAL '10 11' DAY TO HOUR
SELECT CAST('10 11' AS INTERVAL DAY TO HOUR);
>> INTERVAL '10 11' DAY TO HOUR
SELECT CAST(INTERVAL '10 11:12' DAY TO MINUTE AS VARCHAR);
>> INTERVAL '10 11:12' DAY TO MINUTE
SELECT CAST('INTERVAL ''10 11:12'' DAY TO MINUTE' AS INTERVAL DAY TO MINUTE);
>> INTERVAL '10 11:12' DAY TO MINUTE
SELECT CAST('10 11:12' AS INTERVAL DAY TO MINUTE);
>> INTERVAL '10 11:12' DAY TO MINUTE
SELECT CAST(INTERVAL '10 11:12:13.123456789' DAY TO SECOND AS VARCHAR);
>> INTERVAL '10 11:12:13.123456789' DAY TO SECOND
SELECT CAST('INTERVAL ''10 11:12:13.123456789'' DAY TO SECOND' AS INTERVAL DAY TO SECOND(9));
>> INTERVAL '10 11:12:13.123456789' DAY TO SECOND
SELECT CAST('10 11:12:13.123456789' AS INTERVAL DAY TO SECOND(9));
>> INTERVAL '10 11:12:13.123456789' DAY TO SECOND
SELECT CAST(INTERVAL '11:12' HOUR TO MINUTE AS VARCHAR);
>> INTERVAL '11:12' HOUR TO MINUTE
SELECT CAST('INTERVAL ''11:12'' HOUR TO MINUTE' AS INTERVAL HOUR TO MINUTE);
>> INTERVAL '11:12' HOUR TO MINUTE
SELECT CAST('11:12' AS INTERVAL HOUR TO MINUTE);
>> INTERVAL '11:12' HOUR TO MINUTE
SELECT CAST(INTERVAL '11:12:13.123456789' HOUR TO SECOND AS VARCHAR);
>> INTERVAL '11:12:13.123456789' HOUR TO SECOND
SELECT CAST('INTERVAL ''11:12:13.123456789'' HOUR TO SECOND' AS INTERVAL HOUR TO SECOND(9));
>> INTERVAL '11:12:13.123456789' HOUR TO SECOND
SELECT CAST('11:12:13.123456789' AS INTERVAL HOUR TO SECOND(9));
>> INTERVAL '11:12:13.123456789' HOUR TO SECOND
SELECT CAST(INTERVAL '12:13.123456789' MINUTE TO SECOND AS VARCHAR);
>> INTERVAL '12:13.123456789' MINUTE TO SECOND
SELECT CAST('INTERVAL ''12:13.123456789'' MINUTE TO SECOND' AS INTERVAL MINUTE TO SECOND(9));
>> INTERVAL '12:13.123456789' MINUTE TO SECOND
SELECT CAST('12:13.123456789' AS INTERVAL MINUTE TO SECOND(9));
>> INTERVAL '12:13.123456789' MINUTE TO SECOND
-- More formats
SELECT INTERVAL +'+10' SECOND;
>> INTERVAL '10' SECOND
SELECT CAST('INTERVAL +''+10'' SECOND' AS INTERVAL SECOND);
>> INTERVAL '10' SECOND
SELECT INTERVAL -'-10' HOUR;
>> INTERVAL '10' HOUR
SELECT CAST('INTERVAL -''-10'' HOUR' AS INTERVAL HOUR);
>> INTERVAL '10' HOUR
SELECT CAST('INTERVAL ''1'' MINUTE' AS INTERVAL SECOND);
>> INTERVAL '60' SECOND
SELECT CAST(' interval + ''12-2'' Year To Month ' AS INTERVAL YEAR TO MONTH);
>> INTERVAL '12-2' YEAR TO MONTH
SELECT CAST('INTERVAL''11:12''HOUR TO MINUTE' AS INTERVAL HOUR TO MINUTE);
>> INTERVAL '11:12' HOUR TO MINUTE
-- Arithmetic
SELECT INTERVAL '1000' SECOND + INTERVAL '10' MINUTE;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论