Skip to content

Commit

Permalink
fix corner cases
Browse files Browse the repository at this point in the history
  • Loading branch information
KeXiangWang committed Dec 19, 2023
1 parent a7ffbf4 commit cc7fb7a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 34 deletions.
32 changes: 21 additions & 11 deletions e2e_test/batch/functions/to_char.slt.part
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,24 @@ select to_char('0year 0 days 0hours'::interval, 'YYYY IYYY YY IY MM DD PM pm HH
0000 -001 00 -1 00 00 AM am 12 00 00 00

query T
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS');
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'YYYY IYYY YY IY MM DD PM pm HH12 HH24 MI SS MS US');
----
01 01 01 AM 01 01 01
0001 0001 01 01 01 01 AM am 01 01 01 01 000 000000

query T
select to_char('-1year -1month -1day -1hours -1minute -1second'::interval, 'IY MM DD AM HH12 MM SS');
select to_char('-1year -1month -1day -1hours -1minute -1second'::interval, 'YYYY IYYY YY IY MM DD PM pm HH12 HH24 MI SS MS US');
----
-02 -01 -1 AM -01 -01 -01
-0001 -0002 -01 -02 -01 -1 AM am -01 -01 -01 -01 000 000000

query T
select to_char('23:22:57.124562'::interval, 'HH12 MI SS MS US');
----
11 22 57 124 124562

query T
select to_char('-23:22:57.124562'::interval, 'HH12 MI SS MS US');
----
-11 -22 -57 -124 -124562

query error
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS tzhtzm');
Expand All @@ -107,7 +117,7 @@ Caused by these errors (recent errors listed first):


query error
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS TZH:TZM');
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MI SS TZH:TZM');
----
db error: ERROR: Failed to run the query

Expand All @@ -117,30 +127,30 @@ Caused by these errors (recent errors listed first):


query error
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS TZH');
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MI SS TZH');
----
db error: ERROR: Failed to run the query

Caused by these errors (recent errors listed first):
1: Expr error
2: Invalid parameter pattern: unsupported format specification for an interval value.
2: Invalid parameter pattern: invalid format specification for an interval value, HINT: Intervals are not tied to specific calendar dates.


query error
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS US');
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MI SS Month');
----
db error: ERROR: Failed to run the query

Caused by these errors (recent errors listed first):
1: Expr error
2: Invalid parameter pattern: unsupported format specification for an interval value.
2: Invalid parameter pattern: invalid format specification for an interval value, HINT: Intervals are not tied to specific calendar dates.


query error
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MM SS MS');
select to_char('1year 1month 1day 1hours 1minute 1second'::interval, 'IY MM DD AM HH12 MI SS Mon');
----
db error: ERROR: Failed to run the query

Caused by these errors (recent errors listed first):
1: Expr error
2: Invalid parameter pattern: unsupported format specification for an interval value.
2: Invalid parameter pattern: invalid format specification for an interval value, HINT: Intervals are not tied to specific calendar dates.
41 changes: 22 additions & 19 deletions src/expr/impl/src/scalar/to_char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ fn invalid_pattern_err() -> ExprError {
}
}

#[inline(always)]
fn unsupported_pattern_err() -> ExprError {
ExprError::InvalidParam {
name: "pattern",
reason: "unsupported format specification for an interval value.".into(),
}
}

