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