Métodos

Un método de base de datos de un tipo estructurado es una relación entre un conjunto de valores de datos de entrada y un conjunto de valores resultantes, donde el primer valor de entrada (o argumento sujeto) tiene el mismo tipo, o es un subtipo del tipo sujeto (también llamado parámetro sujeto) del método.

Por ejemplo, es posible pasar valores de datos de entrada de tipo VARCHAR a un método denominado CITY, de tipo ADDRESS y el resultado será un valor ADDRESS (o un subtipo de ADDRESS).

Los métodos se definen implícita o explícitamente, como parte de la definición de un tipo estructurado definido por el usuario.

Los métodos definidos implícitamente se crean para cada tipo estructurado. Se definen métodos observadores para cada atributo del tipo estructurado. Los métodos observadores permiten que una aplicación obtenga el valor de un atributo para una instancia del tipo. También se definen métodos mutadores para cada atributo, que permiten que una aplicación cambie la instancia de tipo modificando el valor de un atributo de una instancia de tipo. El método CITY descrito anteriormente es un ejemplo de método mutador para el tipo ADDRESS.

Los métodos definidos explícitamente o métodos definidos por el usuario son métodos que se registran en el catálogo SYSCAT.ROUTINES de una base de datos, utilizando una combinación de las sentencias CREATE TYPE (o ALTER TYPE ADD METHOD) y CREATE METHOD. Todos los métodos definidos para un tipo estructurado se definen en el mismo esquema que el tipo.

Los métodos definidos por el usuario para tipos estructurados amplían la función de sistema de bases de datos añadiendo definiciones de método (proporcionadas por usuarios o proveedores) que pueden aplicarse a instancias de tipo estructurado en el núcleo de la base de datos. La definición de los métodos de la base de datos permite que la base de datos explote los mismos métodos en su núcleo que los que utiliza una aplicación, proporcionando más sinergia entre la aplicación y la base de datos.

Métodos definidos por el usuario externos y SQL

Un método definido por el usuario puede ser externo o estar basado en una expresión SQL. Un método externo se define para la base de datos con una referencia a una biblioteca de códigos objeto y una función en dicha biblioteca que se ejecutará cuando se invoque el método. Un método basado en una expresión SQL devuelve el resultado de la expresión SQL cuando se invoca el método. Tales métodos no necesitan ninguna biblioteca de códigos objeto, ya que están escritos completamente en SQL.

Un método definido por el usuario puede devolver un sólo valor cada vez que se invoca. Este valor puede ser un tipo estructurado. Un método se puede definir como preservador del tipo (utilizando SELF AS RESULT), para permitir que el tipo dinámico del argumento sujeto sea el tipo devuelto del método. Todos los métodos mutadores definidos implícitamente son preservadores del tipo.

Signaturas de método

Un método se identifica por su tipo sujeto, un nombre de método, el número de parámetros y los tipos de datos de sus parámetros. Esto se denomina una signatura de método y debe ser exclusiva en la base de datos.

Puede existir más de un método con el mismo nombre para un tipo estructurado, siempre que:
  • El número de parámetros o los tipos de datos de los parámetros sean diferentes o
  • Los métodos formen parte de la misma jerarquía de métodos (es decir, los métodos estén en una relación de alteración temporal o alteren temporalmente el mismo método original) o
  • No exista la misma signatura de función (utilizando el tipo sujeto o cualquiera de sus subtipos o supertipos como primer parámetro).

Un nombre de método que tiene varias instancias de método se denomina método sobrecargado. Un nombre de método puede estar sobrecargado dentro de un tipo, lo que significa que existe más de un método de ese nombre para el tipo (todos los cuales tienen diferentes tipos de parámetros). Un nombre de método también puede estar sobrecargado en la jerarquía de tipos sujeto, en cuyo caso existe más de un método con ese nombre en la jerarquía de tipos. Estos métodos deben tener tipos de parámetros distintos.

