proof_of_sql/sql/proof_plans/
empty_exec.rs

1use crate::{
2    base::{
3        database::{
4            ColumnField, ColumnRef, LiteralValue, Table, TableEvaluation, TableOptions, TableRef,
5        },
6        map::{IndexMap, IndexSet},
7        proof::{PlaceholderResult, 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};
18use sqlparser::ast::Ident;
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<TableRef, IndexMap<Ident, S>>,
44        _chi_eval_map: &IndexMap<TableRef, (S, usize)>,
45        _params: &[LiteralValue],
46    ) -> Result<TableEvaluation<S>, ProofError> {
47        Ok(TableEvaluation::new(
48            Vec::<S>::new(),
49            (builder.singleton_chi_evaluation(), 1),
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        _params: &[LiteralValue],
74    ) -> PlaceholderResult<Table<'a, S>> {
75        log::log_memory_usage("Start");
76
77        // Create an empty table with one row
78        let res =
79            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
80                .unwrap();
81
82        log::log_memory_usage("End");
83
84        Ok(res)
85    }
86
87    #[tracing::instrument(name = "EmptyExec::final_round_evaluate", level = "debug", skip_all)]
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        _params: &[LiteralValue],
94    ) -> PlaceholderResult<Table<'a, S>> {
95        log::log_memory_usage("Start");
96
97        // Create an empty table with one row
98        let res =
99            Table::<'a, S>::try_new_with_options(IndexMap::default(), TableOptions::new(Some(1)))
100                .unwrap();
101
102        log::log_memory_usage("End");
103
104        Ok(res)
105    }
106}