El operador específico al que hace referencia una expresión de operador se determina mediante el siguiente procedimiento. Tenga en cuenta que este procedimiento se ve afectado indirectamente por la precedencia de los operadores involucrados, ya que eso determinará qué subexpresiones se toman como entradas de qué operadores. Consulte la Sección 4.1.6 para obtener más información.

Resolución del tipo de operador

  1. Seleccione los operadores a considerar de la pg_operator catálogo del sistema. Si se utilizó un nombre de operador no calificado por esquema (el caso habitual), los operadores considerados son aquellos con el nombre coincidente y el recuento de argumentos que son visibles en la ruta de búsqueda actual (consulte la Sección 5.9.3). Si se proporcionó un nombre de operador calificado, solo se considerarán los operadores del esquema especificado.

    1. Si la ruta de búsqueda encuentra varios operadores con tipos de argumentos idénticos, solo se considera el que aparece antes en la ruta. Los operadores con diferentes tipos de argumentos se consideran en pie de igualdad independientemente de la posición de la ruta de búsqueda.

  2. Busque un operador que acepte exactamente los tipos de argumentos de entrada. Si existe uno (solo puede haber una coincidencia exacta en el conjunto de operadores considerados), utilícelo. La falta de una coincidencia exacta crea un peligro de seguridad al llamar, a través de un nombre calificado [8] (no típico), cualquier operador que se encuentre en un esquema que permita a los usuarios que no son de confianza crear objetos. En tales situaciones, emita argumentos para forzar una coincidencia exacta.

    1. Si un argumento de una invocación de operador binario es del tipo unknown type, luego asuma que es del mismo tipo que el otro argumento para esta verificación. Invocaciones que involucran a dos unknown entradas, o un operador unario con un unknown entrada, nunca encontrará una coincidencia en este paso.

    2. Si un argumento de una invocación de operador binario es del tipo unknown type y el otro es de un tipo de dominio, luego verifique si hay un operador que acepte exactamente el tipo base del dominio en ambos lados; si es así, utilícelo.

  3. Busque la mejor combinación.

    1. Descarte los operadores candidatos para los que los tipos de entrada no coinciden y no se pueden convertir (mediante una conversión implícita) para que coincidan. unknown Se supone que los literales se pueden convertir a cualquier cosa para este propósito. Si solo queda un candidato, utilícelo; de lo contrario, continúe con el siguiente paso.

    2. Si algún argumento de entrada es de un tipo de dominio, trátelo como si fuera del tipo base del dominio para todos los pasos posteriores. Esto asegura que los dominios actúen como sus tipos base para propósitos de resolución de operador ambiguo.

    3. Revise todos los candidatos y mantenga aquellos con las coincidencias más exactas en los tipos de entrada. Conserve todos los candidatos si ninguno tiene coincidencias exactas. Si solo queda un candidato, utilícelo; de lo contrario, continúe con el siguiente paso.

    4. Revise todos los candidatos y mantenga los que aceptan tipos preferidos (de la categoría de tipo del tipo de datos de entrada) en la mayoría de las posiciones donde se requerirá la conversión de tipo. Conserve todos los candidatos si ninguno acepta los tipos preferidos. Si solo queda un candidato, utilícelo; de lo contrario, continúe con el siguiente paso.

    5. Si los argumentos de entrada son unknown, marque las categorías de tipo aceptadas en esas posiciones de argumento por los candidatos restantes. En cada posición, seleccione el string categoría si algún candidato acepta esa categoría. (Este sesgo hacia string es apropiado ya que un literal de tipo desconocido parece un string.) De lo contrario, si todos los candidatos restantes aceptan la misma categoría de tipo, seleccione esa categoría; de lo contrario, fallará porque la elección correcta no se puede deducir sin más pistas. Ahora descarte los candidatos que no acepten la categoría de tipo seleccionada. Además, si algún candidato acepta un tipo preferido en esa categoría, descarte los candidatos que acepten tipos no preferidos para ese argumento. Conserve a todos los candidatos si ninguno sobrevive a estas pruebas. Si solo queda un candidato, utilícelo; de lo contrario, continúe con el siguiente paso.

    6. Si hay ambos unknown y argumentos de tipo conocido, y todos los argumentos de tipo conocido tienen el mismo tipo, suponga que el unknown Los argumentos también son de ese tipo, y compruebe qué candidatos pueden aceptar ese tipo en el unknown-posiciones de argumentos. Si exactamente un candidato pasa esta prueba, úsela. De lo contrario, fracasa.

A continuación se presentan algunos ejemplos.

Ejemplo 10.1. Resolución de tipo de operador de raíz cuadrada

Solo hay un operador de raíz cuadrada (prefix |/) definido en el catálogo estándar, y toma un argumento de tipo double precision. El escáner asigna un tipo inicial de integer al argumento en esta expresión de consulta:

SELECT |/ 40 AS "square root of 40";
 square root of 40
-------------------
 6.324555320336759
(1 row)

Entonces, el analizador realiza una conversión de tipo en el operando y la consulta es equivalente a:

SELECT |/ CAST(40 AS double precision) AS "square root of 40";

Ejemplo 10.2. Resolución de tipo de operador de concatenación de cadenas

A string-como sintaxis se utiliza para trabajar con string tipos y para trabajar con tipos de extensión complejos. Las cadenas con un tipo no especificado se emparejan con posibles candidatos a operadores.

Un ejemplo con un argumento no especificado:

