File Coverage

blib/lib/DBIx/Connection/PostgreSQL/PLSQL.pm
Criterion Covered Total %
statement 18 63 28.5
branch 0 10 0.0
condition 0 3 0.0
subroutine 6 15 40.0
pod 9 9 100.0
total 33 100 33.0


line stmt bran cond sub pod time code
1             package DBIx::Connection::PostgreSQL::PLSQL;
2              
3              
4 1     1   5191 use warnings;
  1         3  
  1         36  
5 1     1   6 use strict;
  1         2  
  1         36  
6              
7 1     1   6 use Abstract::Meta::Class ':all';
  1         1  
  1         191  
8 1     1   6 use Carp 'confess';
  1         1  
  1         50  
9 1     1   5 use base qw(DBIx::PLSQLHandler);
  1         2  
  1         97  
10              
11 1     1   5 use vars qw($VERSION);
  1         2  
  1         873  
12              
13             $VERSION = 0.02;
14              
15             =head1 NAME
16              
17             DBIx::Connection::PostgreSQL::PLSQL - PLSQL block wrapper for PostgreSQL
18              
19             =head1 SYNOPSIS
20              
21             use DBIx::PLSQLHandler;
22              
23             my $plsql_handler = new DBIx::PLSQLHandler(
24             name => 'test_proc',
25             connection => $connection,
26             plsql => "
27             DECLARE
28             var1 INT;
29             BEGIN
30             var1 := :var2 + :var3;
31             END;",
32             bind_variables => {
33             var2 => {type => 'SQL_INTEGER'},
34             var3 => {type => 'SQL_INTEGER'}
35             }
36             );
37             $plsql_handler->execute(var2 => 12, var3 => 8);
38              
39             or
40              
41             use DBIx::Connection;
42              
43              
44             my $plsql_handler = $connection->plsql_handler(
45             name => 'test_proc',
46             connection => $connection,
47             plsql => "
48             DECLARE
49             var1 INT;
50             BEGIN
51             :var1 := :var2 + :var3;
52             END;",
53             bind_variables => {
54             var1 => {type => 'SQL_INTEGER'},
55             var2 => {type => 'SQL_INTEGER'},
56             var3 => {type => 'SQL_INTEGER'}
57             }
58             );
59              
60             my $result_set = $plsql_handler->execute(var2 => 12, var3 => 8);
61              
62              
63             =head1 DESCRIPTION
64              
65             This class creates and invokes plsql function dynamicly that wraps
66             defined plsql block. This module check if body of plsql block has been changed
67             then it recreated wraper function for changed plsql block
68              
69             =cut
70              
71             =head2 METHODS
72              
73             =over
74              
75             =cut
76              
77             {
78             my %SQL = (
79             find_function => 'SELECT prosrc AS routine_definition FROM pg_proc WHERE proname = ? ',
80             function_args => 'SELECT t.typname, t.oid, p.proargtypes FROM pg_proc p JOIN pg_type t ON t.oid = ANY (p.proallargtypes) WHERE p.proname = ? '
81             );
82              
83             =item sql_defintion
84              
85             Return sql statement defintion. Takes sql name.
86              
87             =cut
88              
89             sub sql_defintion {
90 0     0 1   my ($self, $name) = @_;
91 0           $SQL{$name};
92             }
93             }
94              
95              
96             =item prepare
97              
98             Prepares plsql block
99              
100             =cut
101              
102             sub prepare {
103 0     0 1   my ($self) = @_;
104 0           $self->initialise_plsql_block();
105 0           $self->initialise_sql();
106             }
107              
108              
109             =item initialise_plsql_block
110              
111             Initialises plsql block, checks for changes, recreated if necessary.
112              
113             =cut
114              
115             sub initialise_plsql_block {
116 0     0 1   my ($self) = @_;
117 0           my @binded_out_variables = $self->binded_out_variables;
118 0 0         unless (@binded_out_variables) {
119 0           $self->push_bind_out_variables('result');
120 0           $self->bind_variable(result => $self->default_variable_info(binding => 'out'));
121             }
122 0           my $plsql_block_wrapper = $self->plsql_block_wrapper;
123 0 0         if($self->is_block_changed($self->plsql_block_name)) {
124 0           $self->connection->do($plsql_block_wrapper);
125             }
126             }
127              
128             =item drop_plsql_block
129              
130             Removes existing function that acts as plsql block wrapper.
131              
132             =cut
133              
134             sub drop_plsql_block {
135 0     0 1   my ($self) = @_;
136 0           my $connection = $self->connection;
137 0           my $cursor = $connection->query_cursor(sql => $self->sql_defintion('function_args'));
138 0           $cursor->execute([$self->plsql_block_name]);
139 0           my $args;
140 0           while (my ($typname, $oid, $proargtypes) = $cursor->fetch) {
141 0   0       $args ||= join (",", split /\s+/, $proargtypes);
142 0 0         $args =~ s/$oid/$typname/g if $oid;
143             }
144 0           $connection->do("DROP FUNCTION " . $self->plsql_block_name . "($args)" );
145             }
146              
147              
148             =item plsql_block_wrapper
149              
150             Returns plsql block weapper as plsql function
151              
152             =cut
153              
154             sub plsql_block_wrapper {
155 0     0 1   my ($self) = @_;
156 0           'CREATE FUNCTION ' . $self->plsql_block_name . '(' . $self->plsql_block_declaration . ') AS $$'
157             . "\n" . $self->block_source . "\n"
158             . '$$ LANGUAGE plpgsql;';
159             }
160              
161              
162              
163             =item initialise_sql
164              
165             Initialises sql that will be used to invoke postgres function (plsql block)
166              
167             =cut
168              
169             sub initialise_sql {
170 0     0 1   my ($self) = @_;
171 0           my @bind_in_variables = $self->binded_in_variables;
172 0           my @bind_out_variables = $self->binded_out_variables;
173 0           $self->set_sql(scalar(@bind_out_variables) == 1
174 0           ? "SELECT " . $self->plsql_block_name . '(' . join (",", ,map {'?'} @bind_in_variables) . ') AS ' . $bind_out_variables[0]
175 0 0         : "SELECT " . (join ",", (map { '(f.func).' . $_ } @bind_out_variables)) . " FROM (SELECT " . $self->plsql_block_name . '(' . join (",", ,map {'?'} @bind_in_variables) . ') AS func) f');
  0            
176             }
177              
178              
179             =item execute
180              
181             Binds and executes plsql block.
182              
183             =cut
184              
185             sub execute {
186 0     0 1   my ($self, %bind_variables) = @_;
187 0           my @bind_in_variables = $self->binded_in_variables;
188 0           my $connection = $self->connection;
189 0           $connection->no_cache(1);
190 0           my $result_set;
191 0           eval {$result_set = $self->connection->record($self->sql, map {$bind_variables{$_}} @bind_in_variables);};
  0            
  0            
192 0           $connection->no_cache(0);
193 0 0         die $@ if $@;
194 0           $result_set ;
195             }
196              
197              
198             =item type_precision
199              
200             Returns variable precision.
201              
202             =cut
203              
204 0     0 1   sub type_precision {''}
205              
206              
207             {
208             =item type_map
209              
210             Mapping between DBI and specyfic postgres types.
211             The following mapping is defined:
212              
213             SQL_DECIMAL => 'numeric',
214             SQL_VARCHAR => 'varchar',
215             SQL_DATE =>'date',
216             SQL_CHAR =>'varchar',
217             SQL_DOUBLE =>'float8',
218             SQL_INTEGER =>'int4',
219             SQL_BOOLEAN =>'boolean',
220              
221             =cut
222              
223             my %type_map = (
224             SQL_DECIMAL => 'numeric',
225             SQL_VARCHAR => 'varchar',
226             SQL_DATE =>'date',
227             SQL_CHAR =>'varchar',
228             SQL_DOUBLE =>'float8',
229             SQL_INTEGER =>'int4',
230             SQL_BOOLEAN =>'boolean',
231             );
232              
233              
234             =item get_type
235              
236             Returns
237              
238             =cut
239              
240             sub get_type {
241 0     0 1   my ($class, $type) = @_;
242 0           $type_map{$type};
243             }
244             }
245              
246              
247             1;
248              
249             __END__