use super::*;
pub(in crate::relational::codec) struct Input<'a> {
pub(in crate::relational::codec) source: SliceDecodeInput<'a>,
pub(in crate::relational::codec) work: &'a CheckpointWorkContext,
pub(in crate::relational::codec) allocations:
Option<&'a crate::background::CheckpointDecodeContext>,
}
impl DecodeInput for Input<'_> {
fn checkpoint_work_context(&self) -> Option<&CheckpointWorkContext> {
Some(self.work)
}
fn checkpoint_allocation_context(&self) -> Option<&crate::background::CheckpointDecodeContext> {
self.allocations
}
fn len(&self) -> usize {
self.source.len()
}
fn position(&self) -> usize {
self.source.position()
}
fn read_exact(&mut self, output: &mut [u8]) -> Result<(), RelationalError> {
let end = self
.source
.offset
.checked_add(output.len())
.ok_or_else(|| RelationalError::Corruption("durable decoder offset overflow".into()))?;
if end > self.source.len() {
return Err(RelationalError::Corruption(
"truncated relational durable payload".into(),
));
}
for block in output.chunks_mut(64 * 1024) {
let unit = self.work.start_unit().map_err(work_error)?;
self.source.read_exact(block)?;
unit.finish();
}
self.work.checkpoint().map_err(work_error)
}
fn finish(self) -> Result<(), RelationalError> {
self.source.finish()?;
self.work.checkpoint().map_err(work_error)
}
}
pub(crate) fn decode_schema(
encoded: &[u8],
max_encoded_bytes: usize,
max_schema_items: usize,
work: &CheckpointWorkContext,
) -> Result<RelationalTableSchema, RelationalError> {
decode_schema_inner(encoded, max_encoded_bytes, max_schema_items, work, None)
}
pub(crate) fn decode_schema_owned(
encoded: &[u8],
max_encoded_bytes: usize,
max_schema_items: usize,
allocations: &crate::background::CheckpointDecodeContext,
) -> Result<RelationalTableSchema, RelationalError> {
decode_schema_inner(
encoded,
max_encoded_bytes,
max_schema_items,
allocations,
Some(allocations),
)
}
fn decode_schema_inner(
encoded: &[u8],
max_encoded_bytes: usize,
max_schema_items: usize,
work: &CheckpointWorkContext,
allocations: Option<&crate::background::CheckpointDecodeContext>,
) -> Result<RelationalTableSchema, RelationalError> {
if encoded.len() > max_encoded_bytes {
return Err(RelationalError::Admission(format!(
"relational table schema contains {} bytes, exceeding limit {max_encoded_bytes}",
encoded.len()
)));
}
let limits = RelationalDecodeLimits {
max_record_bytes: max_encoded_bytes,
max_tables: 1,
max_writes: 0,
max_rows: 0,
max_values: max_schema_items,
max_value_bytes: max_encoded_bytes,
max_overflow_segments: 0,
max_overflow_bytes: 0,
};
let input = Input {
source: SliceDecodeInput {
bytes: encoded,
offset: 0,
},
work,
allocations,
};
let mut decoder = Decoder::new(input, limits, true);
let schema = decoder.table_schema()?;
decoder.finish()?;
let scratch = allocations.map(|_| crate::background::CheckpointDecodeContext {
work: work.clone(),
memory: std::cell::RefCell::default(),
});
if let Some(scratch) = &scratch {
use crate::projection::predicate_checkpoint::decode::MapMemory;
if !schema.columns.is_empty() {
MapMemory::<usize>::default()
.before_insert(schema.columns.len() - 1, scratch)
.map_err(|error| RelationalError::Admission(error.to_string()))?;
}
let keys = std::iter::once(schema.primary_key.len())
.chain(schema.unique_constraints.iter().map(Vec::len))
.chain(
schema
.foreign_keys
.iter()
.map(|foreign| foreign.columns.len()),
)
.chain(schema.indexes.iter().map(|index| index.columns.len()))
.max()
.unwrap_or(0);
if keys > 0 {
MapMemory::<()>::default()
.before_insert(keys - 1, scratch)
.map_err(|error| RelationalError::Admission(error.to_string()))?;
}
if !schema.indexes.is_empty() {
MapMemory::<()>::default()
.before_insert(schema.indexes.len() - 1, scratch)
.map_err(|error| RelationalError::Admission(error.to_string()))?;
}
}
validate_table_schema_with_work_context(&schema, work)?;
work.checkpoint().map_err(work_error)?;
Ok(schema)
}
pub(crate) fn decode_row_owned(
encoded: &[u8],
max_values: usize,
max_value_bytes: usize,
allocations: &crate::background::CheckpointDecodeContext,
) -> Result<RelationalRow, RelationalError> {
let limits = RelationalDecodeLimits {
max_record_bytes: encoded.len(),
max_tables: 0,
max_writes: 0,
max_rows: 1,
max_values,
max_value_bytes,
max_overflow_segments: 0,
max_overflow_bytes: 0,
};
let input = Input {
source: SliceDecodeInput {
bytes: encoded,
offset: 0,
},
work: allocations,
allocations: Some(allocations),
};
let mut decoder = Decoder::new(input, limits, false);
let row = decoder.row()?;
decoder.finish()?;
Ok(row)
}