Un método se puede invocar haciendo referencia (en un contexto permitido) al nombre de método, precedido por una referencia a una instancia de tipo estructurado (el argumento sujeto) y por el operador de doble punto. A continuación debe seguir una lista de argumentos entre paréntesis. El método que se invoca realmente depende del tipo estático del tipo sujeto, utilizando el proceso de resolución de métodos descrito en la sección siguiente. Los métodos definidos con WITH FUNCTION ACCESS también se pueden invocar utilizando la invocación de funciones, en cuyo caso se aplican las normas normales para la resolución de la función.

Si la resolución de la función da como resultado un método definido con WITH FUNCTION ACCESS, se procesan todos los pasos siguientes de invocación de métodos.

El acceso a los métodos se controla mediante el privilegio EXECUTE. Se utilizan sentencias GRANT y REVOKE para especificar quién puede o no puede ejecutar un método o conjunto de métodos determinado. Se necesita el privilegio EXECUTE (o la autorización DATAACCESS) para invocar un método. La persona que define el método recibe el privilegio EXECUTE de forma automática. Si se trata de un método externo o un método SQL que tienen la opción WITH GRANT en todos los objetos subyacentes, la persona que lo define también recibe la opción WITH GRANT con el privilegio EXECUTE sobre el método. El definidor (o el ID que tenga autorización ACCESSCTRL o SECADM) debe otorgarse, pues, al usuario que desee invocar el método desde cualquier sentencia de SQL o hacer referencia al método en cualquier sentencia DDL (como CREATE VIEW, CREATE TRIGGER o al definir una restricción). Si no se otorga a un usuario el privilegio EXECUTE, el algoritmo de resolución de métodos no tendrá en cuenta el método aunque éste se corresponda mucho mejor.

Resolución de métodos

Después de invocar un método, el gestor de bases de datos debe decidir cuál de los posibles métodos con el mismo nombre es el más apropiado . Las funciones (incorporadas o definidas por el usuario) no se tienen en cuenta durante la resolución del método.

Un argumento es un valor que se pasa a un método en una invocación. Cuando un método se invoca en SQL, se le pasa el argumento sujeto (de algún tipo estructurado) y opcionalmente una lista de argumentos. Son argumentos posicionales en tanto que la semántica de dichos argumentos viene determinada por su posición en la lista de argumentos. Un parámetro es una definición formal de una entrada en un método. Cuando se define un método para la base de datos, ya sea implícitamente (método generado por el sistema para un tipo) o por un usuario (método definido por el usuario), se especifican sus parámetros (con el parámetro sujeto como primer parámetro) y el orden de sus definiciones determina sus posiciones y su semántica. Por tanto, cada parámetro es una entrada posicional determinada de un método. En la invocación, un argumento corresponde a un parámetro determinado en virtud a la posición que éste ocupe en la lista de argumentos.

