Skip to content

Commit

Permalink
remove timestamptz in time zone for now
Browse files Browse the repository at this point in the history
  • Loading branch information
KeXiangWang committed Nov 2, 2023
1 parent a0d1b89 commit b2e145f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 102 deletions.
4 changes: 2 additions & 2 deletions e2e_test/batch/basic/to_jsonb.slt.part
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,15 @@ set timezone to 'Europe/London';
query T
SELECT to_jsonb('2014-05-28 12:22:35.614298'::timestamptz);
----
"2014-05-28T12:22:35.614298+01:00"
"2014-05-28T11:22:35.614298+00:00"

statement ok
SET timezone = 'EST5EDT';

query T
SELECT to_jsonb('2014-05-28 12:22:35.614298'::timestamptz);
----
"2014-05-28T12:22:35.614298-04:00"
"2014-05-28T16:22:35.614298+00:00"

statement ok
set timezone to 'UTC';
Expand Down
115 changes: 31 additions & 84 deletions src/expr/impl/src/scalar/to_jsonb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,15 @@

use std::fmt::Debug;

use anyhow::anyhow;
use jsonbb::{Builder, Value};
use jsonbb::Builder;
use risingwave_common::types::{
DataType, Date, Decimal, Int256Ref, Interval, JsonbRef, JsonbVal, ListRef, ScalarRefImpl,
Serial, StructRef, Time, Timestamp, Timestamptz, ToText, F32, F64,
};
use risingwave_common::util::iter_util::ZipEqFast;
use risingwave_expr::expr::{BoxedExpression, Context};
use risingwave_expr::{build_function, function, ExprError, Result};
use risingwave_expr::expr::Context;
use risingwave_expr::{function, ExprError, Result};

use super::timestamptz::time_zone_err;

// TODO(Kexiang): We can unify all the to_jsonb functions if we include ctx and time zone for all types. Should we?
#[function("to_jsonb(boolean) -> jsonb")]
#[function("to_jsonb(*int) -> jsonb")]
#[function("to_jsonb(decimal) -> jsonb")]
Expand All @@ -36,6 +32,7 @@ use super::timestamptz::time_zone_err;
#[function("to_jsonb(time) -> jsonb")]
#[function("to_jsonb(date) -> jsonb")]
#[function("to_jsonb(timestamp) -> jsonb")]
#[function("to_jsonb(timestamptz) -> jsonb")]
#[function("to_jsonb(interval) -> jsonb")]
#[function("to_jsonb(varchar) -> jsonb")]
#[function("to_jsonb(jsonb) -> jsonb")]
Expand All @@ -51,102 +48,47 @@ pub fn to_jsonb(input: Option<impl ToJsonb>) -> Result<JsonbVal> {
}
}

// Only to register this signature to function signature map.
#[build_function("to_jsonb(timestamptz) -> jsonb")]
#[build_function("to_jsonb(struct) -> jsonb")]
#[build_function("to_jsonb(anyarray) -> jsonb")]
fn build_timestamptz_to_jsonb(
_return_type: DataType,
_children: Vec<BoxedExpression>,
) -> Result<BoxedExpression> {
Err(ExprError::UnsupportedFunction(
"to_jsonb of timestamptz/struct/anyarray should have been rewritten to include timezone"
.into(),
))
}

#[function("to_jsonb(timestamptz, varchar) -> jsonb")]
pub fn timestamptz_to_jsonb(input: Option<Timestamptz>, zone: Option<&str>) -> Result<JsonbVal> {
match input {
Some(inner) => zone
.ok_or_else(|| {
ExprError::Internal(anyhow!(
"to_char(timestamptz, varchar) have a null zone_str"
))
})
.and_then(|zone_str| {
let value = timestamptz_to_value(inner, zone_str)?;
Ok(value.into())
}),
None => Ok(JsonbVal::null()),
}
}

