use super::bounds::{bounded_write_policy_rejection, sql_write_execution_bounds_for_staged_kind};
pub(in crate::db::session::sql) const DEFAULT_PUBLIC_BOUNDED_WRITE_LIMIT: u32 = 100;
pub(in crate::db::session::sql) const DEFAULT_PUBLIC_WRITE_RETURNING_RESPONSE_BYTES: u32 =
1_048_576;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) enum SqlWriteWhereProof {
Missing,
PrimaryKeyEquality,
Other,
}
impl SqlWriteWhereProof {
#[must_use]
pub(in crate::db) const fn has_where(self) -> bool {
!matches!(self, Self::Missing)
}
#[must_use]
pub(in crate::db) const fn is_primary_key_equality(self) -> bool {
matches!(self, Self::PrimaryKeyEquality)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) enum SqlWriteOrderProof {
Missing,
CanonicalPrimaryKey,
DescendingPrimaryKey,
Other,
}
impl SqlWriteOrderProof {
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn is_canonical_primary_key(self) -> bool {
matches!(self, Self::CanonicalPrimaryKey)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) enum SqlWriteReturningShape {
None,
NarrowAll,
NarrowFields,
}
impl SqlWriteReturningShape {
#[must_use]
pub(in crate::db) const fn is_requested(self) -> bool {
!matches!(self, Self::None)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) enum SqlWriteBoundedPolicyRejection {
MissingCanonicalPrimaryKeyOrder,
DescendingOrder,
MissingLimit,
OffsetUnsupported,
LimitTooHigh,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) enum SqlWriteExposureClass {
PublicPrimaryKeyOnly,
PublicBoundedDeterministic,
}
impl SqlWriteExposureClass {
const fn admission_lane(self) -> SqlWriteAdmissionLane {
match self {
Self::PublicPrimaryKeyOnly => SqlWriteAdmissionLane::PrimaryKeyOnly,
Self::PublicBoundedDeterministic => SqlWriteAdmissionLane::BoundedDeterministic,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) enum SqlWriteShapePolicyRejection {
MissingWhere,
PrimaryKeyProofFailed,
Bounded(SqlWriteBoundedPolicyRejection),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) struct SqlWriteReturningBounds {
pub max_rows: Option<u32>,
pub max_response_bytes: Option<u32>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) struct SqlWriteExecutionBounds {
pub max_staged_rows: Option<u32>,
pub returning: SqlWriteReturningBounds,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub(in crate::db) struct SqlWriteStatementShape {
pub where_proof: SqlWriteWhereProof,
pub order_proof: SqlWriteOrderProof,
pub limit: Option<u32>,
pub offset: Option<u32>,
pub returning_shape: SqlWriteReturningShape,
}
impl SqlWriteStatementShape {
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn is_bounded(&self) -> bool {
matches!(self.limit, Some(limit) if limit > 0)
}
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn has_explicit_canonical_primary_key_order(&self) -> bool {
self.order_proof.is_canonical_primary_key()
}
const fn bounded_policy_rejection(
&self,
max_limit: u32,
) -> Option<SqlWriteBoundedPolicyRejection> {
bounded_write_policy_rejection(self.offset, self.limit, max_limit, self.order_proof)
}
pub(in crate::db::session::sql) const fn bounded_policy_rejection_for_bounds(
&self,
bounds: SqlWritePolicyBounds,
) -> Option<SqlWriteBoundedPolicyRejection> {
self.bounded_policy_rejection(bounds.public_bounded_limit)
}
pub(in crate::db::session::sql) const fn required_where_rejection(
&self,
) -> Option<SqlWriteShapePolicyRejection> {
if self.where_proof.has_where() {
None
} else {
Some(SqlWriteShapePolicyRejection::MissingWhere)
}
}
pub(in crate::db::session::sql) const fn primary_key_policy_rejection(
&self,
) -> Option<SqlWriteShapePolicyRejection> {
if let Some(rejection) = self.required_where_rejection() {
return Some(rejection);
}
if self.where_proof.is_primary_key_equality() {
None
} else {
Some(SqlWriteShapePolicyRejection::PrimaryKeyProofFailed)
}
}
pub(in crate::db::session::sql) const fn bounded_deterministic_policy_rejection(
&self,
bounds: SqlWritePolicyBounds,
) -> Option<SqlWriteShapePolicyRejection> {
if let Some(rejection) = self.required_where_rejection() {
return Some(rejection);
}
match self.bounded_policy_rejection_for_bounds(bounds) {
Some(rejection) => Some(SqlWriteShapePolicyRejection::Bounded(rejection)),
None => None,
}
}
pub(in crate::db::session::sql) const fn execution_bounds_for_admission_lane(
&self,
admission_lane: SqlWriteAdmissionLane,
bounds: SqlWritePolicyBounds,
) -> SqlWriteExecutionBounds {
sql_write_execution_bounds_for_staged_kind(
admission_lane.staged_row_bound_kind(),
self.limit,
self.returning_shape.is_requested(),
bounds.returning_rows,
bounds.returning_response_bytes,
)
}
pub(in crate::db::session::sql) const fn execution_bounds_for_exposure_class(
&self,
exposure_class: SqlWriteExposureClass,
bounds: SqlWritePolicyBounds,
) -> SqlWriteExecutionBounds {
self.execution_bounds_for_admission_lane(exposure_class.admission_lane(), bounds)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) struct SqlWritePolicyBounds {
pub(in crate::db::session::sql) public_bounded_limit: u32,
pub(in crate::db::session::sql) returning_rows: Option<u32>,
pub(in crate::db::session::sql) returning_response_bytes: Option<u32>,
}
impl SqlWritePolicyBounds {
pub(in crate::db::session::sql) const fn new(
public_bounded_limit: u32,
returning_rows: Option<u32>,
returning_response_bytes: Option<u32>,
) -> Self {
Self {
public_bounded_limit,
returning_rows,
returning_response_bytes,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) struct SqlWritePlanCore<S> {
statement: S,
execution_bounds: SqlWriteExecutionBounds,
}
impl<S> SqlWritePlanCore<S> {
pub(in crate::db::session::sql) const fn new(
statement: S,
execution_bounds: SqlWriteExecutionBounds,
) -> Self {
Self {
statement,
execution_bounds,
}
}
pub(in crate::db::session::sql) const fn statement(&self) -> &S {
&self.statement
}
pub(in crate::db::session::sql) const fn execution_bounds(&self) -> SqlWriteExecutionBounds {
self.execution_bounds
}
#[cfg(test)]
pub(in crate::db) const fn set_execution_bounds_for_tests(
&mut self,
execution_bounds: SqlWriteExecutionBounds,
) {
self.execution_bounds = execution_bounds;
}
}
impl<S: Clone> SqlWritePlanCore<S> {
pub(in crate::db::session::sql) fn from_borrowed(
statement: &S,
execution_bounds: SqlWriteExecutionBounds,
) -> Self {
Self::new(statement.clone(), execution_bounds)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::session::sql) enum SqlWriteAdmissionLane {
PrimaryKeyOnly,
BoundedDeterministic,
}
impl SqlWriteAdmissionLane {
pub(super) const fn staged_row_bound_kind(self) -> SqlWriteStagedRowBoundKind {
match self {
Self::PrimaryKeyOnly => SqlWriteStagedRowBoundKind::One,
Self::BoundedDeterministic => SqlWriteStagedRowBoundKind::Limit,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(super) enum SqlWriteStagedRowBoundKind {
One,
Limit,
}