0% acharam este documento útil (0 voto)
97 visualizações52 páginas

Programando em Python No Postgres

Este documento discute como programar em Python no PostgreSQL. Ele introduz PL/Python, que permite usar Python como linguagem procedural no PostgreSQL. PL/Python converte tipos de dados entre PostgreSQL e Python e dá acesso a funções e ao banco de dados através do módulo plpy. Embora PL/Python ofereça mais poder do que PL/pgSQL, também representa maior risco devido à capacidade de executar ações fora do banco de dados.

Enviado por

robsoundbass
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
97 visualizações52 páginas

Programando em Python No Postgres

Este documento discute como programar em Python no PostgreSQL. Ele introduz PL/Python, que permite usar Python como linguagem procedural no PostgreSQL. PL/Python converte tipos de dados entre PostgreSQL e Python e dá acesso a funções e ao banco de dados através do módulo plpy. Embora PL/Python ofereça mais poder do que PL/pgSQL, também representa maior risco devido à capacidade de executar ações fora do banco de dados.

Enviado por

robsoundbass
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 52

PL/Python:

Programando em Pyhon no PostgreSQL

Juliano Atanazio
About me
Juliano Atanazio
● Graduated in Computer Science for Business Management (Informática para Gestão de
Negócios), FATEC Zona Sul, São Paulo – SP;
● PostgreSQL DBA;
● Linux admin;
● Instructor (PostgreSQL);
● LPIC-1, LPIC-2 Certified;
● Linux user since 2000;
● Free Software enthusiast;
● Favorite technologies: PostgreSQL, Linux, Python, Shell Script, FreeBSD, etc...;
● Headbanger :) \m/

2/52
Sobre esta Apresentação

Esta apresentação é uma versão alternativa, em português de

"On snakes and elephants


Using Python inside PostgreSQL"
de
Jan Urbański

https://wulczer.org/pywaw-summit.pdf

3/52
Sobre Python

● Linguagem de altíssimo nível;


● Totalmente orientada a objetos;

● Fácil de aprender e de dar manutenção;

● Rica em bibliotecas;

● Propósitos gerais;

● Tipagem forte e dinânica;

● Comunidade forte e solícita;

● Objetiva e muito produtiva: faça mais escrevendo menos.

import this

www.python.org

4/52
Sobre PostgreSQL

É um sistema gerenciador de banco de dados objeto-relacional


originalmente desenvolvido na Universidade da Califórnia no
Departamento de Ciências da Computação em Berkeley.
Hoje é desenvolvido e mantido pelo PGDG (PostgreSQL Global
Development Group – Grupo de Desenvolvimento Global do
PostgreSQL).
● Open source;
● Rico em recursos avançados;

● Muito amigável para programadores;

● Extensível

www.postgresql.org

5/52
Stored Procedures no PostgreSQL

Em outros SGBDs há diferenças entre stored procedures e


functions, no PostgreSQL é tudo function;
Implementa operações que não seriam fáceis ou sequer seriam
possíveis com SQL;
Uma função é chamada dentro de SQL;
Pode encapsular lógica de negócio;

6/52
Stored Procedures no PostgreSQL

PL/pgSQL é a linguagem padrão para se escrever functions no


Postgres;
PL/Python, PL/Perl e PL/Tcl são nativamente suportadas, mas é
possível utilizar outras linguagens procedurais tais como PL/Java,
PL/PHP, PL/v8 (JavaScript), PL/R e etc;
Suporta sobrecarga de função.

7/52
Funções: Sintaxe e Exemplos

Criação da função fc_foo sem parâmetros:


> CREATE OR REPLACE FUNCTION fc_foo()
RETURNS VARCHAR AS $$

BEGIN
RETURN 'Hello, World!';
END; $$ LANGUAGE PLPGSQL;

8/52
Funções: Sintaxe e Exemplos

Criação da função fc_foo com parâmetros:


> CREATE OR REPLACE FUNCTION fc_foo(num1 INT, num2 INT)
RETURNS INT AS $$

BEGIN
RETURN (num1 + num2) * 2;
END; $$ LANGUAGE PLPGSQL;

9/52
Funções: Sintaxe e Exemplos

Execução da função fc_foo sem parâmetros:


> SELECT fc_foo();
fc_foo
---------------
Hello, World!

10/52
Funções: Sintaxe e Exemplos

Execução da função fc_foo com parâmetros:


> SELECT fc_foo(2, 5);
fc_foo
--------
14

11/52
Blocos Anônimos

Sintaxe:
DO $$

. . .
codigo
. . .
$$ LANGUAGE linguagem;

12/52
Blocos Anônimos

> SET client_min_messages = 'notice';

> DO $$
DECLARE n_con INT;
BEGIN
SELECT count(client_addr)
INTO n_con
FROM pg_stat_activity;

RAISE NOTICE
'Conexões não-locais: %', n_con;
END; $$ LANGUAGE PLPGSQL;
NOTICE: Conexões não-locais: 10

13/52
PL/Python

PL/Python é a implementação de Python como linguagem


procedural no Postgres;
Permite utilizar todas as bibliotecas de Python instaladas no
sistema operacional;
Ao rodar PL/Python pela primeira vez após o servidor
PostgreSQL inicializar, um interpretador Python é inicializado
dentro do processo backend;

https://www.postgresql.org/docs/current/static/plpython.html

14/52
PL/Python

Para evitar uma demora inicial pode-se carregar a biblioteca de


sistema plpython.so em alguma configuração “preload”;
Tipos de dados PostgreSQL são convertidos para os de Python e
vice-versa;
Os argumentos de uma função têm escopo global;
O módulo plpy fornece acesso ao banco e funções;
O “path” dos módulos depende da variável de ambiente
PYTHONPATH do usuário que inicia o serviço do PostgreSQL.

15/52
PL/Python: Tipos de Dados

PostgreSQL Python
bigint, integer, smallint int

Real, double float

numeric Decimal

boolean bool

text, varchar, char str

array list

Tipos personalizados dict

null None

16/52
PL/Python: O “U” da Questão

PL/Python é uma linguagem procedural considerada “untrusted”


(não confiável): o que implica na denominação PL/PYTHONU;
O que significa que não é oferecida qualquer forma de restrição
para usuários fazer;
Permite executar ações fora do banco de dados;
Somente superusers podem criar funções em linguagens como
PL/PYTHONU.
“Com grandes poderes vêm grandes responsabilidades”.
Tio Ben (Stan Lee)

17/52
PL/Python vs PL/pgSQL

Qual é a melhor linguagem procedural para PostgreSQL?


PL/Python ou PL/pgSQL?
Depende…
De forma geral podemos dizer que para operações puras na base
de dados é melhor utilizar PL/pgSQL.
E PL/Python para operações que vão além do banco, dando um
maior poder de fogo para o PostgreSQL.
Cada uma tem seu valor e sua aplicabilidade dentro de um
contexto :)

18/52
PL/Python vs PL/pgSQL
Variáveis Especiais para Triggers

PL/pgSQL PL/Python Tipo Descrição


Qual tipo de evento disparou o trigger.
TG_OP TD['event'] Possíveis valores: INSERT, UPDATE, DELETE, ou
TRUNCATE.

string Quando o gatilho (trigger) foi disparado.


TG_WHEN TD['when'] Possíveis valores: BEFORE, AFTER, ou INSTEAD
OF.

TG_LEVEL TD['level'] Qual o nível, por linha ou por comando.


Possíveis valores: ROW ou STATEMENT.
Variável que contém a nova linha para INSERT ou
NEW TD['new'] UPDATE em nível de linha (ROW level). É nula
para DELETE ou nível STATEMENT.
record
Para nível em linha (ROW level), contém a linha
OLD TD['old'] antiga para UPDATE ou DELETE. É nula para o
vível STATEMENT ou para INSERT.
TG_NAME TD['name'] name Nome do gatilho.

19/52
PL/Python vs PL/pgSQL
Variáveis Especiais para Triggers
PL/pgSQL PL/Python Tipo Descrição
TG_TABLE_NAME / Nome da tabela que disparou o
TG_RELNAME TD['table_name']
(depreciado) gatilho.
name
TG_TABLE_SCHEMA TD['table_schema'] Nome do esquema (schema)
da tabela que disparou o gatilho.

TG_RELID TD['relid'] oid OID da tabela que disparou o


gatilho.

Se o comando CREATE
TRIGGER inclui argumentos
para a função eles estão
array disponíveis de TD['args'][0] a
TG_ARGV[] TD['args'] De TD['args'][n - 1].
string Índices de array inválidos
(menor do que zero ou maior do
que TG_NARGS) resultam em
um valor nulo.

20/52
PL/Python vs PL/pgSQL
Variáveis Especiais para Triggers

PL/pgSQL PL/Python Tipo Descrição


TG_NARGS len(TD['args']) inteiro A quantidade de argumentos
passados à função do gatilho.

Se TD['when'] for BEFORE ou INSTEAD OF e TD['level']


for ROW, você pode retornar None ou “OK” da função Python
para indicar que a linha não foi modificada, “SKIP” para abortar o
evento de se TD['event'] for INSERT ou UPDATE você pode
retornar “MODIFY” para indicar que você modificou nova linha.
Caso contrário o valor de retorno será ignorado.

21/52
PL/Python: Instalação
Nosso Laboratório
SO: CentOS Linux 7.5
Python: 3.6
PostgreSQL: 10
Diretório para bibliotecas Python : /var/lib/pgsql/python

PYTHONPATH: ${PYTHONPATH}:/var/lib/pgsql/python

Obs.: Sinta-se à vontade para usar qualquer versão diferente.


Informações meramente ilustrativas que é conforme o laboratório de testes aqui.

22/52
PL/Python: Instalação

Antes da instalação do PostgreSQL indique para a variável de


ambiente o binário referente à versão de Python utilizada:
$ export PYTHON=`which python3.6`

É preciso ter também os pacotes com os headers em C de


Python (-dev, -devel).

No processo de configure utilize a opção --with-python:


$ ./configure --with-python

23/52
PL/Python: Instalação

Crie o diretório Python:


$ mkdir /var/lib/pgsql/python

No arquivo de perfil de shell do usuário


(.bashrc, .bashrc_profile, .profile) coloque a seguinte linha:
export PYTHONPATH="${PYTHONPATH}:/var/lib/pgsql/python"

24/52
PL/Python: Instalação
Para testar podemos iniciar o PostgreSQL passando o valor de
PYTHONPATH:
$ PYTHONPATH="${PYTHONPATH}:/var/lib/pgsql/python" \
pg_ctl start

Podemos incluir a variável PYTHONPATH no Unit File SystemD


do serviço do PostgreSQL:
# systemctl edit --full postgresql.service

25/52
PL/Python: Instalação

Na sessão Unit, diretiva Environment do Unit File:


[Unit]
. . .
Environment=PYTHONPATH=/var/lib/pgsql/python

Reinicialize o serviço do PostgreSQL:


# systemctl restart postgresql.service

26/52
PL/Python: Exemplos
Criação da base de dados de exemplo:
> CREATE DATABASE db_plpython;

Conectar à base:
> \c db_plpython

Habilitar PL/Python 3 na base de dados atual:


> CREATE EXTENSION plpython3u;

27/52
PL/Python: Exemplos

Uma simples função anônima:


> DO $$

from sys import path


plpy.notice(path)

