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 "Not allowed to remove partition column {} from table {}",
100 column_name,
101 table_name
102 ))]
103 RemovePartitionColumn {
104 column_name: String,
105 table_name: String,
106 #[snafu(implicit)]
107 location: Location,
108 },
109
110 #[snafu(display(
111 "Failed to build column descriptor for table: {}, column: {}",
112 table_name,
113 column_name,
114 ))]
115 BuildColumnDescriptor {
116 #[snafu(source)]
117 error: store_api::storage::ColumnDescriptorBuilderError,
118 table_name: String,
119 column_name: String,
120 #[snafu(implicit)]
121 location: Location,
122 },
123
124 #[snafu(display("Failed to operate table"))]
125 TableOperation { source: BoxedError },
126
127 #[snafu(display("Unsupported operation: {}", operation))]
128 Unsupported { operation: String },
129
130 #[snafu(display("Failed to parse table option, key: {}, value: {}", key, value))]
131 ParseTableOption {
132 key: String,
133 value: String,
134 #[snafu(implicit)]
135 location: Location,
136 },
137
138 #[snafu(display(
139 "Conflicting table options: {}={} and {}={}",
140 first_key,
141 first_value,
142 second_key,
143 second_value
144 ))]
145 ConflictingTableOptions {
146 first_key: String,
147 first_value: String,
148 second_key: String,
149 second_value: String,
150 #[snafu(implicit)]
151 location: Location,
152 },
153
154 #[snafu(display("Invalid alter table({}) request: {}", table, err))]
155 InvalidAlterRequest {
156 table: String,
157 #[snafu(implicit)]
158 location: Location,
159 err: String,
160 },
161
162 #[snafu(display("Missing time index column in table: {}", table_name))]
163 MissingTimeIndexColumn {
164 table_name: String,
165 #[snafu(implicit)]
166 location: Location,
167 },
168
169 #[snafu(display("Invalid column option, column name: {}, error: {}", column_name, msg))]
170 InvalidColumnOption {
171 column_name: String,
172 msg: String,
173 #[snafu(implicit)]
174 location: Location,
175 },
176
177 #[snafu(display("Failed to set fulltext options for column {}", column_name))]
178 SetFulltextOptions {
179 column_name: String,
180 source: datatypes::Error,
181 #[snafu(implicit)]
182 location: Location,
183 },
184
185 #[snafu(display("Failed to set skipping index options for column {}", column_name))]
186 SetSkippingOptions {
187 column_name: String,
188 source: datatypes::Error,
189 #[snafu(implicit)]
190 location: Location,
191 },
192
193 #[snafu(display("Failed to unset skipping index options for column {}", column_name))]
194 UnsetSkippingOptions {
195 column_name: String,
196 source: datatypes::Error,
197 #[snafu(implicit)]
198 location: Location,
199 },
200
201 #[snafu(display("Invalid table name: '{s}'"))]
202 InvalidTableName { s: String },
203
204 #[snafu(display("Failed to cast default value, reason: {}", reason))]
205 CastDefaultValue {
206 reason: String,
207 source: datatypes::Error,
208 #[snafu(implicit)]
209 location: Location,
210 },
211
212 #[snafu(display("Sql common error"))]
213 SqlCommon {
214 source: common_sql::error::Error,
215 #[snafu(implicit)]
216 location: Location,
217 },
218}
219
220impl ErrorExt for Error {
221 fn status_code(&self) -> StatusCode {
222 match self {
223 Error::Datafusion { error, .. } => datafusion_status_code::<Self>(error, None),
224 Error::SchemaConversion { .. } | Error::TableProjection { .. } => {
225 StatusCode::EngineExecuteQuery
226 }
227 Error::RemoveColumnInIndex { .. }
228 | Error::RemovePartitionColumn { .. }
229 | Error::BuildColumnDescriptor { .. }
230 | Error::InvalidAlterRequest { .. } => StatusCode::InvalidArguments,
231 Error::CastDefaultValue { source, .. } => source.status_code(),
232 Error::TablesRecordBatch { .. } => StatusCode::Unexpected,
233 Error::ColumnExists { .. } => StatusCode::TableColumnExists,
234 Error::SqlCommon { source, .. } => source.status_code(),
235 Error::SchemaBuild { source, .. } | Error::SetFulltextOptions { source, .. } => {
236 source.status_code()
237 }
238 Error::TableOperation { source } => source.status_code(),
239 Error::InvalidColumnOption { .. } => StatusCode::InvalidArguments,
240 Error::ColumnNotExists { .. } => StatusCode::TableColumnNotFound,
241 Error::Unsupported { .. } => StatusCode::Unsupported,
242 Error::ParseTableOption { .. } | Error::ConflictingTableOptions { .. } => {
243 StatusCode::InvalidArguments
244 }
245 Error::MissingTimeIndexColumn { .. } => StatusCode::IllegalState,
246 Error::SetSkippingOptions { .. }
247 | Error::UnsetSkippingOptions { .. }
248 | Error::InvalidTableName { .. } => StatusCode::InvalidArguments,
249 }
250 }
251
252 fn as_any(&self) -> &dyn Any {
253 self
254 }
255}
256
257impl From<Error> for DataFusionError {
258 fn from(e: Error) -> DataFusionError {
259 DataFusionError::External(Box::new(e))
260 }
261}