mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-08-22 05:58:33 +00:00
fix(metric-engine): validate logical projection indices (#8535)
* fix(metric-engine): validate logical projection indices Signed-off-by: discord9 <discord9@163.com> * perf(metric-engine): avoid cloning projection names Signed-off-by: discord9 <discord9@163.com> --------- Signed-off-by: discord9 <discord9@163.com>
This commit is contained in:
@@ -25,7 +25,8 @@ use store_api::storage::{RegionId, ScanRequest, SequenceNumber};
|
||||
|
||||
use crate::engine::MetricEngineInner;
|
||||
use crate::error::{
|
||||
InvalidMetadataSnafu, LogicalRegionNotFoundSnafu, MitoReadOperationSnafu, Result,
|
||||
InvalidMetadataSnafu, InvalidRequestSnafu, LogicalRegionNotFoundSnafu, MitoReadOperationSnafu,
|
||||
Result,
|
||||
};
|
||||
use crate::metrics::MITO_OPERATION_ELAPSED;
|
||||
use crate::utils;
|
||||
@@ -192,8 +193,16 @@ impl MetricEngineInner {
|
||||
.await?;
|
||||
let projected_logical_names = origin_projection
|
||||
.iter()
|
||||
.map(|i| all_logical_columns[*i].clone())
|
||||
.collect::<Vec<_>>();
|
||||
.map(|&index| {
|
||||
all_logical_columns
|
||||
.get(index)
|
||||
.map(String::as_str)
|
||||
.with_context(|| InvalidRequestSnafu {
|
||||
region_id: logical_region_id,
|
||||
reason: format!("projection index {index} is out of bounds"),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// generate physical projection
|
||||
let mut physical_projection = Vec::with_capacity(origin_projection.len());
|
||||
@@ -206,7 +215,7 @@ impl MetricEngineInner {
|
||||
|
||||
for name in projected_logical_names {
|
||||
// Safety: logical columns is a strict subset of physical columns
|
||||
physical_projection.push(physical_metadata.column_index_by_name(&name).unwrap());
|
||||
physical_projection.push(physical_metadata.column_index_by_name(name).unwrap());
|
||||
}
|
||||
|
||||
Ok(physical_projection)
|
||||
@@ -302,6 +311,8 @@ impl MetricEngineInner {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use common_error::ext::ErrorExt;
|
||||
use common_error::status_code::StatusCode;
|
||||
use store_api::region_request::RegionRequest;
|
||||
|
||||
use super::*;
|
||||
@@ -309,6 +320,33 @@ mod test {
|
||||
TestEnv, alter_logical_region_add_tag_columns, create_logical_region_request,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_invalid_logical_projection() {
|
||||
let env = TestEnv::new().await;
|
||||
env.init_metric_region().await;
|
||||
|
||||
let logical_region_id = env.default_logical_region_id();
|
||||
let invalid_index = usize::MAX;
|
||||
let request = ScanRequest {
|
||||
projection_input: Some(vec![invalid_index].into()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let error =
|
||||
match RegionEngine::handle_query(&env.metric(), logical_region_id, request).await {
|
||||
Ok(_) => panic!("invalid logical projection unexpectedly succeeded"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert_eq!(error.status_code(), StatusCode::InvalidArguments);
|
||||
assert!(
|
||||
error.to_string().contains(&format!(
|
||||
"projection index {invalid_index} is out of bounds"
|
||||
)),
|
||||
"unexpected error: {error}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_scan_req() {
|
||||
let env = TestEnv::new().await;
|
||||
|
||||
Reference in New Issue
Block a user