1use arrow::datatypes::DataType;
2use datafusion::{
3 common::{DataFusionError, JoinConstraint, JoinType},
4 logical_expr::{
5 expr::{AggregateFunction, Placeholder},
6 Expr, Operator,
7 },
8 physical_plan,
9};
10use derive_more::Display;
11use proof_of_sql::{
12 base::math::decimal::DecimalError,
13 sql::{proof_plans::AggregateExecError, AnalyzeError},
14};
15use snafu::Snafu;
16use sqlparser::parser::ParserError;
17
18#[non_exhaustive]
20#[derive(Clone, Debug, Eq, PartialEq, Snafu)]
21pub enum AggregatePlanError {
22 #[snafu(display("group expression {expression} has no output alias"))]
24 MissingGroupExpressionAlias {
25 expression: String,
27 },
28 #[snafu(display("aggregate expression {expression} has no output alias"))]
30 MissingAggregateExpressionAlias {
31 expression: String,
33 },
34 #[snafu(display("aggregate expression list contains non-aggregate expression {expression}"))]
36 UnexpectedAggregateExpression {
37 expression: String,
39 },
40 #[snafu(transparent)]
42 AggregateExec {
43 source: AggregateExecError,
45 },
46}
47
48#[non_exhaustive]
50#[derive(Clone, Debug, Eq, PartialEq, Snafu)]
51pub enum JoinPlanError {
52 #[snafu(display("join type {join_type} is not supported"))]
54 UnsupportedJoinType {
55 join_type: JoinType,
57 },
58 #[snafu(display("join constraint {constraint:?} is not supported"))]
60 UnsupportedJoinConstraint {
61 constraint: JoinConstraint,
63 },
64 #[snafu(display(
66 "join predicate must pair supported columns with the same unqualified name, found {left} and {right}"
67 ))]
68 UnsupportedPredicate {
69 left: String,
71 right: String,
73 },
74}
75
76#[non_exhaustive]
78#[derive(Clone, Copy, Debug, Display, Eq, PartialEq)]
79pub enum LogicalPlanNodeKind {
80 #[display(fmt = "window")]
82 Window,
83 #[display(fmt = "sort")]
85 Sort,
86 #[display(fmt = "cross join")]
88 CrossJoin,
89 #[display(fmt = "repartition")]
91 Repartition,
92 #[display(fmt = "table scan")]
94 TableScan,
95 #[display(fmt = "subquery")]
97 Subquery,
98 #[display(fmt = "statement")]
100 Statement,
101 #[display(fmt = "values")]
103 Values,
104 #[display(fmt = "explain")]
106 Explain,
107 #[display(fmt = "analyze")]
109 Analyze,
110 #[display(fmt = "extension")]
112 Extension,
113 #[display(fmt = "distinct")]
115 Distinct,
116 #[display(fmt = "prepare")]
118 Prepare,
119 #[display(fmt = "data manipulation")]
121 Dml,
122 #[display(fmt = "data definition")]
124 Ddl,
125 #[display(fmt = "copy")]
127 Copy,
128 #[display(fmt = "describe table")]
130 DescribeTable,
131 #[display(fmt = "unnest")]
133 Unnest,
134 #[display(fmt = "recursive query")]
136 RecursiveQuery,
137}
138
139#[non_exhaustive]
141#[derive(Debug, Snafu)]
142pub enum PlannerError {
143 #[snafu(transparent)]
145 AnalyzeError {
146 source: AnalyzeError,
148 },
149 #[snafu(transparent)]
151 DecimalError {
152 source: DecimalError,
154 },
155 #[snafu(transparent)]
157 SqlParserError {
158 source: ParserError,
160 },
161 #[snafu(transparent)]
163 DataFusionError {
164 source: DataFusionError,
166 },
167 #[snafu(display("Column not found"))]
169 ColumnNotFound,
170 #[snafu(display("Table not found: {}", table_name))]
172 TableNotFound {
173 table_name: String,
175 },
176 #[snafu(display("Placeholder id {id:?} is invalid"))]
178 InvalidPlaceholderId {
179 id: String,
181 },
182 #[snafu(display("Placeholder {placeholder:?} is untyped"))]
184 UntypedPlaceholder {
185 placeholder: Placeholder,
187 },
188 #[snafu(display("Unsupported datatype: {}", data_type))]
190 UnsupportedDataType {
191 data_type: DataType,
193 },
194 #[snafu(display("Binary operator {} is not supported", op))]
196 UnsupportedBinaryOperator {
197 op: Operator,
199 },
200 #[snafu(display("Aggregate operation {op:?} is not supported"))]
202 UnsupportedAggregateOperation {
203 op: physical_plan::aggregates::AggregateFunction,
205 },
206 #[snafu(display("AggregateFunction {function:?} is not supported"))]
208 UnsupportedAggregateFunction {
209 function: AggregateFunction,
211 },
212 #[snafu(display("Logical expression {:?} is not supported", expr))]
214 UnsupportedLogicalExpression {
215 expr: Box<Expr>,
217 },
218 #[snafu(
220 context(false),
221 display("Aggregate logical plan is not supported: {source}")
222 )]
223 UnsupportedAggregatePlan {
224 source: AggregatePlanError,
226 },
227 #[snafu(
229 context(false),
230 display("Join logical plan is not supported: {source}")
231 )]
232 UnsupportedJoinPlan {
233 source: JoinPlanError,
235 },
236 #[snafu(display("Logical plan node or shape {node} is not supported"))]
238 UnsupportedLogicalPlan {
239 node: LogicalPlanNodeKind,
241 },
242 #[snafu(display("LogicalPlan is not resolved"))]
244 UnresolvedLogicalPlan,
245 #[snafu(display("Catalog is not supported"))]
247 CatalogNotSupported,
248}
249
250pub type PlannerResult<T> = Result<T, PlannerError>;
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256 use proof_of_sql::base::database::ColumnType;
257
258 #[test]
259 fn planner_sub_errors_include_actionable_context() {
260 assert_eq!(
261 AggregatePlanError::MissingGroupExpressionAlias {
262 expression: "table.id".to_string(),
263 }
264 .to_string(),
265 "group expression table.id has no output alias"
266 );
267 assert_eq!(
268 AggregatePlanError::AggregateExec {
269 source: AggregateExecError::UnsupportedGroupByExpressionType {
270 data_type: ColumnType::VarChar,
271 },
272 }
273 .to_string(),
274 "grouping and deduplication do not support expressions of type VARCHAR"
275 );
276 assert_eq!(
277 JoinPlanError::UnsupportedPredicate {
278 left: "left.a".to_string(),
279 right: "right.b".to_string(),
280 }
281 .to_string(),
282 "join predicate must pair supported columns with the same unqualified name, found left.a and right.b"
283 );
284 }
285
286 #[test]
287 fn logical_plan_node_kinds_have_human_readable_labels() {
288 let expected_labels = [
289 (LogicalPlanNodeKind::Window, "window"),
290 (LogicalPlanNodeKind::Sort, "sort"),
291 (LogicalPlanNodeKind::CrossJoin, "cross join"),
292 (LogicalPlanNodeKind::Repartition, "repartition"),
293 (LogicalPlanNodeKind::TableScan, "table scan"),
294 (LogicalPlanNodeKind::Subquery, "subquery"),
295 (LogicalPlanNodeKind::Statement, "statement"),
296 (LogicalPlanNodeKind::Values, "values"),
297 (LogicalPlanNodeKind::Explain, "explain"),
298 (LogicalPlanNodeKind::Analyze, "analyze"),
299 (LogicalPlanNodeKind::Extension, "extension"),
300 (LogicalPlanNodeKind::Distinct, "distinct"),
301 (LogicalPlanNodeKind::Prepare, "prepare"),
302 (LogicalPlanNodeKind::Dml, "data manipulation"),
303 (LogicalPlanNodeKind::Ddl, "data definition"),
304 (LogicalPlanNodeKind::Copy, "copy"),
305 (LogicalPlanNodeKind::DescribeTable, "describe table"),
306 (LogicalPlanNodeKind::Unnest, "unnest"),
307 (LogicalPlanNodeKind::RecursiveQuery, "recursive query"),
308 ];
309
310 for (node, expected_label) in expected_labels {
311 assert_eq!(node.to_string(), expected_label);
312 }
313 }
314}