$$ LANGUAGE PLPYTHON3U;
NOTICE: ['/var/lib/pgsql/python', '/usr/lib64/python36.zip',
'/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/
lib64/python3.6/site-packages', '/usr/lib/python3.6/site-
packages']

28/52
PL/Python: Exemplos

Função em PL/Python 3 sem argumentos:


> CREATE OR REPLACE FUNCTION fc_py()
RETURNS VARCHAR AS $$

return 'Hello, World!!!'

$$ LANGUAGE plpython3u;

29/52
PL/Python: Exemplos

Sobrecarga de função:

> CREATE OR REPLACE FUNCTION fc_py(num1 INT, num2 INT)


RETURNS INT AS $$

return num1 + num2

$$ LANGUAGE plpython3u;

30/52
PL/Python: Exemplos

Testando a primeira função criada:


> SELECT fc_py();
fc_py
-----------------
Hello, World!!!

Testando a segunda função criada:

> SELECT fc_py(2, 5);


fc_py
-------
7

31/52
PL/Python: Boas Práticas
● Mantenha seu código Python em um módulo;
● Faça todas suas funções SQL com apenas duas linhas;
● Teste o código Python fazendo mock [1].

[1] https://docs.python.org/3/library/unittest.mock.html

32/52
PL/Python: Boas Práticas

Criação do módulo teste dentro do diretório que está em


PYTHONPATH:
$ cat << EOF > /var/lib/pgsql/python/teste.py
def py_version():
import sys
return sys.version.split()[0]
EOF

Conexão ao banco via psql:


$ psql db_plpython

33/52
PL/Python: Boas Práticas

Criação da função seguindo as boas práticas:


> CREATE OR REPLACE FUNCTION fc_py_version()
RETURNS VARCHAR AS $$

from teste import py_version


return py_version()

$$ LANGUAGE plpython3u;

34/52
PL/Python: Boas Práticas

Teste da função:
> SELECT 'Minha versão de Python é: '|| fc_py_version()
AS "Versão de Python";
Versão de Python
---------------------------------
Minha versão de Python é: 3.6.3s

35/52
PL/Python: Use Case

Serão demonstrados 2 (dois) casos de uso


• Converter XML para JSON, na base de dados de um campo
do tipo xml para jsonb;
• Em um sistema de cadastro de apostilas PDF extrair o sumário
(TOC – Table Of Contents).

36/52
PL/Python: Use Case

Instalar os módulos que serão utilizados:


# python3 -m pip install xmltodict pdfminer.six

Editar o arquivo que será o módulo com funções personalizadas:


$ vim /var/lib/pgsql/python/MyFunctions.py

37/52
PL/Python: Use Case
/var/lib/pgsql/python/MyFunctions.py
import json
import pprint
import xmltodict

from pdfminer.pdfdocument import PDFDocument


from pdfminer.pdfparser import PDFParser

Continua...

38/52
PL/Python: Use Case
/var/lib/pgsql/python/MyFunctions.py
def conv_xml_2_json(doc):
'Converte uma string XML para JSON'

doc = xmltodict.parse(doc)
return json.dumps(doc, ensure_ascii=False)

Continua...

39/52
PL/Python: Use Case
/var/lib/pgsql/python/MyFunctions.py
def pdf_extract_toc(f):
'Extrai o sumário de um PDF'

f = open(f, 'rb')
parser = PDFParser(f)
document = PDFDocument(parser)
outlines = document.get_outlines()

lista_tmp = []
for (level, title, dest, a, se) in outlines:
lista_tmp.append(title)

return '\n'.join(lista_tmp)

40/52
PL/Python: Use Case

Converter XML para JSON


No banco criar a função para converter de XML para JSON:
> CREATE OR REPLACE FUNCTION fc_py_xml2jsonb(doc TEXT)
RETURNS jsonb AS $$

from MyFunctions import conv_xml_2_json


return conv_xml_2_json(doc)

$$ LANGUAGE PLPYTHON3U;

41/52
PL/Python: Use Case

Criação da tabela:
> CREATE TABLE tb_xml(
id serial PRIMARY KEY,
campo_xml xml);

42/52
PL/Python: Use Case
Inserir o registro:
> INSERT INTO tb_xml (campo_xml) VALUES (
'<receita nome="pão" tempo_de_preparo="5 minutos"
tempo_de_cozimento="1 hora">
<titulo>Pão simples</titulo>
<ingredientes>
<ingrediente quantidade="3"
unidade="xícaras">Farinha</ingrediente>
<ingrediente quantidade="7"
unidade="gramas">Fermento</ingrediente>
<ingrediente quantidade="1.5" unidade="xícaras"
estado="morna">Água</ingrediente>
<ingrediente quantidade="1" unidade="colheres de
chá">Sal</ingrediente>
</ingredientes>
<instrucoes>
<passo>Misture todos os ingredientes, e dissolva bem.</passo>
<passo>Cubra com um pano e deixe por uma hora em um local
morno.</passo>
<passo>Misture novamente, coloque numa bandeja e asse num
forno.</passo>
</instrucoes>
</receita>');

43/52
PL/Python: Use Case

Converter para JSON:


> SELECT
jsonb_pretty(fc_py_xml2jsonb(campo_xml::text))
FROM tb_xml;
jsonb_pretty
------------------------------------------------------------------------------
{ +
"receita": { +
"@nome": "pão", +
"titulo": "Pão simples", +
"instrucoes": { +
"passo": [ +
"Misture todos os ingredientes, e dissolva bem.", +
"Cubra com um pano e deixe por uma hora em um local morno.",+
"Misture novamente, coloque numa bandeja e asse num forno." +
] +
}, +
. . .

44/52
PL/Python: Use Case

Extrair o Sumário de um PDF


Criação da função:
> CREATE OR REPLACE FUNCTION
fc_py_pdf_extract_toc (arquivo TEXT)
RETURNS TEXT AS $$

from MyFunctions import pdf_extract_toc


return pdf_extract_toc(arquivo)

$$ LANGUAGE PLPYTHON3U;

45/52
PL/Python: Use Case

Criação da tabela:
> CREATE TABLE tb_apostila(
id serial PRIMARY KEY,
titulo VARCHAR(200),
autor VARCHAR(70),
toc text);

46/52
PL/Python: Use Case

Inserir um registro:
> INSERT INTO tb_apostila (titulo, autor, toc) VALUES (
'PostgreSQL - SQL Básico',
'Juliano Atanazio',
fc_py_pdf_extract_toc('/tmp/postgresql_sql_basico.pdf'));

47/52
PL/Python: Use Case

Verificar o que foi inserido:


> SELECT id, titulo, autor, toc FROM tb_apostila;
id | titulo | autor | toc
----+-------------------------+------------------+-------------------------------------------------------------
1 | PostgreSQL - SQL Básico | Juliano Atanazio | 1 SQL +
| | | 1.1 O que é SQL +
| | | 1.2 Subdivisões SQL +
| | | 1.2.1 DDL +
| | | 1.2.2 DML +
| | | 1.2.3 DCL +
| | | 1.3 Identificadores +
| | | 1.4 Operadores +
| | | 1.5 Comentários SQL +
| | | 2 Tipos de Dados +
| | | 2.1 Sobre Tipos de Dados +
. . .

48/52
Conclusão
Utilize PL/Python para coisas
que PL/pgSQL não atende.
PL/Python por ser a
implementação de Python como
linguagem procedural no
PostgreSQL permite que se use
todo seu poder das “baterias
inclusas” além de pacotes de
bibliotecas extras instaladas via
pip, por exemplo.

49/52
Donate!

The elephant needs you!

Contribute! :)

http://www.postgresql.org/about/donate/

50/52
Save our planet!

51/52
See you soon!!!
:)
Juliano Atanazio
juliano777@gmail.com
http://slideshare.net/spjuliano
https://speakerdeck.com/julianometalsp
https://juliano777.wordpress.com

52/52

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy