Skip to main content

nodedb_sql/engine_rules/
columnar.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Engine rules for plain columnar collections.
4
5use crate::engine_rules::*;
6use crate::error::{Result, SqlError};
7use crate::types::*;
8
9pub struct ColumnarRules;
10
11impl EngineRules for ColumnarRules {
12    fn plan_insert(&self, p: InsertParams) -> Result<Vec<SqlPlan>> {
13        Ok(vec![SqlPlan::Insert {
14            collection: p.collection,
15            engine: EngineType::Columnar,
16            rows: p.rows,
17            column_defaults: p.column_defaults,
18            if_absent: p.if_absent,
19            column_schema: p.column_schema,
20        }])
21    }
22
23    /// `UPSERT` / `INSERT ... ON CONFLICT (pk) DO UPDATE` on columnar.
24    /// Duplicate PK tombstones the prior row via the segment's delete
25    /// bitmap; the new row (or its merged form, when `on_conflict_updates`
26    /// is non-empty) is appended. Sort-key semantics are unchanged.
27    fn plan_upsert(&self, p: UpsertParams) -> Result<Vec<SqlPlan>> {
28        Ok(vec![SqlPlan::Upsert {
29            collection: p.collection,
30            engine: EngineType::Columnar,
31            rows: p.rows,
32            column_defaults: p.column_defaults,
33            on_conflict_updates: p.on_conflict_updates,
34            column_schema: p.column_schema,
35        }])
36    }
37
38    fn plan_scan(&self, p: ScanParams) -> Result<SqlPlan> {
39        if p.temporal.is_temporal() && !p.bitemporal {
40            return Err(SqlError::Unsupported {
41                detail: format!(
42                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
43                     collection; '{}' was not created WITH bitemporal = true",
44                    p.collection
45                ),
46            });
47        }
48        Ok(SqlPlan::Scan {
49            collection: p.collection,
50            alias: p.alias,
51            engine: EngineType::Columnar,
52            filters: p.filters,
53            projection: p.projection,
54            sort_keys: p.sort_keys,
55            limit: p.limit,
56            offset: p.offset,
57            distinct: p.distinct,
58            window_functions: p.window_functions,
59            temporal: p.temporal,
60        })
61    }
62
63    fn plan_point_get(&self, p: PointGetParams) -> Result<SqlPlan> {
64        Ok(SqlPlan::PointGet {
65            collection: p.collection,
66            alias: p.alias,
67            engine: EngineType::Columnar,
68            key_column: p.key_column,
69            key_value: p.key_value,
70        })
71    }
72
73    fn plan_update(&self, p: UpdateParams) -> Result<Vec<SqlPlan>> {
74        Ok(vec![SqlPlan::Update {
75            collection: p.collection,
76            engine: EngineType::Columnar,
77            assignments: p.assignments,
78            filters: p.filters,
79            target_keys: p.target_keys,
80            returning: p.returning,
81        }])
82    }
83
84    fn plan_update_from(&self, p: UpdateFromParams) -> Result<Vec<SqlPlan>> {
85        Ok(vec![SqlPlan::UpdateFrom {
86            collection: p.collection,
87            engine: EngineType::Columnar,
88            source: p.source,
89            target_join_col: p.target_join_col,
90            source_join_col: p.source_join_col,
91            assignments: p.assignments,
92            target_filters: p.target_filters,
93            returning: p.returning,
94        }])
95    }
96
97    fn plan_delete(&self, p: DeleteParams) -> Result<Vec<SqlPlan>> {
98        Ok(vec![SqlPlan::Delete {
99            collection: p.collection,
100            engine: EngineType::Columnar,
101            filters: p.filters,
102            target_keys: p.target_keys,
103        }])
104    }
105
106    fn plan_aggregate(&self, p: AggregateParams) -> Result<SqlPlan> {
107        if p.temporal.is_temporal() && !p.bitemporal {
108            return Err(SqlError::Unsupported {
109                detail: format!(
110                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
111                     collection; '{}' was not created WITH bitemporal = true",
112                    p.collection
113                ),
114            });
115        }
116        let base_scan = SqlPlan::Scan {
117            collection: p.collection,
118            alias: p.alias,
119            engine: EngineType::Columnar,
120            filters: p.filters,
121            projection: Vec::new(),
122            sort_keys: Vec::new(),
123            limit: None,
124            offset: 0,
125            distinct: false,
126            window_functions: Vec::new(),
127            temporal: p.temporal,
128        };
129        Ok(SqlPlan::Aggregate {
130            input: Box::new(base_scan),
131            group_by: p.group_by,
132            aggregates: p.aggregates,
133            having: p.having,
134            limit: p.limit,
135            grouping_sets: None,
136            sort_keys: Vec::new(),
137        })
138    }
139
140    fn plan_merge(&self, p: MergeParams) -> Result<Vec<SqlPlan>> {
141        Err(SqlError::Unsupported {
142            detail: format!(
143                "MERGE is not supported on columnar collection '{}'",
144                p.collection
145            ),
146        })
147    }
148}