multisql/executor/query/
mod.rs

1mod get_columns;
2mod get_data;
3mod get_rows;
4mod select;
5mod set_expr;
6
7pub use select::{join::*, ManualError, Plan, PlanError, SelectError};
8use {
9	crate::{
10		recipe::{MetaRecipe, RecipeUtilities},
11		result::Result,
12		types::LabelsAndRows,
13		Cast, Glue, Value,
14	},
15	async_recursion::async_recursion,
16	serde::Serialize,
17	sqlparser::ast::{Cte, Query, TableAlias, With},
18	thiserror::Error as ThisError,
19};
20
21const ENSURE_SIZE: bool = true;
22
23#[derive(ThisError, Serialize, Debug, PartialEq)]
24pub enum QueryError {
25	#[error("query not supported")]
26	QueryNotSupported,
27	#[error("values does not support columns, aggregates or subqueries")]
28	MissingComponentsForValues,
29	#[error("limit does not support columns, aggregates or subqueries")]
30	MissingComponentsForLimit,
31	#[error("offset does not support columns, aggregates or subqueries")]
32	MissingComponentsForOffset,
33	#[error("expected values but found none")]
34	NoValues,
35	#[error(
36		"UNION/EXCEPT/INTERSECT columns misaligned, sides should have an equal number of columns"
37	)]
38	OperationColumnsMisaligned,
39}
40
41impl Glue {
42	#[async_recursion(?Send)]
43	pub async fn ast_query(&mut self, query: Query) -> Result<LabelsAndRows> {
44		let Query {
45			body,
46			order_by,
47			limit,
48			offset,
49			with,
50			// TODO (below)
51			fetch: _,
52			lock: _,
53		} = query;
54
55		let limit: Option<usize> = limit
56			.map(|expression| {
57				MetaRecipe::new(expression)?
58					.simplify_by_tempdb(&self.tempdb)?
59					.confirm_or_err(QueryError::MissingComponentsForLimit.into())?
60					.cast()
61			})
62			.transpose()?;
63		let offset: Option<usize> = offset
64			.map(|offset| {
65				MetaRecipe::new(offset.value)?
66					.simplify_by_tempdb(&self.tempdb)?
67					.confirm_or_err(QueryError::MissingComponentsForOffset.into())?
68					.cast()
69			})
70			.transpose()?;
71
72		if let Some(with) = with {
73			let With {
74				recursive: _, // Recursive not currently supported
75				cte_tables,
76			} = with;
77			for cte in cte_tables.into_iter() {
78				let Cte {
79					alias,
80					query,
81					from: _, // What is `from` for?
82				} = cte;
83				let TableAlias {
84					name,
85					columns: _, // TODO: Columns - Check that number is same and then rename labels
86				} = alias;
87				let name = name.value;
88				let data = self.ast_query(query).await?;
89				self.tempdb.set_table(name, data);
90			}
91		}
92
93		let (mut labels, mut rows) = self.from_body(body, order_by).await?;
94
95		if let Some(offset) = offset {
96			rows.drain(0..offset);
97		}
98		if let Some(limit) = limit {
99			rows.truncate(limit);
100		}
101		if ENSURE_SIZE {
102			let row_width = rows
103				.iter()
104				.map(|values_row| values_row.len())
105				.max()
106				.unwrap_or(0);
107			if row_width > 0 {
108				rows = rows
109					.into_iter()
110					.map(|mut row| {
111						row.resize(row_width, Value::Null);
112						row
113					})
114					.collect();
115				labels.resize(row_width, String::new())
116			};
117		}
118		Ok((labels, rows))
119	}
120}