pgsql: be more strict with pub usage

Review pub visibility to:
Make it pub crate-only wherever possible.
Remove pub altogether where not-needed.
pull/13366/head
Juliana Fajardini 6 months ago
parent 57f7f93a03
commit 68acc0cfcb

@ -21,5 +21,5 @@
pub mod detect;
pub mod logger;
pub mod parser;
mod parser;
pub mod pgsql;

@ -31,15 +31,15 @@ use nom7::number::streaming::{be_u16, be_u32, be_u8};
use nom7::sequence::terminated;
use nom7::{Err, IResult, ToUsize};
pub const PGSQL_LENGTH_FIELD: u32 = 4;
const PGSQL_LENGTH_FIELD: u32 = 4;
pub const PGSQL_DUMMY_PROTO_MAJOR: u16 = 1234; // 0x04d2
pub const PGSQL_DUMMY_PROTO_CANCEL_REQUEST: u16 = 5678; // 0x162e
pub const PGSQL_DUMMY_PROTO_MINOR_SSL: u16 = 5679; //0x162f
pub const _PGSQL_DUMMY_PROTO_MINOR_GSSAPI: u16 = 5680; // 0x1630
const PGSQL_DUMMY_PROTO_MAJOR: u16 = 1234; // 0x04d2
const PGSQL_DUMMY_PROTO_CANCEL_REQUEST: u16 = 5678; // 0x162e
const PGSQL_DUMMY_PROTO_MINOR_SSL: u16 = 5679; //0x162f
const _PGSQL_DUMMY_PROTO_MINOR_GSSAPI: u16 = 5680; // 0x1630
#[derive(Debug, PartialEq, Eq)]
pub enum PgsqlParseError<I> {
pub(crate) enum PgsqlParseError<I> {
InvalidLength,
NomError(I, ErrorKind),
@ -80,7 +80,7 @@ fn parse_exact_length(
}
#[derive(Debug, PartialEq, Eq)]
pub enum PgsqlParameters {
pub(crate) enum PgsqlParameters {
// startup parameters
User,
Database,
@ -104,7 +104,7 @@ pub enum PgsqlParameters {
}
impl PgsqlParameters {
pub fn to_str(&self) -> &str {
pub(crate) fn to_str(&self) -> &str {
match self {
PgsqlParameters::User => "user",
PgsqlParameters::Database => "database",
@ -156,26 +156,26 @@ impl From<&[u8]> for PgsqlParameters {
}
#[derive(Debug, PartialEq, Eq)]
pub struct PgsqlParameter {
pub(crate) struct PgsqlParameter {
pub name: PgsqlParameters,
pub value: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PgsqlStartupParameters {
pub(crate) struct PgsqlStartupParameters {
pub user: PgsqlParameter,
pub optional_params: Option<Vec<PgsqlParameter>>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct DummyStartupPacket {
pub(crate) struct DummyStartupPacket {
length: u32,
proto_major: u16,
proto_minor: u16,
}
#[derive(Debug, PartialEq, Eq)]
pub struct StartupPacket {
pub(crate) struct StartupPacket {
pub length: u32,
pub proto_major: u16,
pub proto_minor: u16,
@ -183,27 +183,27 @@ pub struct StartupPacket {
}
#[derive(Debug, PartialEq, Eq)]
pub struct RegularPacket {
pub(crate) struct RegularPacket {
pub identifier: u8,
pub length: u32,
pub payload: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PgsqlErrorNoticeMessageField {
pub(crate) struct PgsqlErrorNoticeMessageField {
pub field_type: PgsqlErrorNoticeFieldType,
pub field_value: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct ErrorNoticeMessage {
pub(crate) struct ErrorNoticeMessage {
pub identifier: u8,
pub length: u32,
pub message_body: Vec<PgsqlErrorNoticeMessageField>,
}
#[derive(Debug, PartialEq, Eq)]
pub enum SSLResponseMessage {
pub(crate) enum SSLResponseMessage {
SSLAccepted,
SSLRejected,
InvalidResponse,
@ -230,14 +230,14 @@ impl From<char> for SSLResponseMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParameterStatusMessage {
pub(crate) struct ParameterStatusMessage {
pub identifier: u8,
pub length: u32,
pub param: PgsqlParameter,
}
#[derive(Debug, PartialEq, Eq)]
pub struct BackendKeyDataMessage {
pub(crate) struct BackendKeyDataMessage {
pub identifier: u8,
pub length: u32,
pub backend_pid: u32,
@ -245,21 +245,21 @@ pub struct BackendKeyDataMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct ConsolidatedDataRowPacket {
pub(crate) struct ConsolidatedDataRowPacket {
pub identifier: u8,
pub row_cnt: u64, // row or msg cnt
pub data_size: u64,
}
#[derive(Debug, PartialEq, Eq)]
pub struct ReadyForQueryMessage {
pub(crate) struct ReadyForQueryMessage {
pub identifier: u8,
pub length: u32,
pub transaction_status: u8,
}
#[derive(Debug, PartialEq, Eq)]
pub struct NotificationResponse {
pub(crate) struct NotificationResponse {
pub identifier: u8,
pub length: u32,
pub pid: u32,
@ -269,7 +269,7 @@ pub struct NotificationResponse {
}
#[derive(Debug, PartialEq, Eq)]
pub struct CopyResponse {
pub(crate) struct CopyResponse {
pub identifier: u8,
pub length: u32,
pub column_cnt: u16,
@ -278,13 +278,13 @@ pub struct CopyResponse {
}
#[derive(Debug, PartialEq, Eq)]
pub struct NoPayloadMessage {
pub(crate) struct NoPayloadMessage {
pub identifier: u8,
pub length: u32,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PgsqlBEMessage {
pub(crate) enum PgsqlBEMessage {
SSLResponse(SSLResponseMessage),
ErrorResponse(ErrorNoticeMessage),
NoticeResponse(ErrorNoticeMessage),
@ -310,7 +310,7 @@ pub enum PgsqlBEMessage {
}
impl PgsqlBEMessage {
pub fn to_str(&self) -> &'static str {
pub(crate) fn to_str(&self) -> &'static str {
match self {
PgsqlBEMessage::SSLResponse(SSLResponseMessage::SSLAccepted) => "ssl_accepted",
PgsqlBEMessage::SSLResponse(SSLResponseMessage::SSLRejected) => "ssl_rejected",
@ -354,14 +354,14 @@ impl PgsqlBEMessage {
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum SASLAuthenticationMechanism {
pub(crate) enum SASLAuthenticationMechanism {
ScramSha256,
ScramSha256Plus,
// UnknownMechanism,
}
impl SASLAuthenticationMechanism {
pub fn to_str(&self) -> &'static str {
pub(crate) fn to_str(&self) -> &'static str {
match self {
SASLAuthenticationMechanism::ScramSha256 => "scram_SHA256",
SASLAuthenticationMechanism::ScramSha256Plus => "scram_SHA256_plus",
@ -372,13 +372,13 @@ impl SASLAuthenticationMechanism {
type SASLInitialResponse = (SASLAuthenticationMechanism, u32, Vec<u8>);
#[derive(Debug, PartialEq, Eq)]
pub struct CancelRequestMessage {
pub(crate) struct CancelRequestMessage {
pub pid: u32,
pub backend_key: u32,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PgsqlFEMessage {
pub(crate) enum PgsqlFEMessage {
SSLRequest(DummyStartupPacket),
StartupMessage(StartupPacket),
PasswordMessage(RegularPacket),
@ -394,7 +394,7 @@ pub enum PgsqlFEMessage {
}
impl PgsqlFEMessage {
pub fn to_str(&self) -> &'static str {
pub(crate) fn to_str(&self) -> &'static str {
match self {
PgsqlFEMessage::StartupMessage(_) => "startup_message",
PgsqlFEMessage::SSLRequest(_) => "ssl_request",
@ -413,7 +413,7 @@ impl PgsqlFEMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct AuthenticationMessage {
pub(crate) struct AuthenticationMessage {
pub identifier: u8,
pub length: u32,
pub auth_type: u32,
@ -421,7 +421,7 @@ pub struct AuthenticationMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct SASLInitialResponsePacket {
pub(crate) struct SASLInitialResponsePacket {
pub identifier: u8,
pub length: u32,
pub auth_mechanism: SASLAuthenticationMechanism,
@ -430,7 +430,7 @@ pub struct SASLInitialResponsePacket {
}
#[derive(Debug, PartialEq, Eq)]
pub struct AuthenticationSASLMechanismMessage {
pub(crate) struct AuthenticationSASLMechanismMessage {
identifier: u8,
length: u32,
auth_type: u32,
@ -438,7 +438,7 @@ pub struct AuthenticationSASLMechanismMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct RowField {
pub(crate) struct RowField {
pub field_name: Vec<u8>,
pub table_oid: u32,
pub column_index: u16,
@ -452,7 +452,7 @@ pub struct RowField {
}
#[derive(Debug, PartialEq, Eq)]
pub struct RowDescriptionMessage {
pub(crate) struct RowDescriptionMessage {
pub identifier: u8,
pub length: u32,
pub field_count: u16,
@ -460,14 +460,14 @@ pub struct RowDescriptionMessage {
}
#[derive(Debug, PartialEq, Eq)]
pub struct ColumnFieldValue {
pub(crate) struct ColumnFieldValue {
// Can be 0, or -1 as a special NULL column value
pub value_length: i32,
pub value: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PgsqlErrorNoticeFieldType {
pub(crate) enum PgsqlErrorNoticeFieldType {
SeverityLocalizable,
SeverityNonLocalizable,
CodeSqlStateCode,
@ -493,7 +493,7 @@ pub enum PgsqlErrorNoticeFieldType {
}
impl PgsqlErrorNoticeFieldType {
pub fn to_str(&self) -> &'static str {
pub(crate) fn to_str(&self) -> &'static str {
match self {
PgsqlErrorNoticeFieldType::SeverityLocalizable => "severity_localizable",
PgsqlErrorNoticeFieldType::SeverityNonLocalizable => "severity_non_localizable",
@ -607,7 +607,7 @@ fn pgsql_parse_generic_parameter(
))
}
pub fn pgsql_parse_startup_parameters(
fn pgsql_parse_startup_parameters(
i: &[u8],
) -> IResult<&[u8], PgsqlStartupParameters, PgsqlParseError<&[u8]>> {
let (i, mut optional) = opt(terminated(
@ -652,7 +652,7 @@ fn parse_sasl_initial_response_payload(
Ok((i, (sasl_mechanism, param_length, param.to_vec())))
}
pub fn parse_sasl_initial_response(
pub(crate) fn parse_sasl_initial_response(
i: &[u8],
) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?;
@ -673,7 +673,7 @@ pub fn parse_sasl_initial_response(
))
}
pub fn parse_sasl_response(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
pub(crate) fn parse_sasl_response(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?;
let (i, length) = parse_gte_length(i, PGSQL_LENGTH_FIELD)?;
let (i, payload) = take(length - PGSQL_LENGTH_FIELD)(i)?;
@ -685,7 +685,7 @@ pub fn parse_sasl_response(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlPars
Ok((i, resp))
}
pub fn pgsql_parse_startup_packet(
fn pgsql_parse_startup_packet(
i: &[u8],
) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, length) = parse_gte_length(i, 8)?;
@ -742,7 +742,7 @@ pub fn pgsql_parse_startup_packet(
// Source: https://www.postgresql.org/docs/13/protocol-flow.html#id-1.10.5.7.11, GSSAPI Session Encryption
// Password can be encrypted or in cleartext
pub fn parse_password_message(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
pub(crate) fn parse_password_message(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?;
let (i, length) = parse_gte_length(i, PGSQL_LENGTH_FIELD)?;
let (i, password) = map_parser(take(length - PGSQL_LENGTH_FIELD), take_until1("\x00"))(i)?;
@ -789,7 +789,7 @@ fn parse_terminate_message(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlPars
}
// Messages that begin with 'p' but are not password ones are not parsed here
pub fn parse_request(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
pub(crate) fn parse_request(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, tag) = peek(be_u8)(i)?;
let (i, message) = match tag {
b'\0' => pgsql_parse_startup_packet(i)?,
@ -918,7 +918,7 @@ fn parse_parameter_status_message(
))
}
pub fn parse_ssl_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
pub(crate) fn parse_ssl_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, tag) = alt((char('N'), char('S')))(i)?;
Ok((
i,
@ -995,7 +995,7 @@ fn parse_row_field(i: &[u8]) -> IResult<&[u8], RowField, PgsqlParseError<&[u8]>>
))
}
pub fn parse_row_description(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
fn parse_row_description(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'T')(i)?;
let (i, length) = parse_gte_length(i, 7)?;
let (i, field_count) = be_u16(i)?;
@ -1043,7 +1043,7 @@ fn add_up_data_size(columns: Vec<ColumnFieldValue>) -> u64 {
data_size
}
pub fn parse_copy_out_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
fn parse_copy_out_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'H')(i)?;
// copy out message : identifier (u8), length (u32), format (u8), cols (u16), formats (u16*cols)
let (i, length) = parse_gte_length(i, 8)?;
@ -1060,7 +1060,7 @@ pub fn parse_copy_out_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, Pgsql
))
}
pub fn parse_copy_in_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
fn parse_copy_in_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'G')(i)?;
let (i, length) = parse_gte_length(i, 8)?;
let (i, _format) = be_u8(i)?;
@ -1076,7 +1076,7 @@ pub fn parse_copy_in_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlP
))
}
pub fn parse_consolidated_copy_data_out(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
fn parse_consolidated_copy_data_out(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'd')(i)?;
let (i, length) = parse_gte_length(i, 5)?;
let (i, _data) = take(length - PGSQL_LENGTH_FIELD)(i)?;
@ -1089,7 +1089,7 @@ pub fn parse_consolidated_copy_data_out(i: &[u8]) -> IResult<&[u8], PgsqlBEMessa
))
}
pub fn parse_consolidated_copy_data_in(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
fn parse_consolidated_copy_data_in(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'd')(i)?;
let (i, length) = parse_gte_length(i, 5)?;
let (i, _data) = take(length - PGSQL_LENGTH_FIELD)(i)?;
@ -1140,7 +1140,7 @@ fn parse_copy_fail(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage, PgsqlParseError<&
// Currently, we don't store the actual DataRow messages, as those could easily become a burden, memory-wise
// We use ConsolidatedDataRow to store info we still want to log: message size.
// Later on, we calculate the number of lines the command actually returned by counting ConsolidatedDataRow messages
pub fn parse_consolidated_data_row(
fn parse_consolidated_data_row(
i: &[u8],
) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, identifier) = verify(be_u8, |&x| x == b'D')(i)?;
@ -1181,7 +1181,7 @@ fn parse_sasl_mechanisms(
terminated(many1(parse_sasl_mechanism), tag("\x00"))(i)
}
pub fn parse_error_response_code(
fn parse_error_response_code(
i: &[u8],
) -> IResult<&[u8], PgsqlErrorNoticeMessageField, PgsqlParseError<&[u8]>> {
let (i, _field_type) = char('C')(i)?;
@ -1197,7 +1197,7 @@ pub fn parse_error_response_code(
// Parse an error response with non-localizeable severity message.
// Possible values: ERROR, FATAL, or PANIC
pub fn parse_error_response_severity(
fn parse_error_response_severity(
i: &[u8],
) -> IResult<&[u8], PgsqlErrorNoticeMessageField, PgsqlParseError<&[u8]>> {
let (i, field_type) = char('V')(i)?;
@ -1214,7 +1214,7 @@ pub fn parse_error_response_severity(
// The non-localizable version of Severity field has different values,
// in case of a notice: 'WARNING', 'NOTICE', 'DEBUG', 'INFO' or 'LOG'
pub fn parse_notice_response_severity(
fn parse_notice_response_severity(
i: &[u8],
) -> IResult<&[u8], PgsqlErrorNoticeMessageField, PgsqlParseError<&[u8]>> {
let (i, field_type) = char('V')(i)?;
@ -1235,7 +1235,7 @@ pub fn parse_notice_response_severity(
))
}
pub fn parse_error_response_field(
fn parse_error_response_field(
i: &[u8], is_err_msg: bool,
) -> IResult<&[u8], PgsqlErrorNoticeMessageField, PgsqlParseError<&[u8]>> {
let (i, field_type) = peek(be_u8)(i)?;
@ -1262,7 +1262,7 @@ pub fn parse_error_response_field(
Ok((i, data))
}
pub fn parse_error_notice_fields(
fn parse_error_notice_fields(
i: &[u8], is_err_msg: bool,
) -> IResult<&[u8], Vec<PgsqlErrorNoticeMessageField>, PgsqlParseError<&[u8]>> {
let (i, data) = many_till(|b| parse_error_response_field(b, is_err_msg), tag("\x00"))(i)?;
@ -1322,7 +1322,7 @@ fn parse_notification_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, Pgsql
Ok((i, msg))
}
pub fn pgsql_parse_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
pub(crate) fn pgsql_parse_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage, PgsqlParseError<&[u8]>> {
let (i, tag) = peek(be_u8)(i)?;
let (i, message) = match tag {
b'E' => pgsql_parse_error_response(i)?,
@ -1362,7 +1362,7 @@ mod tests {
use nom7::Needed;
impl ErrorNoticeMessage {
pub fn new(identifier: u8, length: u32) -> Self {
fn new(identifier: u8, length: u32) -> Self {
ErrorNoticeMessage {
identifier,
length,

@ -32,14 +32,14 @@ use std::collections::VecDeque;
use std::ffi::CString;
use suricata_sys::sys::AppProto;
pub const PGSQL_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0;
const PGSQL_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0;
pub(crate) static mut ALPROTO_PGSQL: AppProto = ALPROTO_UNKNOWN;
static mut PGSQL_MAX_TX: usize = 1024;
#[derive(AppLayerEvent, Debug, PartialEq, Eq)]
pub enum PgsqlEvent {
enum PgsqlEvent {
InvalidLength, // Can't parse the length field
MalformedRequest, // Enough data, but unexpected request format
MalformedResponse, // Enough data, but unexpected response format
@ -48,7 +48,7 @@ pub enum PgsqlEvent {
#[repr(u8)]
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
pub enum PgsqlTxProgress {
pub(crate) enum PgsqlTxProgress {
TxInit = 0,
TxReceived,
TxDone,
@ -56,7 +56,7 @@ pub enum PgsqlTxProgress {
}
#[derive(Debug)]
pub struct PgsqlTransaction {
pub(crate) struct PgsqlTransaction {
pub tx_id: u64,
pub tx_req_state: PgsqlTxProgress,
pub tx_res_state: PgsqlTxProgress,
@ -82,7 +82,7 @@ impl Default for PgsqlTransaction {
}
impl PgsqlTransaction {
pub fn new() -> Self {
fn new() -> Self {
Self {
tx_id: 0,
tx_req_state: PgsqlTxProgress::TxInit,
@ -95,21 +95,21 @@ impl PgsqlTransaction {
}
}
pub fn incr_row_cnt(&mut self) {
fn incr_row_cnt(&mut self) {
self.data_row_cnt = self.data_row_cnt.saturating_add(1);
}
pub fn get_row_cnt(&self) -> u64 {
fn get_row_cnt(&self) -> u64 {
self.data_row_cnt
}
pub fn sum_data_size(&mut self, row_size: u64) {
fn sum_data_size(&mut self, row_size: u64) {
self.data_size += row_size;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PgsqlStateProgress {
enum PgsqlStateProgress {
IdleState,
// Related to Frontend-received messages //
SSLRequestReceived,
@ -148,7 +148,7 @@ pub enum PgsqlStateProgress {
}
#[derive(Debug)]
pub struct PgsqlState {
struct PgsqlState {
state_data: AppLayerStateData,
tx_id: u64,
transactions: VecDeque<PgsqlTransaction>,
@ -177,7 +177,7 @@ impl Default for PgsqlState {
}
impl PgsqlState {
pub fn new() -> Self {
fn new() -> Self {
Self {
state_data: AppLayerStateData::new(),
tx_id: 0,
@ -210,7 +210,7 @@ impl PgsqlState {
}
}
pub fn get_tx(&mut self, tx_id: u64) -> Option<&PgsqlTransaction> {
fn get_tx(&mut self, tx_id: u64) -> Option<&PgsqlTransaction> {
self.transactions.iter().find(|tx| tx.tx_id == tx_id + 1)
}

Loading…
Cancel
Save