6
use Symbol qw(delete_package);
10
our @ISA = qw(Exporter);
12
# Items to export into callers namespace by default. Note: do not export
13
# names by default without a very good reason. Use EXPORT_OK instead.
14
# Do not simply export all your public functions/methods/constants.
16
# This allows declaration use MySQLUDF ':all';
17
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
19
our %EXPORT_TAGS = ( 'all' => [ qw(
23
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
29
our $VERSION = '0.01';
32
XSLoader::load('MySQLUDF', $VERSION);
36
# Preloaded methods go here.
38
sub valid_package_name
41
$string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
42
# second pass only for words starting with a digit
43
$string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
44
# Dress it up as a real package name
46
return "MyUDF" . $string;
52
my ($filename,$funcname)= @_;
53
my $package= valid_package_name($filename);
54
if (!defined $Cache{$package})
58
'my (%filename,$package,$mtime,$funcname);'.
62
'die "not found" if eval "!defined &'.$filename.'::$func";'.
63
'my $function= eval \'\\&'.$filename.'::\'.$func;'.
64
'die "unknown error" if !defined $function;'.
65
'my $prototype= prototype $function;'.
66
'my @ref= ($function, $prototype);'.
68
'} return \&'.$package.'::handler;';
70
$Cache{$package}= $handler;
72
my $func= $Cache{$package}->($funcname);
79
die "unknown error" if !defined $udf_name;
80
die "bad routine name" if !($udf_name=~ m/::([^:]+)$/);
81
my ($filename, $funcname)= ($`,$1);
82
return load_func($filename,$funcname);
91
my $arg_count= $context->get_arg_count();
94
for ($idx= 0; $idx < $arg_count; $idx++)
97
$arg= $context->val_string($idx) if !($context->val_null($idx));
105
my ($prototype,$parameters,$references,$arguments,$index)= @_;
107
if ('\$' eq $prototype)
109
my $value= $arguments->[$index];
110
push @$references,$index;
111
push @$parameters, \$value;
112
$arguments->[$index++]= \$value;
114
elsif ('$' eq $prototype)
116
push @$parameters, $arguments->[$index++];
118
elsif ('\@' eq $prototype)
120
while ($index < scalar @$arguments)
122
push @$references,$index;
123
push @$parameters, $arguments->[$index++];
126
elsif ('@' eq $prototype)
128
while ($index < scalar @$arguments)
130
push @$parameters, $arguments->[$index++];
135
die "Unsupported argument type in routine prototype"
142
my ($prototype,$arguments,$references)= @_;
146
while ( $prototype=~ m/\G(\\?[\$\@\%\&\*])/g )
148
die 'Insufficient number of parameters' if $index >= scalar @$arguments;
149
$index= handle_arg($1, \@parameters, $references, $arguments, $index);
152
if ($prototype=~ m/;/)
155
while ( $prototype=~ m/\G(\\?[\$\@\%\&\*])/g )
157
last if $index >= scalar @$arguments;
158
$index= handle_arg($1, \@parameters, $references, $arguments, $index);
162
# For now, just shove the surplus arguments on the stack
163
while ($index < scalar @$arguments)
165
push @parameters, $arguments->[$index++];
173
my ($context,$elem,$idx)= @_;
174
$idx=-1 if !defined $idx;
175
$elem= $$elem while 'SCALAR' eq ref $elem;
176
return $context->store_string($idx,"$elem") if defined $elem;
177
return $context->store_null($idx);
182
my ($context,$cols,$row)= @_;
183
$context->row_prepare();
187
send_elem($context,$row->{$_});
189
return $context->row_send();
194
my ($result,$row)= @_;
197
my $elem= $row->{$_};
198
my $length= length "$elem";
199
next if (defined $result->{$_}) && ($length < $result->{$_});
200
$result->{$_}= $length;
208
my ($data,$type)= @_;
210
for ($idx= 0; $idx < scalar @$data; $idx++)
212
return 0 if $type ne ref $data->[$idx];
217
sub send_resultset($$;$)
219
my ($context,$result,$cols)= @_;
222
for ($idx= 0; $idx < scalar @$result; $idx++)
224
$columns= gather_columns($columns, $result->[$idx]);
228
my @sorted_cols= sort keys %$columns;
229
$cols= \@sorted_cols;
233
die "Unable to send column specifications" if
234
$context->row_field("$_", 254, $columns->{$_});
236
for ($idx= 0; $idx < scalar @$result; $idx++)
238
die "Failed to send row result" if
239
send_row($context,$cols,$result->[$idx]);
241
$context->row_send_eof();
249
die "undefined context" if !defined $context;
250
die "undefined function" if !defined $func;
252
my @arguments= get_args($context);
255
if (defined $func->[1])
258
my $parameters= make_args($func->[1], \@arguments, \@references);
260
$result= $func->[0]->(@$parameters);
262
# If the prototype contains references, then we need
263
# to return values back to the caller.
265
foreach (@references)
267
die "Failed to store back parameter $_" if
268
send_elem($context, $arguments[$_], $_);
273
# We don't have a function prototype so assume the
274
# simple case of a simple function call...
275
$result= $func->[0]->(@arguments);
280
if ('HASH' eq ref $result)
283
$columns= gather_columns($columns, $result);
284
my @cols= sort keys %$columns;
287
die "Unable to send column specifications" if
288
$context->row_field("$_", 254, $columns->{$_});
290
die "Failed to send row result" if
291
send_row($context,\@cols,$result);
292
$context->row_send_eof();
294
elsif (('ARRAY' eq ref $result) && allref($result,'HASH'))
296
send_resultset($context, $result);
298
elsif (('ARRAY' eq ref $result) && allref($result,'ARRAY'))
303
for ($idx=0; $idx < scalar @$result; $idx++)
305
my $source= $result->[$idx];
308
for ($col=0; $col < scalar @$source; $col++)
310
$row{$col}= $source->[$col];
312
while (scalar @columns < scalar @$source)
314
push @columns, scalar @columns;
316
push @resultset, \%row;
318
send_resultset($context, \@resultset, \@columns);
320
elsif ('ARRAY' eq ref $result)
326
for ($idx=0; $idx < scalar @$result; $idx++)
328
$hash_result{$idx}= $result->[$idx];
331
push @resultset, \%hash_result;
332
send_resultset($context, \@resultset, \@columns);
336
die "Unable to store result" if
337
$context->store_string(-1, "$result");
342
# we ignore any error result here because we may be
343
# called as a procedure with no resultsets
344
$context->store_null(-1);
353
return eval 'require DBD::mysql;1';
358
# Below is stub documentation for your module. You'd better edit it!
362
MySQLUDF - Perl extension for blah blah blah
371
Stub documentation for MySQLUDF, created by h2xs. It looks like the
372
author of the extension was negligent enough to leave the stub
385
Mention other useful documentation such as the documentation of
386
related modules or operating system documentation (such as man pages
387
in UNIX), or any relevant external documentation such as RFCs or
390
If you have a mailing list set up for your module, mention it here.
392
If you have a web site set up for your module, mention it here.
396
Antony T Curtis, E<lt>antony@mysql.comE<gt>
398
=head1 COPYRIGHT AND LICENSE
400
Copyright (C) 2007 MySQL AB
402
This program is free software; you can redistribute it and/or modify
403
it under the terms of the GNU General Public License as published by
404
the Free Software Foundation; version 2 of the License.