1use crate::types::{TxId, VectorIndexRef};
2
3#[derive(Debug, thiserror::Error)]
4pub enum Error {
5 #[error("table not found: {0}")]
6 TableNotFound(String),
7 #[error("{0} are immutable")]
8 ImmutableTable(String),
9 #[error("column `{column}` on table `{table}` is immutable")]
10 ImmutableColumn { table: String, column: String },
11 #[error("invalid state transition: {0}")]
12 InvalidStateTransition(String),
13 #[error("propagation aborted: {table}.{column} transition {from} -> {to} is invalid")]
14 PropagationAborted {
15 table: String,
16 column: String,
17 from: String,
18 to: String,
19 },
20 #[error("BFS depth exceeds maximum allowed ({0})")]
21 BfsDepthExceeded(u32),
22 #[error("BFS visited set exceeded limit ({0})")]
23 BfsVisitedExceeded(usize),
24 #[error("vector index dimension mismatch on {index:?}: expected {expected}, got {actual}")]
25 VectorIndexDimensionMismatch {
26 index: VectorIndexRef,
27 expected: usize,
28 actual: usize,
29 },
30 #[error("unknown vector index {index:?}")]
31 UnknownVectorIndex { index: VectorIndexRef },
32 #[error("rank policy on index `{index}` references unknown column `{column}`")]
33 RankPolicyColumnUnknown { index: String, column: String },
34 #[error(
35 "rank policy on index `{index}` references ambiguous column `{column}` (present on both anchor and joined table); rename one of the columns -- the rank-formula grammar does not support table-qualified column references"
36 )]
37 RankPolicyColumnAmbiguous { index: String, column: String },
38 #[error(
39 "rank policy on index `{index}` references column `{column}` of type {actual}; expected {expected}"
40 )]
41 RankPolicyColumnType {
42 index: String,
43 column: String,
44 expected: String,
45 actual: String,
46 },
47 #[error("rank policy on index `{index}` joins unknown table `{table}`")]
48 RankPolicyJoinTableUnknown { index: String, table: String },
49 #[error(
50 "rank policy on index `{index}` joins column `{column}` not present on table `{table}`"
51 )]
52 RankPolicyJoinColumnUnknown {
53 index: String,
54 table: String,
55 column: String,
56 },
57 #[error(
58 "rank policy on index `{index}` joins column `{joined_table}.{column}` which has no index; add: CREATE INDEX {joined_table}_{column}_idx ON {joined_table}({column});"
59 )]
60 RankPolicyJoinColumnUnindexed {
61 index: String,
62 joined_table: String,
63 column: String,
64 },
65 #[error("rank policy sort key `{sort_key}` not found on index `{index}`")]
66 RankPolicyNotFound { index: String, sort_key: String },
67 #[error(
68 "rank policy formula on index `{index}` failed to parse at position {position}: {reason}"
69 )]
70 RankPolicyFormulaParse {
71 index: String,
72 position: usize,
73 reason: String,
74 },
75 #[error("USE RANK requires ORDER BY embedding <=> $param in the same query")]
76 UseRankRequiresVectorOrder,
77 #[error("USE RANK requires LIMIT in the same query")]
78 UseRankRequiresLimit,
79 #[error(
80 "{}",
81 drop_blocked_rank_policy_display(
82 table,
83 column,
84 dropped_index,
85 policy_table,
86 policy_column,
87 sort_key
88 )
89 )]
90 DropBlockedByRankPolicy {
91 table: Box<str>,
92 column: Option<Box<str>>,
93 dropped_index: Option<Box<str>>,
94 policy_table: Box<str>,
95 policy_column: Box<str>,
96 sort_key: Box<str>,
97 },
98 #[error(
99 "legacy vector store detected (format marker {found_format_marker:?}); rebuild required for release {expected_release} - sync from a 1.0+ peer or recreate the schema and reimport"
100 )]
101 LegacyVectorStoreDetected {
102 found_format_marker: String,
103 expected_release: String,
104 },
105 #[error("corrupt vector store at {path}: {reason}")]
106 StoreCorrupted { path: String, reason: String },
107 #[error("not found: {0}")]
108 NotFound(String),
109 #[error("transaction not found: {0}")]
110 TxNotFound(TxId),
111 #[error("unique constraint violation: {table}.{column}")]
112 UniqueViolation { table: String, column: String },
113 #[error("foreign key violation: {table}.{column} references {ref_table}")]
114 ForeignKeyViolation {
115 table: String,
116 column: String,
117 ref_table: String,
118 },
119 #[error("recursive CTEs are not supported")]
120 RecursiveCteNotSupported,
121 #[error("window functions are not supported")]
122 WindowFunctionNotSupported,
123 #[error("stored procedures/functions are not supported")]
124 StoredProcNotSupported,
125 #[error("graph traversal requires explicit depth bound")]
126 UnboundedTraversal,
127 #[error("vector search requires LIMIT clause")]
128 UnboundedVectorSearch,
129 #[error("subqueries not supported; use CTE chaining")]
130 SubqueryNotSupported,
131 #[error("full-text search (WHERE column MATCH) is not supported")]
132 FullTextSearchNotSupported,
133 #[error("parse error: {0}")]
134 ParseError(String),
135 #[error("plan error: {0}")]
136 PlanError(String),
137 #[error("sync error: {0}")]
138 SyncError(String),
139 #[error("table {0} is not sync-eligible (no natural key)")]
140 NotSyncEligible(String),
141 #[error(
142 "cycle detected: inserting {edge_type} edge from {source_node} to {target_node} would create a cycle"
143 )]
144 CycleDetected {
145 edge_type: String,
146 source_node: uuid::Uuid,
147 target_node: uuid::Uuid,
148 },
149 #[error("plugin rejected at {hook}: {reason}")]
150 PluginRejected { hook: String, reason: String },
151 #[error(
152 "memory budget exceeded: {subsystem}/{operation} requested {requested_bytes} bytes, {available_bytes} available of {budget_limit_bytes} budget. Hint: {hint}"
153 )]
154 MemoryBudgetExceeded {
155 subsystem: String,
156 operation: String,
157 requested_bytes: usize,
158 available_bytes: usize,
159 budget_limit_bytes: usize,
160 hint: String,
161 },
162 #[error(
163 "disk budget exceeded: {operation} - file is {current_bytes} bytes, limit is {budget_limit_bytes} bytes. Hint: {hint}"
164 )]
165 DiskBudgetExceeded {
166 operation: String,
167 current_bytes: u64,
168 budget_limit_bytes: u64,
169 hint: String,
170 },
171 #[error("column type mismatch: {table}.{column} expected {expected}, got {actual}")]
172 ColumnTypeMismatch {
173 table: String,
174 column: String,
175 expected: &'static str,
176 actual: &'static str,
177 },
178 #[error("tx id out of range: {table}.{column} value {value} exceeds max {max}")]
179 TxIdOutOfRange {
180 table: String,
181 column: String,
182 value: u64,
183 max: u64,
184 },
185 #[error("tx id overflow: {table} incoming {incoming}")]
186 TxIdOverflow { table: String, incoming: u64 },
187 #[error("column {table}.{column} is NOT NULL")]
188 ColumnNotNullable { table: String, column: String },
189 #[error("index not found: {table}.{index}")]
190 IndexNotFound { table: String, index: String },
191 #[error("duplicate index: {table}.{index}")]
192 DuplicateIndex { table: String, index: String },
193 #[error("reserved index name: {table}.{name} uses reserved prefix `{prefix}`")]
194 ReservedIndexName {
195 table: String,
196 name: String,
197 prefix: String,
198 },
199 #[error("column not indexable: {table}.{column} has type {column_type:?}")]
200 ColumnNotIndexable {
201 table: String,
202 column: String,
203 column_type: crate::table_meta::ColumnType,
204 },
205 #[error("column in index: {table}.{column} referenced by index {index}")]
206 ColumnInIndex {
207 table: String,
208 column: String,
209 index: String,
210 },
211 #[error("column not found: {table}.{column}")]
212 ColumnNotFound { table: String, column: String },
213 #[error("{0}")]
214 Other(String),
215}
216
217fn drop_blocked_rank_policy_display(
218 table: &str,
219 column: &Option<Box<str>>,
220 dropped_index: &Option<Box<str>>,
221 policy_table: &str,
222 policy_column: &str,
223 sort_key: &str,
224) -> String {
225 if let Some(column) = column {
226 return format!(
227 "cannot drop or rename column `{table}.{column}`: rank policy `{sort_key}` on `{policy_table}.{policy_column}` depends on it"
228 );
229 }
230 if let Some(index) = dropped_index {
231 return format!(
232 "cannot drop index `{index}` on `{table}`: rank policy `{sort_key}` on `{policy_table}.{policy_column}` depends on it"
233 );
234 }
235 format!(
236 "cannot drop table `{table}`: rank policy `{sort_key}` on `{policy_table}.{policy_column}` depends on it"
237 )
238}
239
240pub type Result<T> = std::result::Result<T, Error>;