Archives for outubro, 2008

PL/PGSQL Funções Aninhadas

Posted on out 29, 2008 under Tutoriais | No Comment

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

Posted on out 29, 2008 under Tutoriais | No Comment

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.

Desligando o computador após download

Posted on out 18, 2008 under Python, Sem categoria | 4 Comentários

Ontem foi a gota d’água!! Começei um download as 22:00H, já era 00:30H e nada do download terminar, faltava 40% para o download terminar, e estava louco de sono. Então me inspirei e desenvolvi um pequeno script em Python, para desligar o notebook após o download ser concluído.

Utilizei o firefox para realizar o download, o qual possui a característica de adicionar ao nome do download a extensão .part. Através desse princípio desenvolvi o script, o qual verifica a existência do arquivo *.part, existindo o arquivo o script dorme por um minuto, quando o arquivo deixar de existir o computador será desligado.

import os.path
from time import sleep
import commands

while 1:

        if os.path.exists('/home/marlon/downloads/teste.rar.part'):
                print 'espera 1 minuto'
                sleep(60)
        else:
                os.system("poweroff")

Hoje pela manhã, o computador estava desligado!

A linguagem Python é muito versátil e elegante, excelente para desenvolvimento rápido. Este script pode ser modificado para tomar a decisão através do tamanho do arquivo, que com Python pode ser descoberto através do método os.path.getsize(‘file’).

Forte abraço.

HD perdeu a tabela de partições

Posted on out 07, 2008 under Dicas Linux | 2 Comentários

Quem já passou por isso ?
A uns dias atrás fui ligar meu notebook e recebi a seguinte mensagem: Operation System not found. Corri na prateleira para pegar o cd de boot do Kurumin, inicializou sem problemas, o hd foi encontrado na inicialização. Mas, sem nenhuma partição. Depois de alguns minutos tentando contabilizar tudo que tinha perdido, algo em torno de 90GB de informação, como por exemplo, códigos fontes, livros, trabalhos da faculdade, artigos, monografia. Claro que tudo tinha backup, mas desatualizado no mínimo 3 meses.
Então começou a saga para tentar resolver o problema. Encontrei dois utilitários gpart e testdisk, estes programas escaneiam o HD em busca do início e do final das partições, a diferença entre eles é o algoritmo de busca.
Comecei utilizando o gpart conforme o comando abaixo. O qual escaneou o HD e não encontrou nenhuma partição, sendo que para escanear o HD levou umas boas horas.
./gpart.linux /dev/hda

Dando seguimento a saga para recuperar algo, tentei o testdisk. Já esse encontrou algumas partições primárias e outras estendidas. Fiquei loco de faceiro, pensei! solucionei o problema. Reiniciei a máquina quando fui montar as partições, somente obtive erros.

Ainda não desiste estou tentando novamente o gpart com alguns parâmetros diferentes. Para encontrar a tabela certinha é necessário que a geometria do disco esteja correta, ou seja, os parâmetros: número de cilindros(cylinders), cabeças(heads) e setores (sectors) estejam corretos. Esse valores podem ser descobertos com o seguinte comando:

#/dmesg | grep CHS

Ajustei os parâmetros no gpart.

gpart -C C,H,S /dev/hda

Onde C é número de cilindros, H heads ,….

Neste momento estou executando novamente o gpart. Desta vez já estou com os dedos cruzados.

Uma dica fácil e muito útil faça um backup da sua tabela de partição com o comando abaixo, será muito útil.

Backup da tabela de partições

dd if=/dev/hda of=hda.mbr bs=512 count=1

Fomato legível

fdisk -l > partitions.txt

Restaurar

dd if=hda.mbr of=/dev/hda bs=512 count=1

Ahh!!!. Se eu tivesse feito isso antes.

Grande abraço a todos.