El gestor de bases de datos utiliza el nombre de método proporcionado en la invocación, el privilegio EXECUTE sobre el método, el número y los tipos de datos de los argumentos, todos los métodos que tienen el mismo nombre para el tipo estático del argumento sujeto y los tipos de datos de sus parámetros correspondientes como base para decidir si selecciona o no un método. A continuación se muestran los resultados posibles del proceso de decisión:

  • Un método determinado se considera que es el más apropiado. Por ejemplo, para los métodos denominados RISK del tipo SITE con signaturas definidas como:
       PROXIMITY(INTEGER) FOR SITE 	
       PROXIMITY(DOUBLE) FOR SITE
    la siguiente invocación de método (donde ST es una columna SITE, DB es una columna DOUBLE):
       SELECT ST..PROXIMITY(DB) ...  
    se elegiría el segundo PROXIMITY.
    La siguiente invocación de método (donde SI es una columna SMALLINT):
       SELECT ST..PROXIMITY(SI) ...
    elegirá el primer PROXIMITY, ya que SMALLINT se puede promover a INTEGER y es una coincidencia mejor que DOUBLE, que se encuentra más abajo en la lista de prioridad.

    Cuando se tienen en cuenta argumentos que son tipos estructurados, la lista de prioridad incluye los supertipos del tipo estático del argumento. La función que mejor se ajusta es la definida con el parámetro de supertipo más cercano, en la jerarquía de tipos estructurados, al tipo estático del argumento de función.

  • Ningún método se considera una opción aceptable. Tomando como ejemplo las dos mismas funciones del caso anterior y la siguiente referencia de función (donde C es una columna CHAR(5)):
       SELECT ST..PROXIMITY(C) ...
    el argumento es incoherente con el parámetro de las dos funciones PROXIMITY.
  • Se selecciona un método determinado basándose en los métodos de la jerarquía de tipos y en el número y tipos de datos de los argumentos pasados en la invocación. Por ejemplo, para los métodos denominados RISK de los tipos SITE y DRILLSITE (un subtipo de SITE) con signaturas definidas como:
       RISK(INTEGER) FOR DRILLSITE
       RISK(DOUBLE) FOR SITE
    y la siguiente invocación de método (donde DRST es una columna DRILLSITE, DB es una columna DOUBLE):
       SELECT DRST..RISK(DB) ...
    se elegirá el segundo RISK, ya que DRILLSITE se puede promocionar a SITE.
    La siguiente referencia a método (donde SI es una columna SMALLINT):
       SELECT DRST..RISK(SI) ...
    elegirá el primer RISK, ya que SMALLINT se puede promocionar a INTEGER, que está más cerca en la lista de prioridad que DOUBLE, y DRILLSITE es una opción mejor que SITE, que es un supertipo.

    Los métodos con la misma jerarquía de tipos no pueden tener las mismas signaturas, teniendo en cuenta parámetros distintos al parámetro sujeto.

Determinación de la mejor opción

La comparación de los tipos de datos de los argumentos con los tipos de datos definidos de los parámetros de los métodos en cuestión, constituye la base primordial para decidir qué método de un grupo de métodos con el mismo nombre se considera el más apropiado. Observe que los tipos de datos de los resultados de los métodos en cuestión no intervienen en esa decisión.

Para la resolución de métodos, si se considera al determinar la mejor opción que el tipo de datos de los argumentos de entrada se puede promocionar al tipo de datos del parámetro correspondiente. A diferencia de la resolución de función, si no se considera al determinar la mejor opción que los argumentos de entrada se pueden convertir de forma implícita al tipo de datos del parámetro correspondiente. Los módulos no se consideran durante la resolución de métodos porque los métodos no se pueden definir en módulos.

La resolución del método se realiza siguiendo los pasos siguientes:

  1. En primer lugar, busque todos los métodos del catálogo (SYSCAT.ROUTINES) que cumplan las condiciones siguientes:
    • El nombre del método coincide con el nombre de invocación, y el parámetro sujeto es el mismo tipo o es un supertipo del tipo estático del argumento sujeto.
    • La persona que lo invoca tiene el privilegio EXECUTE sobre el método.
    • El número de parámetros definidos coincide con la invocación.
    • Cada argumento de invocación coincide con el tipo de datos del parámetro definido correspondiente del método o es promocionable a ese tipo.
  2. A continuación, examine de izquierda a derecha cada argumento de la invocación del método. El argumento situado más a la izquierda (y por tanto el primer argumento) es el parámetro SELF implícito. Por ejemplo, un método definido para el tipo ADDRESS_T tiene un primer parámetro implícito de tipo ADDRESS_T. Para cada argumento, elimine todas las funciones que no sean la mejor coincidencia para ese argumento. La mejor opción para un argumento dado es el primer tipo de datos que aparece en la lista de prioridad correspondiente al tipo de datos del argumento para el cual existe una función con un parámetro de ese tipo de datos. La longitud, la precisión, la escala y el atributo FOR BIT DATA no se tienen en cuenta en esta comparación. Por ejemplo, un argumento DECIMAL(9,1) se considera una coincidencia exacta para un parámetro DECIMAL(6,5) un argumento DECFLOAT(34) se considera una coincidencia exacta para un parámetro DECFLOAT(16) y un argumento VARCHAR(19) es una coincidencia exacta para un parámetro VARCHAR(6).

    La mejor coincidencia para un argumento de tipo estructurado definido por el usuario es el propio argumento; la siguiente mejor coincidencia es el supertipo inmediato, y así sucesivamente para cada supertipo del argumento. Observe que sólo se tiene en cuenta el tipo estático (tipo declarado) del argumento de tipo estructurado, no el tipo dinámico (tipo más específico).

  3. Como máximo, un método candidato permanece después del Paso 2. Este es el método que se elige.
  4. Si después del paso 2 no queda ningún método elegible, se produce un error (SQLSTATE 42884).

