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 #[snafu(display("Failed to cast default value, reason: {}", reason))]
180 CastDefaultValue {
181 reason: String,
182 source: datatypes::Error,
183 #[snafu(implicit)]
184 location: Location,
185 },
186}
187
188impl ErrorExt for Error {
189 fn status_code(&self) -> StatusCode {
190 match self {
191 Error::Datafusion { error, .. } => datafusion_status_code::<Self>(error, None),
192 Error::SchemaConversion { .. } | Error::TableProjection { .. } => {
193 StatusCode::EngineExecuteQuery
194 }
195 Error::RemoveColumnInIndex { .. }
196 | Error::BuildColumnDescriptor { .. }
197 | Error::InvalidAlterRequest { .. } => StatusCode::InvalidArguments,
198 Error::CastDefaultValue { source, .. } => source.status_code(),
199 Error::TablesRecordBatch { .. } => StatusCode::Unexpected,
200 Error::ColumnExists { .. } => StatusCode::TableColumnExists,
201 Error::SchemaBuild { source, .. } | Error::SetFulltextOptions { source, .. } => {
202 source.status_code()
203 }
204 Error::TableOperation { source } => source.status_code(),
205 Error::InvalidColumnOption { .. } => StatusCode::InvalidArguments,
206 Error::ColumnNotExists { .. } => StatusCode::TableColumnNotFound,
207 Error::Unsupported { .. } => StatusCode::Unsupported,
208 Error::ParseTableOption { .. } => StatusCode::InvalidArguments,
209 Error::MissingTimeIndexColumn { .. } => StatusCode::IllegalState,
210 Error::InvalidTableOptionValue { .. }
211 | Error::SetSkippingOptions { .. }
212 | Error::UnsetSkippingOptions { .. }
213 | Error::InvalidTableName { .. } => StatusCode::InvalidArguments,
214 }
215 }
216
217 fn as_any(&self) -> &dyn Any {
218 self
219 }
220}
221
222impl From<Error> for DataFusionError {
223 fn from(e: Error) -> DataFusionError {
224 DataFusionError::External(Box::new(e))
225 }
226}