Skip to main content

sql_fun_sqlast/sem/
parse_context.rs

1mod cast_info;
2mod seq_info;
3mod table_info;
4mod type_info;
5mod view_info;
6
7use std::{
8    io::{Read, Seek},
9    path::Path,
10};
11
12pub use self::{
13    cast_info::CastInfoRead,
14    seq_info::{SequenceInfoRead, SequenceInfoWrite},
15    table_info::{TableInfoRead, TableInfoWrite},
16    type_info::{TypeInfoRead, TypeInfoWrite},
17    view_info::{ViewInfoRead, ViewInfoWrite},
18};
19
20use crate::{
21    StringSpan,
22    sem::{
23        AliasSpec, AnalysisError, AnalysisProblem, Comment, CreateCompositType, CreateDomain,
24        CreateEnum, CreateExtension, CreateFunction, CreateIndex, CreateSchema, CreateSequence,
25        CreateTable, DataSource, FullName, FunctionOverloadCollection, OperatorDefinition,
26        OperatorName, SchemaName, SemScalarExpr, TableName, TypeDefinition, TypeReference,
27        VariableSet, ViewLike, ViewName,
28        search_path::{expand_search_path, expand_search_path_inst},
29        type_system::ArgumentBindingCollection,
30    },
31};
32use sql_fun_core::{IVec, SqlFunArgs};
33
34/// provide access to source SQL file
35pub trait SourceAccessService: std::fmt::Debug {
36    /// Get source span as String
37    fn get_source_span(
38        &self,
39        _config_args: &SqlFunArgs,
40        source_path: &Path,
41        span: StringSpan,
42    ) -> Result<String, AnalysisError> {
43        let source_path = if source_path.is_absolute() {
44            source_path
45        } else {
46            // TODO resove path
47            source_path
48        };
49
50        if !source_path.exists() {
51            AnalysisError::file_not_found(source_path)?;
52            AnalysisError::never()
53        };
54
55        let mut file = std::fs::File::open(source_path)?;
56        file.seek(span.seek_pos())?;
57        let mut source_span = file.take(span.len() as u64);
58        let mut buf = String::default();
59        let result_len = source_span.read_to_string(&mut buf)?;
60        if result_len != span.len() {
61            Err(AnalysisError::unexpected_eof())
62        } else {
63            Ok(buf)
64        }
65    }
66}
67
68/// default implementation for SourceAccessService
69#[derive(Debug, Default)]
70pub struct DefaultSourceAccessService {}
71
72impl SourceAccessService for DefaultSourceAccessService {}
73
74/// get index definition
75pub trait IndexInfoRead {
76    /// get `CREATE INDEX` statement by index name
77    fn get_index(&self, index_name: &str) -> Option<&CreateIndex>;
78}
79
80/// get function definition
81pub trait FunctionInfoRead {
82    /// get `CREATE FUNCTION` statement by function name
83    fn get_function_impl(&self, name: &FullName) -> Option<FunctionOverloadCollection>;
84}
85
86/// store and update function info
87pub trait FunctionInfoWrite
88where
89    Self: Sized,
90{
91    /// apply `create function` statement (implementation)
92    fn apply_create_function_impl(
93        self,
94        name: &FullName,
95        create_function: &CreateFunction,
96    ) -> Result<Self, AnalysisError>;
97}
98
99/// get operator definition
100pub trait OperatorInfoRead {
101    /// get operator definition,
102    ///
103    /// `has_left`, `has_right` both true then returns Binary operator.
104    /// one of `has_left`, `has_right` is ture then returns Left unary or Right unary operator.
105    ///
106    fn get_operator_op(
107        &self,
108        name: &OperatorName,
109        has_left: bool,
110        has_right: bool,
111    ) -> Option<&OperatorDefinition>;
112}
113
114/// search path
115pub trait SearchPathRead {
116    /// set serach path
117    fn set_search_path(&mut self, search_path: Vec<SchemaName>);
118
119    /// get search path
120    fn get_search_path(&self) -> &[SchemaName];
121
122    /// gets default schema.
123    ///
124    /// # Note
125    ///
126    /// returns first item of current search path
127    fn get_default_schema(&self) -> Option<SchemaName>;
128}
129
130/// schema information database
131///
132/// `BaseParseContext` is a Immutable view of schema information,
133///
134/// [`ParseContext`] presents mutate functions.
135///
136pub trait BaseParseContext:
137    CastInfoRead
138    + FunctionInfoRead
139    + IndexInfoRead
140    + OperatorInfoRead
141    + SequenceInfoRead
142    + TypeInfoRead
143    + TableInfoRead
144    + ViewInfoRead
145    + SearchPathRead
146    + std::fmt::Debug
147{
148    /// get context args
149    fn get_args(&self) -> &SqlFunArgs;
150
151    /// get SQL file path
152    fn get_source_file_path(&self) -> Option<&Path>;
153
154    /// get type by name
155    fn get_type(&self, key: &FullName) -> Option<&TypeDefinition> {
156        expand_search_path(self, key, |k| self.get_type_impl(k))
157    }
158
159    /// get `CREATE TABLE` statement by table name
160    fn get_table(&self, name: &TableName) -> Option<&CreateTable> {
161        expand_search_path(self, name.full_name(), |key| self.get_table_impl(key))
162    }
163
164    /// get `CREATE VIEW` statement by view name
165    fn get_view(&self, key: &ViewName) -> Option<&ViewLike> {
166        expand_search_path(self, key.full_name(), |key| self.get_view_impl(key))
167    }
168
169    /// get `CREATE SEQUENCE` statement by sequence name
170    fn get_sequence(&self, seq_name: &FullName) -> Option<&CreateSequence> {
171        expand_search_path(self, seq_name, |key| self.get_sequence_impl(key))
172    }
173
174    /// get `CREATE FUNCTION` statement by function name
175    fn get_function_by_name(&self, name: &FullName) -> Option<FunctionOverloadCollection> {
176        expand_search_path_inst(self, name, |key| self.get_function_impl(key))
177    }
178
179    /// get resolved function name
180    fn resolve_function_name_with_search_path(&self, fun_name: &FullName) -> FullName {
181        if fun_name.schema().is_some() {
182            return fun_name.clone();
183        }
184
185        expand_search_path_inst(self, fun_name, |key| {
186            self.get_function_impl(key).map(|_| key.clone())
187        })
188        .unwrap_or_else(|| fun_name.clone())
189    }
190
191    /// reporting a analysis errors
192    fn report_problem(&mut self, problem: AnalysisProblem) -> Result<(), AnalysisError>;
193
194    /// Load extension and bind to this context
195    fn extend(&mut self, extension: Box<dyn BaseParseContext>);
196
197    /// update location for current statement.
198    fn set_statement_span(&mut self, statement_span: StringSpan);
199
200    /// setup source access service
201    fn set_source_file(&mut self, source_acess_service: Box<dyn SourceAccessService>);
202
203    /// canonicalize a type reference
204    fn canonicalize_type_ref(&self, type_ref: &TypeReference) -> Option<TypeReference> {
205        let type_def = self.get_type(type_ref.full_name())?;
206        type_def.full_name().map(|full_name| {
207            TypeReference::concrete_type_ref(full_name, type_ref.is_array().unwrap_or(false))
208        })
209    }
210}
211
212/// modifiable schema
213///
214/// use in schema loading
215///
216pub trait ParseContext:
217    SequenceInfoWrite
218    + TypeInfoWrite
219    + TableInfoWrite
220    + ViewInfoWrite
221    + FunctionInfoWrite
222    + BaseParseContext
223    + std::fmt::Debug
224where
225    Self: Sized,
226{
227    /// apply `create type` (composite type) to current schema
228    fn apply_create_comp_type(
229        mut self,
230        create_comp_type: &CreateCompositType,
231    ) -> Result<Self, AnalysisError> {
232        let Some(name) = create_comp_type.name() else {
233            AnalysisError::raise_register_dynamic_type(create_comp_type)?;
234            AnalysisError::never()
235        };
236        let name = self.apply_default_schema(name)?;
237        self.insert_create_composite_type(&name, create_comp_type);
238        Ok(self)
239    }
240
241    /// apply `create domain` to current schema
242    fn apply_create_domain(mut self, create_domain: &CreateDomain) -> Result<Self, AnalysisError> {
243        let name = self.apply_default_schema(create_domain.name())?;
244        self.insert_create_domain(&name, create_domain);
245        Ok(self)
246    }
247
248    /// apply `comment` statement to current schema
249    fn apply_comment(self, comment: &Comment) -> Result<Self, AnalysisError>;
250
251    /// apply default schema when name not specify schema
252    fn apply_default_schema(&self, name: &FullName) -> Result<FullName, AnalysisError> {
253        let name = if name.schema().is_none() {
254            let Some(schema) = self.get_default_schema() else {
255                AnalysisError::raise_unexpected_none("context.get_default_schema")?
256            };
257            name.clone().set_schema(schema)
258        } else {
259            name.clone()
260        };
261        Ok(name)
262    }
263
264    /// apply `create type as enum` statement to  current schema
265    fn apply_create_enum(mut self, create_enum_type: &CreateEnum) -> Result<Self, AnalysisError> {
266        let name = self.apply_default_schema(create_enum_type.name())?;
267        self.insert_create_enum(&name, create_enum_type);
268        Ok(self)
269    }
270
271    /// apply `create table` statement to current schema
272    fn apply_create_table(mut self, create_table: &CreateTable) -> Result<Self, AnalysisError> {
273        let name = self.apply_default_schema(create_table.name().full_name())?;
274        self.insert_create_table(&name, create_table);
275        // when create table, define composite type as table
276        self.insert_table_ref_type(&TableName::from(name));
277        Ok(self)
278    }
279
280    /// apply `create extension` to current schema
281    fn apply_create_extension(
282        self,
283        create_extension: &CreateExtension,
284    ) -> Result<Self, AnalysisError>;
285
286    /// apply `create function` statement to current schema
287    fn apply_create_function(
288        self,
289        create_function: &CreateFunction,
290    ) -> Result<Self, AnalysisError> {
291        let name = self.apply_default_schema(create_function.name())?;
292        self.apply_create_function_impl(&name, create_function)
293    }
294
295    /// apply `set` statement to current schema
296    fn apply_variable_set(self, variable_set: &VariableSet) -> Result<Self, AnalysisError>;
297
298    /// apply `create schema` to current schema
299    fn apply_create_schema(self, create_schema: &CreateSchema) -> Result<Self, AnalysisError>;
300
301    /// apply `create index` statement to current schema
302    fn apply_create_index(self, create_index: &CreateIndex) -> Result<Self, AnalysisError>;
303
304    /// resolve table function call as data source
305    fn resolve_table_function(
306        &mut self,
307        call: &crate::syn::FuncCall,
308        func_name: FullName,
309        alias_name: &AliasSpec,
310        arg_exprs: IVec<SemScalarExpr>,
311        arg_types: ArgumentBindingCollection,
312    ) -> Result<DataSource, AnalysisError> {
313        let Some(overloads) = self.get_function_by_name(&func_name) else {
314            self.report_problem(AnalysisProblem::table_function_not_found(&func_name))?;
315            return DataSource::undefined_table_function(call, arg_exprs, alias_name);
316        };
317
318        let Some(calling_overload) = overloads.resolve_overload(self, &arg_types) else {
319            self.report_problem(
320                AnalysisProblem::parameter_type_missmatch_for_table_function(call, arg_types),
321            )?;
322            return DataSource::undefined_table_function(call, arg_exprs, alias_name);
323        };
324
325        Ok(DataSource::table_function(
326            &calling_overload,
327            arg_exprs,
328            alias_name,
329        ))
330    }
331}