| Documentação do PostgreSQL 8.0.0 | ||||
|---|---|---|---|---|
| Anterior | Início | Capítulo 31. Estendendo a linguagem SQL | Fim | Próxima |
Todo operador é uma "suavização sintática" para a chamada a uma função subjacente que realiza o trabalho real; portanto, primeiro deve ser criada a função subjacente para depois ser criado o operador. Entretanto o operador não é meramente uma suavização sintática, porque possui informações adicionais para ajudar o otimizador de comandos a otimizar os comandos que utilizam o operador. A próxima seção se dedica a explicar estas informações adicionais.
O PostgreSQL dá suporte a operador unário esquerdo, unário direito e binário. Os operadores podem ser sobrecarregados, ou seja, o mesmo nome de operador pode ser utilizado por operadores diferentes que possuam número ou tipo diferente de operandos. Quando o comando é executado, o sistema determina o operador a ser chamado a partir do número e tipo dos operandos fornecidos.
Abaixo segue um exemplo da criação de um operador para adicionar dois números complexos. É assumido que já se tenha criado a definição do tipo complex (consulte a Seção 31.11). Primeiro é necessária uma função para fazer o trabalho, para depois ser definido o operador:
CREATE FUNCTION complex_add(complex, complex)
RETURNS complex
AS 'nome_do_arquivo', 'complex_add'
LANGUAGE C IMMUTABLE STRICT;
CREATE OPERATOR + (
leftarg = complex,
rightarg = complex,
procedure = complex_add,
commutator = +
);
Agora é possível executar um comando como este:
SELECT (a + b) AS c FROM test_complex;
c
-----------------
(5.2,6.05)
(133.42,144.95)
Aqui foi mostrado como criar um operador binário. Para criar um operador binário deve-se apenas omitir leftarg (para operadores unários esquerdo) ou rightarg (para operadores unários direito). A cláusula procedure e as cláusulas de argumento são os únicos itens requeridos pelo comando CREATE OPERATOR. A cláusula commutator mostrada no exemplo é uma dica opcional para o otimizador de comandos. Na próxima seção podem ser obtidos mais detalhes sobre a cláusula commutator e outras dicas para o otimizador.
Nota: Seção escrita pelo tradutor, não fazendo parte do manual original.
Os exemplos de operadores definidos pelo usuário mostrados nesta seção utilizam os dados da tabela tbl_santos mostrada abaixo:
CREATE TABLE tbl_santos (nome text);
INSERT INTO tbl_santos VALUES('São José');
INSERT INTO tbl_santos VALUES(' São Bento ');
INSERT INTO tbl_santos VALUES('SAO BENEDITO');
INSERT INTO tbl_santos VALUES(NULL);
INSERT INTO tbl_santos VALUES('SAO BENTO');
INSERT INTO tbl_santos VALUES('Santa Clara');
\pset null '(nulo)'
\pset border 2
\pset title 'Tabela tbl_santos'
SELECT * FROM tbl_santos;
Tabela tbl_santos
+--------------+
| nome |
+--------------+
| São José |
| São Bento |
| SAO BENEDITO |
| (nulo) |
| SAO BENTO |
| Santa Clara |
+--------------+
(6 linhas)
Exemplo 31-10. Operadores para comparar texto sem diferenciar letras minúsculas, maiúsculas ou acentuadas
Os operadores binários definidos pelo usuário mostrados neste exemplo (<<<, >>>, !== e ===) têm por finalidade comparar dois textos sem diferenciar letras minúsculas, maiúsculas ou acentuadas, e também desprezando os espaços em branco no início e no fim dos textos. Além de serem utilizados para comparar dois textos diretamente, estes operadores também são utilizados em consultas para classificar a saída em ordem ascendente e descendente através da cláusula ORDER BY expressão USING operador do comando SELECT.
Abaixo está mostrado o arquivo operador.sql utilizado para criar e testar os operadores:
/*
* Retorna verdade se os dois argumentos forem considerados iguais,
* falso caso contrário.
*/
CREATE FUNCTION fun_igual_ci_ai(a text, b text) RETURNS boolean AS $$
BEGIN
RETURN (lower(to_ascii(trim(a))) = lower(to_ascii(trim(b))));
END;
$$ LANGUAGE plpgsql STRICT;
/*
* Retorna verdade se os dois argumentos forem considerados diferentes,
* falso caso contrário.
*/
CREATE FUNCTION fun_difer_ci_ai(a text, b text) RETURNS boolean AS $$
BEGIN
RETURN (lower(to_ascii(trim(a))) != lower(to_ascii(trim(b))));
END;
$$ LANGUAGE plpgsql STRICT;
/*
* Retorna verdade se o primeiro argumento for considerado maior que o
* segundo argumento, falso caso contrário.
*/
CREATE FUNCTION fun_maior_ci_ai(a text, b text) RETURNS boolean AS $$
BEGIN
RETURN (lower(to_ascii(trim(a))) > lower(to_ascii(trim(b))));
END;
$$ LANGUAGE plpgsql STRICT;
/*
* Retorna verdade se o primeiro argumento for considerado menor que o
* segundo argumento, falso caso contrário.
*/
CREATE FUNCTION fun_menor_ci_ai(a text, b text) RETURNS boolean AS $$
BEGIN
RETURN (lower(to_ascii(trim(a))) < lower(to_ascii(trim(b))));
END;
$$ LANGUAGE plpgsql STRICT;
/*
* Criação dos operadores que implementam as funções de comparação.
*/
CREATE OPERATOR <<< (
PROCEDURE = fun_menor_ci_ai,
LEFTARG = text,
RIGHTARG = text
);
CREATE OPERATOR >>> (
PROCEDURE = fun_maior_ci_ai,
LEFTARG = text,
RIGHTARG = text
);
CREATE OPERATOR !== (
PROCEDURE = fun_difer_ci_ai,
LEFTARG = text,
RIGHTARG = text
);
CREATE OPERATOR === (
PROCEDURE = fun_igual_ci_ai,
LEFTARG = text,
RIGHTARG = text
);
\pset border 2
\pset null '(nulo)'
\pset title 'Resultados das expressões'
SELECT
''' São Bento '' = ''SAO BENTO''' AS expressão,
' São Bento ' = 'SAO BENTO' AS resultado
UNION
SELECT
''' São Bento '' === ''SAO BENTO''',
' São Bento ' === 'SAO BENTO'
UNION
SELECT
''' São Bento '' === NULL',
' São Bento ' === NULL
UNION
SELECT
''' São Bento '' === '' SAO BENEDITO''',
' São Bento ' === ' SAO BENEDITO'
UNION
SELECT
''' São Bento '' !== ''SAO BENTO''',
' São Bento ' !== 'SAO BENTO'
UNION
SELECT
''' São Bento '' >>> '' SAO BENEDITO''',
' São Bento ' >>> ' SAO BENEDITO'
UNION
SELECT
''' São Bento '' <<< '' SAO BENEDITO''',
' São Bento ' <<< ' SAO BENEDITO';
\pset title 'Ascendente'
SELECT nome FROM tbl_santos ORDER BY nome USING <<<;
\pset title 'Descendente'
SELECT nome FROM tbl_santos ORDER BY nome USING >>>;
A seguir está mostrado o resultado do processamento do arquivo:
# psql -U teste -f operador.sql -o operador.out -q teste
# cat operador.out
Resultados das expressões
+-------------------------------------+-----------+
| expressão | resultado |
+-------------------------------------+-----------+
| ' São Bento ' !== 'SAO BENTO' | f |
| ' São Bento ' <<< ' SAO BENEDITO' | f |
| ' São Bento ' = 'SAO BENTO' | f |
| ' São Bento ' === ' SAO BENEDITO' | f |
| ' São Bento ' === 'SAO BENTO' | t |
| ' São Bento ' === NULL | (nulo) |
| ' São Bento ' >>> ' SAO BENEDITO' | t |
+-------------------------------------+-----------+
(7 linhas)
Ascendente
+--------------+
| nome |
+--------------+
| Santa Clara |
| SAO BENEDITO |
| São Bento |
| SAO BENTO |
| São José |
| (nulo) |
+--------------+
(6 linhas)
Descendente
+--------------+
| nome |
+--------------+
| São José |
| SAO BENTO |
| São Bento |
| SAO BENEDITO |
| Santa Clara |
| (nulo) |
+--------------+
(6 linhas)
Exemplo 31-11. Operador para concatenar texto sem nunca retornar nulo
O operador binário definido pelo usuário mostrado neste exemplo (||+) têm por finalidade concatenar dois textos sem nunca retornar o valor nulo. Este exemplo foi baseado no artigo How to add custom operators in PostgreSQL, escrito por Josh Berkus.
Abaixo está mostrado o arquivo concatena.sql utilizado para criar e testar o operador:
/*
* Concatena duas cadeias de caracteres sem nunca retornar nulo.
*/
CREATE FUNCTION fun_concatena_nunca_nulo(text, text) RETURNS text AS $$
SELECT COALESCE($1,'') || COALESCE($2,'');
$$ LANGUAGE SQL IMMUTABLE;
CREATE OPERATOR ||+ (
PROCEDURE = fun_concatena_nunca_nulo,
LEFTARG = text,
RIGHTARG = text
);
\pset border 2
\pset null '(nulo)'
\pset title 'Resultados das expressões'
SELECT
'''Postgre'' || NULL' AS expressão,
'Postgre' || NULL AS resultado
UNION
SELECT
'''Postgre'' ||+ NULL',
'Postgre' ||+ NULL
UNION
SELECT
'NULL ||+ ''SQL''',
NULL ||+ 'SQL'
UNION
SELECT
'''Postgre'' ||+ ''SQL''',
'Postgre' ||+ 'SQL'
UNION
SELECT
'NULL || NULL',
NULL || NULL
UNION
SELECT
'NULL ||+ NULL',
NULL ||+ NULL
;
A seguir está mostrado o resultado do processamento do arquivo:
# psql -U teste -f concatena.sql -o concatena.out -q teste
# cat concatena.out
Resultados das expressões
+---------------------+------------+
| expressão | resultado |
+---------------------+------------+
| 'Postgre' || NULL | (nulo) |
| 'Postgre' ||+ 'SQL' | PostgreSQL |
| 'Postgre' ||+ NULL | Postgre |
| NULL || NULL | (nulo) |
| NULL ||+ 'SQL' | SQL |
| NULL ||+ NULL | |
+---------------------+------------+
(6 linhas)