#[function("to_jsonb(struct, varchar) -> jsonb")]
pub fn struct_to_jsonb(
input: Option<StructRef<'_>>,
zone: Option<&str>,
ctx: &Context,
) -> Result<JsonbVal> {
#[function("to_jsonb(struct) -> jsonb")]
pub fn struct_to_jsonb(input: Option<StructRef<'_>>, ctx: &Context) -> Result<JsonbVal> {
match input {
Some(inner) => zone
.ok_or_else(|| {
ExprError::Internal(anyhow!("to_char(struct, varchar) have a null zone_str"))
})
.and_then(|zone_str| {
let mut builder = Builder::default();
add_struct_to_builder(inner, zone_str, &ctx.arg_types[0], &mut builder)?;
Ok(builder.finish().into())
}),
Some(inner) => {
let mut builder = Builder::default();
add_struct_to_builder(inner, &ctx.arg_types[0], &mut builder)?;
Ok(builder.finish().into())
}
None => Ok(JsonbVal::null()),
}
}

#[function("to_jsonb(anyarray, varchar) -> jsonb")]
pub fn list_to_jsonb(
input: Option<ListRef<'_>>,
zone: Option<&str>,
ctx: &Context,
) -> Result<JsonbVal> {
#[function("to_jsonb(anyarray) -> jsonb")]
pub fn list_to_jsonb(input: Option<ListRef<'_>>, ctx: &Context) -> Result<JsonbVal> {
match input {
Some(inner) => zone
.ok_or_else(|| {
ExprError::Internal(anyhow!("to_char(anyarray, varchar) have a null zone_str"))
})
.and_then(|zone_str| {
let mut builder = Builder::default();
add_anyarrary_to_builder(inner, zone_str, &ctx.arg_types[0], &mut builder)?;
Ok(builder.finish().into())
}),
Some(inner) => {
let mut builder = Builder::default();
add_anyarrary_to_builder(inner, &ctx.arg_types[0], &mut builder)?;
Ok(builder.finish().into())
}
None => Ok(JsonbVal::null()),
}
}

fn timestamptz_to_value(input: Timestamptz, zone: &str) -> Result<Value> {
let time_zone = Timestamptz::lookup_time_zone(zone).map_err(time_zone_err)?;
let instant_local = input.to_datetime_in_zone(time_zone);
Ok(instant_local.to_rfc3339().as_str().into())
}

fn add_anyarrary_to_builder(
input: ListRef<'_>,
zone: &str,
data_type: &DataType,
builder: &mut Builder,
) -> Result<()> {
let data_type_in_list = data_type.as_list();
builder.begin_array();
input
.iter()
.map(|x| add_scalar_to_builder(x, zone, data_type_in_list, builder))
.map(|x| add_scalar_to_builder(x, data_type_in_list, builder))
.try_collect()?;
builder.end_array();
Ok(())
}

fn add_struct_to_builder(
input: StructRef<'_>,
zone: &str,
data_type: &DataType,
builder: &mut Builder,
) -> Result<()> {
Expand All @@ -162,7 +104,7 @@ fn add_struct_to_builder(
} else {
builder.add_string(names[idx]);
};
add_scalar_to_builder(scalar, zone, data_type, builder)?;
add_scalar_to_builder(scalar, data_type, builder)?;
Ok::<(), ExprError>(())
})
.try_collect()?;
Expand All @@ -172,7 +114,6 @@ fn add_struct_to_builder(

fn add_scalar_to_builder(
input: Option<ScalarRefImpl<'_>>,
zone: &str,
data_type: &DataType,
builder: &mut Builder,
) -> Result<()> {
Expand All @@ -194,11 +135,9 @@ fn add_scalar_to_builder(
ScalarRefImpl::Jsonb(v) => v.add_to(builder)?,
ScalarRefImpl::Serial(v) => v.add_to(builder)?,
ScalarRefImpl::Bytea(v) => v.add_to(builder)?,
ScalarRefImpl::Timestamptz(v) => {
builder.add_value(timestamptz_to_value(v, zone)?.as_ref())
}
ScalarRefImpl::Struct(v) => add_struct_to_builder(v, zone, data_type, builder)?,
ScalarRefImpl::List(v) => add_anyarrary_to_builder(v, zone, data_type, builder)?,
ScalarRefImpl::Timestamptz(v) => v.add_to(builder)?,
ScalarRefImpl::Struct(v) => add_struct_to_builder(v, data_type, builder)?,
ScalarRefImpl::List(v) => add_anyarrary_to_builder(v, data_type, builder)?,
},
None => builder.add_null(),
};
Expand Down Expand Up @@ -333,6 +272,14 @@ impl ToJsonb for Timestamp {
}
}

impl ToJsonb for Timestamptz {
fn add_to(self, builder: &mut Builder) -> Result<()> {
let instant_local = self.to_datetime_utc();
builder.display(instant_local.to_rfc3339().as_str());
Ok(())
}
}

impl ToJsonb for Serial {
fn add_to(self, builder: &mut Builder) -> Result<()> {
builder.add_string(self.to_text().as_str());
Expand Down
16 changes: 0 additions & 16 deletions src/frontend/src/expr/session_timezone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,22 +242,6 @@ impl SessionTimezone {
new_inputs.push(ExprImpl::literal_varchar(self.timezone()));
Some(FunctionCall::new(func_type, new_inputs).unwrap().into())
}
// `to_jsonb(input_timestamptz)`
// => `to_jsonb(input_timestamptz, zone_string)`
ExprType::ToJsonb => {
// array or struct type may implicitly contain timestamptz.
if !(inputs.len() == 1
&& matches!(
inputs[0].return_type(),
DataType::Timestamptz | DataType::List(_) | DataType::Struct(_)
))
{
return None;
}
let mut new_inputs = inputs.clone();
new_inputs.push(ExprImpl::literal_varchar(self.timezone()));
Some(FunctionCall::new(func_type, new_inputs).unwrap().into())
}
_ => None,
}
}
Expand Down

0 comments on commit b2e145f

Please sign in to comment.