mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-27 08:38:58 +00:00
178 lines
5.1 KiB
Rust
178 lines
5.1 KiB
Rust
// Copyright 2024 RustFS Team
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use datafusion::{common::DataFusionError, sql::sqlparser::parser::ParserError};
|
|
use std::fmt::Display;
|
|
use thiserror::Error;
|
|
|
|
pub mod object_store;
|
|
pub mod query;
|
|
pub mod server;
|
|
mod storage_api;
|
|
|
|
#[cfg(test)]
|
|
mod test;
|
|
|
|
pub type QueryResult<T> = Result<T, QueryError>;
|
|
pub(crate) use storage_api::crate_boundary::{
|
|
SELECT_DEFAULT_READ_BUFFER_SIZE, SelectGetObjectReader, SelectObjectInfo, SelectObjectOptions, SelectStorageError,
|
|
SelectStore, resolve_select_object_store_handle, select_is_err_bucket_not_found, select_is_err_object_not_found,
|
|
select_is_err_version_not_found,
|
|
};
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum QueryError {
|
|
#[error("DataFusion error: {source}")]
|
|
Datafusion { source: Box<DataFusionError> },
|
|
|
|
#[error("This feature is not implemented: {err}")]
|
|
NotImplemented { err: String },
|
|
|
|
#[error("Multi-statement not allow, found num:{num}, sql:{sql}")]
|
|
MultiStatement { num: usize, sql: String },
|
|
|
|
#[error("Failed to build QueryDispatcher. err: {err}")]
|
|
BuildQueryDispatcher { err: String },
|
|
|
|
#[error("The query has been canceled")]
|
|
Cancel,
|
|
|
|
#[error("{source}")]
|
|
Parser {
|
|
#[from]
|
|
source: ParserError,
|
|
},
|
|
|
|
#[error("Udf not exists, name:{name}.")]
|
|
FunctionNotExists { name: String },
|
|
|
|
#[error("Udf already exists, name:{name}.")]
|
|
FunctionExists { name: String },
|
|
|
|
#[error("Store Error, e:{e}.")]
|
|
StoreError { e: String },
|
|
}
|
|
|
|
impl From<DataFusionError> for QueryError {
|
|
fn from(value: DataFusionError) -> Self {
|
|
match value {
|
|
DataFusionError::External(e) => match e.downcast::<QueryError>() {
|
|
Ok(query_error) => *query_error,
|
|
Err(e) => Self::Datafusion {
|
|
source: Box::new(DataFusionError::External(e)),
|
|
},
|
|
},
|
|
v => Self::Datafusion { source: Box::new(v) },
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct ResolvedTable {
|
|
// path
|
|
table: String,
|
|
}
|
|
|
|
impl ResolvedTable {
|
|
pub fn table(&self) -> &str {
|
|
&self.table
|
|
}
|
|
}
|
|
|
|
impl Display for ResolvedTable {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let Self { table } = self;
|
|
write!(f, "{table}")
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use datafusion::common::DataFusionError;
|
|
use datafusion::sql::sqlparser::parser::ParserError;
|
|
|
|
#[test]
|
|
fn test_query_error_display() {
|
|
let err = QueryError::NotImplemented {
|
|
err: "feature X".to_string(),
|
|
};
|
|
assert_eq!(err.to_string(), "This feature is not implemented: feature X");
|
|
|
|
let err = QueryError::MultiStatement {
|
|
num: 2,
|
|
sql: "SELECT 1; SELECT 2;".to_string(),
|
|
};
|
|
assert_eq!(err.to_string(), "Multi-statement not allow, found num:2, sql:SELECT 1; SELECT 2;");
|
|
|
|
let err = QueryError::Cancel;
|
|
assert_eq!(err.to_string(), "The query has been canceled");
|
|
|
|
let err = QueryError::FunctionNotExists {
|
|
name: "my_func".to_string(),
|
|
};
|
|
assert_eq!(err.to_string(), "Udf not exists, name:my_func.");
|
|
|
|
let err = QueryError::StoreError {
|
|
e: "connection failed".to_string(),
|
|
};
|
|
assert_eq!(err.to_string(), "Store Error, e:connection failed.");
|
|
}
|
|
|
|
#[test]
|
|
fn test_query_error_from_datafusion_error() {
|
|
let df_error = DataFusionError::Plan("invalid plan".to_string());
|
|
let query_error: QueryError = df_error.into();
|
|
|
|
match query_error {
|
|
QueryError::Datafusion { source, .. } => {
|
|
assert!(source.to_string().contains("invalid plan"));
|
|
}
|
|
_ => panic!("Expected Datafusion error"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_query_error_from_parser_error() {
|
|
let parser_error = ParserError::ParserError("syntax error".to_string());
|
|
let query_error = QueryError::Parser { source: parser_error };
|
|
|
|
assert!(query_error.to_string().contains("syntax error"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_resolved_table() {
|
|
let table = ResolvedTable {
|
|
table: "my_table".to_string(),
|
|
};
|
|
|
|
assert_eq!(table.table(), "my_table");
|
|
assert_eq!(table.to_string(), "my_table");
|
|
}
|
|
|
|
#[test]
|
|
fn test_resolved_table_clone_and_eq() {
|
|
let table1 = ResolvedTable {
|
|
table: "table1".to_string(),
|
|
};
|
|
let table2 = table1.clone();
|
|
let table3 = ResolvedTable {
|
|
table: "table2".to_string(),
|
|
};
|
|
|
|
assert_eq!(table1, table2);
|
|
assert_ne!(table1, table3);
|
|
}
|
|
}
|