| // Licensed to the Apache Software Foundation (ASF) under one or more | |
| // contributor license agreements. See the NOTICE file distributed with | |
| // this work for additional information regarding copyright ownership. | |
| // The ASF licenses this file to You under the Apache License, Version 2.0 | |
| // (the "License"); you may not use this file except in compliance with | |
| // the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| use std::sync::Arc; | |
| use arrow::{array::ArrayRef, datatypes::FieldRef, record_batch::RecordBatch}; | |
| use arrow_schema::DataType; | |
| use datafusion::{common::Result, physical_expr::PhysicalExprRef}; | |
| use crate::{ | |
| agg::{AggFunction, agg::create_agg}, | |
| window::{ | |
| processors::{ | |
| agg_processor::AggProcessor, cume_dist_processor::CumeDistProcessor, | |
| lead_processor::LeadProcessor, nth_value_processor::NthValueProcessor, | |
| percent_rank_processor::PercentRankProcessor, rank_processor::RankProcessor, | |
| row_number_processor::RowNumberProcessor, | |
| }, | |
| window_context::WindowContext, | |
| }, | |
| }; | |
| pub mod processors; | |
| pub mod window_context; | |
| #[derive(Debug, Clone, Copy)] | |
| pub enum WindowFunction { | |
| RankLike(WindowRankType), | |
| PercentRank, | |
| NthValue { ignore_nulls: bool }, | |
| Lead, | |
| CumeDist, | |
| Agg(AggFunction), | |
| } | |
| #[derive(Debug, Clone, Copy)] | |
| pub enum WindowRankType { | |
| RowNumber, | |
| Rank, | |
| DenseRank, | |
| } | |
| pub trait WindowFunctionProcessor: Send { | |
| fn process_batch(&mut self, context: &WindowContext, batch: &RecordBatch) -> Result<ArrayRef>; | |
| } | |
| #[derive(Debug, Clone)] | |
| pub struct WindowExpr { | |
| field: FieldRef, | |
| func: WindowFunction, | |
| children: Vec<PhysicalExprRef>, | |
| return_type: DataType, | |
| } | |
| impl WindowExpr { | |
| pub fn new( | |
| func: WindowFunction, | |
| children: Vec<PhysicalExprRef>, | |
| field: FieldRef, | |
| return_type: DataType, | |
| ) -> Self { | |
| Self { | |
| field, | |
| func, | |
| children, | |
| return_type, | |
| } | |
| } | |
| pub fn create_processor( | |
| &self, | |
| context: &Arc<WindowContext>, | |
| ) -> Result<Box<dyn WindowFunctionProcessor>> { | |
| match self.func { | |
| WindowFunction::RankLike(WindowRankType::RowNumber) => { | |
| Ok(Box::new(RowNumberProcessor::new())) | |
| } | |
| WindowFunction::RankLike(WindowRankType::Rank) => { | |
| Ok(Box::new(RankProcessor::new(false))) | |
| } | |
| WindowFunction::RankLike(WindowRankType::DenseRank) => { | |
| Ok(Box::new(RankProcessor::new(true))) | |
| } | |
| WindowFunction::PercentRank => Ok(Box::new(PercentRankProcessor::new())), | |
| WindowFunction::Lead => Ok(Box::new(LeadProcessor::new(self.children.clone()))), | |
| WindowFunction::NthValue { ignore_nulls } => Ok(Box::new(NthValueProcessor::try_new( | |
| self.children.clone(), | |
| ignore_nulls, | |
| )?)), | |
| WindowFunction::CumeDist => Ok(Box::new(CumeDistProcessor::new())), | |
| WindowFunction::Agg(agg_func) => { | |
| let agg = create_agg( | |
| agg_func, | |
| &self.children, | |
| &context.input_schema, | |
| self.return_type.clone(), | |
| )?; | |
| Ok(Box::new(AggProcessor::try_new(agg)?)) | |
| } | |
| } | |
| } | |
| pub fn is_rank_like(&self) -> bool { | |
| matches!(self.func, WindowFunction::RankLike(_)) | |
| } | |
| pub fn requires_full_partition(&self) -> bool { | |
| matches!( | |
| self.func, | |
| WindowFunction::PercentRank | WindowFunction::Lead | WindowFunction::CumeDist | |
| ) | |
| } | |
| } |