Co-authored-by: Murphy <96611012+murphyatwork@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
parent
658d5c1b9d
commit
b228bb67cc
|
|
@ -577,6 +577,7 @@ public class SimplifiedPredicateRule extends BottomUpScalarOperatorRewriteRule {
|
|||
}
|
||||
|
||||
// Simplify hour(from_unixtime(ts)) to hour_from_unixtime(ts)
|
||||
// Also simplify hour(to_datetime(ts)) and hour(to_datetime(ts, 0)) to hour_from_unixtime(ts)
|
||||
private static ScalarOperator simplifiedHourFromUnixTime(CallOperator call) {
|
||||
if (call.getChildren().size() != 1) {
|
||||
return call;
|
||||
|
|
@ -588,19 +589,74 @@ public class SimplifiedPredicateRule extends BottomUpScalarOperatorRewriteRule {
|
|||
}
|
||||
|
||||
CallOperator childCall = (CallOperator) child;
|
||||
if (!FunctionSet.FROM_UNIXTIME.equalsIgnoreCase(childCall.getFnName())) {
|
||||
return call;
|
||||
String childFnName = childCall.getFnName();
|
||||
|
||||
// Case 1: hour(from_unixtime(ts)) -> hour_from_unixtime(ts)
|
||||
if (FunctionSet.FROM_UNIXTIME.equalsIgnoreCase(childFnName)) {
|
||||
// Keep original behavior: only succeeds when argument list matches hour_from_unixtime signature
|
||||
Type[] argTypes = childCall.getChildren().stream().map(ScalarOperator::getType).toArray(Type[]::new);
|
||||
Function fn =
|
||||
Expr.getBuiltinFunction(FunctionSet.HOUR_FROM_UNIXTIME, argTypes, Function.CompareMode.IS_IDENTICAL);
|
||||
|
||||
if (fn == null) {
|
||||
return call;
|
||||
}
|
||||
|
||||
return new CallOperator(FunctionSet.HOUR_FROM_UNIXTIME, call.getType(), childCall.getChildren(), fn);
|
||||
}
|
||||
|
||||
// Create hour_from_unixtime function call
|
||||
Type[] argTypes = childCall.getChildren().stream().map(ScalarOperator::getType).toArray(Type[]::new);
|
||||
Function fn =
|
||||
Expr.getBuiltinFunction(FunctionSet.HOUR_FROM_UNIXTIME, argTypes, Function.CompareMode.IS_IDENTICAL);
|
||||
// Case 2: hour(to_datetime(ts)) or hour(to_datetime(ts, 0)) -> hour_from_unixtime(ts)
|
||||
if (FunctionSet.TO_DATETIME.equalsIgnoreCase(childFnName)) {
|
||||
List<ScalarOperator> args = childCall.getChildren();
|
||||
ScalarOperator tsArg;
|
||||
ScalarOperator unixtimeArgForHour;
|
||||
|
||||
if (fn == null) {
|
||||
return call;
|
||||
if (args.size() == 1) {
|
||||
// Implicit seconds
|
||||
tsArg = args.get(0);
|
||||
unixtimeArgForHour = tsArg;
|
||||
} else if (args.size() == 2) {
|
||||
tsArg = args.get(0);
|
||||
ScalarOperator scaleOp = args.get(1);
|
||||
if (!(scaleOp instanceof ConstantOperator)) {
|
||||
return call;
|
||||
}
|
||||
ConstantOperator scale = (ConstantOperator) scaleOp;
|
||||
if (!Type.INT.equals(scale.getType()) || scale.isNull()) {
|
||||
return call;
|
||||
}
|
||||
int scaleVal = scale.getInt();
|
||||
if (scaleVal == 0) {
|
||||
unixtimeArgForHour = tsArg;
|
||||
} else if (scaleVal == 3) {
|
||||
// milliseconds -> seconds
|
||||
unixtimeArgForHour = new CallOperator(FunctionSet.DIVIDE, Type.BIGINT,
|
||||
Lists.newArrayList(tsArg, ConstantOperator.createInt(1000)), null);
|
||||
} else if (scaleVal == 6) {
|
||||
// microseconds -> seconds
|
||||
unixtimeArgForHour = new CallOperator(FunctionSet.DIVIDE, Type.BIGINT,
|
||||
Lists.newArrayList(tsArg, ConstantOperator.createInt(1_000_000)), null);
|
||||
} else {
|
||||
// Unsupported scale
|
||||
return call;
|
||||
}
|
||||
} else {
|
||||
return call;
|
||||
}
|
||||
|
||||
// Build hour_from_unixtime(...) with the converted unix time argument
|
||||
Type[] argTypes = new Type[] { unixtimeArgForHour.getType() };
|
||||
Function fn =
|
||||
Expr.getBuiltinFunction(FunctionSet.HOUR_FROM_UNIXTIME, argTypes, Function.CompareMode.IS_IDENTICAL);
|
||||
|
||||
if (fn == null) {
|
||||
return call;
|
||||
}
|
||||
|
||||
return new CallOperator(FunctionSet.HOUR_FROM_UNIXTIME, call.getType(),
|
||||
Lists.newArrayList(unixtimeArgForHour), fn);
|
||||
}
|
||||
|
||||
return new CallOperator(FunctionSet.HOUR_FROM_UNIXTIME, call.getType(), childCall.getChildren(), fn);
|
||||
return call;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,4 +140,78 @@ public class SimplifiedPredicateRuleTest {
|
|||
ScalarOperator result2 = rule.apply(hourCall2, null);
|
||||
assertEquals(hourCall2, result2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyHourToDatetimeRewrite() {
|
||||
// hour(to_datetime(ts)) -> hour_from_unixtime(ts)
|
||||
ColumnRefOperator tsColumn = new ColumnRefOperator(2, Type.BIGINT, "ts2", true);
|
||||
|
||||
CallOperator toDatetimeCall = new CallOperator(FunctionSet.TO_DATETIME, Type.DATETIME,
|
||||
Lists.newArrayList(tsColumn), null);
|
||||
CallOperator hourCall = new CallOperator(FunctionSet.HOUR, Type.TINYINT,
|
||||
Lists.newArrayList(toDatetimeCall), null);
|
||||
|
||||
ScalarOperator result = rule.apply(hourCall, null);
|
||||
assertEquals(OperatorType.CALL, result.getOpType());
|
||||
CallOperator resultCall = (CallOperator) result;
|
||||
assertEquals(FunctionSet.HOUR_FROM_UNIXTIME, resultCall.getFnName());
|
||||
assertEquals(1, resultCall.getChildren().size());
|
||||
assertEquals(tsColumn, resultCall.getChild(0));
|
||||
|
||||
// hour(to_datetime(ts, 0)) -> hour_from_unixtime(ts)
|
||||
CallOperator toDatetimeCallScale0 = new CallOperator(FunctionSet.TO_DATETIME, Type.DATETIME,
|
||||
Lists.newArrayList(tsColumn, ConstantOperator.createInt(0)), null);
|
||||
CallOperator hourCall2 = new CallOperator(FunctionSet.HOUR, Type.TINYINT,
|
||||
Lists.newArrayList(toDatetimeCallScale0), null);
|
||||
|
||||
ScalarOperator result2 = rule.apply(hourCall2, null);
|
||||
assertEquals(OperatorType.CALL, result2.getOpType());
|
||||
CallOperator resultCall2 = (CallOperator) result2;
|
||||
assertEquals(FunctionSet.HOUR_FROM_UNIXTIME, resultCall2.getFnName());
|
||||
assertEquals(1, resultCall2.getChildren().size());
|
||||
assertEquals(tsColumn, resultCall2.getChild(0));
|
||||
|
||||
// hour(to_datetime(ts, 3)) -> hour_from_unixtime(ts/1000)
|
||||
CallOperator toDatetimeCallScale3 = new CallOperator(FunctionSet.TO_DATETIME, Type.DATETIME,
|
||||
Lists.newArrayList(tsColumn, ConstantOperator.createInt(3)), null);
|
||||
CallOperator hourCall3 = new CallOperator(FunctionSet.HOUR, Type.TINYINT,
|
||||
Lists.newArrayList(toDatetimeCallScale3), null);
|
||||
ScalarOperator result3 = rule.apply(hourCall3, null);
|
||||
assertEquals(OperatorType.CALL, result3.getOpType());
|
||||
CallOperator resultCall3 = (CallOperator) result3;
|
||||
assertEquals(FunctionSet.HOUR_FROM_UNIXTIME, resultCall3.getFnName());
|
||||
assertEquals(1, resultCall3.getChildren().size());
|
||||
// Expect a divide(ts, 1000) as the argument
|
||||
ScalarOperator arg3 = resultCall3.getChild(0);
|
||||
assertEquals(OperatorType.CALL, arg3.getOpType());
|
||||
CallOperator div3 = (CallOperator) arg3;
|
||||
assertEquals(FunctionSet.DIVIDE, div3.getFnName());
|
||||
assertEquals(tsColumn, div3.getChild(0));
|
||||
assertEquals(ConstantOperator.createInt(1000), div3.getChild(1));
|
||||
|
||||
// hour(to_datetime(ts, 6)) -> hour_from_unixtime(ts/1000000)
|
||||
CallOperator toDatetimeCallScale6 = new CallOperator(FunctionSet.TO_DATETIME, Type.DATETIME,
|
||||
Lists.newArrayList(tsColumn, ConstantOperator.createInt(6)), null);
|
||||
CallOperator hourCall6 = new CallOperator(FunctionSet.HOUR, Type.TINYINT,
|
||||
Lists.newArrayList(toDatetimeCallScale6), null);
|
||||
ScalarOperator result6 = rule.apply(hourCall6, null);
|
||||
assertEquals(OperatorType.CALL, result6.getOpType());
|
||||
CallOperator resultCall6 = (CallOperator) result6;
|
||||
assertEquals(FunctionSet.HOUR_FROM_UNIXTIME, resultCall6.getFnName());
|
||||
assertEquals(1, resultCall6.getChildren().size());
|
||||
ScalarOperator arg6 = resultCall6.getChild(0);
|
||||
assertEquals(OperatorType.CALL, arg6.getOpType());
|
||||
CallOperator div6 = (CallOperator) arg6;
|
||||
assertEquals(FunctionSet.DIVIDE, div6.getFnName());
|
||||
assertEquals(tsColumn, div6.getChild(0));
|
||||
assertEquals(ConstantOperator.createInt(1_000_000), div6.getChild(1));
|
||||
|
||||
// Unsupported scale like 4 should not be rewritten
|
||||
CallOperator toDatetimeCallScale4 = new CallOperator(FunctionSet.TO_DATETIME, Type.DATETIME,
|
||||
Lists.newArrayList(tsColumn, ConstantOperator.createInt(4)), null);
|
||||
CallOperator hourCall4 = new CallOperator(FunctionSet.HOUR, Type.TINYINT,
|
||||
Lists.newArrayList(toDatetimeCallScale4), null);
|
||||
ScalarOperator result4 = rule.apply(hourCall4, null);
|
||||
assertEquals(hourCall4, result4);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue