mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
Merge 'support modifiers for julianday()' from meteorgan
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #1321
This commit is contained in:
commit
d20782350d
5 changed files with 46 additions and 67 deletions
|
@ -325,7 +325,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
|||
| date() | Yes | partially supports modifiers |
|
||||
| time() | Yes | partially supports modifiers |
|
||||
| datetime() | Yes | partially supports modifiers |
|
||||
| julianday() | Partial | does not support modifiers |
|
||||
| julianday() | Yes | partially support modifiers |
|
||||
| unixepoch() | Partial | does not support modifiers |
|
||||
| strftime() | Yes | partially supports modifiers |
|
||||
| timediff() | Yes | partially supports modifiers |
|
||||
|
|
|
@ -46,21 +46,13 @@ enum DateTimeOutput {
|
|||
DateTime,
|
||||
// Holds the format string
|
||||
StrfTime(String),
|
||||
JuliaDay,
|
||||
}
|
||||
|
||||
fn exec_datetime(values: &[Register], output_type: DateTimeOutput) -> OwnedValue {
|
||||
if values.is_empty() {
|
||||
let now = parse_naive_date_time(&OwnedValue::build_text("now")).unwrap();
|
||||
|
||||
let formatted_str = match output_type {
|
||||
DateTimeOutput::DateTime => now.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
DateTimeOutput::Time => now.format("%H:%M:%S").to_string(),
|
||||
DateTimeOutput::Date => now.format("%Y-%m-%d").to_string(),
|
||||
DateTimeOutput::StrfTime(ref format_str) => strftime_format(&now, format_str),
|
||||
};
|
||||
|
||||
// Parse here
|
||||
return OwnedValue::build_text(&formatted_str);
|
||||
return format_dt(now, output_type, false);
|
||||
}
|
||||
if let Some(mut dt) = parse_naive_date_time(values[0].get_owned_value()) {
|
||||
// if successful, treat subsequent entries as modifiers
|
||||
|
@ -91,28 +83,32 @@ fn modify_dt(dt: &mut NaiveDateTime, mods: &[Register], output_type: DateTimeOut
|
|||
if is_leap_second(dt) || *dt > get_max_datetime_exclusive() {
|
||||
return OwnedValue::build_text("");
|
||||
}
|
||||
let formatted = format_dt(*dt, output_type, subsec_requested);
|
||||
OwnedValue::build_text(&formatted)
|
||||
format_dt(*dt, output_type, subsec_requested)
|
||||
}
|
||||
|
||||
fn format_dt(dt: NaiveDateTime, output_type: DateTimeOutput, subsec: bool) -> String {
|
||||
fn format_dt(dt: NaiveDateTime, output_type: DateTimeOutput, subsec: bool) -> OwnedValue {
|
||||
match output_type {
|
||||
DateTimeOutput::Date => dt.format("%Y-%m-%d").to_string(),
|
||||
DateTimeOutput::Date => OwnedValue::from_text(dt.format("%Y-%m-%d").to_string().as_str()),
|
||||
DateTimeOutput::Time => {
|
||||
if subsec {
|
||||
let t = if subsec {
|
||||
dt.format("%H:%M:%S%.3f").to_string()
|
||||
} else {
|
||||
dt.format("%H:%M:%S").to_string()
|
||||
}
|
||||
};
|
||||
OwnedValue::from_text(t.as_str())
|
||||
}
|
||||
DateTimeOutput::DateTime => {
|
||||
if subsec {
|
||||
let t = if subsec {
|
||||
dt.format("%Y-%m-%d %H:%M:%S%.3f").to_string()
|
||||
} else {
|
||||
dt.format("%Y-%m-%d %H:%M:%S").to_string()
|
||||
}
|
||||
};
|
||||
OwnedValue::from_text(t.as_str())
|
||||
}
|
||||
DateTimeOutput::StrfTime(format_str) => strftime_format(&dt, &format_str),
|
||||
DateTimeOutput::StrfTime(format_str) => {
|
||||
OwnedValue::from_text(strftime_format(&dt, &format_str).as_str())
|
||||
}
|
||||
DateTimeOutput::JuliaDay => OwnedValue::Float(to_julian_day_exact(&dt)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,14 +321,8 @@ fn last_day_in_month(year: i32, month: u32) -> u32 {
|
|||
28
|
||||
}
|
||||
|
||||
pub fn exec_julianday(time_value: &OwnedValue) -> Result<String> {
|
||||
let dt = parse_naive_date_time(time_value);
|
||||
match dt {
|
||||
// if we did something heinous like: parse::<f64>().unwrap().to_string()
|
||||
// that would solve the precision issue, but dear lord...
|
||||
Some(dt) => Ok(format!("{:.1$}", to_julian_day_exact(&dt), 8)),
|
||||
None => Ok(String::new()),
|
||||
}
|
||||
pub fn exec_julianday(values: &[Register]) -> OwnedValue {
|
||||
exec_datetime(values, DateTimeOutput::JuliaDay)
|
||||
}
|
||||
|
||||
fn to_julian_day_exact(dt: &NaiveDateTime) -> f64 {
|
||||
|
|
|
@ -1159,7 +1159,7 @@ pub fn translate_expr(
|
|||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Date | ScalarFunc::DateTime => {
|
||||
ScalarFunc::Date | ScalarFunc::DateTime | ScalarFunc::JulianDay => {
|
||||
let start_reg = program
|
||||
.alloc_registers(args.as_ref().map(|x| x.len()).unwrap_or(1));
|
||||
if let Some(args) = args {
|
||||
|
@ -1259,11 +1259,11 @@ pub fn translate_expr(
|
|||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::UnixEpoch | ScalarFunc::JulianDay => {
|
||||
ScalarFunc::UnixEpoch => {
|
||||
let mut start_reg = 0;
|
||||
match args {
|
||||
Some(args) if args.len() > 1 => {
|
||||
crate::bail_parse_error!("epoch or julianday function with > 1 arguments. Modifiers are not yet supported.");
|
||||
crate::bail_parse_error!("epoch function with > 1 arguments. Modifiers are not yet supported.");
|
||||
}
|
||||
Some(args) if args.len() == 1 => {
|
||||
let arg_reg = program.alloc_register();
|
||||
|
|
|
@ -3341,26 +3341,8 @@ pub fn op_function(
|
|||
state.registers[*dest] = Register::OwnedValue(result);
|
||||
}
|
||||
ScalarFunc::JulianDay => {
|
||||
if *start_reg == 0 {
|
||||
let julianday: String = exec_julianday(&OwnedValue::build_text("now"))?;
|
||||
state.registers[*dest] =
|
||||
Register::OwnedValue(OwnedValue::build_text(&julianday));
|
||||
} else {
|
||||
let datetime_value = &state.registers[*start_reg];
|
||||
let julianday = exec_julianday(datetime_value.get_owned_value());
|
||||
match julianday {
|
||||
Ok(time) => {
|
||||
state.registers[*dest] =
|
||||
Register::OwnedValue(OwnedValue::build_text(&time))
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(LimboError::ParseError(format!(
|
||||
"Error encountered while parsing datetime value: {}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = exec_julianday(&state.registers[*start_reg..*start_reg + arg_count]);
|
||||
state.registers[*dest] = Register::OwnedValue(result);
|
||||
}
|
||||
ScalarFunc::UnixEpoch => {
|
||||
if *start_reg == 0 {
|
||||
|
|
|
@ -423,26 +423,33 @@ do_execsql_test julianday-time-only {
|
|||
SELECT julianday('15:30:45');
|
||||
} {2451545.14635417}
|
||||
|
||||
#
|
||||
# TODO: fix precision issue
|
||||
#
|
||||
#do_execsql_test julianday-midnight {
|
||||
# SELECT julianday('2023-05-18 00:00:00');
|
||||
#} {2460082.5}
|
||||
do_execsql_test julianday-midnight {
|
||||
SELECT julianday('2023-05-18 00:00:00');
|
||||
} {2460082.5}
|
||||
|
||||
#do_execsql_test julianday-noon {
|
||||
# SELECT julianday('2023-05-18 12:00:00');
|
||||
#} {2460083.0}
|
||||
do_execsql_test julianday-noon {
|
||||
SELECT julianday('2023-05-18 12:00:00');
|
||||
} {2460083.0}
|
||||
|
||||
#do_execsql_test julianday-fractional-zero {
|
||||
# SELECT julianday('2023-05-18 00:00:00.000');
|
||||
#} {2460082.5}
|
||||
do_execsql_test julianday-fractional-zero {
|
||||
SELECT julianday('2023-05-18 00:00:00.000');
|
||||
} {2460082.5}
|
||||
|
||||
# same issue as above, we return .5000000 because we are using fmt precision
|
||||
#do_execsql_test julianday-date-only {
|
||||
# SELECT julianday('2023-05-18');
|
||||
#} {2460082.5}
|
||||
do_execsql_test julianday-date-only {
|
||||
SELECT julianday('2023-05-18');
|
||||
} {2460082.5}
|
||||
|
||||
do_execsql_test julianday-with-modifier-day {
|
||||
SELECT julianday(2454832.5,'+1 day');
|
||||
} {2454833.5}
|
||||
|
||||
do_execsql_test julianday-with-modifier-hour {
|
||||
SELECT julianday(2454832.5,'-3 hours');
|
||||
} {2454832.375}
|
||||
|
||||
do_execsql_test julianday-max-day {
|
||||
SELECT julianday('9999-12-31 23:59:59');
|
||||
} {5373484.49998843}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue