Your SlideShare is downloading. ×
Using Perl Stored Procedures for MariaDB
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Using Perl Stored Procedures for MariaDB

1,674
views

Published on

https://www.percona.com/live/mysql-conference-2013/sessions/perl-stored-procedures-mariadb …

https://www.percona.com/live/mysql-conference-2013/sessions/perl-stored-procedures-mariadb

Published in: Technology

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,674
On Slideshare
0
From Embeds
0
Number of Embeds
28
Actions
Shares
0
Downloads
14
Comments
0
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Using Perl StoredProcedureswith MariaDBAntony T Curtis <atcurtis@gmail.com>Special thanks to LinkedIn for permitting personal projects
  • 2. Why Perl?• CPAN• "Multiplicity" / Thread-friendly.• Lots of Perl code already written.• MySQL UDFs have no access control.• MySQL UDFs cannot execute dynamic SQL.• Faster than “native” Stored Procedures.
  • 3. Perl Stored Procedures• Implemented as Perl modules.• Use DBD::mysql to access database.• Runs in-process with MariaDB.• Easier to debug than SQL stored routines.
  • 4. Hello WorldMariaDB [Demo]> CREATE PROCEDURE PerlHello()-> DYNAMIC RESULT SETS 1-> NO SQL-> LANGUAGE Perl-> EXTERNAL NAME "HelloWorld::test";Query OK, 0 rows affected (0.02 sec)MariaDB [Demo]> call PerlHello();+-----------------------+| message |+-----------------------+| Hello World from Perl |+-----------------------+1 row in set (0.03 sec)Query OK, 0 rows affected (0.03 sec)package HelloWorld;# put this file in <prefix>/lib/mysql/perluse 5.008008;use strict;use warnings;use Symbol qw(delete_package);require Exporter;our @ISA = qw(Exporter);our @EXPORT_OK = qw( );our @EXPORT = qw( test );our $VERSION = 0.01;sub test(){return {message => Hello World from Perl,};}1;
  • 5. Hello WorldMariaDB [Demo]> CREATE PROCEDURE PerlHello()-> DYNAMIC RESULT SETS 1-> NO SQL-> LANGUAGE Perl-> EXTERNAL NAME "HelloWorld::test";Query OK, 0 rows affected (0.02 sec)MariaDB [Demo]> call PerlHello();+-----------------------+| message |+-----------------------+| Hello World from Perl |+-----------------------+1 row in set (0.03 sec)Query OK, 0 rows affected (0.03 sec)package HelloWorld;# put this file in <prefix>/lib/mysql/perluse 5.008008;use strict;use warnings;use Symbol qw(delete_package);require Exporter;our @ISA = qw(Exporter);our @EXPORT_OK = qw( );our @EXPORT = qw( test );our $VERSION = 0.01;sub test(){return {message => Hello World from Perl,};}1;
  • 6. Error handling or dieMariaDB [Demo]> CREATE PROCEDURE PerlError()-> DYNAMIC RESULT SETS 1-> NO SQL-> LANGUAGE Perl-> EXTERNAL NAME "GoodbyeWorld::test";Query OK, 0 rows affected (0.00 sec)MariaDB [Demo]> call PerlError();ERROR 1220 (HY000): Cannot open file: Nosuch file or directory at /usr/local/mysql/lib/plugin/perl/GoodbyeWorld.pm line 16.package GoodbyeWorld;# put this file in <prefix>/lib/mysql/perluse 5.008008;use strict;use warnings;use Symbol qw(delete_package);require Exporter;our @ISA = qw(Exporter);our @EXPORT_OK = qw( );our @EXPORT = qw( test );our $VERSION = 0.01;sub test({open FILE, "</something/nonexist"or die "Cannot open file: $!";return {message => Goodbye World from Perl,};}1;
  • 7. Reading DataMariaDB [employees]> CREATE PROCEDURE employee(-> empno INT)-> DYNAMIC RESULT SETS 1-> READS SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ReadData::test";Query OK, 0 rows affected (0.02 sec)MariaDB [employees]> call employee(10034)G*************************** 1. row***************************birth_date: 1962-12-29emp_no: 10034first_name: Badergender: Mhire_date: 1988-09-21last_name: Swan1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)package ReadData;# put this file in <prefix>/lib/mysql/perluse 5.008008;use strict;use warnings;use Symbol qw(delete_package);require Exporter;our @ISA = qw(Exporter);our @EXPORT_OK = qw( );our @EXPORT = qw( test );our $VERSION = 0.01;our $DSN = ‘dbi:mysql:employees’;use DBI;use DBD::mysql;sub test($){my($emp_no) = @_;my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";my $s = $dbh->prepare(“SELECT * FROM employees WHERE emp_no=?”);$s->execute(int $emp_no);return $s->fetchrow_hashref;}1;
  • 8. Reading DataMariaDB [employees]> CREATE PROCEDURE employee(-> empno INT)-> DYNAMIC RESULT SETS 1-> READS SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ReadData::test";Query OK, 0 rows affected (0.02 sec)MariaDB [employees]> call employee(10034)G*************************** 1. row***************************birth_date: 1962-12-29emp_no: 10034first_name: Badergender: Mhire_date: 1988-09-21last_name: Swan1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)package ReadData;# put this file in <prefix>/lib/mysql/perluse 5.008008;use strict;use warnings;use Symbol qw(delete_package);require Exporter;our @ISA = qw(Exporter);our @EXPORT_OK = qw( );our @EXPORT = qw( test );our $VERSION = 0.01;our $DSN = ‘dbi:mysql:employees’;use DBI;use DBD::mysql;sub test($){my($emp_no) = @_;my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";my $s = $dbh->prepare(“SELECT * FROM employees WHERE emp_no=?”);$s->execute(int $emp_no);return $s->fetchrow_hashref;}1;
  • 9. Modifying DataMariaDB [employees]> CREATE PROCEDURE-> makesummary(-> empno INT)-> MODIFIES SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ModifyData::test";Query OK, 0 rows affected (0.00 sec)MariaDB [employees]> call makesummary;sub test(){my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";$dbh->begin_work or die $!;my $ins = $dbh->prepare("INSERT INTO summary VALUES (?,?)");my $emps = $dbh->selectall_arrayref("select emp_no, max(salary) salary from employees "."left join salaries using (emp_no) group by emp_no",{ Slice => {} });foreach my $emp (@$emps){$ins->execute($emp->{emp_no}, $emp->{salary}) or die $!;}$dbh->commit or die $!;return undef;}
  • 10. Modifying DataMariaDB [employees]> CREATE PROCEDURE-> makesummary(-> empno INT)-> MODIFIES SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ModifyData::test";Query OK, 0 rows affected (0.00 sec)MariaDB [employees]> call makesummary;Query OK, 0 rows affected (18.02 sec)sub test(){my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";$dbh->begin_work or die $!;my $ins = $dbh->prepare("INSERT INTO summary VALUES (?,?)");my $emps = $dbh->selectall_arrayref("select emp_no, max(salary) salary from employees "."left join salaries using (emp_no) group by emp_no",{ Slice => {} });foreach my $emp (@$emps){$ins->execute($emp->{emp_no}, $emp->{salary}) or die $!;}$dbh->commit or die $!;return undef;}
  • 11. Modifying DataMariaDB [employees]> CREATE PROCEDURE-> makesummary(-> empno INT)-> MODIFIES SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ModifyData::test";Query OK, 0 rows affected (0.00 sec)MariaDB [employees]> call makesummary;Query OK, 0 rows affected (18.02 sec)MariaDB [employees]> select count(*)-> from summary;+----------+| count(*) |+----------+| 300024 |+----------+1 row in set (0.15 sec)sub test(){my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";$dbh->begin_work or die $!;my $ins = $dbh->prepare("INSERT INTO summary VALUES (?,?)");my $emps = $dbh->selectall_arrayref("select emp_no, max(salary) salary from employees "."left join salaries using (emp_no) group by emp_no",{ Slice => {} });foreach my $emp (@$emps){$ins->execute($emp->{emp_no}, $emp->{salary}) or die $!;}$dbh->commit or die $!;return undef;}
  • 12. Modifying DataMariaDB [employees]> CREATE PROCEDURE-> makesummary(-> empno INT)-> MODIFIES SQL DATA-> LANGUAGE Perl-> EXTERNAL NAME "ModifyData::test";Query OK, 0 rows affected (0.00 sec)MariaDB [employees]> call makesummary;Query OK, 0 rows affected (18.02 sec)MariaDB [employees]> select count(*)-> from summary;+----------+| count(*) |+----------+| 300024 |+----------+1 row in set (0.15 sec)sub test(){my $dbh = DBI->connect($DSN, undef, undef) ||die "Failed in call to DBI->connect, $!";$dbh->begin_work or die $!;my $ins = $dbh->prepare("INSERT INTO summary VALUES (?,?)");my $emps = $dbh->selectall_arrayref("select emp_no, max(salary) salary from employees "."left join salaries using (emp_no) group by emp_no",{ Slice => {} });foreach my $emp (@$emps){$ins->execute($emp->{emp_no}, $emp->{salary}) or die $!;}$dbh->commit or die $!;return undef;}select statement - 2 seconds300k inserts in 16 seconds== 18k inserts per second
  • 13. More than just procs• CPAN is a large library...• Can extend MariaDB’s functionality.• How about using HTTP::Daemon?
  • 14. Server Monitoringsub daemon(){my $d = HTTP::Daemon->new(LocalAddr => 127.0.0.1,LocalPort => 8080,) ||die "Failed in call to HTTP::Daemon->new, $!";my $dbh = DBI->connect("dbi:mysql:mysql", undef, undef) ||die "Failed in call to DBI->connect, $!";while (my $c = $d->accept){while (my $r = $c->get_request){if (exists $pages{$r->url->path}){$pages{$r->url->path}->($dbh, $c, $r);}else{$c->send_error(RC_NOT_FOUND);}}$c->close;undef $c;}}What if we can useHTTP::Daemon?
  • 15. Server Monitoring/statusz => sub {my ($dbh,$c,$r) = @_;return $c->send_error(RC_FORBIDDEN)if $r->method ne GET;my $sth = $dbh->prepare_cached(q{SELECT VARIABLE_NAME name, VARIABLE_VALUE valueFROM INFORMATION_SCHEMA.GLOBAL_STATUS}, { Slice => {} });$sth->execute() || die $sth->errstr;my $response = HTTP::Response->new(200, undef,HTTP::Headers->new(Content_Type => "application/json",));my $result = {};while (my $row = $sth->fetchrow_arrayref){$result->{$row->[0]} = $row->[1];}$response->add_content(to_json($result,{ ascii => 1, pretty => 1 }));return $c->send_response($response);},Fetching currentserver status could beas simple as fetchinghttp://127.0.0.1/statusz
  • 16. Status• Code hosted at LaunchPad.• Contributing to MariaDB 10.0 soon.• Stuff needs to be tidied up.• Future steps include better Table Functions.