Skip to content

Commit 087b496

Browse files
committed
Use the precision of the original timestamp column in HOP/TUMBLE
Signed-off-by: Mihai Budiu <mbudiu@feldera.com>
1 parent 2ee0098 commit 087b496

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

core/src/main/java/org/apache/calcite/sql/SqlWindowTableFunction.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040

4141
import static org.apache.calcite.util.Static.RESOURCE;
4242

43+
import static java.util.Objects.requireNonNull;
44+
4345
/**
4446
* Base class for a table-valued function that computes windows. Examples
4547
* include {@code TUMBLE}, {@code HOP} and {@code SESSION}.
@@ -107,14 +109,37 @@ public SqlWindowTableFunction(String name, SqlOperandMetadata operandMetadata) {
107109
private static RelDataType inferRowType(SqlOperatorBinding opBinding) {
108110
final RelDataType inputRowType = opBinding.getOperandType(0);
109111
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
112+
int precision = getTimestampPrecision(opBinding);
110113
return typeFactory.builder()
111114
.kind(inputRowType.getStructKind())
112115
.addAll(inputRowType.getFieldList())
113-
.add("window_start", SqlTypeName.TIMESTAMP)
114-
.add("window_end", SqlTypeName.TIMESTAMP)
116+
.add("window_start", SqlTypeName.TIMESTAMP, precision)
117+
.add("window_end", SqlTypeName.TIMESTAMP, precision)
115118
.build();
116119
}
117120

121+
/** Extract the precision for the start_window, end_window columns from the column supplied as
122+
* DESCRIPTOR for the window function. */
123+
private static int getTimestampPrecision(SqlOperatorBinding opBinding) {
124+
RelDataType inputRowType = opBinding.getOperandType(0);
125+
SqlCallBinding callBinding = (SqlCallBinding) opBinding;
126+
// Locate the "descriptor" argument
127+
for (SqlNode operand : callBinding.operands()) {
128+
if (operand instanceof SqlCall) {
129+
SqlCall opCall = (SqlCall) operand;
130+
if (opCall.getOperator().getKind() == SqlKind.DESCRIPTOR) {
131+
SqlNode descriptor = opCall.operand(0);
132+
SqlIdentifier id = (SqlIdentifier) descriptor;
133+
RelDataTypeField field =
134+
inputRowType.getField(id.getSimple(), false, false);
135+
return requireNonNull(field, "field").getType().getPrecision();
136+
}
137+
}
138+
}
139+
// Should be unreachable, since validation succeeded
140+
throw new RuntimeException("Could not locate DESCRIPTOR column");
141+
}
142+
118143
/** Partial implementation of operand type checker. */
119144
protected abstract static class AbstractOperandMetadata
120145
implements SqlOperandMetadata {

core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,6 +2502,13 @@ void checkCorrelatedMapSubQuery(boolean expand) {
25022502
sql(sql).ok();
25032503
}
25042504

2505+
@Test void testTableFunctionTumbleConvert() {
2506+
final String sql = "with t as (select CAST(rowtime AS TIMESTAMP(2)) as rowtime FROM Shipments) "
2507+
+ "select *\n"
2508+
+ "from table(tumble(table t, descriptor(rowtime), INTERVAL '1.5' SECOND))";
2509+
sql(sql).ok();
2510+
}
2511+
25052512
@Test void testTableFunctionTumbleWithParamNames() {
25062513
final String sql = "select *\n"
25072514
+ "from table(\n"

core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8588,6 +8588,20 @@ LogicalProject(ORDERID=[$0], ROWTIME=[$1], window_start=[$2], window_end=[$3])
85888588
LogicalTableFunctionScan(invocation=[TUMBLE(DESCRIPTOR($1), 60000:INTERVAL MINUTE)], rowType=[RecordType(INTEGER ORDERID, TIMESTAMP(0) ROWTIME, TIMESTAMP(0) window_start, TIMESTAMP(0) window_end)])
85898589
LogicalProject(ORDERID=[$0], ROWTIME=[$1])
85908590
LogicalTableScan(table=[[CATALOG, SALES, SHIPMENTS]])
8591+
]]>
8592+
</Resource>
8593+
</TestCase>
8594+
<TestCase name="testTableFunctionTumbleConvert">
8595+
<Resource name="sql">
8596+
<![CDATA[with t as (select CAST(rowtime AS TIMESTAMP(2)) as rowtime FROM Shipments) select *
8597+
from table(tumble(table t, descriptor(rowtime), INTERVAL '1.5' SECOND))]]>
8598+
</Resource>
8599+
<Resource name="plan">
8600+
<![CDATA[
8601+
LogicalProject(ROWTIME=[$0], window_start=[$1], window_end=[$2])
8602+
LogicalTableFunctionScan(invocation=[TUMBLE(DESCRIPTOR($0), 1500:INTERVAL SECOND)], rowType=[RecordType(TIMESTAMP(2) ROWTIME, TIMESTAMP(2) window_start, TIMESTAMP(2) window_end)])
8603+
LogicalProject(ROWTIME=[CAST($1):TIMESTAMP(2) NOT NULL])
8604+
LogicalTableScan(table=[[CATALOG, SALES, SHIPMENTS]])
85918605
]]>
85928606
</Resource>
85938607
</TestCase>

core/src/test/resources/sql/stream.iq

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@
1717
#
1818
!use orinoco
1919
!set outputformat mysql
20+
21+
# Test case for [CALCITE-7410] TIMESTAMP type for TUMBLE and HOP is hardwired to TIMESTAMP(3)
22+
# Since we cast the input column to TIMESTAMP(3), we expect window_start to have the same type.
23+
WITH S AS (SELECT *, CAST(ROWTIME AS TIMESTAMP(3)) + INTERVAL '0.5' SECONDS AS TS FROM ORDERS)
24+
SELECT * FROM TABLE(TUMBLE((SELECT * FROM S), DESCRIPTOR(TS), INTERVAL '20:10.525' MINUTE TO SECOND));
25+
+---------------------+----+---------+-------+-------------------------+-------------------------+-------------------------+
26+
| ROWTIME | ID | PRODUCT | UNITS | TS | window_start | window_end |
27+
+---------------------+----+---------+-------+-------------------------+-------------------------+-------------------------+
28+
| 2015-02-15 10:15:00 | 1 | paint | 10 | 2015-02-15 10:15:00.500 | 2015-02-15 10:10:31.125 | 2015-02-15 10:30:41.650 |
29+
| 2015-02-15 10:24:15 | 2 | paper | 5 | 2015-02-15 10:24:15.500 | 2015-02-15 10:10:31.125 | 2015-02-15 10:30:41.650 |
30+
| 2015-02-15 10:24:45 | 3 | brush | 12 | 2015-02-15 10:24:45.500 | 2015-02-15 10:10:31.125 | 2015-02-15 10:30:41.650 |
31+
| 2015-02-15 10:58:00 | 4 | paint | 3 | 2015-02-15 10:58:00.500 | 2015-02-15 10:50:52.175 | 2015-02-15 11:11:02.700 |
32+
| 2015-02-15 11:10:00 | 5 | paint | 3 | 2015-02-15 11:10:00.500 | 2015-02-15 10:50:52.175 | 2015-02-15 11:11:02.700 |
33+
+---------------------+----+---------+-------+-------------------------+-------------------------+-------------------------+
34+
(5 rows)
35+
36+
!ok
37+
2038
SELECT * FROM TABLE(
2139
TUMBLE(
2240
DATA => TABLE ORDERS,

0 commit comments

Comments
 (0)