datafusion_physical_expr_common/sort_expr.rs
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//! Sort expressions
19
20use std::cmp::Ordering;
21use std::fmt::{self, Display, Formatter};
22use std::hash::{Hash, Hasher};
23use std::ops::{Deref, DerefMut};
24use std::sync::Arc;
25use std::vec::IntoIter;
26
27use crate::physical_expr::{PhysicalExpr, fmt_sql};
28
29use arrow::compute::kernels::sort::{SortColumn, SortOptions};
30use arrow::datatypes::Schema;
31use arrow::record_batch::RecordBatch;
32use datafusion_common::{HashSet, Result};
33use datafusion_expr_common::columnar_value::ColumnarValue;
34use indexmap::IndexSet;
35/// Represents Sort operation for a column in a RecordBatch
36///
37/// Example:
38/// ```
39/// # use std::any::Any;
40/// # use std::collections::HashMap;
41/// # use std::fmt::{Display, Formatter};
42/// # use std::hash::Hasher;
43/// # use std::sync::Arc;
44/// # use arrow::array::RecordBatch;
45/// # use datafusion_common::Result;
46/// # use arrow::compute::SortOptions;
47/// # use arrow::datatypes::{DataType, Field, FieldRef, Schema};
48/// # use datafusion_expr_common::columnar_value::ColumnarValue;
49/// # use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
50/// # use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
51/// # // this crate doesn't have a physical expression implementation
52/// # // so make a really simple one
53/// # #[derive(Clone, Debug, PartialEq, Eq, Hash)]
54/// # struct MyPhysicalExpr;
55/// # impl PhysicalExpr for MyPhysicalExpr {
56/// # fn data_type(&self, input_schema: &Schema) -> Result<DataType> {todo!()}
57/// # fn nullable(&self, input_schema: &Schema) -> Result<bool> {todo!() }
58/// # fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {todo!() }
59/// # fn return_field(&self, input_schema: &Schema) -> Result<FieldRef> { unimplemented!() }
60/// # fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {todo!()}
61/// # fn with_new_children(self: Arc<Self>, children: Vec<Arc<dyn PhysicalExpr>>) -> Result<Arc<dyn PhysicalExpr>> {todo!()}
62/// # fn fmt_sql(&self, f: &mut Formatter<'_>) -> std::fmt::Result { todo!() }
63/// # }
64/// # impl Display for MyPhysicalExpr {
65/// # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "a") }
66/// # }
67/// # fn col(name: &str) -> Arc<dyn PhysicalExpr> { Arc::new(MyPhysicalExpr) }
68/// // Sort by a ASC
69/// let options = SortOptions::default();
70/// let sort_expr = PhysicalSortExpr::new(col("a"), options);
71/// assert_eq!(sort_expr.to_string(), "a ASC");
72///
73/// // Sort by a DESC NULLS LAST
74/// let sort_expr = PhysicalSortExpr::new_default(col("a"))
75/// .desc()
76/// .nulls_last();
77/// assert_eq!(sort_expr.to_string(), "a DESC NULLS LAST");
78/// ```
79#[derive(Clone, Debug, Eq)]
80pub struct PhysicalSortExpr {
81 /// Physical expression representing the column to sort
82 pub expr: Arc<dyn PhysicalExpr>,
83 /// Option to specify how the given column should be sorted
84 pub options: SortOptions,
85}
86
87impl PhysicalSortExpr {
88 /// Create a new PhysicalSortExpr
89 pub fn new(expr: Arc<dyn PhysicalExpr>, options: SortOptions) -> Self {
90 Self { expr, options }
91 }
92
93 /// Create a new PhysicalSortExpr with default [`SortOptions`]
94 pub fn new_default(expr: Arc<dyn PhysicalExpr>) -> Self {
95 Self::new(expr, SortOptions::default())
96 }
97
98 /// Reverses the sort expression. For instance, `[a ASC NULLS LAST]` turns
99 /// into `[a DESC NULLS FIRST]`. Such reversals are useful in planning, e.g.
100 /// when constructing equivalent window expressions.
101 pub fn reverse(&self) -> Self {
102 let mut result = self.clone();
103 result.options = !result.options;
104 result
105 }
106
107 /// Set the sort sort options to ASC
108 pub fn asc(mut self) -> Self {
109 self.options.descending = false;
110 self
111 }
112
113 /// Set the sort sort options to DESC
114 pub fn desc(mut self) -> Self {
115 self.options.descending = true;
116 self
117 }
118
119 /// Set the sort sort options to NULLS FIRST
120 pub fn nulls_first(mut self) -> Self {
121 self.options.nulls_first = true;
122 self
123 }
124
125 /// Set the sort sort options to NULLS LAST
126 pub fn nulls_last(mut self) -> Self {
127 self.options.nulls_first = false;
128 self
129 }
130
131 /// Like [`PhysicalExpr::fmt_sql`] prints a [`PhysicalSortExpr`] in a SQL-like format.
132 pub fn fmt_sql(&self, f: &mut Formatter) -> fmt::Result {
133 write!(
134 f,
135 "{} {}",
136 fmt_sql(self.expr.as_ref()),
137 to_str(&self.options)
138 )
139 }
140
141 /// Evaluates the sort expression into a `SortColumn` that can be passed
142 /// into the arrow sort kernel.
143 pub fn evaluate_to_sort_column(&self, batch: &RecordBatch) -> Result<SortColumn> {
144 let array_to_sort = match self.expr.evaluate(batch)? {
145 ColumnarValue::Array(array) => array,
146 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(batch.num_rows())?,
147 };
148 Ok(SortColumn {
149 values: array_to_sort,
150 options: Some(self.options),
151 })
152 }
153
154 /// Checks whether this sort expression satisfies the given `requirement`.
155 /// If sort options are unspecified in `requirement`, only expressions are
156 /// compared for inequality. See [`options_compatible`] for details on
157 /// how sort options compare with one another.
158 pub fn satisfy(
159 &self,
160 requirement: &PhysicalSortRequirement,
161 schema: &Schema,
162 ) -> bool {
163 self.expr.eq(&requirement.expr)
164 && requirement.options.is_none_or(|opts| {
165 options_compatible(
166 &self.options,
167 &opts,
168 self.expr.nullable(schema).unwrap_or(true),
169 )
170 })
171 }
172
173 /// Checks whether this sort expression satisfies the given `sort_expr`.
174 /// See [`options_compatible`] for details on how sort options compare with
175 /// one another.
176 pub fn satisfy_expr(&self, sort_expr: &Self, schema: &Schema) -> bool {
177 self.expr.eq(&sort_expr.expr)
178 && options_compatible(
179 &self.options,
180 &sort_expr.options,
181 self.expr.nullable(schema).unwrap_or(true),
182 )
183 }
184}
185
186impl PartialEq for PhysicalSortExpr {
187 fn eq(&self, other: &Self) -> bool {
188 self.options == other.options && self.expr.eq(&other.expr)
189 }
190}
191
192impl Hash for PhysicalSortExpr {
193 fn hash<H: Hasher>(&self, state: &mut H) {
194 self.expr.hash(state);
195 self.options.hash(state);
196 }
197}
198
199impl Display for PhysicalSortExpr {
200 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
201 write!(f, "{} {}", self.expr, to_str(&self.options))
202 }
203}
204
205/// Returns whether the given two [`SortOptions`] are compatible. Here,
206/// compatibility means that they are either exactly equal, or they differ only
207/// in whether NULL values come in first/last, which is immaterial because the
208/// column in question is not nullable (specified by the `nullable` parameter).
209pub fn options_compatible(
210 options_lhs: &SortOptions,
211 options_rhs: &SortOptions,
212 nullable: bool,
213) -> bool {
214 if nullable {
215 options_lhs == options_rhs
216 } else {
217 // If the column is not nullable, NULLS FIRST/LAST is not important.
218 options_lhs.descending == options_rhs.descending
219 }
220}
221
222/// Represents sort requirement associated with a plan
223///
224/// If the requirement includes [`SortOptions`] then both the
225/// expression *and* the sort options must match.
226///
227/// If the requirement does not include [`SortOptions`]) then only the
228/// expressions must match.
229///
230/// # Examples
231///
232/// With sort options (`A`, `DESC NULLS FIRST`):
233/// * `ORDER BY A DESC NULLS FIRST` matches
234/// * `ORDER BY A ASC NULLS FIRST` does not match (`ASC` vs `DESC`)
235/// * `ORDER BY B DESC NULLS FIRST` does not match (different expr)
236///
237/// Without sort options (`A`, None):
238/// * `ORDER BY A DESC NULLS FIRST` matches
239/// * `ORDER BY A ASC NULLS FIRST` matches (`ASC` and `NULL` options ignored)
240/// * `ORDER BY B DESC NULLS FIRST` does not match (different expr)
241#[derive(Clone, Debug)]
242pub struct PhysicalSortRequirement {
243 /// Physical expression representing the column to sort
244 pub expr: Arc<dyn PhysicalExpr>,
245 /// Option to specify how the given column should be sorted.
246 /// If unspecified, there are no constraints on sort options.
247 pub options: Option<SortOptions>,
248}
249
250impl PartialEq for PhysicalSortRequirement {
251 fn eq(&self, other: &Self) -> bool {
252 self.options == other.options && self.expr.eq(&other.expr)
253 }
254}
255
256impl Display for PhysicalSortRequirement {
257 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
258 let opts_string = self.options.as_ref().map_or("NA", to_str);
259 write!(f, "{} {}", self.expr, opts_string)
260 }
261}
262
263/// Writes a list of [`PhysicalSortRequirement`]s to a `std::fmt::Formatter`.
264///
265/// Example output: `[a + 1, b]`
266pub fn format_physical_sort_requirement_list(
267 exprs: &[PhysicalSortRequirement],
268) -> impl Display + '_ {
269 struct DisplayWrapper<'a>(&'a [PhysicalSortRequirement]);
270 impl Display for DisplayWrapper<'_> {
271 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
272 let mut iter = self.0.iter();
273 write!(f, "[")?;
274 if let Some(expr) = iter.next() {
275 write!(f, "{expr}")?;
276 }
277 for expr in iter {
278 write!(f, ", {expr}")?;
279 }
280 write!(f, "]")?;
281 Ok(())
282 }
283 }
284 DisplayWrapper(exprs)
285}
286
287impl PhysicalSortRequirement {
288 /// Creates a new requirement.
289 ///
290 /// If `options` is `Some(..)`, creates an `exact` requirement,
291 /// which must match both `options` and `expr`.
292 ///
293 /// If `options` is `None`, Creates a new `expr_only` requirement,
294 /// which must match only `expr`.
295 ///
296 /// See [`PhysicalSortRequirement`] for examples.
297 pub fn new(expr: Arc<dyn PhysicalExpr>, options: Option<SortOptions>) -> Self {
298 Self { expr, options }
299 }
300
301 /// Returns whether this requirement is equal or more specific than `other`.
302 pub fn compatible(&self, other: &Self) -> bool {
303 self.expr.eq(&other.expr)
304 && other
305 .options
306 .is_none_or(|other_opts| self.options == Some(other_opts))
307 }
308}
309
310/// Returns the SQL string representation of the given [`SortOptions`] object.
311#[inline]
312fn to_str(options: &SortOptions) -> &str {
313 match (options.descending, options.nulls_first) {
314 (true, true) => "DESC",
315 (true, false) => "DESC NULLS LAST",
316 (false, true) => "ASC",
317 (false, false) => "ASC NULLS LAST",
318 }
319}
320
321// Cross-conversion utilities between `PhysicalSortExpr` and `PhysicalSortRequirement`
322impl From<PhysicalSortExpr> for PhysicalSortRequirement {
323 fn from(value: PhysicalSortExpr) -> Self {
324 Self::new(value.expr, Some(value.options))
325 }
326}
327
328impl From<PhysicalSortRequirement> for PhysicalSortExpr {
329 /// The default sort options `ASC, NULLS LAST` when the requirement does
330 /// not specify sort options. This default is consistent with PostgreSQL.
331 ///
332 /// Reference: <https://www.postgresql.org/docs/current/queries-order.html>
333 fn from(value: PhysicalSortRequirement) -> Self {
334 let options = value
335 .options
336 .unwrap_or_else(|| SortOptions::new(false, false));
337 Self::new(value.expr, options)
338 }
339}
340
341/// This object represents a lexicographical ordering and contains a vector
342/// of `PhysicalSortExpr` objects.
343///
344/// For example, a `vec![a ASC, b DESC]` represents a lexicographical ordering
345/// that first sorts by column `a` in ascending order, then by column `b` in
346/// descending order.
347///
348/// # Invariants
349///
350/// The following always hold true for a `LexOrdering`:
351///
352/// 1. It is non-degenerate, meaning it contains at least one element.
353/// 2. It is duplicate-free, meaning it does not contain multiple entries for
354/// the same column.
355#[derive(Clone, Debug)]
356pub struct LexOrdering {
357 /// Vector of sort expressions representing the lexicographical ordering.
358 exprs: Vec<PhysicalSortExpr>,
359 /// Set of expressions in the lexicographical ordering, used to ensure
360 /// that the ordering is duplicate-free. Note that the elements in this
361 /// set are the same underlying physical expressions as in `exprs`.
362 set: IndexSet<Arc<dyn PhysicalExpr>>,
363}
364
365impl LexOrdering {
366 /// Creates a new [`LexOrdering`] from the given vector of sort expressions.
367 /// If the vector is empty, returns `None`.
368 pub fn new(exprs: impl IntoIterator<Item = PhysicalSortExpr>) -> Option<Self> {
369 let exprs = exprs.into_iter();
370 let mut candidate = Self {
371 // not valid yet; valid publicly-returned instance must be non-empty
372 exprs: Vec::new(),
373 set: IndexSet::new(),
374 };
375 for expr in exprs {
376 candidate.push(expr);
377 }
378 if candidate.exprs.is_empty() {
379 None
380 } else {
381 Some(candidate)
382 }
383 }
384
385 /// Appends an element to the back of the `LexOrdering`.
386 pub fn push(&mut self, sort_expr: PhysicalSortExpr) {
387 if self.set.insert(Arc::clone(&sort_expr.expr)) {
388 self.exprs.push(sort_expr);
389 }
390 }
391
392 /// Add all elements from `iter` to the `LexOrdering`.
393 pub fn extend(&mut self, sort_exprs: impl IntoIterator<Item = PhysicalSortExpr>) {
394 for sort_expr in sort_exprs {
395 self.push(sort_expr);
396 }
397 }
398
399 /// Returns the leading `PhysicalSortExpr` of the `LexOrdering`. Note that
400 /// this function does not return an `Option`, as a `LexOrdering` is always
401 /// non-degenerate (i.e. it contains at least one element).
402 pub fn first(&self) -> &PhysicalSortExpr {
403 // Can safely `unwrap` because `LexOrdering` is non-degenerate:
404 self.exprs.first().unwrap()
405 }
406
407 /// Returns the number of elements that can be stored in the `LexOrdering`
408 /// without reallocating.
409 pub fn capacity(&self) -> usize {
410 self.exprs.capacity()
411 }
412
413 /// Truncates the `LexOrdering`, keeping only the first `len` elements.
414 /// Returns `true` if truncation made a change, `false` otherwise. Negative
415 /// cases happen in two scenarios: (1) When `len` is greater than or equal
416 /// to the number of expressions inside this `LexOrdering`, making truncation
417 /// a no-op, or (2) when `len` is `0`, making truncation impossible.
418 pub fn truncate(&mut self, len: usize) -> bool {
419 if len == 0 || len >= self.exprs.len() {
420 return false;
421 }
422 for PhysicalSortExpr { expr, .. } in self.exprs[len..].iter() {
423 self.set.swap_remove(expr);
424 }
425 self.exprs.truncate(len);
426 true
427 }
428
429 /// Check if reversing this ordering would satisfy another ordering requirement.
430 ///
431 /// This supports **prefix matching**: if this ordering is `[A DESC, B ASC]`
432 /// and `other` is `[A ASC]`, reversing this gives `[A ASC, B DESC]`, which
433 /// satisfies `other` since `[A ASC]` is a prefix.
434 ///
435 /// # Arguments
436 /// * `other` - The ordering requirement to check against
437 ///
438 /// # Returns
439 /// `true` if reversing this ordering would satisfy `other`
440 ///
441 /// # Example
442 /// ```text
443 /// self: [number DESC, letter ASC]
444 /// other: [number ASC]
445 /// After reversing self: [number ASC, letter DESC] ✓ Prefix match!
446 /// ```
447 pub fn is_reverse(&self, other: &LexOrdering) -> bool {
448 let self_exprs = self.as_ref();
449 let other_exprs = other.as_ref();
450
451 if other_exprs.len() > self_exprs.len() {
452 return false;
453 }
454
455 other_exprs.iter().zip(self_exprs.iter()).all(|(req, cur)| {
456 req.expr.eq(&cur.expr) && is_reversed_sort_options(&req.options, &cur.options)
457 })
458 }
459
460 /// Returns the sort options for the given expression if one is defined in this `LexOrdering`.
461 pub fn get_sort_options(&self, expr: &dyn PhysicalExpr) -> Option<SortOptions> {
462 for e in self {
463 if e.expr.as_ref().dyn_eq(expr) {
464 return Some(e.options);
465 }
466 }
467
468 None
469 }
470}
471
472/// Check if two SortOptions represent reversed orderings.
473///
474/// Returns `true` if both `descending` and `nulls_first` are opposite.
475///
476/// # Example
477/// ```
478/// use arrow::compute::SortOptions;
479/// # use datafusion_physical_expr_common::sort_expr::is_reversed_sort_options;
480///
481/// let asc_nulls_last = SortOptions {
482/// descending: false,
483/// nulls_first: false,
484/// };
485/// let desc_nulls_first = SortOptions {
486/// descending: true,
487/// nulls_first: true,
488/// };
489///
490/// assert!(is_reversed_sort_options(&asc_nulls_last, &desc_nulls_first));
491/// assert!(is_reversed_sort_options(&desc_nulls_first, &asc_nulls_last));
492/// ```
493pub fn is_reversed_sort_options(lhs: &SortOptions, rhs: &SortOptions) -> bool {
494 lhs.descending != rhs.descending && lhs.nulls_first != rhs.nulls_first
495}
496
497impl PartialEq for LexOrdering {
498 fn eq(&self, other: &Self) -> bool {
499 let Self {
500 exprs,
501 set: _, // derived from `exprs`
502 } = self;
503 // PartialEq must be consistent with PartialOrd
504 exprs == &other.exprs
505 }
506}
507impl Eq for LexOrdering {}
508impl PartialOrd for LexOrdering {
509 /// There is a partial ordering among `LexOrdering` objects. For example, the
510 /// ordering `[a ASC]` is coarser (less) than ordering `[a ASC, b ASC]`.
511 /// If two orderings do not share a prefix, they are incomparable.
512 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
513 // PartialEq must be consistent with PartialOrd
514 self.exprs
515 .iter()
516 .zip(other.exprs.iter())
517 .all(|(lhs, rhs)| lhs == rhs)
518 .then(|| self.len().cmp(&other.len()))
519 }
520}
521
522impl<const N: usize> From<[PhysicalSortExpr; N]> for LexOrdering {
523 fn from(value: [PhysicalSortExpr; N]) -> Self {
524 // TODO: Replace this assertion with a condition on the generic parameter
525 // when Rust supports it.
526 assert!(N > 0);
527 Self::new(value)
528 .expect("A LexOrdering from non-empty array must be non-degenerate")
529 }
530}
531
532impl Deref for LexOrdering {
533 type Target = [PhysicalSortExpr];
534
535 fn deref(&self) -> &Self::Target {
536 self.exprs.as_slice()
537 }
538}
539
540impl Display for LexOrdering {
541 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
542 let mut first = true;
543 for sort_expr in &self.exprs {
544 if first {
545 first = false;
546 } else {
547 write!(f, ", ")?;
548 }
549 write!(f, "{sort_expr}")?;
550 }
551 Ok(())
552 }
553}
554
555impl IntoIterator for LexOrdering {
556 type Item = PhysicalSortExpr;
557 type IntoIter = IntoIter<Self::Item>;
558
559 fn into_iter(self) -> Self::IntoIter {
560 self.exprs.into_iter()
561 }
562}
563
564impl<'a> IntoIterator for &'a LexOrdering {
565 type Item = &'a PhysicalSortExpr;
566 type IntoIter = std::slice::Iter<'a, PhysicalSortExpr>;
567
568 fn into_iter(self) -> Self::IntoIter {
569 self.exprs.iter()
570 }
571}
572
573impl From<LexOrdering> for Vec<PhysicalSortExpr> {
574 fn from(ordering: LexOrdering) -> Self {
575 ordering.exprs
576 }
577}
578
579/// This object represents a lexicographical ordering requirement and contains
580/// a vector of `PhysicalSortRequirement` objects.
581///
582/// For example, a `vec![a Some(ASC), b None]` represents a lexicographical
583/// requirement that firsts imposes an ordering by column `a` in ascending
584/// order, then by column `b` in *any* (ascending or descending) order. The
585/// ordering is non-degenerate, meaning it contains at least one element, and
586/// it is duplicate-free, meaning it does not contain multiple entries for the
587/// same column.
588///
589/// Note that a `LexRequirement` need not enforce the uniqueness of its sort
590/// expressions after construction like a `LexOrdering` does, because it provides
591/// no mutation methods. If such methods become necessary, we will need to
592/// enforce uniqueness like the latter object.
593#[derive(Debug, Clone, PartialEq)]
594pub struct LexRequirement {
595 reqs: Vec<PhysicalSortRequirement>,
596}
597
598impl LexRequirement {
599 /// Creates a new [`LexRequirement`] from the given vector of sort expressions.
600 /// If the vector is empty, returns `None`.
601 pub fn new(reqs: impl IntoIterator<Item = PhysicalSortRequirement>) -> Option<Self> {
602 let (non_empty, requirements) = Self::construct(reqs);
603 non_empty.then_some(requirements)
604 }
605
606 /// Returns the leading `PhysicalSortRequirement` of the `LexRequirement`.
607 /// Note that this function does not return an `Option`, as a `LexRequirement`
608 /// is always non-degenerate (i.e. it contains at least one element).
609 pub fn first(&self) -> &PhysicalSortRequirement {
610 // Can safely `unwrap` because `LexRequirement` is non-degenerate:
611 self.reqs.first().unwrap()
612 }
613
614 /// Constructs a new `LexRequirement` from the given sort requirements w/o
615 /// enforcing non-degeneracy. This function is used internally and is not
616 /// meant (or safe) for external use.
617 fn construct(
618 reqs: impl IntoIterator<Item = PhysicalSortRequirement>,
619 ) -> (bool, Self) {
620 let mut set = HashSet::new();
621 let reqs = reqs
622 .into_iter()
623 .filter_map(|r| set.insert(Arc::clone(&r.expr)).then_some(r))
624 .collect();
625 (!set.is_empty(), Self { reqs })
626 }
627}
628
629impl<const N: usize> From<[PhysicalSortRequirement; N]> for LexRequirement {
630 fn from(value: [PhysicalSortRequirement; N]) -> Self {
631 // TODO: Replace this assertion with a condition on the generic parameter
632 // when Rust supports it.
633 assert!(N > 0);
634 let (non_empty, requirement) = Self::construct(value);
635 debug_assert!(non_empty);
636 requirement
637 }
638}
639
640impl Deref for LexRequirement {
641 type Target = [PhysicalSortRequirement];
642
643 fn deref(&self) -> &Self::Target {
644 self.reqs.as_slice()
645 }
646}
647
648impl IntoIterator for LexRequirement {
649 type Item = PhysicalSortRequirement;
650 type IntoIter = IntoIter<Self::Item>;
651
652 fn into_iter(self) -> Self::IntoIter {
653 self.reqs.into_iter()
654 }
655}
656
657impl<'a> IntoIterator for &'a LexRequirement {
658 type Item = &'a PhysicalSortRequirement;
659 type IntoIter = std::slice::Iter<'a, PhysicalSortRequirement>;
660
661 fn into_iter(self) -> Self::IntoIter {
662 self.reqs.iter()
663 }
664}
665
666impl From<LexRequirement> for Vec<PhysicalSortRequirement> {
667 fn from(requirement: LexRequirement) -> Self {
668 requirement.reqs
669 }
670}
671
672// Cross-conversion utilities between `LexOrdering` and `LexRequirement`
673impl From<LexOrdering> for LexRequirement {
674 fn from(value: LexOrdering) -> Self {
675 // Can construct directly as `value` is non-degenerate:
676 let (non_empty, requirements) =
677 Self::construct(value.into_iter().map(Into::into));
678 debug_assert!(non_empty);
679 requirements
680 }
681}
682
683impl From<LexRequirement> for LexOrdering {
684 fn from(value: LexRequirement) -> Self {
685 // Can construct directly as `value` is non-degenerate
686 Self::new(value.into_iter().map(Into::into))
687 .expect("A LexOrdering from LexRequirement must be non-degenerate")
688 }
689}
690
691/// Represents a plan's input ordering requirements. Vector elements represent
692/// alternative ordering requirements in the order of preference. The list of
693/// alternatives can be either hard or soft, depending on whether the operator
694/// can work without an input ordering.
695///
696/// # Invariants
697///
698/// The following always hold true for a `OrderingRequirements`:
699///
700/// 1. It is non-degenerate, meaning it contains at least one ordering. The
701/// absence of an input ordering requirement is represented by a `None` value
702/// in `ExecutionPlan` APIs, which return an `Option<OrderingRequirements>`.
703#[derive(Debug, Clone, PartialEq)]
704pub enum OrderingRequirements {
705 /// The operator is not able to work without one of these requirements.
706 Hard(Vec<LexRequirement>),
707 /// The operator can benefit from these input orderings when available,
708 /// but can still work in the absence of any input ordering.
709 Soft(Vec<LexRequirement>),
710}
711
712impl OrderingRequirements {
713 /// Creates a new instance from the given alternatives. If an empty list of
714 /// alternatives are given, returns `None`.
715 pub fn new_alternatives(
716 alternatives: impl IntoIterator<Item = LexRequirement>,
717 soft: bool,
718 ) -> Option<Self> {
719 let alternatives = alternatives.into_iter().collect::<Vec<_>>();
720 (!alternatives.is_empty()).then(|| {
721 if soft {
722 Self::Soft(alternatives)
723 } else {
724 Self::Hard(alternatives)
725 }
726 })
727 }
728
729 /// Creates a new instance with a single hard requirement.
730 pub fn new(requirement: LexRequirement) -> Self {
731 Self::Hard(vec![requirement])
732 }
733
734 /// Creates a new instance with a single soft requirement.
735 pub fn new_soft(requirement: LexRequirement) -> Self {
736 Self::Soft(vec![requirement])
737 }
738
739 /// Adds an alternative requirement to the list of alternatives.
740 pub fn add_alternative(&mut self, requirement: LexRequirement) {
741 match self {
742 Self::Hard(alts) | Self::Soft(alts) => alts.push(requirement),
743 }
744 }
745
746 /// Returns the first (i.e. most preferred) `LexRequirement` among
747 /// alternative requirements.
748 pub fn into_single(self) -> LexRequirement {
749 match self {
750 Self::Hard(mut alts) | Self::Soft(mut alts) => alts.swap_remove(0),
751 }
752 }
753
754 /// Returns a reference to the first (i.e. most preferred) `LexRequirement`
755 /// among alternative requirements.
756 pub fn first(&self) -> &LexRequirement {
757 match self {
758 Self::Hard(alts) | Self::Soft(alts) => &alts[0],
759 }
760 }
761
762 /// Returns all alternatives as a vector of `LexRequirement` objects and a
763 /// boolean value indicating softness/hardness of the requirements.
764 pub fn into_alternatives(self) -> (Vec<LexRequirement>, bool) {
765 match self {
766 Self::Hard(alts) => (alts, false),
767 Self::Soft(alts) => (alts, true),
768 }
769 }
770}
771
772impl From<LexRequirement> for OrderingRequirements {
773 fn from(requirement: LexRequirement) -> Self {
774 Self::new(requirement)
775 }
776}
777
778impl From<LexOrdering> for OrderingRequirements {
779 fn from(ordering: LexOrdering) -> Self {
780 Self::new(ordering.into())
781 }
782}
783
784impl Deref for OrderingRequirements {
785 type Target = [LexRequirement];
786
787 fn deref(&self) -> &Self::Target {
788 match &self {
789 Self::Hard(alts) | Self::Soft(alts) => alts.as_slice(),
790 }
791 }
792}
793
794impl DerefMut for OrderingRequirements {
795 fn deref_mut(&mut self) -> &mut Self::Target {
796 match self {
797 Self::Hard(alts) | Self::Soft(alts) => alts.as_mut_slice(),
798 }
799 }
800}
801
802#[cfg(test)]
803mod tests {
804 use super::*;
805
806 #[test]
807 fn test_is_reversed_sort_options() {
808 // Test basic reversal: ASC NULLS LAST ↔ DESC NULLS FIRST
809 let asc_nulls_last = SortOptions {
810 descending: false,
811 nulls_first: false,
812 };
813 let desc_nulls_first = SortOptions {
814 descending: true,
815 nulls_first: true,
816 };
817 assert!(is_reversed_sort_options(&asc_nulls_last, &desc_nulls_first));
818 assert!(is_reversed_sort_options(&desc_nulls_first, &asc_nulls_last));
819
820 // Test another reversal: ASC NULLS FIRST ↔ DESC NULLS LAST
821 let asc_nulls_first = SortOptions {
822 descending: false,
823 nulls_first: true,
824 };
825 let desc_nulls_last = SortOptions {
826 descending: true,
827 nulls_first: false,
828 };
829 assert!(is_reversed_sort_options(&asc_nulls_first, &desc_nulls_last));
830 assert!(is_reversed_sort_options(&desc_nulls_last, &asc_nulls_first));
831
832 // Test non-reversal: same options
833 assert!(!is_reversed_sort_options(&asc_nulls_last, &asc_nulls_last));
834 assert!(!is_reversed_sort_options(
835 &desc_nulls_first,
836 &desc_nulls_first
837 ));
838
839 // Test non-reversal: only descending differs
840 assert!(!is_reversed_sort_options(&asc_nulls_last, &desc_nulls_last));
841 assert!(!is_reversed_sort_options(&desc_nulls_last, &asc_nulls_last));
842
843 // Test non-reversal: only nulls_first differs
844 assert!(!is_reversed_sort_options(&asc_nulls_last, &asc_nulls_first));
845 assert!(!is_reversed_sort_options(&asc_nulls_first, &asc_nulls_last));
846 }
847}