self_cell::self_cell! {
pub struct ChronoPattern {
owner: String,
Expand All @@ -62,7 +54,7 @@ impl ChronoPattern {
/// Compile the pg pattern to chrono pattern.
// TODO: Chrono can not fully support the pg format, so consider using other implementations
// later.
pub fn compile(tmpl: &str) -> ChronoPattern {
pub fn compile(tmpl: &str, is_interval: bool) -> ChronoPattern {
// mapping from pg pattern to chrono pattern
// pg pattern: https://www.postgresql.org/docs/current/functions-formatting.html
// chrono pattern: https://docs.rs/chrono/latest/chrono/format/strftime/index.html
Expand Down Expand Up @@ -118,7 +110,13 @@ impl ChronoPattern {
// replace all pg patterns with chrono patterns
let mut chrono_tmpl = String::new();
AC.replace_all_with(tmpl, &mut chrono_tmpl, |mat, _, dst| {
dst.push_str(PATTERNS[mat.pattern()].1);
if is_interval && PATTERNS[mat.pattern()].1 == "%6f" {
dst.push_str("%.6f");
} else if is_interval && PATTERNS[mat.pattern()].1 == "%3f" {
dst.push_str("%.3f");
} else {
dst.push_str(PATTERNS[mat.pattern()].1);
}
true
});
tracing::debug!(tmpl, chrono_tmpl, "compile_pattern_to_chrono");
Expand All @@ -130,7 +128,7 @@ impl ChronoPattern {

#[function(
"to_char(timestamp, varchar) -> varchar",
prebuild = "ChronoPattern::compile($1)"
prebuild = "ChronoPattern::compile($1, false)"
)]
fn timestamp_to_char(data: Timestamp, pattern: &ChronoPattern, writer: &mut impl Write) {
let format = data.0.format_with_items(pattern.borrow_dependent().iter());
Expand All @@ -142,7 +140,7 @@ fn _timestamptz_to_char() {}

#[function(
"to_char(timestamptz, varchar, varchar) -> varchar",
prebuild = "ChronoPattern::compile($1)"
prebuild = "ChronoPattern::compile($1, false)"
)]
fn timestamptz_to_char3(
data: Timestamptz,
Expand All @@ -159,7 +157,7 @@ fn timestamptz_to_char3(

#[function(
"to_char(interval, varchar) -> varchar",
prebuild = "ChronoPattern::compile($1)"
prebuild = "ChronoPattern::compile($1, true)"
)]
fn interval_to_char(
interval: Interval,
Expand Down Expand Up @@ -319,10 +317,17 @@ fn format_inner(w: &mut impl Write, interval: Interval, item: &Item<'_>) -> Resu
}
Ok(())
}
// TODO: support Internal(_), Nanosecond3NoDot and Nanosecond6NoDot are valid.
// TimezoneOffsetPermissive and Nanosecond9NoDot are invalid.
Internal(_) => Err(unsupported_pattern_err()),
ShortMonthName | LongMonthName | TimezoneOffset | TimezoneOffsetZ
Nanosecond3 => {
let usec = interval.usecs() % 1_000_000;
write!(w, "{:03}", usec / 1000).unwrap();
Ok(())
}
Nanosecond6 => {
let usec = interval.usecs() % 1_000_000;
write!(w, "{:06}", usec).unwrap();
Ok(())
}
Internal(_) | ShortMonthName | LongMonthName | TimezoneOffset | TimezoneOffsetZ
| TimezoneOffsetColon => Err(invalid_pattern_err()),
ShortWeekdayName
| LongWeekdayName
Expand All @@ -331,8 +336,6 @@ fn format_inner(w: &mut impl Write, interval: Interval, item: &Item<'_>) -> Resu
| TimezoneOffsetTripleColon
| TimezoneOffsetColonZ
| Nanosecond
| Nanosecond3
| Nanosecond6
| Nanosecond9
| RFC2822
| RFC3339 => unreachable!(),
Expand Down
9 changes: 5 additions & 4 deletions src/expr/impl/src/scalar/to_timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ fn parse(s: &str, tmpl: &ChronoPattern) -> Result<Parsed> {

#[function(
"to_timestamp1(varchar, varchar) -> timestamp",
prebuild = "ChronoPattern::compile($1)",
prebuild = "ChronoPattern::compile($1, false)",
deprecated
)]
pub fn to_timestamp_legacy(s: &str, tmpl: &ChronoPattern) -> Result<Timestamp> {
Expand All @@ -82,7 +82,7 @@ pub fn to_timestamp_legacy(s: &str, tmpl: &ChronoPattern) -> Result<Timestamp> {

#[function(
"to_timestamp1(varchar, varchar, varchar) -> timestamptz",
prebuild = "ChronoPattern::compile($1)"
prebuild = "ChronoPattern::compile($1, false)"
)]
pub fn to_timestamp(s: &str, timezone: &str, tmpl: &ChronoPattern) -> Result<Timestamptz> {
let parsed = parse(s, tmpl)?;
Expand All @@ -98,7 +98,7 @@ fn _to_timestamp1() {}

#[function(
"char_to_date(varchar, varchar) -> date",
prebuild = "ChronoPattern::compile($1)"
prebuild = "ChronoPattern::compile($1, false)"
)]
pub fn to_date(s: &str, tmpl: &ChronoPattern) -> Result<Date> {
let mut parsed = parse(s, tmpl)?;
Expand Down Expand Up @@ -130,7 +130,8 @@ mod tests {
"2020-02-03 09:34:56",
),
] {
let actual = to_timestamp_legacy(input, &ChronoPattern::compile(format)).unwrap();
let actual =
to_timestamp_legacy(input, &ChronoPattern::compile(format, false)).unwrap();
assert_eq!(actual.to_string(), expected);
}
}
Expand Down

0 comments on commit cc7fb7a

Please sign in to comment.