proof_of_sql/sql/proof_plans/
empty_exec.rs

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