1mod impl_analyze_range_var_node;
2
3use sql_fun_core::IVec;
4
5use crate::{
6 AstAndContextPair,
7 sem::{
8 AliasSpec, AnalysisError, ColumnName, DataSourceRowFunctions, DataSourceRowsFromFunc,
9 FromClause, FullName, JoinKind, ParseContext, SemAst, WithClause, analyze_node,
10 analyze_scaler_expr,
11 data_source::{JoinExprDataSource, join_expr::JoinUsingClause},
12 },
13 syn::{ListOpt, Opt, ScanToken},
14};
15
16use super::{DataSource, SubQueryDataSource};
17
18impl DataSource {
19 fn analyze_range_subselect<TParseContext>(
21 mut context: TParseContext,
22 range_subsel: crate::syn::RangeSubselect,
23 tokens: &IVec<ScanToken>,
24 ) -> Result<(Self, TParseContext), AnalysisError>
25 where
26 TParseContext: ParseContext,
27 {
28 let Some(alias) = range_subsel.get_alias().as_inner() else {
29 AnalysisError::raise_unexpected_none("range_subsel.alias")?
30 };
31 let (alias_name, new_context) = AliasSpec::analyze_without_relname(context, &alias)?;
32 context = new_context;
33
34 let Some(query) = range_subsel.get_subquery().as_inner() else {
35 AnalysisError::raise_unexpected_none("range_subselect.subquery")?
36 };
37 let AstAndContextPair(sem, new_context) = analyze_node(context, &None, query, tokens)?;
38 let SemAst::SelectStatement(s) = sem else {
39 AnalysisError::raise_unexpected_none("subquery is not select?")?
40 };
41 Ok((
42 SubQueryDataSource::new_data_source(&s, &alias_name),
43 new_context,
44 ))
45 }
46}
47
48#[cfg(test)]
49mod test_analyze_range_subselect {
50 use sql_fun_core::IVec;
51 use testresult::TestResult;
52
53 use crate::{
54 syn::{Node, NodeList, WithClauseOpt},
55 test_helpers::{SynBuilder, TestParseContext, test_context},
56 };
57
58 #[rstest::rstest]
59 fn test_analyze_range_subselect(test_context: TestParseContext) -> TestResult {
60 let builder = SynBuilder::new();
61
62 let res_target = builder.res_target(
63 "name",
64 crate::syn::NodeInner::AConst(builder.const_int4(10)).into(),
65 );
66 let query = builder.select_stmt(
67 WithClauseOpt::none(),
68 NodeList::from(Vec::<Node>::new()),
69 vec![res_target],
70 );
71 let alias_spec = builder.alias_name_only("alias1");
72 let range_subselect = builder.range_subselect(alias_spec, query);
73 let tokens = IVec::default();
74
75 super::DataSource::analyze_range_subselect(test_context, range_subselect, &tokens)?;
76 Ok(())
77 }
78}
79
80impl DataSource {
81 fn analyze_join_using_clause<TParseContext>(
82 mut context: TParseContext,
83 join_expr: crate::syn::JoinExpr,
84 ) -> Result<(Option<JoinUsingClause>, TParseContext), AnalysisError>
85 where
86 TParseContext: ParseContext,
87 {
88 if let Some(using_columns) = join_expr.get_using_clause().as_inner()
89 && !using_columns.is_empty()
90 {
91 let using_columns: Vec<ColumnName> = using_columns
92 .iter()
93 .filter_map(|c| c.as_string().get_sval())
94 .map(|v| ColumnName::from(v.as_str()))
95 .collect();
96
97 let (alias, new_context) =
98 if let Some(alias) = join_expr.get_join_using_alias().as_inner() {
99 let (alias, new_context) = AliasSpec::analyze_without_relname(context, &alias)?;
100 (Some(alias), new_context)
101 } else {
102 (None, context)
103 };
104
105 context = new_context;
106 let join_using = JoinUsingClause::new(&using_columns, &alias);
107 Ok((Some(join_using), context))
108 } else {
109 Ok((None, context))
110 }
111 }
112
113 fn analyze_join_expr<TParseContext>(
114 mut context: TParseContext,
115 with_clause: &WithClause,
116 from_clause: &FromClause,
117 join_expr: crate::syn::JoinExpr,
118 tokens: &IVec<ScanToken>,
119 ) -> Result<(Self, TParseContext), AnalysisError>
120 where
121 TParseContext: ParseContext,
122 {
123 let mut from_clause = from_clause.clone();
124
125 let Some(left) = join_expr.get_larg().as_inner() else {
126 AnalysisError::raise_unexpected_none("join_expr.larg")?
127 };
128 let Some(right) = join_expr.get_rarg().as_inner() else {
129 AnalysisError::raise_unexpected_none("join_expr.rarg")?
130 };
131
132 let (left_source, new_context) =
133 Self::analyze_from_clause_node(context, with_clause, &from_clause, left, tokens)?;
134 context = new_context;
135 let (right_source, new_context) =
136 Self::analyze_from_clause_node(context, with_clause, &from_clause, right, tokens)?;
137 context = new_context;
138
139 from_clause.push(left_source.clone());
140 from_clause.push(right_source.clone());
141
142 let qualifications = if let Some(qualifications) = join_expr.get_quals().as_inner() {
143 let (quals, new_context) =
144 analyze_scaler_expr(context, with_clause, &from_clause, qualifications, tokens)?;
145 context = new_context;
146 Some(quals)
147 } else {
148 None
149 };
150
151 let alias = if let Some(alias) = join_expr.get_alias().as_inner() {
152 let (alias, new_context) = AliasSpec::analyze_without_relname(context, &alias)?;
153 context = new_context;
154 Some(alias)
155 } else {
156 None
157 };
158
159 let join_kind = JoinKind::try_from(join_expr.get_jointype())?;
160 let natural = join_expr.get_is_natural();
161 let (using_clause, new_context) = Self::analyze_join_using_clause(context, join_expr)?;
162 context = new_context;
163
164 Ok((
165 JoinExprDataSource::new_data_source(
166 &join_kind,
167 &left_source,
168 &right_source,
169 &qualifications,
170 &alias,
171 &using_clause,
172 natural,
173 ),
174 context,
175 ))
176 }
177}
178
179#[cfg(test)]
180mod test_analyze_join_expr {
181 use crate::{
182 sem::{
183 ColumnDefinition, ColumnName, FromClause, FullName, SchemaName, TypeReference,
184 WithClause,
185 },
186 syn::{AliasOpt, JoinType, NodeInner},
187 test_helpers::{SynBuilder, TestParseContext, test_context},
188 };
189 use sql_fun_core::IVec;
190 use testresult::TestResult;
191
192 #[rstest::rstest]
193 fn test_analyze_join_expr(mut test_context: TestParseContext) -> TestResult {
194 test_context.set_get_search_path_result(&vec![
195 SchemaName::from("public"),
196 SchemaName::from("pg_catalog"),
197 ]);
198 let int4_type_ref = TypeReference::from_master_type_name("int4");
199 test_context.setup_type(int4_type_ref.clone());
200 let columns = vec![ColumnDefinition::new(
201 &Some(ColumnName::from("id")),
202 Some(&int4_type_ref),
203 Some(true),
204 )];
205 test_context.setup_table("table1", &columns);
206 test_context.setup_table("table2", &columns);
207 test_context.setup_binary("=", "int4", "int4", "bool", true);
208
209 let builder = SynBuilder::new();
210
211 let name = FullName::from_local_name("table1");
212 let alias = builder.alias("t1", &[]);
213 let table1 = NodeInner::RangeVar(builder.range_var(&name, &alias.into()));
214 let name = FullName::from_local_name("table2");
215 let alias = builder.alias("t2", &[]);
216 let table2 = NodeInner::RangeVar(builder.range_var(&name, &alias.into()));
217 let left = builder.column_ref("t1", "id");
218 let right = builder.column_ref("t2", "id");
219 let qual = builder.operator_equals(
220 NodeInner::ColumnRef(left).into(),
221 NodeInner::ColumnRef(right).into(),
222 );
223
224 let join_expr = builder.join_expr(
225 JoinType::JoinInner.into(),
226 table1.into(),
227 table2.into(),
228 qual,
229 AliasOpt::none(),
230 &[],
231 AliasOpt::none(),
232 false,
233 );
234
235 let with_clause = WithClause::default();
236 let from_clause = FromClause::default();
237 let tokens = IVec::default();
238
239 let (_ds, _) = super::DataSource::analyze_join_expr(
240 test_context,
241 &with_clause,
242 &from_clause,
243 join_expr,
244 &tokens,
245 )?;
246
247 Ok(())
248 }
249}
250
251impl DataSource {
252 fn analyze_range_table_func<TParseContext>(
253 context: TParseContext,
254 with_clause: &WithClause,
255 from_clause: &FromClause,
256 node: crate::syn::RangeTableFunc,
257 tokens: &IVec<ScanToken>,
258 ) -> Result<(Self, TParseContext), AnalysisError>
259 where
260 TParseContext: ParseContext,
261 {
262 let Some(row_expr) = node.get_rowexpr().as_inner() else {
263 AnalysisError::raise_unexpected_none("RangeTableFunc.rowexpr")?
264 };
265 let Some(call) = row_expr.as_func_call().as_inner() else {
266 AnalysisError::raise_unexpected_none("RangeTableFunc.rowexpr is not FuncCall")?
267 };
268 let _func_name = FullName::try_from(call.get_funcname())?;
269
270 Self::call_table_func(
271 context,
272 with_clause,
273 from_clause,
274 call,
275 node.get_alias().as_inner(),
276 tokens,
277 )
278 }
279}
280
281#[cfg(test)]
282mod test_data_source_analyze_range_table_func {
283 use sql_fun_core::IVec;
284 use testresult::TestResult;
285
286 use crate::{
287 sem::{DataSource, SchemaName, WithClause},
288 test_helpers::{SynBuilder, TestParseContext, setup_function_overload, test_context},
289 };
290
291 #[rstest::rstest]
292 fn test_analyze_range_table_func(mut test_context: TestParseContext) -> TestResult {
293 test_context.set_get_search_path_result(&vec![SchemaName::from("public")]);
294 let (int4, overload) = setup_function_overload();
295 test_context.setup_type(int4);
296 test_context.setup_function("table_func", &[overload.clone()]);
297
298 let builder = SynBuilder::new();
299 let func_call_node = builder.build_func_call_node("table_func");
300 let alias = builder.alias("func_alias", &[]);
301 let range_table_func = builder.build_range_table_func(func_call_node, alias);
302 let tokens = IVec::default();
303 let with_clause = WithClause::default();
304 let from_clause = super::FromClause::default();
305
306 let (ds, _) = super::DataSource::analyze_range_table_func(
307 test_context,
308 &with_clause,
309 &from_clause,
310 range_table_func,
311 &tokens,
312 )?;
313
314 let mut aliases = Vec::new();
315 ds.push_alias_names(&mut aliases);
316 assert_eq!(aliases.len(), 1);
317 assert_eq!(aliases[0].name().as_str(), "func_alias");
318 let DataSource::CallTableFunc(table_func_ds) = ds else {
319 panic!("expected table function datasource");
320 };
321 assert_eq!(table_func_ds.function(), &overload);
322 Ok(())
323 }
324}
325
326impl DataSource {
327 fn analyze_range_func_rows_from<TParseContext>(
328 mut context: TParseContext,
329 with_clause: &WithClause,
330 from_clause: &FromClause,
331 node: crate::syn::RangeFunction,
332 tokens: &IVec<ScanToken>,
333 ) -> Result<(Self, TParseContext), AnalysisError>
334 where
335 TParseContext: ParseContext,
336 {
337 let Some(alias) = node.get_alias().as_inner() else {
338 AnalysisError::raise_unexpected_none("RangeFunction.alias")?
339 };
340 let (alias, new_context) = AliasSpec::analyze_without_relname(context, &alias)?;
341 context = new_context;
342
343 let Some(functions) = node.get_functions().as_inner() else {
344 AnalysisError::raise_unexpected_none("RangeFunction.functions")?
345 };
346 let mut sem_functions = Vec::new();
347 for function in functions {
348 let (fun, new_context) = DataSourceRowsFromFunc::analyze_node(
349 context,
350 with_clause,
351 from_clause,
352 function,
353 tokens,
354 )?;
355 context = new_context;
356 sem_functions.push(fun);
357 }
358 let rf = DataSourceRowFunctions::new(&sem_functions.into(), &alias);
359
360 Ok((Self::RowFunctions(rf), context))
361 }
362}
363
364#[cfg(test)]
365mod test_data_source_analyze_range_func_rows_from {
366 use sql_fun_core::IVec;
367 use testresult::TestResult;
368
369 use crate::{
370 sem::{
371 AliasSpec, DataSource, DataSourceRowFunctions, DataSourceRowsFromFunc, SchemaName,
372 WithClause,
373 },
374 test_helpers::{SynBuilder, TestParseContext, setup_function_overload, test_context},
375 };
376
377 #[rstest::rstest]
378 fn test_analyze_range_func_rows_from(mut test_context: TestParseContext) -> TestResult {
379 test_context.set_get_search_path_result(&vec![SchemaName::from("public")]);
380 let (int4, overload) = setup_function_overload();
381 test_context.setup_type(int4);
382 let func_name = test_context.setup_function("rows_func", &[overload.clone()]);
383
384 let builder = SynBuilder::new();
385 let func_call_node = builder.build_func_call_node(func_name.local_name().as_str());
386 let range_function = builder.build_range_function(func_call_node, "rows_alias", true);
387 let tokens = IVec::default();
388 let with_clause = WithClause::default();
389 let from_clause = super::FromClause::default();
390
391 let (ds, _) = super::DataSource::analyze_range_func_rows_from(
392 test_context,
393 &with_clause,
394 &from_clause,
395 range_function,
396 &tokens,
397 )?;
398
399 let expected_rows_func = DataSourceRowsFromFunc::FuncCall(
400 func_name.clone(),
401 Vec::new(),
402 overload.returning_table(),
403 );
404 let expected_functions: IVec<_> = vec![expected_rows_func].into();
405 let expected_alias = AliasSpec::from_local_name("rows_alias");
406 let expected_row_functions =
407 DataSourceRowFunctions::new(&expected_functions, &expected_alias);
408 let expected = DataSource::RowFunctions(expected_row_functions);
409 assert_eq!(expected, ds);
410 Ok(())
411 }
412}
413
414impl DataSource {
415 fn analyze_range_func<TParseContext>(
416 context: TParseContext,
417 with_clause: &WithClause,
418 from_clause: &FromClause,
419 node: crate::syn::RangeFunction,
420 tokens: &IVec<ScanToken>,
421 ) -> Result<(Self, TParseContext), AnalysisError>
422 where
423 TParseContext: ParseContext,
424 {
425 if node.get_is_rowsfrom() {
426 return Self::analyze_range_func_rows_from(
427 context,
428 with_clause,
429 from_clause,
430 node,
431 tokens,
432 );
433 }
434
435 let Some(functions) = node
436 .get_functions()
437 .map_values(|v| v.as_list().get_items().as_inner())
438 else {
439 AnalysisError::raise_unexpected_none("RangeFunction.functions")?
440 };
441 let functions: Vec<_> = functions
442 .iter()
443 .flatten()
444 .filter_map(crate::syn::Opt::as_inner)
445 .collect();
446 if functions.len() != 1 {
447 AnalysisError::raise_unexpected_input(&format!(
448 "RangeFunction.functions len!=1 : {functions:?}"
449 ))?;
450 }
451 let function = &functions[0];
452
453 let Some(call) = function.as_func_call().as_inner() else {
454 AnalysisError::raise_unexpected_input(&format!(
455 "RangeFunction.functions[0] is not FuncCall : {functions:#?}"
456 ))?
457 };
458
459 Self::call_table_func(
460 context,
461 with_clause,
462 from_clause,
463 call,
464 node.get_alias().as_inner(),
465 tokens,
466 )
467 }
468}
469
470#[cfg(test)]
471mod test_data_source_analyze_range_functions {
472 use sql_fun_core::IVec;
473 use testresult::TestResult;
474
475 use crate::{
476 sem::{DataSource, SchemaName, WithClause},
477 test_helpers::{SynBuilder, TestParseContext, setup_function_overload, test_context},
478 };
479
480 #[rstest::rstest]
481 fn test_analyze_range_func(mut test_context: TestParseContext) -> TestResult {
482 test_context.set_get_search_path_result(&vec![SchemaName::from("public")]);
483 let (int4, overload) = setup_function_overload();
484 test_context.setup_type(int4);
485 test_context.setup_function("set_func", &[overload.clone()]);
486
487 let builder = SynBuilder::new();
488 let func_call_node = builder.build_func_call_node("set_func");
489 let functions_node = builder.build_list_node(vec![func_call_node]);
490 let range_function = builder.build_range_function(functions_node, "set_alias", false);
491 let tokens = IVec::default();
492 let with_clause = WithClause::default();
493 let from_clause = super::FromClause::default();
494
495 let (ds, _) = super::DataSource::analyze_range_func(
496 test_context,
497 &with_clause,
498 &from_clause,
499 range_function,
500 &tokens,
501 )?;
502
503 let mut aliases = Vec::new();
504 ds.push_alias_names(&mut aliases);
505 assert_eq!(aliases.len(), 1);
506 assert_eq!(aliases[0].name().as_str(), "set_alias");
507 let DataSource::CallTableFunc(table_func) = ds else {
508 panic!("expected table function datasource");
509 };
510 assert_eq!(table_func.function(), &overload);
511 Ok(())
512 }
513}
514
515impl DataSource {
516 pub fn analyze_from_clause_node<TParseContext>(
518 context: TParseContext,
519 with_clause: &WithClause,
520 from_clause: &FromClause,
521 node: crate::syn::Node,
522 tokens: &IVec<ScanToken>,
523 ) -> Result<(Self, TParseContext), AnalysisError>
524 where
525 TParseContext: ParseContext,
526 {
527 if let Some(range_var) = node.as_range_var().as_inner() {
528 Ok(Self::analyze_range_var_node(
529 context,
530 with_clause,
531 range_var,
532 )?)
533 } else if let Some(range_subq) = node.as_range_subselect().as_inner() {
534 Ok(Self::analyze_range_subselect(context, range_subq, tokens)?)
535 } else if let Some(join_expr) = node.as_join_expr().as_inner() {
536 Ok(Self::analyze_join_expr(
537 context,
538 with_clause,
539 from_clause,
540 join_expr,
541 tokens,
542 )?)
543 } else if let Some(range_tablef) = node.as_range_table_func().as_inner() {
544 Ok(Self::analyze_range_table_func(
545 context,
546 with_clause,
547 from_clause,
548 range_tablef,
549 tokens,
550 )?)
551 } else if let Some(range_fun) = node.as_range_function().as_inner() {
552 Ok(Self::analyze_range_func(
553 context,
554 with_clause,
555 from_clause,
556 range_fun,
557 tokens,
558 )?)
559 } else if let Some(_range_samp) = node.as_range_table_sample().as_inner() {
560 todo!()
561 } else {
562 AnalysisError::raise_unexpected_none("from_clause inner node")?
563 }
564 }
565}