Line # Revision Author
1 8 ahitrov@rambler.ru package Contenido::DB::PostgreSQL;
2
3 # ----------------------------------------------------------------------------
4 # Класс реализации работы базой данных PostgreSQL
5 # ----------------------------------------------------------------------------
6 use strict;
7 use warnings;
8
9 use DBI;
10 use DBD::Pg;
11
12 use Contenido::Globals;
13 use Contenido::Msg;
14
15 # МЕТОДЫ ДОСТУПА К СОЕДИНЕНИЯМ С БАЗОЙ УМНЫЕ
16 # получение соединения с базой или установка нового если его не было
17 sub SQL {
18 my $self = shift;
19 return ($self->connect_check() ? $self->{SQL} : undef);
20 }
21
22 #получение транзакционного соединения с базой или установка нового если его не было
23 sub TSQL {
24 my $self = shift;
25 return ($self->t_connect_check() ? $self->{TSQL} : undef);
26 }
27
28 # -------------------------------------------------------------------------------------------------
29 # Открываем соединение с базой данных
30 # -------------------------------------------------------------------------------------------------
31 sub connect {
32 my $self = shift;
33 #соединение уже есть
34 if ($self->is_connected) {
35 } else {
36 unless ($self->{SQL} = $self->create_db_connect) {
37 $log->error("Не могу соединиться с базой данных");
38 die;
39 }
40 $self->{SQL}->do("SET NAMES '".$self->state->db_client_encoding."'") if ($self->state->db_client_encoding);
41 }
42
43 $self->{_connect_ok} = 1;
44 return 1;
45 }
46
47 sub t_connect {
48 my $self = shift;
49 #транзакционный connect уже есть
50 if ($self->is_t_connected) {
51 $self->{TSQL_level}++;
52 } else {
53 unless ($self->{TSQL} = $self->create_db_t_connect) {
54 $log->error("Не могу соединиться с базой данных");
55 die;
56 }
57 $self->{TSQL}->do("SET NAMES '".$self->state->db_client_encoding."'") if ($self->state->db_client_encoding);
58 $self->{TSQL_level} = 1;
59 #если не проставлено значение то 0
60 $self->{TSQLStable} = 0 unless (exists $self->{TSQLStable});
61 }
62 $self->{_t_connect_ok} = 1;
63 $self->{oldSQL} = $self->{SQL} if ($self->{SQL} and (!$self->{oldSQL}));
64 $self->{SQL} = $self->{TSQL};
65
66 return 1;
67 }
68
69 #получение соединения с базой (возможно кому то вне keeper надо)
70 #возвращает $dbh или undef
71 sub create_db_connect {
72 my $self = shift;
73 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} } );
74 }
75
76 sub create_db_t_connect {
77 my $self = shift;
78 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} } );
79 }
80
81 #физическая проверка состояния соединения с базой
82 sub is_connected {
83 my $self = shift;
84 if (ref($self->{SQL}) and $self->{SQL}->can('ping') and $self->{SQL}->ping()) {
85 $self->{_connect_ok} = 1;
86 return 1;
87 } else {
88 $self->{_connect_ok} = 0;
89 return 0;
90 }
91 }
92
93 #физическая проверка состояния соединения с базой
94 sub is_t_connected {
95 my $self = shift;
96 if (ref($self->{TSQL}) and $self->{TSQL}->can('ping') and $self->{TSQL}->ping()) {
97 $self->{_t_connect_ok} = 1;
98 return 1;
99 } else {
100 $self->{_t_connect_ok} = 0;
101 return 0;
102 }
103 }
104
105 #проверка соединения с базой кеширующая состояние соединения
106 sub connect_check {
107 my $self = shift;
108 return 1 if ($self->{_connect_ok});
109 if ($self->is_connected) {
110 $self->{_connect_ok} = 1;
111 return 1;
112 } else {
113 if ($self->connect) {
114 return 1;
115 } else {
116 #сюда по логике попадать не должно так как die вылететь должен
117 return 0;
118 }
119 }
120 }
121
122 sub t_connect_check {
123 my $self = shift;
124 return 1 if ($self->{_t_connect_ok});
125 if ($self->is_t_connected) {
126 $self->{_t_connect_ok} = 1;
127 return 1;
128 } else {
129 if ($self->t_connect) {
130 return 1;
131 } else {
132 #сюда по логике попадать не должно так как die вылететь должен
133 return 0;
134 }
135 }
136 }
137
138 # -------------------------------------------------------------------------------------------------
139 # Закрываем соединение с базой данных
140 # -------------------------------------------------------------------------------------------------
141 sub shutdown
142 {
143 my $self = shift;
144 $self->{SQL} = $self->{oldSQL} if $self->{oldSQL};
145 delete $self->{oldSQL};
146 $self->{SQL}->disconnect() if ($self->is_connected);
147 delete $self->{SQL};
148 $self->{_connect_ok} = 0;
149 $log->info("Закрыто соединение с базой данных PostgreSQL на порту ".$self->{db_port}." keepalive=".$self->state->db_keepalive) if $self->{debug};
150 return 1;
151 }
152
153 #завершение соединения с поддержкой транзакций
154 sub t_shutdown {
155 my $self = shift;
156 my $force = shift;
157 #если не указан stable transaction enabled connect то сносим его
158 if ($force or !$self->TSQLStable) {
159 $self->{SQL} = $self->{oldSQL} if ($self->{oldSQL});
160 $self->{TSQL}->disconnect() if ($self->is_t_connected);
161 delete $self->{TSQL};
162 $self->{_t_connect_ok} = 0;
163 }
164 return 1;
165 }
166
167 #rollback+disconnect 2 в 1 флаконе для отката в аварийных ситуациях
168 #наиболее эффективно что то типа || return $keeper->t_abort("что то сломалось похоже");
169 sub t_abort {
170 my $self=shift;
171 if ($self->is_t_connected) {
172 $self->{TSQL}->rollback();
173 #в случе t_abort не проверяем уровень вложенности транзакции
174 $self->t_shutdown();
175 }
176 return undef;
177 }
178
179 #commit+disconnect 2 в 1 флаконе
180 sub t_finish {
181 my $self=shift;
182 if ($self->is_t_connected) {
183 $self->{TSQL_level}--;
184 #вышли на самый верх наконец то
185 #надо реально комитить
186 # <0 защита от всевозможных глюков
187 if ($self->{TSQL_level}<=0) {
188 $self->{TSQL}->commit();
189 $self->t_shutdown();
190 }
191 }
192 return 1;
193 }
194
195 #доступ к управлению состоянием TSQLStable (постоянного транзакционного соединения)
196 sub TSQLStable {
197 my $self = shift;
198 my $val = shift;
199 if (defined $val) {
200 $self->{TSQLStable} = $val;
201 } else {
202 $self->{TSQLStable} ||= 0;
203 }
204 return $self->{TSQLStable};
205 }
206
207
208 #COMPATIBILITY SUBS
209 sub db_connect {
210 return shift->connect;
211 }
212
213 sub t_dis_connect {
214 return shift->t_shutdown;
215 }
216
217 1;
218