mito2/read/read_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::mem;
16
17use store_api::storage::{ColumnId, NestedPath};
18
19/// Logical columns to read from a region.
20///
21/// Read columns describe which logical columns and nested fields should be read
22/// from storage. Each read column is identified by its [`ColumnId`],
23/// which represents the root column in the storage schema.
24///
25/// Nested fields under the column are specified by [`NestedPath`] entries.
26/// Each path includes the root column name as its first element.
27///
28/// For example, assume column id `9` corresponds to a root column named `j`
29/// with nested fields:
30///
31/// ```text
32/// j
33/// ├── a
34/// └── b
35/// └── c
36/// ```
37///
38/// The following SQL:
39///
40/// SELECT j.a, j.b.c FROM t
41///
42/// may produce read columns like:
43///
44/// ```text
45/// ReadColumn {
46/// column_id: 9,
47/// nested_paths: [
48/// ["j", "a"],
49/// ["j", "b", "c"],
50/// ]
51/// }
52/// ```
53///
54/// If `nested_paths` is empty, the whole column will be read.
55#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
56pub struct ReadColumns {
57 pub cols: Vec<ReadColumn>,
58}
59
60impl ReadColumns {
61 pub fn from_deduped_column_ids<I>(column_ids: I) -> Self
62 where
63 I: IntoIterator<Item = ColumnId>,
64 {
65 let cols = column_ids
66 .into_iter()
67 .map(|col_id| ReadColumn::new(col_id, vec![]))
68 .collect();
69 ReadColumns { cols }
70 }
71
72 pub fn is_empty(&self) -> bool {
73 self.cols.is_empty()
74 }
75
76 pub fn column_ids_iter(&self) -> impl Iterator<Item = ColumnId> + '_ {
77 self.cols.iter().map(|column| column.column_id)
78 }
79
80 pub fn column_ids(&self) -> Vec<ColumnId> {
81 self.column_ids_iter().collect()
82 }
83
84 pub fn columns(&self) -> &[ReadColumn] {
85 &self.cols
86 }
87
88 pub fn estimated_size(&self) -> usize {
89 self.cols.capacity() * mem::size_of::<ReadColumn>()
90 + self
91 .cols
92 .iter()
93 .map(ReadColumn::estimated_size)
94 .sum::<usize>()
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Hash)]
99pub struct ReadColumn {
100 pub column_id: ColumnId,
101 /// Nested field paths under this column.
102 /// Empty means reading the whole column.
103 pub nested_paths: Vec<NestedPath>,
104}
105
106impl ReadColumn {
107 pub fn new(column_id: ColumnId, nested_paths: Vec<NestedPath>) -> Self {
108 Self {
109 column_id,
110 nested_paths,
111 }
112 }
113
114 pub fn nested_paths(&self) -> &[NestedPath] {
115 &self.nested_paths
116 }
117
118 pub fn estimated_size(&self) -> usize {
119 mem::size_of::<ColumnId>()
120 + self.nested_paths.capacity() * mem::size_of::<NestedPath>()
121 + self
122 .nested_paths
123 .iter()
124 .map(|path| {
125 path.capacity() * mem::size_of::<String>()
126 + path.iter().map(|node| node.capacity()).sum::<usize>()
127 })
128 .sum::<usize>()
129 }
130}