risingwave_frontend/handler/
variable.rs1use anyhow::Context;
16use itertools::Itertools;
17use pgwire::pg_field_descriptor::PgFieldDescriptor;
18use pgwire::pg_protocol::ParameterStatus;
19use pgwire::pg_response::{PgResponse, StatementType};
20use risingwave_common::session_config::{ConfigReporter, SESSION_CONFIG_LIST_SEP};
21use risingwave_common::system_param::reader::SystemParamsRead;
22use risingwave_common::types::Fields;
23use risingwave_sqlparser::ast::{Ident, SetTimeZoneValue, SetVariableValue, Value};
24
25use super::{RwPgResponse, RwPgResponseBuilderExt, fields_to_descriptors};
26use crate::error::Result;
27use crate::handler::HandlerArgs;
28
29pub(crate) fn set_var_to_param_str(value: &SetVariableValue) -> Option<String> {
31 match value {
32 SetVariableValue::Single(var) => Some(var.to_string_unquoted()),
33 SetVariableValue::List(list) => Some(
34 list.iter()
35 .map(|var| var.to_string_unquoted())
36 .join(SESSION_CONFIG_LIST_SEP),
37 ),
38 SetVariableValue::Default => None,
39 }
40}
41
42pub fn handle_set(
43 handler_args: HandlerArgs,
44 name: Ident,
45 value: SetVariableValue,
46) -> Result<RwPgResponse> {
47 let string_val = set_var_to_param_str(&value);
49
50 let mut status = ParameterStatus::default();
51
52 struct Reporter<'a> {
53 status: &'a mut ParameterStatus,
54 }
55
56 impl ConfigReporter for Reporter<'_> {
57 fn report_status(&mut self, key: &str, new_val: String) {
58 if key == "APPLICATION_NAME" {
59 self.status.application_name = Some(new_val);
60 }
61 }
62 }
63
64 handler_args.session.set_config_report(
68 &name.real_value().to_lowercase(),
69 string_val,
70 Reporter {
71 status: &mut status,
72 },
73 )?;
74
75 Ok(PgResponse::builder(StatementType::SET_VARIABLE)
76 .status(status)
77 .into())
78}
79
80pub(super) fn handle_set_time_zone(
81 handler_args: HandlerArgs,
82 value: SetTimeZoneValue,
83) -> Result<RwPgResponse> {
84 let tz_info = match value {
85 SetTimeZoneValue::Local => {
86 iana_time_zone::get_timezone().context("Failed to get local time zone")
87 }
88 SetTimeZoneValue::Default => Ok("UTC".to_owned()),
89 SetTimeZoneValue::Ident(ident) => Ok(ident.real_value()),
90 SetTimeZoneValue::Literal(Value::DoubleQuotedString(s))
91 | SetTimeZoneValue::Literal(Value::SingleQuotedString(s)) => Ok(s),
92 _ => Ok(value.to_string()),
93 }?;
94
95 handler_args.session.set_config("timezone", tz_info)?;
96
97 Ok(PgResponse::empty_result(StatementType::SET_VARIABLE))
98}
99
100pub(super) async fn handle_show(
101 handler_args: HandlerArgs,
102 variable: Vec<Ident>,
103) -> Result<RwPgResponse> {
104 let name = variable.iter().map(|e| e.real_value()).join(" ");
106 if name.eq_ignore_ascii_case("PARAMETERS") {
107 handle_show_system_params(handler_args).await
108 } else if name.eq_ignore_ascii_case("ALL") {
109 handle_show_all(handler_args.clone())
110 } else {
111 let config_reader = handler_args.session.config();
112 Ok(PgResponse::builder(StatementType::SHOW_VARIABLE)
113 .rows([ShowVariableRow {
114 name: config_reader.get(&name)?,
115 }])
116 .into())
117 }
118}
119
120fn handle_show_all(handler_args: HandlerArgs) -> Result<RwPgResponse> {
121 let config_reader = handler_args.session.config();
122
123 let all_variables = config_reader.show_all();
124
125 let rows = all_variables.iter().map(|info| ShowVariableAllRow {
126 name: info.name.clone(),
127 setting: info.setting.clone(),
128 description: info.description.clone(),
129 });
130 Ok(PgResponse::builder(StatementType::SHOW_VARIABLE)
131 .rows(rows)
132 .into())
133}
134
135async fn handle_show_system_params(handler_args: HandlerArgs) -> Result<RwPgResponse> {
136 let params = handler_args
137 .session
138 .env()
139 .meta_client()
140 .get_system_params()
141 .await?;
142 let rows = params
143 .get_all()
144 .into_iter()
145 .map(|info| ShowVariableParamsRow {
146 name: info.name.into(),
147 value: info.value,
148 description: info.description.into(),
149 mutable: info.mutable,
150 });
151 Ok(PgResponse::builder(StatementType::SHOW_VARIABLE)
152 .rows(rows)
153 .into())
154}
155
156pub fn infer_show_variable(name: &str) -> Vec<PgFieldDescriptor> {
157 fields_to_descriptors(if name.eq_ignore_ascii_case("ALL") {
158 ShowVariableAllRow::fields()
159 } else if name.eq_ignore_ascii_case("PARAMETERS") {
160 ShowVariableParamsRow::fields()
161 } else {
162 ShowVariableRow::fields()
163 })
164}
165
166#[derive(Fields)]
167#[fields(style = "Title Case")]
168struct ShowVariableRow {
169 name: String,
170}
171
172#[derive(Fields)]
173#[fields(style = "Title Case")]
174struct ShowVariableAllRow {
175 name: String,
176 setting: String,
177 description: String,
178}
179
180#[derive(Fields)]
181#[fields(style = "Title Case")]
182struct ShowVariableParamsRow {
183 name: String,
184 value: String,
185 description: String,
186 mutable: bool,
187}