Ejemplo de resolución de método

A continuación se muestra un ejemplo de una resolución de método satisfactoria.

Existen siete métodos FOO para tres tipos estructurados definidos en una jerarquía de GOVERNOR como un subtipo de EMPEROR, como un subtipo de HEADOFSTATE, registrados con las signaturas siguientes:
   CREATE METHOD FOO (CHAR(5), INT, DOUBLE)  FOR HEADOFSTATE SPECIFIC FOO_1 ...
   CREATE METHOD FOO (INT, INT, DOUBLE)      FOR HEADOFSTATE SPECIFIC FOO_2 ...
   CREATE METHOD FOO (INT, INT, DOUBLE, INT) FOR HEADOFSTATE SPECIFIC FOO_3 ...
   CREATE METHOD FOO (INT, DOUBLE, DOUBLE)   FOR EMPEROR     SPECIFIC FOO_4 ... 
   CREATE METHOD FOO (INT, INT, DOUBLE)      FOR EMPEROR     SPECIFIC FOO_5 ...
   CREATE METHOD FOO (SMALLINT, INT, DOUBLE) FOR EMPEROR     SPECIFIC FOO_6 ...
   CREATE METHOD FOO (INT, INT, DEC(7,2))    FOR GOVERNOR    SPECIFIC FOO_7 ...
La referencia al método es la siguiente (donde I1 e I2 son columnas INTEGER, D es una columna DECIMAL y E es una columna EMPEROR):
   SELECT E..FOO(I1, I2, D) ...
De acuerdo con el algoritmo...
  • FOO_7 se elimina como candidato, porque el tipo GOVERNOR es un subtipo (no un supertipo) de EMPEROR.
  • FOO_3 se elimina como candidato, porque tiene un número erróneo de parámetros.
  • FOO_1 y FOO_6 se eliminan porque, en ambos casos, el primer argumento (no el argumento sujeto) no se puede promocionar al tipo de datos del primer parámetro. Como sigue habiendo más de un candidato, los argumentos se tienen en cuenta siguiendo un orden.
  • Para el argumento sujeto, FOO_2 es un supertipo, mientras que FOO_4 y FOO_5 coinciden con el argumento sujeto.
  • Para el primer argumento, los métodos restantes, FOO_4 y FOO_5, coinciden exactamente con el tipo del argumento. No se puede asignar ningún método y, por tanto, se debe examinar el argumento siguiente.
  • Para este segundo argumento, FOO_5 es una coincidencia exacta pero FOO_4 no lo es, por lo cual se descarta. Esto deja FOO_5 como método elegido.

Invocación de métodos

Una vez seleccionado el método, pueden todavía existir algunos motivos por los cuales no se pueda utilizar el método.

