line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PostgreSQL::PLPerl::Call; |
2
|
|
|
|
|
|
|
our $VERSION = '1.006'; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
PostgreSQL::PLPerl::Call - Simple interface for calling SQL functions from PostgreSQL PL/Perl |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
version 1.006 |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use PostgreSQL::PLPerl::Call; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Returning single-row single-column values: |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
$pi = call('pi'); # 3.14159265358979 |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
$net = call('network(inet)', '192.168.1.5/24'); # '192.168.1.0/24'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$seqn = call('nextval(regclass)', $sequence_name); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
$dims = call('array_dims(text[])', '{a,b,c}'); # '[1:3]' |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# array arguments can be perl array references: |
27
|
|
|
|
|
|
|
$ary = call('array_cat(int[], int[])', [1,2,3], [2,1]); # '{1,2,3,2,1}' |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
Returning multi-row single-column values: |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
@ary = call('generate_series(int,int)', 10, 15); # (10,11,12,13,14,15) |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Returning single-row multi-column values: |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# assuming create function func(int) returns table (r1 text, r2 int) ... |
36
|
|
|
|
|
|
|
$row = call('func(int)', 42); # returns hash ref { r1=>..., r2=>... } |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Returning multi-row multi-column values: |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
@rows = call('pg_get_keywords'); # ({...}, {...}, ...) |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
Alternative method-call syntax: |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
$pi = PG->pi(); |
45
|
|
|
|
|
|
|
$seqn = PG->nextval($sequence_name); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Here C simply means PostgreSQL. (C is actually an imported constant whose |
48
|
|
|
|
|
|
|
value is the name of a package containing an AUTOLOAD function that dispatches |
49
|
|
|
|
|
|
|
to C. In case you wanted to know.) |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 DESCRIPTION |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
The C function provides a simple efficient way to call SQL functions |
54
|
|
|
|
|
|
|
from PostgreSQL PL/Perl code. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
The first parameter is a I that specifies the name of the function |
57
|
|
|
|
|
|
|
to call and, optionally, the types of the arguments. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Any further parameters are used as argument values for the function being called. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head2 Signature |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
The first parameter to C is a I that specifies the name of |
64
|
|
|
|
|
|
|
the function. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Immediately after the function name, in parenthesis, a comma separated list of |
67
|
|
|
|
|
|
|
type names can be given. For example: |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
'pi' |
70
|
|
|
|
|
|
|
'generate_series(int,int)' |
71
|
|
|
|
|
|
|
'array_cat(int[], int[])' |
72
|
|
|
|
|
|
|
'myschema.myfunc(date, float8)' |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
The types specify how the I to the call should be interpreted. |
75
|
|
|
|
|
|
|
They don't have to exactly match the types used to declare the function you're |
76
|
|
|
|
|
|
|
calling. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
You also don't have to specify types for I the arguments, just the |
79
|
|
|
|
|
|
|
left-most arguments that need types. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The function name should be given in the same way it would in an SQL statement, |
82
|
|
|
|
|
|
|
so if identifier quoting is needed it should be specified already enclosed in |
83
|
|
|
|
|
|
|
double quotes. For example: |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
call('myschema."Foo Bar"'); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 Array Arguments |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
The argument value corresponding to a type that contains 'C<[]>' can be a |
90
|
|
|
|
|
|
|
string formated as an array literal, or a reference to a perl array. In the |
91
|
|
|
|
|
|
|
later case the array reference is automatically converted into an array literal |
92
|
|
|
|
|
|
|
using the C function. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head2 Varadic Functions |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Functions with C arguments can be called with a fixed number of |
97
|
|
|
|
|
|
|
arguments by repeating the type name in the signature the same number of times. |
98
|
|
|
|
|
|
|
For example, given: |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
create function vary(VARIADIC int[]) as ... |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
you can call that function with three arguments using: |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
call('vary(int,int,int)', $int1, $int2, $int3); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Alternatively, you can append the string 'C<...>' to the last type in the |
107
|
|
|
|
|
|
|
signature to indicate that the argument is variadic. For example: |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
call('vary(int...)', @ints); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Type names must be included in the signature in order to call variadic functions. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Functions with a variadic argument must have at least one value for that |
114
|
|
|
|
|
|
|
argument. Otherwise you'll get a "function ... does not exist" error. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 Method-call Syntax |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
An alternative syntax can be used for making calls: |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
PG->function_name(@args) |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
For example: |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
$pi = PG->pi(); |
125
|
|
|
|
|
|
|
$seqn = PG->nextval($sequence_name); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Using this form you can't easily specify a schema name or argument types, and |
128
|
|
|
|
|
|
|
you can't call variadic functions. (For various technical reasons.) |
129
|
|
|
|
|
|
|
In cases where a signature is needed, like variadic or polymorphic functions, |
130
|
|
|
|
|
|
|
you might get a somewhat confusing error message. For example: |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
PG->generate_series(10,20); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
fails with the error "there is no parameter $1". The underlying problem is that |
135
|
|
|
|
|
|
|
C is a polymorphic function: different versions of the |
136
|
|
|
|
|
|
|
function are executed depending on the type of the arguments. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 Wrapping and Currying |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
It's simple to wrap a call into an anonymous subroutine and pass that code |
141
|
|
|
|
|
|
|
reference around. For example: |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
$nextval_fn = sub { PG->nextval(@_) }; |
144
|
|
|
|
|
|
|
... |
145
|
|
|
|
|
|
|
$val = $nextval_fn->($sequence_name); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
or |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
$some_func = sub { call('some_func(int, date[], int)', @_) }; |
150
|
|
|
|
|
|
|
... |
151
|
|
|
|
|
|
|
$val = $some_func->($foo, \@dates, $debug); |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
You can take this approach further by specifying some of the arguments in the |
154
|
|
|
|
|
|
|
anonymous subroutine so they don't all have to be provided in the call: |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
$some_func = sub { call('some_func(int, date[], int)', $foo, shift, $debug) }; |
157
|
|
|
|
|
|
|
... |
158
|
|
|
|
|
|
|
$val = $some_func->(\@dates); |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 Results |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
The C function processes return values in one of four ways depending on |
164
|
|
|
|
|
|
|
two criteria: single column vs. multi-column results, and list context vs scalar context. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
If the results contain a single column with the same name as the function that |
167
|
|
|
|
|
|
|
was called, then those values are extracted and returned directly. This makes |
168
|
|
|
|
|
|
|
simple calls very simple: |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
@ary = call('generate_series(int,int)', 10, 15); # (10,11,12,13,14,15) |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Otherwise, the rows are returned as references to hashes: |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
@rows = call('pg_get_keywords'); # ({...}, {...}, ...) |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
If the C function was executed in list context then all the values/rows |
177
|
|
|
|
|
|
|
are returned, as shown above. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
If the function was executed in scalar context then an exception will be thrown |
180
|
|
|
|
|
|
|
if more than one row is returned. For example: |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
$foo = call('generate_series(int,int)', 10, 10); # 10 |
183
|
|
|
|
|
|
|
$bar = call('generate_series(int,int)', 10, 11); # dies |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
If you only want the first result you can use list context; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
($bar) = call('generate_series(int,int)', 10, 11); |
188
|
|
|
|
|
|
|
$bar = (call('generate_series(int,int)', 10, 11))[0]; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=head1 ENABLING |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
In order to use this module you need to arrange for it to be loaded when |
193
|
|
|
|
|
|
|
PostgreSQL initializes a Perl interpreter. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Create a F file in the same directory as your |
196
|
|
|
|
|
|
|
F file, if it doesn't exist already. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
In the F file write the code to load this module. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 PostgreSQL 8.x |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Set the C before starting postgres, to something like this: |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
PERL5OPT='-e "require q{plperlinit.pl}"' |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
The code in the F should also include C |
207
|
|
|
|
|
|
|
to avoid any problems with nested invocations of perl, e.g., via a C |
208
|
|
|
|
|
|
|
function. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head2 PostgreSQL 9.0 |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
For PostgreSQL 9.0 you can still use the C method described above. |
213
|
|
|
|
|
|
|
Alternatively, and preferably, you can use the C configuration |
214
|
|
|
|
|
|
|
variable in the F file. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
plperl.on_init='require q{plperlinit.pl};' |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head plperl |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
You can use the L module to make the |
221
|
|
|
|
|
|
|
call() function available for use in the C language: |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
use PostgreSQL::PLPerl::Injector; |
224
|
|
|
|
|
|
|
inject_plperl_with_names_from(PostgreSQL::PLPerl::Call => 'call'); |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head1 OTHER INFORMATION |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 Performance |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Internally C uses C to create a plan to execute the |
231
|
|
|
|
|
|
|
function with the typed arguments. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
The plan is cached using the call 'signature' as the key. Minor variations in |
234
|
|
|
|
|
|
|
the signature will still reuse the same plan. |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
For variadic functions, separate plans are created and cached for each distinct |
237
|
|
|
|
|
|
|
number of arguments the function is called with. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head2 Limitations and Caveats |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Requires PostgreSQL 9.0 or later. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Types that contain a comma can't be used in the call signature. That's not a |
244
|
|
|
|
|
|
|
problem in practice as it only affects 'C' and 'C' |
245
|
|
|
|
|
|
|
and the 'C<,s>' part isn't needed. Typically the 'C<(p,s)>' portion isn't used in |
246
|
|
|
|
|
|
|
signatures. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
The return value of functions that have a C return type should not be |
249
|
|
|
|
|
|
|
relied upon, naturally. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 Author and Copyright |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Tim Bunce L |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Copyright (c) Tim Bunce, Ireland, 2010. All rights reserved. |
256
|
|
|
|
|
|
|
You may use and distribute on the same terms as Perl 5.10.1. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
With thanks to L for sponsoring development. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=cut |
261
|
|
|
|
|
|
|
|
262
|
1
|
|
|
1
|
|
1193
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
263
|
1
|
|
|
1
|
|
7
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
33
|
|
264
|
1
|
|
|
1
|
|
14
|
use Exporter; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
48
|
|
265
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
247
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
268
|
|
|
|
|
|
|
our @EXPORT = qw(call PG); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
my %sig_cache; |
271
|
|
|
|
|
|
|
our $debug = 0; |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# encapsulated package to provide an AUTOLOAD interface to call() |
274
|
1
|
|
|
|
|
2
|
use constant PG => do { |
275
|
|
|
|
|
|
|
package PostgreSQL::PLPerl::Call::PG; |
276
|
1
|
|
|
|
|
2
|
our $VERSION = '1.006'; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub AUTOLOAD { |
279
|
|
|
|
|
|
|
#(my $function = our $AUTOLOAD) =~ s/.*:://; |
280
|
0
|
|
|
0
|
|
|
our $AUTOLOAD =~ s/.*:://; |
281
|
0
|
|
|
|
|
|
shift; |
282
|
0
|
|
|
|
|
|
return PostgreSQL::PLPerl::Call::call($AUTOLOAD, @_); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
1
|
|
|
|
|
1225
|
__PACKAGE__; |
286
|
1
|
|
|
1
|
|
6
|
}; |
|
1
|
|
|
|
|
2
|
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub call { |
290
|
0
|
|
|
0
|
0
|
|
my $sig = shift; |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
my $arity = scalar @_; # argument count to handle variadic subs |
293
|
|
|
|
|
|
|
|
294
|
0
|
|
0
|
|
|
|
my $how = $sig_cache{"$sig.$arity"} ||= do { |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# get a normalized signature to recheck the cache with |
297
|
|
|
|
|
|
|
# and also extract the SP name and argument types |
298
|
0
|
0
|
|
|
|
|
my ($stdsig, $fullspname, $spname, $arg_types) = _parse_signature($sig, $arity) |
299
|
|
|
|
|
|
|
or croak "Can't parse '$sig'"; |
300
|
0
|
0
|
|
|
|
|
warn "parsed call($sig) => $stdsig\n" |
301
|
|
|
|
|
|
|
if $debug; |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# recheck the cache with with the normalized signature |
304
|
0
|
|
0
|
|
|
|
$sig_cache{"$stdsig.$arity"} ||= [ # else a new entry (for both caches) |
305
|
|
|
|
|
|
|
$spname, # is name of column for single column results |
306
|
|
|
|
|
|
|
scalar _mk_process_args($arg_types), |
307
|
|
|
|
|
|
|
scalar _mk_process_call($fullspname, $arity, $arg_types), |
308
|
|
|
|
|
|
|
$fullspname, # is name used in SQL to make the call |
309
|
|
|
|
|
|
|
$stdsig, |
310
|
|
|
|
|
|
|
]; |
311
|
|
|
|
|
|
|
}; |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
my ($spname, $prepargs, $callsub) = @$how; |
314
|
|
|
|
|
|
|
|
315
|
0
|
0
|
|
|
|
|
my $rv = $callsub->( $prepargs ? $prepargs->(@_) : @_ ); |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
|
my $rows = $rv->{rows}; |
318
|
0
|
0
|
|
|
|
|
my $row1 = $rows->[0] # peek at first row |
319
|
|
|
|
|
|
|
or return; # no row: undef in scalar context else empty list |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
0
|
|
|
|
my $is_single_column = (keys %$row1 == 1 and exists $row1->{$spname}); |
322
|
|
|
|
|
|
|
|
323
|
0
|
0
|
|
|
|
|
if (wantarray) { # list context - all rows |
|
|
0
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
0
|
0
|
|
|
|
|
return map { $_->{$spname} } @$rows if $is_single_column; |
|
0
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
return @$rows; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
elsif (defined wantarray) { # scalar context - single row |
329
|
|
|
|
|
|
|
|
330
|
0
|
0
|
|
|
|
|
croak "$sig was called in scalar context but returned more than one row" |
331
|
|
|
|
|
|
|
if @$rows > 1; |
332
|
|
|
|
|
|
|
|
333
|
0
|
0
|
|
|
|
|
return $row1->{$spname} if $is_single_column; |
334
|
0
|
|
|
|
|
|
return $row1; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
# else void context - nothing to do |
337
|
0
|
|
|
|
|
|
return; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub _parse_signature { |
342
|
0
|
|
|
0
|
|
|
my ($sig, $arity) = @_; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# extract types from signature, if any |
345
|
0
|
|
|
|
|
|
my $arg_types; |
346
|
0
|
0
|
|
|
|
|
if ($sig =~ s/\s*\((.*?)\)\s*$//) { |
347
|
0
|
|
|
|
|
|
$arg_types = [ split(/\s*,\s*/, lc($1), -1) ]; |
348
|
0
|
|
|
|
|
|
s/^\s+// for @$arg_types; |
349
|
0
|
|
|
|
|
|
s/\s+$// for @$arg_types; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# if variadic, replace '...' marker with the appropriate number |
352
|
|
|
|
|
|
|
# of copies of the preceding type name |
353
|
0
|
0
|
0
|
|
|
|
if (@$arg_types and $arg_types->[-1] =~ s/\s*\.\.\.//) { |
354
|
0
|
|
|
|
|
|
my $variadic_type = pop @$arg_types; |
355
|
0
|
|
|
|
|
|
push @$arg_types, $variadic_type |
356
|
|
|
|
|
|
|
until @$arg_types >= $arity; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# the full name is what's left in sig |
361
|
0
|
|
|
|
|
|
my $fullspname = $sig; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# extract the function name and un-escape it to get the column name |
364
|
0
|
|
|
|
|
|
(my $spname = $fullspname) =~ s/.*\.//; # remove schema, if any |
365
|
0
|
0
|
|
|
|
|
if ($spname =~ s/^"(.*)"$/$1/) { # unescape |
366
|
0
|
|
|
|
|
|
$spname =~ s/""/"/; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# compose a normalized signature |
370
|
0
|
0
|
|
|
|
|
my $stdsig = "$fullspname". |
371
|
|
|
|
|
|
|
($arg_types ? "(".join(",",@$arg_types).")" : ""); |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
return ($stdsig, $fullspname, $spname, $arg_types); |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub _mk_process_args { |
378
|
0
|
|
|
0
|
|
|
my ($arg_types) = @_; |
379
|
|
|
|
|
|
|
|
380
|
0
|
0
|
|
|
|
|
return undef unless $arg_types; |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# return a closure that pre-processes the arguments of the call |
383
|
|
|
|
|
|
|
# else undef if no argument pre-processing is required |
384
|
|
|
|
|
|
|
|
385
|
0
|
|
|
|
|
|
my $hooks; |
386
|
0
|
|
|
|
|
|
my $i = 0; |
387
|
0
|
|
|
|
|
|
for my $type (@$arg_types) { |
388
|
0
|
0
|
|
|
|
|
if ($type =~ /\[/) { # ARRAY |
389
|
0
|
|
|
0
|
|
|
$hooks->{$i} = sub { return ::encode_array_literal(shift) }; |
|
0
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
} |
391
|
0
|
|
|
|
|
|
++$i; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
0
|
0
|
|
|
|
|
return undef unless $hooks; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
my $sub = sub { |
397
|
0
|
|
|
0
|
|
|
my @args = @_; |
398
|
0
|
|
|
|
|
|
while ( my ($argidx, $preproc) = each %$hooks ) { |
399
|
0
|
|
|
|
|
|
$args[$argidx] = $preproc->($args[$argidx]); |
400
|
|
|
|
|
|
|
} |
401
|
0
|
|
|
|
|
|
return @args; |
402
|
0
|
|
|
|
|
|
}; |
403
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
return $sub; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub _mk_process_call { |
409
|
0
|
|
|
0
|
|
|
my ($fullspname, $arity, $arg_types) = @_; |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# return a closure that will execute the query and return result ref |
412
|
|
|
|
|
|
|
|
413
|
0
|
|
|
|
|
|
my $placeholders = join ",", map { '$'.$_ } 1..$arity; |
|
0
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
my $sql = "select * from $fullspname($placeholders)"; |
415
|
0
|
0
|
|
|
|
|
my $plan = eval { ::spi_prepare($sql, $arg_types ? @$arg_types : ()) }; |
|
0
|
|
|
|
|
|
|
416
|
0
|
0
|
|
|
|
|
if ($@) { # internal error, should never happen |
417
|
0
|
|
|
|
|
|
chomp $@; |
418
|
0
|
|
|
|
|
|
croak "$@ while preparing $sql"; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
my $sub = sub { |
422
|
|
|
|
|
|
|
# XXX need to catch exceptions from here and rethrow using croak |
423
|
|
|
|
|
|
|
# to appear to come from the callers location (outside this package) |
424
|
0
|
0
|
|
0
|
|
|
warn "calling $sql(@_) [@{$arg_types||[]}]" |
|
0
|
0
|
|
|
|
|
|
425
|
|
|
|
|
|
|
if $debug; |
426
|
0
|
|
|
|
|
|
return ::spi_exec_prepared($plan, @_) |
427
|
0
|
|
|
|
|
|
}; |
428
|
|
|
|
|
|
|
|
429
|
0
|
|
|
|
|
|
return $sub; |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
1; |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=begin Pod::Coverage |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
call |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=end Pod::Coverage |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
# vim: ts=8:sw=4:sts=4:et |