From 6684fb46e445441263ff8878c5f886029a66daa2 Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Mon, 5 Aug 2024 07:17:04 +0530 Subject: [PATCH 1/6] FEAT: Implement the unixepoch function Signed-off-by: Rajiv Harlalka --- core/function.rs | 3 +++ core/translate/expr.rs | 10 +++++++++- core/vdbe/datetime.rs | 4 ++++ core/vdbe/mod.rs | 9 +++++++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/core/function.rs b/core/function.rs index 9bd7bdc3a..ae1ab0966 100644 --- a/core/function.rs +++ b/core/function.rs @@ -63,6 +63,7 @@ pub enum ScalarFunc { Time, Unicode, Quote, + UnixEpoch, } impl ToString for ScalarFunc { @@ -91,6 +92,7 @@ impl ToString for ScalarFunc { ScalarFunc::Time => "time".to_string(), ScalarFunc::Unicode => "unicode".to_string(), ScalarFunc::Quote => "quote".to_string(), + ScalarFunc::UnixEpoch => "unixepoch".to_string(), } } } @@ -137,6 +139,7 @@ impl Func { "unicode" => Ok(Func::Scalar(ScalarFunc::Unicode)), "quote" => Ok(Func::Scalar(ScalarFunc::Quote)), "json" => Ok(Func::Json(JsonFunc::JSON)), + "unixepoch" => Ok(Func::Scalar(ScalarFunc::UnixEpoch)), _ => Err(()), } } diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 9eba86073..991fc5d70 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -941,7 +941,15 @@ pub fn translate_expr( dest: target_register, func: crate::vdbe::Func::Scalar(ScalarFunc::Substring), }); - + Ok(target_register) + } + ScalarFunc::UnixEpoch => { + let start_reg = program.alloc_register(); + program.emit_insn(Insn::Function { + start_reg, + dest: target_register, + func: crate::vdbe::Func::Scalar(srf), + }); Ok(target_register) } ScalarFunc::Time => { diff --git a/core/vdbe/datetime.rs b/core/vdbe/datetime.rs index a56abff33..faa0da446 100644 --- a/core/vdbe/datetime.rs +++ b/core/vdbe/datetime.rs @@ -94,6 +94,10 @@ fn apply_modifier(dt: &mut NaiveDateTime, modifier: &str) -> Result<()> { Ok(()) } +pub fn exec_unixepoch() -> Result { + Ok((Utc::now().timestamp()).to_string()) +} + fn parse_naive_date_time(time_value: &OwnedValue) -> Option { match time_value { OwnedValue::Text(s) => get_date_time_from_time_value_string(s), diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index d31cb636c..bdb976a8b 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -33,7 +33,7 @@ use crate::storage::{btree::BTreeCursor, pager::Pager}; use crate::types::{AggContext, Cursor, CursorResult, OwnedRecord, OwnedValue, Record}; use crate::Result; -use datetime::{exec_date, exec_time}; +use datetime::{exec_date, exec_time, exec_unixepoch}; use rand::distributions::{Distribution, Uniform}; use rand::{thread_rng, Rng}; @@ -1365,7 +1365,12 @@ impl Program { state.registers[*dest] = result; state.pc += 1; } - Func::Scalar(ScalarFunc::Unicode) => { + Func::UnixEpoch => { + let unixepoch: String = exec_unixepoch()?; + state.registers[*dest] = OwnedValue::Text(Rc::new(unixepoch)); + state.pc += 1 + } + Func::Unicode => { let reg_value = state.registers[*start_reg].borrow_mut(); state.registers[*dest] = exec_unicode(reg_value); state.pc += 1; From 1de974253baad4f1647a3126a90149cbc7297afa Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Tue, 6 Aug 2024 15:13:39 +0530 Subject: [PATCH 2/6] add support for custom date time value as first parameter Signed-off-by: Rajiv Harlalka --- core/translate/expr.rs | 17 ++++++++++++++++- core/vdbe/datetime.rs | 13 +++++++++++-- core/vdbe/mod.rs | 25 +++++++++++++++++++++---- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 991fc5d70..b834f2a97 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -944,7 +944,22 @@ pub fn translate_expr( Ok(target_register) } ScalarFunc::UnixEpoch => { - let start_reg = program.alloc_register(); + let mut start_reg = 0; + if let Some(args) = args { + if args.len() > 1 { + crate::bail_parse_error!("epoch function with > 1 arguments. Modifiers are not yet supported."); + } else if args.len() == 1 { + let arg_reg = program.alloc_register(); + let _ = translate_expr( + program, + referenced_tables, + &args[0], + arg_reg, + cursor_hint, + )?; + start_reg = arg_reg; + } + } program.emit_insn(Insn::Function { start_reg, dest: target_register, diff --git a/core/vdbe/datetime.rs b/core/vdbe/datetime.rs index faa0da446..b0bebae01 100644 --- a/core/vdbe/datetime.rs +++ b/core/vdbe/datetime.rs @@ -94,8 +94,17 @@ fn apply_modifier(dt: &mut NaiveDateTime, modifier: &str) -> Result<()> { Ok(()) } -pub fn exec_unixepoch() -> Result { - Ok((Utc::now().timestamp()).to_string()) +pub fn exec_unixepoch(time_value: &OwnedValue) -> Result { + let dt = parse_naive_date_time(time_value); + match dt { + Some(dt) => Ok(get_unixepoch_from_naive_datetime(dt)), + None => Ok(String::new()), + } + // Ok((Utc::now().timestamp()).to_string()) +} + +fn get_unixepoch_from_naive_datetime(value: NaiveDateTime) -> String { + return value.and_utc().timestamp().to_string(); } fn parse_naive_date_time(time_value: &OwnedValue) -> Option { diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index bdb976a8b..aefe6c271 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -1365,12 +1365,29 @@ impl Program { state.registers[*dest] = result; state.pc += 1; } - Func::UnixEpoch => { - let unixepoch: String = exec_unixepoch()?; - state.registers[*dest] = OwnedValue::Text(Rc::new(unixepoch)); + Func::Scalar(ScalarFunc::UnixEpoch) => { + if *start_reg == 0 { + let unixepoch: String = + exec_unixepoch(&OwnedValue::Text(Rc::new("now".to_string())))?; + state.registers[*dest] = OwnedValue::Text(Rc::new(unixepoch)); + } else { + let datetime_value = &state.registers[*start_reg]; + let unixepoch = exec_unixepoch(datetime_value); + match unixepoch { + Ok(time) => { + state.registers[*dest] = OwnedValue::Text(Rc::new(time)) + } + Err(e) => { + return Err(LimboError::ParseError(format!( + "Error encountered while parsing datetime value: {}", + e + ))); + } + } + } state.pc += 1 } - Func::Unicode => { + Func::Scalar(ScalarFunc::Unicode) => { let reg_value = state.registers[*start_reg].borrow_mut(); state.registers[*dest] = exec_unicode(reg_value); state.pc += 1; From e2013b0ef6e530ca47ce7c8b04335193c4549884 Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Tue, 6 Aug 2024 15:22:49 +0530 Subject: [PATCH 3/6] add unixepoch tests Signed-off-by: Rajiv Harlalka --- testing/scalar-functions.test | 100 ++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/testing/scalar-functions.test b/testing/scalar-functions.test index 2113eae79..3d85bbdfc 100755 --- a/testing/scalar-functions.test +++ b/testing/scalar-functions.test @@ -403,6 +403,106 @@ do_execsql_test date-with-invalid-timezone { SELECT date('2023-05-18 15:30:45+25:00'); } {{}} +do_execsql_test time-no-arg { + SELECT length(time()) = 8; +} {1} + +do_execsql_test time-current-time { + SELECT length(time('now')) = 8; +} {1} + +do_execsql_test time-specific-time { + SELECT time('04:02:00'); +} {04:02:00} + +do_execsql_test time-of-datetime { + SELECT time('2023-05-18 15:30:45'); +} {15:30:45} + +do_execsql_test time-iso8601 { + SELECT time('2023-05-18T15:30:45'); +} {15:30:45} + +do_execsql_test time-with-milliseconds { + SELECT time('2023-05-18 15:30:45.123'); +} {15:30:45} + +do_execsql_test time-julian-day-integer { + SELECT time(2460082); +} {12:00:00} + +do_execsql_test time-julian-day-float { + SELECT time(2460082.2); +} {16:48:00} + +do_execsql_test time-invalid-input { + SELECT time('not a time'); +} {{}} + +do_execsql_test time-null-input { + SELECT time(NULL); +} {{}} + +do_execsql_test time-out-of-range { + SELECT time('25:05:01'); +} {{}} + +do_execsql_test time-date-only { + SELECT time('2024-02-02'); +} {00:00:00} + +do_execsql_test time-with-timezone-utc { + SELECT time('2023-05-18 15:30:45Z'); +} {15:30:45} + +do_execsql_test time-with-timezone-positive { + SELECT time('2023-05-18 23:30:45+07:00'); +} {16:30:45} + +do_execsql_test time-with-timezone-negative { + SELECT time('2023-05-19 01:30:45-05:00'); +} {06:30:45} + +do_execsql_test time-with-timezone-day-change-positive { + SELECT time('2023-05-18 23:30:45-03:00'); +} {02:30:45} + +do_execsql_test time-with-timezone-day-change-negative { + SELECT time('2023-05-19 01:30:45+03:00'); +} {22:30:45} + +do_execsql_test time-with-timezone-iso8601 { + SELECT time('2023-05-18T15:30:45+02:00'); +} {13:30:45} + +do_execsql_test time-with-timezone-and-milliseconds { + SELECT time('2023-05-18 15:30:45.123+02:00'); +} {13:30:45} + +do_execsql_test time-with-invalid-timezone { + SELECT time('2023-05-18 15:30:45+25:00'); +} {{}} + +do_execsql_test unixepoch-at-start { + SELECT unixepoch('1970-01-01'); +} {0} + +do_execsql_test unixepoch-at-1-second-before-epochtime { + SELECT unixepoch('1969-12-31 23:59:59'); +} {-1} + +do_execsql_test unixepoch-at-future { + SELECT unixepoch('9999-12-31 23:59:59'); +} {253402300799} + +do_execsql_test unixepoch-at-start-of-time { + SELECT unixepoch('0000-01-01 00:00:00'); +} {-62167219200} + +do_execsql_test unixepoch-at-millisecond-precision-input-produces-seconds-precision-output { + SELECT unixepoch('2022-01-27 12:59:28.052'); +} {1643288368} + do_execsql_test unicode-a { SELECT unicode('a'); } {97} From 0b5b0a426dcf9b923af816c2ec673cdabc24e4e2 Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Sun, 25 Aug 2024 11:02:28 +0530 Subject: [PATCH 4/6] remove redundant comment Signed-off-by: Rajiv Harlalka --- core/vdbe/datetime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vdbe/datetime.rs b/core/vdbe/datetime.rs index b0bebae01..8f9c91a2b 100644 --- a/core/vdbe/datetime.rs +++ b/core/vdbe/datetime.rs @@ -100,7 +100,6 @@ pub fn exec_unixepoch(time_value: &OwnedValue) -> Result { Some(dt) => Ok(get_unixepoch_from_naive_datetime(dt)), None => Ok(String::new()), } - // Ok((Utc::now().timestamp()).to_string()) } fn get_unixepoch_from_naive_datetime(value: NaiveDateTime) -> String { From 3447a553e16734705b0874d0b734d9324a4df44e Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Fri, 30 Aug 2024 20:30:06 +0530 Subject: [PATCH 5/6] chore: move tests Signed-off-by: Rajiv Harlalka --- testing/scalar-functions-datetime.test | 20 +++++ testing/scalar-functions.test | 102 +------------------------ 2 files changed, 21 insertions(+), 101 deletions(-) diff --git a/testing/scalar-functions-datetime.test b/testing/scalar-functions-datetime.test index 13cbf9a01..8cf53a316 100755 --- a/testing/scalar-functions-datetime.test +++ b/testing/scalar-functions-datetime.test @@ -123,3 +123,23 @@ do_execsql_test time-with-invalid-modifier { SELECT time('2023-05-18 15:30:45', '+1 hour', 'invalid modifier'); } {{}} + +do_execsql_test unixepoch-at-start { + SELECT unixepoch('1970-01-01'); +} {0} + +do_execsql_test unixepoch-at-1-second-before-epochtime { + SELECT unixepoch('1969-12-31 23:59:59'); +} {-1} + +do_execsql_test unixepoch-at-future { + SELECT unixepoch('9999-12-31 23:59:59'); +} {253402300799} + +do_execsql_test unixepoch-at-start-of-time { + SELECT unixepoch('0000-01-01 00:00:00'); +} {-62167219200} + +do_execsql_test unixepoch-at-millisecond-precision-input-produces-seconds-precision-output { + SELECT unixepoch('2022-01-27 12:59:28.052'); +} {1643288368} \ No newline at end of file diff --git a/testing/scalar-functions.test b/testing/scalar-functions.test index 3d85bbdfc..07d54a1f9 100755 --- a/testing/scalar-functions.test +++ b/testing/scalar-functions.test @@ -403,106 +403,6 @@ do_execsql_test date-with-invalid-timezone { SELECT date('2023-05-18 15:30:45+25:00'); } {{}} -do_execsql_test time-no-arg { - SELECT length(time()) = 8; -} {1} - -do_execsql_test time-current-time { - SELECT length(time('now')) = 8; -} {1} - -do_execsql_test time-specific-time { - SELECT time('04:02:00'); -} {04:02:00} - -do_execsql_test time-of-datetime { - SELECT time('2023-05-18 15:30:45'); -} {15:30:45} - -do_execsql_test time-iso8601 { - SELECT time('2023-05-18T15:30:45'); -} {15:30:45} - -do_execsql_test time-with-milliseconds { - SELECT time('2023-05-18 15:30:45.123'); -} {15:30:45} - -do_execsql_test time-julian-day-integer { - SELECT time(2460082); -} {12:00:00} - -do_execsql_test time-julian-day-float { - SELECT time(2460082.2); -} {16:48:00} - -do_execsql_test time-invalid-input { - SELECT time('not a time'); -} {{}} - -do_execsql_test time-null-input { - SELECT time(NULL); -} {{}} - -do_execsql_test time-out-of-range { - SELECT time('25:05:01'); -} {{}} - -do_execsql_test time-date-only { - SELECT time('2024-02-02'); -} {00:00:00} - -do_execsql_test time-with-timezone-utc { - SELECT time('2023-05-18 15:30:45Z'); -} {15:30:45} - -do_execsql_test time-with-timezone-positive { - SELECT time('2023-05-18 23:30:45+07:00'); -} {16:30:45} - -do_execsql_test time-with-timezone-negative { - SELECT time('2023-05-19 01:30:45-05:00'); -} {06:30:45} - -do_execsql_test time-with-timezone-day-change-positive { - SELECT time('2023-05-18 23:30:45-03:00'); -} {02:30:45} - -do_execsql_test time-with-timezone-day-change-negative { - SELECT time('2023-05-19 01:30:45+03:00'); -} {22:30:45} - -do_execsql_test time-with-timezone-iso8601 { - SELECT time('2023-05-18T15:30:45+02:00'); -} {13:30:45} - -do_execsql_test time-with-timezone-and-milliseconds { - SELECT time('2023-05-18 15:30:45.123+02:00'); -} {13:30:45} - -do_execsql_test time-with-invalid-timezone { - SELECT time('2023-05-18 15:30:45+25:00'); -} {{}} - -do_execsql_test unixepoch-at-start { - SELECT unixepoch('1970-01-01'); -} {0} - -do_execsql_test unixepoch-at-1-second-before-epochtime { - SELECT unixepoch('1969-12-31 23:59:59'); -} {-1} - -do_execsql_test unixepoch-at-future { - SELECT unixepoch('9999-12-31 23:59:59'); -} {253402300799} - -do_execsql_test unixepoch-at-start-of-time { - SELECT unixepoch('0000-01-01 00:00:00'); -} {-62167219200} - -do_execsql_test unixepoch-at-millisecond-precision-input-produces-seconds-precision-output { - SELECT unixepoch('2022-01-27 12:59:28.052'); -} {1643288368} - do_execsql_test unicode-a { SELECT unicode('a'); } {97} @@ -541,4 +441,4 @@ do_execsql_test quote-null { do_execsql_test quote-integer { SELECT quote(123) -} {123} +} {123} \ No newline at end of file From b30974d2d228459737ae8ba05366e6759a2dc588 Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Fri, 30 Aug 2024 20:35:12 +0530 Subject: [PATCH 6/6] update COMPAT.md Signed-off-by: Rajiv Harlalka --- COMPAT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPAT.md b/COMPAT.md index ebf8ab655..421b1e9d0 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -143,7 +143,7 @@ This document describes the SQLite compatibility status of Limbo: | time() | Partial | partially supports modifiers | | datetime() | No | | | julianday() | No | | -| unixepoch() | No | | +| unixepoch() | Partial | does not support modifiers | | strftime() | No | | | timediff() | No | |