catalog/system_schema/
memory_table.rs1mod table_columns;
16
17use std::sync::Arc;
18
19use arrow_schema::SchemaRef as ArrowSchemaRef;
20use common_error::ext::BoxedError;
21use common_recordbatch::adapter::RecordBatchStreamAdapter;
22use common_recordbatch::{RecordBatch, SendableRecordBatchStream};
23use datafusion::execution::TaskContext;
24use datafusion::physical_plan::SendableRecordBatchStream as DfSendableRecordBatchStream;
25use datafusion::physical_plan::stream::RecordBatchStreamAdapter as DfRecordBatchStreamAdapter;
26use datafusion::physical_plan::streaming::PartitionStream as DfPartitionStream;
27use datatypes::schema::SchemaRef;
28use datatypes::vectors::VectorRef;
29use snafu::ResultExt;
30use store_api::storage::{ScanRequest, TableId};
31
32use crate::error::{CreateRecordBatchSnafu, InternalSnafu, Result};
33use crate::system_schema::SystemTable;
34use crate::system_schema::information_schema::{InformationSchemaTableScope, InformationTable};
35
36#[derive(Debug)]
38pub(crate) struct MemoryTable {
39 pub(crate) table_id: TableId,
40 pub(crate) table_name: &'static str,
41 pub(crate) schema: SchemaRef,
42 pub(crate) columns: Vec<VectorRef>,
43 scope: InformationSchemaTableScope,
44}
45
46impl MemoryTable {
47 pub fn new(
49 table_id: TableId,
50 table_name: &'static str,
51 schema: SchemaRef,
52 columns: Vec<VectorRef>,
53 scope: InformationSchemaTableScope,
54 ) -> Self {
55 Self {
56 table_id,
57 table_name,
58 schema,
59 columns,
60 scope,
61 }
62 }
63
64 pub fn builder(&self) -> MemoryTableBuilder {
65 MemoryTableBuilder::new(self.schema.clone(), self.columns.clone())
66 }
67}
68
69pub(crate) struct MemoryTableBuilder {
70 schema: SchemaRef,
71 columns: Vec<VectorRef>,
72}
73
74impl MemoryTableBuilder {
75 fn new(schema: SchemaRef, columns: Vec<VectorRef>) -> Self {
76 Self { schema, columns }
77 }
78
79 pub async fn memory_records(&mut self) -> Result<RecordBatch> {
81 if self.columns.is_empty() {
82 Ok(RecordBatch::new_empty(self.schema.clone()))
83 } else {
84 RecordBatch::new(self.schema.clone(), std::mem::take(&mut self.columns))
85 .context(CreateRecordBatchSnafu)
86 }
87 }
88}
89
90impl DfPartitionStream for MemoryTable {
91 fn schema(&self) -> &ArrowSchemaRef {
92 self.schema.arrow_schema()
93 }
94
95 fn execute(&self, _: Arc<TaskContext>) -> DfSendableRecordBatchStream {
96 let schema = self.schema.arrow_schema().clone();
97 let mut builder = self.builder();
98 Box::pin(DfRecordBatchStreamAdapter::new(
99 schema,
100 futures::stream::once(async move {
101 builder
102 .memory_records()
103 .await
104 .map(|x| x.into_df_record_batch())
105 .map_err(Into::into)
106 }),
107 ))
108 }
109}
110
111impl InformationTable for MemoryTable {
112 fn scope(&self) -> InformationSchemaTableScope {
113 self.scope
114 }
115}
116
117impl SystemTable for MemoryTable {
118 fn table_id(&self) -> TableId {
119 self.table_id
120 }
121
122 fn table_name(&self) -> &'static str {
123 self.table_name
124 }
125
126 fn schema(&self) -> SchemaRef {
127 self.schema.clone()
128 }
129
130 fn to_stream(&self, _request: ScanRequest) -> Result<SendableRecordBatchStream> {
131 let schema = self.schema.arrow_schema().clone();
132 let mut builder = self.builder();
133 let stream = Box::pin(DfRecordBatchStreamAdapter::new(
134 schema,
135 futures::stream::once(async move {
136 builder
137 .memory_records()
138 .await
139 .map(|x| x.into_df_record_batch())
140 .map_err(Into::into)
141 }),
142 ));
143 Ok(Box::pin(
144 RecordBatchStreamAdapter::try_new(stream)
145 .map_err(BoxedError::new)
146 .context(InternalSnafu)?,
147 ))
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use std::sync::Arc;
154
155 use common_recordbatch::RecordBatches;
156 use datatypes::prelude::ConcreteDataType;
157 use datatypes::schema::{ColumnSchema, Schema};
158 use datatypes::vectors::StringVector;
159
160 use super::*;
161 use crate::system_schema::SystemTable;
162
163 #[tokio::test]
164 async fn test_memory_table() {
165 let schema = Arc::new(Schema::new(vec![
166 ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
167 ColumnSchema::new("b", ConcreteDataType::string_datatype(), false),
168 ]));
169
170 let table = MemoryTable::new(
171 42,
172 "test",
173 schema.clone(),
174 vec![
175 Arc::new(StringVector::from(vec!["a1", "a2"])),
176 Arc::new(StringVector::from(vec!["b1", "b2"])),
177 ],
178 InformationSchemaTableScope::Global,
179 );
180
181 assert_eq!(42, table.table_id());
182 assert_eq!("test", table.table_name);
183 assert_eq!(schema, SystemTable::schema(&table));
184
185 let stream = table.to_stream(ScanRequest::default()).unwrap();
186
187 let batches = RecordBatches::try_collect(stream).await.unwrap();
188
189 assert_eq!(
190 "\
191+----+----+
192| a | b |
193+----+----+
194| a1 | b1 |
195| a2 | b2 |
196+----+----+",
197 batches.pretty_print().unwrap()
198 );
199 }
200
201 #[tokio::test]
202 async fn test_empty_memory_table() {
203 let schema = Arc::new(Schema::new(vec![
204 ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
205 ColumnSchema::new("b", ConcreteDataType::string_datatype(), false),
206 ]));
207
208 let table = MemoryTable::new(
209 42,
210 "test",
211 schema.clone(),
212 vec![],
213 InformationSchemaTableScope::Global,
214 );
215
216 assert_eq!(42, table.table_id());
217 assert_eq!("test", table.table_name());
218 assert_eq!(schema, SystemTable::schema(&table));
219
220 let stream = table.to_stream(ScanRequest::default()).unwrap();
221
222 let batches = RecordBatches::try_collect(stream).await.unwrap();
223
224 assert_eq!(
225 "\
226+---+---+
227| a | b |
228+---+---+
229+---+---+",
230 batches.pretty_print().unwrap()
231 );
232 }
233}