Skip to content

Commit

Permalink
[CALCITE-6585] In the Postgres TO_CHAR function, improve caching
Browse files Browse the repository at this point in the history
* Refactored code to separate parsing a date/time format and applying it
* A parsed date/time format can now be reused
* Fixed up some minor issues with when to space pad day or month names
  • Loading branch information
normanj-bitquill committed Sep 24, 2024
1 parent 963f898 commit e0f012b
Show file tree
Hide file tree
Showing 40 changed files with 2,500 additions and 1,763 deletions.
12 changes: 6 additions & 6 deletions babel/src/test/resources/sql/postgresql.iq
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,17 @@ EXPR$0
a.d.
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'MONTH');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMMONTH');
EXPR$0
JUNE
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'Month');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMMonth');
EXPR$0
June
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'month');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMmonth');
EXPR$0
june
!ok
Expand All @@ -293,17 +293,17 @@ EXPR$0
jun
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'DAY');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMDAY');
EXPR$0
FRIDAY
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'Day');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMDay');
EXPR$0
Friday
!ok

select to_char(timestamp '2022-06-03 12:15:48.678', 'day');
select to_char(timestamp '2022-06-03 12:15:48.678', 'FMday');
EXPR$0
friday
!ok
Expand Down
22 changes: 15 additions & 7 deletions core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.calcite.util.format.FormatElement;
import org.apache.calcite.util.format.FormatModel;
import org.apache.calcite.util.format.FormatModels;
import org.apache.calcite.util.format.postgresql.CompiledDateTimeFormat;
import org.apache.calcite.util.format.postgresql.PostgresqlDateTimeFormatter;

import org.apache.commons.codec.DecoderException;
Expand Down Expand Up @@ -4372,6 +4373,11 @@ private static class Key extends MapEntry<FormatModel, String> {
.maximumSize(FUNCTION_LEVEL_CACHE_MAX_SIZE.value())
.build(CacheLoader.from(key -> key.t.parseNoCache(key.u)));

private static final LoadingCache<String, CompiledDateTimeFormat> FORMAT_CACHE_PG =
CacheBuilder.newBuilder()
.maximumSize(FUNCTION_LEVEL_CACHE_MAX_SIZE.value())
.build(CacheLoader.from(PostgresqlDateTimeFormatter::compilePattern));

/** Given a format string and a format model, calls an action with the
* list of elements obtained by parsing that format string. */
protected final void withElements(FormatModel formatModel, String format,
Expand Down Expand Up @@ -4405,10 +4411,11 @@ public String toChar(long timestamp, String pattern) {
public static String toCharPg(DataContext root, long timestamp, String pattern) {
final ZoneId zoneId = DataContext.Variable.TIME_ZONE.<TimeZone>get(root).toZoneId();
final Locale locale = requireNonNull(DataContext.Variable.LOCALE.get(root));
final CompiledDateTimeFormat dateTimeFormat = FORMAT_CACHE_PG.getUnchecked(pattern);
final Timestamp sqlTimestamp = internalToTimestamp(timestamp);
final ZonedDateTime zonedDateTime =
ZonedDateTime.of(sqlTimestamp.toLocalDateTime(), zoneId);
return PostgresqlDateTimeFormatter.toChar(pattern, zonedDateTime, locale).trim();
return dateTimeFormat.formatDateTime(zonedDateTime, locale);
}

public int toDate(String dateString, String fmtString) {
Expand All @@ -4419,9 +4426,9 @@ public int toDate(String dateString, String fmtString) {
public static int toDatePg(DataContext root, String dateString, String fmtString) {
try {
final Locale locale = requireNonNull(DataContext.Variable.LOCALE.get(root));
return (int) PostgresqlDateTimeFormatter.toTimestamp(dateString, fmtString, LOCAL_ZONE,
locale)
.getLong(ChronoField.EPOCH_DAY);
final CompiledDateTimeFormat dateTimeFormat = FORMAT_CACHE_PG.getUnchecked(fmtString);
return (int) dateTimeFormat.parseDateTime(dateString, LOCAL_ZONE, locale).getLong(
ChronoField.EPOCH_DAY);
} catch (Exception e) {
SQLException sqlEx =
new SQLException(
Expand All @@ -4440,9 +4447,10 @@ public long toTimestamp(String timestampString, String fmtString) {
public static long toTimestampPg(DataContext root, String timestampString, String fmtString) {
try {
final Locale locale = requireNonNull(DataContext.Variable.LOCALE.get(root));
return PostgresqlDateTimeFormatter.toTimestamp(timestampString, fmtString, LOCAL_ZONE,
locale)
.toInstant().toEpochMilli();
final CompiledDateTimeFormat dateTimeFormat = FORMAT_CACHE_PG.getUnchecked(fmtString);
return dateTimeFormat.parseDateTime(timestampString, LOCAL_ZONE, locale)
.toInstant()
.toEpochMilli();
} catch (Exception e) {
SQLException sqlEx =
new SQLException(
Expand Down
Loading

0 comments on commit e0f012b

Please sign in to comment.