|
15 | 15 | // specific language governing permissions and limitations |
16 | 16 | // under the License. |
17 | 17 |
|
| 18 | +use crate::dataframe::PyDataFrame; |
| 19 | +use crate::dataset::Dataset; |
| 20 | +use crate::utils::table_provider_from_pycapsule; |
| 21 | +use arrow::datatypes::SchemaRef; |
18 | 22 | use arrow::pyarrow::ToPyArrow; |
| 23 | +use async_trait::async_trait; |
| 24 | +use datafusion::catalog::Session; |
| 25 | +use datafusion::common::Column; |
19 | 26 | use datafusion::datasource::{TableProvider, TableType}; |
| 27 | +use datafusion::logical_expr::{Expr, LogicalPlanBuilder, TableProviderFilterPushDown}; |
| 28 | +use datafusion::physical_plan::ExecutionPlan; |
| 29 | +use datafusion::prelude::DataFrame; |
20 | 30 | use pyo3::prelude::*; |
| 31 | +use std::any::Any; |
21 | 32 | use std::sync::Arc; |
22 | 33 |
|
23 | | -use crate::dataframe::PyDataFrame; |
24 | | -use crate::dataset::Dataset; |
25 | | -use crate::utils::table_provider_from_pycapsule; |
26 | | - |
27 | 34 | /// This struct is used as a common method for all TableProviders, |
28 | 35 | /// whether they refer to an FFI provider, an internally known |
29 | 36 | /// implementation, a dataset, or a dataframe view. |
@@ -104,3 +111,82 @@ impl From<Arc<dyn TableProvider>> for PyTable { |
104 | 111 | Self { table } |
105 | 112 | } |
106 | 113 | } |
| 114 | + |
| 115 | +#[derive(Clone, Debug)] |
| 116 | +pub(crate) struct TempViewTable { |
| 117 | + df: Arc<DataFrame>, |
| 118 | +} |
| 119 | + |
| 120 | +/// This is nearly identical to `DataFrameTableProvider` |
| 121 | +/// except that it is for temporary tables. |
| 122 | +/// Remove when https://github.com/apache/datafusion/issues/18026 |
| 123 | +/// closes. |
| 124 | +impl TempViewTable { |
| 125 | + pub(crate) fn new(df: Arc<DataFrame>) -> Self { |
| 126 | + Self { df } |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +#[async_trait] |
| 131 | +impl TableProvider for TempViewTable { |
| 132 | + fn as_any(&self) -> &dyn Any { |
| 133 | + self |
| 134 | + } |
| 135 | + |
| 136 | + fn schema(&self) -> SchemaRef { |
| 137 | + Arc::new(self.df.schema().into()) |
| 138 | + } |
| 139 | + |
| 140 | + fn table_type(&self) -> TableType { |
| 141 | + TableType::Temporary |
| 142 | + } |
| 143 | + |
| 144 | + async fn scan( |
| 145 | + &self, |
| 146 | + state: &dyn Session, |
| 147 | + projection: Option<&Vec<usize>>, |
| 148 | + filters: &[Expr], |
| 149 | + limit: Option<usize>, |
| 150 | + ) -> datafusion::common::Result<Arc<dyn ExecutionPlan>> { |
| 151 | + let filter = filters.iter().cloned().reduce(|acc, new| acc.and(new)); |
| 152 | + let plan = self.df.logical_plan().clone(); |
| 153 | + let mut plan = LogicalPlanBuilder::from(plan); |
| 154 | + |
| 155 | + if let Some(filter) = filter { |
| 156 | + plan = plan.filter(filter)?; |
| 157 | + } |
| 158 | + |
| 159 | + let mut plan = if let Some(projection) = projection { |
| 160 | + // avoiding adding a redundant projection (e.g. SELECT * FROM view) |
| 161 | + let current_projection = (0..plan.schema().fields().len()).collect::<Vec<usize>>(); |
| 162 | + if projection == ¤t_projection { |
| 163 | + plan |
| 164 | + } else { |
| 165 | + let fields: Vec<Expr> = projection |
| 166 | + .iter() |
| 167 | + .map(|i| { |
| 168 | + Expr::Column(Column::from( |
| 169 | + self.df.logical_plan().schema().qualified_field(*i), |
| 170 | + )) |
| 171 | + }) |
| 172 | + .collect(); |
| 173 | + plan.project(fields)? |
| 174 | + } |
| 175 | + } else { |
| 176 | + plan |
| 177 | + }; |
| 178 | + |
| 179 | + if let Some(limit) = limit { |
| 180 | + plan = plan.limit(0, Some(limit))?; |
| 181 | + } |
| 182 | + |
| 183 | + state.create_physical_plan(&plan.build()?).await |
| 184 | + } |
| 185 | + |
| 186 | + fn supports_filters_pushdown( |
| 187 | + &self, |
| 188 | + filters: &[&Expr], |
| 189 | + ) -> datafusion::common::Result<Vec<TableProviderFilterPushDown>> { |
| 190 | + Ok(vec![TableProviderFilterPushDown::Exact; filters.len()]) |
| 191 | + } |
| 192 | +} |
0 commit comments