Krátce o PL/Perl

17. 3. 2004
Doba čtení: 4 minuty

Sdílet

Tento článek stručně, leč s užitím názorných příkladů, přibližuje programovací jazyk plperl, jejž lze využít při práci s databází PostgreSQL.

Neznám žádnou jinou SQL databázi, které by měla bohatší nabídku programovacích jazyků než PostgreSQL. Pravdou je, že tuto vlastnost jsem nikdy nevyužil – oblíbil jsem si jednoduchý a relativně přehledný zápis SQL příkazů v PL/pgSQL a neměl jsem potřebu zkoušet nic dalšího, ačkoliv jsem sem tam v konferenci narazil na příklady použití pltcl a plperl. Na libůstky typy plR se stále dívám jako na čistě akademickou záležitost – patrně asi nikdy nebudu spouštět z uložené procedury komplikované statistické výpočty a R použiji nejspíš jen na klientské straně. Následující příklady ukazují možnosti, které plpgsql nemá (spoušť v pltcl konvertující všechny pole na malá písmena, R – agregační funkce pro určení mediánu).

CREATE OR REPLACE FUNCTION lowercase() RETURNS TRIGGER AS '
  set NEW($1) [string tolower $NEW($1)]
  return [array get NEW]' LANGUAGE pltcl;

CREATE OR REPLACE FUNCTION r_median(_float8) RETURNS float as '
  median(arg1)
' language 'plr';

CREATE AGGREGATE median (
  sfunc = plr_array_accum,
  basetype = float8,
  stype = _float8,
  finalfunc = r_median
); 

Když jsem poprvé viděl plperl, nechápal jsem, k čemu vůbec může být. V předchozích verzích měl relativně velká omezení, víceméně se z něj nedaly spouštět dotazy, nedal se použít pro tvorbu spouští. Snad jen masochista by si místo plpgsql vybral plperl. Nedávno jsem svůj názor musel přehodnotit. Procedury v plperlu se mi náramně hodily.

SELECT substring('žlutý kůň 23' FROM '^[[:alpha:]]+'); --> žlutý
SELECT substring('žlutý kůň 23' FROM '[[:digit:]]+');  --> 23
SELECT * FROM lidi WHERE prijmeni ~* 'a$'; 

PostgreSQL sice obsahuje podporu regulárních výrazů (funkce substring a operátory ~ a ~*), pro složitější úlohy ale vestavěná podpora nestačí. Pokud chceme s regulárními výrazy pracovat více – použít náhrady, výběr řetězců – pak vlastně nemáme žádnou jinou možnost než použít plperl. Ovšem co jiného použít na regulární výrazy než Perl, že? plpgsql regulární výrazy nepodporuje, alespoň já o žádné podpoře nevím. (Kromě plperlu samozřejmě můžeme použít plphp, případně pltcl nebo plpython.) Otázka zní, proč pracovat s regulárními výrazy. Potřeboval jsem čistit databázi. V MySQL, MSSQL bych si musel napsat externí aplikaci, kterou data proženu. V MSSQL si mohu pomoci DTS (data transformation services), kde mám regulární výrazy přístupné ve VB scriptu. V Oracle je package owa_pattern. Teprve nyní mi přijde cena za možnost použití více jazyků přijatelná – komplikovaný zápis, resp. kód, se předává jako string – následně vznikají problémy s nečitelností v plpgsql (přehršel apostrofů).

CREATE OR REPLACE FUNCTION get_numbers(VARCHAR) RETURNS INTEGER[] AS '
  my($source) = @_; $retval = "";
  while ( $source =~ m/([[:digit:]]+)/g ) {
    $retval = $retval . ", " if ($retval ne "");
    $retval = $retval . $1;
  }
  return "{$retval}"; ' LANGUAGE plperl;

work=#SELECT get_numbers('dasf adfsadf 10 dasf dasf 20 adsf 111');
get_numbers
--
{10,20,111}
{1 řádka} 

Bohužel plperl má pravděpodobně nejkomplikovanější instalaci z jazyků podporovaných PostgreSQL. Vyžaduje knihovnu libperl, která obyčejně není na počítačích nainstalována (perl je slinkován staticky). Až budete překládat perl, nezapomeňte, že napřed musíte mít přeloženou a zaregistrovanou knihovnu libperl, pak teprve můžete znova provést configure PostgreSQL se svými parametry a navíc s –with-perl. Není nutné překládat kompletní PostgreSQL, stačí jen adresář /src/pl/plperl.

plperl můžeme použít bez problémů (běží v safe módu). Bohužel se opět jednou projeví naše česká specifika. Aby se operace s řetězci chovaly správně vůči diakritice, je třeba použít locale. Jenomže to už je pro perl nebezpečná operace, a musíme tedy použít untrusted perl. Což může vadit v systémech, kde se tvůrci databází netěší až tak velké důvěře: webhostingy, školy atd. Untrusted plperl nejenže nemá žádná omezení v přístupu k lokálním zdrojům, ale běží pod uživatelem postgres. Není problém si například smazat databázi.

-- Pokud se jedna o Prahu, Brno, Liberec, Ostravu,
-- Plzen nebo Karvinou, tj. jednoslovne nazvy, da
-- se predpokladat, ze dalsim slovem bude identifikace
-- casti, napr. Praha Bohnice -> Praha - Bohnice

CREATE OR REPLACE FUNCTION checkname(varchar) RETURNS varchar AS '
  use locale;
  my ($source) = @_;
  if (! defined $source) {return undef;}

  if ($source =~ m#[a-zA-Z]+[[:space:]]+[a-zA-Z]+#i) {
    if (index($source, "-") == -1 && index($source, ",") && index($source, "+")) {
      $source =~ s/^[[:space:]]*(Praha|Brno|Liberec|Ostrava|Plzeň|Karviná) {1}[[:space:]]/$1 - /i;
    }
  }
  return uc($source); ' LANGUAGE plperlu; 

(Pozn. ed.: mezera za Karvinou být nemá, ústupek sazbě –Johanka)

bitcoin školení listopad 24

Nejtvrdším omezením plperl je nemožnost přímo volat funkce PostgreSQL. Jakékoliv hodnoty se při převodu z Perlu do PostgreSQL konvertují do řetězců: čísla, texty, ale i pole. plperl podporuje typ record, hodnoty jsou opět textové a uložené v hash tabulce. Pro přístup k funkcím PostgreSQL musíme použít rozhraní DBD::PgSPI. Bohužel toto rozhraní již tři roky nebylo aktualizováno a jeho dokumentace také není nejlepší.

CREATE OR REPLACE FUNCTION foospi() RETURNS VARCHAR AS '
  use DBD::PgSPI;
  my @ar=$pg_dbh->selectrow_array("SELECT CURRENT_USER");
  return $ar[0]; ' LANGUAGE plperlu; 

Když už nám nezbude nic jiného než použít untrusted plperl, nemusíme se bránit používání existující další (nejen db relevantní knihovny) Perlu. S trochou nadsázky by se dalo říci, že o něco podobného se snaží v tuto chvíli Microsoft se svou integrací .NET frameworku do MsSQL.

CREATE OR REPLACE FUNCTION foo() RETURNS text AS '
  use Mail::Sendmail;
  %mail = ( To   =>  q(you@yourname.com),
            From =>  q(me@here.com),
            Message => "This is very short message"
          );
  sendmail(%mail) or die $Mail::Sendmail::error;
  return "Ok. Log says:\n", $Mail::Sendmail::log;
' LANGUAGE plperlu; 

Autor článku

Pavel Stěhule je odborníkem na relační databázový systém PostgreSQL, pracuje jako školitel a konzultant.