Posts Tagged ‘postgresql’

PL/PGSQL Funções Aninhadas

quarta-feira, outubro 29th, 2008

Utilizando a versão 8.2.7 do Postgresql verifiquei a possibilidade de criar funções aninhadas.
Veja o exemplo:

CREATE OR REPLACE FUNCTION testNestedFunction() RETURNS  REAL as
$$
<>
DECLARE
v_test REAL;
r REAL;
BEGIN
   CREATE OR REPLACE FUNCTION addTest(a REAL,b REAL) RETURNS REAL AS
   $BODY_ADDTEST$
	DECLARE
		r REAL;
	BEGIN
		r := a + b;
	RETURN r;
   END;
   $BODY_ADDTEST$language plpgsql;

   r := addTest(1,1);
   RAISE NOTICE ‘addTest = %’,r;

   r := addTest(2,2);
   RAISE NOTICE ‘addTest = %’,r;

   RETURN r;
END global;
$$ LANGUAGE ‘plpgsql’;

Na função acima criei uma função aninhada chamada addTest(REAL,REAL) recebendo como parâmetro dois valores do tipo real, com os quais é efetuado uma soma e retornado o resultado. Executando a função temos o seguinte resultado:

SELECT testNestedFunction();

NOTA:  addTest = 2
NOTA:  addTest = 4

Tempo total de execução da consulta: 18 ms.
1 registros recuperados.

Como pode ser visto foi realizado duas chamadas a função aninhada addTest() passando diferentes parâmetros.

O interessante é que o Postgresql cria duas funções: testNestedFunction() e addTest(REAL,REAL). E não somente uma função aninhada, isso favorece aos bugs, vamos simular um então.

Vamos deletar a função addTest(REAL,REAL) e executar novamente.

DROP FUNCTION addtest(real, real);
SELECT testNestedFunction();

ERRO:  cache lookup failed for function 1906343
CONTEXT:  PL/pgSQL function "testnestedfunction" line 16 at assignment

********** Erro **********

ERRO: cache lookup failed for function 1906343
SQL state: XX000
Contexto: PL/pgSQL function "testnestedfunction" line 16 at assignment

O comando DROP FUNCTION addTest(REAL,REAL) não verificou que a função testnestedfunction() é depende daquela para sua execução, procurei na documentação uma maneira de declarar a dependência mas não encontrei. Outro detalhe interessante é que a função addTest() não existe até a primeira execução, ou seja, quando o comando é executado SELECT testnestedfunction() pela primeira vez a função addTest() é criada. Então quando deletamos a função addTest() e executamos novamente o comando SELECT testnestedfunction(), a função addTest() não é criada novamente.

Funções aninhadas são interessantes para melhorar a leitura do código e prover reutilização de código. O problema é se por acidente algum DBA deletar a função aninhada como mostrado acima. Irá causar um bug difícil de resolver. Pois, a resposta do erro é pouco intuitiva não informando claramente a função que não foi encontrada.

Criar funções separadas é uma outra solução invés de criar uma função aninhada. Mas, o problema que dificulta a leitura e entendimento do código.

Carpe Diem!

PL/PGSQL blocos de código

quarta-feira, outubro 29th, 2008

A linguagem PL/PGSQL permite a criação de blocos de código. Com essa característica é possível definir o escopo das variáveis. Sendo um recurso interessante para deixar o código mais legível, auxiliando também na depuração do código.
As variáveis existem no momento da declaração do bloco até o final do bloco onde a variável é declarada.
Rótulos podem ser adicionados aos blocos para melhorar a leitura e também para qualificar as variáveis que existem dentro do bloco. Os blocos de código são definidos da seguinte forma:

<

Como exemplo vamos criar uma função onde teremos dois blocos global e local, com uma variável declarada no bloco global com o nome v_test do tipo real e outra variável também declarada com o nome v_test dentro do bloco local. Veja o exemplo:

CREATE OR REPLACE FUNCTION test() RETURNS VOID as
$$
<>
DECLARE
v_test REAL;
BEGIN
        v_test := 1;
        <>
        DECLARE
             v_test REAL;
        BEGIN
	      v_test :=2;
	      RAISE NOTICE ‘global.v_test = %, v_test = %’,global.v_test,v_test;
        END local;

 RAISE NOTICE ‘Global v_test = %’,v_test;

END global;
$$ LANGUAGE ‘plpgsql’;

Resultado da execução:

select test();
NOTA:  global.v_test = 1, v_test = 2
NOTA:  Global v_test = 1
Tempo total de execução da consulta: 6 ms.
1 registros recuperados.

Essa função demonstra claramente o escopo da variáveis e também demonstra que podemos ter sub blocos de código dentro de uma função.
É importante notar que BEGIN/END é utilizado para agrupar as declarações da linguagem PL/PGSQL e também como comandos de controle de transações. Mas, um detalhe interessante é que funções e triggers não podem iniciar ou encerrar transações e o Postgresql não suporta transações aninhadas.

Carpe Diem.

Revista Postgresql Online

sexta-feira, agosto 8th, 2008

Acessando o site dbrunas.com.ar um site argentino sobre banco de dados. Encontrei um link para a revista PostgreSQL Online.
A edição de agosto da Revista PostgreSQL Online está em edição mas já tem dois artigos muito interessantes:

Boa Leitura.

PL/PGSQL Programando no Postgresql

domingo, julho 13th, 2008

Postgresql suporta uma variedade de linguagens procedurais, podemos programar uma store procedure na linguagens de nossa preferência como exemplos: Pl/Perl, Pl/Python, Pl/Java, Pl/PHP, Pl/Ruby e muitas outras. Para utilizar estas linguagens primeiro é necessário habilitar na base de dados.

O comando para habilitar a linguagem na base de dados não é complicado. Nesse post iremos utilizar a linguagem nativa do PostgreSQL que PL/PGSQL.

Habilitando a linguagem em uma bases de dados.

create lang plpgsql nomedabasededados

Por exemplo na base de dados book

create lang plpgsql book

Este comando deve ser executado no shell.

O exemplo tem a finalidade de mostrar o poder de um procedimento armazenado (store procedure) da linguagem PL/PGSQL está linguagem somente irá atuar dentro da base de dados, então não será possível executar comandos externos. Caso seja necessário é possível desenvolver uma função externa em C ou usar uma linguagem procedural não confiável a qual pode inserir algum risco de segurança a base de dados.

Voltando ao exemplo vamos desenvolver o algoritmo da torre de hanoi em PL/PGSQL.

CREATE FUNCTION towerHanoi(ndisk INTEGER,src INTEGER,dst INTEGER, tmp INTEGER) RETURNS void AS '
Declare

BEGIN
	IF ndisk = 1 THEN
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,dst;
	ELSE
		perform towerHanoi(ndisk - 1,src,dst,tmp);
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,tmp;
		perform towerHanoi(ndisk - 1,src,tmp,src);
	END IF;

END;
' LANGUAGE 'plpgsql';

Executando a função
select towerHanoi(3,1,2,3);

Veja o resultado da função

NOTA: DISK 1 Move da haste 1 para haste 2
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 2 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 1 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 3 Move da haste 1 para haste 3
NOTA: DISK 1 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
NOTA: DISK 2 Move da haste 1 para haste 1
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
NOTA: DISK 1 Move da haste 1 para haste 1
CONTEXT: comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 - 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform

Total query runtime: 2 ms.
Data retrieval runtime: 7 ms.
1 rows retrieved.

Esta simples função demonstra como usar recursividade, passagem de parâmetros e como chamar uma função em PL/PGSQL.

Estou pesquisando pra ver se consigo fazer uma árvore binária em PL/PGSQL. Quando eu conseguir coloco o algoritmo.

Abraços

Hei pessoal não se esqueçam a assinatura dos feeds é gratuita então não percam tempo.

Explorando o PostgreSQL - Como descobrir o tamanho de uma tabela no disco

sábado, julho 12th, 2008

imagem postgresqlA algum tempo atrás, surgiu a necessidade de saber o tamanho de cada tabela em bytes, numa base de dados (database) Postgresql. Era necessário para estimar o crescimento destas tabelas e saber quanto tempo levaria que esgotar a capacidade do HD.
Nesta pesquisa encontrei muitos dados interessantes que irei compartilhar com vocês. Claro que para alguns não terá novidade nenhuma nesta matéria, mas com certeza será valioso para alguém como foi para mim.

Antes de começar temos que entender como o postgresql gerencia os arquivos da base de dados, então vamos explora-lo.

Como PostgreSQL gerencia os arquivos da base de dados ?

O conceito fundamental do Postgresql e de outros SGBDS é que os dados são armazenados em tabelas e as tabelas agrupadas em base de dados (databases). Em um nível mais alto desta organização as base de dados são agrupadas em clusters – e um cluster de base de dados é gerenciado pelo postmaster.

E como fica essa hierarquia no disco ?

Para descobrir como funciona essa hierarquia na prática vamos fazer umas consultas (queries) , executar um comandos no shell.
Vamos começar conectando a base de dados e descobrindo o OID (Obect ID) através de uma consulta.

~$ psql book -U postgres

book=# SELECT datname, oid from pg_database;

datname oid
postgres 10819
book 16384
template1 1
template0 10818

(4 registros)

Na resposta da nossa query podemos ver que temos 4 base de dados (databases) no cluster. Agora podemos encontrar as base de dados no disco dentro do diretório $PG_DATA.

~$ cd $PG_DATA
~$ ls
base pg_clog pg_ident.conf pg_subtrans pg_twophase pg_xlog postmaster.opts
global pg_hba.conf pg_multixact pg_tblspc PG_VERSION postgresql.conf postmaster.pid

Dentro do subdiretório base encontra-se as base de dados no SELECT que executamos antes tem um oid 1 para a base de dados (datname) template1. Vamos entrar dentro do diretório base e ver o que tem por lá.
~$ cd base
~$ ls -la
drwx—— 2 postgres postgres 2648 Jul 11 11:17 1
drwx—— 2 postgres postgres 2648 Jul 11 11:17 10818
drwx—— 2 postgres postgres 2680 Jul 11 11:18 10819
drwx—— 2 postgres postgres 2680 Jul 11 11:39 16384

Neste exemplo temos 4 diretórios o mesmo números de registros quando executamos o SELECT então isso demonstra que o OID(object ID) corresponde ao nome do diretorio dentro da base de dados. Como exemplo o diretórios 1 corresponde a base de dados template1.
Entrando no diretório 1 podemos ver que existem vários arquivos vamos descobrir o que significa cada um deles.

~$ cd 1
~$ ls
10737 10747 10757 10767 1250 2603 2609 2615 2650 2656 2662 2668 2678 2684 690 2700 2831 2837 10739 10749 10759 10769 1255 2604 2610 2616 2651 2657 2663 2669
….
….

Para saber o que significa cada um desses arquivos temos que descobrir os OIDS dentro da base de dados template1. Vamos voltar ao psql

~$ psql -q -d template1
template1=# select oid, relname from pg_class;

oid relname
10762 sql_sizing
10769 pg_toast_10767
10771 pg_toast_10767_index
10767 sql_sizing_profiles
10772 table_constraints
10776 table_privileges
10780 tables
10784 triggered_update_columns
10787 triggers

Na tabela pg_class existe mais informação que pode nos ajudar a explorar a estrutura de armazenamento do PostgreSQL.

psql book -Upostgres
book=# select relname,oid,relpages, reltuples FROM pg_class ORDER BY OID;

relname oid relpages reltuples
pg_type 1247 5 242
pg_autovacuum 1248 0 0
pg_attribute 1249 28 1628
pg_autovacuum_vacrelid_index 1250 1 0
pg_proc 1255 45 1929
pg_class 1259 5 204

A coluna reltuples informa quantas tuplas tem em cada tabela. Já a coluna relpages mostra quantas páginas (pages) são requiridas para armazenar o conteúdo da tabela.

Qual a correspondência entre relpages e reltuples com o tamanho do arquivo no disco ?

Vamos listar o conteúdo do diretório e pegar dois exemplos

$ ls -l 1247 1249
-rw------- 1 postgres postgres  40960 Jul  11 11:17 1247
-rw------- 1 postgres postgres 229376 Jul 11 11:17 1249

O arquivo chamado 1247 tabela pg_type ocupa um espaço em disco e 40960 bytes. Se dividirmos 40960/5 relpages = 8192 bytes, realizando o mesmo cálculo para a tabela pg_attribute que corresponde ao arquivo 1249 que possui um tamanho em disco de 229376 bytes / 28 relpages = 8192 bytes.
O tamanho 8192 refere-se ao tamanho da página este valor é fixo como podemos verificar.

Com esta matéria acho que consegui mostrar como o PostgreSQL estrutura os dados no disco.
E como descobrir o tamanho da tabela no Hd, com certeza existe outras maneiras mas escolhi está para demonstrar também como o postgresql organiza as tabelas no HD.

Referência:
Livro PostgreSQL - Korry Douglas e Susan Douglas