Skip to main content

metric_engine/engine/alter/
extract_new_columns.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::collections::{HashMap, HashSet};
16
17use api::v1::SemanticType;
18use common_query::native_histogram::is_native_histogram_value_type;
19use snafu::ensure;
20use store_api::metadata::ColumnMetadata;
21use store_api::region_request::{AlterKind, RegionAlterRequest};
22use store_api::storage::RegionId;
23
24use crate::error::{AddingFieldColumnSnafu, Result};
25
26/// Extract new columns from the create requests.
27///
28/// # Panics
29///
30/// This function will panic if the alter kind is not `AddColumns`.
31pub fn extract_new_columns<'a>(
32    requests: &'a [(RegionId, RegionAlterRequest)],
33    physical_columns: &HashMap<String, ColumnMetadata>,
34    new_column_names: &mut HashSet<&'a str>,
35    new_columns: &mut Vec<ColumnMetadata>,
36) -> Result<()> {
37    for (_, request) in requests {
38        let AlterKind::AddColumns { columns } = &request.kind else {
39            unreachable!()
40        };
41        for col in columns {
42            let column_name = col.column_metadata.column_schema.name.as_str();
43            if !physical_columns.contains_key(column_name)
44                && !new_column_names.contains(column_name)
45            {
46                ensure!(
47                    col.column_metadata.semantic_type != SemanticType::Field
48                        || is_native_histogram_value_type(
49                            &col.column_metadata.column_schema.data_type
50                        ),
51                    AddingFieldColumnSnafu {
52                        name: column_name.to_string(),
53                    }
54                );
55                new_column_names.insert(column_name);
56                // TODO(weny): avoid clone
57                new_columns.push(col.column_metadata.clone());
58            }
59        }
60    }
61
62    Ok(())
63}
64
65#[cfg(test)]
66mod tests {
67    use std::collections::{HashMap, HashSet};
68
69    use api::v1::SemanticType;
70    use datatypes::prelude::ConcreteDataType;
71    use datatypes::schema::ColumnSchema;
72    use store_api::metadata::ColumnMetadata;
73    use store_api::region_request::{AddColumn, AlterKind, RegionAlterRequest};
74    use store_api::storage::RegionId;
75
76    use super::*;
77    use crate::error::Error;
78
79    #[test]
80    fn test_extract_new_columns_with_field_type() {
81        let requests = vec![(
82            RegionId::new(1, 1),
83            RegionAlterRequest {
84                kind: AlterKind::AddColumns {
85                    columns: vec![AddColumn {
86                        column_metadata: ColumnMetadata {
87                            column_schema: ColumnSchema::new(
88                                "new_column".to_string(),
89                                ConcreteDataType::string_datatype(),
90                                false,
91                            ),
92                            semantic_type: SemanticType::Field,
93                            column_id: 0,
94                        },
95                        location: None,
96                    }],
97                },
98            },
99        )];
100
101        let physical_columns = HashMap::new();
102        let mut new_column_names = HashSet::new();
103        let mut new_columns = Vec::new();
104
105        let err = extract_new_columns(
106            &requests,
107            &physical_columns,
108            &mut new_column_names,
109            &mut new_columns,
110        )
111        .unwrap_err();
112
113        assert!(matches!(err, Error::AddingFieldColumn { .. }));
114    }
115}