datafusion_catalog/
view.rs1use std::{borrow::Cow, sync::Arc};
21
22use crate::Session;
23use crate::TableProvider;
24
25use arrow::datatypes::SchemaRef;
26use async_trait::async_trait;
27use datafusion_common::Column;
28use datafusion_common::error::Result;
29use datafusion_expr::TableType;
30use datafusion_expr::{Expr, LogicalPlan};
31use datafusion_expr::{LogicalPlanBuilder, TableProviderFilterPushDown};
32use datafusion_physical_plan::ExecutionPlan;
33
34#[derive(Debug)]
36pub struct ViewTable {
37 logical_plan: LogicalPlan,
39 table_schema: SchemaRef,
41 definition: Option<String>,
43}
44
45impl ViewTable {
46 pub fn new(logical_plan: LogicalPlan, definition: Option<String>) -> Self {
54 let table_schema = Arc::clone(logical_plan.schema().inner());
55 Self {
56 logical_plan,
57 table_schema,
58 definition,
59 }
60 }
61
62 pub fn definition(&self) -> Option<&String> {
64 self.definition.as_ref()
65 }
66
67 pub fn logical_plan(&self) -> &LogicalPlan {
69 &self.logical_plan
70 }
71}
72
73#[async_trait]
74impl TableProvider for ViewTable {
75 fn get_logical_plan(&'_ self) -> Option<Cow<'_, LogicalPlan>> {
76 Some(Cow::Borrowed(&self.logical_plan))
77 }
78
79 fn schema(&self) -> SchemaRef {
80 Arc::clone(&self.table_schema)
81 }
82
83 fn table_type(&self) -> TableType {
84 TableType::View
85 }
86
87 fn get_table_definition(&self) -> Option<&str> {
88 self.definition.as_deref()
89 }
90 fn supports_filters_pushdown(
91 &self,
92 filters: &[&Expr],
93 ) -> Result<Vec<TableProviderFilterPushDown>> {
94 Ok(vec![TableProviderFilterPushDown::Exact; filters.len()])
96 }
97
98 async fn scan(
99 &self,
100 state: &dyn Session,
101 projection: Option<&Vec<usize>>,
102 filters: &[Expr],
103 limit: Option<usize>,
104 ) -> Result<Arc<dyn ExecutionPlan>> {
105 let filter = filters.iter().cloned().reduce(|acc, new| acc.and(new));
106 let plan = self.logical_plan().clone();
107 let mut plan = LogicalPlanBuilder::from(plan);
108
109 if let Some(filter) = filter {
110 plan = plan.filter(filter)?;
111 }
112
113 let mut plan = if let Some(projection) = projection {
114 let current_projection =
116 (0..plan.schema().fields().len()).collect::<Vec<usize>>();
117 if projection == ¤t_projection {
118 plan
119 } else {
120 let fields: Vec<Expr> = projection
121 .iter()
122 .map(|i| {
123 Expr::Column(Column::from(
124 self.logical_plan.schema().qualified_field(*i),
125 ))
126 })
127 .collect();
128 plan.project(fields)?
129 }
130 } else {
131 plan
132 };
133
134 if let Some(limit) = limit {
135 plan = plan.limit(0, Some(limit))?;
136 }
137
138 state.create_physical_plan(&plan.build()?).await
139 }
140}