use std::any::Any;
use common_error::ext::{BoxedError, ErrorExt};
use common_error::status_code::StatusCode;
use common_macro::stack_trace_debug;
use common_query::error::datafusion_status_code;
use datafusion::error::DataFusionError;
use datatypes::arrow::error::ArrowError;
use snafu::{Location, Snafu};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Snafu)]
#[snafu(visibility(pub))]
#[stack_trace_debug]
pub enum Error {
#[snafu(display("DataFusion error"))]
Datafusion {
#[snafu(source)]
error: DataFusionError,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Failed to convert Arrow schema"))]
SchemaConversion {
source: datatypes::error::Error,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Table projection error"))]
TableProjection {
#[snafu(source)]
error: ArrowError,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Failed to create record batch for Tables"))]
TablesRecordBatch {
#[snafu(implicit)]
location: Location,
source: BoxedError,
},
#[snafu(display("Column {column_name} already exists in table {table_name}"))]
ColumnExists {
column_name: String,
table_name: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Failed to build schema, msg: {}", msg))]
SchemaBuild {
#[snafu(implicit)]
location: Location,
source: datatypes::error::Error,
msg: String,
},
#[snafu(display("Column {} not exists in table {}", column_name, table_name))]
ColumnNotExists {
column_name: String,
table_name: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display(
"Not allowed to remove index column {} from table {}",
column_name,
table_name
))]
RemoveColumnInIndex {
column_name: String,
table_name: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display(
"Failed to build column descriptor for table: {}, column: {}",
table_name,
column_name,
))]
BuildColumnDescriptor {
#[snafu(source)]
error: store_api::storage::ColumnDescriptorBuilderError,
table_name: String,
column_name: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Failed to operate table"))]
TableOperation { source: BoxedError },
#[snafu(display("Unsupported operation: {}", operation))]
Unsupported { operation: String },
#[snafu(display("Failed to parse table option, key: {}, value: {}", key, value))]
ParseTableOption {
key: String,
value: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Invalid alter table({}) request: {}", table, err))]
InvalidAlterRequest {
table: String,
#[snafu(implicit)]
location: Location,
err: String,
},
#[snafu(display("Missing time index column in table: {}", table_name))]
MissingTimeIndexColumn {
table_name: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Table options value is not valid, key: `{}`, value: `{}`", key, value))]
InvalidTableOptionValue { key: String, value: String },
#[snafu(display("Invalid column option, column name: {}, error: {}", column_name, msg))]
InvalidColumnOption {
column_name: String,
msg: String,
#[snafu(implicit)]
location: Location,
},
#[snafu(display("Failed to set fulltext options for column {}", column_name))]
SetFulltextOptions {
column_name: String,
source: datatypes::Error,
#[snafu(implicit)]
location: Location,
},
}
impl ErrorExt for Error {
fn status_code(&self) -> StatusCode {
match self {
Error::Datafusion { error, .. } => datafusion_status_code::<Self>(error, None),
Error::SchemaConversion { .. } | Error::TableProjection { .. } => {
StatusCode::EngineExecuteQuery
}
Error::RemoveColumnInIndex { .. }
| Error::BuildColumnDescriptor { .. }
| Error::InvalidAlterRequest { .. } => StatusCode::InvalidArguments,
Error::TablesRecordBatch { .. } => StatusCode::Unexpected,
Error::ColumnExists { .. } => StatusCode::TableColumnExists,
Error::SchemaBuild { source, .. } | Error::SetFulltextOptions { source, .. } => {
source.status_code()
}
Error::TableOperation { source } => source.status_code(),
Error::InvalidColumnOption { .. } => StatusCode::InvalidArguments,
Error::ColumnNotExists { .. } => StatusCode::TableColumnNotFound,
Error::Unsupported { .. } => StatusCode::Unsupported,
Error::ParseTableOption { .. } => StatusCode::InvalidArguments,
Error::MissingTimeIndexColumn { .. } => StatusCode::IllegalState,
Error::InvalidTableOptionValue { .. } => StatusCode::InvalidArguments,
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl From<Error> for DataFusionError {
fn from(e: Error) -> DataFusionError {
DataFusionError::External(Box::new(e))
}
}