1use std::fmt;
2
3use powdb_storage::types::Value;
4
5#[derive(Debug)]
7pub enum QueryResult {
8 Rows {
9 columns: Vec<String>,
10 rows: Vec<Vec<Value>>,
11 },
12 Scalar(Value), Modified(u64), Created(String), Executed {
16 message: String,
17 }, }
19
20impl QueryResult {
21 pub fn row_count(&self) -> usize {
22 match self {
23 QueryResult::Rows { rows, .. } => rows.len(),
24 QueryResult::Scalar(_) => 1,
25 QueryResult::Modified(n) => *n as usize,
26 QueryResult::Created(_) => 0,
27 QueryResult::Executed { .. } => 0,
28 }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq)]
39pub enum QueryError {
40 TableNotFound(String),
42 ColumnNotFound { table: String, column: String },
44 TypeError(String),
46 JoinLimitExceeded,
48 NestedLoopPairLimitExceeded {
51 left_rows: usize,
52 right_rows: usize,
53 limit: usize,
54 },
55 SortLimitExceeded,
57 MemoryLimitExceeded {
61 limit_bytes: usize,
62 requested_bytes: usize,
63 },
64 Parse(String),
66 IndexError(String),
68 ViewError(String),
70 StorageError(String),
72 ReadonlyNeedsWrite,
74 Timeout { timeout_ms: u64 },
79 Cancelled,
82 Execution(String),
84}
85
86impl fmt::Display for QueryError {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 match self {
89 QueryError::TableNotFound(t) => write!(f, "table '{t}' not found"),
90 QueryError::ColumnNotFound { table, column } => {
91 if table.is_empty() {
92 write!(f, "column '{column}' not found")
93 } else {
94 write!(f, "column '{column}' not found in table '{table}'")
95 }
96 }
97 QueryError::TypeError(msg) => write!(f, "type mismatch: {msg}"),
98 QueryError::JoinLimitExceeded => write!(f, "join result exceeds row limit"),
99 QueryError::NestedLoopPairLimitExceeded {
100 left_rows,
101 right_rows,
102 limit,
103 } => {
104 let pairs = left_rows.checked_mul(*right_rows);
105 match pairs {
106 Some(pairs) => write!(
107 f,
108 "nested-loop join would evaluate {pairs} candidate pairs, above the {limit} pair limit; add an equi-key to ON, index/filter an input, reduce the joined row counts, or raise the cap via POWDB_MAX_NESTED_LOOP_PAIRS"
109 ),
110 None => write!(
111 f,
112 "nested-loop join candidate count overflows usize ({left_rows} x {right_rows}), above the {limit} pair limit; add an equi-key to ON, index/filter an input, reduce the joined row counts, or raise the cap via POWDB_MAX_NESTED_LOOP_PAIRS"
113 ),
114 }
115 }
116 QueryError::SortLimitExceeded => {
117 write!(f, "sort input exceeds row limit — add a LIMIT clause")
118 }
119 QueryError::MemoryLimitExceeded {
120 limit_bytes,
121 requested_bytes,
122 } => write!(
123 f,
124 "query exceeded memory budget: requested {requested_bytes} bytes, limit {limit_bytes} bytes"
125 ),
126 QueryError::Parse(msg) => write!(f, "{msg}"),
127 QueryError::IndexError(msg) => write!(f, "{msg}"),
128 QueryError::ViewError(msg) => write!(f, "{msg}"),
129 QueryError::StorageError(msg) => write!(f, "{msg}"),
130 QueryError::ReadonlyNeedsWrite => {
131 write!(f, "__POWDB_READONLY_NEEDS_WRITE__")
132 }
133 QueryError::Timeout { timeout_ms } => {
134 write!(f, "query timeout after {timeout_ms}ms")
135 }
136 QueryError::Cancelled => write!(f, "query cancelled by client disconnect"),
137 QueryError::Execution(msg) => write!(f, "{msg}"),
138 }
139 }
140}
141
142impl std::error::Error for QueryError {}
143
144impl From<String> for QueryError {
145 fn from(s: String) -> Self {
146 QueryError::Execution(s)
147 }
148}
149
150impl From<&str> for QueryError {
151 fn from(s: &str) -> Self {
152 QueryError::Execution(s.to_string())
153 }
154}