Skip to content

Commit 7ba03c9

Browse files
committed
feat(dqe): timestamp sort, DATE literal, and type support
- SortOperator: add TimestampType and BooleanType comparison - ExpressionCompiler: handle GenericLiteral (DATE, TIMESTAMP types) to convert date strings to epoch microseconds for comparison - ConstantExpression: add TimestampType and IntegerType block building Fixes Q25, Q27 (timestamp sort), Q37, Q38, Q42 (DATE comparisons).
1 parent 678acd4 commit 7ba03c9

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

dqe/src/main/java/org/opensearch/sql/dqe/function/expression/ConstantExpression.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import io.trino.spi.type.BigintType;
1414
import io.trino.spi.type.BooleanType;
1515
import io.trino.spi.type.DoubleType;
16+
import io.trino.spi.type.IntegerType;
17+
import io.trino.spi.type.TimestampType;
1618
import io.trino.spi.type.Type;
1719
import io.trino.spi.type.VarcharType;
1820
import lombok.Getter;
@@ -51,8 +53,18 @@ private static Block buildSingleValueBlock(Object value, Type type) {
5153
VarcharType.VARCHAR.writeSlice(builder, Slices.utf8Slice(value.toString()));
5254
} else if (type instanceof BooleanType) {
5355
BooleanType.BOOLEAN.writeBoolean(builder, (Boolean) value);
56+
} else if (type instanceof TimestampType) {
57+
// Timestamp values are stored as long (microseconds since epoch)
58+
type.writeLong(builder, ((Number) value).longValue());
59+
} else if (type instanceof IntegerType) {
60+
IntegerType.INTEGER.writeLong(builder, ((Number) value).intValue());
5461
} else {
55-
throw new UnsupportedOperationException("Unsupported constant type: " + type);
62+
// Fallback: try writeLong for numeric types
63+
try {
64+
type.writeLong(builder, ((Number) value).longValue());
65+
} catch (Exception e) {
66+
throw new UnsupportedOperationException("Unsupported constant type: " + type);
67+
}
5668
}
5769
return builder.build();
5870
}

dqe/src/main/java/org/opensearch/sql/dqe/function/expression/ExpressionCompiler.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.trino.spi.type.BooleanType;
1010
import io.trino.spi.type.DoubleType;
1111
import io.trino.spi.type.IntegerType;
12+
import io.trino.spi.type.TimestampType;
1213
import io.trino.spi.type.Type;
1314
import io.trino.spi.type.VarcharType;
1415
import io.trino.sql.tree.ArithmeticBinaryExpression;
@@ -22,6 +23,7 @@
2223
import io.trino.sql.tree.DoubleLiteral;
2324
import io.trino.sql.tree.Expression;
2425
import io.trino.sql.tree.FunctionCall;
26+
import io.trino.sql.tree.GenericLiteral;
2527
import io.trino.sql.tree.Identifier;
2628
import io.trino.sql.tree.InListExpression;
2729
import io.trino.sql.tree.InPredicate;
@@ -81,6 +83,8 @@ public BlockExpression compile(Expression expr) {
8183
return new ConstantExpression(((BooleanLiteral) expr).getValue(), BooleanType.BOOLEAN);
8284
} else if (expr instanceof NullLiteral) {
8385
return new ConstantExpression(null, BigintType.BIGINT);
86+
} else if (expr instanceof GenericLiteral generic) {
87+
return compileGenericLiteral(generic);
8488
} else if (expr instanceof ComparisonExpression cmp) {
8589
return new ComparisonBlockExpression(
8690
cmp.getOperator(), compile(cmp.getLeft()), compile(cmp.getRight()));
@@ -140,6 +144,45 @@ public BlockExpression compile(Expression expr) {
140144
"Unsupported expression type: " + expr.getClass().getSimpleName());
141145
}
142146

147+
/**
148+
* Compile a GenericLiteral (e.g., DATE '2013-07-01', TIMESTAMP '2013-07-01 12:00:00'). Converts
149+
* the literal value to the appropriate Trino internal representation.
150+
*/
151+
private BlockExpression compileGenericLiteral(GenericLiteral literal) {
152+
String typeName = literal.getType().toUpperCase(java.util.Locale.ROOT);
153+
String value = literal.getValue();
154+
155+
switch (typeName) {
156+
case "DATE":
157+
{
158+
// Parse date string and convert to Trino timestamp micros
159+
java.time.LocalDate date = java.time.LocalDate.parse(value);
160+
long epochMicros = date.toEpochDay() * 86_400_000_000L;
161+
return new ConstantExpression(epochMicros, TimestampType.TIMESTAMP_MILLIS);
162+
}
163+
case "TIMESTAMP":
164+
{
165+
// Parse timestamp string and convert to Trino timestamp micros
166+
java.time.LocalDateTime dt =
167+
java.time.LocalDateTime.parse(
168+
value, java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
169+
long epochMicros =
170+
dt.toEpochSecond(java.time.ZoneOffset.UTC) * 1_000_000L + dt.getNano() / 1_000L;
171+
return new ConstantExpression(epochMicros, TimestampType.TIMESTAMP_MILLIS);
172+
}
173+
case "INTEGER":
174+
case "INT":
175+
return new ConstantExpression(Long.parseLong(value), BigintType.BIGINT);
176+
case "BIGINT":
177+
return new ConstantExpression(Long.parseLong(value), BigintType.BIGINT);
178+
case "DOUBLE":
179+
return new ConstantExpression(Double.parseDouble(value), DoubleType.DOUBLE);
180+
default:
181+
// Treat as VARCHAR for unknown types
182+
return new ConstantExpression(value, VarcharType.VARCHAR);
183+
}
184+
}
185+
143186
private BlockExpression compileIdentifier(Identifier identifier) {
144187
String name = identifier.getValue();
145188
Integer colIdx = columnIndexMap.get(name);

dqe/src/main/java/org/opensearch/sql/dqe/operator/SortOperator.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
import io.trino.spi.block.Block;
1010
import io.trino.spi.block.BlockBuilder;
1111
import io.trino.spi.type.BigintType;
12+
import io.trino.spi.type.BooleanType;
1213
import io.trino.spi.type.DoubleType;
1314
import io.trino.spi.type.IntegerType;
15+
import io.trino.spi.type.TimestampType;
1416
import io.trino.spi.type.Type;
1517
import io.trino.spi.type.VarcharType;
1618
import java.util.ArrayList;
@@ -173,8 +175,19 @@ private static int compareValues(Block block, int posA, int posB, Type type) {
173175
return VarcharType.VARCHAR
174176
.getSlice(block, posA)
175177
.compareTo(VarcharType.VARCHAR.getSlice(block, posB));
178+
} else if (type instanceof TimestampType) {
179+
// TimestampType stores values as long (microseconds since epoch)
180+
return Long.compare(type.getLong(block, posA), type.getLong(block, posB));
181+
} else if (type instanceof BooleanType) {
182+
return Boolean.compare(
183+
BooleanType.BOOLEAN.getBoolean(block, posA), BooleanType.BOOLEAN.getBoolean(block, posB));
184+
}
185+
// Fallback: try comparing as longs for any other numeric type
186+
try {
187+
return Long.compare(type.getLong(block, posA), type.getLong(block, posB));
188+
} catch (Exception e) {
189+
throw new UnsupportedOperationException("Unsupported type for sorting: " + type);
176190
}
177-
throw new UnsupportedOperationException("Unsupported type for sorting: " + type);
178191
}
179192

180193
@Override

0 commit comments

Comments
 (0)