/Users/andrewlamb/Software/datafusion/datafusion/physical-expr/src/expressions/literal.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | //! Literal expressions for physical operations |
19 | | |
20 | | use std::any::Any; |
21 | | use std::hash::{Hash, Hasher}; |
22 | | use std::sync::Arc; |
23 | | |
24 | | use crate::physical_expr::{down_cast_any_ref, PhysicalExpr}; |
25 | | |
26 | | use arrow::{ |
27 | | datatypes::{DataType, Schema}, |
28 | | record_batch::RecordBatch, |
29 | | }; |
30 | | use datafusion_common::{Result, ScalarValue}; |
31 | | use datafusion_expr::Expr; |
32 | | use datafusion_expr_common::columnar_value::ColumnarValue; |
33 | | use datafusion_expr_common::interval_arithmetic::Interval; |
34 | | use datafusion_expr_common::sort_properties::{ExprProperties, SortProperties}; |
35 | | |
36 | | /// Represents a literal value |
37 | | #[derive(Debug, PartialEq, Eq, Hash)] |
38 | | pub struct Literal { |
39 | | value: ScalarValue, |
40 | | } |
41 | | |
42 | | impl Literal { |
43 | | /// Create a literal value expression |
44 | 1.53k | pub fn new(value: ScalarValue) -> Self { |
45 | 1.53k | Self { value } |
46 | 1.53k | } |
47 | | |
48 | | /// Get the scalar value |
49 | 4.21k | pub fn value(&self) -> &ScalarValue { |
50 | 4.21k | &self.value |
51 | 4.21k | } |
52 | | } |
53 | | |
54 | | impl std::fmt::Display for Literal { |
55 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
56 | 0 | write!(f, "{}", self.value) |
57 | 0 | } |
58 | | } |
59 | | |
60 | | impl PhysicalExpr for Literal { |
61 | | /// Return a reference to Any that can be used for downcasting |
62 | 35.9k | fn as_any(&self) -> &dyn Any { |
63 | 35.9k | self |
64 | 35.9k | } |
65 | | |
66 | 100k | fn data_type(&self, _input_schema: &Schema) -> Result<DataType> { |
67 | 100k | Ok(self.value.data_type()) |
68 | 100k | } |
69 | | |
70 | 0 | fn nullable(&self, _input_schema: &Schema) -> Result<bool> { |
71 | 0 | Ok(self.value.is_null()) |
72 | 0 | } |
73 | | |
74 | 88.4k | fn evaluate(&self, _batch: &RecordBatch) -> Result<ColumnarValue> { |
75 | 88.4k | Ok(ColumnarValue::Scalar(self.value.clone())) |
76 | 88.4k | } |
77 | | |
78 | 5.49k | fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> { |
79 | 5.49k | vec![] |
80 | 5.49k | } |
81 | | |
82 | 0 | fn with_new_children( |
83 | 0 | self: Arc<Self>, |
84 | 0 | _children: Vec<Arc<dyn PhysicalExpr>>, |
85 | 0 | ) -> Result<Arc<dyn PhysicalExpr>> { |
86 | 0 | Ok(self) |
87 | 0 | } |
88 | | |
89 | 0 | fn dyn_hash(&self, state: &mut dyn Hasher) { |
90 | 0 | let mut s = state; |
91 | 0 | self.hash(&mut s); |
92 | 0 | } |
93 | | |
94 | 1 | fn get_properties(&self, _children: &[ExprProperties]) -> Result<ExprProperties> { |
95 | 1 | Ok(ExprProperties { |
96 | 1 | sort_properties: SortProperties::Singleton, |
97 | 1 | range: Interval::try_new(self.value().clone(), self.value().clone())?0 , |
98 | | }) |
99 | 1 | } |
100 | | } |
101 | | |
102 | | impl PartialEq<dyn Any> for Literal { |
103 | 33.8k | fn eq(&self, other: &dyn Any) -> bool { |
104 | 33.8k | down_cast_any_ref(other) |
105 | 33.8k | .downcast_ref::<Self>() |
106 | 33.8k | .map(|x| self == x8.43k ) |
107 | 33.8k | .unwrap_or(false) |
108 | 33.8k | } |
109 | | } |
110 | | |
111 | | /// Create a literal expression |
112 | 87 | pub fn lit<T: datafusion_expr::Literal>(value: T) -> Arc<dyn PhysicalExpr> { |
113 | 87 | match value.lit() { |
114 | 87 | Expr::Literal(v) => Arc::new(Literal::new(v)), |
115 | 0 | _ => unreachable!(), |
116 | | } |
117 | 87 | } |
118 | | |
119 | | #[cfg(test)] |
120 | | mod tests { |
121 | | use super::*; |
122 | | |
123 | | use arrow::array::Int32Array; |
124 | | use arrow::datatypes::*; |
125 | | use datafusion_common::cast::as_int32_array; |
126 | | |
127 | | #[test] |
128 | | fn literal_i32() -> Result<()> { |
129 | | // create an arbitrary record bacth |
130 | | let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]); |
131 | | let a = Int32Array::from(vec![Some(1), None, Some(3), Some(4), Some(5)]); |
132 | | let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(a)])?; |
133 | | |
134 | | // create and evaluate a literal expression |
135 | | let literal_expr = lit(42i32); |
136 | | assert_eq!("42", format!("{literal_expr}")); |
137 | | |
138 | | let literal_array = literal_expr |
139 | | .evaluate(&batch)? |
140 | | .into_array(batch.num_rows()) |
141 | | .expect("Failed to convert to array"); |
142 | | let literal_array = as_int32_array(&literal_array)?; |
143 | | |
144 | | // note that the contents of the literal array are unrelated to the batch contents except for the length of the array |
145 | | assert_eq!(literal_array.len(), 5); // 5 rows in the batch |
146 | | for i in 0..literal_array.len() { |
147 | | assert_eq!(literal_array.value(i), 42); |
148 | | } |
149 | | |
150 | | Ok(()) |
151 | | } |
152 | | } |