table/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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/// Default error implementation of table.
28#[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}