Skip to content
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 @@ -238,6 +238,43 @@ private DateTimeUtils() {
if (trimmed.isEmpty()) {
return null;
}

// Structural pre-classification to reduce unnecessary formatter attempts.
// Each failed DateTimeFormatter.parse() throws DateTimeParseException with
// expensive stack trace capture (~1-5us per exception).
boolean hasColon = trimmed.indexOf(':') > 0;
boolean hasDateSep = trimmed.length() >= 8
&& (trimmed.indexOf('-') > 0 || trimmed.indexOf('/') > 0
|| Character.isDigit(trimmed.charAt(0)));
boolean hasZoneInfo = false;
if (trimmed.length() > 10) {
hasZoneInfo = trimmed.indexOf('+', 10) >= 0
|| trimmed.indexOf('Z', 10) >= 0
|| trimmed.contains("[");
}

if (hasZoneInfo) {
if (matchesTimestampWithZone(trimmed, timestampTzFormatters)) {
return DateTimeType.TIMESTAMP_TZ;
}
}
if (hasDateSep && hasColon) {
if (matchesLocalDateTime(trimmed, timestampFormatters)) {
return DateTimeType.TIMESTAMP;
}
}
if (hasDateSep && !hasColon) {
if (matchesLocalDate(trimmed, dateFormatters)) {
return DateTimeType.DATE;
}
}
if (hasColon && !hasDateSep) {
if (matchesLocalTime(trimmed, timeFormatters)) {
return DateTimeType.TIME;
}
}

// Fallback: full scan for ambiguous inputs
if (matchesTimestampWithZone(trimmed, timestampTzFormatters)) {
return DateTimeType.TIMESTAMP_TZ;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
public class DateTimeConverter {

private final ZoneId defaultZone;
private final StringDateTimeParser stringParser = new StringDateTimeParser();

public DateTimeConverter(ZoneId defaultZone) {
this.defaultZone = defaultZone;
Expand All @@ -53,8 +54,7 @@ public DingoDateTime convertInput(Object input, DateTimeType targetType) {
} else if (input instanceof java.util.Date) {
return convertUtilDate((java.util.Date) input, targetType);
} else if (input instanceof String) {
StringDateTimeParser parser = new StringDateTimeParser();
return parser.parseString((String) input, targetType, defaultZone);
return stringParser.parseString((String) input, targetType, defaultZone);
} else if (input instanceof DingoDateTime) {
return convertDingoDateTime((DingoDateTime) input, targetType);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@
import io.dingodb.expr.common.timezone.core.DateTimeType;
import io.dingodb.expr.common.timezone.core.DingoDateTime;
import io.dingodb.expr.common.timezone.core.SimpleTimeZoneConfig;
import io.dingodb.expr.common.timezone.operations.ArithmeticOperations;
import io.dingodb.expr.common.timezone.operations.ExtractionOperations;
import io.dingodb.expr.common.timezone.operations.FormattingOperations;
import io.dingodb.expr.common.timezone.operations.OperationResult;
import lombok.Getter;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

Expand Down Expand Up @@ -60,6 +62,18 @@ public Object processDateTime(Object input, DateTimeType inputType,
if (input == null || inputType == null) {
return null;
}
// Fast path: same type, non-TZ-sensitive SQL types — no conversion needed
if (inputType == outputType) {
if (input instanceof java.sql.Date && inputType == DateTimeType.DATE) {
return input;
}
if (input instanceof java.sql.Time && inputType == DateTimeType.TIME) {
return input;
}
if (input instanceof java.sql.Timestamp && inputType == DateTimeType.TIMESTAMP) {
return input;
}
}
try {
DingoDateTime internal = tierProcessor.convertInput(input, inputType);

Expand Down Expand Up @@ -134,29 +148,50 @@ public ZoneId getStorageZone() {
}

public DingoDateTime dateAdd(DingoDateTime dateTime, long amount, ChronoUnit unit) {
ArithmeticOperations.AddOperation operation = new ArithmeticOperations.AddOperation(unit, amount);

OperationResult result = (OperationResult) operation.execute(new DingoDateTime[]{dateTime}, getOutputZone());

if (result.isSuccess() && result.getValue() instanceof DingoDateTime) {
return (DingoDateTime) result.getValue();
if (dateTime.isTimeZoneSensitive()) {
DingoDateTime.DingoTimestampTZ tzValue = (DingoDateTime.DingoTimestampTZ) dateTime;
ZonedDateTime zdt = tzValue.getUtcValue().atZone(tzValue.getOriginalZone());
return new DingoDateTime.DingoTimestampTZ(zdt.plus(amount, unit).toInstant(), tzValue.getOriginalZone());
}

throw new DateTimeProcessingException("Date add operation failed: "
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
Object value = dateTime.getValue();
if (value instanceof LocalDate) {
return new DingoDateTime.DingoLocalDate(((LocalDate) value).plus(amount, unit));
} else if (value instanceof LocalDateTime) {
return new DingoDateTime.DingoLocalDateTime(((LocalDateTime) value).plus(amount, unit));
} else if (value instanceof LocalTime) {
return new DingoDateTime.DingoLocalTime(((LocalTime) value).plus(amount, unit));
}
throw new DateTimeProcessingException("Unsupported type for add: " + value.getClass());
}

public DingoDateTime dateSubtract(DingoDateTime dateTime, long amount, ChronoUnit unit) {
ArithmeticOperations.SubtractOperation operation = new ArithmeticOperations.SubtractOperation(unit, amount);
if (dateTime.isTimeZoneSensitive()) {
DingoDateTime.DingoTimestampTZ tzValue = (DingoDateTime.DingoTimestampTZ) dateTime;
ZonedDateTime zdt = tzValue.getUtcValue().atZone(tzValue.getOriginalZone());
return new DingoDateTime.DingoTimestampTZ(zdt.minus(amount, unit).toInstant(), tzValue.getOriginalZone());
}
Object value = dateTime.getValue();
if (value instanceof LocalDate) {
return new DingoDateTime.DingoLocalDate(((LocalDate) value).minus(amount, unit));
} else if (value instanceof LocalDateTime) {
return new DingoDateTime.DingoLocalDateTime(((LocalDateTime) value).minus(amount, unit));
} else if (value instanceof LocalTime) {
return new DingoDateTime.DingoLocalTime(((LocalTime) value).minus(amount, unit));
}
throw new DateTimeProcessingException("Unsupported type for subtract: " + value.getClass());
}

OperationResult result = (OperationResult) operation.execute(new DingoDateTime[]{dateTime}, getOutputZone());
// -------------------------------------------------------------------------
// Type-specialized extraction fast paths — bypass the full pipeline
// for non-timezone-sensitive java.sql types (Date, Timestamp).
// -------------------------------------------------------------------------

if (result.isSuccess() && result.getValue() instanceof DingoDateTime) {
return (DingoDateTime) result.getValue();
}
public Integer extractYear(java.sql.Date value) {
return value == null ? null : value.toLocalDate().getYear();
}

throw new DateTimeProcessingException("Date subtract operation failed: "
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
public Integer extractYear(java.sql.Timestamp value) {
return value == null ? null : value.toLocalDateTime().getYear();
}

public Integer extractYear(Object input) {
Expand All @@ -178,6 +213,14 @@ public Integer extractYear(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractMonth(java.sql.Date value) {
return value == null ? null : value.toLocalDate().getMonthValue();
}

public Integer extractMonth(java.sql.Timestamp value) {
return value == null ? null : value.toLocalDateTime().getMonthValue();
}

public Integer extractMonth(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.month();
DateTimeType inputType = inferInputType(input);
Expand All @@ -198,6 +241,14 @@ public Integer extractMonth(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractDay(java.sql.Date value) {
return value == null ? null : value.toLocalDate().getDayOfMonth();
}

public Integer extractDay(java.sql.Timestamp value) {
return value == null ? null : value.toLocalDateTime().getDayOfMonth();
}

public Integer extractDay(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.dayOfMonth();
DateTimeType inputType = inferInputType(input);
Expand All @@ -218,6 +269,14 @@ public Integer extractDay(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractQuarter(java.sql.Date value) {
return value == null ? null : (value.toLocalDate().getMonthValue() - 1) / 3 + 1;
}

public Integer extractQuarter(java.sql.Timestamp value) {
return value == null ? null : (value.toLocalDateTime().getMonthValue() - 1) / 3 + 1;
}

public Integer extractQuarter(Object input) {
ExtractionOperations.ExtractQuarterOperation operation = ExtractionOperations.quarter();
DateTimeType inputType = inferInputType(input);
Expand All @@ -238,6 +297,20 @@ public Integer extractQuarter(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractWeek(java.sql.Date value) {
if (value == null) {
return null;
}
return value.toLocalDate().get(java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR);
}

public Integer extractWeek(java.sql.Timestamp value) {
if (value == null) {
return null;
}
return value.toLocalDateTime().get(java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR);
}

public Integer extractWeek(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.week();
DateTimeType inputType = inferInputType(input);
Expand All @@ -259,6 +332,18 @@ public Integer extractWeek(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractHour(java.sql.Date value) {
return 0;
}

public Integer extractHour(java.sql.Timestamp value) {
return value == null ? 0 : value.toLocalDateTime().getHour();
}

public Integer extractHour(java.sql.Time value) {
return value == null ? 0 : value.toLocalTime().getHour();
}

public Integer extractHour(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.hour();
DateTimeType inputType = inferInputType(input);
Expand All @@ -276,6 +361,18 @@ public Integer extractHour(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractMinute(java.sql.Date value) {
return 0;
}

public Integer extractMinute(java.sql.Timestamp value) {
return value == null ? 0 : value.toLocalDateTime().getMinute();
}

public Integer extractMinute(java.sql.Time value) {
return value == null ? 0 : value.toLocalTime().getMinute();
}

public Integer extractMinute(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.minute();
DateTimeType inputType = inferInputType(input);
Expand All @@ -293,6 +390,18 @@ public Integer extractMinute(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractSecond(java.sql.Date value) {
return 0;
}

public Integer extractSecond(java.sql.Timestamp value) {
return value == null ? 0 : value.toLocalDateTime().getSecond();
}

public Integer extractSecond(java.sql.Time value) {
return value == null ? 0 : value.toLocalTime().getSecond();
}

public Integer extractSecond(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.second();
DateTimeType inputType = inferInputType(input);
Expand All @@ -310,6 +419,17 @@ public Integer extractSecond(Object input) {
+ (result.getErrorMessage() != null ? result.getErrorMessage() : "Unknown error"));
}

public Integer extractMillisecond(java.sql.Date value) {
return 0;
}

public Integer extractMillisecond(java.sql.Timestamp value) {
if (value == null) {
return 0;
}
return value.toLocalDateTime().getNano() / 1_000_000;
}

public Integer extractMillisecond(Object input) {
ExtractionOperations.ExtractFieldOperation operation = ExtractionOperations.millisecond();
DateTimeType inputType = inferInputType(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ default void setProcessor(DingoTimeZoneProcessor processor) {
}

default DingoTimeZoneProcessor getProcessor() {
return new DingoTimeZoneProcessor(ZoneId.systemDefault());
return DefaultProcessorHolder.INSTANCE;
}

default DateTimeFormatter[] getParseDateFormatters() {
Expand Down Expand Up @@ -122,4 +122,11 @@ default DateTimeFormatter getOutputTimeFormatter() {
default DateTimeFormatter getOutputTimestampFormatter() {
return DateTimeUtils.DEFAULT_OUTPUT_TIMESTAMP_FORMATTER;
}

// Lazy initialization holder for the default DingoTimeZoneProcessor singleton.
// Avoids creating a new processor instance on every getProcessor() call.
class DefaultProcessorHolder {
static final DingoTimeZoneProcessor INSTANCE =
new DingoTimeZoneProcessor(ZoneId.systemDefault());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public Object eval(EvalContext context, ExprConfig config) {

@Override
public boolean isConst(@NonNull NullaryOpExpr expr) {
return false;
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public Type getType() {

@Override
public boolean isConst(@NonNull NullaryOpExpr expr) {
return false;
return true;
}

@Override
Expand Down
Loading