use powdb_storage::types::Value;
#[derive(Debug)]
pub enum QueryResult {
Rows {
columns: Vec<String>,
rows: Vec<Vec<Value>>,
},
Scalar(Value), Modified(u64), Created(String), Executed {
message: String,
}, }
impl QueryResult {
pub fn row_count(&self) -> usize {
match self {
QueryResult::Rows { rows, .. } => rows.len(),
QueryResult::Scalar(_) => 1,
QueryResult::Modified(n) => *n as usize,
QueryResult::Created(_) => 0,
QueryResult::Executed { .. } => 0,
}
}
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum QueryError {
#[error("table '{0}' not found")]
TableNotFound(String),
#[error("{}", column_not_found_message(table, column))]
ColumnNotFound { table: String, column: String },
#[error("type mismatch: {0}")]
TypeError(String),
#[error("join result exceeds row limit")]
JoinLimitExceeded,
#[error("{}", nested_loop_pair_limit_message(*left_rows, *right_rows, *limit))]
NestedLoopPairLimitExceeded {
left_rows: usize,
right_rows: usize,
limit: usize,
},
#[error("sort input exceeds row limit \u{2014} add a LIMIT clause")]
SortLimitExceeded,
#[error(
"query exceeded memory budget: requested {requested_bytes} bytes, limit {limit_bytes} bytes"
)]
MemoryLimitExceeded {
limit_bytes: usize,
requested_bytes: usize,
},
#[error("{0}")]
Parse(String),
#[error("{0}")]
IndexError(String),
#[error("{0}")]
ViewError(String),
#[error("{0}")]
StorageError(String),
#[error("__POWDB_READONLY_NEEDS_WRITE__")]
ReadonlyNeedsWrite,
#[error(
"readonly mode: statement requires a writer (this database was opened read-only for snapshot serving; refresh materialized views before snapshotting a read-only directory)"
)]
ReadonlyMode,
#[error("query timeout after {timeout_ms}ms")]
Timeout { timeout_ms: u64 },
#[error("query cancelled by client disconnect")]
Cancelled,
#[error("{0}")]
Execution(String),
}
fn column_not_found_message(table: &str, column: &str) -> String {
if table.is_empty() {
format!("column '{column}' not found")
} else {
format!("column '{column}' not found in table '{table}'")
}
}
fn nested_loop_pair_limit_message(left_rows: usize, right_rows: usize, limit: usize) -> String {
match left_rows.checked_mul(right_rows) {
Some(pairs) => format!(
"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"
),
None => format!(
"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"
),
}
}
impl From<String> for QueryError {
fn from(s: String) -> Self {
QueryError::Execution(s)
}
}
impl From<&str> for QueryError {
fn from(s: &str) -> Self {
QueryError::Execution(s.to_string())
}
}