hdbconnect_impl/protocol/parts/
execution_result.rs

1use std::vec::IntoIter;
2
3use crate::{HdbResult, ServerError};
4use byteorder::{LittleEndian, ReadBytesExt};
5
6/// Describes the success of a command.
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub enum ExecutionResult {
9    /// Number of rows that were affected by the successful execution.
10    RowsAffected(usize),
11    /// Command was successful.
12    SuccessNoInfo, // -2
13    /// Execution failed with given `ServerError`.
14    Failure(Option<ServerError>), // -3
15    /// `ServerError` was reported without matching execution failure
16    ExtraFailure(ServerError),
17}
18impl ExecutionResult {
19    /// True if it is an instance of `Self::Failure`.
20    #[must_use]
21    pub fn is_failure(&self) -> bool {
22        matches!(self, Self::Failure(_))
23    }
24    /// True if it is an instance of `Self::RowsAffected`.
25    #[must_use]
26    pub fn is_rows_affected(&self) -> bool {
27        matches!(self, Self::RowsAffected(_))
28    }
29}
30
31impl std::fmt::Display for ExecutionResult {
32    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
33        match *self {
34            Self::RowsAffected(count) => writeln!(fmt, "Number of affected rows: {count}, ")?,
35            Self::SuccessNoInfo => writeln!(
36                fmt,
37                "Command successfully executed but number of affected rows cannot be determined"
38            )?,
39            Self::Failure(Some(ref server_error)) => writeln!(
40                fmt,
41                "Execution of statement or processing of row has failed with {server_error:?}",
42            )?,
43            Self::Failure(None) => writeln!(
44                fmt,
45                "Execution of statement or processing of row has failed"
46            )?,
47            Self::ExtraFailure(ref server_error) => {
48                writeln!(fmt, "Extra server error was reported: {server_error:?}",)?;
49            }
50        }
51        Ok(())
52    }
53}
54
55#[derive(Debug)]
56/// A list of execution results.
57pub struct ExecutionResults(Vec<ExecutionResult>);
58impl std::fmt::Display for ExecutionResults {
59    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
60        for execution_result in &self.0 {
61            std::fmt::Display::fmt(&execution_result, fmt)?;
62        }
63        Ok(())
64    }
65}
66impl ExecutionResults {
67    pub(crate) fn parse(count: usize, rdr: &mut dyn std::io::Read) -> HdbResult<Self> {
68        let mut vec = Vec::<ExecutionResult>::with_capacity(count);
69        for _ in 0..count {
70            match rdr.read_i32::<LittleEndian>()? {
71                -2 => vec.push(ExecutionResult::SuccessNoInfo),
72                -3 => vec.push(ExecutionResult::Failure(None)),
73                #[allow(clippy::cast_sign_loss)]
74                i => vec.push(ExecutionResult::RowsAffected(i as usize)),
75            }
76        }
77        Ok(Self(vec))
78    }
79
80    pub(crate) fn mix_in_server_errors(&mut self, mut err_iter: IntoIter<ServerError>) {
81        for execution_result in &mut self.0 {
82            if let ExecutionResult::Failure(_) = *execution_result {
83                *execution_result = ExecutionResult::Failure(err_iter.next());
84            }
85        }
86        for e in err_iter {
87            warn!(
88                "Reply::handle_db_error(): \
89                 found more server_errors than instances of ExecutionResult::Failure"
90            );
91            self.0.push(ExecutionResult::Failure(Some(e)));
92        }
93    }
94}
95
96impl std::iter::IntoIterator for ExecutionResults {
97    type Item = ExecutionResult;
98    type IntoIter = std::vec::IntoIter<ExecutionResult>;
99    fn into_iter(self) -> Self::IntoIter {
100        self.0.into_iter()
101    }
102}
103impl<I: std::slice::SliceIndex<[ExecutionResult]>> std::ops::Index<I> for ExecutionResults {
104    type Output = I::Output;
105    fn index(&self, index: I) -> &Self::Output {
106        &self.0[index]
107    }
108}