1pub mod context;
16pub mod hints;
17pub mod protocol_ctx;
18pub mod query_id;
19pub mod query_options;
20pub mod session_config;
21pub mod table_name;
22pub mod write_progress;
23
24use std::collections::{HashMap, VecDeque};
25use std::net::SocketAddr;
26use std::sync::{Arc, RwLock};
27use std::time::Duration;
28
29use auth::UserInfoRef;
30use common_catalog::build_db_string;
31use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
32use common_recordbatch::cursor::RecordBatchStreamCursor;
33pub use common_session::ReadPreference;
34use common_time::Timezone;
35use common_time::timezone::get_timezone;
36use context::{ConfigurationVariables, QueryContextBuilder};
37use derive_more::Debug;
38
39use crate::context::{Channel, ConnInfo, QueryContextRef, dialect_for_channel};
40
41#[derive(snafu::Snafu)]
43#[common_macro::stack_trace_debug]
44pub enum SessionError {
45 #[snafu(display("No database selected"))]
46 NoDatabaseSelected {},
47}
48
49impl common_error::ext::ErrorExt for SessionError {
50 fn status_code(&self) -> common_error::status_code::StatusCode {
51 common_error::status_code::StatusCode::DatabaseNotFound
54 }
55
56 fn as_any(&self) -> &dyn std::any::Any {
57 self
58 }
59}
60
61const MAX_WARNINGS: usize = 64;
63
64#[derive(Debug)]
66pub struct Session {
67 catalog: RwLock<String>,
68 mutable_inner: Arc<RwLock<MutableInner>>,
69 conn_info: ConnInfo,
70 configuration_variables: Arc<ConfigurationVariables>,
71 process_id: u32,
73}
74
75pub type SessionRef = Arc<Session>;
76
77#[derive(Debug, Clone)]
79pub(crate) struct MutableInner {
80 schema: String,
81 user_info: UserInfoRef,
82 timezone: Timezone,
83 query_timeout: Option<Duration>,
84 read_preference: ReadPreference,
85 last_procedure_id: Option<String>,
88 skip_wal: bool,
90 #[debug(skip)]
91 pub(crate) cursors: HashMap<String, Arc<RecordBatchStreamCursor>>,
92 warnings: VecDeque<String>,
94}
95
96impl Default for MutableInner {
97 fn default() -> Self {
98 Self {
99 schema: DEFAULT_SCHEMA_NAME.into(),
100 user_info: auth::userinfo_by_name(None),
101 timezone: get_timezone(None).clone(),
102 query_timeout: None,
103 read_preference: ReadPreference::Leader,
104 last_procedure_id: None,
105 skip_wal: false,
106 cursors: HashMap::with_capacity(0),
107 warnings: VecDeque::new(),
108 }
109 }
110}
111
112impl Session {
113 pub fn new(
114 addr: Option<SocketAddr>,
115 channel: Channel,
116 configuration_variables: ConfigurationVariables,
117 process_id: u32,
118 ) -> Self {
119 Session {
120 catalog: RwLock::new(DEFAULT_CATALOG_NAME.into()),
121 conn_info: ConnInfo::new(addr, channel),
122 configuration_variables: Arc::new(configuration_variables),
123 mutable_inner: Arc::new(RwLock::new(MutableInner::default())),
124 process_id,
125 }
126 }
127
128 pub fn new_query_context(&self) -> QueryContextRef {
129 QueryContextBuilder::default()
130 .current_catalog(self.catalog.read().unwrap().clone())
133 .mutable_session_data(self.mutable_inner.clone())
134 .sql_dialect(dialect_for_channel(self.conn_info.channel))
135 .configuration_parameter(self.configuration_variables.clone())
136 .channel(self.conn_info.channel)
137 .process_id(self.process_id)
138 .conn_info(self.conn_info.clone())
139 .build()
140 .into()
141 }
142
143 pub fn get_cursor(&self, name: &str) -> Option<Arc<RecordBatchStreamCursor>> {
145 let guard = self.mutable_inner.read().unwrap();
146 guard.cursors.get(name).cloned()
147 }
148
149 pub fn conn_info(&self) -> &ConnInfo {
150 &self.conn_info
151 }
152
153 pub fn timezone(&self) -> Timezone {
154 self.mutable_inner.read().unwrap().timezone.clone()
155 }
156
157 pub fn read_preference(&self) -> ReadPreference {
158 self.mutable_inner.read().unwrap().read_preference
159 }
160
161 pub fn set_timezone(&self, tz: Timezone) {
162 let mut inner = self.mutable_inner.write().unwrap();
163 inner.timezone = tz;
164 }
165
166 pub fn set_read_preference(&self, read_preference: ReadPreference) {
167 self.mutable_inner.write().unwrap().read_preference = read_preference;
168 }
169
170 pub fn user_info(&self) -> UserInfoRef {
171 self.mutable_inner.read().unwrap().user_info.clone()
172 }
173
174 pub fn set_user_info(&self, user_info: UserInfoRef) {
175 self.mutable_inner.write().unwrap().user_info = user_info;
176 }
177
178 pub fn set_catalog(&self, catalog: String) {
179 *self.catalog.write().unwrap() = catalog;
180 }
181
182 pub fn catalog(&self) -> String {
183 self.catalog.read().unwrap().clone()
184 }
185
186 pub fn schema(&self) -> String {
187 self.mutable_inner.read().unwrap().schema.clone()
188 }
189
190 pub fn set_schema(&self, schema: String) {
191 self.mutable_inner.write().unwrap().schema = schema;
192 }
193
194 pub fn get_db_string(&self) -> String {
195 build_db_string(&self.catalog(), &self.schema())
196 }
197
198 pub fn process_id(&self) -> u32 {
199 self.process_id
200 }
201
202 pub fn warnings_count(&self) -> usize {
203 self.mutable_inner.read().unwrap().warnings.len()
204 }
205
206 pub fn warnings(&self) -> Vec<String> {
207 self.mutable_inner
208 .read()
209 .unwrap()
210 .warnings
211 .iter()
212 .cloned()
213 .collect()
214 }
215
216 pub fn add_warning(&self, warning: String) {
218 let mut inner = self.mutable_inner.write().unwrap();
219 if inner.warnings.len() >= MAX_WARNINGS {
220 inner.warnings.pop_front();
221 }
222 inner.warnings.push_back(warning);
223 }
224
225 pub fn clear_warnings(&self) {
226 let mut inner = self.mutable_inner.write().unwrap();
227 if inner.warnings.is_empty() {
228 return;
229 }
230 inner.warnings.clear();
231 }
232}