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)