use crate::protocol::parts::{ParameterDescriptors, Parts, StatementContext};
use crate::protocol::{Part, RequestType};
use byteorder::{LittleEndian, WriteBytesExt};
use std::sync::Arc;
const MESSAGE_HEADER_SIZE: u32 = 32;
const SEGMENT_HEADER_SIZE: usize = 24; pub const HOLD_CURSORS_OVER_COMMIT: u8 = 8;
#[derive(Debug)]
pub(crate) struct Request<'a> {
pub request_type: RequestType,
command_options: u8,
parts: Parts<'a>,
}
impl<'a> Request<'a> {
pub fn new(request_type: RequestType, command_options: u8) -> Request<'a> {
Request {
request_type,
command_options,
parts: Parts::default(),
}
}
pub fn new_for_disconnect() -> Request<'a> {
Request::new(RequestType::Disconnect, 0)
}
pub fn push(&mut self, part: Part<'a>) {
self.parts.push(part);
}
pub fn add_statement_context(&mut self, ssi_value: i64) {
let mut stmt_ctx = StatementContext::default();
stmt_ctx.set_statement_sequence_info(ssi_value);
trace!(
"Sending StatementContext with sequence_info = {:?}",
ssi_value
);
self.push(Part::StatementContext(stmt_ctx));
}
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
pub fn emit(
&self,
session_id: i64,
seq_number: i32,
auto_commit: bool,
o_a_descriptors: Option<&Arc<ParameterDescriptors>>,
w: &mut dyn std::io::Write,
) -> std::io::Result<()> {
let varpart_size = self.varpart_size(o_a_descriptors)?;
let total_size = MESSAGE_HEADER_SIZE + varpart_size;
trace!("Writing request with total size {}", total_size);
let mut remaining_bufsize = total_size - MESSAGE_HEADER_SIZE;
debug!(
"Request::emit() of type {:?} for session_id = {}, seq_number = {}",
self.request_type, session_id, seq_number
);
w.write_i64::<LittleEndian>(session_id)?; w.write_i32::<LittleEndian>(seq_number)?; w.write_u32::<LittleEndian>(varpart_size)?; w.write_u32::<LittleEndian>(remaining_bufsize)?; w.write_i16::<LittleEndian>(1)?; for _ in 0..10 {
w.write_u8(0)?;
}
let parts_len = self.parts.len() as i16;
let size = self.seg_size(o_a_descriptors)? as i32;
w.write_i32::<LittleEndian>(size)?; w.write_i32::<LittleEndian>(0)?; w.write_i16::<LittleEndian>(parts_len)?; w.write_i16::<LittleEndian>(1)?; w.write_i8(1)?; w.write_i8(self.request_type as i8)?; w.write_i8(auto_commit.into())?; w.write_u8(self.command_options)?; for _ in 0..8 {
w.write_u8(0)?;
}
remaining_bufsize -= SEGMENT_HEADER_SIZE as u32;
trace!("Headers are written");
for part in self.parts.ref_inner() {
remaining_bufsize = part.emit(remaining_bufsize, o_a_descriptors, w)?;
}
w.flush()?;
trace!("Parts are written");
Ok(())
}
#[allow(clippy::cast_possible_truncation)]
fn varpart_size(
&self,
o_a_descriptors: Option<&Arc<ParameterDescriptors>>,
) -> std::io::Result<u32> {
let mut len = 0_u32;
len += self.seg_size(o_a_descriptors)? as u32;
trace!("varpart_size = {}", len);
Ok(len)
}
fn seg_size(
&self,
o_a_descriptors: Option<&Arc<ParameterDescriptors>>,
) -> std::io::Result<usize> {
let mut len = SEGMENT_HEADER_SIZE;
for part in self.parts.ref_inner() {
len += part.size(true, o_a_descriptors)?;
}
Ok(len)
}
}