1use std::any::Any;
16
17use common_error::ext::{BoxedError, ErrorExt};
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use common_query::error::datafusion_status_code;
21use datafusion::error::DataFusionError;
22use datatypes::arrow::error::ArrowError;
23use snafu::{Location, Snafu};
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27#[derive(Snafu)]
29#[snafu(visibility(pub))]
30#[stack_trace_debug]
31pub enum Error {
32 #[snafu(display("DataFusion error"))]
33 Datafusion {
34 #[snafu(source)]
35 error: DataFusionError,
36 #[snafu(implicit)]
37 location: Location,
38 },
39
40 #[snafu(display("Failed to convert Arrow schema"))]
41 SchemaConversion {
42 source: datatypes::error::Error,
43 #[snafu(implicit)]
44 location: Location,
45 },
46
47 #[snafu(display("Table projection error"))]
48 TableProjection {
49 #[snafu(source)]
50 error: ArrowError,
51 #[snafu(implicit)]
52 location: Location,
53 },
54
55 #[snafu(display("Failed to create record batch for Tables"))]
56 TablesRecordBatch {
57 #[snafu(implicit)]
58 location: Location,
59 source: BoxedError,
60 },
61
62 #[snafu(display("Column {column_name} already exists in table {table_name}"))]
63 ColumnExists {
64 column_name: String,
65 table_name: String,
66 #[snafu(implicit)]
67 location: Location,
68 },
69
70 #[snafu(display("Failed to build schema, msg: {}", msg))]
71 SchemaBuild {
72 #[snafu(implicit)]
73 location: Location,
74 source: datatypes::error::Error,
75 msg: String,
76 },
77
78 #[snafu(display("Column {} not exists in table {}", column_name, table_name))]
79 ColumnNotExists {
80 column_name: String,
81 table_name: String,
82 #[snafu(implicit)]
83 location: Location,
84 },
85
86 #[snafu(display(
87 "Not allowed to remove index column {} from table {}",
88 column_name,
89 table_name
90 ))]
91 RemoveColumnInIndex {
92 column_name: String,
93 table_name: String,
94 #[snafu(implicit)]
95 location: Location,
96 },
97
98 #[snafu(display(
99 "Failed to build column descriptor for table: {}, column: {}",
100 table_name,
101 column_name,
102 ))]
103 BuildColumnDescriptor {
104 #[snafu(source)]
105 error: store_api::storage::ColumnDescriptorBuilderError,
106 table_name: String,
107 column_name: String,
108 #[snafu(implicit)]
109 location: Location,
110 },
111
112 #[snafu(display("Failed to operate table"))]
113 TableOperation { source: BoxedError },
114
115 #[snafu(display("Unsupported operation: {}", operation))]
116 Unsupported { operation: String },
117
118 #[snafu(display("Failed to parse table option, key: {}, value: {}", key, value))]
119 ParseTableOption {
120 key: String,
121 value: String,
122 #[snafu(implicit)]
123 location: Location,
124 },
125
126 #[snafu(display("Invalid alter table({}) request: {}", table, err))]
127 InvalidAlterRequest {
128 table: String,
129 #[snafu(implicit)]
130 location: Location,
131 err: String,
132 },
133
134 #[snafu(display("Missing time index column in table: {}", table_name))]
135 MissingTimeIndexColumn {
136 table_name: String,
137 #[snafu(implicit)]
138 location: Location,
139 },
140
141 #[snafu(display("Table options value is not valid, key: `{}`, value: `{}`", key, value))]
142 InvalidTableOptionValue { key: String, value: String },
143
144 #[snafu(display("Invalid column option, column name: {}, error: {}", column_name, msg))]
145 InvalidColumnOption {
146 column_name: String,
147 msg: String,
148 #[snafu(implicit)]
149 location: Location,
150 },
151
152 #[snafu(display("Failed to set fulltext options for column {}", column_name))]
153 SetFulltextOptions {
154 column_name: String,
155 source: datatypes::Error,
156 #[snafu(implicit)]
157 location: Location,
158 },
159
160 #[snafu(display("Failed to set skipping index options for column {}", column_name))]
161 SetSkippingOptions {
162 column_name: String,
163 source: datatypes::Error,
164 #[snafu(implicit)]
165 location: Location,
166 },
167
168 #[snafu(display("Failed to unset skipping index options for column {}", column_name))]
169 UnsetSkippingOptions {
170 column_name: String,
171 source: datatypes::Error,
172 #[snafu(implicit)]
173 location: Location,
174 },
175
176 #[snafu(display("Invalid table name: '{s}'"))]
177 InvalidTableName { s: String },
178}
179
180impl ErrorExt for Error {
181 fn status_code(&self) -> StatusCode {
182 match self {
183 Error::Datafusion { error, .. } => datafusion_status_code::<Self>(error, None),
184 Error::SchemaConversion { .. } | Error::TableProjection { .. } => {
185 StatusCode::EngineExecuteQuery
186 }
187 Error::RemoveColumnInIndex { .. }
188 | Error::BuildColumnDescriptor { .. }
189 | Error::InvalidAlterRequest { .. } => StatusCode::InvalidArguments,
190 Error::TablesRecordBatch { .. } => StatusCode::Unexpected,
191 Error::ColumnExists { .. } => StatusCode::TableColumnExists,
192 Error::SchemaBuild { source, .. } | Error::SetFulltextOptions { source, .. } => {
193 source.status_code()
194 }
195 Error::TableOperation { source } => source.status_code(),
196 Error::InvalidColumnOption { .. } => StatusCode::InvalidArguments,
197 Error::ColumnNotExists { .. } => StatusCode::TableColumnNotFound,
198 Error::Unsupported { .. } => StatusCode::Unsupported,
199 Error::ParseTableOption { .. } => StatusCode::InvalidArguments,
200 Error::MissingTimeIndexColumn { .. } => StatusCode::IllegalState,
201 Error::InvalidTableOptionValue { .. }
202 | Error::SetSkippingOptions { .. }
203 | Error::UnsetSkippingOptions { .. }
204 | Error::InvalidTableName { .. } => StatusCode::InvalidArguments,
205 }
206 }
207
208 fn as_any(&self) -> &dyn Any {
209 self
210 }
211}
212
213impl From<Error> for DataFusionError {
214 fn from(e: Error) -> DataFusionError {
215 DataFusionError::External(Box::new(e))
216 }
217}