SlideShare une entreprise Scribd logo
1  sur  16
Télécharger pour lire hors ligne
Using Perl Stored
Procedures
with MariaDB
Antony T Curtis <atcurtis@gmail.com>
Special thanks to LinkedIn for permitting personal projects
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.
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.
Hello World
MariaDB [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/perl
use 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;
Hello World
MariaDB [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/perl
use 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;
Error handling or die
MariaDB [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: No
such file or directory at /usr/local/mysql/
lib/plugin/perl/GoodbyeWorld.pm line 16.
package GoodbyeWorld;
# put this file in <prefix>/lib/mysql/perl
use 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;
Reading Data
MariaDB [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-29
emp_no: 10034
first_name: Bader
gender: M
hire_date: 1988-09-21
last_name: Swan
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
package ReadData;
# put this file in <prefix>/lib/mysql/perl
use 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;
Reading Data
MariaDB [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-29
emp_no: 10034
first_name: Bader
gender: M
hire_date: 1988-09-21
last_name: Swan
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
package ReadData;
# put this file in <prefix>/lib/mysql/perl
use 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;
Modifying Data
MariaDB [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;
}
Modifying Data
MariaDB [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;
}
Modifying Data
MariaDB [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;
}
Modifying Data
MariaDB [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 seconds
300k inserts in 16 seconds
== 18k inserts per second
More than just procs
• CPAN is a large library...
• Can extend MariaDB’s functionality.
• How about using HTTP::Daemon?
Server Monitoring
sub 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 use
HTTP::Daemon?
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 value
FROM 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 current
server status could be
as simple as fetching
http://127.0.0.1/statusz
Status
• Code hosted at LaunchPad.
• Contributing to MariaDB 10.0 soon.
• Stuff needs to be tidied up.
• Future steps include better Table Functions.

Contenu connexe

Tendances

MySQL Performance schema missing_manual_flossuk
MySQL Performance schema missing_manual_flossukMySQL Performance schema missing_manual_flossuk
MySQL Performance schema missing_manual_flossuk
Valeriy Kravchuk
 
Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013
Valeriy Kravchuk
 

Tendances (20)

New features in Performance Schema 5.7 in action
New features in Performance Schema 5.7 in actionNew features in Performance Schema 5.7 in action
New features in Performance Schema 5.7 in action
 
MySQL Performance Schema in Action
MySQL Performance Schema in ActionMySQL Performance Schema in Action
MySQL Performance Schema in Action
 
Developers’ mDay 2021: Bogdan Kecman, Oracle – MySQL nekad i sad
Developers’ mDay 2021: Bogdan Kecman, Oracle – MySQL nekad i sadDevelopers’ mDay 2021: Bogdan Kecman, Oracle – MySQL nekad i sad
Developers’ mDay 2021: Bogdan Kecman, Oracle – MySQL nekad i sad
 
DBA Commands and Concepts That Every Developer Should Know
DBA Commands and Concepts That Every Developer Should KnowDBA Commands and Concepts That Every Developer Should Know
DBA Commands and Concepts That Every Developer Should Know
 
MySQL Performance schema missing_manual_flossuk
MySQL Performance schema missing_manual_flossukMySQL Performance schema missing_manual_flossuk
MySQL Performance schema missing_manual_flossuk
 
Mysql 56-experiences-bugs-solutions-50mins
Mysql 56-experiences-bugs-solutions-50minsMysql 56-experiences-bugs-solutions-50mins
Mysql 56-experiences-bugs-solutions-50mins
 
MariaDB for developers
MariaDB for developersMariaDB for developers
MariaDB for developers
 
Summary tables with flexviews
Summary tables with flexviewsSummary tables with flexviews
Summary tables with flexviews
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database Jones
 
Flame Graphs for MySQL DBAs - FOSDEM 2022 MySQL Devroom
Flame Graphs for MySQL DBAs - FOSDEM 2022 MySQL DevroomFlame Graphs for MySQL DBAs - FOSDEM 2022 MySQL Devroom
Flame Graphs for MySQL DBAs - FOSDEM 2022 MySQL Devroom
 
Troubleshooting MySQL Performance
Troubleshooting MySQL PerformanceTroubleshooting MySQL Performance
Troubleshooting MySQL Performance
 
Php classes in mumbai
Php classes in mumbaiPhp classes in mumbai
Php classes in mumbai
 
Introduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sIntroduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]s
 
Developing for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQLDeveloping for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQL
 
Performance Schema for MySQL Troubleshooting
Performance Schema for MySQL TroubleshootingPerformance Schema for MySQL Troubleshooting
Performance Schema for MySQL Troubleshooting
 
Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013
 
Why Use EXPLAIN FORMAT=JSON?
 Why Use EXPLAIN FORMAT=JSON?  Why Use EXPLAIN FORMAT=JSON?
Why Use EXPLAIN FORMAT=JSON?
 
Performance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshootingPerformance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshooting
 
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
 
MySQL 101 PHPTek 2017
MySQL 101 PHPTek 2017MySQL 101 PHPTek 2017
MySQL 101 PHPTek 2017
 

Similaire à Using Perl Stored Procedures for MariaDB

DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7
chuvainc
 
Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-rails
Novelys
 

Similaire à Using Perl Stored Procedures for MariaDB (20)

DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7
 
MySQLinsanity
MySQLinsanityMySQLinsanity
MySQLinsanity
 
DBD::SQLite
DBD::SQLiteDBD::SQLite
DBD::SQLite
 
Triggers and Stored Procedures
Triggers and Stored ProceduresTriggers and Stored Procedures
Triggers and Stored Procedures
 
OSMC 2008 | Monitoring MySQL by Geert Vanderkelen
OSMC 2008 | Monitoring MySQL by Geert VanderkelenOSMC 2008 | Monitoring MySQL by Geert Vanderkelen
OSMC 2008 | Monitoring MySQL by Geert Vanderkelen
 
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, HerokuPostgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
 
PHP tips and tricks
PHP tips and tricks PHP tips and tricks
PHP tips and tricks
 
Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8
 
Instalar MySQL CentOS
Instalar MySQL CentOSInstalar MySQL CentOS
Instalar MySQL CentOS
 
My sql1
My sql1My sql1
My sql1
 
veracruz
veracruzveracruz
veracruz
 
veracruz
veracruzveracruz
veracruz
 
veracruz
veracruzveracruz
veracruz
 
veracruz
veracruzveracruz
veracruz
 
php2.pptx
php2.pptxphp2.pptx
php2.pptx
 
The Ring programming language version 1.7 book - Part 31 of 196
The Ring programming language version 1.7 book - Part 31 of 196The Ring programming language version 1.7 book - Part 31 of 196
The Ring programming language version 1.7 book - Part 31 of 196
 
Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-rails
 
Replication Troubleshooting in Classic VS GTID
Replication Troubleshooting in Classic VS GTIDReplication Troubleshooting in Classic VS GTID
Replication Troubleshooting in Classic VS GTID
 
MySQL InnoDB Cluster 미리보기 (remote cluster test)
MySQL InnoDB Cluster 미리보기 (remote cluster test)MySQL InnoDB Cluster 미리보기 (remote cluster test)
MySQL InnoDB Cluster 미리보기 (remote cluster test)
 
Service discovery and configuration provisioning
Service discovery and configuration provisioningService discovery and configuration provisioning
Service discovery and configuration provisioning
 

Dernier

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 

Dernier (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

Using Perl Stored Procedures for MariaDB

  • 1. Using Perl Stored Procedures with MariaDB Antony 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 World MariaDB [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/perl use 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 World MariaDB [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/perl use 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 die MariaDB [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: No such file or directory at /usr/local/mysql/ lib/plugin/perl/GoodbyeWorld.pm line 16. package GoodbyeWorld; # put this file in <prefix>/lib/mysql/perl use 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 Data MariaDB [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-29 emp_no: 10034 first_name: Bader gender: M hire_date: 1988-09-21 last_name: Swan 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) package ReadData; # put this file in <prefix>/lib/mysql/perl use 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 Data MariaDB [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-29 emp_no: 10034 first_name: Bader gender: M hire_date: 1988-09-21 last_name: Swan 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) package ReadData; # put this file in <prefix>/lib/mysql/perl use 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 Data MariaDB [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 Data MariaDB [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 Data MariaDB [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 Data MariaDB [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 seconds 300k 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 Monitoring sub 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 use HTTP::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 value FROM 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 current server status could be as simple as fetching http://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.