uqa_sql/expr/
current_time.rs1use super::{age_between, coerce_temporal, EvalContext, Result, SQLError, TemporalValue, Value};
10
11#[must_use]
13pub fn clock_timestamp_micros() -> i64 {
14 chrono::Utc::now().timestamp_micros()
15}
16
17pub(super) fn eval_current_time(
18 name: &str,
19 args: &[Value],
20 context: Option<&EvalContext<'_>>,
21) -> Option<Result<Value>> {
22 if !(matches!(
23 name,
24 "now"
25 | "transaction_timestamp"
26 | "statement_timestamp"
27 | "current_timestamp"
28 | "current_date"
29 | "current_time"
30 | "localtime"
31 | "localtimestamp"
32 ) || name == "age" && args.len() == 1)
33 {
34 return None;
35 }
36 Some((|| {
37 if name == "age" && matches!(args, [Value::Null]) {
38 return Ok(Value::Null);
39 }
40 if name != "age" && !args.is_empty() {
41 return Err(SQLError::BadArity {
42 name: name.into(),
43 expected: "0".into(),
44 actual: args.len(),
45 });
46 }
47 let micros = context
48 .and_then(|context| context.engine)
49 .and_then(|engine| {
50 if name == "statement_timestamp" {
51 engine.statement_timestamp_micros()
52 } else {
53 engine.transaction_timestamp_micros()
54 }
55 })
56 .unwrap_or_else(clock_timestamp_micros);
57 const MICROS_PER_DAY: i64 = 86_400_000_000;
58 let value = match name {
59 "current_date" => TemporalValue::Date {
60 days: i32::try_from(micros.div_euclid(MICROS_PER_DAY)).map_err(|_| {
61 SQLError::Internal("current date exceeds its day carrier".into())
62 })?,
63 },
64 "current_time" => TemporalValue::TimeTz {
65 micros: micros.rem_euclid(MICROS_PER_DAY),
66 offset_minutes: 0,
67 },
68 "localtime" => TemporalValue::Time {
69 micros: micros.rem_euclid(MICROS_PER_DAY),
70 },
71 "localtimestamp" => TemporalValue::Timestamp { micros },
72 "age" => {
73 return age_between(
74 &TemporalValue::Timestamp {
75 micros: micros.div_euclid(MICROS_PER_DAY) * MICROS_PER_DAY,
76 },
77 &coerce_temporal(&args[0])?,
78 );
79 }
80 _ => TemporalValue::TimestampTz { micros },
81 };
82 Ok(Value::Temporal(value))
83 })())
84}