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