SELECT text 'abc' || 'def' AS "text and unknown";

 text and unknown
------------------
 abcdef
(1 row)

En este caso, el analizador busca ver si hay un operador tomando text para ambos argumentos. Dado que existe, se supone que el segundo argumento debe interpretarse como tipo text.

Aquí hay una concatenación de dos valores de tipos no especificados:

SELECT 'abc' || 'def' AS "unspecified";

 unspecified
-------------
 abcdef
(1 row)

En este caso, no hay una pista inicial sobre qué tipo usar, ya que no se especifican tipos en la consulta. Entonces, el analizador busca todos los operadores candidatos y encuentra que hay candidatos que aceptan ambos string-categoría y bit-string-Categoría de entradas. Ya que string Se prefiere la categoría cuando está disponible, se selecciona esa categoría y luego el tipo preferido para cadenas, text, se usa como el tipo específico para resolver los literales de tipo desconocido como.

Ejemplo 10.3. Resolución de tipo de operador de valor absoluto y negación

El catálogo de operadores de PostgreSQL tiene varias entradas para el prefix operador @, todos los cuales implementan operaciones de valor absoluto para varios tipos de datos numéricos. Una de estas entradas es para el tipo float8, que es el tipo preferido en la categoría numérica. Por lo tanto, PostgreSQL utilizará esa entrada cuando se enfrente a una unknown aporte:

SELECT @ '-4.5' AS "abs";
 abs
-----
 4.5
(1 row)

Aquí el sistema ha resuelto implícitamente el literal de tipo desconocido como tipo float8 antes de aplicar el operador elegido. Podemos verificar que float8 y no se usó otro tipo:

SELECT @ '-4.5e500' AS "abs";

ERROR:  "-4.5e500" is out of range for type double precision

Por otro lado, el prefix operador ~ (negación bit a bit) se define solo para tipos de datos enteros, no para float8. Entonces, si probamos un caso similar con ~, obtenemos:

SELECT ~ '20' AS "negation";

ERROR:  operator is not unique: ~ "unknown"
HINT:  Could not choose a best candidate operator. You might need to add
explicit type casts.

Esto sucede porque el sistema no puede decidir cuál de los varios posibles ~ los operadores deben ser preferidos. Podemos ayudarlo con un elenco explícito:

SELECT ~ CAST('20' AS int8) AS "negation";

 negation
----------
      -21
(1 row)

Ejemplo 10.4. Resolución de tipo de operador de inclusión de matriz

Aquí hay otro ejemplo de cómo resolver un operador con una entrada conocida y una desconocida:

SELECT array[1,2] <@ '1,2,3' as "is subset";

 is subset
-----------
 t
(1 row)

El catálogo de operadores de PostgreSQL tiene varias entradas para el operador infijo <@, pero los únicos dos que posiblemente podrían aceptar un número entero array en el lado izquierdo están array inclusiónanyarray<@anyarray) e inclusión de rango (anyelement<@anyrange). Dado que ninguno de estos pseudo-tipos polimórficos (consulte la Sección 8.21) se considera preferido, el analizador no puede resolver la ambigüedad sobre esa base. Sin embargo, el Paso 3.f le dice que asuma que el literal de tipo desconocido es del mismo tipo que la otra entrada, es decir, entero array. Ahora solo uno de los dos operadores puede coincidir, por lo que array se selecciona la inclusión. (Si se hubiera seleccionado la inclusión de rango, habríamos obtenido un error, porque el string no tiene el formato correcto para ser un literal de rango).

Ejemplo 10.5. Operador personalizado en un tipo de dominio

Los usuarios a veces intentan declarar operadores que se aplican solo a un tipo de dominio. Esto es posible, pero no es tan útil como podría parecer, porque las reglas de resolución de operadores están diseñadas para seleccionar operadores que se aplican al tipo base del dominio. Como ejemplo, considere

CREATE DOMAIN mytext AS text CHECK(...);
CREATE FUNCTION mytext_eq_text (mytext, text) RETURNS boolean AS ...;
CREATE OPERATOR = (procedure=mytext_eq_text, leftarg=mytext, rightarg=text);
CREATE TABLE mytable (val mytext);

SELECT * FROM mytable WHERE val = 'foo';

Esta consulta no utilizará el operador personalizado. El analizador primero verá si hay un mytext=mytext operador (Paso 2.a), que no existe; entonces considerará el tipo base del dominio texty ver si hay un text=text operador (Paso 2.b), que hay; por lo que resuelve el unknown-tipo literal como text y usa el text=text operador. La única forma de utilizar el operador personalizado es emitir explícitamente el literal:

SELECT * FROM mytable WHERE val = text 'foo';

de manera que la mytext=text El operador se encuentra inmediatamente de acuerdo con la regla de coincidencia exacta. Si se alcanzan las reglas de mejor coincidencia, discriminan activamente a los operadores por tipos de dominio. Si no lo hicieran, dicho operador crearía demasiadas fallas de operador ambiguo, porque las reglas de conversión siempre consideran un dominio como convertible ao desde su tipo base, por lo que el operador de dominio se consideraría utilizable en todos los mismos casos como un operador con nombre similar en el tipo base.

[8] El peligro no surge con un nombre no calificado por esquema, porque una ruta de búsqueda que contiene esquemas que permiten a los usuarios que no son de confianza crear objetos no es un patrón de uso de esquema seguro.

Anterior Hasta próximo
10.1. Visión general Hogar 10.3. Funciones