use crate::db::{
cursor::{
CursorBoundary, WindowCursorContract, effective_page_offset_for_window,
window_cursor_contract_for_plan,
},
executor::ExecutionKernel,
query::plan::AccessPlannedQuery,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct PageWindow {
pub(in crate::db) fetch_count: usize,
pub(in crate::db) keep_count: usize,
}
#[must_use]
pub(in crate::db) fn compute_page_keep_count(offset: u32, limit: u32) -> usize {
let offset = usize::try_from(offset).unwrap_or(usize::MAX);
let limit = usize::try_from(limit).unwrap_or(usize::MAX);
offset.saturating_add(limit)
}
#[must_use]
pub(in crate::db) fn compute_page_window(offset: u32, limit: u32) -> PageWindow {
let keep_count = compute_page_keep_count(offset, limit);
let fetch_count = keep_count.saturating_add(1);
PageWindow {
fetch_count,
keep_count,
}
}
impl ExecutionKernel {
pub(in crate::db::executor) fn window_cursor_contract(
plan: &AccessPlannedQuery,
cursor_boundary: Option<&CursorBoundary>,
) -> WindowCursorContract {
window_cursor_contract_for_plan(plan, cursor_boundary)
}
#[must_use]
pub(in crate::db::executor) fn effective_page_offset(
plan: &AccessPlannedQuery,
cursor_boundary: Option<&CursorBoundary>,
) -> u32 {
effective_page_offset_for_window(plan, cursor_boundary.is_some())
}
#[must_use]
pub(in crate::db::executor) fn bounded_order_keep_count(
plan: &AccessPlannedQuery,
cursor_boundary: Option<&CursorBoundary>,
) -> Option<usize> {
let logical = plan.scalar_plan();
if !logical.mode.is_load() || cursor_boundary.is_some() {
return None;
}
let page = logical.page.as_ref()?;
let limit = page.limit?;
if limit == 0 {
return None;
}
Some(compute_page_window(page.offset, limit).fetch_count)
}
}
#[cfg(test)]
mod tests {
use super::{PageWindow, compute_page_keep_count, compute_page_window};
#[test]
fn compute_page_window_zero_offset_zero_limit_projects_keep_and_fetch() {
let window = compute_page_window(0, 0);
assert_eq!(
window,
PageWindow {
fetch_count: 1,
keep_count: 0,
}
);
}
#[test]
fn compute_page_window_zero_offset_limit_one_projects_keep_and_fetch() {
let window = compute_page_window(0, 1);
assert_eq!(
window,
PageWindow {
fetch_count: 2,
keep_count: 1,
}
);
}
#[test]
fn compute_page_window_offset_n_limit_one() {
let window = compute_page_window(37, 1);
assert_eq!(
window,
PageWindow {
fetch_count: 39,
keep_count: 38,
}
);
}
#[test]
fn compute_page_window_high_bounds_saturates_keep_and_fetch() {
let base = usize::try_from(u32::MAX).unwrap_or(usize::MAX);
let expected_keep = base.saturating_add(base);
let window = compute_page_window(u32::MAX, u32::MAX);
assert_eq!(
window,
PageWindow {
fetch_count: expected_keep.saturating_add(1),
keep_count: expected_keep,
}
);
}
#[test]
fn compute_page_keep_and_fetch_counts_matches_window_projections() {
let window = compute_page_window(37, 11);
assert_eq!(window.keep_count, compute_page_keep_count(37, 11));
assert_eq!(window.fetch_count, compute_page_window(37, 11).fetch_count);
}
}