Cada método está definido para devolver un resultado con un tipo de datos específico. Si este tipo de datos resultante no es compatible con el contexto donde se invoca el método, se produce un error. Por ejemplo, supongamos que se definen los siguientes métodos llamados STEP, cada uno con un tipo de datos diferentes como resultado:
   STEP(SMALLINT) FOR TYPEA RETURNS CHAR(5)
   STEP(DOUBLE) FOR TYPEA RETURNS INTEGER
y la siguiente referencia a método (donde S es una columna SMALLINT y TA es una columna TYPEA):
   SELECT 3 + TA..STEP(S) ...
en este caso se elige el primer STEP, pues hay una coincidencia exacta del tipo del argumento. Se produce un error en la sentencia, porque el tipo resultante es CHAR(5) en lugar de un tipo numérico, tal como necesita un argumento del operador de suma.

Empezando por el método que se ha seleccionado, se utiliza el algoritmo descrito en Asignación dinámica de métodos para crear el conjunto de métodos asignables durante la compilación. En Asignación dinámica de métodos se describe con exactitud el método que se invoca.

Observe que cuando el método seleccionado es un método conservador del tipo:
  • el tipo estático resultante tras la resolución de la función es el mismo que el tipo estático del argumento sujeto de la invocación del método
  • el tipo dinámico resultante cuando se invoca el método es el mismo que el tipo dinámico del argumento sujeto de la invocación del método.
Esto puede ser un subtipo del tipo resultante especificado en la definición del método conservador del tipo, que a su vez puede ser un supertipo del tipo dinámico devuelto realmente cuando se procesa el método.

En los casos donde los argumentos de la invocación del método no coinciden exactamente con los tipos de datos de los parámetros del método seleccionado, los argumentos se convierten al tipo de datos del parámetro durante la ejecución, utilizando las mismas normas que para la asignación a columnas. Esto incluye el caso en el que la precisión, escala o longitud difiere entre el argumento y el parámetro, pero excluye el caso en el que el tipo dinámico del argumento es un subtipo del tipo estático del parámetro.

Asignación dinámica de métodos

Los métodos proporcionan la funcionalidad y encapsulan los datos de un tipo. Un método se define para un tipo y siempre puede asociarse con este tipo. Uno de los parámetros del método es el parámetro implícito SELF. El parámetro SELF es del tipo para el que se ha declarado el método. El argumento que se pasa al argumento SELF cuando se invoca el método en una sentencia DML se denomina sujeto.

Cuando se elige un método utilizando la resolución de método (consulte Resolución de método), o se ha especificado un método en una sentencia DDL, este método se conoce como el método autorizado aplicable más específico. Si el sujeto es de tipo estructurado, es posible que el método tenga uno o varios métodos alternativos. Entonces se determina seleccionar qué método se debe invocar, basándose en el tipo dinámico (tipo más específico) del asunto en tiempo de ejecución. Esta determinación se denomina determinación del método asignable más específico. Este proceso se describe aquí.

  1. En la jerarquía de métodos, busque el método original del que forme parte el método autorizado más específico. Se denomina el método raíz.
  2. Cree el conjunto de métodos asignables, que debe incluir los siguientes:
    • El método autorizado aplicable más específico.
    • Cualquier método que altere temporalmente el método autorizado aplicable más específico y que esté definido para un tipo que sea un subtipo del sujeto de esta invocación.
  3. Determine el método asignable más específico, de la forma siguiente:
    1. Empiece con un método arbitrario que sea un elemento del conjunto de métodos asignables y que sea un método del tipo dinámico del sujeto o de uno de sus supertipos. Es el método asignable inicial más específico.
    2. Itere por los elementos del conjunto de métodos asignables. Para cada método: Si el método está definido para uno de los subtipos adecuados del tipo para el que está definido el método asignable más específico y si está definido para uno de los supertipos del tipo más específico del sujeto, repita el paso 2 con este método como el método asignable más específico; de lo contrario, siga iterando.
  4. Invoque el método asignable más específico.

Ejemplo:

