File Coverage

blib/lib/DBIx/Connection/PostgreSQL/SQL.pm
Criterion Covered Total %
statement 15 104 14.4
branch 0 46 0.0
condition 0 8 0.0
subroutine 5 16 31.2
pod 6 6 100.0
total 26 180 14.4


line stmt bran cond sub pod time code
1             package DBIx::Connection::PostgreSQL::SQL;
2              
3 1     1   10518 use strict;
  1         2  
  1         41  
4 1     1   5 use warnings;
  1         2  
  1         37  
5 1     1   6 use vars qw($VERSION $LOB_MAX_SIZE);
  1         2  
  1         54  
6              
7 1     1   6 use Abstract::Meta::Class ':all';
  1         2  
  1         190  
8 1     1   6 use Carp 'confess';
  1         3  
  1         1408  
9              
10             $VERSION = 0.03;
11             $LOB_MAX_SIZE = (1024 * 1024 * 1024);
12              
13             =head1 NAME
14              
15             DBIx::Connection::PostgreSQL::SQL - PostgreSQL catalog sql abstractaction layer.
16              
17             =cut
18              
19             =head1 SYNOPSIS
20            
21             use DBIx::Connection::PostgreSQL::SQL;
22              
23             =head1 DESCRIPTION
24              
25             Represents sql abstractaction layer
26              
27             =head1 EXPORT
28              
29             None
30              
31             =head2 METHODS
32              
33             =over
34              
35             =item sequence_value
36              
37             Returns sql statement that returns next sequence value
38              
39             =cut
40              
41             sub sequence_value {
42 0     0 1   my ($class, $sequence_name) = @_;
43 0           "SELECT nextval('${sequence_name}') AS val"
44             }
45              
46              
47             =item reset_sequence
48              
49             Returns sql statement that restarts sequence.
50              
51             =cut
52              
53             sub reset_sequence {
54 0     0 1   my ($class, $sequence_name, $restart_with, $increment_by) = @_;
55 0 0         ("ALTER SEQUENCE ${sequence_name} RESTART WITH ${restart_with}",
56             ($increment_by ? "ALTER SEQUENCE ${sequence_name} INCREMENT ${increment_by}" : ()));
57             }
58              
59              
60             =item has_sequence
61              
62             Returns sql statement that check is sequence exists in database schema
63              
64             =cut
65              
66             sub has_sequence {
67 0     0 1   my ($class, $schema) = @_;
68 0           "SELECT pc.relname AS sequence_name
69             FROM pg_class pc
70             JOIN pg_authid pa ON pa.oid = pc.relowner AND pc.relkind = 'S' AND pc.relname = lower(?) AND rolname = '". $schema ."' ";
71             }
72              
73              
74             =item set_session_variables
75              
76             Sets session variables
77              
78             It uses the following sql command pattern:
79              
80             SET variable TO value;
81              
82             DBIx::Connection::PostgreSQL::SQL->set_session_variables($connection, {DateStyle => 'US'});
83              
84             =cut
85              
86             sub set_session_variables {
87 0     0 1   my ($class, $connection, $db_session_variables) = @_;
88 0           my $sql = "";
89             $sql .= "SET " . $_ . " TO " . $db_session_variables->{$_} . ";"
90 0           for keys %$db_session_variables;
91 0           $connection->do($sql);
92             }
93              
94              
95             =item update_lob
96              
97             Updates lob. (Large Object)
98             Takes connection object, table name, lob column_name, lob conetent, hash_ref to primary key values. optionally lob size column name.
99              
100             =cut
101              
102             sub update_lob {
103 0     0 1   my ($class, $connection, $table_name, $lob_column_name, $lob, $primary_key_values, $lob_size_column_name) = @_;
104 0 0 0       confess "missing primary key for lob update on ${table_name}.${lob_column_name}"
105             if (!$primary_key_values || ! (%$primary_key_values));
106 0 0         confess "missing lob size column name" unless $lob_size_column_name;
107 0           my $sql = "UPDATE ${table_name} SET ${lob_column_name} = ? ";
108 0 0         $sql .= ($lob_size_column_name ? ", ${lob_size_column_name} = ? " : '')
109             . $connection->_where_clause($primary_key_values);
110            
111 0           $class->_unlink_lob($connection, $class->_get_lob_id($connection, $table_name, $primary_key_values, $lob_column_name));
112 0           my $lob_id = $class->_create_lob($connection, $lob);
113 0           my $bind_counter = 1;
114 0           my $sth = $connection->dbh->prepare($sql);
115 0           $sth->bind_param($bind_counter++ ,$lob_id);
116 0 0         $sth->bind_param($bind_counter++ , length($lob)) if $lob_size_column_name;
117 0           for my $k (sort keys %$primary_key_values) {
118 0           $sth->bind_param($bind_counter++ , $primary_key_values->{$k});
119             }
120 0           $sth->execute();
121             }
122              
123              
124              
125             =item fetch_lob
126              
127             Retrieve lobs.
128             Takes connection object, table name, lob column_name, hash_ref to primary key values. optionally lob size column name.
129             By default max lob size is set to 1 GB
130             DBIx::Connection::Oracle::SQL::LOB_MAX_SIZE = (1024 * 1024 * 1024);
131              
132             =cut
133              
134             sub fetch_lob {
135 0     0 1   my ($class, $connection, $table_name, $lob_column_name, $primary_key_values, $lob_size_column_name) = @_;
136 0 0 0       confess "missing primary key for lob update on ${table_name}.${lob_column_name}"
137             if (! $primary_key_values || ! (%$primary_key_values));
138 0 0         confess "missing lob size column name" unless $lob_size_column_name;
139 0           my $lob_id = $class->_get_lob_id($connection, $table_name, $primary_key_values, $lob_column_name);
140 0           my $lob_size = $class->_get_lob_size($connection, $table_name, $primary_key_values, $lob_size_column_name);
141 0           $class->_read_lob($connection, $lob_id, $lob_size);
142             }
143              
144              
145              
146             =item _create_lob
147              
148             Creates lob
149              
150             =cut
151              
152             sub _create_lob {
153 0     0     my ($class, $connection, $lob) = @_;
154 0           my $dbh = $connection->dbh;
155 0           my $autocomit_mode = $connection->has_autocomit_mode;
156 0 0         $connection->begin_work if $autocomit_mode;
157 0           my $mode = $dbh->{pg_INV_WRITE};
158 0 0         my $lob_id = $dbh->func($mode, 'lo_creat')
159             or confess "can't create lob ". $!;
160 0           my $lobj_fd = $dbh->func($lob_id, $mode, 'lo_open');
161 0 0         confess "can't open lob ${lob_id}". $!
162             unless defined $lobj_fd;
163 0   0       my $length = length($lob || '');
164 0           my $offset = 0;
165 0           while($length > 0) {
166 0           $dbh->func($lobj_fd, $offset, 0, 'lo_lseek');
167 0 0         my $nbytes = $dbh->func($lobj_fd, substr($lob, $offset, $length), $length, 'lo_write')
168             or confess "can't write lob " . $!;
169 0           $offset += $nbytes;
170 0           $length -= $nbytes;
171             }
172 0           $dbh->func($lobj_fd, 'lo_close');
173 0 0         $connection->commit if ($autocomit_mode);
174 0           $lob_id;
175             }
176            
177              
178              
179             =item _read_lob
180              
181             Reads lob
182              
183             =cut
184              
185             sub _read_lob {
186 0     0     my ($class, $connection, $lob_id, $length) = @_;
187 0           my $dbh = $connection->dbh;
188 0           my $autocomit_mode = $connection->has_autocomit_mode;
189 0 0         $connection->begin_work if $autocomit_mode;
190 0           my $mode = $dbh->{pg_INV_READ};
191 0           my $lobj_fd = $dbh->func($lob_id, $mode, 'lo_open');
192 0 0         confess "can't open lob ${lob_id}". $!
193             unless defined $lobj_fd;
194 0           my $result = '';
195 0           my $buff = '';
196 0           my $offset = 0;
197 0           while(1) {
198 0           $dbh->func($lobj_fd, $offset, 0, 'lo_lseek');
199 0           my $nbytes = $dbh->func($lobj_fd, $buff, $length, 'lo_read');
200 0 0         confess "can't read lob ${lob_id}" . $!
201             unless defined $nbytes;
202 0           $result .= $buff;
203 0           $offset += $nbytes;
204 0 0         last if ($offset == $length);
205             }
206 0           $dbh->func($lobj_fd, 'lo_close');
207 0 0         $connection->commit if ($autocomit_mode);
208 0           $result
209             }
210            
211              
212             =item _unlnik_lob
213              
214             Removes lob.
215              
216             =cut
217              
218             sub _unlink_lob {
219 0     0     my ($class, $connection, $lob_id) = @_;
220 0 0         return unless $lob_id;
221 0           my $dbh = $connection->dbh;
222 0           my $autocomit_mode = $connection->has_autocomit_mode;
223 0 0         $connection->begin_work if $autocomit_mode;
224 0 0         $dbh->func($lob_id, 'lo_unlink')
225             or confess "can't unlink lob ${lob_id}". $!;
226 0 0         $connection->commit if ($autocomit_mode);
227             }
228              
229              
230             =item _get_lob_size
231              
232             Returns lob size.
233              
234             =cut
235              
236             sub _get_lob_size {
237 0     0     my ($class, $connection, $table_name, $primary_key_values, $lob_size_column_name) = @_;
238 0           my $resut;
239 0 0         if($lob_size_column_name) {
240 0           my $sql = "SELECT ${lob_size_column_name} as lob_size FROM ${table_name} " . $connection->_where_clause($primary_key_values);
241 0           my ($record) = $connection->record($sql, map { $primary_key_values->{$_}} sort keys %$primary_key_values);
  0            
242 0           $resut = $record->{lob_size};
243             }
244 0 0         $resut || $LOB_MAX_SIZE;
245             }
246              
247              
248             =item _get_lob_id
249              
250             Returns lob oid.
251              
252             =cut
253              
254             sub _get_lob_id {
255 0     0     my ($class, $connection, $table_name, $primary_key_values, $lob_column_name) = @_;
256 0           my $resut;
257 0           my $sql = "SELECT ${lob_column_name} as lob_id FROM ${table_name} " . $connection->_where_clause($primary_key_values);
258 0           my ($record) = $connection->record($sql, map { $primary_key_values->{$_}} sort keys %$primary_key_values);
  0            
259 0           $resut = $record->{lob_id};
260             }
261              
262             1;
263              
264             __END__