Skip to content

Commit 1c8b5df

Browse files
committed
Add VARCHAR-literal regression test and trim helper comments
Cover the case where RexSimplify strips a literal's EXPR_TIMESTAMP UDT during Sarg folding and the field is the only timestamp anchor left. Without the fix, the raw "yyyy-MM-dd HH:mm:ss" string would ship without format("date_time"), and the shard's default parser would reject it. Trim the two helper-method JavaDocs to single-line `//` comments now that the test pins the behavior. Signed-off-by: Jialiang Liang <jiallian@amazon.com>
1 parent 9aa7976 commit 1c8b5df

2 files changed

Lines changed: 35 additions & 21 deletions

File tree

opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,34 +1447,16 @@ public QueryExpression lte(LiteralExpression literal) {
14471447
return this;
14481448
}
14491449

1450-
/**
1451-
* Whether the comparison should be treated as a timestamp range. The field's type is the
1452-
* reliable source — {@code literal.isDateTime()} relies on the literal's UDT, which {@link
1453-
* org.apache.calcite.rex.RexSimplify} can strip when a sibling clause is folded into a {@code
1454-
* Sarg} (e.g. {@code @timestamp > X AND severityText IN (...)}). Without this defensive check,
1455-
* the literal arrives as VARCHAR, the raw string ships to the shard without {@code
1456-
* format("date_time")} or ISO-8601 normalization, and the shard's default date parser rejects
1457-
* the space-separated {@code "2026-05-28 16:18:43"} form. See #5481.
1458-
*/
1450+
// Field type is the reliable source: RexSimplify can strip the literal's UDT when a sibling
1451+
// clause is folded into a Sarg, leaving it as VARCHAR.
14591452
private boolean isFieldOrLiteralDateTime(LiteralExpression literal) {
14601453
return literal.isDateTime() || (rel != null && rel.isTimeStampType());
14611454
}
14621455

1463-
/**
1464-
* Resolves the comparison endpoint to a value the shard's date parser accepts. Mirrors the Sarg
1465-
* path's {@code convertEndpointValue} — when the field is a timestamp, the value is routed
1466-
* through {@link #timestampValueForPushDown} to land in canonical ISO-8601 regardless of the
1467-
* literal's surviving type.
1468-
*/
14691456
private Object endpointValue(LiteralExpression literal, boolean isTimeStamp) {
1470-
if (!isTimeStamp) {
1471-
return literal.value();
1472-
}
1473-
if (literal.isDateTime()) {
1474-
// literal.value() already normalizes for EXPR_TIMESTAMP / EXPR_DATE literals.
1457+
if (!isTimeStamp || literal.isDateTime()) {
14751458
return literal.value();
14761459
}
1477-
// Field is timestamp but literal was re-typed to VARCHAR — normalize the raw value.
14781460
return timestampValueForPushDown(literal.value().toString());
14791461
}
14801462

opensearch/src/test/java/org/opensearch/sql/opensearch/request/PredicateAnalyzerTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,38 @@ void notEquals_generatesBoolQueryForDateTime() throws ExpressionNotAnalyzableExc
11471147
result.toString());
11481148
}
11491149

1150+
/**
1151+
* RexSimplify can strip the EXPR_TIMESTAMP UDT off a literal when a sibling clause is folded into
1152+
* a Sarg (e.g. {@code @timestamp > X AND severityText IN (...)}), leaving the literal as plain
1153+
* VARCHAR. The comparison must still emit a {@code format("date_time")} range query keyed off the
1154+
* field's type so the shard's default date parser accepts the value.
1155+
*/
1156+
@Test
1157+
void gt_normalizesVarcharLiteralAgainstTimestampField()
1158+
throws ExpressionNotAnalyzableException {
1159+
RexLiteral varcharLiteral = (RexLiteral) builder.makeLiteral("1987-02-03 04:34:56");
1160+
RexNode call = builder.makeCall(SqlStdOperatorTable.GREATER_THAN, field4, varcharLiteral);
1161+
QueryBuilder result = PredicateAnalyzer.analyze(call, schema, fieldTypes);
1162+
1163+
assertInstanceOf(RangeQueryBuilder.class, result);
1164+
assertEquals(
1165+
"""
1166+
{
1167+
"range" : {
1168+
"d" : {
1169+
"from" : "1987-02-03T04:34:56.000Z",
1170+
"to" : null,
1171+
"include_lower" : false,
1172+
"include_upper" : true,
1173+
"format" : "date_time",
1174+
"boost" : 1.0
1175+
}
1176+
}
1177+
}\
1178+
""",
1179+
result.toString());
1180+
}
1181+
11501182
@Test
11511183
void gte_generatesRangeQueryWithFormatForDateTime() throws ExpressionNotAnalyzableException {
11521184
RexNode call =

0 commit comments

Comments
 (0)