Se proporcionan tres tipos: "Persona", "Empleado" y"Director". Existe un método original "ingresos", definido para "Persona", que calcula los ingresos de una persona. Por omisión, una persona es un desempleado (un niño, un jubilado, etc.). Por lo tanto, "ingresos" para el tipo "Persona" siempre devuelve cero. Para el tipo "Empleado" y para el tipo "Director", deben aplicarse algoritmos distintos para calcular los ingresos. Por lo tanto, el método "ingresos" para el tipo "Persona" se altera temporalmente en "Empleado" y en "Director".

Cree y rellene una tabla de la manera siguiente:
   CREATE TABLE aTable (id integer, personColumn Person);
     INSERT INTO aTable VALUES (0, Person()), (1, Employee()), (2, Manager());
Liste todas las personas que tengan unos ingresos mínimos de 40000€:
   SELECT id, person, name
     FROM aTable
     WHERE person..income() >= 40000;

Utilizando la resolución de métodos, se selecciona el método "ingresos" para el tipo "Persona" como el método autorizado aplicable más específico.

  1. El método raíz es "ingresos" para "Persona".
  2. El segundo paso del algoritmo anterior se lleva a cabo para construir el conjunto de métodos asignables:
    • Se incluye el método "ingresos" para el tipo "Persona", porque es el método autorizado aplicable más específico.
    • Se incluye el método "ingresos" para el tipo "Empleado" e "ingresos" para "Director", porque ambos métodos alteran temporalmente el método raíz y tanto "Empleado" como "Director" son subtipos de "Persona".

    Por lo tanto, el conjunto de métodos asignables es: {"ingresos" para "Persona", "ingresos" para "Empleado", "ingresos" para "Director"}.

  3. Determine el método asignable más específico:
    • Para un sujeto cuyo tipo más específico sea "Persona":
      1. Deje que el método asignable inicial más específico sea "ingresos" para el tipo "Persona".
      2. Como no hay ningún otro método en el conjunto de métodos asignables que esté definido para un subtipo adecuado de "Persona" y para un supertipo del tipo más específico del sujeto, "ingresos" para el tipo "Persona" es el método asignable más específico.
    • Para un sujeto cuyo tipo más específico sea "Empleado":
      1. Deje que el método asignable inicial más específico sea "ingresos" para el tipo "Persona".
      2. Itere por el conjunto de métodos asignables. Debido a que el método "ingresos" para el tipo "Empleado" se define para un subtipo adecuado de "Persona" y para un supertipo del tipo más específico del sujeto (Nota: Un tipo es su propio supertipo y subtipo.), método "income" para el tipo "Employee" es una mejor coincidencia para el método asignable más específico. Repita este paso con el método "ingresos" para el tipo "Empleado" como el método asignable más específico.
      3. Como no hay ningún otro método en el conjunto de métodos asignables que esté definido para un subtipo adecuado de "Empleado" y para un supertipo del tipo más específico del sujeto, el método "ingresos" para el tipo "Empleado" es el método asignable más específico.
    • Para un sujeto cuyo tipo más específico sea "Director":
      1. Deje que el método asignable inicial más específico sea "ingresos" para el tipo "Persona".
      2. Itere por el conjunto de métodos asignables. Debido a que el método "income" para el tipo "Manager" se define para un subtipo adecuado de "Person" y para un supertipo del tipo más específico del sujeto (Nota: Un tipo es su propio supertipo y subtipo.), método "income" para el tipo "Manager" es una mejor coincidencia para el método asignable más específico. Repita este paso con el método "ingresos" para el tipo "Director" como el método asignable más específico.
      3. Como no hay ningún otro método en el conjunto de métodos asignables que esté definido para un subtipo adecuado de "Director" y para un supertipo del tipo más específico del sujeto, el método "ingresos" para el tipo "Director" es el método asignable más específico.
  4. Invoque el método asignable más específico.