<commit_before>pub(crate) mod cursor;
pub mod raw;
#[doc(hidden)]
pub mod result;
mod row;
mod stmt;

use std::ffi::CString;
use std::os::raw as libc;

use self::cursor::*;
use self::raw::{PgTransactionStatus, RawConnection};
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
use crate::connection::*;
use crate::expression::QueryMetadata;
use crate::pg::metadata_lookup::{GetPgMetadataCache, PgMetadataCache};
use crate::pg::{Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
use crate::result::*;

/// The connection string expected by `PgConnection::establish`
/// should be a PostgreSQL connection string, as documented at
/// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
#[allow(missing_debug_implementations)]
pub struct PgConnection {
    pub(crate) raw_connection: RawConnection,
    transaction_state: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
        let query = CString::new(query)?;
        let inner_result = unsafe { self.raw_connection.exec(query.as_ptr()) };
        PgResult::new(inner_result?)?;
        Ok(())
    }
}

impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg> for PgConnection {
    type Cursor = Cursor;
    type Row = self::row::PgRow;
}

impl CommitErrorProcessor for PgConnection {
    fn process_commit_error(&self, transaction_depth: i32, error: Error) -> CommitErrorOutcome {
        if matches!(
            error,
            Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
        ) {
            return CommitErrorOutcome::Throw(error);
        }
        if transaction_depth <= 1 {
            match error {
                Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _) => {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        } else {
            let transaction_status = self.raw_connection.transaction_status();
            match error {
                Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                    if transaction_status == PgTransactionStatus::InError =>
                {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction<commit_msg>Mark transaction manager as broken when a Postgres transaction returns PQTRANS_UNKNOWN<commit_after>pub(crate) mod cursor;
pub mod raw;
#[doc(hidden)]
pub mod result;
mod row;
mod stmt;

use std::ffi::CString;
use std::os::raw as libc;

use self::cursor::*;
use self::raw::{PgTransactionStatus, RawConnection};
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
use crate::connection::*;
use crate::expression::QueryMetadata;
use crate::pg::metadata_lookup::{GetPgMetadataCache, PgMetadataCache};
use crate::pg::{Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
use crate::result::*;

/// The connection string expected by `PgConnection::establish`
/// should be a PostgreSQL connection string, as documented at
/// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
#[allow(missing_debug_implementations)]
pub struct PgConnection {
    pub(crate) raw_connection: RawConnection,
    transaction_state: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
        let query = CString::new(query)?;
        let inner_result = unsafe { self.raw_connection.exec(query.as_ptr()) };
        PgResult::new(inner_result?)?;
        Ok(())
    }
}

impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg> for PgConnection {
    type Cursor = Cursor;
    type Row = self::row::PgRow;
}

impl CommitErrorProcessor for PgConnection {
    fn process_commit_error(&self, transaction_depth: i32, error: Error) -> CommitErrorOutcome {
        let transaction_status = self.raw_connection.transaction_status();
        if transaction_status == PgTransactionStatus::Unknown {
            return CommitErrorOutcome::ThrowAndMarkManagerAsBroken(error);
        }
        if matches!(
            error,
            Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
        ) {
            return CommitErrorOutcome::Throw(error);
        }
        if transaction_depth <= 1 {
            match error {
                Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _) => {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        } else {
            match error {
                Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                    if transaction_status == PgTransactionStatus::InError =>
                {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
{'fraction_non_alphanumeric': 0.1101782485145957, 'fraction_numerical': 0.0012916559028674762, 'mean_word_length': 3.1517426273458446, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7463293', 'n_tokens_mistral': 2055, 'n_tokens_neox': 2026, 'n_words': 358}