1use crate::optimizer::workload::{global_workload_learner, QueryPattern};
20use radixdb_core::CompactArc;
21use radixdb_core::{Error, Result, Row, RowVec, Value};
22use radixdb_sql::ast::Expression;
23use radixdb_storage::traits::{
24 DeferredRow, QueryResult, TypedBatchFallbackReason, TypedColumnBatch,
25};
26use rustc_hash::{FxHashMap, FxHasher};
27use std::cell::OnceCell;
28use std::fs::{File, OpenOptions};
29use std::hash::{Hash, Hasher};
30use std::io::{BufReader, BufWriter, Read, Write};
31use std::path::PathBuf;
32use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
33use std::sync::Arc;
34
35use super::context::{CancellationHandle, TimeoutGuard};
36use super::expression::RowFilter;
37use super::operator::Operator;
38use crate::memory::RetainedRowsBudget;
39
40pub type ExecutionResult = Box<dyn QueryResult>;
45
46pub use radixdb_storage::traits::{AliasedResult, ScannerResult};
49
50#[doc(hidden)]
54pub struct TimedQueryResult {
55 inner: Box<dyn QueryResult>,
56 timeout_guard: Option<TimeoutGuard>,
57 cancellation: CancellationHandle,
58 cancelled_error_returned: bool,
59 workload: Option<WorkloadObservation>,
60 workload_started_at: radixdb_core::time_compat::Instant,
61 workload_rows: u64,
62}
63
64#[derive(Clone, Copy)]
65struct WorkloadObservation {
66 fingerprint: u64,
67 pattern: QueryPattern,
68}
69
70impl TimedQueryResult {
71 #[cfg(test)]
72 pub fn wrap(
73 inner: ExecutionResult,
74 timeout_guard: Option<TimeoutGuard>,
75 cancellation: CancellationHandle,
76 ) -> ExecutionResult {
77 Box::new(Self {
78 inner,
79 timeout_guard,
80 cancellation,
81 cancelled_error_returned: false,
82 workload: None,
83 workload_started_at: radixdb_core::time_compat::Instant::now(),
84 workload_rows: 0,
85 })
86 }
87
88 pub fn wrap_with_workload(
89 inner: ExecutionResult,
90 timeout_guard: Option<TimeoutGuard>,
91 cancellation: CancellationHandle,
92 sql: &str,
93 ) -> ExecutionResult {
94 let upper = sql.to_ascii_uppercase();
95 let pattern = if upper.trim_start().starts_with("INSERT") {
96 QueryPattern::InsertHeavy
97 } else if upper.trim_start().starts_with("UPDATE")
98 || upper.trim_start().starts_with("DELETE")
99 {
100 QueryPattern::UpdateHeavy
101 } else if upper.contains(" JOIN ") {
102 QueryPattern::JoinHeavy
103 } else if ["COUNT(", "SUM(", "AVG(", "MIN(", "MAX(", "GROUP BY"]
104 .iter()
105 .any(|needle| upper.contains(needle))
106 {
107 QueryPattern::Aggregation
108 } else if upper.trim_start().starts_with("SELECT") {
109 QueryPattern::FullScan
110 } else {
111 QueryPattern::Unknown
112 };
113 let mut hasher = FxHasher::default();
114 sql.hash(&mut hasher);
115
116 Box::new(Self {
117 inner,
118 timeout_guard,
119 cancellation,
120 cancelled_error_returned: false,
121 workload: Some(WorkloadObservation {
122 fingerprint: hasher.finish(),
123 pattern,
124 }),
125 workload_started_at: radixdb_core::time_compat::Instant::now(),
126 workload_rows: 0,
127 })
128 }
129
130 fn finish_workload_observation(&mut self) {
131 let Some(observation) = self.workload.take() else {
132 return;
133 };
134 let affected = self.inner.rows_affected().max(0) as u64;
135 let rows = self.workload_rows.max(affected);
136 global_workload_learner().record_query(
137 observation.fingerprint,
138 observation.pattern,
139 self.workload_started_at.elapsed(),
140 0,
141 rows,
142 rows,
143 Vec::new(),
144 Vec::new(),
145 Vec::new(),
146 );
147 }
148}
149
150impl QueryResult for TimedQueryResult {
151 fn columns(&self) -> &[String] {
152 self.inner.columns()
153 }
154
155 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
156 self.inner.columns_arc()
157 }
158
159 fn next(&mut self) -> bool {
160 if self.cancellation.is_cancelled() {
161 return false;
162 }
163 let has_row = self.inner.next();
164 if has_row {
165 self.workload_rows = self.workload_rows.saturating_add(1);
166 } else {
167 self.finish_workload_observation();
168 }
169 has_row
170 }
171
172 fn scan(&self, dest: &mut [Value]) -> Result<()> {
173 self.inner.scan(dest)
174 }
175
176 fn row(&self) -> &Row {
177 self.inner.row()
178 }
179
180 fn take_row(&mut self) -> Row {
181 self.inner.take_row()
182 }
183
184 fn take_deferred_row(&mut self) -> DeferredRow {
185 self.inner.take_deferred_row()
186 }
187
188 fn preserves_deferred_rows(&self) -> bool {
189 self.inner.preserves_deferred_rows()
190 }
191
192 fn close(&mut self) -> Result<()> {
193 let result = self.inner.close();
194 self.finish_workload_observation();
195 self.timeout_guard.take();
196 result
197 }
198
199 fn rows_affected(&self) -> i64 {
200 self.inner.rows_affected()
201 }
202
203 fn last_insert_id(&self) -> i64 {
204 self.inner.last_insert_id()
205 }
206
207 fn try_into_arc_rows(&mut self) -> Option<CompactArc<Vec<Row>>> {
208 let rows = self.inner.try_into_arc_rows();
209 if let Some(rows) = rows.as_ref() {
210 self.workload_rows = self.workload_rows.saturating_add(rows.len() as u64);
211 self.finish_workload_observation();
212 }
213 rows
214 }
215
216 fn estimated_count(&self) -> Option<usize> {
217 self.inner.estimated_count()
218 }
219
220 fn supports_typed_batches(&self) -> bool {
221 self.inner.supports_typed_batches()
222 }
223
224 fn typed_batch_fallback_reason(&self) -> Option<TypedBatchFallbackReason> {
225 self.inner.typed_batch_fallback_reason()
226 }
227
228 fn next_typed_batch(&mut self) -> Result<Option<TypedColumnBatch>> {
229 if self.cancellation.is_cancelled() {
230 return Err(radixdb_core::Error::QueryCancelled);
231 }
232 let batch = self.inner.next_typed_batch()?;
233 if let Some(batch) = batch.as_ref() {
234 self.workload_rows = self.workload_rows.saturating_add(batch.row_count() as u64);
235 } else {
236 self.finish_workload_observation();
237 }
238 Ok(batch)
239 }
240
241 fn last_error(&mut self) -> Option<radixdb_core::Error> {
242 if self.cancellation.is_cancelled() && !self.cancelled_error_returned {
243 self.cancelled_error_returned = true;
244 Some(radixdb_core::Error::QueryCancelled)
245 } else {
246 self.inner.last_error()
247 }
248 }
249
250 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
251 let Self {
252 inner,
253 timeout_guard,
254 cancellation,
255 cancelled_error_returned,
256 workload,
257 workload_started_at,
258 workload_rows,
259 } = *self;
260 Box::new(Self {
261 inner: inner.with_aliases(aliases),
262 timeout_guard,
263 cancellation,
264 cancelled_error_returned,
265 workload,
266 workload_started_at,
267 workload_rows,
268 })
269 }
270}
271
272pub struct ExecResult {
280 affected: i64,
282 insert_id: i64,
284}
285
286static EMPTY_COLUMNS: &[String] = &[];
288
289static EMPTY_ROW: std::sync::OnceLock<Row> = std::sync::OnceLock::new();
291
292#[inline]
293fn get_empty_row() -> &'static Row {
294 EMPTY_ROW.get_or_init(Row::new)
295}
296
297impl ExecResult {
298 #[inline]
300 pub fn new(rows_affected: i64, last_insert_id: i64) -> Self {
301 Self {
302 affected: rows_affected,
303 insert_id: last_insert_id,
304 }
305 }
306
307 #[inline]
309 pub fn empty() -> Self {
310 Self::new(0, 0)
311 }
312
313 #[inline]
315 pub fn with_rows_affected(rows_affected: i64) -> Self {
316 Self::new(rows_affected, 0)
317 }
318
319 #[inline]
321 pub fn with_last_insert_id(rows_affected: i64, last_insert_id: i64) -> Self {
322 Self::new(rows_affected, last_insert_id)
323 }
324}
325
326impl QueryResult for ExecResult {
327 fn columns(&self) -> &[String] {
328 EMPTY_COLUMNS
329 }
330
331 fn next(&mut self) -> bool {
332 false
334 }
335
336 fn scan(&self, _dest: &mut [Value]) -> Result<()> {
337 Err(radixdb_core::Error::internal(
338 "scan() called on exec result",
339 ))
340 }
341
342 fn row(&self) -> &Row {
343 get_empty_row()
344 }
345
346 fn close(&mut self) -> Result<()> {
347 Ok(())
348 }
349
350 fn rows_affected(&self) -> i64 {
351 self.affected
352 }
353
354 fn last_insert_id(&self) -> i64 {
355 self.insert_id
356 }
357
358 fn with_aliases(self: Box<Self>, _aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
359 self
360 }
361}
362
363enum RowStorage {
369 Owned(RowVec),
371 Shared(CompactArc<Vec<Row>>),
373}
374
375impl RowStorage {
376 #[inline]
377 fn len(&self) -> usize {
378 match self {
379 RowStorage::Owned(rv) => rv.len(),
380 RowStorage::Shared(rows) => rows.len(),
381 }
382 }
383
384 #[inline]
385 fn get(&self, index: usize) -> Option<&Row> {
386 match self {
387 RowStorage::Owned(rv) => rv.get(index).map(|(_, row)| row),
388 RowStorage::Shared(rows) => rows.get(index),
389 }
390 }
391
392 #[inline]
393 fn take(&mut self, index: usize) -> Row {
394 match self {
395 RowStorage::Owned(rv) => std::mem::take(&mut rv[index].1),
396 RowStorage::Shared(rows) => rows[index].clone(),
398 }
399 }
400}
401
402pub struct ExecutorResult {
403 columns: CompactArc<Vec<String>>,
405 rows: RowStorage,
407 len: usize,
409 current_index: Option<usize>,
411 closed: bool,
413 affected: i64,
415 insert_id: i64,
417}
418
419#[doc(hidden)]
426pub struct DeferredExecutorResult {
427 columns: CompactArc<Vec<String>>,
428 rows: Vec<Option<DeferredRow>>,
429 current_index: Option<usize>,
430 current_materialized: OnceCell<Row>,
431 closed: bool,
432}
433
434#[doc(hidden)]
440pub struct CertifiedOrderedResult {
441 inner: Box<dyn QueryResult>,
442 ordering: Vec<usize>,
443}
444
445impl CertifiedOrderedResult {
446 pub fn ascending_nulls_last(inner: Box<dyn QueryResult>, ordering: Vec<usize>) -> Self {
447 Self { inner, ordering }
448 }
449}
450
451impl QueryResult for CertifiedOrderedResult {
452 fn columns(&self) -> &[String] {
453 self.inner.columns()
454 }
455
456 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
457 self.inner.columns_arc()
458 }
459
460 fn next(&mut self) -> bool {
461 self.inner.next()
462 }
463
464 fn scan(&self, dest: &mut [Value]) -> Result<()> {
465 self.inner.scan(dest)
466 }
467
468 fn row(&self) -> &Row {
469 self.inner.row()
470 }
471
472 fn take_row(&mut self) -> Row {
473 self.inner.take_row()
474 }
475
476 fn take_deferred_row(&mut self) -> DeferredRow {
477 self.inner.take_deferred_row()
478 }
479
480 fn preserves_deferred_rows(&self) -> bool {
481 self.inner.preserves_deferred_rows()
482 }
483
484 fn ascending_nulls_last_ordering(&self) -> Option<Vec<usize>> {
485 Some(self.ordering.clone())
486 }
487
488 fn close(&mut self) -> Result<()> {
489 self.inner.close()
490 }
491
492 fn rows_affected(&self) -> i64 {
493 self.inner.rows_affected()
494 }
495
496 fn last_insert_id(&self) -> i64 {
497 self.inner.last_insert_id()
498 }
499
500 fn last_error(&mut self) -> Option<radixdb_core::Error> {
501 self.inner.last_error()
502 }
503
504 fn estimated_count(&self) -> Option<usize> {
505 self.inner.estimated_count()
506 }
507
508 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
509 let Self { inner, ordering } = *self;
510 Box::new(Self {
511 inner: inner.with_aliases(aliases),
512 ordering,
513 })
514 }
515}
516
517impl DeferredExecutorResult {
518 pub fn with_arc_columns(columns: CompactArc<Vec<String>>, rows: Vec<DeferredRow>) -> Self {
519 radixdb_storage::instrumentation::record_join_deferred_boundary_rows(rows.len() as u64);
520 Self {
521 columns,
522 rows: rows.into_iter().map(Some).collect(),
523 current_index: None,
524 current_materialized: OnceCell::new(),
525 closed: false,
526 }
527 }
528
529 fn current_deferred(&self) -> &DeferredRow {
530 let index = self
531 .current_index
532 .expect("row access without successful next()");
533 self.rows[index]
534 .as_ref()
535 .expect("row already consumed from deferred result")
536 }
537}
538
539impl QueryResult for DeferredExecutorResult {
540 fn columns(&self) -> &[String] {
541 &self.columns
542 }
543
544 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
545 Some(CompactArc::clone(&self.columns))
546 }
547
548 fn next(&mut self) -> bool {
549 if self.closed {
550 return false;
551 }
552 self.current_materialized = OnceCell::new();
553 let next_index = self.current_index.map_or(0, |index| index + 1);
554 if next_index < self.rows.len() {
555 self.current_index = Some(next_index);
556 true
557 } else {
558 false
559 }
560 }
561
562 fn scan(&self, dest: &mut [Value]) -> Result<()> {
563 let row = self.row();
564 if dest.len() != row.len() {
565 return Err(radixdb_core::Error::internal(format!(
566 "scan destination has {} values but row has {} columns",
567 dest.len(),
568 row.len()
569 )));
570 }
571 dest.clone_from_slice(row.as_slice());
572 Ok(())
573 }
574
575 fn row(&self) -> &Row {
576 self.current_materialized
577 .get_or_init(|| self.current_deferred().to_owned())
578 }
579
580 fn take_row(&mut self) -> Row {
581 let index = self
582 .current_index
583 .expect("take_row() called without successful next()");
584 let deferred = self.rows[index]
585 .take()
586 .expect("take_row() called after current row was consumed");
587 self.current_materialized
588 .take()
589 .unwrap_or_else(|| deferred.into_owned())
590 }
591
592 fn take_deferred_row(&mut self) -> DeferredRow {
593 let index = self
594 .current_index
595 .expect("take_deferred_row() called without successful next()");
596 let deferred = self.rows[index]
597 .take()
598 .expect("take_deferred_row() called after current row was consumed");
599 self.current_materialized
600 .take()
601 .map_or(deferred, DeferredRow::owned)
602 }
603
604 fn preserves_deferred_rows(&self) -> bool {
605 true
606 }
607
608 fn close(&mut self) -> Result<()> {
609 self.closed = true;
610 Ok(())
611 }
612
613 fn rows_affected(&self) -> i64 {
614 0
615 }
616
617 fn last_insert_id(&self) -> i64 {
618 0
619 }
620
621 fn estimated_count(&self) -> Option<usize> {
622 if self.closed {
623 return Some(0);
624 }
625 let consumed = self
626 .current_index
627 .map_or(0, |index| index.saturating_add(1));
628 Some(self.rows.len().saturating_sub(consumed))
629 }
630
631 fn with_aliases(
632 mut self: Box<Self>,
633 aliases: FxHashMap<String, String>,
634 ) -> Box<dyn QueryResult> {
635 let columns = CompactArc::make_mut(&mut self.columns);
636 for column in columns {
637 if let Some((alias, _)) = aliases.iter().find(|(_, original)| *original == column) {
638 *column = alias.clone();
639 }
640 }
641 self
642 }
643}
644
645#[doc(hidden)]
651pub struct OperatorExecutorResult {
652 columns: CompactArc<Vec<String>>,
653 operator: Box<dyn Operator>,
654 cancellation: CancellationHandle,
655 current: Option<DeferredRow>,
656 current_materialized: OnceCell<Row>,
657 pending_error: Option<radixdb_core::Error>,
658 estimated_rows: Option<usize>,
659 emitted_rows: usize,
660 remaining_limit: Option<usize>,
661 ordering: Option<Vec<usize>>,
662 closed: bool,
663}
664
665impl OperatorExecutorResult {
666 pub fn open(
667 columns: CompactArc<Vec<String>>,
668 mut operator: Box<dyn Operator>,
669 cancellation: CancellationHandle,
670 limit: Option<u64>,
671 ) -> Result<Self> {
672 let estimated_rows = operator.estimated_rows().map(|rows| {
673 limit.map_or(rows, |limit| {
674 rows.min(usize::try_from(limit).unwrap_or(usize::MAX))
675 })
676 });
677 let ordering = match operator.ordering() {
678 super::operator::OrderingProperty::AscendingNullsLast(keys) => Some(keys),
679 super::operator::OrderingProperty::Unknown => None,
680 };
681 if let Err(error) = operator.open() {
682 let _ = operator.close();
683 return Err(error);
684 }
685 Ok(Self {
686 columns,
687 operator,
688 cancellation,
689 current: None,
690 current_materialized: OnceCell::new(),
691 pending_error: None,
692 estimated_rows,
693 emitted_rows: 0,
694 remaining_limit: limit.map(|limit| usize::try_from(limit).unwrap_or(usize::MAX)),
695 ordering,
696 closed: false,
697 })
698 }
699
700 fn finish(&mut self) -> Result<()> {
701 if self.closed {
702 return Ok(());
703 }
704 self.closed = true;
705 self.operator.close()
706 }
707
708 fn fail(&mut self, error: radixdb_core::Error) -> bool {
709 self.pending_error = Some(error);
710 if let Err(close_error) = self.finish() {
711 if self.pending_error.is_none() {
712 self.pending_error = Some(close_error);
713 }
714 }
715 false
716 }
717
718 fn current_deferred(&self) -> &DeferredRow {
719 self.current
720 .as_ref()
721 .expect("row access without successful next()")
722 }
723}
724
725impl Drop for OperatorExecutorResult {
726 fn drop(&mut self) {
727 let _ = self.finish();
728 }
729}
730
731impl QueryResult for OperatorExecutorResult {
732 fn columns(&self) -> &[String] {
733 &self.columns
734 }
735
736 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
737 Some(CompactArc::clone(&self.columns))
738 }
739
740 fn next(&mut self) -> bool {
741 if self.closed || self.pending_error.is_some() {
742 return false;
743 }
744 self.current = None;
745 self.current_materialized = OnceCell::new();
746 if self.remaining_limit == Some(0) {
747 return match self.finish() {
748 Ok(()) => false,
749 Err(error) => self.fail(error),
750 };
751 }
752 if self.cancellation.is_cancelled() {
753 return self.fail(radixdb_core::Error::QueryCancelled);
754 }
755
756 match self.operator.next() {
757 Ok(Some(row)) => {
758 self.current = Some(row.into_deferred());
759 self.emitted_rows = self.emitted_rows.saturating_add(1);
760 if let Some(remaining) = self.remaining_limit.as_mut() {
761 *remaining = remaining.saturating_sub(1);
762 }
763 true
764 }
765 Ok(None) => match self.finish() {
766 Ok(()) => false,
767 Err(error) => self.fail(error),
768 },
769 Err(error) => self.fail(error),
770 }
771 }
772
773 fn scan(&self, dest: &mut [Value]) -> Result<()> {
774 let row = self.row();
775 if dest.len() != row.len() {
776 return Err(radixdb_core::Error::internal(format!(
777 "scan destination has {} values but row has {} columns",
778 dest.len(),
779 row.len()
780 )));
781 }
782 dest.clone_from_slice(row.as_slice());
783 Ok(())
784 }
785
786 fn row(&self) -> &Row {
787 self.current_materialized
788 .get_or_init(|| self.current_deferred().to_owned())
789 }
790
791 fn take_row(&mut self) -> Row {
792 let deferred = self
793 .current
794 .take()
795 .expect("take_row() called without successful next()");
796 self.current_materialized
797 .take()
798 .unwrap_or_else(|| deferred.into_owned())
799 }
800
801 fn take_deferred_row(&mut self) -> DeferredRow {
802 let deferred = self
803 .current
804 .take()
805 .expect("take_deferred_row() called without successful next()");
806 self.current_materialized
807 .take()
808 .map_or(deferred, DeferredRow::owned)
809 }
810
811 fn preserves_deferred_rows(&self) -> bool {
812 true
813 }
814
815 fn ascending_nulls_last_ordering(&self) -> Option<Vec<usize>> {
816 self.ordering.clone()
817 }
818
819 fn close(&mut self) -> Result<()> {
820 self.current = None;
821 self.current_materialized = OnceCell::new();
822 self.finish()
823 }
824
825 fn rows_affected(&self) -> i64 {
826 0
827 }
828
829 fn last_insert_id(&self) -> i64 {
830 0
831 }
832
833 fn estimated_count(&self) -> Option<usize> {
834 if self.closed {
835 return Some(0);
836 }
837 self.estimated_rows
838 .map(|rows| rows.saturating_sub(self.emitted_rows))
839 }
840
841 fn last_error(&mut self) -> Option<radixdb_core::Error> {
842 self.pending_error.take()
843 }
844
845 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
846 Box::new(AliasedResult::new(self, aliases))
847 }
848}
849
850#[doc(hidden)]
856pub struct StreamingRowsResult {
857 columns: Vec<String>,
858 rows: Box<dyn Iterator<Item = Result<(i64, Row)>> + Send>,
859 current: Option<Row>,
860 pending_error: Option<radixdb_core::Error>,
861}
862
863impl StreamingRowsResult {
864 pub fn new(
865 columns: Vec<String>,
866 rows: Box<dyn Iterator<Item = Result<(i64, Row)>> + Send>,
867 ) -> Self {
868 Self {
869 columns,
870 rows,
871 current: None,
872 pending_error: None,
873 }
874 }
875}
876
877impl QueryResult for StreamingRowsResult {
878 fn columns(&self) -> &[String] {
879 &self.columns
880 }
881
882 fn next(&mut self) -> bool {
883 self.current = None;
884 match self.rows.next() {
885 Some(Ok((_, row))) => {
886 self.current = Some(row);
887 true
888 }
889 Some(Err(error)) => {
890 self.pending_error = Some(error);
891 false
892 }
893 None => false,
894 }
895 }
896
897 fn scan(&self, dest: &mut [Value]) -> Result<()> {
898 let row = self.row();
899 if dest.len() != row.len() {
900 return Err(radixdb_core::Error::internal(format!(
901 "scan destination has {} values but row has {} columns",
902 dest.len(),
903 row.len()
904 )));
905 }
906 dest.clone_from_slice(row.as_slice());
907 Ok(())
908 }
909
910 fn row(&self) -> &Row {
911 self.current
912 .as_ref()
913 .expect("row() called without successful next()")
914 }
915
916 fn rows_affected(&self) -> i64 {
917 0
918 }
919
920 fn last_insert_id(&self) -> i64 {
921 0
922 }
923
924 fn take_row(&mut self) -> Row {
925 self.current
926 .take()
927 .expect("take_row() called without successful next()")
928 }
929
930 fn last_error(&mut self) -> Option<radixdb_core::Error> {
931 self.pending_error.take()
932 }
933
934 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
935 Box::new(AliasedResult::new(self, aliases))
936 }
937}
938
939impl ExecutorResult {
940 pub fn new(columns: Vec<String>, rows: RowVec) -> Self {
942 let len = rows.len();
943 Self {
944 columns: CompactArc::new(columns),
945 rows: RowStorage::Owned(rows),
946 len,
947 current_index: None,
948 closed: false,
949 affected: 0,
950 insert_id: 0,
951 }
952 }
953
954 pub fn with_arc_columns(columns: CompactArc<Vec<String>>, rows: RowVec) -> Self {
956 let len = rows.len();
957 Self {
958 columns,
959 rows: RowStorage::Owned(rows),
960 len,
961 current_index: None,
962 closed: false,
963 affected: 0,
964 insert_id: 0,
965 }
966 }
967
968 pub fn with_shared_rows(columns: Vec<String>, rows: CompactArc<Vec<Row>>) -> Self {
971 let len = rows.len();
972 Self {
973 columns: CompactArc::new(columns),
974 rows: RowStorage::Shared(rows),
975 len,
976 current_index: None,
977 closed: false,
978 affected: 0,
979 insert_id: 0,
980 }
981 }
982
983 pub fn with_arc_columns_shared_rows(
985 columns: CompactArc<Vec<String>>,
986 rows: CompactArc<Vec<Row>>,
987 ) -> Self {
988 let len = rows.len();
989 Self {
990 columns,
991 rows: RowStorage::Shared(rows),
992 len,
993 current_index: None,
994 closed: false,
995 affected: 0,
996 insert_id: 0,
997 }
998 }
999
1000 pub fn empty() -> Self {
1002 Self::new(Vec::new(), RowVec::new())
1003 }
1004
1005 pub fn with_columns(columns: Vec<String>) -> Self {
1007 Self::new(columns, RowVec::new())
1008 }
1009
1010 pub fn add_row(&mut self, row: Row) {
1012 let shared_rows = match &self.rows {
1014 RowStorage::Owned(_) => None,
1015 RowStorage::Shared(arc_rows) => {
1016 let mut rows = RowVec::with_capacity(arc_rows.len() + 1);
1017 for (index, row) in arc_rows.iter().enumerate() {
1018 rows.push((index as i64, row.clone()));
1019 }
1020 Some(rows)
1021 }
1022 };
1023 if let Some(rows) = shared_rows {
1024 self.rows = RowStorage::Owned(rows);
1025 }
1026 if let RowStorage::Owned(rv) = &mut self.rows {
1027 rv.push((self.len as i64, row));
1028 self.len += 1;
1029 }
1030 }
1031
1032 #[inline]
1034 pub fn row_count(&self) -> usize {
1035 self.len
1036 }
1037
1038 #[inline]
1040 pub fn get_row(&self, index: usize) -> Option<&Row> {
1041 self.rows.get(index)
1042 }
1043
1044 pub fn into_rows(self) -> Vec<Row> {
1046 match self.rows {
1047 RowStorage::Owned(mut rv) => rv.drain_rows().collect(),
1048 RowStorage::Shared(rows) => {
1049 CompactArc::try_unwrap(rows).unwrap_or_else(|arc| (*arc).clone())
1051 }
1052 }
1053 }
1054
1055 pub fn into_arc_rows(self) -> CompactArc<Vec<Row>> {
1058 match self.rows {
1059 RowStorage::Owned(mut rv) => CompactArc::new(rv.drain_rows().collect()),
1060 RowStorage::Shared(rows) => rows,
1061 }
1062 }
1063
1064 pub fn reset(&mut self) {
1066 self.current_index = None;
1067 }
1068
1069 pub fn set_rows_affected(&mut self, count: i64) {
1071 self.affected = count;
1072 }
1073
1074 pub fn set_last_insert_id(&mut self, id: i64) {
1076 self.insert_id = id;
1077 }
1078}
1079
1080impl QueryResult for ExecutorResult {
1081 fn columns(&self) -> &[String] {
1082 &self.columns
1083 }
1084
1085 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
1086 Some(CompactArc::clone(&self.columns))
1087 }
1088
1089 #[inline]
1090 fn next(&mut self) -> bool {
1091 if self.closed {
1092 return false;
1093 }
1094
1095 let next_index = match self.current_index {
1096 None => 0,
1097 Some(i) => i + 1,
1098 };
1099
1100 if next_index < self.len {
1101 self.current_index = Some(next_index);
1102 true
1103 } else {
1104 false
1105 }
1106 }
1107
1108 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1109 let row = self.row();
1110
1111 if dest.len() != row.len() {
1112 return Err(radixdb_core::Error::internal(format!(
1113 "scan destination has {} values but row has {} columns",
1114 dest.len(),
1115 row.len()
1116 )));
1117 }
1118
1119 for (i, value) in row.iter().enumerate() {
1120 dest[i] = value.clone();
1121 }
1122
1123 Ok(())
1124 }
1125
1126 fn row(&self) -> &Row {
1127 match self.current_index {
1128 Some(i) => self
1129 .rows
1130 .get(i)
1131 .expect("row() called without successful next()"),
1132 _ => panic!("row() called without successful next()"),
1133 }
1134 }
1135
1136 fn take_row(&mut self) -> Row {
1137 match self.current_index {
1138 Some(i) if i < self.rows.len() => self.rows.take(i),
1139 _ => panic!("take_row() called without successful next()"),
1140 }
1141 }
1142
1143 fn close(&mut self) -> Result<()> {
1144 self.closed = true;
1145 Ok(())
1146 }
1147
1148 fn rows_affected(&self) -> i64 {
1149 self.affected
1150 }
1151
1152 fn last_insert_id(&self) -> i64 {
1153 self.insert_id
1154 }
1155
1156 fn try_into_arc_rows(&mut self) -> Option<CompactArc<Vec<Row>>> {
1157 let rows = std::mem::replace(&mut self.rows, RowStorage::Owned(RowVec::new()));
1159 self.closed = true; match rows {
1161 RowStorage::Owned(mut rv) => Some(CompactArc::new(rv.drain_rows().collect())),
1162 RowStorage::Shared(arc) => Some(arc),
1163 }
1164 }
1165
1166 fn estimated_count(&self) -> Option<usize> {
1167 if self.closed {
1168 return Some(0);
1169 }
1170 let consumed = self
1171 .current_index
1172 .map_or(0, |index| index.saturating_add(1));
1173 Some(self.len.saturating_sub(consumed))
1174 }
1175
1176 fn with_aliases(
1177 mut self: Box<Self>,
1178 aliases: FxHashMap<String, String>,
1179 ) -> Box<dyn QueryResult> {
1180 let columns = CompactArc::make_mut(&mut self.columns);
1182 for col in columns {
1183 for (alias, original) in &aliases {
1185 if col == original {
1186 *col = alias.clone();
1187 break;
1188 }
1189 }
1190 }
1191 self
1192 }
1193}
1194
1195pub struct FilteredResult {
1200 inner: Box<dyn QueryResult>,
1202 filter: RowFilter,
1204 current_row: Option<Row>,
1206 columns: Vec<String>,
1208 pending_error: Option<radixdb_core::Error>,
1210}
1211
1212#[doc(hidden)]
1219pub struct DeferredFilteredResult {
1220 inner: Box<dyn QueryResult>,
1221 filter: RowFilter,
1222 current: Option<DeferredRow>,
1223 current_materialized: OnceCell<Row>,
1224 columns: CompactArc<Vec<String>>,
1225 pending_error: Option<radixdb_core::Error>,
1226}
1227
1228impl DeferredFilteredResult {
1229 pub fn from_filter(inner: Box<dyn QueryResult>, filter: RowFilter) -> Self {
1230 let columns = inner
1231 .columns_arc()
1232 .unwrap_or_else(|| CompactArc::new(inner.columns().to_vec()));
1233 Self {
1234 inner,
1235 filter,
1236 current: None,
1237 current_materialized: OnceCell::new(),
1238 columns,
1239 pending_error: None,
1240 }
1241 }
1242
1243 fn current_deferred(&self) -> &DeferredRow {
1244 self.current
1245 .as_ref()
1246 .expect("row access without successful next()")
1247 }
1248}
1249
1250impl QueryResult for DeferredFilteredResult {
1251 fn columns(&self) -> &[String] {
1252 &self.columns
1253 }
1254
1255 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
1256 Some(CompactArc::clone(&self.columns))
1257 }
1258
1259 fn next(&mut self) -> bool {
1260 self.current = None;
1261 self.current_materialized = OnceCell::new();
1262 while self.inner.next() {
1263 let row = self.inner.take_deferred_row();
1264 match self.filter.matches_deferred_checked(&row) {
1265 Ok(true) => {
1266 self.current = Some(row);
1267 return true;
1268 }
1269 Ok(false) => {}
1270 Err(error) => {
1271 self.pending_error = Some(error);
1272 return false;
1273 }
1274 }
1275 }
1276 false
1277 }
1278
1279 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1280 let row = self.row();
1281 if dest.len() != row.len() {
1282 return Err(radixdb_core::Error::internal(format!(
1283 "scan destination has {} values but row has {} columns",
1284 dest.len(),
1285 row.len()
1286 )));
1287 }
1288 dest.clone_from_slice(row.as_slice());
1289 Ok(())
1290 }
1291
1292 fn row(&self) -> &Row {
1293 self.current_materialized
1294 .get_or_init(|| self.current_deferred().to_owned())
1295 }
1296
1297 fn take_row(&mut self) -> Row {
1298 let deferred = self
1299 .current
1300 .take()
1301 .expect("take_row() called without successful next()");
1302 self.current_materialized
1303 .take()
1304 .unwrap_or_else(|| deferred.into_owned())
1305 }
1306
1307 fn take_deferred_row(&mut self) -> DeferredRow {
1308 let deferred = self
1309 .current
1310 .take()
1311 .expect("take_deferred_row() called without successful next()");
1312 self.current_materialized
1313 .take()
1314 .map_or(deferred, DeferredRow::owned)
1315 }
1316
1317 fn preserves_deferred_rows(&self) -> bool {
1318 true
1319 }
1320
1321 fn ascending_nulls_last_ordering(&self) -> Option<Vec<usize>> {
1322 self.inner.ascending_nulls_last_ordering()
1323 }
1324
1325 fn close(&mut self) -> Result<()> {
1326 self.current = None;
1327 self.current_materialized = OnceCell::new();
1328 self.inner.close()
1329 }
1330
1331 fn rows_affected(&self) -> i64 {
1332 self.inner.rows_affected()
1333 }
1334
1335 fn last_insert_id(&self) -> i64 {
1336 self.inner.last_insert_id()
1337 }
1338
1339 fn last_error(&mut self) -> Option<radixdb_core::Error> {
1340 self.pending_error
1341 .take()
1342 .or_else(|| self.inner.last_error())
1343 }
1344
1345 fn estimated_count(&self) -> Option<usize> {
1346 self.inner.estimated_count()
1347 }
1348
1349 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
1350 Box::new(AliasedResult::new(self, aliases))
1351 }
1352}
1353
1354impl FilteredResult {
1355 pub fn new(inner: Box<dyn QueryResult>, filter_expr: &Expression) -> Result<Self> {
1363 let columns = inner.columns().to_vec();
1364 let filter = RowFilter::new(filter_expr, &columns)?;
1365
1366 Ok(Self {
1367 inner,
1368 filter,
1369 current_row: None,
1370 columns,
1371 pending_error: None,
1372 })
1373 }
1374
1375 pub fn from_filter(inner: Box<dyn QueryResult>, filter: RowFilter) -> Self {
1380 let columns = inner.columns().to_vec();
1381 Self {
1382 inner,
1383 filter,
1384 current_row: None,
1385 columns,
1386 pending_error: None,
1387 }
1388 }
1389
1390 pub fn with_defaults(inner: Box<dyn QueryResult>, filter_expr: Expression) -> Result<Self> {
1392 let columns = inner.columns().to_vec();
1393 let filter = RowFilter::new(&filter_expr, &columns)?;
1394
1395 Ok(Self {
1396 inner,
1397 filter,
1398 current_row: None,
1399 columns,
1400 pending_error: None,
1401 })
1402 }
1403}
1404
1405impl QueryResult for FilteredResult {
1406 fn columns(&self) -> &[String] {
1407 &self.columns
1408 }
1409
1410 fn next(&mut self) -> bool {
1411 while self.inner.next() {
1413 let row = self.inner.row();
1414 match self.filter.matches_checked(row) {
1416 Ok(true) => {
1417 self.current_row = Some(self.inner.take_row());
1418 return true;
1419 }
1420 Ok(false) => continue,
1421 Err(e) => {
1422 self.pending_error = Some(e);
1423 self.current_row = None;
1424 return false;
1425 }
1426 }
1427 }
1428 self.current_row = None;
1429 false
1430 }
1431
1432 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1433 if let Some(ref row) = self.current_row {
1434 if dest.len() != row.len() {
1435 return Err(radixdb_core::Error::internal(format!(
1436 "scan destination has {} values but row has {} columns",
1437 dest.len(),
1438 row.len()
1439 )));
1440 }
1441 for (i, value) in row.iter().enumerate() {
1442 dest[i] = value.clone();
1443 }
1444 Ok(())
1445 } else {
1446 Err(radixdb_core::Error::internal(
1447 "scan() called without successful next()",
1448 ))
1449 }
1450 }
1451
1452 fn row(&self) -> &Row {
1453 self.current_row
1454 .as_ref()
1455 .expect("row() called without successful next()")
1456 }
1457
1458 fn take_row(&mut self) -> Row {
1459 self.current_row
1460 .take()
1461 .expect("take_row() called without successful next()")
1462 }
1463
1464 fn close(&mut self) -> Result<()> {
1465 self.inner.close()
1466 }
1467
1468 fn rows_affected(&self) -> i64 {
1469 self.inner.rows_affected()
1470 }
1471
1472 fn last_insert_id(&self) -> i64 {
1473 self.inner.last_insert_id()
1474 }
1475
1476 fn last_error(&mut self) -> Option<radixdb_core::Error> {
1477 self.pending_error
1479 .take()
1480 .or_else(|| self.inner.last_error())
1481 }
1482
1483 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
1484 Box::new(AliasedResult::new(self, aliases))
1485 }
1486}
1487
1488#[doc(hidden)]
1496pub struct PrefetchedResult {
1497 inner: Box<dyn QueryResult>,
1498 columns: Vec<String>,
1499 prefetched: Option<Row>,
1500 current_row: Option<Row>,
1501}
1502
1503impl PrefetchedResult {
1504 pub fn new(prefetched: Row, inner: Box<dyn QueryResult>) -> Self {
1505 let columns = inner.columns().to_vec();
1506 Self {
1507 inner,
1508 columns,
1509 prefetched: Some(prefetched),
1510 current_row: None,
1511 }
1512 }
1513}
1514
1515impl QueryResult for PrefetchedResult {
1516 fn columns(&self) -> &[String] {
1517 &self.columns
1518 }
1519
1520 fn next(&mut self) -> bool {
1521 self.current_row = None;
1522 if let Some(row) = self.prefetched.take() {
1523 self.current_row = Some(row);
1524 return true;
1525 }
1526 if self.inner.next() {
1527 self.current_row = Some(self.inner.take_row());
1528 return true;
1529 }
1530 false
1531 }
1532
1533 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1534 let row = self.current_row.as_ref().ok_or_else(|| {
1535 radixdb_core::Error::internal("scan() called without successful next()")
1536 })?;
1537 if dest.len() != row.len() {
1538 return Err(radixdb_core::Error::internal(format!(
1539 "scan destination has {} values but row has {} columns",
1540 dest.len(),
1541 row.len()
1542 )));
1543 }
1544 for (index, value) in row.iter().enumerate() {
1545 dest[index] = value.clone();
1546 }
1547 Ok(())
1548 }
1549
1550 fn row(&self) -> &Row {
1551 self.current_row
1552 .as_ref()
1553 .expect("row() called without successful next()")
1554 }
1555
1556 fn take_row(&mut self) -> Row {
1557 self.current_row
1558 .take()
1559 .expect("take_row() called without successful next()")
1560 }
1561
1562 fn close(&mut self) -> Result<()> {
1563 self.prefetched = None;
1564 self.current_row = None;
1565 self.inner.close()
1566 }
1567
1568 fn rows_affected(&self) -> i64 {
1569 self.inner.rows_affected()
1570 }
1571
1572 fn last_insert_id(&self) -> i64 {
1573 self.inner.last_insert_id()
1574 }
1575
1576 fn estimated_count(&self) -> Option<usize> {
1577 self.inner
1578 .estimated_count()
1579 .map(|count| count.saturating_add(usize::from(self.prefetched.is_some())))
1580 }
1581
1582 fn last_error(&mut self) -> Option<radixdb_core::Error> {
1583 self.inner.last_error()
1584 }
1585
1586 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
1587 Box::new(AliasedResult::new(self, aliases))
1588 }
1589}
1590
1591enum CompiledProjection {
1593 Star,
1595 QualifiedStar {
1597 qualifier_lower: String,
1599 },
1600 Compiled(super::expression::SharedProgram),
1602}
1603
1604pub struct ExprMappedResult {
1609 inner: Box<dyn QueryResult>,
1611 projections: Vec<CompiledProjection>,
1613 vm: super::expression::ExprVM,
1615 current_row: Row,
1617 output_columns: Vec<String>,
1619 source_columns_lower: Vec<String>,
1621 pending_error: Option<radixdb_core::Error>,
1623 params: Vec<Value>,
1624 named_params: FxHashMap<String, Value>,
1625 transaction_id: Option<u64>,
1626 stored_function_invoker: Option<Arc<dyn super::context::StoredFunctionInvoker>>,
1627 ordering: Option<Vec<usize>>,
1628}
1629
1630impl ExprMappedResult {
1631 fn direct_source_index(expression: &Expression, source_columns: &[String]) -> Option<usize> {
1632 let expression = match expression {
1633 Expression::Aliased(aliased) => aliased.expression.as_ref(),
1634 other => other,
1635 };
1636 match expression {
1637 Expression::QualifiedIdentifier(identifier) => {
1638 let qualified = identifier.to_string();
1639 source_columns
1640 .iter()
1641 .position(|column| column.eq_ignore_ascii_case(&qualified))
1642 }
1643 Expression::Identifier(identifier) => {
1644 let mut matches = source_columns.iter().enumerate().filter(|(_, column)| {
1645 column.eq_ignore_ascii_case(identifier.value.as_str())
1646 || column.rsplit_once('.').is_some_and(|(_, base)| {
1647 base.eq_ignore_ascii_case(identifier.value.as_str())
1648 })
1649 });
1650 let (index, _) = matches.next()?;
1651 matches.next().is_none().then_some(index)
1652 }
1653 _ => None,
1654 }
1655 }
1656
1657 pub fn new(
1666 inner: Box<dyn QueryResult>,
1667 expressions: Vec<Expression>,
1668 output_columns: Vec<String>,
1669 ) -> Result<Self> {
1670 Self::new_with_optional_context(inner, expressions, output_columns, None)
1671 }
1672
1673 pub fn with_context(
1674 inner: Box<dyn QueryResult>,
1675 expressions: Vec<Expression>,
1676 output_columns: Vec<String>,
1677 ctx: &super::context::ExecutionContext,
1678 ) -> Result<Self> {
1679 Self::new_with_optional_context(inner, expressions, output_columns, Some(ctx))
1680 }
1681
1682 fn new_with_optional_context(
1683 inner: Box<dyn QueryResult>,
1684 expressions: Vec<Expression>,
1685 output_columns: Vec<String>,
1686 ctx: Option<&super::context::ExecutionContext>,
1687 ) -> Result<Self> {
1688 use super::expression::compile_expression;
1689
1690 let source_columns = inner.columns().to_vec();
1691 let source_ordering = inner.ascending_nulls_last_ordering();
1692
1693 let mut projections = Vec::with_capacity(expressions.len());
1695 for expr in &expressions {
1696 let projection = match expr {
1697 Expression::Star(_) => CompiledProjection::Star,
1698 Expression::QualifiedStar(qs) => CompiledProjection::QualifiedStar {
1699 qualifier_lower: qs.qualifier.to_lowercase().to_string(),
1700 },
1701 _ => {
1702 let program = compile_expression(expr, &source_columns)?;
1703 CompiledProjection::Compiled(program)
1704 }
1705 };
1706 projections.push(projection);
1707 }
1708
1709 let source_columns_lower: Vec<String> =
1711 source_columns.iter().map(|c| c.to_lowercase()).collect();
1712 let ordering = source_ordering.and_then(|keys| {
1713 let mut remapped = Vec::with_capacity(keys.len());
1714 for key in keys {
1715 let output = expressions.iter().position(|expression| {
1716 Self::direct_source_index(expression, &source_columns) == Some(key)
1717 })?;
1718 remapped.push(output);
1719 }
1720 (!remapped.is_empty()).then_some(remapped)
1721 });
1722
1723 let capacity = projections.len();
1725 Ok(Self {
1726 inner,
1727 projections,
1728 vm: super::expression::ExprVM::new(),
1729 current_row: Row::with_capacity(capacity),
1730 output_columns,
1731 source_columns_lower,
1732 pending_error: None,
1733 params: ctx.map_or_else(Vec::new, |ctx| ctx.params().to_vec()),
1734 named_params: ctx.map_or_else(FxHashMap::default, |ctx| ctx.named_params().clone()),
1735 transaction_id: ctx.and_then(super::context::ExecutionContext::transaction_id),
1736 stored_function_invoker: ctx.and_then(|ctx| ctx.stored_function_invoker().cloned()),
1737 ordering,
1738 })
1739 }
1740
1741 pub fn with_defaults(
1743 inner: Box<dyn QueryResult>,
1744 expressions: Vec<Expression>,
1745 output_columns: Vec<String>,
1746 ) -> Result<Self> {
1747 Self::new(inner, expressions, output_columns)
1748 }
1749}
1750
1751impl QueryResult for ExprMappedResult {
1752 fn columns(&self) -> &[String] {
1753 &self.output_columns
1754 }
1755
1756 fn next(&mut self) -> bool {
1757 use super::expression::ExecuteContext;
1758
1759 if self.inner.next() {
1760 let source_row = self.inner.row();
1761
1762 self.current_row.reserve_inline(self.projections.len());
1765 self.current_row.clear_inline();
1767 for projection in &self.projections {
1768 match projection {
1769 CompiledProjection::Star => {
1770 for value in source_row.iter() {
1772 self.current_row.push_inline(value.clone());
1773 }
1774 }
1775 CompiledProjection::QualifiedStar { qualifier_lower } => {
1776 let qualifier_len = qualifier_lower.len();
1779 for (idx, col_lower) in self.source_columns_lower.iter().enumerate() {
1780 if col_lower.len() > qualifier_len
1782 && col_lower.starts_with(qualifier_lower.as_str())
1783 && col_lower.as_bytes()[qualifier_len] == b'.'
1784 && idx < source_row.len()
1785 {
1786 self.current_row.push_inline(source_row[idx].clone());
1787 }
1788 }
1789 }
1790 CompiledProjection::Compiled(program) => {
1791 let ctx = ExecuteContext::with_common_params(
1792 source_row,
1793 &self.params,
1794 (!self.named_params.is_empty()).then_some(&self.named_params),
1795 self.transaction_id,
1796 )
1797 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1798 let value = self.vm.execute_cow(program, &ctx);
1799 match value {
1800 Ok(value) => self.current_row.push_inline(value),
1801 Err(error) => {
1802 self.pending_error = Some(error);
1803 self.current_row.clear_inline();
1804 return false;
1805 }
1806 }
1807 }
1808 }
1809 }
1810 true
1811 } else {
1812 false
1813 }
1814 }
1815
1816 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1817 if dest.len() != self.current_row.len() {
1818 return Err(radixdb_core::Error::internal(format!(
1819 "scan destination has {} values but row has {} columns",
1820 dest.len(),
1821 self.current_row.len()
1822 )));
1823 }
1824 for (i, value) in self.current_row.iter().enumerate() {
1825 dest[i] = value.clone();
1826 }
1827 Ok(())
1828 }
1829
1830 fn row(&self) -> &Row {
1831 &self.current_row
1832 }
1833
1834 fn take_row(&mut self) -> Row {
1835 std::mem::take(&mut self.current_row)
1838 }
1839
1840 fn ascending_nulls_last_ordering(&self) -> Option<Vec<usize>> {
1841 self.ordering.clone()
1842 }
1843
1844 fn close(&mut self) -> Result<()> {
1845 self.inner.close()
1846 }
1847
1848 fn rows_affected(&self) -> i64 {
1849 0
1850 }
1851
1852 fn last_insert_id(&self) -> i64 {
1853 0
1854 }
1855
1856 fn last_error(&mut self) -> Option<radixdb_core::Error> {
1857 self.pending_error
1858 .take()
1859 .or_else(|| self.inner.last_error())
1860 }
1861
1862 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
1863 Box::new(AliasedResult::new(self, aliases))
1864 }
1865}
1866
1867mod ordering;
1868pub use ordering::{LimitedResult, OrderedResult, RadixOrderSpec, TopNResult};
1869#[cfg(test)]
1870use ordering::{ORDERED_RUN_MAX_BYTES, ORDERED_RUN_MAX_ROWS};
1871
1872pub struct DistinctResult {
1879 inner: Box<dyn QueryResult>,
1881 columns: Vec<String>,
1883 distinct_column_count: usize,
1886 seen: FxHashMap<u64, Vec<Vec<Value>>>,
1889 current_row: Row,
1891 has_current: bool,
1893 budget: RetainedRowsBudget,
1894 terminal_error: Option<radixdb_core::Error>,
1895}
1896
1897impl DistinctResult {
1898 pub fn new(inner: Box<dyn QueryResult>) -> Self {
1900 Self::with_column_count(inner, None)
1901 }
1902
1903 pub fn with_column_count(inner: Box<dyn QueryResult>, distinct_columns: Option<usize>) -> Self {
1910 let columns = inner.columns().to_vec();
1911 let distinct_column_count = distinct_columns.unwrap_or(columns.len());
1912
1913 Self {
1914 inner,
1915 columns,
1916 distinct_column_count,
1917 seen: FxHashMap::default(),
1918 current_row: Row::new(),
1919 has_current: false,
1920 budget: RetainedRowsBudget::new("DISTINCT"),
1921 terminal_error: None,
1922 }
1923 }
1924
1925 fn hash_row(&self, row: &Row) -> u64 {
1927 use std::hash::{Hash, Hasher};
1928 let mut hasher = FxHasher::default();
1929 for value in row.iter().take(self.distinct_column_count) {
1930 value.hash(&mut hasher);
1931 }
1932 hasher.finish()
1933 }
1934
1935 fn extract_distinct_values(&self, row: &Row) -> Vec<Value> {
1937 row.iter()
1938 .take(self.distinct_column_count)
1939 .cloned()
1940 .collect()
1941 }
1942}
1943
1944impl QueryResult for DistinctResult {
1945 fn columns(&self) -> &[String] {
1946 &self.columns
1947 }
1948
1949 fn next(&mut self) -> bool {
1950 while self.inner.next() {
1952 let row = self.inner.row();
1953 let hash = self.hash_row(row);
1954
1955 let values = self.extract_distinct_values(row);
1957
1958 let is_dup = if let Some(seen_rows) = self.seen.get(&hash) {
1960 seen_rows.contains(&values)
1961 } else {
1962 false
1963 };
1964
1965 if !is_dup {
1966 if let Err(error) = self.budget.admit_values(&values) {
1968 self.terminal_error = Some(error);
1969 self.has_current = false;
1970 return false;
1971 }
1972 self.current_row = self.inner.take_row();
1973 self.seen.entry(hash).or_default().push(values);
1974 self.has_current = true;
1975 return true;
1976 }
1977 }
1979
1980 self.has_current = false;
1982 false
1983 }
1984
1985 fn scan(&self, dest: &mut [Value]) -> Result<()> {
1986 if !self.has_current {
1987 return Err(radixdb_core::Error::internal(
1988 "scan() called without successful next()",
1989 ));
1990 }
1991 if dest.len() != self.current_row.len() {
1992 return Err(radixdb_core::Error::internal(format!(
1993 "scan destination has {} values but row has {} columns",
1994 dest.len(),
1995 self.current_row.len()
1996 )));
1997 }
1998 for (i, v) in self.current_row.iter().enumerate() {
1999 dest[i] = v.clone();
2000 }
2001 Ok(())
2002 }
2003
2004 fn row(&self) -> &Row {
2005 &self.current_row
2006 }
2007
2008 fn take_row(&mut self) -> Row {
2009 self.has_current = false;
2010 std::mem::take(&mut self.current_row)
2011 }
2012
2013 fn close(&mut self) -> Result<()> {
2014 self.inner.close()
2015 }
2016
2017 fn rows_affected(&self) -> i64 {
2018 0
2019 }
2020
2021 fn last_insert_id(&self) -> i64 {
2022 0
2023 }
2024
2025 fn last_error(&mut self) -> Option<radixdb_core::Error> {
2026 self.terminal_error
2027 .take()
2028 .or_else(|| self.inner.last_error())
2029 }
2030
2031 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
2032 Box::new(AliasedResult::new(self, aliases))
2033 }
2034}
2035
2036pub struct DistinctOnResult {
2043 inner: Box<dyn QueryResult>,
2044 columns: Vec<String>,
2045 key_indices: Vec<usize>,
2047 seen: FxHashMap<u64, Vec<Vec<Value>>>,
2049 current_row: Row,
2050 has_current: bool,
2051 budget: RetainedRowsBudget,
2052 terminal_error: Option<radixdb_core::Error>,
2053}
2054
2055impl DistinctOnResult {
2056 pub fn new(inner: Box<dyn QueryResult>, key_indices: Vec<usize>) -> Self {
2057 let columns = inner.columns().to_vec();
2058 Self {
2059 inner,
2060 columns,
2061 key_indices,
2062 seen: FxHashMap::default(),
2063 current_row: Row::new(),
2064 has_current: false,
2065 budget: RetainedRowsBudget::new("DISTINCT ON"),
2066 terminal_error: None,
2067 }
2068 }
2069
2070 fn extract_key(&self, row: &Row) -> Vec<Value> {
2071 self.key_indices
2072 .iter()
2073 .map(|&i| row.get(i).cloned().unwrap_or_else(Value::null_unknown))
2074 .collect()
2075 }
2076
2077 fn hash_key(&self, key: &[Value]) -> u64 {
2078 use std::hash::{Hash, Hasher};
2079 let mut hasher = FxHasher::default();
2080 for value in key {
2081 value.hash(&mut hasher);
2082 }
2083 hasher.finish()
2084 }
2085}
2086
2087impl QueryResult for DistinctOnResult {
2088 fn columns(&self) -> &[String] {
2089 &self.columns
2090 }
2091
2092 fn next(&mut self) -> bool {
2093 while self.inner.next() {
2094 let row = self.inner.row();
2095 let key = self.extract_key(row);
2096 let hash = self.hash_key(&key);
2097
2098 let is_dup = if let Some(seen_keys) = self.seen.get(&hash) {
2100 seen_keys.contains(&key)
2101 } else {
2102 false
2103 };
2104
2105 if is_dup {
2106 continue; }
2108
2109 if let Err(error) = self.budget.admit_values(&key) {
2110 self.terminal_error = Some(error);
2111 self.has_current = false;
2112 return false;
2113 }
2114 self.seen.entry(hash).or_default().push(key);
2115 self.current_row = self.inner.take_row();
2116 self.has_current = true;
2117 return true;
2118 }
2119 self.has_current = false;
2120 false
2121 }
2122
2123 fn scan(&self, dest: &mut [Value]) -> Result<()> {
2124 if !self.has_current {
2125 return Err(radixdb_core::Error::internal(
2126 "scan() called without successful next()",
2127 ));
2128 }
2129 if dest.len() != self.current_row.len() {
2130 return Err(radixdb_core::Error::internal(format!(
2131 "scan destination has {} values but row has {} columns",
2132 dest.len(),
2133 self.current_row.len()
2134 )));
2135 }
2136 for (i, v) in self.current_row.iter().enumerate() {
2137 dest[i] = v.clone();
2138 }
2139 Ok(())
2140 }
2141
2142 fn row(&self) -> &Row {
2143 &self.current_row
2144 }
2145
2146 fn take_row(&mut self) -> Row {
2147 self.has_current = false;
2148 std::mem::take(&mut self.current_row)
2149 }
2150
2151 fn close(&mut self) -> Result<()> {
2152 self.seen.clear();
2153 self.inner.close()
2154 }
2155
2156 fn rows_affected(&self) -> i64 {
2157 0
2158 }
2159
2160 fn last_insert_id(&self) -> i64 {
2161 0
2162 }
2163
2164 fn last_error(&mut self) -> Option<radixdb_core::Error> {
2165 self.terminal_error
2166 .take()
2167 .or_else(|| self.inner.last_error())
2168 }
2169
2170 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
2171 Box::new(AliasedResult::new(self, aliases))
2172 }
2173}
2174
2175pub struct ProjectedResult {
2180 inner: Box<dyn QueryResult>,
2181 keep_columns: usize,
2183 projected_columns: Vec<String>,
2185 current_row: Row,
2187}
2188
2189impl ProjectedResult {
2190 pub fn new(inner: Box<dyn QueryResult>, keep_columns: usize) -> Self {
2192 let projected_columns: Vec<String> =
2193 inner.columns().iter().take(keep_columns).cloned().collect();
2194
2195 Self {
2197 inner,
2198 keep_columns,
2199 projected_columns,
2200 current_row: Row::with_capacity(keep_columns),
2201 }
2202 }
2203}
2204
2205impl QueryResult for ProjectedResult {
2206 fn columns(&self) -> &[String] {
2207 &self.projected_columns
2208 }
2209
2210 fn next(&mut self) -> bool {
2211 if self.inner.next() {
2212 self.current_row.reserve_inline(self.keep_columns);
2215 self.current_row.clear_inline();
2216 let full_row = self.inner.row();
2217 for i in 0..self.keep_columns {
2218 self.current_row
2219 .push_inline(full_row.get(i).cloned().unwrap_or(Value::null_unknown()));
2220 }
2221 true
2222 } else {
2223 false
2224 }
2225 }
2226
2227 fn scan(&self, dest: &mut [Value]) -> Result<()> {
2228 for (i, val) in dest.iter_mut().enumerate().take(self.keep_columns) {
2229 *val = self
2230 .current_row
2231 .get(i)
2232 .cloned()
2233 .unwrap_or(Value::null_unknown());
2234 }
2235 Ok(())
2236 }
2237
2238 fn row(&self) -> &Row {
2239 &self.current_row
2240 }
2241
2242 fn take_row(&mut self) -> Row {
2243 std::mem::take(&mut self.current_row)
2244 }
2245
2246 fn close(&mut self) -> Result<()> {
2247 self.inner.close()
2248 }
2249
2250 fn rows_affected(&self) -> i64 {
2251 0
2252 }
2253
2254 fn last_insert_id(&self) -> i64 {
2255 0
2256 }
2257
2258 fn last_error(&mut self) -> Option<radixdb_core::Error> {
2259 self.inner.last_error()
2260 }
2261
2262 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
2263 Box::new(AliasedResult::new(self, aliases))
2264 }
2265}
2266
2267pub struct StreamingProjectionResult {
2272 inner: Box<dyn QueryResult>,
2274 column_indices: Vec<usize>,
2276 output_columns: Vec<String>,
2278 current_row: Row,
2280}
2281
2282impl StreamingProjectionResult {
2283 pub fn new(
2290 inner: Box<dyn QueryResult>,
2291 column_indices: Vec<usize>,
2292 output_columns: Vec<String>,
2293 ) -> Self {
2294 let capacity = column_indices.len();
2296 Self {
2297 inner,
2298 column_indices,
2299 output_columns,
2300 current_row: Row::with_capacity(capacity),
2301 }
2302 }
2303}
2304
2305impl QueryResult for StreamingProjectionResult {
2306 fn columns(&self) -> &[String] {
2307 &self.output_columns
2308 }
2309
2310 fn next(&mut self) -> bool {
2311 if self.inner.next() {
2312 self.current_row.reserve_inline(self.column_indices.len());
2314 self.current_row.clear_inline();
2315 let source_row = self.inner.row();
2316 for &idx in &self.column_indices {
2317 self.current_row.push_inline(
2318 source_row
2319 .get(idx)
2320 .cloned()
2321 .unwrap_or(Value::null_unknown()),
2322 );
2323 }
2324 true
2325 } else {
2326 false
2327 }
2328 }
2329
2330 fn scan(&self, dest: &mut [Value]) -> Result<()> {
2331 if dest.len() != self.current_row.len() {
2332 return Err(radixdb_core::Error::internal(format!(
2333 "scan destination has {} values but row has {} columns",
2334 dest.len(),
2335 self.current_row.len()
2336 )));
2337 }
2338 for (i, value) in self.current_row.iter().enumerate() {
2339 dest[i] = value.clone();
2340 }
2341 Ok(())
2342 }
2343
2344 fn row(&self) -> &Row {
2345 &self.current_row
2346 }
2347
2348 fn take_row(&mut self) -> Row {
2349 std::mem::take(&mut self.current_row)
2350 }
2351
2352 fn close(&mut self) -> Result<()> {
2353 self.inner.close()
2354 }
2355
2356 fn rows_affected(&self) -> i64 {
2357 0
2358 }
2359
2360 fn last_insert_id(&self) -> i64 {
2361 0
2362 }
2363
2364 fn last_error(&mut self) -> Option<radixdb_core::Error> {
2365 self.inner.last_error()
2366 }
2367
2368 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
2369 Box::new(AliasedResult::new(self, aliases))
2370 }
2371}
2372
2373pub struct ColumnarResult {
2387 columns: CompactArc<Vec<String>>,
2389 data: Vec<Vec<Value>>,
2391 num_rows: usize,
2393 current_index: Option<usize>,
2395 current_row: Row,
2397 closed: bool,
2399}
2400
2401impl ColumnarResult {
2402 pub fn new(columns: Vec<String>, data: Vec<Vec<Value>>) -> Self {
2411 debug_assert!(
2412 columns.len() == data.len(),
2413 "columns.len() ({}) != data.len() ({})",
2414 columns.len(),
2415 data.len()
2416 );
2417
2418 let num_rows = data.first().map(|c| c.len()).unwrap_or(0);
2419
2420 #[cfg(debug_assertions)]
2422 for (i, col) in data.iter().enumerate() {
2423 debug_assert!(
2424 col.len() == num_rows,
2425 "column {} has {} rows but expected {}",
2426 i,
2427 col.len(),
2428 num_rows
2429 );
2430 }
2431
2432 let num_cols = columns.len();
2434
2435 Self {
2436 columns: CompactArc::new(columns),
2437 data,
2438 num_rows,
2439 current_index: None,
2440 current_row: Row::with_capacity(num_cols),
2441 closed: false,
2442 }
2443 }
2444
2445 pub fn with_arc_columns(columns: CompactArc<Vec<String>>, data: Vec<Vec<Value>>) -> Self {
2447 let num_rows = data.first().map(|c| c.len()).unwrap_or(0);
2448 let num_cols = columns.len();
2449
2450 Self {
2451 columns,
2452 data,
2453 num_rows,
2454 current_index: None,
2455 current_row: Row::with_capacity(num_cols),
2456 closed: false,
2457 }
2458 }
2459
2460 #[inline]
2462 pub fn row_count(&self) -> usize {
2463 self.num_rows
2464 }
2465
2466 #[inline]
2468 pub fn column_count(&self) -> usize {
2469 self.data.len()
2470 }
2471}
2472
2473impl QueryResult for ColumnarResult {
2474 fn columns(&self) -> &[String] {
2475 &self.columns
2476 }
2477
2478 fn columns_arc(&self) -> Option<CompactArc<Vec<String>>> {
2479 Some(CompactArc::clone(&self.columns))
2480 }
2481
2482 #[inline]
2483 fn next(&mut self) -> bool {
2484 if self.closed {
2485 return false;
2486 }
2487
2488 let next_idx = match self.current_index {
2489 None => 0,
2490 Some(i) => i + 1,
2491 };
2492
2493 if next_idx >= self.num_rows {
2494 return false;
2495 }
2496
2497 self.current_index = Some(next_idx);
2498
2499 self.current_row.reserve_inline(self.data.len());
2501 self.current_row.clear_inline();
2503 for col_data in &self.data {
2504 self.current_row.push_inline(col_data[next_idx].clone());
2506 }
2507
2508 true
2509 }
2510
2511 fn scan(&self, dest: &mut [Value]) -> Result<()> {
2512 if dest.len() != self.current_row.len() {
2513 return Err(radixdb_core::Error::internal(format!(
2514 "scan destination has {} values but row has {} columns",
2515 dest.len(),
2516 self.current_row.len()
2517 )));
2518 }
2519 for (i, value) in self.current_row.iter().enumerate() {
2520 dest[i] = value.clone();
2521 }
2522 Ok(())
2523 }
2524
2525 #[inline]
2526 fn row(&self) -> &Row {
2527 &self.current_row
2528 }
2529
2530 fn take_row(&mut self) -> Row {
2531 std::mem::take(&mut self.current_row)
2534 }
2535
2536 fn close(&mut self) -> Result<()> {
2537 self.closed = true;
2538 self.data.clear();
2540 Ok(())
2541 }
2542
2543 fn rows_affected(&self) -> i64 {
2544 0
2545 }
2546
2547 fn last_insert_id(&self) -> i64 {
2548 0
2549 }
2550
2551 fn estimated_count(&self) -> Option<usize> {
2552 Some(self.num_rows)
2553 }
2554
2555 fn with_aliases(self: Box<Self>, aliases: FxHashMap<String, String>) -> Box<dyn QueryResult> {
2556 Box::new(AliasedResult::new(self, aliases))
2557 }
2558}
2559
2560#[cfg(test)]
2561mod tests;