Revision 3 (by ahitrov@rambler.ru, 2010/03/24 15:19:32) The CORE
package Contenido::DB::PostgreSQL;

# ----------------------------------------------------------------------------
# ����� ���������� ������ ����� ������ PostgreSQL 
# ----------------------------------------------------------------------------
use strict;
use warnings;

use DBI;
use DBD::Pg;

use Contenido::Globals;
use Contenido::Msg;

# ������ ������� � ����������� � ����� �����
# ��������� ���������� � ����� ��� ��������� ������ ���� ��� �� ����
sub SQL {
    my $self = shift;
    return ($self->connect_check() ? $self->{SQL} : undef);
}

#��������� ��������������� ���������� � ����� ��� ��������� ������ ���� ��� �� ����
sub TSQL {
    my $self = shift;
    return ($self->t_connect_check() ? $self->{TSQL} : undef);
}

# -------------------------------------------------------------------------------------------------
# ��������� ���������� � ����� ������
# -------------------------------------------------------------------------------------------------
sub connect {
    my $self = shift;
    #���������� ��� ����
    if ($self->is_connected) {
    } else {
        unless ($self->{SQL} = $self->create_db_connect) {
            $log->error("�� ���� ����������� � ����� ������");
            die;
        }
        $self->{SQL}->do("SET NAMES '".$self->state->db_client_encoding."'") if ($self->state->db_client_encoding);
    }

    $self->{_connect_ok} = 1;
    return 1;
}

sub t_connect {
    my $self = shift;
    #�������������� connect ��� ����
    if ($self->is_t_connected) {
        $self->{TSQL_level}++;
    } else {
        unless ($self->{TSQL} = $self->create_db_t_connect) {
            $log->error("�� ���� ����������� � ����� ������");
            die;
        }
        $self->{TSQL}->do("SET NAMES '".$self->state->db_client_encoding."'") if ($self->state->db_client_encoding);
   	    $self->{TSQL_level} = 1;
        #���� �� ����������� �������� �� 0
        $self->{TSQLStable} = 0 unless (exists $self->{TSQLStable});
    }
    $self->{_t_connect_ok} = 1;
    $self->{oldSQL} = $self->{SQL} if ($self->{SQL} and (!$self->{oldSQL}));
	$self->{SQL} = $self->{TSQL};

    return 1;
}

#��������� ���������� � ����� (�������� ���� �� ��� keeper ����)
#���������� $dbh ��� undef
sub create_db_connect {
    my $self = shift;
    return DBI->connect("dbi:Pg:dbname=$self->{db_name};".( $self->{db_host} ne 'localhost' ? "host=$self->{db_host};" : "" )."port=$self->{db_port}", $self->{db_user}, $self->{db_password}, { 'AutoCommit' => 1, pg_server_prepare => $self->{db_prepare}, 'pg_enable_utf8' => $self->{db_enable_utf8} } );
}

sub create_db_t_connect {
    my $self = shift;
    return DBI->connect("dbi:Pg:dbname=$self->{db_name};".( $self->{db_host} ne 'localhost' ? "host=$self->{db_host};" : "" )."port=$self->{db_port}", $self->{db_user}, $self->{db_password}, { 'AutoCommit' => 0, pg_server_prepare => $self->{db_prepare}, 'pg_enable_utf8' => $self->{db_enable_utf8} } );
}

#���������� �������� ��������� ���������� � ����� 
sub is_connected {
    my $self = shift;
    if (ref($self->{SQL}) and $self->{SQL}->can('ping') and $self->{SQL}->ping()) {
        $self->{_connect_ok} = 1;
        return 1;
    } else {
        $self->{_connect_ok} = 0;
        return 0;               
    }
}

#���������� �������� ��������� ���������� � �����
sub is_t_connected {
    my $self = shift;
    if (ref($self->{TSQL}) and $self->{TSQL}->can('ping') and $self->{TSQL}->ping()) {
        $self->{_t_connect_ok} = 1;
        return 1;
    } else {
        $self->{_t_connect_ok} = 0;
        return 0;
    }
}

#�������� ���������� � ����� ���������� ��������� ���������� 
sub connect_check {
    my $self = shift;
    return 1 if ($self->{_connect_ok});
    if ($self->is_connected) {
        $self->{_connect_ok} = 1;
        return 1;
    } else {
        if ($self->connect) {
            return 1;
        } else {
            #���� �� ������ �������� �� ������ ��� ��� die �������� ������
            return 0;
        }
    }
}

sub t_connect_check {
    my $self = shift;
    return 1 if ($self->{_t_connect_ok});
    if ($self->is_t_connected) {
        $self->{_t_connect_ok} = 1;
        return 1;
    } else {
        if ($self->t_connect) {
            return 1;
        } else {
            #���� �� ������ �������� �� ������ ��� ��� die �������� ������
            return 0;
        }
    }
}

# -------------------------------------------------------------------------------------------------
# ��������� ���������� � ����� ������
# -------------------------------------------------------------------------------------------------
sub shutdown
{
    my $self = shift;
    $self->{SQL} = $self->{oldSQL} if $self->{oldSQL};
    delete $self->{oldSQL};
    $self->{SQL}->disconnect()     if ($self->is_connected);
    delete $self->{SQL};
    $self->{_connect_ok} = 0;
    $log->info("������� ���������� � ����� ������ PostgreSQL �� ����� ".$self->{db_port}." keepalive=".$self->state->db_keepalive) if $self->{debug};
    return 1;
}

#���������� ���������� � ���������� ����������
sub t_shutdown {
    my $self = shift;
    my $force = shift; 
    #���� �� ������ stable transaction enabled connect �� ������ ���
    if ($force or !$self->TSQLStable) {
        $self->{SQL} = $self->{oldSQL} if ($self->{oldSQL});
        $self->{TSQL}->disconnect() if ($self->is_t_connected);
        delete $self->{TSQL};
        $self->{_t_connect_ok} = 0;
    }
    return 1;
}

#rollback+disconnect 2 � 1 ������� ��� ������ � ��������� ���������
#�������� ���������� ��� �� ���� || return $keeper->t_abort("��� �� ��������� ������");
sub t_abort {
    my $self=shift;
    if ($self->is_t_connected) {
        $self->{TSQL}->rollback();
        #� ����� t_abort �� ��������� ������� ����������� ����������
        $self->t_shutdown();
    }
    return undef;
}

#commit+disconnect 2 � 1 �������
sub t_finish {
    my $self=shift;
    if ($self->is_t_connected) {
        $self->{TSQL_level}--;
        #����� �� ����� ���� ������� ��
        #���� ������� ��������
        # <0 ������ �� ������������ ������
        if ($self->{TSQL_level}<=0) {
            $self->{TSQL}->commit();
            $self->t_shutdown();
        }
    }
    return 1;
}

#������ � ���������� ���������� TSQLStable (����������� ��������������� ����������)
sub TSQLStable {
    my $self = shift;
    my $val = shift;
    if (defined $val) {
        $self->{TSQLStable} = $val;
    } else {
        $self->{TSQLStable} ||= 0;
    } 
    return $self->{TSQLStable};
}


#COMPATIBILITY SUBS
sub db_connect {
    return shift->connect;
}

sub t_dis_connect {
    return shift->t_shutdown;
}

1;