Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support implicit type conversion from string to temporal #171

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_BOOLEAN;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_BYTE;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_DATE;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_DATETIME;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_DOUBLE;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_FLOAT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_INT;
Expand Down Expand Up @@ -77,6 +78,7 @@ public class Cast extends UnresolvedExpression {
.put("date", CAST_TO_DATE.getName())
.put("time", CAST_TO_TIME.getName())
.put("timestamp", CAST_TO_TIMESTAMP.getName())
.put("datetime", CAST_TO_DATETIME.getName())
.build();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ public enum ExprCoreType implements ExprType {
* Date.
* Todo. compatible relationship.
*/
TIMESTAMP(UNDEFINED),
DATE(UNDEFINED),
TIME(UNDEFINED),
DATETIME(UNDEFINED),
TIMESTAMP(STRING),
DATE(STRING),
TIME(STRING),
DATETIME(STRING),
INTERVAL(UNDEFINED),

/**
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -645,4 +645,9 @@ public FunctionExpression castTimestamp(Expression value) {
return (FunctionExpression) repository
.compile(BuiltinFunctionName.CAST_TO_TIMESTAMP.getName(), Arrays.asList(value));
}

public FunctionExpression castDatetime(Expression value) {
return (FunctionExpression) repository
.compile(BuiltinFunctionName.CAST_TO_DATETIME.getName(), Arrays.asList(value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ public enum BuiltinFunctionName {
CAST_TO_BOOLEAN(FunctionName.of("cast_to_boolean")),
CAST_TO_DATE(FunctionName.of("cast_to_date")),
CAST_TO_TIME(FunctionName.of("cast_to_time")),
CAST_TO_TIMESTAMP(FunctionName.of("cast_to_timestamp"));
CAST_TO_TIMESTAMP(FunctionName.of("cast_to_timestamp")),
CAST_TO_DATETIME(FunctionName.of("cast_to_datetime"));

private final FunctionName name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.opensearch.sql.data.model.ExprBooleanValue;
import org.opensearch.sql.data.model.ExprByteValue;
import org.opensearch.sql.data.model.ExprDateValue;
import org.opensearch.sql.data.model.ExprDatetimeValue;
import org.opensearch.sql.data.model.ExprDoubleValue;
import org.opensearch.sql.data.model.ExprFloatValue;
import org.opensearch.sql.data.model.ExprIntegerValue;
Expand Down Expand Up @@ -80,6 +81,7 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(castToDate());
repository.register(castToTime());
repository.register(castToTimestamp());
repository.register(castToDatetime());
}


Expand Down Expand Up @@ -205,4 +207,15 @@ private static FunctionResolver castToTimestamp() {
impl(nullMissingHandling((v) -> v), TIMESTAMP, TIMESTAMP)
);
}

private static FunctionResolver castToDatetime() {
return FunctionDSL.define(BuiltinFunctionName.CAST_TO_DATETIME.getName(),
impl(nullMissingHandling(
(v) -> new ExprDatetimeValue(v.stringValue())), DATETIME, STRING),
impl(nullMissingHandling(
(v) -> new ExprDatetimeValue(v.datetimeValue())), DATETIME, TIMESTAMP),
impl(nullMissingHandling(
(v) -> new ExprDatetimeValue(v.datetimeValue())), DATETIME, DATE)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public void castAnalyzer() {
);

assertThrows(IllegalStateException.class, () -> analyze(AstDSL.cast(AstDSL.unresolvedAttr(
"boolean_value"), AstDSL.stringLiteral("DATETIME"))));
"boolean_value"), AstDSL.stringLiteral("INTERVAL"))));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opensearch.sql.data.type.ExprCoreType.ARRAY;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
import static org.opensearch.sql.data.type.ExprCoreType.SHORT;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
import static org.opensearch.sql.data.type.ExprCoreType.STRUCT;
import static org.opensearch.sql.data.type.ExprCoreType.TIME;
import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP;
import static org.opensearch.sql.data.type.ExprCoreType.UNDEFINED;
import static org.opensearch.sql.data.type.ExprCoreType.UNKNOWN;

Expand All @@ -59,7 +63,12 @@ public void isCompatible() {
assertTrue(FLOAT.isCompatible(LONG));
assertTrue(FLOAT.isCompatible(INTEGER));
assertTrue(FLOAT.isCompatible(SHORT));

assertTrue(BOOLEAN.isCompatible(STRING));
assertTrue(TIMESTAMP.isCompatible(STRING));
assertTrue(DATE.isCompatible(STRING));
assertTrue(TIME.isCompatible(STRING));
assertTrue(DATETIME.isCompatible(STRING));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.BYTE;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
import static org.opensearch.sql.data.type.ExprCoreType.SHORT;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
import static org.opensearch.sql.data.type.ExprCoreType.TIME;
import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP;
import static org.opensearch.sql.data.type.ExprCoreType.UNDEFINED;
import static org.opensearch.sql.data.type.WideningTypeRule.IMPOSSIBLE_WIDENING;
import static org.opensearch.sql.data.type.WideningTypeRule.TYPE_EQUAL;
Expand Down Expand Up @@ -73,6 +77,10 @@ class WideningTypeRuleTest {
.put(LONG, DOUBLE, 2)
.put(FLOAT, DOUBLE, 1)
.put(STRING, BOOLEAN, 1)
.put(STRING, TIMESTAMP, 1)
.put(STRING, DATE, 1)
.put(STRING, TIME, 1)
.put(STRING, DATETIME, 1)
.put(UNDEFINED, BYTE, 1)
.put(UNDEFINED, SHORT, 2)
.put(UNDEFINED, INTEGER, 3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.BYTE;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
Expand Down Expand Up @@ -366,4 +367,20 @@ void castToTimestamp() {
assertEquals(TIMESTAMP, expression.type());
assertEquals(new ExprTimestampValue("2012-08-07 01:01:01"), expression.valueOf(null));
}

@Test
void castToDatetime() {
FunctionExpression expression = dsl.castDatetime(DSL.literal("2012-08-07 01:01:01"));
assertEquals(DATETIME, expression.type());
assertEquals(new ExprDatetimeValue("2012-08-07 01:01:01"), expression.valueOf(null));

expression = dsl.castDatetime(DSL.literal(new ExprTimestampValue("2012-08-07 01:01:01")));
assertEquals(DATETIME, expression.type());
assertEquals(new ExprDatetimeValue("2012-08-07 01:01:01"), expression.valueOf(null));

expression = dsl.castDatetime(DSL.literal(new ExprDateValue("2012-08-07")));
assertEquals(DATETIME, expression.type());
assertEquals(new ExprDatetimeValue("2012-08-07 00:00:00"), expression.valueOf(null));
}

}
30 changes: 23 additions & 7 deletions docs/user/general/datatypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ The following matrix illustrates the conversions allowed by our query engine for
+--------------+------+-------+---------+------+-------+--------+---------+--------------+------+--------+-----------+------+------+----------+----------+-----------+-----+--------+-----------+---------+
| TEXT | | | | | | | | | N/A | IE | | | | X | X | X | X | X | X | X |
+--------------+------+-------+---------+------+-------+--------+---------+--------------+------+--------+-----------+------+------+----------+----------+-----------+-----+--------+-----------+---------+
| STRING | E | E | E | E | E | E | IE | X | X | N/A | E | E | E | X | X | X | X | X | X | X |
| STRING | E | E | E | E | E | E | IE | X | X | N/A | IE | IE | IE | IE | X | X | X | X | X | X |
+--------------+------+-------+---------+------+-------+--------+---------+--------------+------+--------+-----------+------+------+----------+----------+-----------+-----+--------+-----------+---------+
| TIMESTAMP | X | X | X | X | X | X | X | X | X | E | N/A | | | X | X | X | X | X | X | X |
+--------------+------+-------+---------+------+-------+--------+---------+--------------+------+--------+-----------+------+------+----------+----------+-----------+-----+--------+-----------+---------+
Expand Down Expand Up @@ -183,13 +183,14 @@ Here are a few examples for implicit type conversion::

os> SELECT
... 1 = 1.0,
... 'True' = true;
... 'True' = true,
... DATE('2021-06-10') < '2021-06-11';
fetched rows / total rows = 1/1
+-----------+-----------------+
| 1 = 1.0 | 'True' = true |
|-----------+-----------------|
| True | True |
+-----------+-----------------+
+-----------+-----------------+-------------------------------------+
| 1 = 1.0 | 'True' = true | DATE('2021-06-10') < '2021-06-11' |
|-----------+-----------------+-------------------------------------|
| True | True | True |
+-----------+-----------------+-------------------------------------+

Here are a few examples for explicit type conversion::

Expand Down Expand Up @@ -331,6 +332,21 @@ Conversion from TIMESTAMP

- Conversion from timestamp is much more straightforward. To convert it to date is to extract the date value, and conversion to time is to extract the time value. Conversion to datetime, it will extracts the datetime value and leave the timezone information over. For example, the result to convert datetime '2020-08-17 14:09:00' UTC to date is date '2020-08-17', to time is '14:09:00' and to datetime is datetime '2020-08-17 14:09:00'.

Conversion from string to date and time types
---------------------------------------------

A string can also represent and be converted to date and time types (except to interval type). As long as the string value is of valid format required by the target date and time types, the conversion can happen implicitly or explicitly as follows::

os> SELECT
... TIMESTAMP('2021-06-17 00:00:00') = '2021-06-17 00:00:00',
... '2021-06-18' < DATE('2021-06-17'),
... '10:20:00' <= TIME('11:00:00');
fetched rows / total rows = 1/1
+------------------------------------------------------------+-------------------------------------+----------------------------------+
| TIMESTAMP('2021-06-17 00:00:00') = '2021-06-17 00:00:00' | '2021-06-18' < DATE('2021-06-17') | '10:20:00' <= TIME('11:00:00') |
|------------------------------------------------------------+-------------------------------------+----------------------------------|
| True | False | True |
+------------------------------------------------------------+-------------------------------------+----------------------------------+

String Data Types
=================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ false = 'False' as implicitCast
false = 'true' as implicitCast
'TRUE' = true as implicitCast
'false' = true as implicitCast
CAST('2021-06-17 00:00:00' AS TIMESTAMP) = '2021-06-17 00:00:00' as implicitCast
'2021-06-18' < CAST('2021-06-17' AS DATE) as implicitCast
'10:20:00' <= CAST('11:00:00' AS TIME) as implicitCast