proof_of_sql/sql/proof_plans/
empty_exec.rs

1use crate::{
2    base::{
3        database::{
4            ColumnField, ColumnRef, OwnedTable, Table, TableEvaluation, TableOptions, TableRef,
5        },
6        map::{IndexMap, IndexSet},
7        proof::ProofError,
8        scalar::Scalar,
9    },
10    sql::proof::{
11        FinalRoundBuilder, FirstRoundBuilder, ProofPlan, ProverEvaluate, VerificationBuilder,
12    },
13    utils::log,
14};
15use alloc::vec::Vec;
16use bumpalo::Bump;
17use serde::{Deserialize, Serialize};
18
19/// Source [`ProofPlan`] for (sub)queries without table source such as `SELECT "No table here" as msg;`
20/// Inspired by [`DataFusion EmptyExec`](https://docs.rs/datafusion/latest/datafusion/physical_plan/empty/struct.EmptyExec.html)
21#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
22pub struct EmptyExec {}
23
24impl Default for EmptyExec {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl EmptyExec {
31    /// Creates a new empty plan.
32    #[must_use]
33    pub fn new() -> Self {
34        Self {}
35    }
36}
37
38impl ProofPlan for EmptyExec {
39    fn verifier_evaluate<S: Scalar>(
40        &self,
41        builder: &mut impl VerificationBuilder<S>,
42        _accessor: &IndexMap<ColumnRef, S>,
43        _result: Option<&OwnedTable<S>>,
44        _chi_eval_map: &IndexMap<TableRef, S>,
45    ) -> Result<TableEvaluation<S>, ProofError> {
46        Ok(TableEvaluation::new(
47            Vec::<S>::new(),
48            builder.singleton_chi_evaluation(),
49        ))
50    }
51
52    fn get_column_result_fields(&self) -> Vec<ColumnField> {
53        Vec::new()
54    }
55
56    fn get_column_references(&self) -> IndexSet<ColumnRef> {
57        IndexSet::default()
58    }
59
60    fn get_table_references(&self) -> IndexSet<TableRef> {
61        IndexSet::default()
62    }
63}
64
65impl ProverEvaluate for EmptyExec {
66    #[tracing::instrument(name = "EmptyExec::first_round_evaluate", level = "debug", skip_all)]
67    fn first_round_evaluate<'a, S: Scalar>(
68        &self,
69        _builder: &mut FirstRoundBuilder<'a, S>,
70        _alloc: &'a Bump,
71        _table_map: &IndexMap<TableRef, Table<'a, S>>,
72    ) -> Table<'a, S> {
73        log::log_memory_usage("Start");
74
75        // Create an empty table with one row
76        let res =
77            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
78                .unwrap();
79
80        log::log_memory_usage("End");
81
82        res
83    }
84
85    #[tracing::instrument(name = "EmptyExec::final_round_evaluate", level = "debug", skip_all)]
86    fn final_round_evaluate<'a, S: Scalar>(
87        &self,
88        _builder: &mut FinalRoundBuilder<'a, S>,
89        _alloc: &'a Bump,
90        _table_map: &IndexMap<TableRef, Table<'a, S>>,
91    ) -> Table<'a, S> {
92        log::log_memory_usage("Start");
93
94        // Create an empty table with one row
95        let res =
96            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
97                .unwrap();
98
99        log::log_memory_usage("End");
100
101        res
102    }
103}