Skip to content

Commit 65a641d

Browse files
authored
feat(frontend): support SET TIME ZONE (risingwavelabs#8572)
Signed-off-by: TennyZhuang <[email protected]>
1 parent c19fc72 commit 65a641d

File tree

9 files changed

+95
-3
lines changed

9 files changed

+95
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common/src/session_config/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use derivative::{self, Derivative};
2424
use itertools::Itertools;
2525
pub use query_mode::QueryMode;
2626
pub use search_path::{SearchPath, USER_NAME_WILD_CARD};
27+
use tracing::info;
2728

2829
use crate::error::{ErrorCode, RwError};
2930
use crate::session_config::transaction_isolation_level::IsolationLevel;
@@ -357,6 +358,7 @@ pub struct ConfigMap {
357358

358359
impl ConfigMap {
359360
pub fn set(&mut self, key: &str, val: Vec<String>) -> Result<(), RwError> {
361+
info!(%key, ?val, "set config");
360362
let val = val.iter().map(AsRef::as_ref).collect_vec();
361363
if key.eq_ignore_ascii_case(ImplicitFlush::entry_name()) {
362364
self.implicit_flush = val.as_slice().try_into()?;

src/frontend/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum-as-inner = "0.5"
3131
fixedbitset = "0.4.1"
3232
futures = { version = "0.3", default-features = false, features = ["alloc"] }
3333
futures-async-stream = "0.2"
34+
iana-time-zone = "0.1"
3435
itertools = "0.10"
3536
lazy_static = "1"
3637
maplit = "1"

src/frontend/src/handler/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use risingwave_common::error::{ErrorCode, Result};
2828
use risingwave_sqlparser::ast::*;
2929

3030
use self::util::DataChunkToRowSetAdapter;
31+
use self::variable::handle_set_time_zone;
3132
use crate::scheduler::{DistributedQueryStream, LocalQueryStream};
3233
use crate::session::SessionImpl;
3334
use crate::utils::WithOptions;
@@ -351,6 +352,7 @@ pub async fn handle(
351352
variable,
352353
value,
353354
} => variable::handle_set(handler_args, variable, value),
355+
Statement::SetTimeZone { local: _, value } => handle_set_time_zone(handler_args, value),
354356
Statement::ShowVariable { variable } => variable::handle_show(handler_args, variable).await,
355357
Statement::CreateIndex {
356358
name,

src/frontend/src/handler/variable.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use itertools::Itertools;
1616
use pgwire::pg_field_descriptor::PgFieldDescriptor;
1717
use pgwire::pg_response::{PgResponse, StatementType};
1818
use pgwire::types::Row;
19-
use risingwave_common::error::Result;
19+
use risingwave_common::error::{ErrorCode, Result};
2020
use risingwave_common::types::DataType;
21-
use risingwave_sqlparser::ast::{Ident, SetVariableValue, Value};
21+
use risingwave_sqlparser::ast::{Ident, SetTimeZoneValue, SetVariableValue, Value};
2222

2323
use super::RwPgResponse;
2424
use crate::handler::HandlerArgs;
@@ -48,6 +48,25 @@ pub fn handle_set(
4848
Ok(PgResponse::empty_result(StatementType::SET_VARIABLE))
4949
}
5050

51+
pub(super) fn handle_set_time_zone(
52+
handler_args: HandlerArgs,
53+
value: SetTimeZoneValue,
54+
) -> Result<RwPgResponse> {
55+
let tz_info = match value {
56+
SetTimeZoneValue::Local => iana_time_zone::get_timezone()
57+
.map_err(|e| ErrorCode::InternalError(format!("Failed to get local time zone: {}", e))),
58+
SetTimeZoneValue::Default => Ok("UTC".to_string()),
59+
SetTimeZoneValue::Ident(ident) => Ok(ident.real_value()),
60+
SetTimeZoneValue::Literal(Value::DoubleQuotedString(s))
61+
| SetTimeZoneValue::Literal(Value::SingleQuotedString(s)) => Ok(s),
62+
_ => Ok(value.to_string()),
63+
}?;
64+
65+
handler_args.session.set_config("timezone", vec![tz_info])?;
66+
67+
Ok(PgResponse::empty_result(StatementType::SET_VARIABLE))
68+
}
69+
5170
pub(super) async fn handle_show(
5271
handler_args: HandlerArgs,
5372
variable: Vec<Ident>,

src/sqlparser/src/ast/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,11 @@ pub enum Statement {
10411041
snapshot: Option<Value>,
10421042
session: bool,
10431043
},
1044+
/// `SET [ SESSION | LOCAL ] TIME ZONE { value | 'value' | LOCAL | DEFAULT }`
1045+
SetTimeZone {
1046+
local: bool,
1047+
value: SetTimeZoneValue,
1048+
},
10441049
/// `COMMENT ON ...`
10451050
///
10461051
/// Note: this is a PostgreSQL-specific statement.
@@ -1450,6 +1455,14 @@ impl fmt::Display for Statement {
14501455
}
14511456
Ok(())
14521457
}
1458+
Statement::SetTimeZone { local, value } => {
1459+
write!(f, "SET")?;
1460+
if *local {
1461+
write!(f, " LOCAL")?;
1462+
}
1463+
write!(f, " TIME ZONE {}", value)?;
1464+
Ok(())
1465+
}
14531466
Statement::Commit { chain } => {
14541467
write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
14551468
}
@@ -1975,6 +1988,26 @@ impl fmt::Display for EmitMode {
19751988
}
19761989
}
19771990

1991+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1992+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1993+
pub enum SetTimeZoneValue {
1994+
Ident(Ident),
1995+
Literal(Value),
1996+
Local,
1997+
Default,
1998+
}
1999+
2000+
impl fmt::Display for SetTimeZoneValue {
2001+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2002+
match self {
2003+
SetTimeZoneValue::Ident(ident) => write!(f, "{}", ident),
2004+
SetTimeZoneValue::Literal(value) => write!(f, "{}", value),
2005+
SetTimeZoneValue::Local => f.write_str("LOCAL"),
2006+
SetTimeZoneValue::Default => f.write_str("DEFAULT"),
2007+
}
2008+
}
2009+
}
2010+
19782011
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19792012
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19802013
pub enum TransactionMode {

src/sqlparser/src/parser.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,6 +3282,23 @@ impl Parser {
32823282

32833283
pub fn parse_set(&mut self) -> Result<Statement, ParserError> {
32843284
let modifier = self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL]);
3285+
if self.parse_keywords(&[Keyword::TIME, Keyword::ZONE]) {
3286+
let value = if self.parse_keyword(Keyword::DEFAULT) {
3287+
SetTimeZoneValue::Default
3288+
} else if self.parse_keyword(Keyword::LOCAL) {
3289+
SetTimeZoneValue::Local
3290+
} else if let Ok(ident) = self.parse_identifier() {
3291+
SetTimeZoneValue::Ident(ident)
3292+
} else {
3293+
let value = self.parse_value()?;
3294+
SetTimeZoneValue::Literal(value)
3295+
};
3296+
3297+
return Ok(Statement::SetTimeZone {
3298+
local: modifier == Some(Keyword::LOCAL),
3299+
value,
3300+
});
3301+
}
32853302
let variable = self.parse_identifier()?;
32863303
if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
32873304
let mut values = vec![];

src/sqlparser/tests/testdata/select.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,4 @@
7878
Near "SELECT 1::int"
7979
- input: select id1, a1, id2, a2 from stream as S join version FOR SYSTEM_TIME AS OF NOW() AS V on id1= id2
8080
formatted_sql: SELECT id1, a1, id2, a2 FROM stream AS S JOIN version FOR SYSTEM_TIME AS OF NOW() AS V ON id1 = id2
81-
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(Identifier(Ident { value: "id1", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "a1", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "id2", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "a2", quote_style: None }))], from: [TableWithJoins { relation: Table { name: ObjectName([Ident { value: "stream", quote_style: None }]), alias: Some(TableAlias { name: Ident { value: "S", quote_style: None }, columns: [] }), for_system_time_as_of_now: false }, joins: [Join { relation: Table { name: ObjectName([Ident { value: "version", quote_style: None }]), alias: Some(TableAlias { name: Ident { value: "V", quote_style: None }, columns: [] }), for_system_time_as_of_now: true }, join_operator: Inner(On(BinaryOp { left: Identifier(Ident { value: "id1", quote_style: None }), op: Eq, right: Identifier(Ident { value: "id2", quote_style: None }) })) }] }], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
81+
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(Identifier(Ident { value: "id1", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "a1", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "id2", quote_style: None })), UnnamedExpr(Identifier(Ident { value: "a2", quote_style: None }))], from: [TableWithJoins { relation: Table { name: ObjectName([Ident { value: "stream", quote_style: None }]), alias: Some(TableAlias { name: Ident { value: "S", quote_style: None }, columns: [] }), for_system_time_as_of_now: false }, joins: [Join { relation: Table { name: ObjectName([Ident { value: "version", quote_style: None }]), alias: Some(TableAlias { name: Ident { value: "V", quote_style: None }, columns: [] }), for_system_time_as_of_now: true }, join_operator: Inner(On(BinaryOp { left: Identifier(Ident { value: "id1", quote_style: None }), op: Eq, right: Identifier(Ident { value: "id2", quote_style: None }) })) }] }], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'

src/sqlparser/tests/testdata/set.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This file is automatically generated. See `src/sqlparser/test_runner/src/bin/apply.rs` for more information.
2+
- input: SET TIME ZONE LOCAL
3+
formatted_sql: SET TIME ZONE LOCAL
4+
- input: SET TIME ZONE DEFAULT
5+
formatted_sql: SET TIME ZONE DEFAULT
6+
- input: SET TIME ZONE "Asia/Shanghai"
7+
formatted_sql: SET TIME ZONE "Asia/Shanghai"
8+
- input: SET TIME ZONE 'Asia/Shanghai'
9+
error_msg: |-
10+
sql parser error: Expected a value, found: EOF
11+
Near "SET TIME ZONE 'Asia/Shanghai'"
12+
- input: SET TIME ZONE "UTC"
13+
formatted_sql: SET TIME ZONE "UTC"
14+
- input: SET TIME ZONE UTC
15+
formatted_sql: SET TIME ZONE UTC
16+
- input: set time = '1';
17+
formatted_sql: SET time = '1'

0 commit comments

Comments
 (0)