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    #[allow(unused_variables)]
40    fn verifier_evaluate<S: Scalar>(
41        &self,
42        builder: &mut impl VerificationBuilder<S>,
43        _accessor: &IndexMap<ColumnRef, S>,
44        _result: Option<&OwnedTable<S>>,
45        _chi_eval_map: &IndexMap<TableRef, S>,
46    ) -> Result<TableEvaluation<S>, ProofError> {
47        Ok(TableEvaluation::new(
48            Vec::<S>::new(),
49            builder.singleton_chi_evaluation(),
50        ))
51    }
52
53    fn get_column_result_fields(&self) -> Vec<ColumnField> {
54        Vec::new()
55    }
56
57    fn get_column_references(&self) -> IndexSet<ColumnRef> {
58        IndexSet::default()
59    }
60
61    fn get_table_references(&self) -> IndexSet<TableRef> {
62        IndexSet::default()
63    }
64}
65
66impl ProverEvaluate for EmptyExec {
67    #[tracing::instrument(name = "EmptyExec::first_round_evaluate", level = "debug", skip_all)]
68    fn first_round_evaluate<'a, S: Scalar>(
69        &self,
70        _builder: &mut FirstRoundBuilder<'a, S>,
71        _alloc: &'a Bump,
72        _table_map: &IndexMap<TableRef, Table<'a, S>>,
73    ) -> Table<'a, S> {
74        log::log_memory_usage("Start");
75
76        // Create an empty table with one row
77        let res =
78            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
79                .unwrap();
80
81        log::log_memory_usage("End");
82
83        res
84    }
85
86    #[tracing::instrument(name = "EmptyExec::final_round_evaluate", level = "debug", skip_all)]
87    #[allow(unused_variables)]
88    fn final_round_evaluate<'a, S: Scalar>(
89        &self,
90        _builder: &mut FinalRoundBuilder<'a, S>,
91        _alloc: &'a Bump,
92        _table_map: &IndexMap<TableRef, Table<'a, S>>,
93    ) -> Table<'a, S> {
94        log::log_memory_usage("Start");
95
96        // Create an empty table with one row
97        let res =
98            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
99                .unwrap();
100
101        log::log_memory_usage("End");
102
103        res
104    }
105}