| 13 | use crate::engine_evaluator::evaluate_expression; |
| 14 | |
| 15 | pub(crate) fn execute_order_by_statement( |
| 16 | env: &mut Environment, |
| 17 | statement: &OrderByStatement, |
| 18 | gitql_object: &mut GitQLObject, |
| 19 | group_index: usize, |
| 20 | ) -> Result<(), String> { |
| 21 | if gitql_object.is_empty() || group_index >= gitql_object.len() { |
| 22 | return Ok(()); |
| 23 | } |
| 24 | |
| 25 | let main_group: &mut Group = &mut gitql_object.groups[group_index]; |
| 26 | if main_group.is_empty() { |
| 27 | return Ok(()); |
| 28 | } |
| 29 | |
| 30 | let rows_len = main_group.rows.len(); |
| 31 | let arguments_len = statement.arguments.len(); |
| 32 | let main_group_rows = &main_group.rows; |
| 33 | let titles = &gitql_object.titles; |
| 34 | |
| 35 | let mut eval_map: HashMap<usize, Vec<Box<dyn Value>>> = HashMap::with_capacity(rows_len); |
| 36 | |
| 37 | for row in main_group_rows.iter() { |
| 38 | let row_addr = row.values.as_ptr() as usize; |
| 39 | let mut arguments_values: Vec<Box<dyn Value>> = Vec::with_capacity(arguments_len); |
| 40 | for argument in statement.arguments.iter() { |
| 41 | // No need to compare if the ordering argument is constants |
| 42 | if argument.is_const() { |
| 43 | arguments_values.push(Box::new(NullValue)); |
| 44 | continue; |
| 45 | } |
| 46 | |
| 47 | let value = &evaluate_expression(env, argument, titles, &row.values)?; |
| 48 | arguments_values.push(value.to_owned()); |
| 49 | } |
| 50 | |
| 51 | eval_map.insert(row_addr, arguments_values); |
| 52 | } |
| 53 | |
| 54 | main_group.rows.sort_by(|a, b| { |
| 55 | for arg_index in 0..arguments_len { |
| 56 | let argument = &statement.arguments[arg_index]; |
| 57 | // No need to compare if the ordering argument is constants |
| 58 | if argument.is_const() { |
| 59 | continue; |
| 60 | } |
| 61 | |
| 62 | // Use the Memory address of A, B as Map keys |
| 63 | let a_addr = a.values.as_ptr() as usize; |
| 64 | let b_addr = b.values.as_ptr() as usize; |
| 65 | |
| 66 | // Get pre evaluated values from the eval map using addr as key, arg index as offset |
| 67 | let a_value = &eval_map.get(&a_addr).unwrap()[arg_index]; |
| 68 | let b_value = &eval_map.get(&b_addr).unwrap()[arg_index]; |
| 69 | |
| 70 | let null_ordering_policy = &statement.nulls_order_policies[arg_index]; |
| 71 | if a_value.is_null() { |
| 72 | return if null_ordering_policy.eq(&NullsOrderPolicy::NullsFirst) { |