kimberlite_query/error.rs
1//! Error types for query operations.
2
3use kimberlite_store::StoreError;
4
5use crate::value::Value;
6
7/// Errors that can occur during query parsing and execution.
8#[derive(thiserror::Error, Debug)]
9pub enum QueryError {
10 /// SQL syntax or parsing error.
11 #[error("parse error: {0}")]
12 ParseError(String),
13
14 /// Table not found in schema.
15 #[error("table '{0}' not found")]
16 TableNotFound(String),
17
18 /// Column not found in table.
19 #[error("column '{column}' not found in table '{table}'")]
20 ColumnNotFound { table: String, column: String },
21
22 /// Query parameter not provided.
23 #[error("parameter ${0} not provided")]
24 ParameterNotFound(usize),
25
26 /// Type mismatch between expected and actual value.
27 #[error("type mismatch: expected {expected}, got {actual}")]
28 TypeMismatch { expected: String, actual: String },
29
30 /// SQL feature not supported.
31 #[error("unsupported feature: {0}")]
32 UnsupportedFeature(String),
33
34 /// SQL input exceeds a complexity limit (depth or token budget).
35 /// Pre-parse guard that rejects pathological inputs which would
36 /// trigger super-linear behavior in the upstream SQL parser.
37 #[error("sql too complex: {kind} = {value} exceeds limit {limit}")]
38 SqlTooComplex {
39 /// Which budget was exceeded (e.g., `paren_depth`, `not_tokens`).
40 kind: &'static str,
41 /// Observed value.
42 value: usize,
43 /// Configured limit.
44 limit: usize,
45 },
46
47 /// Constraint violation (e.g., NOT NULL violation, type constraint).
48 ///
49 /// Generic catch-all for non-uniqueness constraint failures.
50 /// Duplicate primary keys raise [`Self::DuplicatePrimaryKey`] instead
51 /// so SDK callers can pattern-match without parsing message strings.
52 #[error("constraint violation: {0}")]
53 ConstraintViolation(String),
54
55 /// Duplicate primary-key value detected on INSERT.
56 ///
57 /// Carries the table name and the rejected key tuple so callers can
58 /// short-circuit retry/upsert flows without parsing the error string.
59 /// Notebar's webhook-dedup loop (try-INSERT-then-SELECT) is the
60 /// canonical consumer.
61 #[error("duplicate primary key in table '{table}': {key:?}")]
62 DuplicatePrimaryKey {
63 /// Name of the table whose primary key was violated.
64 table: String,
65 /// Rejected key tuple (one element per primary-key column).
66 key: Vec<Value>,
67 },
68
69 /// Correlated subquery row-evaluation cap exceeded.
70 ///
71 /// Emitted before the correlated-loop executor runs when the estimated
72 /// product of outer rows × inner rows per iteration exceeds the
73 /// configured cap (default `10_000_000`; see
74 /// `QueryEngine::with_correlated_cap`). Fails fast rather than
75 /// consuming memory. See `docs/reference/sql/correlated-subqueries.md`.
76 #[error(
77 "correlated subquery cardinality exceeded: estimated {estimated} row \
78 evaluations exceeds cap of {cap}"
79 )]
80 CorrelatedCardinalityExceeded { estimated: u64, cap: u64 },
81
82 /// Requested `AS OF TIMESTAMP` precedes the earliest retained event.
83 ///
84 /// Emitted when a `FOR SYSTEM_TIME AS OF '<iso>'` / `AS OF TIMESTAMP`
85 /// query asks for a wall-clock instant older than the oldest entry
86 /// in the timestamp-to-offset index (typically a freshly-opened
87 /// database, or a timestamp predating any write). Distinguished
88 /// from a general "no offset found" error so callers can surface
89 /// the retention horizon to the user.
90 ///
91 /// `requested_ns` is the caller-supplied Unix-nanosecond timestamp;
92 /// `horizon_ns` is the earliest wall-clock instant the index can
93 /// answer for (or `0` when the log is empty).
94 ///
95 /// Shipped with v0.6.0 Tier 2 #6 (AS OF TIMESTAMP time-travel).
96 #[error(
97 "AS OF TIMESTAMP {requested_ns} ns precedes the earliest retained \
98 event (retention horizon: {horizon_ns} ns)"
99 )]
100 AsOfBeforeRetentionHorizon { requested_ns: i64, horizon_ns: i64 },
101
102 /// Underlying store error.
103 #[error("store error: {0}")]
104 Store(#[from] StoreError),
105
106 /// JSON serialization/deserialization error.
107 #[error("json error: {0}")]
108 Json(#[from] serde_json::Error),
109}
110
111/// Result type for query operations.
112pub type Result<T> = std::result::Result<T, QueryError>;