• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gluesql / gluesql / 26679091029

30 May 2026 08:20AM UTC coverage: 98.131% (-0.002%) from 98.133%
26679091029

push

github

web-flow
Introduce statement execution plans (#1900)

Introduces StatementPlan as the execution-facing representation and starts separating execution metadata from AST.

The main boundary this PR establishes is:

AST represents parsed SQL syntax and storage-facing definitions.
StatementPlan represents the structure consumed by planning and execution.
ast_builder remains a fluent query builder, but its primary build() output is now StatementPlan.
Builder nodes may temporarily hold plan-only metadata, such as hash join executor selection and index selection, but that metadata is emitted only into plan types and is rejected when constructing AST.
The scope is intentionally conservative. This PR keeps most plan structs close to the existing AST shape so the transition stays reviewable. Deeper plan redesigns, such as pipeline/operator nodes, table scan access paths, and projection expansion, are left for follow-up work.

3525 of 3553 new or added lines in 104 files covered. (99.21%)

21 existing lines in 5 files now uncovered.

44368 of 45213 relevant lines covered (98.13%)

75547.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/python/src/lib.rs
1
#![cfg(feature = "include-python-workspace")]
2

3
use {
4
    error::GlueSQLError,
5
    gluesql_core::{
6
        plan::StatementPlan,
7
        prelude::{Payload, execute, parse},
8
        store::Planner,
9
        translate::translate,
10
    },
11
    payload::{PyPayload, convert},
12
    pyo3::{prelude::*, types::PyString},
13
    storages::{
14
        PyJsonStorage, PyMemoryStorage, PySharedMemoryStorage, PySledStorage, PySledStorageConfig,
15
        PySledStorageModeConfig, PyStorageEngine,
16
    },
17
};
18

19
mod error;
20
mod payload;
21
mod storages;
22

23
#[pyclass(name = "Glue")]
24
pub struct PyGlue {
25
    pub storage: PyStorageEngine,
26
}
27

28
macro_rules! plan {
29
    ($storage:expr, $statement:expr) => {{
30
        $storage
31
            .0
32
            .plan($statement)
33
            .await
34
            .map_err(|e| GlueSQLError::new_err(e.to_string()))
×
35
    }};
36
}
37

38
macro_rules! execute {
39
    ($storage:expr, $statement:expr) => {{
40
        execute(&mut $storage.0, $statement)
41
            .await
42
            .map_err(|e| GlueSQLError::new_err(e.to_string()))
×
43
    }};
44
}
45

46
impl PyGlue {
47
    #[tokio::main]
NEW
48
    pub async fn plan(&self, statement: StatementPlan) -> PyResult<StatementPlan> {
×
49
        let storage = &self.storage;
×
50

51
        match storage {
×
52
            PyStorageEngine::Memory(storage) => plan!(storage, statement),
×
53
            PyStorageEngine::Json(storage) => plan!(storage, statement),
×
54
            PyStorageEngine::SharedMemory(storage) => plan!(storage, statement),
×
55
            PyStorageEngine::Sled(storage) => plan!(storage, statement),
×
56
        }
×
57
    }
×
58

59
    #[tokio::main]
NEW
60
    pub async fn execute(&mut self, statement: StatementPlan) -> PyResult<Payload> {
×
61
        let storage = &mut self.storage;
×
62

63
        match storage {
×
64
            PyStorageEngine::Memory(storage) => execute!(storage, &statement),
×
65
            PyStorageEngine::Json(storage) => execute!(storage, &statement),
×
66
            PyStorageEngine::SharedMemory(storage) => execute!(storage, &statement),
×
67
            PyStorageEngine::Sled(storage) => execute!(storage, &statement),
×
68
        }
×
69
    }
×
70
}
71

72
#[pymethods]
73
impl PyGlue {
74
    #[new]
75
    pub fn new(storage: PyStorageEngine) -> Self {
×
76
        PyGlue { storage }
×
77
    }
×
78

79
    pub fn query(&mut self, py: Python, sql: &PyString) -> PyResult<PyObject> {
×
80
        let sql = sql.to_string();
×
81
        let queries = parse(sql).map_err(|e| GlueSQLError::new_err(e.to_string()))?;
×
82

83
        let mut payloads: Vec<PyPayload> = vec![];
×
84
        for query in queries.iter() {
×
85
            let statement = translate(query).map_err(|e| GlueSQLError::new_err(e.to_string()))?;
×
NEW
86
            let statement = statement.into();
×
UNCOV
87
            let statement = self.plan(statement)?;
×
88

89
            let payload = self.execute(statement)?;
×
90

91
            payloads.push(PyPayload { payload });
×
92
        }
93

94
        Ok(convert(py, payloads))
×
95
    }
×
96
}
97

98
#[pymodule]
99
fn gluesql(py: Python, m: &PyModule) -> PyResult<()> {
×
100
    m.add_class::<PyGlue>()?;
×
101
    m.add_class::<PyMemoryStorage>()?;
×
102
    m.add_class::<PyJsonStorage>()?;
×
103
    m.add_class::<PySharedMemoryStorage>()?;
×
104
    m.add_class::<PySledStorage>()?;
×
105
    m.add_class::<PySledStorageConfig>()?;
×
106
    m.add_class::<PySledStorageModeConfig>()?;
×
107

108
    m.add("GlueSQLError", py.get_type::<GlueSQLError>())?;
×
109
    Ok(())
×
110
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc