1use crate::error::{QueryError, Result};
4use crate::executor::filter::{Value, evaluate_expr_for_row};
5use crate::executor::scan::{ColumnData, RecordBatch};
6use crate::parser::ast::OrderByExpr;
7use std::cmp::Ordering;
8
9pub struct Sort {
11 pub order_by: Vec<OrderByExpr>,
13}
14
15impl Sort {
16 pub fn new(order_by: Vec<OrderByExpr>) -> Self {
18 Self { order_by }
19 }
20
21 pub fn execute(&self, batch: &RecordBatch) -> Result<RecordBatch> {
23 if self.order_by.is_empty() {
24 return Ok(batch.clone());
25 }
26
27 let mut keys: Vec<Vec<Value>> = Vec::with_capacity(self.order_by.len());
34 for order in &self.order_by {
35 let mut column_keys = Vec::with_capacity(batch.num_rows);
36 for row in 0..batch.num_rows {
37 let value = evaluate_expr_for_row(&order.expr, batch, row)?;
38 if matches!(value, Value::Geometry(_)) {
42 return Err(QueryError::unsupported(
43 "ORDER BY expression produced a value with no defined ordering (geometry)",
44 ));
45 }
46 column_keys.push(value);
47 }
48 keys.push(column_keys);
49 }
50
51 let mut indices: Vec<usize> = (0..batch.num_rows).collect();
53 indices.sort_by(|&a, &b| self.compare_rows(&keys, a, b));
54
55 let mut sorted_columns = Vec::new();
57 for column in &batch.columns {
58 sorted_columns.push(self.reorder_column(column, &indices));
59 }
60
61 RecordBatch::new(batch.schema.clone(), sorted_columns, batch.num_rows)
62 }
63
64 fn compare_rows(&self, keys: &[Vec<Value>], a: usize, b: usize) -> Ordering {
66 for (idx, order) in self.order_by.iter().enumerate() {
67 let ordering = compare_value(&keys[idx][a], &keys[idx][b], order.nulls_first);
68 let ordering = if order.asc {
69 ordering
70 } else {
71 ordering.reverse()
72 };
73
74 if ordering != Ordering::Equal {
75 return ordering;
76 }
77 }
78 Ordering::Equal
79 }
80
81 fn reorder_column(&self, column: &ColumnData, indices: &[usize]) -> ColumnData {
83 match column {
84 ColumnData::Boolean(data) => {
85 let reordered = indices.iter().map(|&i| data[i]).collect();
86 ColumnData::Boolean(reordered)
87 }
88 ColumnData::Int32(data) => {
89 let reordered = indices.iter().map(|&i| data[i]).collect();
90 ColumnData::Int32(reordered)
91 }
92 ColumnData::Int64(data) => {
93 let reordered = indices.iter().map(|&i| data[i]).collect();
94 ColumnData::Int64(reordered)
95 }
96 ColumnData::Float32(data) => {
97 let reordered = indices.iter().map(|&i| data[i]).collect();
98 ColumnData::Float32(reordered)
99 }
100 ColumnData::Float64(data) => {
101 let reordered = indices.iter().map(|&i| data[i]).collect();
102 ColumnData::Float64(reordered)
103 }
104 ColumnData::String(data) => {
105 let reordered = indices.iter().map(|&i| data[i].clone()).collect();
106 ColumnData::String(reordered)
107 }
108 ColumnData::Binary(data) => {
109 let reordered = indices.iter().map(|&i| data[i].clone()).collect();
110 ColumnData::Binary(reordered)
111 }
112 }
113 }
114}
115
116fn compare_value(a: &Value, b: &Value, nulls_first: bool) -> Ordering {
123 use Value::*;
124
125 match (a, b) {
127 (Null, Null) => return Ordering::Equal,
128 (Null, _) => {
129 return if nulls_first {
130 Ordering::Less
131 } else {
132 Ordering::Greater
133 };
134 }
135 (_, Null) => {
136 return if nulls_first {
137 Ordering::Greater
138 } else {
139 Ordering::Less
140 };
141 }
142 _ => {}
143 }
144
145 match (a, b) {
146 (Boolean(x), Boolean(y)) => x.cmp(y),
147 (Int32(x), Int32(y)) => x.cmp(y),
148 (Int64(x), Int64(y)) => x.cmp(y),
149 (Int32(x), Int64(y)) => (*x as i64).cmp(y),
150 (Int64(x), Int32(y)) => x.cmp(&(*y as i64)),
151 (Float32(x), Float32(y)) => x.partial_cmp(y).unwrap_or(Ordering::Equal),
152 (Float64(x), Float64(y)) => x.partial_cmp(y).unwrap_or(Ordering::Equal),
153 (Float32(x), Float64(y)) => (*x as f64).partial_cmp(y).unwrap_or(Ordering::Equal),
154 (Float64(x), Float32(y)) => x.partial_cmp(&(*y as f64)).unwrap_or(Ordering::Equal),
155 (Int32(x), Float64(y)) => (*x as f64).partial_cmp(y).unwrap_or(Ordering::Equal),
156 (Int64(x), Float64(y)) => (*x as f64).partial_cmp(y).unwrap_or(Ordering::Equal),
157 (Float64(x), Int32(y)) => x.partial_cmp(&(*y as f64)).unwrap_or(Ordering::Equal),
158 (Float64(x), Int64(y)) => x.partial_cmp(&(*y as f64)).unwrap_or(Ordering::Equal),
159 (Int32(x), Float32(y)) => (*x as f32).partial_cmp(y).unwrap_or(Ordering::Equal),
160 (Int64(x), Float32(y)) => (*x as f64)
161 .partial_cmp(&(*y as f64))
162 .unwrap_or(Ordering::Equal),
163 (Float32(x), Int32(y)) => x.partial_cmp(&(*y as f32)).unwrap_or(Ordering::Equal),
164 (Float32(x), Int64(y)) => (*x as f64)
165 .partial_cmp(&(*y as f64))
166 .unwrap_or(Ordering::Equal),
167 (String(x), String(y)) => x.cmp(y),
168 _ => Ordering::Equal,
171 }
172}
173
174#[cfg(test)]
175#[allow(clippy::panic)]
176mod tests {
177 use super::*;
178 use crate::executor::scan::{DataType, Field, Schema};
179 use crate::parser::ast::{BinaryOperator, Expr};
180 use std::sync::Arc;
181
182 fn col(name: &str) -> Expr {
183 Expr::Column {
184 table: None,
185 name: name.to_string(),
186 }
187 }
188
189 #[test]
190 fn test_sort_execution() -> Result<()> {
191 let schema = Arc::new(Schema::new(vec![
192 Field::new("id".to_string(), DataType::Int64, false),
193 Field::new("value".to_string(), DataType::Int64, false),
194 ]));
195
196 let columns = vec![
197 ColumnData::Int64(vec![Some(3), Some(1), Some(4), Some(1), Some(5)]),
198 ColumnData::Int64(vec![Some(30), Some(10), Some(40), Some(15), Some(50)]),
199 ];
200
201 let batch = RecordBatch::new(schema, columns, 5)?;
202
203 let order_by = vec![OrderByExpr {
205 expr: Expr::Column {
206 table: None,
207 name: "id".to_string(),
208 },
209 asc: true,
210 nulls_first: false,
211 }];
212
213 let sort = Sort::new(order_by);
214 let sorted = sort.execute(&batch)?;
215
216 let ColumnData::Int64(data) = &sorted.columns[0] else {
218 panic!("Expected Int64 column");
219 };
220 assert_eq!(data[0], Some(1));
221 assert_eq!(data[1], Some(1));
222 assert_eq!(data[2], Some(3));
223 assert_eq!(data[3], Some(4));
224 assert_eq!(data[4], Some(5));
225
226 Ok(())
227 }
228
229 #[test]
230 fn test_sort_by_arithmetic_expression() -> Result<()> {
231 let schema = Arc::new(Schema::new(vec![
233 Field::new("a".to_string(), DataType::Int64, false),
234 Field::new("b".to_string(), DataType::Int64, false),
235 ]));
236 let columns = vec![
237 ColumnData::Int64(vec![Some(2), Some(1), Some(3)]),
238 ColumnData::Int64(vec![Some(5), Some(4), Some(1)]),
239 ];
240 let batch = RecordBatch::new(schema, columns, 3)?;
241 let order_by = vec![OrderByExpr {
243 expr: Expr::BinaryOp {
244 left: Box::new(col("a")),
245 op: BinaryOperator::Multiply,
246 right: Box::new(col("b")),
247 },
248 asc: true,
249 nulls_first: false,
250 }];
251 let sorted = Sort::new(order_by).execute(&batch)?;
252 let ColumnData::Int64(a) = &sorted.columns[0] else {
253 panic!("Expected Int64 column");
254 };
255 assert_eq!(a[0], Some(3)); assert_eq!(a[1], Some(1)); assert_eq!(a[2], Some(2)); Ok(())
259 }
260
261 #[test]
262 fn test_sort_nulls_first() -> Result<()> {
263 let schema = Arc::new(Schema::new(vec![Field::new(
264 "v".to_string(),
265 DataType::Int64,
266 true,
267 )]));
268 let columns = vec![ColumnData::Int64(vec![
269 Some(3),
270 None,
271 Some(1),
272 None,
273 Some(2),
274 ])];
275 let batch = RecordBatch::new(schema, columns, 5)?;
276
277 let order_by = vec![OrderByExpr {
279 expr: col("v"),
280 asc: true,
281 nulls_first: true,
282 }];
283 let sorted = Sort::new(order_by).execute(&batch)?;
284 let ColumnData::Int64(v) = &sorted.columns[0] else {
285 panic!("Expected Int64 column");
286 };
287 assert_eq!(v[0], None);
288 assert_eq!(v[1], None);
289 assert_eq!(v[2], Some(1));
290 assert_eq!(v[3], Some(2));
291 assert_eq!(v[4], Some(3));
292
293 let order_by = vec![OrderByExpr {
295 expr: col("v"),
296 asc: true,
297 nulls_first: false,
298 }];
299 let sorted = Sort::new(order_by).execute(&batch)?;
300 let ColumnData::Int64(v) = &sorted.columns[0] else {
301 panic!("Expected Int64 column");
302 };
303 assert_eq!(v[0], Some(1));
304 assert_eq!(v[1], Some(2));
305 assert_eq!(v[2], Some(3));
306 assert_eq!(v[3], None);
307 assert_eq!(v[4], None);
308 Ok(())
309 }
310
311 #[test]
312 fn test_sort_unknown_column_errors() -> Result<()> {
313 let schema = Arc::new(Schema::new(vec![Field::new(
314 "v".to_string(),
315 DataType::Int64,
316 false,
317 )]));
318 let columns = vec![ColumnData::Int64(vec![Some(1), Some(2)])];
319 let batch = RecordBatch::new(schema, columns, 2)?;
320 let order_by = vec![OrderByExpr {
321 expr: col("does_not_exist"),
322 asc: true,
323 nulls_first: false,
324 }];
325 assert!(Sort::new(order_by).execute(&batch).is_err());
327 Ok(())
328 }
329}