Skip to content

Commit

Permalink
Merge 'Add partial support for datetime() function' from Preston Thorpe
Browse files Browse the repository at this point in the history
This PR adds the `datetime` function, with all the support currently
that date/time have for modifiers, and `julianday` function, as well as
some additional modifiers for date/time/datetime.
There are a couple considerations here, I left a couple comments but
essentially there is going to have to be some more work done to track
the state of the expression during the application of modifiers, to
handle a bunch of edge-cases like re-applying the same timezone modifier
to itself, or converting an integer automatically assumed to be
julianday, into epoch, or `ceiling`/`floor` which will determine
relative addition of time in cases like
```
2024-01-31 +1 month = 2024-03-02
```
which was painful enough to get working to begin with.
I couldn't get the `julianday_converter` library to get the exact same
float precision as sqlite, so function is included that matches their
output, for some reason floating point math + `.floor()` would give the
correct result. They seem to 'round' to 8 decimal places, and I was able
to get this to work with the same output as sqlite, except in cases like
`2234.5`, in which case we return `2234.5000000` because of the `fmt`
precision:
```rust
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()),
    }
}
```
Suggestions would be appreciated on the float precision issue.

Reviewed-by: Sonny <[email protected]>

Closes #600
  • Loading branch information
penberg committed Jan 5, 2025
2 parents 651442d + ca428b3 commit ba28999
Show file tree
Hide file tree
Showing 6 changed files with 944 additions and 136 deletions.
31 changes: 29 additions & 2 deletions COMPAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,39 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|-------------|---------|------------------------------|
| date() | Yes | partially supports modifiers |
| time() | Yes | partially supports modifiers |
| datetime() | No | |
| julianday() | No | |
| datetime() | Yes | partially supports modifiers |
| julianday() | Partial | does not support modifiers |
| unixepoch() | Partial | does not support modifiers |
| strftime() | No | |
| timediff() | No | |

### Date and Time Modifiers
| Modifier | Status| Comment |
|----------------|-------|---------------------------------|
| Days | Yes | |
| Hours | Yes | |
| Minutes | Yes | |
| Seconds | Yes | |
| Months | Yes | |
| Years | Yes | |
| TimeOffset | Yes | |
| DateOffset | Yes | |
| DateTimeOffset | Yes | |
| Ceiling | No | |
| Floor | No | |
| StartOfMonth | Yes | |
| StartOfYear | Yes | |
| StartOfDay | Yes | |
| Weekday(N) | Yes | |
| Auto | No | |
| UnixEpoch | No | |
| JulianDay | No | |
| Localtime |Partial| requires fixes to avoid double conversions.|
| Utc |Partial| requires fixes to avoid double conversions.|
| Subsec | Yes | |



### JSON functions

| Function | Status | Comment |
Expand Down
6 changes: 6 additions & 0 deletions core/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ pub enum ScalarFunc {
Date,
Time,
TotalChanges,
DateTime,
Typeof,
Unicode,
Quote,
SqliteVersion,
UnixEpoch,
JulianDay,
Hex,
Unhex,
ZeroBlob,
Expand Down Expand Up @@ -157,12 +159,14 @@ impl Display for ScalarFunc {
Self::Unicode => "unicode".to_string(),
Self::Quote => "quote".to_string(),
Self::SqliteVersion => "sqlite_version".to_string(),
Self::JulianDay => "julianday".to_string(),
Self::UnixEpoch => "unixepoch".to_string(),
Self::Hex => "hex".to_string(),
Self::Unhex => "unhex".to_string(),
Self::ZeroBlob => "zeroblob".to_string(),
Self::LastInsertRowid => "last_insert_rowid".to_string(),
Self::Replace => "replace".to_string(),
Self::DateTime => "datetime".to_string(),
};
write!(f, "{}", str)
}
Expand Down Expand Up @@ -352,6 +356,7 @@ impl Func {
"substring" => Ok(Self::Scalar(ScalarFunc::Substring)),
"date" => Ok(Self::Scalar(ScalarFunc::Date)),
"time" => Ok(Self::Scalar(ScalarFunc::Time)),
"datetime" => Ok(Self::Scalar(ScalarFunc::DateTime)),
"typeof" => Ok(Self::Scalar(ScalarFunc::Typeof)),
"last_insert_rowid" => Ok(Self::Scalar(ScalarFunc::LastInsertRowid)),
"unicode" => Ok(Self::Scalar(ScalarFunc::Unicode)),
Expand All @@ -367,6 +372,7 @@ impl Func {
#[cfg(feature = "json")]
"json_extract" => Ok(Func::Json(JsonFunc::JsonExtract)),
"unixepoch" => Ok(Self::Scalar(ScalarFunc::UnixEpoch)),
"julianday" => Ok(Self::Scalar(ScalarFunc::JulianDay)),
"hex" => Ok(Self::Scalar(ScalarFunc::Hex)),
"unhex" => Ok(Self::Scalar(ScalarFunc::Unhex)),
"zeroblob" => Ok(Self::Scalar(ScalarFunc::ZeroBlob)),
Expand Down
6 changes: 3 additions & 3 deletions core/translate/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,7 @@ pub fn translate_expr(
});
Ok(target_register)
}
ScalarFunc::Date => {
ScalarFunc::Date | ScalarFunc::DateTime => {
if let Some(args) = args {
for arg in args.iter() {
// register containing result of each argument expression
Expand Down Expand Up @@ -1334,11 +1334,11 @@ pub fn translate_expr(
});
Ok(target_register)
}
ScalarFunc::UnixEpoch => {
ScalarFunc::UnixEpoch | ScalarFunc::JulianDay => {
let mut start_reg = 0;
match args {
Some(args) if args.len() > 1 => {
crate::bail_parse_error!("epoch function with > 1 arguments. Modifiers are not yet supported.");
crate::bail_parse_error!("epoch or julianday function with > 1 arguments. Modifiers are not yet supported.");
}
Some(args) if args.len() == 1 => {
let arg_reg = program.alloc_register();
Expand Down
Loading

0 comments on commit ba28999

Please sign in to comment.