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(InsertPlan {
14            collection: p.collection,
15            engine: EngineType::Columnar,
16            route: WriteRoute::ColumnarFamily,
17            rows: p.rows,
18            volatile_defaults: p.volatile_defaults,
19            if_absent: p.if_absent,
20            column_schema: p.column_schema,
21            primary_key: p.primary_key,
22        })])
23    }
24
25    /// `UPSERT` / `INSERT ... ON CONFLICT (pk) DO UPDATE` on columnar.
26    /// Duplicate PK tombstones the prior row via the segment's delete
27    /// bitmap; the new row (or its merged form, when `on_conflict_updates`
28    /// is non-empty) is appended. Sort-key semantics are unchanged.
29    fn plan_insert_select(&self, p: InsertSelectParams) -> Result<Vec<SqlPlan>> {
30        Err(SqlError::Unsupported {
31            detail: format!(
32                "INSERT ... SELECT into columnar collection '{}' is not supported; \
33                 the target must be a document collection",
34                p.collection
35            ),
36        })
37    }
38
39    fn plan_upsert(&self, p: UpsertParams) -> Result<Vec<SqlPlan>> {
40        Ok(vec![SqlPlan::Upsert(UpsertPlan {
41            collection: p.collection,
42            engine: EngineType::Columnar,
43            route: WriteRoute::ColumnarFamily,
44            rows: p.rows,
45            volatile_defaults: p.volatile_defaults,
46            on_conflict_updates: p.on_conflict_updates,
47            column_schema: p.column_schema,
48            primary_key: p.primary_key,
49        })])
50    }
51
52    fn plan_scan(&self, p: ScanParams) -> Result<SqlPlan> {
53        if p.temporal.is_temporal() && !p.bitemporal {
54            return Err(SqlError::Unsupported {
55                detail: format!(
56                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
57                     collection; '{}' was not created WITH bitemporal = true",
58                    p.collection
59                ),
60            });
61        }
62        Ok(SqlPlan::Scan {
63            collection: p.collection,
64            alias: p.alias,
65            engine: EngineType::Columnar,
66            filters: p.filters,
67            projection: p.projection,
68            sort_keys: p.sort_keys,
69            limit: p.limit,
70            offset: p.offset,
71            distinct: p.distinct,
72            window_functions: p.window_functions,
73            temporal: p.temporal,
74        })
75    }
76
77    fn plan_point_get(&self, p: PointGetParams) -> Result<SqlPlan> {
78        Ok(SqlPlan::PointGet {
79            collection: p.collection,
80            alias: p.alias,
81            engine: EngineType::Columnar,
82            key_column: p.key_column,
83            key_value: p.key_value,
84            projection: p.projection,
85        })
86    }
87
88    fn plan_update(&self, p: UpdateParams) -> Result<Vec<SqlPlan>> {
89        Ok(vec![SqlPlan::Update {
90            collection: p.collection,
91            engine: EngineType::Columnar,
92            assignments: p.assignments,
93            filters: p.filters,
94            target_keys: p.target_keys,
95            returning: p.returning,
96        }])
97    }
98
99    /// `UPDATE ... FROM` writes through the document join-update, which
100    /// columnar storage does not take.
101    fn plan_update_from(&self, p: UpdateFromParams) -> Result<Vec<SqlPlan>> {
102        Err(SqlError::Unsupported {
103            detail: format!(
104                "UPDATE ... FROM is not supported on columnar collection '{}'; \
105                 the target must be a document collection",
106                p.collection
107            ),
108        })
109    }
110
111    fn plan_delete(&self, p: DeleteParams) -> Result<Vec<SqlPlan>> {
112        Ok(vec![SqlPlan::Delete {
113            collection: p.collection,
114            engine: EngineType::Columnar,
115            filters: p.filters,
116            target_keys: p.target_keys,
117        }])
118    }
119
120    fn plan_truncate(&self, p: TruncateParams) -> Result<Vec<SqlPlan>> {
121        Ok(vec![SqlPlan::Truncate {
122            collection: p.collection,
123            engine: EngineType::Columnar,
124            restart_identity: p.restart_identity,
125        }])
126    }
127
128    fn plan_aggregate(&self, p: AggregateParams) -> Result<SqlPlan> {
129        if p.temporal.is_temporal() && !p.bitemporal {
130            return Err(SqlError::Unsupported {
131                detail: format!(
132                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
133                     collection; '{}' was not created WITH bitemporal = true",
134                    p.collection
135                ),
136            });
137        }
138        let base_scan = SqlPlan::Scan {
139            collection: p.collection,
140            alias: p.alias,
141            engine: EngineType::Columnar,
142            filters: p.filters,
143            projection: Vec::new(),
144            sort_keys: Vec::new(),
145            limit: None,
146            offset: 0,
147            distinct: false,
148            window_functions: Vec::new(),
149            temporal: p.temporal,
150        };
151        Ok(SqlPlan::Aggregate {
152            input: Box::new(base_scan),
153            group_by: p.group_by,
154            group_by_aliases: Vec::new(),
155            output_order: Vec::new(),
156            aggregates: p.aggregates,
157            having: p.having,
158            limit: p.limit,
159            grouping_sets: p.grouping_sets,
160            sort_keys: Vec::new(),
161        })
162    }
163
164    fn plan_merge(&self, p: MergeParams) -> Result<Vec<SqlPlan>> {
165        Err(SqlError::Unsupported {
166            detail: format!(
167                "MERGE is not supported on columnar collection '{}'",
168                p.collection
169            ),
170        })
171    }
172
173    /// Every column is declared at creation and encoded per column.
174    fn accepts_undeclared_columns(&self) -> bool {
175        false
176    }
177}