7.2. Operadores

Os tipos dos operandos em chamadas de operador são resolvidos utilizando o procedimento descrito abaixo. Observe que este procedimento é indiretamente afetado pela precedência dos operadores envolvidos. Veja a Seção 1.1.6 para obter mais informações.

Determinação do tipo do operando

  1. Selecionar no catálogo do sistema pg_operator os operadores a ser considerados. Se um nome não qualificado de operador for utilizado (o caso usual), os operadores considerados são aqueles com o mesmo nome e número de argumentos visíveis no caminho de procura corrente (veja a Seção 2.8.3). Se um nome qualificado de operador for fornecido, somente os operadores no esquema especificado são considerados.

    1. Se no caminho de procura forem encontrados vários operadores com argumentos do mesmo tipo, somente o que aparece primeiro no caminho é considerado. Mas os operadores com argumentos de tipos diferentes são levados em consideração com a mesma precedência, não importando a posição no caminho de procura.

  2. Verificar se algum operador aceita os mesmos tipos de dado dos argumentos de entrada. Caso exista (só pode haver uma correspondência exata no conjunto de operadores considerados), este é usado.

    1. Se um dos argumentos de um operador binário for do tipo unknown (desconhecido), então pressupõe-se possuir o mesmo tipo do outro argumento nesta verificação. Outros casos envolvendo o tipo unknown nunca encontram correspondência nesta etapa.

  3. Procurar pela melhor correspondência.

    1. Rejeitar os operadores candidatos para os quais os tipos da entrada não correspondem e não podem ser forçados (utilizando uma função implícita de conversão) a corresponder. Pressupõe-se que os literais do tipo unknown podem ser convertidos em qualquer outro tipo para esta finalidade. Se apenas um operador candidato permanecer, então este é usado; senão continuar na próxima etapa.

    2. Examinar todos os operadores candidatos, e manter aqueles com mais correspondências exatas com os tipos da entrada. Manter todos os candidatos se nenhum possuir alguma correspondência exata. Se apenas um candidato permanecer, este é usado; senão continuar na próxima etapa.

    3. Examinar todos os operadores candidatos, e manter aqueles com mais correspondências exatas ou correspondências compatíveis binariamente com os tipos da entrada. Manter todos os candidatos se nenhum possuir correspondências exatas ou binariamente compatíveis. Se apenas um operador candidato permanecer, este é usado; senão continuar na próxima etapa.

    4. Examinar todos os operadores candidatos, e manter aqueles que aceitam os tipos preferidos em mais posições onde a conversão de tipo será necessária. Manter todos os candidatos se nenhum aceitar os tipos preferidos. Se apenas um operador candidato permanecer, este é usado; senão continuar na próxima etapa.

    5. Se algum dos argumentos de entrada for do tipo "unknown", verificar as categorias de tipo aceitas nesta posição do argumento pelos candidatos remanescentes. Em cada posição, selecionar a categoria string se qualquer um dos candidatos aceitar esta categoria (isto faz a cadeia de caracteres parecer apropriada porque todo literal de tipo desconhecido se parece com uma cadeia de caracteres). Senão, se todos os candidatos remanescentes aceitam a mesma categoria de tipo, selecionar esta categoria; senão falha porque a escolha correta não pode ser deduzida sem mais informações. Também observa se algum dos candidatos aceita um tipo de dado preferido dentro da categoria selecionada. Agora rejeita os operadores candidatos que não aceitam a categoria de tipo selecionada; além disso, se algum operador candidato aceitar o tipo preferido em uma dada posição do argumento, rejeitar os candidatos que aceitam tipos não preferidos para este argumento.

    6. Se apenas um operador candidato permanecer, este é usado; Se nenhum candidato, ou mais de um candidato, permanecer, então falha.

Exemplos

Exemplo 7-1. Determinação do tipo em operador de exponenciação

Existe apenas um operador de exponenciação definido no catálogo, e recebe argumentos do tipo double precision. Inicialmente é atribuído o tipo integer para os dois argumentos desta expressão de consulta:

tgl=> SELECT 2 ^ 3 AS "Exp";
 Exp
-----
   8
(1 row)

Portanto, o analisador faz uma conversão de tipo nos dois operandos e a consulta fica equivalente a

tgl=> SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "Exp";
 Exp
-----
   8
(1 row)

ou

tgl=> SELECT 2.0 ^ 3.0 AS "Exp";
 Exp
-----
   8
(1 row)

Nota: Esta última forma ocasiona menos trabalho adicional, porque nenhuma função é chamada para fazer a conversão implícita de tipo. Isto não causa problema em consultas pequenas, mas pode ter impacto no desempenho das consultas envolvendo tabelas grandes.

Exemplo 7-2. Determinação do tipo em operador de concatenação de cadeia de caracteres

Uma sintaxe estilo cadeia de caracteres é utilizada para trabalhar com tipos string, assim como para trabalhar com tipos estendidos complexos. Cadeias de caracteres de tipo não especificado são correspondidas por praticamente todos os operadores candidatos.

Um exemplo com um argumento não especificado:

tgl=> SELECT text 'abc' || 'def' AS "Texto e Desconhecido";
 Texto e Desconhecido
----------------------
 abcdef
(1 row)

Neste caso o analisador procura pela existência de algum operador recebendo o tipo text nos dois argumentos. Existindo, pressupõe que o segundo argumento deve ser interpretado como sendo do tipo text.

Concatenação de tipos não especificados:

tgl=> SELECT 'abc' || 'def' as "Não Especificado";
 Não Especificado
------------------
 abcdef
(1 row)

Neste caso não existe nenhuma informação inicial do tipo a ser usado, porque nenhum tipo foi especificado na consulta. Portanto, o analisador procura todos os operadores candidatos e descobre que existem candidatos aceitando as categorias de entrada cadeia de caracteres e cadeia de bits. Uma vez que a categoria cadeia de caracteres é a preferida quando está disponível, então o "tipo preferido" para cadeias de caracteres, text, é utilizado como o tipo específico para resolver os literais desconhecidos.

Exemplo 7-3. Determinação do tipo em operador de valor absoluto e em fatorial

O catálogo de operadores do PostgreSQL possui várias entradas para o operador de prefixo @, todas implementando operações de valor absoluto para vários tipos de dado numéricos. Uma destas entradas é para o tipo float8, que é o tipo preferido na categoria numérica. Portanto, o PostgreSQL usa esta entrada quando confrontado com uma entrada não numérica:

tgl=> select @ text '-4.5' as "abs";
 abs
-----
 4.5
(1 row)

Aqui o sistema realiza uma conversão implícita text-to-float8 antes de aplicar o operador escolhido. Pode ser verificado que o float8, e não algum outro tipo, foi utilizado:

tgl=> select @ text '-4.5e500' as "abs";
ERROR:  Input '-4.5e500' is out of range for float8

Por outro lado, o operador de sufixo ! (fatorial) é definido apenas para tipos de dado inteiros, e não para float8. Portanto, se tentarmos algo semelhante usando o !, resulta em:

tgl=> select text '20' ! as "fatorial";
ERROR:  Unable to identify a postfix operator '!' for type 'text'
        You may need to add parentheses or an explicit cast

Isto acontece porque o sistema não pode decidir qual dos vários operadores ! possíveis deve ser o preferido. Pode ser dada uma ajuda usando uma transformação explícita:

tgl=> select cast(text '20' as int8) ! as "fatorial";
      fatorial
---------------------
 2432902008176640000
(1 row)