POSTGRESQLf: Implementación de Extensiones …jtcadenas/PostgreSQLf/Documento_PostgreSQLf.pdf ·...

347
UNIVERSIDAD DE CARABOBO FACULTAD EXPERIMENTAL DE CIENCIAS Y TECNOLOGÍA DEPARTAMENTO DE COMPUTACIÓN BASE DE DATOS POSTGRESQLf: Implementación de Extensiones Difusas de manera Fuertemente Acoplada sobre el RDBMS PostgreSQL Ayudante de Investigador: Lic. Rodolfo Vegas Gerentes de Proyecto: Ana Aguilera (phd) Tineo Leonid (phd) José Cadenas (msc) Barbula, Diciembre de 2.009

Transcript of POSTGRESQLf: Implementación de Extensiones …jtcadenas/PostgreSQLf/Documento_PostgreSQLf.pdf ·...

UNIVERSIDAD DE CARABOBO FACULTAD EXPERIMENTAL DE CIENCIAS Y TECNOLOGÍA

DEPARTAMENTO DE COMPUTACIÓN BASE DE DATOS

POSTGRESQLf: Implementación de Extensiones Difusas de manera Fuertemente

Acoplada sobre el RDBMS PostgreSQL

Ayudante de Investigador: Lic. Rodolfo Vegas Gerentes de Proyecto: Ana Aguilera (phd)

Tineo Leonid (phd) José Cadenas (msc)

Barbula, Diciembre de 2.009

ii

Contenido

Indice de Figuras ........................................................................................................................... 4

Indice de Tablas ............................................................................................................................. 9

Introducción ................................................................................................................................ 10

Postgresql .................................................................................................................................... 13

Arquitectura de Postgresql ...................................................................................................... 14

Arquitectura Conceptual del Servidor Postgresql ................................................................... 14

Lógica Difusa ............................................................................................................................... 17

Teoría de Conjuntos Difusos ................................................................................................... 17

Operaciones Sobre Conjuntos Difusos .................................................................................... 18

Logica Difusa .......................................................................................................................... 18

Sqlf .......................................................................................................................................... 20

Ddl Para Componentes Difusos (Sqlf-Ddl) ......................................................................... 20

Dml Para Componentes Difusos (Sqlf-Dml) ....................................................................... 23

Principio de Derivación ........................................................................................................... 25

Manual de Usuario ...................................................................................................................... 27

1. Introducción .................................................................................................................... 27

2. Acerca de Postgresqlf ...................................................................................................... 27

2.1. Instalación ............................................................................................................... 27

2.2. Consideraciones Importantes: ................................................................................. 31

iii

2.3. Lenguaje de Manejo de Datos en Base a Comparadores Difusos ........................... 32

2.4. Selección de Datos .................................................................................................. 36

Manual De Programador ............................................................................................................. 40

1. Introducción .................................................................................................................... 40

2. Consideraciones Generales ............................................................................................. 40

2.1. Catalogo Del Sistema .............................................................................................. 40

2.2. Parser ....................................................................................................................... 43

2.4. Traffic Cop (Tcop) .................................................................................................. 75

2.4. Planner/Optimizer ................................................................................................... 77

2.5. Executor .................................................................................................................. 92

Pruebas De La Extension Postgresqlf ........................................................................................ 104

Pruebas de Funcionalidad...................................................................................................... 104

Pruebas de Escalabilidad ....................................................................................................... 128

Anexo A .................................................................................................................................... 152

Anexo B .................................................................................................................................... 164

Anexo C .................................................................................................................................... 222

Anexo D .................................................................................................................................... 262

Anexo E ..................................................................................................................................... 299

Anexo F ..................................................................................................................................... 342

Bibliografía ................................................................................................................................ 348

PostgreSQLf Página 4

Indice de Figuras

Figura 1 Arquitectura simplificada de PostgreSQL .................................................................... 14

Figura 2 Arquitectura conceptual de PostgreSQL ....................................................................... 15

Figura 3 Representación de un Conjunto Difuso con un Trapecio ............................................. 17

Figura 4 Estructura pg_fuzzypred ............................................................................................... 41

Figura 5 Estructura pg_fuzzymod ............................................................................................... 42

Figura 6 Estructura pg_fuzzycomp ............................................................................................. 42

Figura 7 Estructura pg_fuzzyconn .............................................................................................. 43

Figura 8 Estructura pg_fuzzyquan .............................................................................................. 43

Figura 9 Estructura A_FuzzyPred ............................................................................................... 49

Figura 10 Estructura A_FuzzyQuan ............................................................................................ 49

Figura 11 Estructura A_FuzzyComp ........................................................................................... 50

Figura 12 Parser tree difuso para el predicado joven .................................................................. 51

Figura 13 Estructura simplificada de un query tree difuso ......................................................... 52

Figura 14 Parser tree difuso para el modificador muy y predicado gordo .................................. 54

Figura 15 Query tree simplificado .............................................................................................. 56

Figura 16 Árbol A_Expr que define una sentencia ..................................................................... 57

Figura 17 Árbol A_Expr que define una sentencia ..................................................................... 58

Figura 18 Proceso de Eliminación de la ...................................................................................... 59

Figura 19 Lista que almacena el nodo que presenta un comparador difuso y ............................. 59

PostgreSQLf Página 5

Figura 20 Creación del Árbol A_Expr para una sentencia .......................................................... 60

Figura 21 Eliminación de la rama del árbol que presenta un comparador difuso e inserción en la

lista FuzzyComp A_FuzzyComp y el nodo correspondiente al elemento que se le aplica dicho

comparador (A_FuzzyPred ó A_Const) ...................................................................................... 61

Figura 22 Árbol A_Expr generado aplicando el principio de derivación ................................... 62

Figura 23 Parser tree difuso de un cuantificador difuso .............................................................. 68

Figura 24 derivate fuzzy quan ..................................................................................................... 69

Figura 25 Estructura simplificada de un subárbol difuso con cuantificación ............................. 70

Figura 26 Resultado de ejecutar el comando explain analyze ..................................................... 71

Figura 27 Modificaciones al parsenodes.h .................................................................................. 72

Figura 28 Modificaciones al parse_node.h ................................................................................. 72

Figura 29 Modificaciones al parse_clause.c................................................................................ 72

Figura 30 Parse tree difuso, group by con having difuso ............................................................ 74

Figura 31 Modificaciones al archivo analyze.c ........................................................................... 75

Figura 32 Modificaciones al parse_relation.c ............................................................................. 75

Figura 33 Modificaciones al archivo rel.h .................................................................................. 76

Figura 34 Modificaciones al readfuncs.c .................................................................................... 76

Figura 35 Modificaciones al relutils.c ......................................................................................... 77

Figura 36 Subárbol quals............................................................................................................. 78

Figura 37 Estructura simplificada de un subárbol qual ............................................................... 79

Figura 38 Estructura simplificada de un subárbol qual derivado ................................................ 80

PostgreSQLf Página 6

Figura 39 Estructura simplificada de query tree difuso derivado................................................ 81

Figura 40 Estructura simplificada de un plan tree difuso ............................................................ 83

Figura 41 Verificación de vistas o reglas difusas en el planner.c ............................................... 88

Figura 42 Cálculo de grado de membrecía para predicados difusos tipo .................................... 97

Figura 43 Modificación al archivo fmgr.h .................................................................................. 97

Figura 44 Modelo Relacional de la Base de Datos lab_marcha ................................................ 104

Figura 45 Creación de Comparadores Difusos .......................................................................... 106

Figura 46 Tabla pg_fuzzycomp ................................................................................................. 106

Figura 47 Consulta #1 con condición difusa que presenta el cuantificador difuso al_menos3 . 107

Figura 48 Consulta #2 con having difuso .................................................................................. 108

Figura 49 Consulta #3 con cuantificador al_menos3 y modificador difuso muy ...................... 108

Figura 50 Consulta #4 con cuantificador al_menos3 y comparador difuso >> ......................... 109

Figura 51 Consulta #1 aplicando UNION difusa con predicados difusos atonía e hipertonía .. 109

Figura 52 Consulta #2 aplicando INTERSECT con predicados difusos joven, viejo y

cuantificador al_menos3 ........................................................................................................... 110

Figura 53 Consulta #3 aplicando EXCEPT junto al predicado difuso maduro y group by con

having difusos ........................................................................................................................... 110

Figura 54 Consulta #4 aplicando UNION con predicados difusos tales como joven, maduro y

modificador difuso muy ............................................................................................................ 111

Figura 55 Consulta #5 aplicando INTERSECT con condiciones difusas que implican predicados

difusos como joven, viejo y maduro ......................................................................................... 112

Figura 56 Consulta #6 aplicando EXCEPT junto a los predicados difusos maduro y joven .... 113

PostgreSQLf Página 7

Figura 57 Consulta #7 aplicando UNION con predicados difusos joven y viejo...................... 114

Figura 58 Consulta #8 aplicando INTERSECT/EXCEPT/UNION con predicados difusos tales

como: joven, viejo y maduro ..................................................................................................... 115

Figura 59 Consulta #9 aplicando INTERSECT junto con consultas difusas en el from y

predicados difusos tales como: joven, viejo y maduro .............................................................. 116

Figura 60 Consulta #10 aplicando EXCEPT con consultas difusas en el from cuyas condiciones

presentan predicados difusos como: joven y maduro ................................................................ 117

Figura 61 Consulta #11 aplicando UNION con consultas difusas en el from y predicados difusos

como: joven, viejo y maduro ..................................................................................................... 118

Figura 62 Consulta #12 aplicando INTERSECT/EXCEPT/UNION con consultas difusas en el

from y predicados difusos tales como: joven, viejo y maduro .................................................. 119

Figura 63 Consulta #13 aplicando INTERSECT con comparadores difusos tales como: <<, >> y

~................................................................................................................................................. 120

Figura 64 Consulta #14 aplicando EXCEPT junto a los comparadores difusos >> y << ......... 121

Figura 65 Consulta #15 aplicando UNION junto con los comparadores difusos << y >> ....... 121

Figura 66 Consulta #16 aplicando INTERSECT/EXCEPT/UNION junto a los comparadores

difusos <<, ~ y << y predicados difusos viejo ......................................................................... 122

Figura 67 Consulta #17 aplicando INTERSECT junto al comparador difuso ~ y los predicados

difusos joven, maduro y viejo ................................................................................................... 123

Figura 68 Consulta #18 aplicando UNION/EXCEPT/INTERSECT junto a los comparadores

difusos << y >> además de los predicados difusos joven, viejo y maduro ............................... 124

Figura 69 Consulta #19 aplicando INTERSECT junto al predicado difuso hipertonía con el

conector not ............................................................................................................................... 124

Figura 70 Consulta #20 aplicando EXCEPT junto a los predicados difusos atonía e hipertonía

................................................................................................................................................... 125

PostgreSQLf Página 8

Figura 71 Consulta #21 aplicando UNION junto a los comparadores difusos << y >> ........... 125

Figura 72 Consulta #22 aplicando INTERSECT/EXCEPT/UNION presentando condiciones con

los comparadores difusos: <<, >> y ~ ....................................................................................... 126

Figura 73 Consulta #23 aplicando INTERSECT/EXCEPT/UNION con condiciones difusas en

el from, además de los comparadores difusos: <<, >> y ~; predicados difusos tales como:

hipertonía y atonía y el conector not ......................................................................................... 127

Figura 74 Esquema del TPC-H ................................................................................................. 128

Figura 75 Histograma sobre la variable numérica Tiempo ....................................................... 136

Figura 76 Diagrama de Caja, Volumen Bajo ............................................................................ 138

Figura 77 Diagrama de Caja agrupado por Tipo de Consulta, Volúmen Bajo .......................... 139

Figura 78 Histograma sobre la variable numérica Tiempo ....................................................... 140

Figura 79 Diagrama de Caja, Volúmen Alto ............................................................................. 142

Figura 80 Diagrama de Caja agrupado por Tipo de Consulta, Volúmen Alto .......................... 143

Figura 81 Datos de entrada que recibe R para realizar el test de Friedman .............................. 146

Figura 82 Resultado del test de Friedman ................................................................................. 146

Figura 83 Resultado del analisis de varianza o ANOVA .......................................................... 148

Figura 84 Medias marginales estimadas de Tiempo (milisegundo) .......................................... 149

Figura 85 Grafico que muestra la relación del tiempo de procesamiento ................................. 150

Figura 86 Relación del tiempo de procesamiento de consultas ................................................. 151

PostgreSQLf Página 9

Indice de Tablas

Tabla 1 Integrantes involucrados en la extensión de PostgreSQLf con sus respectivos aportes . 11

Tabla 2 Instancia relacional difuso tipo-1 A ............................................................................... 98

Tabla 3 Instancia relacional difuso tipo-1 B ............................................................................... 98

Tabla 4 Relación resultante al aplicar la operación INTERSECT .............................................. 99

Tabla 5 Relación resultante al aplicar la operación EXCEPT ..................................................... 99

Tabla 6 Relación resultante al aplicar la operación UNION ....................................................... 99

Tabla 7 Consultas clásicas y difusas con sus respectivos tiempos de procesamientos expresados

en milisegundos para altos y bajos volúmenes de datos ........................................................... 135

Tabla 8 Estadísticos descriptivos para volúmen de datos bajo.................................................. 137

Tabla 9 Medias por tipo de Consulta (tiempo en milisegundos), Volúmen Bajo ..................... 139

Tabla 10 Estadísticos descriptivos para volúmen de datos alto ................................................ 141

Tabla 11 Medias por tipo de Consulta (tiempo en milisegundos), Volúmen Alto .................... 143

Tabla 12 Prueba de Kolmogorov-Smirnov para una muestra ................................................... 144

Tabla 13 Datos de entrada que recibe R para realizar el ANOVA ............................................ 148

PostgreSQLf Página 10

INTRODUCCIÓN

La imprecisión es una de las características del lenguaje natural que hace difícil su utilización en sistemas computacionales. Por ejemplo conceptos como pequeño o grande, tienen significados diferentes de acuerdo al contexto en el que se estén utilizando, e incluso dentro del mismo contexto, pueden significar cosas diferentes para diferentes individuos. La teoría de los conjuntos difusos desarrollada por Zadeh, provee una poderosa herramienta para la representación y manejo de la imprecisión por lo que actualmente está siendo utilizada en varios campos para el diseño de sistemas basados en la lógica difusa. La teoría de conjuntos difusos, extiende la teoría clásica de conjuntos al permitir que el grado de membresía o pertenencia de un objeto a un conjunto sea representada como un número real entre 0 y 1 en vez del concepto clásico en el que solo se tiene la posibilidad de pertenecer a un conjunto o no pertenecer al mismo; en otras palabras, el grado de pertenencia a un conjunto en la teoría clásica tiene solo dos valores posibles: 0 y 1. En el sentido más amplio, un sistema basado en reglas difusas es un sistema basado en reglas donde la lógica difusa es utilizada como una herramienta para representar diferentes formas de conocimiento acerca del problema a resolver, así como para modelar las interacciones y relaciones que existen entre sus variables. Debido a estas propiedades, los sistemas basados en la lógica difusa han sido aplicados de forma exitosa en varios dominios en los que la información vaga o imprecisa emerge en diferentes formas. Actualmente, el modelo relacional no permite el procesamiento de consultas del tipo “Encontrar a todos los trabajadores que gane muy bien” dado que ni el cálculo ni el álgebra relacional, que establecen el resultado de cualquier consulta como una nueva relación, tienen la capacidad de permitir consultas de una manera difusa. Por otra parte, estamos entrando en una era donde predomina la tecnología basada en la Inteligencia Artificial, dicha tecnología pretende simular o copiar la capacidad de pensamiento y razonamiento del cerebro humano, ya que permite el manejo de información con una terminología que es muy similar a la del lenguaje natural. Una solución que aparece recurrentemente en los trabajos de investigación actuales en esta área es la fusión de los sistemas manejadores de bases de datos relacionales con la lógica difusa, lo que da lugar a la extensión de PostgreSQLf desarrollado en conjunto con grupos de desarrollo de la Universidad Simón Bolívar y la Universidad de Carabobo. Cabe resaltar, que esta investigación viene dada a partir de un macro proyecto de transferencia tecnológica “G-2005000278” financiado por el FONACIT, cuyo objetivo principal es la implementación de algunas operaciones de SQLf dentro del gestor de base de datos PostgreSQL. En la Tabla 1 se presenta los integrantes de este proyecto con las operaciones implementadas de SQLf.

PostgreSQLf Página 11

Trabajo Elaborado por: Implementación Una Contribución a la Interrogación

Flexible de Bases de Datos: Optimización y Evaluación a Nivel Físico, Universidad

Simón Bolívar, Diciembre (2006).

José T. Cadenas Tesis de Maestría

Predicados difusos por trapecio, operador AND.

PostgreSQLf: Sistema de Consultas Flexibles Fuertemente Acoplado con el

SGBD PostgreSQL

Arturo Rossodivita Tesis de Pregrado

Predicados difusos por Expresión y Extensión, operador OR, modificadores

difusos.

PostgreSQLf: Implementación de Extensiones Difusas de manera

Fuertemente Acoplada sobre el RDBMS PostgreSQL,

Armando Bracho Tesis de Pregrado

Consultas particionadas GROUP BY, HAVING, UPDATE vistas, y operación

de unión difusa.

PostgreSQLf: Implementación de Cuantificadores Difusos Sobre el SGBD

PostgreSQL

Gustavo Bazán Tesis de Pregrado

Consultas con Cuantificación Difusa.

Operaciones conjuntistas, sub consultas difusas y comparadores difusos para

PostgreSQLf

Rodolfo Vegas Trabajo de

investigación y desarrollo

Comparadores, operaciones conjuntistas y sub consultas difusas en el FROM.

Tabla 1 Integrantes involucrados en la extensión de PostgreSQLf con sus respectivos aportes

Cabe destacar que para lograr esta Investigación se utilizarón como base los siguientes trabajos:

• “Interrogaciones Flexibles en Base de Datos Relacionales” . Trabajo de ascenso presentado ante la ilustre Universidad Simón Bolívar para optar a la categoría de Profesor Agregado por Leonid Tineo (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998).

• “ Una contribución a la interrogación flexible de bases de datos: evaluación de consultas cuantificadas difusas”. Tesis de grado para optar al título de Doctor en Ciencias de la Computación, presentada en la Universidad Simón Bolívar por Leonid Tineo (Tineo, Una contribución a la interrogación flexible de bases de datos: evaluación de consultas cuantificadas difusas, 2006)

• “ Una Contribución a la Interrogación Flexible de Bases de Datos: Optimización y Evaluación a Nivel Físico” . Trabajo de Grado presentado a la Universidad Simón Bolívar como requisito parcial para optar el grado de Magíster en Ciencias de la Computación por José Cadenas (Cadenas Lucero, 2008).

• “ Reingeniería del Sistema de Consultas Difusas a Bases de Datos SQLfi” . Proyecto de Grado presentado ante la ilustre Universidad Simón Bolívar como requisito parcial para optar al título de Ingeniero en Computación por Verónica Crespo (Crespo, 2006).

PostgreSQLf Página 12

• “ PostgreSQLf: Sistema de Consultas Flexibles Fuertemente Acoplado con el SGBD PostgreSQL” . Trabajo Especial de Grado presentado ante la ilustre Universidad de Carabobo como requisito parcial para optar por el titulo de Licenciado en Computación por Arturo Rossodivita (Rossodivita, 2009).

• “ PostgreSQLf: Implementación de Extensiones Difusas de manera Fuertemente Acoplada sobre el RDBMS PostgreSQL”. Trabajo Especial de Grado presentado ante la ilustre Universidad de Carabobo como requisito parcial para optar por el titulo de Licenciado en Computación por Armando Bracho (Bracho, 2009).

• “ PostgreSQLf: Implementación de Cuantificadores Difusos Sobre el SGBD PostgreSQL”. Trabajo Especial de Grado presentado ante la ilustre Universidad de Carabobo como requisito parcial para optar por el titulo de Licenciado en Computación por Gustavo Bazan (Bazán, 2009)

Los aportes hechos en la extensión de PostgreSQLf en esta investigación son: Predicados difusos tipo trapecio, consultas difusas con conectores lógicos clásicos (AND, OR y NOT), predicados por extensión, predicados difusos por expresión, modificadores difusos, comparadores difusos, consultas particionadas con condiciones difusas, operaciones conjuntistas con subconsultas difusas (Unión, Intersección, Diferencia), consultas cuantificadas difusas, subconsultas difusas simples en la clausula FROM, y la función CALIBRATION en consultas difusas. Además de ser la única extensión fuertemente acoplada.

PostgreSQLf Página 13

POSTGRESQL

PostgreSQL es un manejador de bases de datos relacionales, de tipo cliente / servidor. Este ofrece una mezcla única de características que lo equiparan con los grandes manejadores de bases de datos tales como Oracle (Free and Open Source Software from Oracle), Sybase (Sybase: Managing, Analyzing and Mobilizing Information. Sybase Inc), DB2 (DB2 Express C. IBM.), entre otros. Una de las mayores ventajas que ofrece PostgreSQL es que su código es abierto (se puede ver su código fuente) ya que PostgreSQL no es propiedad de una sola compañía sino que es mantenido, desarrollado y actualizado por un grupo de desarrolladores voluntarios alrededor del mundo. Para esta investigación la premisa anterior es fundamental y es una de las razones por la que se ha seleccionado el RDBMS PostgreSQL como la plataforma donde se realizarán las extensiones difusas propuestas ya que a pesar de existir en el mercado actual distintos manejadores de bases de datos como MySQL (MySQL AB), Oracle, DB2, Microsoft SQL Server (Microsoft SQL Server 2005 Express Edition), entre otros; estos no proveen el código fuente y la documentación existente sobre los mismos es muy escaza, por lo que es imposible su extensión y modificación para los efectos de esta investigación. Entre las mejoras incorporadas a PostgreSQL a lo largo de los años (entre la versión 6 y 7.4 del mismo) (PostgreSQL Global Development Group) podemos mencionar:

• Multiversion Concurrency Control (MVCC): La implementación de este sofisticado sistema de control de concurrencias permite a los lectores tener consistencia en la lectura de datos aún cuando se estén realizando escrituras sobre la misma, además de permitir la realización de respaldos mientras la base está activa.

• Implementaciones de SQL: Se incorporan importantes características de SQL como las subconsultas, el uso de claves primarias y foráneas, implementación de nuevos tipos de datos como los enteros binarios y hexadecimales, entre otras mejoras.

• Mejora en la velocidad del sistema: Se implementan reestructuraciones en el código que brindan mejoras de 20 – 40% a nivel general en el backend y reducción en el tiempo de inicio del sistema hasta un 80%.

• Importantes mejoras como la implementación de Esquemas SQL, joins externos, consultas complejas, sintaxis SQL92 del join, incorporación de lenguajes procedimentales, información estadística de la base de datos, mejoras en la seguridad, auto-vacuum, funciones sobre tablas, entre otras mejoras.

Toda esta serie de mejoras permiten que hoy en día PostgreSQL sea uno de los RDBMS más robustos y reconocidos del mercado y sirven de base para la selección de PostgreSQL como el sistema base donde se desarrollara la presente investigación.

PostgreSQLf Página 14

ARQUITECTURA DE POSTGRESQL

PostgreSQL implementa una arquitectura cliente-servidor (Geschwwinde & Shonig, 2001) para proveer acceso multiusuario, en este se pueden diferenciar tres grandes subsistemas: el cliente, el servidor y el gestor de almacenamiento los cuales en conjunto permiten el funcionamiento del sistema. La Figura 1 ilustra de manera general dichos componentes:

Figura 1 Arquitectura simplificada de PostgreSQL (Chen, Lim, & Xiao)

A continuación describiremos la función específica de cada uno de estos componentes:

• El Cliente: se denota así a cualquier aplicación que haga uso del sistema, estableciendo una conexión al mismo a través del componente Libpq, subsistema implementado en C nativo que funciona como intermediario entre el cliente y el servidor, encargándose de enviar las consultas realizadas por el cliente al servidor.

• Servidor (Server): es el componente que recibe las consultas realizadas y está compuesto principalmente por el Postmaster y el servidor Postgres. El Postmaster se encarga de aceptar cada una de las peticiones del cliente que desee establecer una conexión, realiza las tareas de autenticación y control de acceso, y establece finalmente la conexión entre el cliente y un nuevo proceso o hilo del servidor Postgres. Por su parte el servidor Postgres se encarga de manejar todas las consultas y comandos enviados por el cliente, realizando todos los cálculos y operaciones necesarias para responder a las consultas realizadas.

• Gestor de Almacenamiento: Este se encarga de gestionar y controlar los recursos de almacenamiento en el servidor, incluyendo buffers de memoria compartidos, gestión de archivos, control de consistencia y manejo de locks sobre los archivos.

ARQUITECTURA CONCEPTUAL DEL SERVIDOR POSTGRESQL Tras estudiar y entender la arquitectura general de PostgreSQL se procederá a explicar de manera más detallada los distintos componentes que forman parte de la arquitectura

PostgreSQLf Página 15

del sistema a través del estudio de la arquitectura Conceptual de PostgreSQL, la cual se puede observar en la Figura 2

Figura 2 Arquitectura conceptual de PostgreSQL (Chen, Lim, & Xiao)

Donde se muestra de manera más especifica los componentes esenciales del sistema, cuyo funcionamiento se explica a continuación:

• El Parser chequea primero si la consulta recibida por el programa posee una sintaxis válida. Si la sintaxis es correcta, el parser se encarga de transformar dicha consulta en un árbol de análisis (parse tree) que será almacenado y empleado para procesar la consulta; si la sintaxis es inválida el parser retorna un error. La traducción de la consulta es realizada por medio de las herramientas LEX (GNU Project) (generador de analizadores léxicos en expresiones regulares) y YACC (Stephen, 1979) (generador de analizadores de sintaxis por medio de lenguajes de programación).

• El Traffic cop se encarga de identificar la consulta recibida y clasificarla en consulta sencilla o consulta compleja. Si la consulta recibida es de tipo sencilla, esta se envía al Utility commands para ser procesada; por otra parte si la consulta recibida es de tipo compleja, la misma es enviada al Rewriter para ser procesada.

• El Utility Commands manejan las consultas que no requieren un procesamiento complejo y que pueden ser realizadas sin mayor modificación al árbol de análisis (parse tree) generado, como lo son las consultas de vacío, copia, actualización, creación de tablas, creación de tipos, entre muchos otros que emplean comandos generales.

• El Query Rewriter es un subsistema ubicado entre el Parser y el Planner que se encarga de procesar el árbol del análisis (parse tree) enviado por el Traffic Cop cuando la consulta es de tipo compleja, de manera de aplicar cualquier regla o vista que se halla especificado sobre la consulta, reescribiendo el árbol de forma que pueda ser procesado posteriormente.

• El Planner es un componente de vital importancia puesto que recibe el parse tree y realiza un análisis sobre el mismo con la finalidad de proporcionar un plan óptimo de ejecución para la consulta recibida. La idea básica del

PostgreSQLf Página 16

Planner es la selección de costo estimado basado en el mejor plan de consulta el cual obtiene de la siguiente manera:

o Primero combina todas las maneras posibles de procesar la consulta, explorando todas las posibles conexiones entre las relaciones que aparecen en la consulta.

o Luego verifica que todas las trayectorias calculadas conduzcan al mismo resultado y el Planner estima los costos de ejecución de cada trayectoria.

o Finalmente el Planner elige la trayectoria cuyo costo sea el menor de todos y es esta la que se envía al Ejecutor para su procesamiento final.

• El Ejecutor toma el plan enviado por el Planner y comienza a procesar desde el nodo superior. Para ello ejecuta el plan tree, que es una red canalizada y organizada de nodos de proceso. Cada nodo del nivel inferior del árbol produce la tupla siguiente en la consulta generando una salida en secuencia cada vez que es llamado un nodo. En contraste, los nodos del nivel superior son exploraciones de tablas físicas, exploraciones secuenciales o las exploraciones del índice. El ejecutor hace uso el sistema gestor de almacenamiento mientras que explora las relaciones, realiza clases y evalúa cualificaciones para finalmente devolver las tuplas derivadas.

PostgreSQLf Página 17

LÓGICA DIFUSA

TEORÍA DE CONJUNTOS DIFUSOS En los conjuntos clásicos los elementos pertenecen o no al conjunto. En el caso de los conjuntos difusos se presenta una gradualidad en la pertenencia al conjunto, lo cual se traduce en la existencia de elementos que pertenecen al conjunto, así como la existencia de elementos que potencialmente podrían pertenecer al conjunto. Para determinar si un objeto pertenece al conjunto se emplea la función de membrecía, la cual asocia a un objeto un valor real en el rango �0,1�, donde 0 indica la no pertenencia absoluta y 1 indica la pertenencia total. Usualmente, esta función de membrecía es representada con el símbolo ��, siendo � el identificador del conjunto difuso. Estos grados inducen un orden, lo cual es uno de los puntos claves para el uso de estos conjuntos. Este orden define preferencias sobre el universo. Existen varias notaciones para representar a los conjuntos difusos, las cuales son: Extensión, Trapecio y Expresión.

• Extensión: (en el caso de universos discretos). El conjunto difuso � sobre el universo � ��, � , … , ��� se representa mediante la expresión �� ��/��, � /� , . . . , ��/��� donde ����� �������. Como ejemplo podemos mencionar el conjunto difuso “flaco” definido sobre el dominio “contextura” se define como: � ����� �� !"/0, ��# !"/0.3, %��&"'/0.6, � '�"�"/1�

• Trapecio: usualmente la función característica tiene forma trapezoide y se representa por la cuádrupla de valores del universo �", �, ), �� que indican los puntos que definen el trapezoide. La función característica viene dada por la función que se muestra en la Figura 3.

Figura 3 Representación de un Conjunto Difuso con un Trapecio

Como ejemplo podemos citar el conjunto difuso “Maduro” definido en un dominio entre 0 y 120 como: � &"�#�� �20, 22, 25, 27�

• Expresión: En ciertas ocasiones la función característica se define mediante una expresión aritmética y el grado de membrecía es calculado en base a dicha expresión.

0

1

a b c d

PostgreSQLf Página 18

La teoría de conjuntos difusos define como características de los conjuntos difusos la altura, la norma, el soporte, el núcleo y el - . )#/. A continuación se da una breve descripción de las características anteriormente mencionadas:

• Altura: Se define como el mayor valor de la función de membrecía del conjunto

difuso y se expresa mediante: 0 1�0/�2� 3#4 � 5 6 Fµ ���.

• Norma: Se define como la existencia de un elemento cuya pertenencia sea total, es decir, la existencia de un elemento con grado de pertenencia igual a uno.

• Soporte: Son aquellos elementos del conjunto cuyo grado de pertenencia es superior a cero y se expresa mediante: 3#44��/�2� � 5 6 / �2��� 7 0�.

• Núcleo: Son aquellos elementos que pertenecen totalmente al conjunto. Se puede notar que el núcleo del conjunto es subconjunto del soporte. El núcleo se expresa mediante )�� �2� � 5 6 / �2��� 1�.

• λ-cut: Se define como el grado mínimo de pertenencia para los elementos del conjunto. Dado un conjunto A, al aplicar λ-cut al conjunto se obtiene un subconjunto que satisface 2 � 5 6 / �2��� 8 -�.

OPERACIONES SOBRE CONJUNTOS DIFUSOS Las operaciones conjuntistas difusas son básicamente las mismas clásicas: Intersección (9), Unión (:) y Diferencia (.); pero extendiéndolas para operar con conjuntos difusos en lugar de clásicos. Para ello se utiliza las definiciones más usuales las cuales son, según (Cadenas Lucero, 2008):

• La intersección de dos conjuntos difusos A y B es un conjunto difuso C, denotado como ; 2 9 <, o alternativamente, denotado como ; 2 "%� <, cuya función de pertenencia es relacionada a aquellos de A y B por:

�=��� min��A���, �B���� �A��� C �B���

• El complemento de un conjunto difuso A, denotado por 2�D2, %�/ 2� es definido como:

�A��� 1 . �A���

• La unión de dos conjuntos difusos A y B es un conjunto difuso C, denotado como ; 2 : <, o alternativamente, denotado como ; 2 �� <, cuya función de pertenencia es relacionada a aquellos de A y B por:

�=��� max��A���, �B���� �A��� G �B��� LOGICA DIFUSA La lógica difusa es una técnica de la inteligencia computacional que permite manejar información con alto grado de imprecision, en esto se diferencia de la lógica clásica que trabaja con información bien definida y precisa. También se puede definir como una metodología que proporciona de manera fácil decisiones a partir de información vaga,

PostgreSQLf Página 19

ambigua e imprecisa; en general la lógica difusa trata de imitar la forma de toma de decisiones de un ser humano. El concepto de Lógica Difusa fue concebido por Lofti Zadeh, profesor de la Universidad de California en Berkley, quien inconforme con los conjuntos clásicos (crisp sets) que sólo permiten dos opciones (la pertenencia o no de un elemento a dichos conjuntos) la presentó como una forma de procesar información permitiendo pertenencias parciales a los conjuntos (Conjuntos Difusos o fuzzy sets). El concepto de conjunto difuso fue expuesto por Lofti Zadeh en un paper en el año de 1965, el artículo se titula "Fuzzy Sets" y fue publicado en la revista Information and Control. El mismo autor publica en 1971 el artículo, "Quantitative Fuzzy Semantics", en donde introduce los elementos formales que acabarían componiendo el cuerpo de la teoría de la lógica difusa y sus aplicaciones tal como se conocen en la actualidad. El profesor Zadeh menciona que la gente no requiere información numérica precisa del medio que lo rodea para desarrollar tareas de control altamente adaptable por ejemplo conducir un automóvil o caminar por una acera sin chocarse con los postes u otras personas (López, 2001). La lógica difusa permite darle una interpretación a los llamados términos lingüísticos: predicados, modificadores, comparadores, conectores y cuantificadores.

• Predicados Difusos: La lógica difusa extiende los predicados de la lógica clásica definiendo los predicados mediante conjuntos difusos, y la satisfacción del predicado está dada por la función de membrecía del conjunto que lo define. Los predicados son los componentes atómicos de la lógica difusa (Cadenas Lucero, 2008) (Rossodivita, 2009).

• Modificadores Difusos: Permiten definir predicados difusos modificando predicados existentes. Los modificadores se definen mediante la aplicación de operaciones sobre la función de membrecía de predicados. Un ejemplo de modificador difuso es la negación (Rossodivita, 2009).

• Cuantificadores Difusos: Permiten determinar la cantidad o porcentaje de elementos que cumplen una condición. En la lógica clásica los cuantificadores son el existencial y el universal. Desde la lógica difusa estos son los extremos de una serie de cuantificadores, los cuales se clasifican en dos categorías. Los cuantificadores absolutos que son aquellos que se refieren a una cantidad de elementos, por ejemplo “casi más 20”. Los cuantificadores relativos determinan una proporción respecto al total de elementos, por ejemplo “la mayor parte” (Bazán, 2009).

• Comparadores Difusos: Son un tipo particular de predicados difusos que se definen sobre un universo formado por pares de elementos de un dominio. Los comparadores establecen una comparación entre los elementos del domino (Rossodivita, 2009).

• Conectores Difusos: Permiten combinar valores de verdad de sentencias de lógica difusa y preservan la correspondencia existente entre las operaciones unión, intersección y complemento (Rossodivita, 2009).

PostgreSQLf Página 20

SQLF El álgebra relacional definido por Edgar Codd (1970) es un conjunto de operaciones que se pueden aplicar sobre las relaciones. Dichas operaciones son: unión, intersección, diferencia, producto cartesiano, selección, proyección y división (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). El modelo relacional está basado en la teoría de conjuntos y los datos son representados como conjuntos de relaciones matemáticas. Los datos se definen adecuadamente y son regidos por la lógica booleana; como consecuencia existe un conjunto clásico de datos que satisface cada aseveración (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). Al poco tiempo de ser desarrollado este modelo, se convirtió en el más usado como mecanismo de definición y manipulación de datos. SQLf se divide en dos sublenguajes según su propósito, que son el sublenguaje de definición de datos difusos y el sublenguaje de manipulación de datos difusos. DDL Para Componentes Difusos (SQLF-DDL) En general, las interrogaciones difusas involucran términos (predicados atómicos, modificadores, conectores, comparadores y cuantificadores) y alguno de ellos tiene un significado que es específico para un grupo de usuarios, o un individuo, dependiendo del contexto en el cual se desarrolle. Por ello se hace necesario proveer de un lenguaje para la definición de estos componentes difusos, tal es el caso del Sublenguaje de definición de datos de SQLf, el cual se inspira en el DDL de SQL. Predicados Difusos Existen, en primera instancia, predicados básicos (o atómicos). Cada uno de ellos es representado por una función de membresía sobre un subconjunto de un dominio subyacente. Se consideran predicados P que aplican a elementos individuales . Estos se definen mediante la sentencia: CREATE FUZZY PREDICATE <nombre> ON <dominio> AS <cj to difuso> donde:

• <dominio> es: Un rango de caracteres, enteros o reales, o un tipo escalar definido por el usuario.

• <cjto difuso> es: Una especificación de conjunto difuso, que puede ser: o Una distribución de posibilidades representada por un trapezoide con la

sintaxis: �H I"'��� 7, H I"'�� 7, H I"'��J 7, H I"'��K 7�

pudiendo usarse el valor especial “INFINIT” cuya semántica es infinito.

• Una distribución de posibilidades representada por extensión, con la sintaxis:

H I"'��� 7/H ��"��� 7, . . . , H I"'��� 7/H ��"��� 7�

PostgreSQLf Página 21

• Una expresión aritmética que usa la variable predefinida “x” que denota

el argumento del predicado. Modificadores Difusos Los modificadores difusos permiten definir predicados a partir de otros existentes; estos predicados se llaman predicados modificados. En SQLf existen dos modificadores predefinidos: la negación “NOT” y el “antónimo”. El usuario puede crear sus propios modificadores, según la sintaxis y semántica que se especifica a continuación: Adverbios vistos como potencia del grado de membresía, la sentencia para crear tales modificadores es:

CREATE MODIFIER <nombre> AS POWER <n> Adverbios vistos como potencias de conjuntos difusos, estos modificadores se definen en SQLf con la construcción: CREATE MODIFIER <nombre> AS <norma> POWER <n> donde:

• <norma> es una norma o una conorma triangular que se especifica mediante una expresión con las variables predefinidas "x", "y" que denotan al primer y al segundo argumento, respectivamente.

Adverbios vistos como traslaciones. Algunos modificadores lingüísticos tienen el efecto de trasladar los grados de certeza de los predicados. La sentencia para crear estos tipos de modificadores se especifica así: CREATE MODIFIER <nombre> AS TRANSLATION <d> donde:

• <d> es un valor que se suma al argumento del predicado original para hacer la traslación.

Conectores Difusos En SQLf las condiciones pueden combinarse mediante conectores difusos. Los conectores usuales de conjunción “AND” y disyunción “OR” están predefinidos mediante la norma triangular “min” y su respectiva conorma “max”; también se provee el conector unario de negación “NOT”. Sin embargo, el usuario podría desear usar otras normas u otros conectores (como la implicación). El lenguaje permite crear conectores mediante la sentencia

PostgreSQLf Página 22

CREATE CONNECTOR <nombre> AS <expresión> donde:

• <expresión> es la expresión que permite calcular el valor del predicado compuesto a partir de los valores de sus miembros. En esta expresión el miembro izquierdo se denota con la variable � y el derecho con la variable L.

También pueden usarse operadores n-ários llamados “medias” que permiten establecer compromisos, o preferencias, entre predicados usados como parámetros. Los conectores predefinidos en SQLf son:

- Media aritmética “am”. - Media geométrica “gm”. - Media armónica “hm”. - Media ponderada “wm”. - Media ordenada ponderada “OWA”. - Media generalizada “glm”.

Comparadores Difusos Además, de los comparadores usuales, un requerimiento difuso podría usar comparadores difusos cuya semántica puede variar dependiendo de los datos, o del usuario (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). Estos comparadores se crean mediante la sentencia:

CREATE COMPARATOR <nambre> ON <dominio> AS <expresión> donde:

• <name> es el identificador del comparador, la cual puede ser un nombre alfabético o un símbolo.

• <dominio> es como el caso de los predicados atómicos. • <expresión> es la expresión que permite calcular el valor de la comparación a

partir de los dos elementos comparados, los cuales son denotados con la variable x (para el término izquierdo) y la variable y (para el término derecho). Esta expresión puede utilizar conjuntos difusos.

Para fines de esta investigación, éstos comparadores son llamados comparadores trapezoidales. Por otra parte, en el proyecto de grado de (Crespo, 2006) definen otro tipo de comparadores, las cuales son un tipo particular de predicados difusos que se definen sobre un universo formado por pares de elementos de un dominio. Los comparadores establecen una comparación entre los elementos del domino. Para esta investigación éstos comparadores tienen como nombre comparadores por extensión. La definición o sintaxis de los dos comparadores descritos anteriormente se muestra en el manual de programación.

PostgreSQLf Página 23

Cuantificadores Difusos Permiten determinar la cantidad o porcentaje de elementos que cumplen una condición. En la lógica clásica los cuantificadores son el existencial y el universal. Desde la lógica difusa estos son los extremos de una serie de cuantificadores, los cuales se clasifican en dos categorías. Los cuantificadores absolutos que son aquellos que se refieren a una cantidad de elementos, por ejemplo “casi más 20”. Los cuantificadores relativos determinan una proporción respecto al total de elementos, por ejemplo “la mayor parte”.

CREATE [ABSOLUTE/RELATIVE] QUANTIFIER <nombre> AS < cjto difuso> donde:

• El <nombre> es el identificador del cuantificador. • <cjto difuso> es el conjunto difuso que define al cuantificador.

DML Para Componentes Difusos (SQLf-DML) La estructura fundamental de consulta en SQLf, al igual que en SQL, es el bloque multirelacional. La diferencia fundamental con SQL radica en que la condición de la cláusula WHERE es una condición difusa. La sintaxis del bloque básico difuso es: SELECT <lista de atributos> FROM <lista de relaciones> WHERE <condición difusa> WITH CALIBRATION c La proyección viene dada por la cláusula SELECT, la cual especifica los atributos de las relaciones que serán seleccionados y las operaciones que se aplicarán sobre estos atributos. El producto cartesiano se corresponde a la cláusula FROM, la cual especifica las relaciones en las que se basa la consulta. La selección está representada por la cláusula WHERE, la cual especifica los predicados que deben satisfacer las tuplas de las relaciones para ser seleccionadas. La cláusula WITH CALIBRATION representa el nivel mínimo de satisfacción que debe cumplirse para ser seleccionado. SQLf extiende el particionamiento mediante la cláusula GROUP BY – HAVING permitiendo que la condición de la cláusula HAVING sea difusa, mediante cuantificación difusa o funciones de agregación sobre expresiones en lógica difusa. Por otra parte, en esta investigación se implementa los subqueries difusos en el from en condiciones de bloques simples. Se determinó que el grado de satisfacción es el mínimo entre el grado de satisfacción de la condición interna y la condición externa (Crespo, 2006). Ejemplo, sea la consulta difusa:

PostgreSQLf Página 24

3 ' )/ H "/�1�#/�!� 7 M��& �selectHatributosj7fromHtablas7whereHcondición difusa interna7�

]0 � H )�%�1)1ó% �1M#!" �/ �%" 7

El grado de satisfacción de cada tupla del resultado viene dado por: &1%��H )�%�1)1ó%_1%/ �%" 7�, ��)�%�1)1ó%_ �/ �%"��

• Predicado Difuso. Los Predicados Difusos, definidos por el usuario, son utilizados como etiquetas lingüísticas que se comparan con igualdad a una expresión como si se tratara de un valor (debe haber compatibilidad de tipos para usarlos). La sintaxis es: <expresión> = <etiqueta>, donde: <etiqueta> es el nombre del predicado difuso definido por el usuario.

• Modificadores Difusos. Los Modificadores Difusos, son utilizados de manera prefija sobre las etiquetas lingüísticas que representa al predicado que modifica. La sintaxis es: <expresión> = <modificador> <etiqueta>, donde: <etiqueta> es el nombre del predicado difuso definido por el usuario.

• Conectores Difusos. Los conectores predefinidos “AND” y “OR”, y los definidos por el usuario se usan según la sintaxis: <condición><conector><condición>. El conector predefinido “NOT” tiene la sintaxis: NOT <condición>. Las medias permiten combinar las condiciones y establecer preferencias entre ellas. Éstas se utilizan de manera prefija, encerrando en paréntesis sus argumentos. La sintaxis es: en el caso de medias ponderadas: <media> (<pesos>,<condiciones>), en el caso de media generalizada: <media> (<exponente>,<pesos>,<condiciones>), en cualquier otro caso: <media> (<condiciones>). Donde: <media> es la abreviatura de la media, <condiciones> es la lista de condiciones combinadas, <exponente> es un número entero, <pesos> es una lista de pesos que coincide en número con la lista de condiciones.

• Comparadores Difusos. Los Comparadores Difusos, definidos por el usuario, pueden ser utilizados en cualquier comparación, siempre que haya compatibilidad de tipos. La sintaxis es: <expresión> <comparador> <expresión>. Donde: <comparador> es el nombre o símbolo de un conector definido por el usuario.

• Cuantificadores Difusos. Los Cuantificadores Difusos, definidos por el usuario, son utilizados como etiquetas lingüísticas seguidos por una lista de predicados difusos. La sintaxis es <expresión> <cuantificador_difuso>(<lista_predicados_difusos>).

• Se puede la cláusla CHECK aplicar sobre atributos y tuplas y la sentencia es: CHECK(<condición difusa>). Donde la condición difusa puede incluir términos difusos o consultas difusas.

• Es posible construir tablas virtuales a partir de consultas difusas. La sintaxis para definir las vistas difusas es CREATE VIEW <nombreVista> AS <Consulta Difusa>.

• Los operadores de conjunto UNION, INTERSECT y EXCEPT son extendidos mediante una semántica de teoría de conjuntos difusos. La operación union se define como: (<subconsulta difusa> UNION <subconsulta difusa>). La sintaxis de la interesección corresponde a (<subconsulta> INTERSECT <subconsulta>).

PostgreSQLf Página 25

El operador EXCEPT posee como sintaxis: (<subconsulta> EXCEPT <subconsulta>).

• Las cláusulas de manipulación de datos UPDATE permite que en la cláusula WHERE se emplee una condición difusa.

Nota: Las sentencias de cada una de las operaciones descritas anteriormente se mostraran en lenguaje SQL en el Manual de Usuario.

PRINCIPIO DE DERIVACIÓN El Principio de Derivación fue propuesto por Bosc y Pivert (2000; 1995) para definir mecanismos de evaluación de consultas difusas que intenten reducir el número de filas consultadas por cada operación que se realiza buscando descartar aquellas cuyo grado de satisfacción de la condición difusa sea vacio. La idea principal de este principio es la de aprovechar la relación existente entre las condiciones basadas en la lógica difusa y las condiciones booleanas. Dichas relaciones vienen de los conceptos de la Teoría de Conjuntos Difusos. Los conceptos usados para el Principio de la Derivación son: el soporte de un conjunto difuso (support) que es el conjunto clásico que contiene sólo los elementos del conjunto difuso cuyo grado de membrecía no es nulo; y el _-corte de un conjunto difuso, el cual es el conjunto clásico formado por todos los elementos del conjunto difuso que tienen grado de membrecía mayor o igual que el umbral _. La aplicación del Principio de Derivación para el procesamiento de consulta en SQLf ha sido objeto de estudio en trabajos previos (Bosc & Pivert, 1995) (Tineo, Una contribución a la interrogación flexible de bases de datos: evaluación de consultas cuantificadas difusas, 2006). Los conceptos más relevantes de la teoría asociada al Principio de Derivación son los conceptos de: consultas derivadas, condiciones necesarias derivadas, condiciones suficientes derivadas, derivación fuerte y derivación débil. Conceptos sobre Derivación El Principio de Derivación se basa en el uso de transformaciones lógicas que permiten llevar una consulta difusa a una clásica. La idea tras el principio de derivación es conseguir una consulta clásica que logre obtener las mismas filas resultado las generadas a partir de una consulta difusa. Para algunos casos, no es posible obtener dicha consulta, sino una consulta en SQL que obtiene todas las filas de la consulta original y, posiblemente, algunas filas no deseadas (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). La consulta clásica obtenida como derivación de la consulta difusa es la condición derivada necesaria (DNC) de la consulta difusa. Si la DNC obtiene justamente las tuplas correspondientes a la consulta difusa original se habla de derivación fuerte, en cambio si

PostgreSQLf Página 26

la DNC obtiene algunas tuplas adicionales se habla de derivación débil (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). Un concepto no menos significativo es la condición derivada suficiente (DSC), que consiste en una consulta que obtiene un subconjunto del resultado esperado de la consulta difusa original. Este tipo de derivación es útil cuando es mejor que falten tuplas a que sobren, por ejemplo si al emplear una consulta de tipo DNC una de las tuplas sobrantes ha eliminado una tupla legítima (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). Existe una estrategia de evaluación basada en el principio de derivación, la cual permite determinar las consultas clásicas más adecuadas para resolver las consultas difusas. En ocasiones el procesamiento de las consultas y el determinar el grado de satisfacción de cada fila puede necesitar, por motivaciones algorítmicas, incluir elementos no previstos teóricamente en la consulta derivada. En los casos cubiertos por principio de derivación es posible aplicar la estrategia de programa derivado, cuyo desempeño en experimentos realizados ha sido eficiente en la mayoría de los casos (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998). Varios autores entre ellos Bosc, Pivert y Tineo han desarrollado esquemas de traducción de consultas en SQLf a SQL mediante el principio de derivación (Tineo, Interrogaciones Flexibles en Base de Datos Relacionales, 1998) (Tineo, Una contribución a la interrogación flexible de bases de datos: evaluación de consultas cuantificadas difusas, 2006).

PostgreSQLf Página 27

MANUAL DE USUARIO

1. Introducción

El presente manual de usuario, tiene como finalidad dar a conocer de una manera detallada y sencilla, el proceso de instalación de la extensión de PostgreSQLf; además de mostrar las funcionalidades implementadas en esta investigación y como se manejan en dicha extensión, con el propósito de que los usuarios se familiaricen con la extensión de PostgreSQLf y de los grandes beneficios que le pueden aportar a sus actividades tan sólo por el hecho de estar basado en la lógica difusa. Con el desarrollo de esta extensión se esta poniendo en práctica el mecanismo llamado transferencia tecnológica, la cual da impulso al desarrollo y crecimiento de los diversos sectores de la sociedad y en especial aquellos que utilicen como manejador de base de datos PostgreSQLf, impulsando así la competencia y los beneficios económicos de las instituciones y organizaciones de Venezuela con el fin de prepararlos a las nuevas tecnologías desarrolladas en el mundo, además serían pioneros por usar la extensión de PostgreSQLf ya que es tecnología nueva, no desarrollada antes en nuestro país.

2. Acerca de PostgreSQLf

Para la versión final del RFDBMS PostgreSQLf, se incluyen las funcionalidades de Creación de Comparadores Difusos trapezoidales y por extensión, y Selección de Datos de acuerdo a la extensión del lenguaje SQLf para el manejo de comparadores, consultas difusas en el from y operaciones conjuntistas difusas. A partir de esto, en el presente manual se definen entonces de forma detallada dos componentes de la última versión dePostgreSQLf: • Instalación de PostgreSQLf: especificación de pasos que se deben llevar a

cabo para instalar esta versión del sistema. • Lenguaje de Manejo de Datos en base a Comparadores Difusos, consultas

difusas en el from y operaciones conjuntistas difusas: especificación de la sintaxis definida por esta propuesta de extensión de SQLf para llevar a cabo las tareas de creación de comparadores y selección de datos que involucren comparadores, consultas difusas en el from y operaciones conjuntistas difusas. A su vez se definen una serie de ejemplos que faciliten la comprensión de dicho lenguaje por parte del lector.

2.1. Instalación

A continuación se describe de manera detallada, la forma en la cual se debe instalar el RFDBMS PostgreSQLf en una plataforma de sistema operativo basada en LINUX. Así mismo, se hace referencias a consideraciones que se deban tomar en cuenta al llevar a cabo dicho proceso.

PostgreSQLf Página 28

Requerimientos del Sistema En general, cualquier sistema compatible con el UNIX moderno está en capacidad de soportar la ejecución del PostgreSQLf sobre la plataforma respectiva. De cualquier manera, para la instalación de este SMBD, es necesario constar con cada uno de los siguientes paquetes de software descritos a continuación:

GNU make: Cualquier otro sistema de construcción “make” no funcionará a la hora de construir el sistema a partir de su código fuente. La mayoría de los sistemas basados en UNIX poseen este paquete como predeterminado, específicamente con el nombre “gmake‟. Para probar su existencia, sólo se debe hacer: # gmake –version Compilador ISO/ANSI C: Son recomendadas las versiones recientes de GCC, pero en el caso de PostgreSQL, se ha demostrado que es posible el que sea construido a partir de una gran variedad de compiladores de distintos proveedores. Herramienta de Compresión TAR: Este paquete es necesario para descomprimir el código fuente del sistema PostgreSQLf. Librería Readline de GNU: Esta librería es usada por defecto por parte del sistema, aunque en los casos en los cuales no se desee utilizar la misma en conjunción con el RT-PostgreSQL, únicamente se debe especificar el comando --without-readline a la hora de establecer la configuración del sistema (./configure --without-readline). Esta librería aporta funcionalidades de edición de líneas y recuperación de historiales de ejecución de comandos. Librería de Compresión ZLIB: Al igual que la librería READLINE, esta librería es usada por defecto por parte del sistema, y de la misma manera, en los casos en los cuales no se desee utilizar la misma en conjunción con el RT-PostgreSQL, únicamente se debe especificar el comando --without-zlib a la hora de establecer la configuración del sistema (./configure --without-zlib). Esta librería permite el uso de archivos comprimidos a partir de los comandos pg_dump y pg_restore. Requerimientos Adicionales: En vista de que el sistema RT-PostgreSQL es una versión modificada del sistema base de PostgreSQL, es necesario constar con ciertos paquetes que permitan hacer uso de esta versión, para el soporte de variaciones en los archivos léxicos y de gramática. Para dar soporte a dichas variaciones, es necesario entonces de manera obligatoria, instalar los paquetes GNU Flex y Bison, en sus versiones iguales o superiores a la 2.5.4 y 1.875 respectivamente.

Detalles de Instalación A continuación se describe paso a paso, la manera en la cual debe llevarse a cabo la instalación del RT-PostgreSQL.

PostgreSQLf Página 29

Descomprimir el Archivo: Suponiendo que el archivo PostgreSQLf.tar.gz fue descargado y colocado en el directorio /usr/local/, debe desempacarse y descomprimirse así: # cd /usr/local # tar -xzf postgresqlf.tar.gz Ahora debe accederse al directorio postgresql de la siguiente manera: # cd postgresql Configuración: El próximo paso en el procedimiento de instalación es la configuración del sistema base, así como la elección de las opciones adicionales de construcción del mismo. Esto debe llevarse a cabo mediante la ejecución del SCRIPT de configuración. Para la configuración por defecto solo se debe hacer ./configure desde el directorio base del sistema. A partir de esto, el script ejecutará una serie de pruebas para determinar el valor de distintas variables del sistema, así como comprobar a su vez la configuración actual del sistema en sí, permitiendo de esta manera saber si es posible o no instalar el RT-PostgreSQL sobre la plataforma en cuestión. Para llevar a cabo una configuración personalizada, existen distintas opciones, de las cuales se describen a continuación las más importantes: --prefix = PREFIX El sistema se instalará por defecto en /usr/local/pgsql/, pero en caso de que el mismo se desee instalar en alguna otra ubicación, PREFIX, será entonces la dirección del directorio a utilizar. --with-pgport = NUMBER El sistema por defecto posee como número de puerto, 5432. Si se desea utilizar algún otro número, el mismo estará identificado por NUMBER. --enable-depend Permite llevar un chequeo dinámico de dependencias. Por medio de esta opción los makefiles correspondientes a todos los archivos serán configurados de manera tal que todos los archivos serán reconstruidos en caso de que cualquiera de sus archivos de cabecera (o header files) sea modificado. Al igual que en la opción anterior, se recomienda utilizar esta opción cuando se están llevando a cabo modificaciones sobre el código fuente del sistema. Para conocer todas las opciones de configuración disponibles, se recomienda revisar el archivo INSTALL, el cual se encuentra en el directorio base del RTDBMS. Ahora, para llevar a cabo la configuración, se debe hacer entonces: # ./configure Construcción: Para la construcción del sistema sólo se debe ejecutar make así: # make

PostgreSQLf Página 30

Una vez que se haya construido por completo el sistema, se mostrará el siguiente mensaje: All of PostgreSQL is successfully made. Ready to install. Instalación de Archivos: Finalmente, para llevar a cabo la instalación de los archivos respectivos del sistema, se debe hacer: # make install A partir de este comando, se colocarán de manera adecuada los archivos necesarios dentro del directorio especificado en el apartado 1.2.3-PREFIX. Es necesario evaluar siempre que se posean los permisos necesarios para escribir datos sobre el área especificada. Configuración del Usuario postgres: Se debe crear una cuenta de usuario UNIX para poseer y gestionar los archivos de bases de datos de PostgreSQLf. Este usuario es denominado postgres, el cual será considerado el usuario root o superusuario de PostgreSQLf. Para esto es necesario tener privilegios de root. En una máquina Linux, el usuario postgres debe añadirse por medio del comando useradd, así: # adduser postgres Crear Cluster para la Base de Datos: Este es el cluster que contendrá las bases de datos que vayamos creando. Al momento de inicializar un cluster de bases de datos de PostgreSQL, se tiene que especificar el directorio donde se creará el mismo. El propietario de ese directorio tiene que ser un usuario que no sea root, en este caso, el usuario será postgres. Como ya se ha indicado en el /etc/passwd que el HOME del usuario postgres es /var/pgsql/data, siguiendo con esa lógica, se indicará que ése será el directorio donde se localice el cluster de bases de datos. Entonces se crea el directorio y se cambia el propietario: # mkdir -p /var/pgsql/data # chown postgres /var/pgsql/data Ahora se cambia al usuario postgres y se inicializa el cluster de las bases de datos con el comando initdb: # su – postgres postgres# /usr/local/pgsql/bin/initdb -D /var/pgsql/data Si la inicialización del cluster se llevó a cabo con éxito, el resultado final del comando será similar al que se muestra a continuación: Success. You can now start the database server using: /usr/local/pgsql/bin/postmaster -D /var/pgsql/data or /usr/local/pgsql/bin/pg_ctl -D /var/pgsql/data -l logfile start Iniciar el Servidor: Lo que sigue es iniciar el servidor de bases de datos. Antes de esto, se recomienda agregar las próximas líneas al profile (archivo .bash_profile o .bashrc) del usuario postgres, el cual debe encontrarse en el directorio HOME de este usuario, /var/pgsql/data/. PGDATA=/var/pgsql/data PATH=/usr/local/pgsql/bin:$PATH

PostgreSQLf Página 31

MANPATH=/usr/local/pgsql/man:$MANPATH export PATH PGDATA MANPATH Esto debería funcionar para cualquier shell basada en sh (incluyendo bash y ksh). Esto se hace para evitar la molestia de poner toda la ruta del cluster de la base de datos cada vez que se inicializa el servidor, y a su vez para agregar al PATH del sistema el directorio donde están los comandos de PostgreSQL: Nota: es necesario loguearse de nuevo a la consola del sistema una vez se haya actualizado el archivo correspondiente, de manera tal que la shell haga uso de la nueva configuración. Ahora, como usuario postgres inicializar el servidor de bases de datos con el comando pg_ctl, así: postgres# pg_ctl start –l nombre_log postmaster starting De esta manera ya se tiene PostgreSQL funcionando y cada uno de los registros del sistema (logs) se almacenarán en el archivo nombre_log. Para conectarse a un servidor de base datos PostgreSQL se utiliza el comando psql. Se le pueden pasar muchos parámetros a este comando de la forma psql [OPTIONS]... [DBNAME [USERNAME]]. Para probar, puede conectarse al servidor de PostgreSQL sobre la base de datos base que se acaba de crear: postgres# psql template1 Welcome to psql 8.1.4, the PostgreSQL interactive terminal. Type: \copyright for distribution terms \h for help with SQL commands \? for help with psql commands \g or terminate with semicolon to execute query \q to quit template1=# Ahora, template1 es el nombre de una de las dos bases de datos que por defecto se encuentran en el cluster. Entre otras cosas, template1 se utiliza como plantilla base para la creación de una base de datos nueva. Para mayor información acerca del uso y manejo de PostgreSQL se recomienda descargar los manuales de PostgreSQL desde la siguiente dirección: [http://www.postgresql.org/files/documentation/pdf/8.2/postgresql-8.2-A4.pdf ]

Para salir del shell del PostgreSQL se utiliza el comando \q. Parar el Servidor: Ahora, para detener el servicio del servidor de PostgreSQL, se debe hacer lo siguiente: postgres# pg_ctl stop postmaster stopped

2.2. Consideraciones Importantes: El sistema PostgreSQLf ha sido diseñado tomando en cuenta la estructura y definiciones de la extensión del lenguaje de consultas difusas SQLf para el de consultas flexibles. Debido a que el lenguaje SQLf es una extensión realizada sobre el estándar SQL92, son muchos los aspectos del DDL (Data Definition Language) y el DML (Data

PostgreSQLf Página 32

Manipulation Language) de SQLf que se encuentran descritos por el estándar SQL92, por lo que no se hace mayor referencia a dichos aspectos dentro del presente manual. De la misma manera se cumple esto para aquellos aspectos específicos del lenguaje SQLf y su extensión. Como consecuencia de esto, mucha de la sintaxis detallada en el manual se encuentra resumida, por lo que el lector debe tomar en cuenta que al ver puntos suspensivos (…) dentro de una descripción sintáctica, estará en presencia de un aspecto de la sintaxis de SQL92, el cual fue omitido. Para mayor información acerca de cada uno de los aspectos descritos por el estándar SQL92, se recomienda visitar el siguiente enlace: [http://www.postgresql.org/docs/8.2/interactive/sql-commands.html ]

2.3. Lenguaje de Manejo de Datos en base a Comparadores Difusos

A continuación se describe la forma en la cual se deben llevar a cabo las operaciones de Creación de Tablas e Inserción y Selección de Datos de acuerdo a la extensión de SQLf para el Manejo de Datos imprecisos. Comparadores Difusos Creación de Comparadores Difusos Trapezoidales CREATE COMPARATOR <nombre_comparador> as <expresión> donde: <expresión> es: (INFINITE, INFINITE, expresión1, expresión2) para comparadores difusos decrecientes. | (expresión1, expresión2, expresión3, expresión4) para comparadores difusos unimodales. | (expresión1, expresión2, INFINITE, INFINITE) para comparadores difusos crecientes. Donde expresióni es la expresión que permite calcular el valor de la comparación a partir de los dos elementos comparados, los cuales son denotados con la variable x (para el término izquierdo) y la variable y (para el término derecho). Esta expresión puede utilizar conjuntos difusos. Creación de Comparadores Difusos por Extensión CREATE COMPARATOR name ON domdisc AS conj donde:

i. name: nombre del comparador difuso. ii. domdisc: nombre del dominio discreto. iii. conj: lista de pares ordenados con su respectivo grado de

membresía, su sintaxis es la siguiente: ((elementoa,elementob)/Gr.Memb.), … )

PostgreSQLf Página 33

Los elementosi pertenecen al dominio discreto definido al momento de crear el comparador difuso por extensión, se presentan en pares ordenados junto con el grado de membresía que concierne a dicho par, separados por el símbolo “/”. La sintaxis definida anteriormente hace posible la creación de comparadores difusos crecientes, decrecientes y unimodales; además de los comparadores difusos por extensión. Ejemplos

• Comparadores Difusos Trapezoidales CREATE COMPARATOR '~' ON 1 .. 100 AS ('x*y- 5','y','y',’x*y+5'); CREATE COMPARATOR '<<' ON 1 .. 100 AS ('INFINITE','INFINITE','y/3','y'); CREATE COMPARATOR '>>' ON 1 .. 100 AS ('y','y*3','INFINITE','INFINITE');

• Comparadores Difusos por Extensión CREATE COMPARATOR 'parecido1' ON plato AS ('(china,thailandesa)/0.8','(japonesa,china)/0.4','(portuguesa,espanola)/0.7','(espanola,china)/0.1','(venezolana,colombiana)/0.95','(venezolana,mexicana)/0.2','(mexicana,argentina)/0.4','(china,vietnamita)/1','(venezolana,peruana)/0.5','(colombiana,peruana)/0.36','(portuguesa,venezolana)/0.8','(espanola,colombiana)/0.25','(espanola,venezolana)/0.69','(portuguesa,peruana)/0.85','(japonesa,vietnamita)/0.92','(thailandesa,peruana)/0.02'); CREATE COMPARATOR 'parecido2' ON piel AS ('(negra,india)/0.8','(negra,morena)/1.0','(blanca,negra)/0.01','(blanca,india)/0.2','(india,triguena)/0.5','(morena,blanca)/0.01','(triguena,blanca)/0.01','(negra,triguena)/0.6');

Predicados Difusos Creación de Predicados Difusos Atómicos CREATE FUZZY PREDICATE term ON ib .. ie AS conj; donde:

i. term es un string de caracteres con el nombre del predicado difuso,

ii. ib, ie números enteros que indica el dominio. iii. conj es la definición de la función de membresía de un trapecio

que puede ser de tres formas: a) (infinite, infinite, i1, i2), b) (i1, i2, infinite, infinite) ó c) (i1, i2, i3, i4),

Las cuales describen función de membresía monótona decreciente (al menos), monótona creciente (a lo sumo) y unimodal respectivamente.

PostgreSQLf Página 34

Ejemplos

• CREATE FUZZY PREDICATE joven ON 0 .. 120 AS (infinite, infinite, 20, 40);

• CREATE FUZZY PREDICATE viejo ON 0 .. 120 AS (40, 80, infinite, infinite);

• CREATE FUZZY PREDICATE maduro ON 0 .. 120 AS (20, 40, 60, 80);

• CREATE FUZZY PREDICATE cerca_50 ON 0 .. 120 AS (20, 49, 51, 80);

Creación de Predicados por Extensión y por Expresión CREATE FUZZY PREDICATE term ON dom AS conj; donde:

i. term es un string de caracteres con el nombre del predicado difuso.

ii. dom es un string de caracteres que indica el dominio discreto. iii. conj es la definición de la función de membresía que puede ser:

a) (val1/grado1, val2/grado2,..., valn/gradon), para la función de membresía por extensión.

b) (expr) siendo expr una expresión para la función de membresía por expresión.

Ejemplos

• CREATE FUZZY PREDICATE gordo ON contextura AS ('obeso/1', 'grueso/0.7', 'normal/0.4'); Predicado por extensión

• CREATE FUZZY PREDICATE aprox ON promedio AS ('x+0.5/10'); Predicado por expresión

Creación de Modificadores Difusos CREATE MODIFIER nombre AS POWER n CREATE MODIFIER nombre AS norm POWER n CREATE MODIFIER nombre AS TRANSLATION d donde:

i. n es la potencia a la cual se va a elevar el grado de membresía. ii. norm es una norma o conorma triangular que se le aplica al grado

de membresía iii. d es un valor que se suma al argumento del predicado original

para hacer la traslación. Ejemplos

• CREATE MODIFIER muy AS POWER 2;

PostgreSQLf Página 35

• CREATE MODIFIER extremadamente AS max ('x+y-1', '0') POWER 4;

• CREATE MODIFIER realmente AS TRANSLATION -10;

Creación de Conectores Difusos CREATE CONNECTOR nombre AS expr donde:

i. expr es la expresión que permite calcular el valor del predicado compuesto a partir de los valores de sus miembros.

Ejemplo

• CREATE CONNECTOR imp AS max ('1-x, y’); Cuantificadores Difusos CREATE [ABSOLUTE/RELATIVE] QUANTIFIER <nombre> AS <conj> donde:

i. ABSOLUTE/RELATIVE dependerá del tipo de cuantificador que se desee crear.

ii. nombre es un string de caracteres con el nombre del cuantificador difuso.

iii. conj es la definición de la función de membrecía de un trapecio que puede ser de tres formas:

a) (infinite, infinite, f1, f2), b) (f1, f2, infinite, infinite) ó c) (f1, f2, f3, f4),

Las cuales describen función de membrecía monótona decreciente (al menos), monótona creciente (a lo sumo) y unimodal respectivamente.

Ejemplos

• CREATE ABSOLUTE QUANTIFIER a_lo_sumo_2 AS (0.0, 0.0, 2.0, 3.0);

• CREATE ABSOLUTE QUANTIFIER al_menos3 AS (1.0, 3.0, infinite, infinite);

• CREATE ABSOLUTE QUANTIFIER aprox_5 AS (3.0, 5.0, 5.0, 7.0);

• CREATE RELATIVE QUANTIFIER la_minoria AS (0.0, 0.0, 0.25, 0.5);

• CREATE RELATIVE QUANTIFIER la_mayoria AS (0.5, 0.75, 1, 1);

• CREATE RELATIVE QUANTIFIER aprox_la_mitad AS (0.25, 0.5, 0.5, 0.75);

PostgreSQLf Página 36

Vistas Difusas CREATE VIEW <nombre_vista> AS <condicion_difusa>; donde:

i. <nombre_vista> es: La etiqueta o nombre que se usa para identificar la vista.

ii. <condición_difusa> es: La consulta difusa empleada para crear la vista.

Ejemplos

• CREATE VIEW repuestos_baratos_vol_bajo AS SELECT ps_partkey FROM partsupp WHERE ps_supplycost = barato;

2.4. Selección de Datos.

A continuación se presenta la sintaxis para la Selección de Datos empleando predicados difusos, conectores difusos, cuantificadores difusos, modificadores difusos, comparadores difusos, consultas difusas en el from, operaciones conjuntistas difusas, consultas particionadas difusas, creación y consulta de Vistas difusas y el uso de los operadores CHECK y UPDATE difusos por la extensión de SQLf para el Manejo de Datos en base a consultas con preferencias.

• SELECT <ATRIBUTOS> FROM <TABLAS> WHERE <lista_de_comparadores_difusos>

donde: <lista_de_comparadores_difusos> es (comparador1, comparador2, …, comparadorn). Ejemplo: select * from datos where edad ‘<<’ joven and edad ‘>>’ 10 or plato ‘parecido’ china;

• SELECT <ATRIBUTOS> FROM <TABLAS> WHERE

<lista_de_predicados_difusos>

donde: <lista_de_predicados_difusos> es (predicado1, predicado2, …, predicadon). Ejemplo: select * from datos where edad = joven and edad = aprox or peso = gordo;

• SELECT <ATRIBUTOS> FROM <TABLAS> WHERE

<lista_de_modificadores_difusos>

PostgreSQLf Página 37

donde: <lista_de_modificadores_difusos> es (modificador1, modificador2, …, modificadorn). Ejemplo: select * from datos where edad ‘muy’ joven and edad ‘extremadamente’ viejo;

• SELECT <ATRIBUTOS> FROM <TABLAS> WHERE

<lista_de_conectores_difusos>

donde: <lista_de_conectores_difusos> es (conector1, conector2, …, conectorn). Ejemplo: select * from datos where edad = joven and not edad = aprox or imp peso = gordo;

• SELECT ... FROM … WHERE Q<lista_pred_difusos>...

donde: Q es un cuantificador difuso <lista_pred_difusos> es: (FuzzyPred1,..., FuzzyPredn) Ejemplo: SELECT * FROM datos WHERE lamayoria(edad=joven, talla=grande);

• Para el caso de las vistas difusas

SELECT <atributos> FROM <nombre_vista>; Ejemplo: SELECT * FROM repuestos_baratos_vol_bajo;

• Consultas Particionadas Difusas

SELECT <atributos> FROM <tablas> WHERE <condicion> GROUP BY <atributos_grupo> HAVING <condicion_difusa>; donde: <atributos_grupo> es: El o los atributos que servirán como criterio de agrupamiento. <condición_difusa> es: La condición difusa impuesta sobre los grupos.

PostgreSQLf Página 38

Ejemplo: SELECT ps_partkey, avg(ps_supplycost) FROM partsupp GROUP BY ps_partkey having avg(ps_supplycost) = costeable;

• Update Difuso

UPDATE <tabla> SET <atributo> = [<valor>] WHERE <condicion_difusa>; Ejemplo: UPDATE supplier SET s_nationkey = 26 WHERE s_nationkey = 20 AND s_acctbal = bajo;

• Check Difuso

CREATE TABLE <nombre_tabla> AS (nombre_atributo tipo_atributo (CHECK nombre_atributo = condición_difusa)); donde: <nombre_atributo tipo_atributo> es: El nombre y tipo de atributo creado en la tabla, este puede ser uno o varios atributos dependiendo de las necesidades del usuario (CHECK nombre_atributo = condición_difusa) es: La regla difusa que se verificara cada vez que se inserta un nuevo valor para el atributo en la tabla. Ejemplo: CREATE TABLE pacientes_jovenes (id_paciente integer, nomb_paciente varchar(15), edad integer CHECK(edad = joven)); INSERT INTO pacientes_jovenes VALUES (1,'Pedro',23); INSERT 0 1 INSERT INTO pacientes_jovenes VALUES (3,'Jose',31); ERROR: new row for relation "pacientes_jovenes" violates check constraint "pacientes_jovenes_edad_check"

• Para el caso de las consultas difusas en el from, tenemos:

SELECT <ATRIBUTOS> FROM (SELECT <ATRIBUTOSJ> FROM <TABLAS> WHERE <CONDICIÓN DIFUSA INTERNA>) AS ALIAS WHERE <CONDICION DIFUSA EXTERNA> donde: <CONDICION DIFUSA INTERNA>, <CONDICION DIFUSA EXTERNA> pueden presentar predicados difusos, comparadores difusos, cuantificadores difusos o grupo by con having difuso. Ejemplo: select * from (select * from (select * from datos where lamayoria(edad=joven, talla=grande)) as alias1 where edad ‘<<’ 10) as alias2 where edad=joven;

PostgreSQLf Página 39

• Para el caso de consultas que presenten operación conjuntistas difusas, tenemos:

SELECTi [INTERSECT|EXCEPT|UNION ] SELECTj donde: SELECTk presentan condiciones difusas definidas por predicados difusos, comparadores difusos, cuantificadores difusos, modificadores difusos, conectores difusos o group by con having difuso. Ejemplo: select * from (select * from (select * from datos where lamayoria(edad=joven, talla=grande)) as alias1 where edad ‘<<’ 10) as alias2 where edad=joven [INTERSECT|EXCEPT|UNION ] select * from datos group by atributoi having(atributoi) = viejo

• Función de Calibración

SELECT <lista de atributos> FROM <lista de relaciones> WHERE <condición difusa> [WITH CALIBRATION <c>] La cláusula WITH CALIBRATION es opcional, donde H ) 7 es el factor de calibración que permite al usuario determinar un filtro adicional a las tuplas de acuerdo al grado de membresía a la consulta o un número determinado de tuplas, ya sea un número real entre mayor a 0 y menor o igual a 1 (0 H ) ` 1) o un número entero positivo mayor a 0, respectivamente.

PostgreSQLf Página 40

MANUAL DE PROGRAMADOR

1. Introducción

El propósito de este manual de programador es dar a conocer todos los listados de cada una de las modificaciones de los módulos de postgresql involucrados para la implementación de predicados difusos, modificadores difusos, conectores difusos y comparadores difusos; cuantificadores difusos; group by, having difuso; así como también las operaciones conjuntistas difusas, consultas difusas en el from y comparadores difusos. Para ello se tratará de forma amena y concisa un repaso de la funcionalidad de los módulos de PostgreSQL involucrado para las operaciones antes mencionadas, con el fin de que investigadores involucrados en la extensión de PostgreSQLf y posteriores a éste proyecto pueda modificar a su gusto algunos valores, parámetros u operaciones de las operaciones que se plantean a continuación.

2. Consideraciones Generales

2.1. Catalogo del Sistema (Ver Anexo A)

PostgreSQL así como otros SGBD gestiona las tablas del sistema con el mismo gestor de Bases de Datos, dichas tablas conforman el catálogo de un SGBD. En PostgreSQL todas estas comienzan con el prefijo “pg_” y para cada objeto creado en la Base de Datos se le asigna un OID (identificador de objeto), y es almacenado en la tabla del catálogo pg_class. El catálogo es utilizado por todos los subsistemas del backend de postgres y la mayoría de las tablas de este en PostgreSQL son copiadas de un patrón de Bases de Datos (template) el cual se usa al inicializar el sistema con el comando initdb por lo cual son específicos de la Base de Datos. En vista que las tablas del catálogo se acceden de una forma más eficiente que las tablas de usuario, debido al uso de rutinas contenidas en el directorio utils/cache que permiten mejorar los tiempos de búsqueda manteniendo una memoria cache para esto. Se decide crear en la extensión PostgreSQLf tablas del catálogo para almacenar los Predicados Difusos, Modificadores Difusos, Compradores Difusos , Conectores Difusos y Cuantificadores difusos; cuyos nombres son pg_fuzzypred, pg_fuzzymod, pg_fuzzycomp, pg_fuzzyconn y pg_fuzzyquan respectivamente. Luego de que el parser reconoce la sentencia de SQLf, para la creación de Predicados Difusos ya sean Atómicos, por Extensión y por Expresión, Modificadores Difusos, Comparadores Difusos Trapezoidales y por Extensión, Conectores Difusos y Cuantificadores Difusos; nace la necesidad de almacenar los datos que conforman a estos en las tablas del catálogo mencionadas anteriormente. Para llevar a cabo esto, se elaboraron nuevos archivos de cabecera denominados pg_fuzzypred, pg_fuzzymod, pg_fuzzycomp,

PostgreSQLf Página 41

pg_fuzzyconn y pg_fuzzyquan, ubicados en el directorio /include/catalog, y de esta forma al ejecutar initdb para la instalación de PostgreSQLf este añada las tablas pg_fuzzypred, pg_fuzzymod, pg_fuzzycomp, pg_fuzzyconn y pg_fuzzyquan al catálogo del sistema. En el Makefile ubicado en el directorio /include/catalog se incluyen los archivos de cabecera para que sean considerados a la hora de compilar por el gmake. Para incluir las nuevas tablas del catálogo como nuevos objetos que pueda reconocer PostgreSQLf, fue necesario modificar el archivo de cabecera pg_class.h y asignar un OID a cada tabla, por último se añadieron entradas en el contenido de los archivos de cabecera pg_attribute.h y pg_type.h ubicados en el mismo directorio, donde se indican las características de cada columna de las nuevas tablas del catálogo, es decir, su esquema y el tipo de atributos. En cada una de las nuevas tablas del catálogo se almacena la información necesaria para poder realizar consultas de tipo difuso, a continuación se detalla cada tabla:

• pg_fuzzypred: La función de membresía tipo extensión (string de caracteres), la función de membresía tipo expresión (string de caracteres), el dominio discreto (string de caracteres). Cabe destacar que esta es una extensión de la tabla de catalogo creada en su trabajo de investigación por Cadenas (2008), esto puede observarse en la siguiente figura.

Figura 4 Estructura pg_fuzzypred

• pg_fuzzymod: El nombre del modificador difuso (string de caracteres), la potencia a utilizar por el modificador (numero entero), el nombre de la norma o conorma, el argumento izquierdo y argumento derecho de las normas o conormas (todos string de caracteres) y el tipo del modificador, la siguiente figura muestra gráficamente esta estructura.

PostgreSQLf Página 42

Figura 5 Estructura pg_fuzzymod

• pg_fuzzycomp: El nombre del comparador difuso (string de caracteres), la información del dominio sea este un dominio real o de tipo discreto, el soporte y el núcleo para un modificador con función de membresía trapezoidal, y la función de membresía tipo extensión (string de caracteres) y el tipo de comparador, en la siguiente figura se muestra la representación gráfica de esta estructura.

Figura 6 Estructura pg_fuzzycomp

• pg_fuzzyconn: el nombre del conector difuso y la expresión asociada a dicho conector (todas string de caracteres), como puede verse en la siguiente figura.

PostgreSQLf Página 43

Figura 7 Estructura pg_fuzzyconn

• pg_fuzzyquan: el nombre del cuantificador difuso, el soporte y el núcleo de una función de membrecía tipo trapecio (todos estos números reales), además de dos campos que indica el tipo de cuantificación (monótono creciente, monótono decreciente o unimodal, relativo o absoluto), como puede verse en la siguiente figura.

Figura 8 Estructura pg_fuzzyquan

2.2. Parser (Ver Anexo B)

La extensión se realizó en primer lugar para que procesara la creación de predicados difusos atómicos de la forma (Cadenas Lucero, 2008): CREATE FUZZY PREDICATE term ON ib .. ie AS conj; donde: term es un string de caracteres con el nombre del predicado difuso, ib, ie números enteros que indica el dominio. conj es la definición de la función de membresía de un trapecio que puede ser de tres formas:

a) (infinite, infinite, i1, i2), b) (i1, i2, infinite, infinite) ó c) (i1, i2, i3, i4),

Las cuales describen función de membresía monótona decreciente (al menos), monótona creciente (a lo sumo) y unimodal respectivamente. En el caso del apartado c) en que i2= i3, entonces sería la representación de una función triangular; además i1, i2, i3, i4, son números enteros.

PostgreSQLf Página 44

A continuación se presentaran unos ejemplos de creación de predicados difusos atómicos:

a) CREATE FUZZY PREDICATE joven ON 0 .. 120 AS (infinite, infinite, 20, 40);

b) CREATE FUZZY PREDICATE viejo ON 0 .. 120 AS (40, 80, infinite, infinite);

c) CREATE FUZZY PREDICATE maduro ON 0 .. 120 AS (20, 40, 60, 80);

d) CREATE FUZZY PREDICATE cerca_50 ON 0 .. 120 AS (20, 49, 51, 80);

Creación de Predicados Difusos por Extensión y por Expresión (Rossodivita, 2009): CREATE FUZZY PREDICATE term ON dom AS conj; donde: term es un string de caracteres con el nombre del predicado difuso. dom es un string de caracteres que indica el dominio discreto. conj es la definición de la función de membresía que puede ser:

a) (val1/grado1, val2/grado2,..., valn/gradon), para la función de membresía por extensión.

b) (expr) siendo expr una expresión para la función de membresía por expresión.

A continuación se muestra un ejemplo para la creación de estos tipos de Predicados:

a) CREATE FUZZY PREDICATE gordo ON contextura AS ('obeso/1', 'grueso/0.7', 'normal/0.4'); Predicado por extensión

b) CREATE FUZZY PREDICATE aprox ON promedio AS ('x+0.5/10'); Predicado por expresión

Creación de Modificadores Difusos, estos pueden ser de tres tipos diferentes (Rossodivita, 2009): CREATE MODIFIER nombre AS POWER n CREATE MODIFIER nombre AS norm POWER n CREATE MODIFIER nombre AS TRANSLATION d Donde: n es la potencia a la cual se va a elevar el grado de membresía. norm es una norma o conorma triangular que se le aplica al grado de membresía d es un valor que se suma al argumento del predicado original para hacer la traslación. A continuación se muestra un ejemplo para la creación de modificadores difusos:

a) CREATE MODIFIER muy AS POWER 2; b) CREATE MODIFIER extremadamente AS max ('x+y-1', '0') POWER 4;

PostgreSQLf Página 45

c) CREATE MODIFIER realmente AS TRANSLATION -10;

Creación de Comparadores Trapezoidales (Rossodivita, 2009): CREATE COMPARATOR name ON ib .. ie AS conj Donde: name: nombre del comparador difuso. ib, ie: números enteros que indican el dominio. conj: es la definición de la función de membresía de un trapecio que puede ser:

a) (infinite, infinite, expresión1, expresión2), b) (expresión1, expresión2, infinite, infinite) ó c) (expresión1, expresión2, expresión3, expresión4).

Las cuales describen función de membresía monótona decreciente (al menos), monótona creciente (a lo sumo) y unimodal respectivamente. Los términos expresióni son expresiones de cadenas de caracteres, que por lo menos tiene que presentar en su definición una de estas dos variables: x e y, donde la variable x representa el lado izquierdo del comparador e y el lado derecho del comparador difuso.

Ejemplos:

a) CREATE COMPARATOR '~' ON 1 .. 100 AS ('x*y-5','y','y',’x*y+5'); b) CREATE COMPARATOR '<<' ON 1 .. 100 AS

('INFINITE','INFINITE','y/3','y'); c) CREATE COMPARATOR '>>' ON 1 .. 100 AS

('y','y*3','INFINITE','INFINITE'); El nombre del comparador difuso se cierra entre comillas simples que representa un tipo de dato SCONST, esto se hizo con el fin de poder diferenciar los comparadores que maneja postgresql y los comparadores difusos definidos por el usuario.

Creación de Comparadores por Extensión (Rossodivita, 2009) CREATE COMPARATOR name ON domdisc AS conj Donde: name nombre del comparador difuso. domdisc nombre del dominio discreto. conj lista de pares ordenados con su respectivo grado de membresía, su sintaxis es la siguiente:

a) ((elementoa,elementob)/Gr.Memb.), … ) Los elementosi pertenecen al dominio discreto definido al momento de crear el comparador difuso por extensión, se presentan en pares ordenados junto con el grado de membresía que concierne a dicho par, separados por el símbolo “/”.

PostgreSQLf Página 46

Ejemplos:

a) CREATE COMPARATOR 'parecido1' ON plato AS ('(china,thailandesa)/0.8','(japonesa,china)/0.4','(portuguesa,espanola)/0.7','(espanola,china)/0.1','(venezolana,colombiana)/0.95','(venezolana,mexicana)/0.2','(mexicana,argentina)/0.4','(china,vietnamita)/1','(venezolana,peruana)/0.5','(colombiana,peruana)/0.36','(portuguesa,venezolana)/0.8','(espanola,colombiana)/0.25','(espanola,venezolana)/0.69','(portuguesa,peruana)/0.85','(japonesa,vietnamita)/0.92','(thailandesa,peruana)/0.02');

b) CREATE COMPARATOR 'parecido2' ON piel AS ('(negra,india)/0.8','(negra,morena)/1.0','(blanca,negra)/0.01','(blanca,india)/0.2','(india,triguena)/0.5','(morena,blanca)/0.01','(triguena,blanca)/0.01','(negra,triguena)/0.6');

Creación de Conectores Difusos (Rossodivita, 2009) CREATE CONNECTOR nombre AS expr Donde: expr es la expresión que permite calcular el valor del predicado compuesto a partir de los valores de sus miembros. Ejemplo de creación de conectores difusos

a) CREATE CONNECTOR imp AS max ('1-x, y’);

Creación de Cuantificadores Difusos (Bazán, 2009) CREATE [ABSOLUTE/RELATIVE] QUANTIFIER <nombre> AS <conj> Donde: ABSOLUTE/RELATIVE dependerá del tipo de cuantificador que se desee crear. nombre es un string de caracteres con el nombre del cuantificador difuso. conj es la definición de la función de membrecía de un trapecio que puede ser de tres formas:

a) (infinite, infinite, f1, f2), b) (f1, f2, infinite, infinite) ó c) (f1, f2, f3, f4),

Las cuales describen función de membrecía monótona decreciente (al menos), monótona creciente (a lo sumo) y unimodal respectivamente. En el caso del apartado c) en que f2= f3, entonces sería la representación de una función triangular; además f1, f2, f3, f4, son números reales.

Ejemplos:

a) CREATE ABSOLUTE QUANTIFIER a_lo_sumo_2 AS (0.0, 0.0, 2.0, 3.0);

b) CREATE ABSOLUTE QUANTIFIER al_menos3 AS (1.0, 3.0, infinite, infinite);

c) CREATE ABSOLUTE QUANTIFIER aprox_5 AS (3.0, 5.0, 5.0, 7.0);

PostgreSQLf Página 47

d) CREATE RELATIVE QUANTIFIER la_minoria AS (0.0, 0.0, 0.25, 0.5);

e) CREATE RELATIVE QUANTIFIER la_mayoria AS (0.5, 0.75, 1, 1); f) CREATE RELATIVE QUANTIFIER aprox_la_mitad AS (0.25, 0.5, 0.5,

0.75);

En esta extensión se hace uso de la cláusula WITH CALIBRATION, cuya sintaxis es la siguiente: SELECT <lista de atributos> FROM <lista de relaciones> WHERE <condición difusa> [WITH CALIBRATION <c>] La cláusula WITH CALIBRATION es opcional, donde <c> es el factor de calibración que permite al usuario determinar un filtro adicional a las tuplas de acuerdo al grado de membresía a la consulta o un número determinado de tuplas, ya sea un número real entre mayor a 0 y menor o igual a 1 �0 H ) ` 1�. Con esta función dará como salida aquellas tuplas cuyo grado de membresía es mayor o igual a c (calibración cualitativa) (Cadenas Lucero, 2008). Para que el parser reconociera estas sentencias se añadieron las palabras claves: FUZZY, PREDICATE, COMPARATOR, MODIFIER, POWER, TRANSLATION, CONNECTOR, ABSOLUTE, QUANTIFIER, RELATIVE, INFINITE y CALIBRATION, en el archivo keywords.c ubicado en el directorio /src/backend/parser/. Luego además de dichas palabras reservadas, en el archivo gram.y ubicado en el mismo directorio, se incluyeron los siguientes comandos para reconocer las sintaxis de creación señaladas anteriormente:

- CreateFuzzyPredStmt (Create Fuzzy Predicate Statement). - CreateFuzzyModStmt (Create Fuzzy Modifier Statement). - CreateFuzzyCompStmt (Create Fuzzy Comparator Statement). - CreateFuzzyConnStmt (Create Fuzzy Connector Statement). - CreateFuzzyQuanStmt (Create Fuzzy Quantifier Statement).

El Tcop es el encargado de tomar el control, ya que este tipo de sentencias no requieren de optimización, y así verificar si existe el Predicado Difuso, Modificador Difuso, Comparador Difuso, Conector difuso o Cuantificador Difuso que se desea crear en sus respectivas tablas del catálogo, de no existir procede a introducirlo entonces en esta. Para que el parser pueda analizar las expresiones contenidas en un comando Select y con este crear el árbol correspondiente (parser tree difuso), se extendió el programa parse_expr.c para el reconocimiento de Predicados Difusos Atómicos, por Extensión y por Expresión, Modificadores Difusos, Comparadores Difusos, Conectores Difusos y Cuantificadores Difusos definidos en sus respectivas tablas del catálogo. En este se incluyeron archivos cabecera para el uso de rutinas del utilitario access y con estas buscar si uno o más

PostgreSQLf Página 48

identificadores contenidos en el comando Select se encuentra definido como Predicado Difuso Atómicos o por Extensión, Modificador Difuso, Conector Difuso o Cuantificadores Difusos dentro de las tablas del catálogo definidas para el almacenamiento de estos. Para los Predicados Difusos por Expresión y los Comparadores Difusos ya sean Trapezoidales o por Extensión, la búsqueda de estos en el comando Select se realiza con la extensión del programa analyze.c, ya que estos involucran argumentos de la tabla que se consulta y dichos atributos solo se pueden obtener en el programa analyze.c. Todo esto permite procesar consultas multirrelaciones de la forma: SELECT <lista de atributos> FROM <lista de relaciones> WHERE <condición difusa> De encontrarse definido un Predicado Difuso, Modificador Difuso, Comparador Difuso, Conector Difuso o Cuantificadores Difuso, se crea un nuevo nodo denominado A_FuzzyPred (un predicado difuso), donde se colocan los parámetros extraídos de la tabla pg_fuzzypred además de los parámetros extraídos de pg_fuzzymod o pg_fuzzyconn si poseen Modificadores Difusos o Conectores Difusos respectivamente; o el nodo A_FuzzyComp (un comparador difuso), donde se colocan los parámetros extraídos de la tabla pg_fuzzycomp. En la lista whereClause se tiene un nodo A_FuzzyQuan donde se indica el nombre del cuantificador junto a todos sus atributos, a esto se le agrega una lista (args) con cada uno de los predicados difusos que contiene (A_FuzzyPred). Estos nuevos nodos va a ser parte del parser tree, creando así un parser tree difuso, a continuación se muestra la representación gráfica de estos nodos.

PostgreSQLf Página 49

Figura 9 Estructura A_FuzzyPred

Figura 10 Estructura A_FuzzyQuan

PostgreSQLf Página 50

Figura 11 Estructura A_FuzzyComp

Predicados Difusos Atómicos (Cadenas Lucero, 2008) En el archivo nodes.h se colocan los indicadores dentro del nodo query tree: hasFuzzyPred (posee predicados difuso) y numFuzzyPred (número de predicados difusos). En el directorio /src/backend/include/parser/ se modificó el archivo de cabecera parse_node.h para incluir en el parser state el indicador booleano p_hasFuzzyPred y el entero p_numFuzzyPred, que corresponden a los mencionados anteriormente en el query tree. Adicionalmente se modificó el archivo parse_coerce.c para una verificación de un nodo difuso. A continuación se mostrara un ejemplo, donde se efectúa una consulta simple de SQLf, se muestra lo explicado anteriormente. Se supone que el predicado difuso “joven” fue creado a través de una sentencia como la siguiente: CREATE FUZZY PREDICATE joven ON 0 .. 120 AS (Infinite, Infinite, 20, 50); Esta permite introducir el predicado difuso monótono “joven” en la tabla del catálogo pg_fuzzypred. Ejemplo: Generación de un parser tree difuso a partir de una consulta difusa Dada la siguiente consulta SQLf simple:

PostgreSQLf Página 51

SELECT nombre, apellido FROM Estudiante WHERE edad = joven; El módulo del parser genera un parser tree con un nodo raíz SelectStmt, el cual contiene una lista de nodos TargetList (lista de atributos a proyectar) y por cada atributo contenido en la cláusula select un nodo ResTarget que apunta a un nodo Attr con el nombre de la relación y un apuntador a un nodo Value que indica el nombre del atributo; también una lista fromClause con un nodo RangeVar por cada entrada de una tabla en la cláusula FROM. En este caso se tendría un nodo (correspondiente a estudiante) y un apuntador a un nodo RelExpr que contiene el nombre de la tabla. En la lista whereClause se tiene un nodo A_Expr donde se indica el nombre de la operación (=), éste último tiene dos sucesores (lexpr y rexpr) que apuntan a dos nodos uno izquierdo y otro derecho; en lexpr se apunta al atributo joven, mientras que en rexpr al nodo A_FuzzyPred joven.

Figura 12 Parser tree difuso para el predicado joven

El proceso de transformación toma el parser tree difuso y lo recorre recursivamente, al encontrar un nodo SelectStmt es transformado a un nodo Query, el cual estará la raíz de la nueva estructura query tree difuso, la estructura

PostgreSQLf Página 52

de éste último es muy parecida al parser tree difuso sólo que con ciertas transformaciones. La cláusula where es de especial interés porque allí es donde se almacena el predicado difuso, esta cláusula es transformada al campo qual del query tree. En el directorio /src/backend/parser/ se modificó el programa analyze.c quién es el encargado de transformar el parser tree en un query tree para pasar el valor de los campos p_hasFuzzyPred y p_numFuzzyPred desde el parser state al query tree. En la figura 13 se muestra un ejemplo simplificado de la forma de un query tree difuso generado por esta consulta en particular, se diferencian cuatro partes principales: la identificación del comando (query) representado por la transformación del nodo superior SelectStmt del parser tree, el target list que representa una lista de las columnas a ser proyectadas, rtable que contiene las tablas a ser usadas y la qualification con un nodo denominado OpExpr (Operation Expresión) que indica las condiciones por las cuales van a ser filtradas las tuplas resultantes.

Figura 13 Estructura simplificada de un query tree difuso

PostgreSQLf Página 53

Predicados Difusos por Extensión, por Expresión, Comparadores Difusos Trapezoidales y por Extensión y conectores Difusos (Rossodivita, 2009) Dentro del parser state se incluyeron los parámetros siguientes, p_FuzzyPredExpr el cuál es una lista con las expresiones de los Predicados Difusos por Expresión y una lista con los nombres de los Modificadores Difusos p_FuzzyMod. A través del ejemplo que se mostrara a continuación, donde se efectúa una consulta SQLf haciendo uso de un Predicado Difuso y un Modificador Difuso, se muestra la generación de un parser tree difuso. Se supone que el Predicado Difuso “gordo” y el Modificador Difuso “muy” fueron creados previamente. Dada la siguiente consulta SQLf: SELECT nombre,ci FROM estudiante WHERE contextura = muy gordo El módulo del parser de PostgreSQL con este tipo de sentencias genera un parser tree, el cual contiene como raíz un nodo SelectStmt que consta de una lista de nodos TargetList (lista de atributos a proyectar), y por cada atributo contenido en la cláusula SELECT un nodo ResTarget que apunta a un nodo Attr, este contiene el nombre de la relación y un apuntador a un nodo Value donde se indica el nombre del atributo; el nodo SelectStmt posee también una lista fromClause con un nodo RangeVar para cada entrada en la cláusula FROM, y un apuntador a un nodo RelExpr que contiene el nombre de la tabla; y la lista whereClause la cual tiene un nodo A_Expr donde se indica el nombre de la operación, este es un árbol que tiene dos hojas lexpr apunta al lado izquierdo de la operación, en este caso el atributo contextura, y rexpr que apunta al lado derecho de la operación que para este caso es el nodo A_FuzzyPred “gordo” con el Modificador Difuso “muy”, representando esto el query tree difuso generado por PostgreSQLf. La estructura del query tree difuso se muestra en la figura 14.

PostgreSQLf Página 54

Figura 14 Parser tree difuso para el modificador muy y predicado gordo

El módulo parser de PostgreSQLf en el proceso de transformar el parser tree difuso a un query tree difuso, transforma el nodo raíz SelectStmt a un nodo Query, el cual será la raíz de la nueva estructura query tree difuso. La cláusula

SelectStmt

unique

unionall

targetList

fromClause

whereClause

groupClause

havingClause

sortClause

ResTarget

Attr

relname

attrs Value

Var.str

A_Expr

opname

oper

rexpr

lexpr Attr

relname

attrs

Value

Var.str

A_FuzzyPred

pred gordo

minfp 0

modminfp 0

core1 0

modcore1 0

core2 0

modcore2 0

maxfp 0

modmaxfp 0

typefp 4

modtypefp 0

vno 1

vattno 5

vtype 35

compfplist obeso/1, grueso/0.7

modcompfplist

exprfp

disd contextura

hasfm true

fuzzymod muy

Mtype 1

Mpower 4

RangeVar

name

relExpr

“nombre”

“estudiante”

“=”

“estudiante”

“edad”

PostgreSQLf Página 55

WHERE del parser tree difuso es de especial interés pues es en esta donde se almacenan los Predicados Difusos, los Modificadores Difusos, Comparadores Difusos, Conectores difusos y/o Cuantificadores Difusos; esta clausula es transformada al campo qual del query tree difuso. El programa analyze.c de PostgreSQL ubicado en el directorio backend/parser, encargado este de transformar el parser tree en un query tree, fue modificado para pasar los valores de los campos p_FuzzyPredExp, p_FuzzyMod, p_hasFuzzyComp y p_numFuzzyComp almacenados en el parse state al query tree difuso. En la figura 15 se muestra un query tree difuso simplificado generado a partir del parser tree difuso mostrado en la figura 14.

PostgreSQLf Página 56

Figura 15 Query tree simplificado

El módulo del parser también fue extendido para que reconociera consultas que presenten comparadores difusos, para lograr esto en el gram.y se ingreso esta nueva línea de código:

Var

varno: 1

Varattno: 5

Vartype: 35

A_FuzzyPred

pred gordo

minfp 0

modminfp 0

core1 0

modcore1 0

core2 0

modcore2 0

maxfp 0

modmaxfp 0

typefp 4

modtypefp 0

vno 1

vattno 5

vtype 35

compfplist obeso/1, grueso/0.7

modcompfplist

exprfp

disd contextura

hasfm true

fuzzymod muy

Mtype 1

Mpower 4

RTE

Relname

.

.

Query

commandType

jointree

.

.

hasFuzzyPred true

numFuzzyPred 1

targetList

rtable

.

.

returningLists

hasFuzzyComp false

FuzzyPredExp

FuzzyComp

OpExpr

Opno: 98 (=)

args

Resjunk

TLE

Resorigtable

Resorigcol

Attnumber: 1

Resname nombre

Ressortgrouppref

“estudiante”

qual

PostgreSQLf

| a_expr SCONST b_expr{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, } El nombre de cualquier comparador difuso pertenece a un tipo de dato por el hecho de que al momento de crearlo se encierran dentro de comillas simples, aparte de esto se crea un árbol A_Expr y para reconocer si en dicárbol existe un comparador difuso, se extendió el programa archivo se incluyeron archivos de cabecera para utilizar las rutinas del utilitario access y buscar si un identificador después de pasar todos los chequeos se encuentra definido como comparador difuso en la tabla del catálogo pg_fuzzycomp. Por ejemplo, tenemos el siguiente query: '>>' viejo; para esta sentencia se creará el siguiente árbol muestra en la Figure 1

Figura 16

Además de tener en un query un comparador junto a un predicado difuso, se puede también tener comparadores difusos con constantes, por ejemplo, tenemos el siguiente query: siguiente árbol A_Expr

COLUMNREF

| a_expr SCONST b_expr

$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, (Node *) makeSimpleA_Expr(AEXPR_OP, "=",(Node *) makeString($2), $3, @2), @2);

El nombre de cualquier comparador difuso pertenece a un tipo de dato por el hecho de que al momento de crearlo se encierran dentro de comillas simples, aparte de esto se crea un árbol A_Expr y para reconocer si en dicárbol existe un comparador difuso, se extendió el programa analyze.carchivo se incluyeron archivos de cabecera para utilizar las rutinas del utilitario access y buscar si un identificador después de pasar todos los chequeos se

do como comparador difuso en la tabla del catálogo

Por ejemplo, tenemos el siguiente query: select * from sospechoso where edad para esta sentencia se creará el siguiente árbol A_Expr

muestra en la Figure 16.

16 Árbol A_Expr que define una sentencia que presenta comparador difuso

Además de tener en un query un comparador junto a un predicado difuso, se puede también tener comparadores difusos con constantes, por ejemplo, tenemos

iente query: select * from sospechoso where edad '>>' 10; A_Expr como se muestra en la Figura 17.

AEXPR

=

COLUMNREF

edad

AEXPR

=

COLUMNREF

>>

COLUMNREF

joven

Página 57

$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, (Node *) makeSimpleA_Expr(AEXPR_OP,

ing($2), $3, @2),

El nombre de cualquier comparador difuso pertenece a un tipo de dato SCONST por el hecho de que al momento de crearlo se encierran dentro de comillas simples, aparte de esto se crea un árbol A_Expr y para reconocer si en dicho

analyze.c, en éste archivo se incluyeron archivos de cabecera para utilizar las rutinas del utilitario access y buscar si un identificador después de pasar todos los chequeos se

do como comparador difuso en la tabla del catálogo

select * from sospechoso where edad A_Expr como se

Además de tener en un query un comparador junto a un predicado difuso, se puede también tener comparadores difusos con constantes, por ejemplo, tenemos

select * from sospechoso where edad '>>' 10; se creará el

PostgreSQLf

Figura 17

Luego, en el analyzprocesa dicho árbol, se verifica si existe un comparador difuso, en caso de encontrarse definido el comparador difuso en nodo (incluido en los nodos del parser) denominado comparador difuso), donde se colocan los parámetros extraídos de la tabla pg_fuzzycomp, un nuevo nodo que puede ser ó A_Const (una constante) que es el elemento que se le esta aplicando el comparador difuso. Además de un elemento entero que indica el índice de la constante que se le aplica un comparador difuso sólo y cuando este sea de extensión (Los detalles de porque se almacena ese elemento entero se mostrará más adelante), el A_FuzzyComp(cuando hay comparadores difusos por extensión) se almacenan en una lista como se muestra en la Figura 16, que va a formar parte de la estructura Se incluyeron en la estructura query tree, un booleano que indica si existe o no comparador difuso y otro una Lista que almacenara los elementos descritos anteriormente. Esto se realiza para poder calcular posteriormente (en el módulo ejecutor) los grados de membresía de cada tupla, de acuerdo a los comparadores difusos involucrados. A continuación en la figura 1como el nodo donde se almacena el comparador difuso del subforma en el gram.y indicando que ya se procesó dichacomparador difuso.

17 Árbol A_Expr que define una sentencia que presenta comparador difuso.

analyze.c en la función recursiva “Transform_compqual”procesa dicho árbol, se verifica si existe un comparador difuso, en caso de encontrarse definido el comparador difuso en pg_fuzzycomp, se crea un nuevo nodo (incluido en los nodos del parser) denominado A_FuzzyCompcomparador difuso), donde se colocan los parámetros extraídos de la tabla

, un nuevo nodo que puede ser A_FuzzyPred (un predicado difuso) (una constante) que es el elemento que se le esta aplicando el

. Además de un elemento entero que indica el índice de la constante que se le aplica un comparador difuso sólo y cuando este sea de extensión (Los detalles de porque se almacena ese elemento entero se mostrará

A_FuzzyComp, A_FuzzyPred ó A_Const y el elemento entero (cuando hay comparadores difusos por extensión) se almacenan en una lista como se muestra en la Figura 16, que va a formar parte de la estructura Se incluyeron en la estructura Query dos parámetros, una vez que se genera

, un booleano que indica si existe o no comparador difuso y otro una Lista que almacenara los elementos descritos anteriormente. Esto se realiza para poder calcular posteriormente (en el módulo ejecutor) los grados de membresía

de acuerdo a los comparadores difusos involucrados.

A continuación en la figura 18, se muestra como se elimina tanto el nodo raíz como el nodo donde se almacena el comparador difuso del subforma en el gram.y indicando que ya se procesó dicha condición que presenta un

AEXPR

=

COLUMNREF

edad

AEXPR

=

COLUMNREF

>>

ACONST

10

Página 58

Transform_compqual”, se procesa dicho árbol, se verifica si existe un comparador difuso, en caso de

, se crea un nuevo A_FuzzyComp (un

comparador difuso), donde se colocan los parámetros extraídos de la tabla (un predicado difuso)

(una constante) que es el elemento que se le esta aplicando el . Además de un elemento entero que indica el índice de la

constante que se le aplica un comparador difuso sólo y cuando este sea de extensión (Los detalles de porque se almacena ese elemento entero se mostrará

y el elemento entero (cuando hay comparadores difusos por extensión) se almacenan en una lista como se muestra en la Figura 16, que va a formar parte de la estructura Query.

dos parámetros, una vez que se genera el , un booleano que indica si existe o no comparador difuso y otro una

Lista que almacenara los elementos descritos anteriormente. Esto se realiza para poder calcular posteriormente (en el módulo ejecutor) los grados de membresía

de acuerdo a los comparadores difusos involucrados.

, se muestra como se elimina tanto el nodo raíz como el nodo donde se almacena el comparador difuso del sub-árbol que se

condición que presenta un

PostgreSQLf

Figura rama que presenta un comparador difuso

Figura 19 Lista que almacena el nodo que presenta un comparadel nodo que representa el elemento que se le aplica

dicho comparador (A_FuzzyPred ó A_Const)

Después que se elimina la rama del árbol que tiene el comparador difuso, se procesa el nodo A_FuzzyPredOp (solo para aquellos comparadores de función de membresía de trapecio), tomemos el siguiente ejemplo: edad ‘<<’ 10; ‘~’ ‘<<’maduro

• Se verifica si los comparadores y predicados difusos son del mismo tipo (creciente, decreciente o unimodalun A_Const

• Dependiendo del tipo del comparador difuso, se extrae los términos correspondientes para realizar el posfijo de la expresión que pertenece al término que se esta extrayendo y luego sustituir con el valor que corresponde,

o Posfijo ‘~’:�

o Sustitución de valores�

AEXPR

=

COLUMNREF

edad

COLUMNREF

>>

Query: FuzzyComp

Figura 18 Proceso de Eliminación de la rama que presenta un comparador difuso

Lista que almacena el nodo que presenta un comparador difuso y

el nodo que representa el elemento que se le aplica dicho comparador (A_FuzzyPred ó A_Const)

Después que se elimina la rama del árbol que tiene el comparador difuso, se A_FuzzyPred ó A_Const para transfórmalo en un árbol

(solo para aquellos comparadores de función de membresía de trapecio), tomemos el siguiente ejemplo: select * from Table where edad ‘

)

Se verifica si los comparadores y predicados difusos son del mismo tipo creciente, decreciente o unimodal), si el lado derecho del comparador es

no se realiza dicha verificación. Dependiendo del tipo del comparador difuso, se extrae los términos correspondientes para realizar el posfijo de la expresión que pertenece al término que se esta extrayendo y luego sustituir con el valor que corresponde, ya sea un predicado difuso o una constante.

Posfijo ‘~’: � Término1 = xy*5-, � Término4 = xy*5+,

Sustitución de valores � Término1 = edad18*5-,

AEXPR

AEXPR

=

COLUMNREF COLUMNREF

joven

AEXPR

=

COLUMNREF

edad

A_FuzzyComp

>>

name, soporte, núcleo, etc...

A_FuzzyPred

joven

name, soporte, núcleo, etc...

Página 59

or difuso y

Después que se elimina la rama del árbol que tiene el comparador difuso, se para transfórmalo en un árbol A_Expr

(solo para aquellos comparadores de función de membresía de trapecio), select * from Table where edad ‘~’ maduro or

Se verifica si los comparadores y predicados difusos son del mismo tipo ), si el lado derecho del comparador es

Dependiendo del tipo del comparador difuso, se extrae los términos correspondientes para realizar el posfijo de la expresión que pertenece al término que se esta extrayendo y luego sustituir con el valor que

AEXPR

=

COLUMNREF

joven

A_FuzzyPred

name, soporte, núcleo, etc...

PostgreSQLf

o Posfijo ‘<<’:�

o Sustitución de valores�

• Se realiza el principio de decomparador difuso a través de las expresiones sustituidas resultantes del posfijo. Este proceso no se lleva a cabo cuando se presentan comparadores difusos por extensión.

En la figura 20-22

Figura 20 Creación del Árbol A_Expr para una sentencia que presenta un comparador difuso

AEXPR

COLUMNREF

edad

COLUMNREF

� Término4 = edad30*5+, Posfijo ‘<<’:

� Término4 = y, Sustitución de valores

� Término4 = 10, Se realiza el principio de derivación dependiendo del tipo del comparador difuso a través de las expresiones sustituidas resultantes del posfijo. Este proceso no se lleva a cabo cuando se presentan comparadores difusos por extensión.

22 se presenta como estos cambios quedarían reflejados:

Creación del Árbol A_Expr para una sentencia que presenta un comparador difuso

BOOLEXPR

OR

AEXPR

=

COLUMNREF AEXPR

=

COLUMNREF

~

COLUMNREF

maduro

AEXPR

=

COLUMNREF

edad

AEXPR

COLUMNREF

<<

Página 60

rivación dependiendo del tipo del comparador difuso a través de las expresiones sustituidas resultantes del posfijo. Este proceso no se lleva a cabo cuando se presentan

quedarían reflejados:

Creación del Árbol A_Expr para una sentencia

AEXPR

=

COLUMNREF ACONST

10

PostgreSQLf

A_FuzzyComp ~

Figura 21 Eliminación dinserción en la lista FuzzyComp A_FuzzyComp y el nodo correspondiente al elemento

que se le aplica dicho comparador (A_FuzzyPred ó A_Const)

AEXPR

COLUMNREF

edad

A_FuzzyPred

maduro A_FuzzyComp

<< Eliminación de la rama del árbol que presenta un comparador difuso e

inserción en la lista FuzzyComp A_FuzzyComp y el nodo correspondiente al elemento que se le aplica dicho comparador (A_FuzzyPred ó A_Const)

BOOLEXPR

OR

AEXPR

=

COLUMNREF

maduro

AEXPR

COLUMNREF

edad

Página 61

A_Const 10

e la rama del árbol que presenta un comparador difuso e inserción en la lista FuzzyComp A_FuzzyComp y el nodo correspondiente al elemento

que se le aplica dicho comparador (A_FuzzyPred ó A_Const)

AEXPR

=

COLUMNREF ACONST

10

PostgreSQLf

Figura 22 Árbol A_Expr gene

dependiendo del tipo de comparador difuso definido con los elementos que se le aplica dicho comparador

Como se mencionó anteriormente, los comparadores difusos por extensión están representados por pares ordenad

). En el caso que se tengan queries que presenten comparadores difusos por extensión, por ejemplo: <condicion1>, plato = ‘china’ <condicionFuzzyComp almacenara: el comparador difuso (se le aplica dicho comparador (donde se encuentra el comparador. En el /optimizer/plan/planner.c al formar el plan se utiliza el query treepresenta en sus nodos los comparadores difusos y el query que se ejecuto anteriormente quedaría transformado de la siguiente manera: where plato = ‘china<condicionn> , como se puede notar se tienen dos condiciones <condicion2> que son definidas de la misma manera pero una de ellas utilizó un comparador difuso por extensión antes de ser procesado analyze.c, esta es la razón por la cual se debe tener un identificador para determinar a que condiciónrealizar el proceso de derivate_fuzzy_opex_comp que se explicará en detalle más adelante. La función que procesa el eliminación de nodos e inserción de parámetro en la lista FuzzyComp se describe a continuación:

AEXPR OP

<

COLUMNREF

edad

AEXPR

*

COLUMNREF

edad

Árbol A_Expr generado aplicando el principio de derivación dependiendo del tipo de comparador difuso

definido con los elementos que se le aplica dicho comparador

Como se mencionó anteriormente, los comparadores difusos por extensión están representados por pares ordenados con su grado de membresía ((a,b)/valor

En el caso que se tengan queries que presenten comparadores difusos por extensión, por ejemplo: select * from Table where plato ‘parecido’ ‘china’

>, plato = ‘china’ <condicion2>, …, <condicionn>almacenara: el comparador difuso (A_FuzzyComp), la constante que

se le aplica dicho comparador (A_Const) y un elemento entero idonde se encuentra el comparador. En el /optimizer/plan/planner.c al formar el

query tree que se proceso en el analyze.c, dicha estructura ya no presenta en sus nodos los comparadores difusos y el query que se ejecuto anteriormente quedaría transformado de la siguiente manera: select * from Table

plato = ‘china’ <condicion1>, plato = ‘china’ <condicion, como se puede notar se tienen dos condiciones <

> que son definidas de la misma manera pero una de ellas utilizó un comparador difuso por extensión antes de ser procesado el query treeanalyze.c, esta es la razón por la cual se debe tener un identificador para

condicióni pertenece el comparador difuso por extensión y realizar el proceso de derivate_fuzzy_opex_comp que se explicará en detalle

La función que procesa el query tree para identificar los comparadores difusos, eliminación de nodos e inserción de parámetro en la lista FuzzyComp se describe a continuación:

BOOLEXPR

OR

BOOLEXPR

AND

AEXPR OP

AEXPR

+

ACONST

30

ACONST

5

AEXPR OP

>

COLUMNREF

edad

AEXPR

-

AEXPR

*

COLUMNREF

edad

ACONST

18

ACONST

5

AEXPR

<

COLUMNREF

edad

Página 62

rado aplicando el principio de derivación

definido con los elementos que se le aplica dicho comparador

Como se mencionó anteriormente, los comparadores difusos por extensión están os con su grado de membresía ((a,b)/valor

En el caso que se tengan queries que presenten comparadores difusos por plato ‘parecido’ ‘china’

> , la lista Query: ), la constante que i de la condicioni

donde se encuentra el comparador. En el /optimizer/plan/planner.c al formar el que se proceso en el analyze.c, dicha estructura ya no

presenta en sus nodos los comparadores difusos y el query que se ejecuto select * from Table

>, plato = ‘china’ <condicion2>, …, , como se puede notar se tienen dos condiciones <condicion1,

> que son definidas de la misma manera pero una de ellas utilizó un query tree en el

analyze.c, esta es la razón por la cual se debe tener un identificador para pertenece el comparador difuso por extensión y

realizar el proceso de derivate_fuzzy_opex_comp que se explicará en detalle

para identificar los comparadores difusos, eliminación de nodos e inserción de parámetro en la lista FuzzyComp se

ACONST

10

PostgreSQLf Página 63

var compNames : pointer to List;

var constIndex : integer;

function Transform_compqual(in pstate : pointer to ParseState, in-out newWhere : pointer to

Node, in-out iscomp : bool)

begin

l, r : pointer to Node;

a : pointer to A_Expr;

l a NULL; //Almacenar hijo izquierdo r a NULL; //Almacenar hijo derecho a a NULL; //Almacenar nodo raíz de tipo AEXPR if (newWhere <> NULL) then //Árbol no vacio begin

if (newWhere = A_Expr) then

begin

a a newWhere;

l a a↑.lexpr;

r a a↑.rexpr;

if (l <> NULL) then

begin

if (l = A_Expr) then

l a Transform_compqual(pstate,l,iscomp);

else

begin

if (l = ColumnRef) then

begin

if (r = A_Expr) then //Al hacer el hizo izquierdo un ColumnRef y el hijo derecho A_Expr puede ser que haya un comparador difuso begin

aux : pointer to A_Expr;

aux a r;

if (aux↑.rexpr = ColumnRef) then

begin

n : pointer to A_FuzzyPred;

if (aux↑.rexpr es A_FuzzyPred) then

begin

n a aux↑.rexpr;

result, result1 : pointer to Node;

nc : pointer to A_FuzzyComp;

if (aux↑.lexpr es A_FuzzyComp) then

begin

nc a aux↑.lexpr;

a↑.rexpr a aux↑.rexpr //Eliminación de la rama donde esta el comparador difuso newWhere a a;

if (n↑.typefp = 4 or n↑.typefp = 5) then

ERROR //Cuando hay comparadores difusos no se permiten predicados difusos por expresión ni extensión respectivamente if (nc↑.typefp <> n↑.typefp) then

ERROR //No se permiten comparadores y predicados de distintos tipos iscomp a true;

//Inserción en la lista compNames los nodos A_FuzzyComp y

A_FuzzyPred

compNames a lappend(compNames,nc); //A_FuzzyComp

PostgreSQLf Página 64

compNames a lappend(compNames,n); //A_FuzzyPred posijo, min, max, core1, core2, auxiliar : pointer to char;

switch(nc↑.typefp)

begin

case 1:

posfijo a makePosfijo(nc↑.minfp);

min a n↑.minfp;

auxiliar a sustitucion_valores_posfijo(posfijo, min);

result a makeExprfpNode(pstate,auxiliar,l);

posfijo a makePosfijo(nc↑.maxfp);

max a n↑.maxfp;

auxiliar a sustitucion_valores_posfijo(posfijo, max);

result1 a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeA_Expr(AEXPR_AND, NIL, (Node *)

makeSimpleA_Expr(AEXPR_OP, ">", l, result, -1), (Node *)

makeSimpleA_Expr(AEXPR_OP, "<", l, result1, -1), -1);

end

case 2:

posfijo a makePosfijo(nc↑.maxfp);

max a n↑.maxfp;

auxiliar a sustitucion_valores_posfijo(posfijo, max);

result a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l,

result, -1);

end

case 3:

posfijo a makePosfijo(nc↑.minfp);

min a n↑.minfp;

auxiliar a sustitucion_valores_posfijo(posfijo, min);

result a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l,

result, -1);

end

end_switch

end_if

else

ERROR //No existe Comparador Difuso Transform_compqual a result;

end_if

else

ERROR //No existe Predicado difuso end_if

else

begin

if (aux↑.rexpr = A_Const) then

begin

result, result1 : pointer to Node;

nc : pointer to A_FuzzyComp;

c : pointer to A_Const;

c a aux↑.rexpr ;

constIndex a constIndex + 1;

PostgreSQLf Página 65

if (aux↑.lexpr es A_FuzzyComp) then

begin

nc a aux↑.lexpr;

a↑.rexpr a aux↑.rexpr //Eliminación de la rama donde esta el comparador difuso newWhere a a;

iscomp a true;

//Inserción en la lista compNames los nodos A_FuzzyComp y

A_Const y un elemento entero

compNames a lappend(compNames,nc); //A_FuzzyComp compNames a lappend(compNames,n); //A_Const compNames a lappend(compNames,constIndex); //elemento entero posijo, min, max, core1, core2, auxiliar : pointer to char;

termino : float; //almacenar el valor del nodo A_Const

termino a c↑.valor;

switch(nc↑.typefp)

begin

case 1:

posfijo a makePosfijo(nc↑.minfp);

auxiliar a sustitucion_valores_posfijo(posfijo, termino);

result a makeExprfpNode(pstate,auxiliar,l);

posfijo a makePosfijo(nc↑.maxfp);

auxiliar a sustitucion_valores_posfijo(posfijo, termino);

result1 a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeA_Expr(AEXPR_AND, NIL, (Node *)

makeSimpleA_Expr(AEXPR_OP, ">", l, result, -1), (Node *)

makeSimpleA_Expr(AEXPR_OP, "<", l, result1, -1), -1);

end

case 2:

posfijo a makePosfijo(nc↑.maxfp);

auxiliar a sustitucion_valores_posfijo(posfijo, termino);

result a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l,

result, -1);

end

case 3:

posfijo a makePosfijo(nc↑.minfp);

auxiliar a sustitucion_valores_posfijo(posfijo, termino);

result a makeExprfpNode(pstate,auxiliar,l);

result a (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l,

result, -1);

end

case 4:

result a newWhere;

end

end_switch

end_if

else

ERROR //No existe el comparador difuso Transform_compqual a result;

PostgreSQLf Página 66

end_if end_else

end_if

end_if

end_else

end_if

if (r <> NULL) then

begin

if (r = A_Expr) then

r a Transform_compqual(pstate,r,iscomp);

else

begin

if (r = A_Const) then

constIndex a constIndex + 1;

end_else

end_if

end_if

end_if

if (l <> NULL) then

a↑.lexpr a l;

if (r <> NULL) then

a↑.rexpr a r;

Transform_compqual a a;

end

INICIO //transformSelectStmt en analyze.c iscomp : bool;

constIndex a 0;

compNames a NIL;

iscomp a false;

newWhere a Transform_compqual(pstate,newWhere,iscomp);

END

Cuantificadores Difusos (Bazán, 2009) En el archivo nodes.h se colocan los indicadores dentro del nodo query tree: hasFuzzyQuan (tiene cuantificadores difusos) y numFuzzyQuan (número de cuantificadores difusos). En el directorio /src/backend/include/parser/ se modificó el archivo de cabecera parse_node.h para incluir en el parser state el indicador booleano p_hasFuzzyQuan y el entero p_numFuzzyQuan, que corresponden a los mencionados anteriormente en el query tree. Adicionalmente se modificó el archivo parse_coerce.c para una verificación de un nodo difuso. A continuación se efectúa una consulta simple de SQLf usando cuantificación lingüística, donde se muestra lo explicado anteriormente. Se construye el cuantificador absoluto creciente “al menos 3” como: CREATE ABSOLUTE QUANTIFIER al_menos3 AS (1.0, 3.0, INFINITE, INFINITE);

PostgreSQLf Página 67

Esto permite introducir el predicado difuso monótono “al_menos3” en la tabla del catálogo pg_fuzzyquan. Suponiendo que los predicados “aproximadamente 34 años”, “alto”, “pesado”, “alto nivel” y “salario regular” han sido creados y definidos con las siguientes instrucciones: CREATE FUZZY PREDICATE aprox_34_anos ON 0 .. 120 AS (30, 32, 36, 38); CREATE FUZZY PREDICATE alto ON 0 .. 300 AS (100, 200, infinite, infinite); CREATE FUZZY PREDICATE pesado ON 0 .. 200 AS (80, 120, INFINITE, INFINITE); CREATE FUZZY PREDICATE alto_nivel ON 0 .. 10 AS (3, 6, INFINITE, INFINITE); CREATE FUZZY PREDICATE salario_regular ON 0 .. 3000 AS (750, 1000, 1500, 1750); Dada la siguiente consulta SQLf simple: SELECT id_num FROM empleado WHERE al_menos3 (edad=aprox_34_anos, estatura=alto, peso=pesado, nivel=alto_nivel, salario=salario_regular); El módulo del parser genera un parser tree con un nodo raíz SelectStmt, el cual contiene una lista de nodos TargetList (lista de atributos a proyectar) y por cada atributo contenido en la cláusula SELECT un nodo ResTarget que apunta a un nodo Attr con el nombre de la relación y un apuntador a un nodo Value que indica el nombre del atributo; también una lista fromClause con un nodo RangeVar por cada entrada de una tabla en la cláusula FROM. En este caso se tendría un nodo (correspondiente a empleado) y un apuntador a un nodo RelExpr que contiene el nombre de la tabla. En la lista whereClause se tiene un nodo A_FuzzyQuan donde se indica el nombre del cuantificador junto a todos sus atributos, a esto se le agrega una lista (args) con cada uno de los predicados difusos que contiene( A_FuzzyPred). En la Figura 23 se muestra el parser tree difuso generado por esta consulta en particular, se diferencian cuatro partes principales: la identificación del comando (query) representado por la transformación del nodo superior SelectStmt del parser tree, el target list que representa una lista de las columnas a ser proyectadas, rtable que contiene las tablas a ser usadas y la qualification con un nodo denominado OpExpr (Operation Expresión) que indica las condiciones por las cuales van a ser filtradas las tuplas resultantes. El recorrido del parser tree se realiza recursivamente para cada elemento del árbol, una vez se tiene un cuantificador difuso como raíz del árbol (A_FuzzyQuan) se llama a un procedimiento implementado que aplica el principio de derivación para el nodo, resultando en una consulta estándar SQL.

PostgreSQLf Página 68

El procedimiento de derivación llamado derívate_fuzzy_quan, toma cada predicado difuso de la lista de argumentos almacenado en A_FuzzyQuan para generar nodos del tipo BoolExpr (Expresiones Booleanas) y OpExpr (Expresiones de Operación). Cada nodo BoolExpr puede apuntar en sus argumentos (args) a otro nodo BoolExpr y uno OpExpr o a dos nodos OpExpr. Básicamente el procedimiento consiste en generar una combinatoria de los predicados difusos mediante el BoolExpr de tipo AND, esta combinatoria es luego unida mediante BoolExpr OR, obteniendo la consulta derivada para cuantificación lingüística.

SelectStmt

unionall: false

unique

whereClause

fromClause

groupClause

havingClause

targetList

sortClause

ResTarget

val “empleado”

attr

Attr

relname

“id_num”

Value

val.str

RangeVar

name

relExpr

“empleado”

A_FuzzyQuan

Predname: al_menos3

Core1: 3

Minfp: 1

Core2: 0

Maxfp: 0

Typefp: 3

Typefq: 1

args

A_FuzzyPred

Predname: alto

Core1: 300

Minfp: 100

Core2: 0

Maxfp: 0

Typefp: 3

begd: 0

begd: 300

Figura 23 Parser tree difuso de un cuantificador difuso

PostgreSQLf Página 69

Figura 24 derivate fuzzy quan Debido a su importancia para aplicar la derivación y a fin de visualizar gráficamente su significado, en la Figura 25 se muestra un esquema simplificado de lo que constituye un subárbol correspondiente a una consulta difusa como la mostrada anteriormente.

PostgreSQLf Página 70

EL árbol resultante puede resultar bastante complejo es por ello para facilitar la interpretación de este árbol se emplea una herramienta de PosgreSQL que permite visualizar su plan de ejecución, dando un vistazo a como PosgreSQL interpreta y evalúa los cuantificadores difusos. Es través del comando explain analyze de psql que se puede visualizar el plan tree obtenido, además de los costos estimados por el planner. Al efectuar esta sentencia se ejecuta la consulta y muestra el tiempo de ejecución (run time) acumulado dentro de cada nodo plan en conjunto con los costos estimados. Es de hacer notar que el actual time devuelto por el explain analyze es en milisegundos, mientras que los costos estimados son expresados en unidades arbitrarias, por lo que no se pueden comparar directamente sino a través de la consistencia de los porcentajes de diferencia. En la Figura 26 se muestra el resultado de ejecutar este comando sobre la consulta SQLf anterior.

BoolExpr

OR

args

OpExpr

Opno…

args

BoolExpr

AND

args

BoolExpr

AND

args

OpExpr

Opno…

args

OpExpr

Opno…

args

OpExpr

Opno…

args

Var

A_FuzzyPred

Var

A_FuzzyPred

Var

A_FuzzyPred

Var

A_FuzzyPred

Figura 25 Estructura simplificada de un subárbol difuso con cuantificación

PostgreSQLf Página 71

Figura 26 Resultado de ejecutar el comando explain analyze

Al eliminar los nodos A_FuzzyQuan del parse tree, nació la necesidad de seguir almacenando estos nodos para poder calcular posteriormente (en el módulo ejecutor) los grados de membrecía de cada tupla, de acuerdo a los predicados difusos involucrados. Así se creó una lista denominada fuzzyquan, donde se colocan todos los nodos ya transformados del query tree, además de un indicador booleano hfq (tiene cuantificador difusos), extendiendo así la estructura parse tree difuso. En el directorio /src/backend/parser/ se modificó el programa analyze.c quién es el encargado de transformar el parser tree en un query tree para pasar el valor de los campos p_hasFuzzyQuan, p_numFuzzyQuan y la lista con los cuantificadores (fuzzyquan) desde el parser state al query tree. Group By con Having Difuso (Bracho, 2009) Fue necesario realizar modificaciones en los archivos cabecera incluidos en el directorio /src/include/nodes/; ya que era necesario identificar si la condición difusa presente en una consulta se encontraba ubicada en la cláusula WHERE o en la cláusula HAVING, por lo que se añadió al archivo parsenodes.h las variables booleanas hasFuzzyQual para identificar la presencia de una condición difusa en la cláusula WHERE y hasFuzzyHavingQual para identificar la presencia de una condición difusa en la cláusula HAVING como se puede apreciar en la Figura 27.

PostgreSQLf Página 72

Figura 27 Modificaciones al parsenodes.h

Igualmente en el directorio /src/backend/include/parser/ se modificó el archivo de cabecera parse_node.h para incluir en el parser state los indicadores booleanos p_hasFuzzyQual y p_hasFuzzyHavingQual, que corresponden a los mencionados anteriormente.

Figura 28 Modificaciones al parse_node.h

Una vez incorporadas estas variables se realizó una modificación la siguiente modificación al archivo parse_clause.c:

Figura 29 Modificaciones al parse_clause.c

Aquí se incluyó una rutina de reconocimiento de condiciones difusas que permitió identificar la ubicación de la condición difusa dentro de la consulta. A continuación se muestra un ejemplo donde se realizara una consulta particionada difusa en el sistema de manera de mostrar el nuevo parse tree difuso que será generado para soportar este tipo de consultas. Ejemplo: Generación de un parse tree difuso a partir de una consulta particionada difusa SELECT id_empleado FROM Empleados WHERE edad = maduro GROUP BY id_empleado HAVING AVG(salario) = Alto Esta consulta genera un parser tree que contendrá un nodo raíz SelectStmt conformado por las siguientes estructuras:

• TargetList: aquí se almacenan los atributos que se desean proyectar y por cada uno de estos atributos se genera un nodo ResTarget que

if(pstate->p_hasFuzzyPred)

{

if(strncmp(constructName, "HAVING", 6) == 0)

pstate->p_hasFuzzyHavingQual = true;

else

pstate->p_hasFuzzyHavingQual = false;

if(strncmp(constructName, "WHERE", 5) == 0)

pstate->p_hasFuzzyQual = true;

else

pstate->p_hasFuzzyQual = false;

}

bool p_hasFuzzyHavingQual; /*has Fuzzy Qual on Having. bool p_hasFuzzyQual; /*has Fuzzy Qual on Where.

bool hasFuzzyHavingQual; /*has Fuzzy Qual on Having*/ bool hasFuzzyQual; /*has Fuzzy Qual on Whe re*/

PostgreSQLf Página 73

apunta a un nodo Attr que contiene el nombre de la relación y un apuntador a un nodo Value que indica el nombre del atributo

• fromClause: esta estructura está compuesta por un nodo RangeVar por cada tabla seleccionada en la cláusula FROM y un apuntador a un nodo RelExpr que contiene el nombre de la tabla.

• whereClause: aquí se tiene un nodo A_Expr donde se indica el nombre de la operación empleada en la cláusula WHERE y los apuntadores (lexpr y rexpr) que almacenan el atributo y la condición aplicadas en la cláusula, ubicados del lado izquierdo y derecho del operador respectivamente.

• groupClause: esta estructura es similar almacena una variable de referencia al atributo o atributos que se emplearan para agrupar y una variable de control de ordenamiento. Ambas son estructuras referenciales de uso interno de PostgreSQL.

• havingClause: de manera similar al whereClause este se encarga de almacenar la condición que será aplicada en un nodo A_Expr, solo que en este caso la condición se aplica a grupos. Otra diferencia encontrada en esta estructura es la presencia de la variable Aggref la cual se incluye en case de existir funciones agregadas como el AVG, SUM, etc; y este se sirve para identificar el tipo de función agregada que se está empleando.

Quedando así el parse tree difuso que se muestra en la Figura 30

PostgreSQLf Página 74

Figura 30 Parse tree difuso, group by con having difuso

SelectStmt

unionall: false

unique

whereClause

fromClause

groupClause

havingClause

targetList

sortClause

ResTarget

val “Empleados”

attr

Attr

relname

“id_empleado”

Value

val.str RangeVar

name

relExpr

“Empleados”

A_FuzzyPred

Predname: maduro

Core1: 22

Minfp: 20

Core2: 25

Maxfp: 27

Typefp: 1

begd: 0

begd: 120

A_Expr

oper: OP

rexpr

opname

lexpr

Attr

relname

attrs

A_Expr

oper: OP

rexpr

opname

lexpr

A_FuzzyPred

Predname: alto

Core1: 4000

Minfp: 2000

Core2: 0

Maxfp: 0

Typefp: 3

begd: 0

begd: 5000

Attr

relname

attrs

“Empleados”

“Empleados”

“=”

“=”

Value

val.str

aggref

“salario”

Value

val.str “edad”

PostgreSQLf Página 75

Tras construir este parse tree difuso el parser realiza un recorrido del mismo de manera de transformarlo en un query tree difuso que es la estructura que será recibida y manejada posteriormente en el planner, en este caso fue necesario realizar modificaciones en el archivo analyze.c ubicado en /src/backend/parser/ quien es el encargado de realizar la transformación anteriormente mencionada; donde fue necesario agregar las variables qry->hasFuzzyQual y qry->hasFuzzyHavingQual (Figura 31) para aceptar los identificadores booleanos creados anteriormente de manera de obtener un query tree difuso adaptado a nuestras extensiones.

Figura 31 Modificaciones al archivo analyze.c

La modificación final implementada en el parser se aprecian en la Figura 32, esta modificación se realizo en el archivo parse_relation.c en el cual se agrego la variable booleana rd_hasFuzzyPred cuya creación y uso se tratara de manera más detallada en la siguiente sección, y que en este archivo cumple la función de indicar si la relación posee un predicado difuso, que en el caso de ser verdadero se pasa este valor a la variable del parse tree difuso hasFuzzyPred implementada por Cadenas (2008).

Figura 32 Modificaciones al parse_relation.c

2.4. Traffic Cop (TCOP) (Ver Anexo C)

Aquí se encuentra el programa postgres principal manejador del backend, así como el código encargado de hacer las llamadas al parser, planner/optimizer, ejecutor y funciones commands.

El módulo tcop además es el encargado de comparar la consulta para clasificarla en simple o compleja. En el primer caso, la consulta no requiere de optimización (instrucciones SQL create, explain, alter table, copy, entre otros) por lo que se direcciona el control a un módulo de utilitarios commands donde se ejecuta la función deseada; en el segundo caso (select, insert, update o delete) el query tree es enviado al módulo del Rewiter para continuar con su procesamiento. Una vez que el parser chequea y acepta la sintaxis, el Tcop ejecuta un programa denominado utility.c, este llama a los procedimientos CreateFuzzyPredicate, CreateFuzzyModifier, CreateFuzzyComparate, CreateFuzzyConnector y CreateFuzzyQuantifier. Dichos procedimientos están definidos en los archivos fuzzypred.c, fuzzymod.c, fuzzycomp.c y fuzzyconn.c respectivamente, estos se encuentran ubicados en el archivo /backend/commands y se encargan de validar que no exista Predicado Difuso, Modificador Difuso, Comparador Difuso, Conector Difuso o Cuantificador Difuso en sus respectivas tablas del catálogo, luego para evitar errores semánticos, se valida que los parámetros ingresados estén dentro de los rangos correctos y de superar estos chequeos se inserta el

if(rel->rd_hasFuzzyPred) pstate->p_hasFuzzyPred = true;

qry->hasFuzzyQual = pstate->p_hasFuzzyQual; qry->hasFuzzyHavingQual = pstate->p_hasFuzzyHavingQ ual;

PostgreSQLf Página 76

nuevo registro en la tabla de catálogo correspondiente con los valores ingresados. Para hacer referencia a los nuevos procedimientos se incluyeron nuevos archivos cabecera denominados fuzzypred.h, fuzzymod.h, fuzzycomp.h, fuzzyconn.h y fuzzyquan.h en el directorio /include/commands, y se incluyeron los archivos objeto fuzzypred.o, fuzzymod.o, fuzzucomp.o, fuzzyconn.o y fuzzyquan.o en el archivo Makefile ubicado en el directorio /backend/commands. Por otra parte, fue necesario extender las funcionalidades de este módulo de manera de soportar la optimización y manejo de las vistas, update y check difusos. Primeramente se modifico el archivo de cabecera rel.h donde se creó la variable booleana rd_hasFuzzyPred que se utiliza para identificar si una relación presenta una condición difusa, como se aprecia en la figura 33.

Figura 33 Modificaciones al archivo rel.h

Una vez creada la variable mencionada anteriormente se modificó el archivo readfuncs.c ubicado en /src/backend/nodes/, un utilitario empleado por Postgres para la lectura de consultas y que fue necesario extender puesto que al emplear las cláusulas CHECK, UPDATE o la creación de vistas el sistema realiza una lectura de las consultas recibidas para crear relaciones temporales a partir de estas, que serán utilizadas posteriormente para aplicar las reglas o modificaciones establecidas por la consulta. En este caso se extendieron las capacidades de éstas rutinas utilitarias del sistema para soportar la lectura y reconocimiento de nodos difusos. La Figura 34 muestra la extensión que permite la lectura de nodos difusos.

Figura 34 Modificaciones al readfuncs.c

Igualmente se modifico el archivo ruleutils.c para incluir una función que reconociera y manejara el caso de reglas con condiciones difusas (Figura 35)

static A_FuzzyPred *

_readFuzzyPredicate(void)

{

READ_LOCALS(A_FuzzyPred);

READ_STRING_FIELD(pred);

READ_INT_FIELD(minfp);

READ_INT_FIELD(core1);

READ_INT_FIELD(core2);

READ_INT_FIELD(maxfp);

READ_INT_FIELD(typefp);

READ_INT_FIELD(vno);

READ_INT_FIELD(vattno);

READ_DONE();

}

bool rd_hasFuzzyPred; /*Indicates if a Fuzzy Predi cate Exist.

PostgreSQLf Página 77

tomando el nodo difuso y generando a partir de este una regla que se almacena con el nombre de la relación y al atributo al que afecta en la misma.

Figura 35 Modificaciones al relutils.c

Dentro de los archivos utilitarios de Postgres también encontramos el archivo relcache.c que maneja las rutinas de análisis y optimización de las consulta para la creación de las relaciones necesarias para su aplicación y manejo; aquí se crearon rutinas que reciben las relaciones difusas leídas por las funciones extendidas creadas en el archivo readfuncs.c y analizan las mismas para identificar la presencia de condiciones difusas; de encontrarse una condición difusa se emplea la variable rd_hasFuzzyPred para indicar la presencia de la misma.

2.4. Planner/Optimizer (Ver Anexo D) La tarea de este módulo es crear un plan de ejecución difuso. Primero se combina posibles maneras de recorrer las relaciones (index scan, sequential scan o bitmap index scan) y de efectuar el join si es necesario (nested loop join, hashed join o merge sort join), los caminos de acceso (access path) generados llevan al mismo resultado y la tarea de este módulo es estimar los costos de ejecución de cada path y escoger el más económico. Es de hacer notar que si la consulta requiere más de doce (12) tablas es utilizado un algoritmo de optimización genético, a menos que se especifique como parámetro de configuración que nunca utilice este último. También es importante acotar que dentro de los proyectos de mejoras a futuro del PostgreSQL está la utilización de algoritmos de optimización aleatorios para sustituir al genético. Si la consulta requiere de join, funciones de agregación, ordenación u otras operaciones sobre filas de tablas, entonces son añadidos nodos “atop” al plan para ejecutar estas operaciones; hay diferentes maneras de obtener el mismo resultado por lo que pueden aparecer diferentes tipos de nodos. La extensión de este módulo consistió en verificar si el query tree es un árbol difuso (query tree difuso), y de serlo aplicar el principio de derivación para a partir de condiciones difusas obtener condiciones booleanas. Además de

case T_A_FuzzyPred: { A_FuzzyPred *n = (A_FuzzyPred *) node; char *attname; attname = n->pred; if (attname) appendStringInfoString(buf, quote_identifier(attn ame)); else appendStringInfoString(buf, "*"); } break;

PostgreSQLf Página 78

verificar en cada nodo del plan si hay Predicados Difusos, de existir se genera un TargetEntry para el grado de membresía y se coloca en el targetlist del nodo plan para que luego, en el módulo executor, almacenar el grado de membresía calculado. Dichas modificaciones y el cálculo del grado de membresía (en el módulo executor), representan la extensión más importante de la implementación de PostgreSQLf.

Al identificar que en el subárbol quals del jointree, contenido en el query tree, existen Predicados Difusos Atómicos, por Extensión y/o Predicados Difusos por Expresión; pudiendo estos contener o no Modificadores Difusos, Comparadores Difusos y/o Conectores Difusos, se crearon mecanismos para deriva cualquier cantidad de este tipo de Predicados Difusos presentes en el query tree difuso. Dicho subárbol es un árbol binario de profundidad izquierda donde los nodos internos son Expresiones Booleanas (BoolExpr) y las hojas Expresiones de Operación (OpExpr), cada OpExpr puede tener una lista de dos argumentos y cada BoolExpr posee dos argumentos que pueden ser dos BoolExpr, un BoolExpr y un OpExpr o dos OpExpr. A continuación se muestra en la figura 36 la representación grafica de dicho subárbol.

Figura 36 Subárbol quals

Para el caso específico de los OpExpr se consideró revisar si el segundo argumento es un nodo A_FuzzyPred o un nodo A_FuzzyComp, en caso afirmativo se convierte este nodo A_FuzzyPred en un BoolExpr para los Predicados Difusos por Extensión y por Expresión, o en un OpExpr para los Comparadores Difusos. En la siguiente figura se muestra un esquema simplificado es un subárbol quals correspondiente a una consulta difusa como la mostrada a continuación: SELECT * FROM Estudiante WHERE ciudad_proc = ‘Maracay’ AND edad = maduro AND Promedio=Bueno

BoolExpr

OpExpr OpExpr

firstarg secarg firstar secarg

PostgreSQLf Página 79

Figura 37 Estructura simplificada de un subárbol qual difuso con dos conjunciones

Se crearon dos rutinas derivate_fuzzy_opex (deriva un nodo OpExpr) y derivate_fuzzy-boex (deriva un nodo BoolExpr), esta última es una rutina recursiva donde se sigue derivando hasta llegar al caso base que es encontrar dos nodos OpExpr. Mediante este recorrido recursivo del subárbol quals se garantiza derivar cualquier cantidad de predicados difusos; el detalle de la extensión del programa planner.c ubicado en el directorio /src/backend/optimizer/plan/. En la figura 38 se muestra el subárbol quals simplificado resultado de la derivación del subárbol quals anterior.

PostgreSQLf Página 80

Figura 38 Estructura simplificada de un subárbol qual derivado

La derivación de un OpExpr consiste en colocar un nuevo tipo de operador dependiendo del tipo de predicado difuso (>=, <=, >= y <=), además de utilizar el núcleo y soporte de la función de membresía para formar las nuevas operaciones con las variables identificadas (aquí se utilizan vattno y vno). En esta rutina se utilizó la gestión de nodos (creación de nodos de tipo constante, variable, OpExpr o BoolExpr) conversión entre nodos y expresiones (y viceversa), la gestión de listas (eliminar nodos y añadir nodos a una lista), además de identificar los tipos de operaciones presentes en la tabla del catálogo pg_operator dependiendo del tipo de variable y constante involucrada en la operación. Al eliminar los nodos A_FuzzyPred del query tree, transformando el subárbol qual, nació la necesidad de seguir almacenando estos nodos para poder calcular posteriormente (en el modulo ejecutor) los grados de membresía de cada tupla, de acuerdo a los predicados difusos involucrados. Así se creó una lista denominada newfp (nuevos predicados difusos), donde se colocan todos los nodos ya transformados del query tree, esta lista se denominó fuzzypred, además de un indicador booleano hfp (tiene predicados difusos), extendiendo así la estructura query tree difuso. En la figura 39 se muestra un esquema simplificado del query tree difuso derivado que será entregado al optimizador después de derivar la consulta que tiene dos predicados difusos.

PostgreSQLf Página 81

Figura 39 Estructura simplificada de query tree difuso derivado

Es importante destacar que se extendió el programa /src/backend/optimizer/util/relnode.c que contiene las rutinas para la construcción de nodos “relation” y la rutina extendida se denomina build_simple_rel quien se encarga de crear una estructura denominada RelOptInfo para cada relación base; en esta estructura se colocan los predicados difusos correspondientes a cada relación base. Esto es lo que en el diseño de la propuesta se denominó empujar hacia las hojas del plan tree los predicados difusos para que el ejecutor pueda calcular el grado de membresía utilizando una técnica bottom-up; paso muy importante en esta extensión. Además en la rutina build_join_rel de este mismo programa se extendió el código para colocar en el RelOptInfo (contiene información acerca del join de dos relaciones en el access path del plan) la información de que una de los nodos del plan (ya sea el outer o el innner) posee predicados difusos. Las extensiones de la estructuras ReloptInfo tanto de la relación base como del join se realizó en el programa cabecera /src/include/nodes/relation.h. La estructura de un plan de ejecución (plan tree) es un árbol de nodos tipo plan. Los nodos al nivel más bajo (hojas del árbol) son nodos scan que devuelven filas de una tabla, de acuerdo a los métodos físicos de acceso y los índices definidos para cada relación (secuencial, indexado o bitmap indexado). Otra de las extensiones vitales es modificar las rutinas que crean el plan tree que va a ser entregado al modulo ejecutor que se encuentran en el fuente /src/backend/optimizer/plan/createplan.c, allí se identifica si una relación base

PostgreSQLf Página 82

tiene predicado difusos para colocar en el nodo del plan la variable booleana hfp que indica que este nodo tiene predicado difusos, así como los correspondientes predicados difusos en la lista fuzzypred (esto es anotar en dicho nodo los correspondientes predicados difusos). Además se convierte en difusas tanto las relaciones base como las resultantes de cada nodo del plan al agregar un nuevo Target Entry (atributo proyectado) a cada uno de los nodos siempre que se verifique que alguno de los planes o relaciones base (el nodo izquierdo o derecho del plan) posee predicados difusos. Dada la siguiente consulta de SQLf: SELECT estudiante.carnet, nombre, apellido FROM estudiante, materia, cursa WHERE edad = maduro AND promedio = facil and estudiante.carnet = cursa.carnet AND cursa.codmat = materia.codmat La estructura simplificada del plan tree difuso generado por el planner/optimizer del PostgreSQLf para esta consulta se muestra en la figura 40.

PostgreSQLf Página 83

Figura 40 Estructura simplificada de un plan tree difuso

Para el reconocimiento de predicados difusos por extensión o por expresión se modificaron las derivaciones explicadas anteriormente realizadas por Cadenas (2008)

- derívate_fuzzy_opex, la cual a partir de un OpExpr el cual contiene un A_FuzzyPred por Extensión o por Expresión como segundo argumento, deriva dicho segundo argumento a un OpExpr.

- derivate_fuzzy-boex, es una rutina recursiva la cual a partir de un

BoolExpr continua derivando hasta encontrar dos nodos OpExpr, si alguno de estos contiene un A_FuzzyPred o un A_FuzzyComp en su segundo argumento llama a las rutinas de derivación requerida, y deriva un nodo BoolExpr con los nuevos OpExpr. Mediante este recorrido recursivo del subárbol quals se garantiza derivar cualquier cantidad de predicados difusos.

Para el caso del reconocimiento de comparadores difusos, consistió en verificar si el query tree es un árbol difuso (a través del indicador booleano hasFuzzyComp) y en este caso concatenar la lista definida en el planner newfp y la lista FuzzyComp del query tree, la lista newfp va a formar parte del planner que almacena los nodos A_FuzzyPred y A_FuzzyComp, para el cálculo del grado de membresía en el módulo ejecutor. Además se genera un TargetEntry

PostgreSQLf Página 84

(grado de membresía) colocándolo en el targetlist del nodo plan, con la intención de que el ejecutor pueda ir almacenando en dicho nodo el resultado del cálculo del grado de membresía. Mediante el recorrido recursivo que se hace en la función derívate_fuzzy_boex (deriva un nodo BoolExpr) del subárbol qual se garantiza cualquier cantidad de comparadores difusos de tipo extensión y los nodos tipo A_FuzzyPred. Se tiene una variable global constIndex que va a ir incrementando a medida que en el derívate_fuzzy_boex encuentre un nodo OpExpr donde el segundo argumento de éste sea un nodo de tipo A_Const, porque puede darse el caso que en ese nodo OpExpr se haya definido un comparador difuso por extensión. Se agregó la nueva rutina derivate_fuzzy_opex_extendC, donde se verifica que el nodo OpExpr sea la condición que se le aplico un comparador difuso a través de la variable global constIndex y el elemento entero de la lista FuzzyComp, si estas variables son iguales se guarda en dos variables el nodo A_FuzzyComp y A_Const respectivamente, para realizar el proceso de derivación a través de la rutina derivate_fuzzy_opex_comp. El nodo A_Const que se extrae de la lista FuzzyComp en la rutina derivate_fuzzy_opex_extendC, hace referencia a uno de los elementos de los pares ordenados definidos en la creación de comparadores difusos por extensión, en la rutina derivate_fuzzy_opex_comp se recorre la lista de pares ordenados para encontrar donde haya ocurrencia con el nodo A_Const y así almacenar en una nueva lista el otro elemento del par ordenado donde se encuentre dicho nodo, luego se crea un árbol BoolExp or con cada uno de los elementos descritos anteriormente. Para culminar se almacena en la lista newfp el nodo A_FuzzyComp que representa un comparador difuso por extensión, para realizar el cálculo de grado de membresía en el módulo ejecutor. Cabe destacar que el tipo de dato creado A_FuzzyComp tiene un atributo de tipo A_Const, donde se almacena el nodo A_Const que se extrajo de la lista FuzzyComp en la rutina derívate_fuzzy_opex_extendC. La rutina derivate_fuzzy_opex_comp se muestra a continuación

function derívate_fuzzy_opex_comp(in varfa : pointer to Var, in n : pointer to A_FuzzyComp) :

pointer to Node

begin

i, listCount : integer;

x : pointer to ListCell;

ptr1, ptr2 : pointer to char;

c : pointer to A_Const;

aux, tup : pointer to List;

c a n↑.secarg //Nodo A_Const que representa un elemento del par ordenado aux a NIL;

foreach(x, n↑.compfclist) //Recorrido de la lista de pares ordenado begin

cad : pointer to char;

cad a lfirst(x); //(a,b)/Gr.Memb. //Se realiza los token necesarios solo para quedarnos con los elementos del par ordenado ptr1 a Primer_Elemento_Par_Ordenado //a <- (a,b) ptr2 a Segundo_Elemento_Par_Ordenado //b <- (a,b)

PostgreSQLf Página 85

//Buscar el elemento a ó b que coincide con el nodo A_Const que se almaceno en la variable c if (ptr1 = c↑.valor) then

aux a lappend(aux,ptr2); //Si a del par ordenado (a,b) resulta ser igual al valor que contiene el nodo A_Const se almacena en la lista aux el elemento b del par ordenado if (ptr2 = c↑.valor) then

aux a lappend(aux,ptr1); //Si b del par ordenado (a,b) resulta ser igual al valor que contiene el nodo A_Const se almacena en la lista aux el elemento a del par ordenado end_foreach

listCount a list_length(aux);

fpNames = array of Datum [1 .. listCount];

i a 0;

foreach(x,aux)

begin

fpNames[i] a lfirst(x);

i a i + 1;

end_foreach

for(i = 0; i < listCount; i++)

tup a lappend(tup, (Node *) make_opclause(98, 25, false, (Expr *) varfa, (Expr *)

makeConst(25, -1, fpNames[i],false,false)));

n↑.vno a varfa↑.varno;

n↑.vattno a varfa↑.varattno;

newfp a lappend(newfp, n);

derívate_fuzzy_opex_comp a make_orclause(tup);

end

Por otra parte, para procesar los subqueries en el from, se agrego en la estructura Query una nueva variable booleana llamada hasFuzzy, esta variable será inicializada en true cuando existe condiciones difusas en el from ya sea cuando haya presencia de predicados, comparadores o cuantificadores difusos; además se creó la nueva rutina FuzzySubquery en planner.c, esta rutina es un procedimiento recursivo que procesa un query tree verificando la variable rtable que es una lista de nodos de tipo de datos RangeTblEntry, este tipo de dato contiene una variable denominada subquery de tipo Query, si esta variable es distinto NULL es porque existen subqueries en el from, si este query presenta predicado, comparadores difusos se aplica el principio de derivación para obtener las condiciones booleanas a partir de las difusas, además al query padre se le agrega un nuevo TargetEntry indicando el grado de membresía, también se verifica si el query presenta cuantificadores difusos, si es así en la lista newfp se almacena cada uno de los cuantificadores definidos en dicho query. Luego se utilizó una variable de tipo BoolExprType, la cual tendrá el valor de AND_EXPR si dos o más subqueries presentan predicados, comparadores o cuantificadores difusos, esta variable se verifica en el módulo ejecutor para el cálculo del grado de membresía y obtener el menor de estos. Se invoca la rutina FuzzySubquery hasta que la variable subquery sea igual a NULL. La única limitación es que los subqueries en el from son solo queries simples, aquellos subqueries que presentan operaciones, funciones de agregaciones, particionamiento, etc., no darán los grados de membresía correctos. Cabe destacar, cada consultas definidas en el from pueden presentar la función de calibración, para este caso se obtiene el valor de calibración de la consulta padre y de las consultas en el from para dejar solamente el mayor de todos éstos valores, los demás valores se eliminaran.

PostgreSQLf Página 86

El procedimiento FuzzySubquery se muestra a continuación: proc FuzzySubquery(in-out parse : pointer to Query, in-out fp : bool, in-out hasFuzzy : bool)

begin

boextype : BoolExprType,

boextype a -1;

if (parse <> NULL) then

begin

if (fp = true) then

begin

newfp a NIL;

fp a false;

end_if

l1 : pointer to List;

foreach(l1,parse↑.rtable)

begin

auxiliar : pointer to RangeTblEntry;

auxiliar a lfirst(l1);

bandera : bool;

bandera a false;

if (auxiliar↑.alias <> NULL) then

begin

if (auxiliar↑.alias↑.aliasname = “SELECT”) then //El subnquery no es un select simple bandera a true;

end_if

if (bandera = false) then

FuzzySubquery(auxiliar↑.subquery,fp,hasFuzzy);

if(bandera=false and auxiliar↑.subquery<>NULL and

auxiliar↑.subquery↑.hasFuzzyPred) then //Subqueries con predicados difusos begin

hasFuzzy a true;

//Buscar el mayor de los valores definidos enla calibración

if (bandera=false and auxiliar↑.subquery<>NULL and

(auxiliar↑.subquery↑.hasFuzzyComp or auxiliar↑.subquery↑.hasFuzzyQual or

auxiliar↑.subquery↑.hasFuzzyQual)) then

begin

if (parse↑.calibracion <> NULL and auxiliar↑.subquery ↑.calibracion <> NULL) then

if(parse↑.calibracion < auxiliar↑.subquery ↑.calibracion)then

parse↑.calibracion = auxiliar↑.subquery ↑.calibracion

if (parse↑.calibracion == NULL and auxiliar↑.subquery ↑.calibracion <> NULL) then

parse↑.calibracion = auxiliar↑.subquery ↑.calibracion;

end

//Proceso de derivación al presentarse query con predicados difusos

if (cantidad_subquery_difusos > 2) then

boextype a AND_EXPR;

end_if

else

begin

if(bandera=false and auxiliar↑.subquery<>NULL and

auxiliar↑.subquery↑.hasFuzzyComp) then //subqueries con comparadores difusos begin

hasFuzzy a true;

//Proceso de derivación al presentarse query con predicados difusos

if (cantidad_subquery_difusos > 2) then

boextype a AND_EXPR;

PostgreSQLf Página 87

en_if

else

begin

if(bandera=false and auxiliar↑.subquery<>NULL and

auxiliar↑.subquery↑.hasFuzzyQual) then //subqueries con cuantificadores difusos

begin

x : pointer to ListCell;

foreach(x, auxiliar↑.subquery↑.fuzzyquan)

begin

parse↑.fuzzyquan a lappend(parse↑.fuzzyquan,lfirst(x)); //Se propaga cada

uno de los cuantificadores difusos al nivel superior

end_foreach

end_if

end_else

end_else

end_foreach

end_if

end

INICIO

fp, hasFuzzy : bool;

if (parse↑.hasFuzzyPred=false and parse↑.hasFuzzyComp=false) then

fp a false;

else

fp a true;

hasFuzzy a false;

FuzzySubquery(parse,fp,hasFuzzy);

if (hasFuzzy <> false and parse↑.hasFuzzyPred=false and parse↑.hasFuzzyComp=false) then

begin

//Creación del nuevo targetentry que almacenara el valor del grado de membresía tfp : pointer to TargetEntry;

tfp↑.resname a “Gr.Memb.”;

parse↑.targertlist a lappend(parse↑.targertlist,tfp) ;

parse↑.hasFuzzy a hasFuzzy; //Indica si hay consultas difusas en el from

end_if

END

En cuanto a los cuantificadores difusos, gracias a que la derivación se realiza en el parser, al planner le llega un árbol de consulta totalmente operable por PostgreSQL, esto hace que el proceso de optimización de la consulta no requiera ser modificado. Las modificaciones en el planner consistieron en conservar la lista con los cuantificadores difusos (fuzzyquan) que viene del módulo anterior y poder ser entregada al ejecutor para el cálculo del grado de membrecía. Para el caso de having difuso, las extensiones en este modulo consistieron en analizar el query tree recibido y verificar si el mismo presenta condiciones difusas valiéndose de las variables hasFuzzyQual y hasFuzzyHavingQual. En el caso de condiciones difusas ubicadas en la cláusula HAVING solo se genera el TargetEntry para las mismas en este modulo de manera de poder incluir el cálculo del grado de membrecía posteriormente mas su derivación es soportada por funciones implementadas en el Executor de las cuales de detallara posteriormente.

PostgreSQLf Página 88

Otra extensión realizada en este modulo fue la implementación de rutinas que analizan el query tree difuso para identificar si existen relaciones provenientes de reglas generadas en la etapa de optimización con consultas del Rewriter (Figura 41), con la finalidad de poder procesar las mismas y derivar las condiciones necesarias. Igualmente se incluyeron rutinas para la verificación de la presencia de la instrucción UPDATE puesto que al presentarse una consulta que requiera actualizar datos, se debe obviar la creación del TargetEntry que almacena el grado de membrecía en el nodo puesto que no se utiliza en estos casos; también como parte de la integración de otras extensiones realizadas sobre PostgreSQLf se agregó rutinas de soporte de consultas particionadas difusas como subconsultas.

Figura 41 Verificación de vistas o reglas difusas en el planner.c

Por último en el planner.c se verifica el query tree; específicamente la variable calibración (variable que almacena el valor CALIBRATION), y se pasa al plan tree siempre y cuando el query tree presenten predicados difusos, comparadores difusos, cuantificadores difusos o having difusos. Este valor se utilizara en el módulo executor para obtener un filtro de los grados de membresía del conjunto difuso resultante. Cuando se ejecuta Operaciones Conjuntistas: UNION/INTERSECT/EXCEPT la función plan_set_operations en el Archivo /src/backend/optimazer/prep/prepunion.c planea el plan para un árbol de set operations (UNION/INTERSECT/EXCEPT). Esta rutina trata solamente el árbol setOperations del query dado. El plan que se genera viene dado en forma de Árbol donde el primer nivel representa el nodo de la operación conjuntista a realizar, el tipo de dato del nodo que representa las operaciones INTERSECT/EXCEPT es SetOp; por otra parte, si la Operación es UNION, el tipo de dato del nodo que representa dicha operación es Unique. El último nivel del plan generado es otro plan que representa los Select’s involucrados en las operaciones conjuntistas, este plan es el que va a indicar a través de la variable hfp si la operación conjuntista es difusa o no. Se recorre todo el plan que genera plan_set_operations hasta el último nivel para determinar si por lo menos un Select es difuso (a través de la variable hfp), si esta variable resulta true se va propagando este resultado en cada uno de los niveles del plan hasta llegar al

if(IsA(parse->jointree, FromExpr)) { if(IsA(parse->jointree->quals, OpExpr)){ OpExpr *opex = (OpExpr *) parse->jointree->quals; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)){ parse->hasFuzzyQual = true; parse->hasFuzzyPred = true; } } }

PostgreSQLf Página 89

primer nivel; además de crear un nuevo TargetEntry que representa el atributo Gr. Memb. (Grado de Membresía). Por otra parte, puede haber casos de operaciones conjuntistas difusas donde algunos de los Select’s involucrados en la misma no poseen condición difusa, al presentarse este caso lo que se determinó fue inicializar el atributo Gr. Memb., en 1; es decir, todas las tuplas resultante del Select pertenecerán al conjunto difuso. Para realizar el recorrido del árbol y determinar si al menos un Select contiene una o más condiciones difusas se implemento el procedimiento validarFuzzyPredicate que se presenta a continuación. proc validarFuzzyPredicate(in-out plan : pointer to Plan, in-out isfuzzy : boolean )

begin

if (plan <> NULL) then

begin

switch (nodeTag(plan)) //Recorrido de cada uno de los niveles del Plan

begin

case T_Result:

if (plan↑.hfp) then

isfuzzy a true;

validarFuzzyPredicate(plan, isfuzzy);

if (isfuzzy and ¬plan↑.hfp) then

begin

tlast : pointer to TargertEntry;

tlast a makeNode(TargetEntry);

aux : pointer to TargertEntry;

aux a list_nth(planb.lefttreeb.targetlist,

list_length(plan↑.lefttree↑.targetlist)-1);

tlast↑.expr a aux↑.expr;

tlast↑.resno a list_length(plan↑.targetlist) + 1;

tlast↑.resname a "Gr.Memb.";

tlast↑.ressortgroupref a 0;

tlast↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tlast);

plan↑.hfp a true;

end_if

end

case T_Append:

if (plan↑.hfp) then

isfuzzy a true;

subnode : pointer to ListCell;

cappendplans : pointer to List;

cappendplans a ((Append *) plan)↑.appendplans;

cappendplans a list_truncate(cappendplans,0);

foreach(subnode, ((Append *) plan)↑.appendplans)

begin

subplan : pointer to Plan;

subplan a (Plan *) lfirst(subnode);

validarFuzzyPredicate(subplan,isfuzzy);

cappendplans a lappend(cappendplans,subplan);

end_foreach

PostgreSQLf Página 90

((Append *) plan)↑.appendplans a list_truncate(((Append *)

plan)↑.appendplans,0);

foreach(subnode,cappendplans)

begin

subplan : pointer to Plan;

subplan a (Plan *) lfirst(subnode);

validarFuzzyPredicate(subplan,isfuzzy);

((Append *) plan)↑.appendplans a lappend(((Append *)

plan)↑.appendplans,subplan);

end_foreach

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

end_if

end

case T_SubqueryScan:

if (plan↑.hfp) then

isfuzzy a true;

validarFuzzyPredicate(((SubqueryScan *) plan) ↑.subplan,isfuzzy);

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

plan↑.fuzzypred = ((SubqueryScan *) plan) ↑.subplan↑.fuzzypred;

//Heredar la lista de predicados difusos de cada uno de los Select’s

end_if

end

case T_Sort:

PostgreSQLf Página 91

if (plan↑.hfp) then

isfuzzy a true;

validarFuzzyPredicate( plan ↑.lefttree,isfuzzy);

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

end_if

end

case T_SetOp:

if (plan↑.hfp) then

isfuzzy a true;

validarFuzzyPredicate( plan ↑.lefttree,isfuzzy);

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

end_if

end

case T_Unique:

if (plan↑.hfp) then

isfuzzy a true;

validarFuzzyPredicate( plan ↑.lefttree,isfuzzy);

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

PostgreSQLf Página 92

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

end_if

end

default:

if (plan↑.hfp) then

isfuzzy a true;

if (isfuzzy and ¬plan↑.hfp) then

begin

tfp : pointer to Targetentry;

tfp a makeNode(TargetEntry);

cn : pointer to Const;

cn a makeNode(Const);

val : float;

val a 1.0;

cn a makeConst(700, 4, (Float4GetDatum(val)), false, true);

tfp↑.expr a (Expr *) cn;

tfp↑.resno a list_length(plan↑.targetlist) + 1;

tfp↑.resname a "Gr.Memb.";

tfp↑.ressortgroupref a 0;

tfp↑.resjunk a true;

//New Target entry in targetList

plan↑.targetlist a lappend(plan↑.targetlist, tfp);

plan↑.hfp a true;

end_if

end

end_switch

end_if

end

2.5. Executor (Ver Anexo E) Este módulo toma el plan de ejecución resultado del planner/optimizer y lo procesa recursivamente para obtener el conjunto de filas requeridas; utiliza un mecanismo encauzado (pipeline) de demanda progresiva. Cada vez que un nodo tipo plan es llamado, deberá despachar una o más filas, o reportar que ya terminó con todas las filas requeridas (devuelve NULL). Consultas complejas pueden involucrar varios niveles de nodos tipo plan, pero la técnica general es la misma: cada nodo calcula y devuelve su próxima fila de salida cada vez que es llamado, además de aplicar cualquier selección o proyección que fueran asignadas por el planner. En este módulo se realiza otra de las extensiones primordiales para la investigación. Se extendieron los programas que ejecutan el nodo del plan de

PostgreSQLf Página 93

ejecución para que verificaran si dicho nodo posee predicados difusos y calcule el grado de membresía correspondiente, es decir aquí se están extendiendo los mecanismos de acceso físicos: sequential scan, index scan, bitmap heap scan; además de los operadores físicos relacionales: nested loop join, hash join, hash y merge join; para convertirlos en difusos al calcular el grado de membresía de la tupla resultante. Si la consulta posee Conectores Difusos de disyunción (OR) o de negación (NOT), se calcula el grado de membresía mínimo para la disyunción o el complemento para la negación como lo establece SQLf, y se coloca éste en la última posición de la tupla difusa. En el mismo programa execScan.c se definieron las normas y conormas predefinidas de SQLf para los Modificadores Difusos, las cuales son usadas para el cálculo del grado de membresía. Para el cálculo del grado de membresía en el caso que haya comparadores difusos, se tienen en cuenta si el comparador difuso es por extensión o no, ya que los cálculos son diferentes. Cuando son comparadores trapezoidales, se extrae cada uno de los términos correspondientes dependiendo si son de tipo al menos, a lo sumo o unimodal. Se realiza el posfijo, se reemplaza los valores correspondientes a través de los elemento que se le esta aplicando un comparador difuso ya sea un predicado difuso o una constante, si la expresión presenta variable x se reemplaza con el valor que corresponde a la parte izquierda del comparador difuso, si presenta la variable y se reemplaza con el valor que corresponde a la parte derecha del comparador difuso. Si son comparadores difusos por extensión éste almacena el nodo A_Const que representa la parte derecha del comparador y que pertenece a uno de los elementos de los pares ordenados del mismo, el otro elemento del par ordenado donde encuentra el valor del nodo A_Const se extrae de la variable slot que es de tipo de dato TupleTableSlot, esta variable almacena cada una de las tuplas resultantes del select que se esta procesando. El plan contiene una lista llamada fuzzypred que contiene los comparadores y predicados difusos definidos en un determinado select, de esta lista es que se extraen los nodos A_FuzzyPred y A_FuzzyComp y así realizar el cálculo del grado de membresía. El cálculo del grado de membresía cuando hay presencia de comparadores difusos se presenta a continuación: //Proceso del cálculo del grado de membresía para los comparadores difusos en el execScan.c if (node↑.ps↑.plan↑.fuzzypred) then //Verificar si al menos la lista fuzzypred tiene un elemento begin

lc : pointer to ListCell;

grmemb : float;

foreach(lc, node↑.ps↑.plan↑.fuzzypred)

begin

if (lfirst(lc) = A_FuzzyComp) then

PostgreSQLf Página 94

begin

lfp : pointer to A_FuzzyComp;

fp : pointer to A_FuzzyPred;

c : pointer to A_Const;

varfp : integer;

varfp2, posfijo, posifjo1, min, max, core1, core2 : pointer to char;

constante : float;

lfp a lfirst(lc); //Comparador difuso

if (lfp↑.typefp = 4) then //Comparadores por extensión varfp2 a slot[lfp↑.vattno] //Valor correspondiente a la parte derecha del comparador que pertence a uno de los elementos de los pares ordenados definidos en la creación de comparadores por extensión else //Comparadores trapezoidales begin

varfp a slot[lfp↑.vattno] //Valor correspondiente a la parte derecha del comparador lc a lnext(lc); //Por cada comparador difuso trapezoidal se almacena un nodo A_FuzzyPred o A_Const, que son los elementos que se le aplica dicho comparador end_else

if (varfp=NULL or varfp2=NULL) then

ERROR //Variable vacía else

begin

switch(lfp↑.typefp)

begin

case 1: //Comparador unimodal if (lfirst(lc) = A_FuzzyPred) then //En a un predicado difuso que se le aplica el comparador begin

fp a lfirst(lc); //Predicado difuso que se le aplica el comparador posfijo a makePosfijo(lfp↑.minfp);

min a fp↑.minfp;

min a sustitucion_valores_posfijo_X_Y(posfijo, varfp, min);

posfijo a makePosfijo(lfp↑.core1);

core1 a fp↑.core1;

core1 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, core1);

posfijo a makePosfijo(lfp↑.core2);

core2 a fp↑.core2;

core2 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, core2);

posfijo a makePosfijo(lfp↑.maxfp);

maxfp a fp↑.maxfp;

max a sustitucion_valores_posfijo_X_Y(posfijo, varfp, maxfp);

grmemb a CalculateGrMemb(1,min,core1,core2,max);

end_if

if (lfirst(lc) = A_Const) then //En a una constante que se le aplica el comparador begin

c a lfirst(lc); //Constante que se le aplica el comparador constante a c↑.valor;

posfijo a makePosfijo(lfp↑.minfp);

min a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

posfijo a makePosfijo(lfp↑.core1);

core1 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

posfijo a makePosfijo(lfp↑.core2);

core2 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

posfijo a makePosfijo(lfp↑.maxfp);

PostgreSQLf Página 95

max a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

grmemb a CalculateGrMemb(1,min,core1,core2,max);

end_if

end

case 2: //Comparadores al menos min a 0;

core1 a 0;

if (lfirst(lc) = A_FuzzyPred) then //En a un predicado difuso que se le aplica el comparador begin

fp a lfirst(lc); //Predicado difuso que se le aplica el comparador posfijo a makePosfijo(lfp↑.core2);

core2 a fp↑.core2;

core2 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, core2);

posfijo a makePosfijo(lfp↑.maxfp);

maxfp a fp↑.maxfp;

max a sustitucion_valores_posfijo_X_Y(posfijo, varfp, maxfp);

grmemb a CalculateGrMemb(2,min,core1,core2,max);

end_if

if (lfirst(lc) = A_Const) then //En a una constante que se le aplica el comparador begin

c a lfirst(lc); //Constante que se le aplica el comparador constante a c↑.valor;

posfijo a makePosfijo(lfp↑.core2);

core2 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

posfijo a makePosfijo(lfp↑.maxfp);

max a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

grmemb a CalculateGrMemb(2,min,core1,core2,max);

end_if

end

case 3: //Comparadores a lo sumo core2 a 0;

max a 0;

if (lfirst(lc) = A_FuzzyPred) then //En a un predicado difuso que se le aplica el comparador begin

fp a lfirst(lc); //Predicado difuso que se le aplica el comparador posfijo a makePosfijo(lfp↑.minfp);

min a fp↑.minfp;

min a sustitucion_valores_posfijo_X_Y(posfijo, varfp, min);

posfijo a makePosfijo(lfp↑.core1);

core1 a fp↑.core1;

core1 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, core1);

grmemb a CalculateGrMemb(3,min,core1,core2,max);

end_if

if (lfirst(lc) = A_Const) then //En a una constante que se le aplica el comparador begin

c a lfirst(lc); //Constante que se le aplica el comparador constante a c↑.valor;

posfijo a makePosfijo(lfp↑.minfp);

min a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

posfijo a makePosfijo(lfp↑.core1);

core1 a sustitucion_valores_posfijo_X_Y(posfijo, varfp, constante);

grmemb a CalculateGrMemb(3,min,core1,core2,max);

PostgreSQLf Página 96

end_if

end

case 4: //Comparadores por extensión grmemb a CalculateGrMemb_CompExt(varfp2,lfp); begin

end_switch

end_else

end_if

end_foreach

end_if

En el caso de los operadores relacionales físicos se extendieron cada uno de los programas que representa un nodo del plan, los cuales son: /src/backend/executor/nodeNestLoop.c, /src/backend/executor/nodeHashJoin.c y /src/backend/executor/nodeMergejoin.c. Aquí se calcula el grado tomando el cuenta el mínimo, ya que se esta implementando natural join sin eliminación de duplicados; también es importante acotar que se verifica si los nodos hijos ambos tienen predicados difusos o al menos uno de ellos para ir propagando hacia arriba en el árbol el cálculo del grado de membresía. Posteriormente se implementaron modificaciones en el archivo execQual.c ubicados en /src/backend/executor/ que es donde se encuentran las rutinas empleadas por PostgreSQL para evaluar los distintos tipos de datos recibidos por los qual tanto de la cláusula WHERE como del HAVING por lo que fue necesario implementar rutinas de soporte para el manejo de nodos difusos provenientes de la cláusula HAVING creándose la función ExecEvalFuzzyPred que recibe una expresión con una condición difusa y deriva la misma para poder ser procesada. Igualmente fue necesario modificar el archivo cabecera fuzzypred.h para incluir las funciones ValidateFuzzyPred y grmembFuzzyPred cuya implementación se incluyo en el archivo fuzzypred.c, para dar soporte en el manejo de nodos difusos y el cálculo de grados de membrecía dado que la primera función valida si existe un predicado difuso dentro de un nodo recibido y de ser así envía la información contenida en el mismo empleando una estructura de datos fcinfo que se introduce como parámetro de entrada en la función grmembFuzzyPred que se encarga de realizar el cálculo del grado de membrecía correspondiente tomando en cuenta el tipo de predicado difuso que se recibe en la consulta para luego aplicar los cálculos de acuerdo a las implementaciones de Cadenas (2008) como se puede apreciar en la Figura 42, donde se muestra el proceso de cálculo de grado de membrecía para un predicado difuso tipo 1.

PostgreSQLf Página 97

Figura 42 Cálculo de grado de membrecía para predicados difusos tipo La implementación de la función grmembFuzzyPred también implicó modificaciones en el archivo de cabecera fmgr.h (Figura 43) puesto que se debió extender el tipo de dato fcinfo utilizado por PostgreSQL para incluir las variables hasFuzzyPred para identificar la presencia de una condición difusa y typefp para indicar el tipo de condición difusa; esta extensión también fue implementada como parte de las rutinas de soporte de nodos difusos que se implementaron en el archivo execQual.c donde también se emplea la estructura de datos fcinfo como apoyo en el manejo de las condiciones difusas.

Figura 43 Modificación al archivo fmgr.h

Otra gran modificación tuvo lugar en el archivo nodeAgg.c el cual se encarga de recibir las tuplas que han sido procesadas por el execQual.c y provienen de una cláusula HAVING e identifica si las mismas presentan funciones agregadas. De existir funciones agregadas en la consulta se procesan los grupos de tuplas a los que aplique la función agregada y se realiza el cálculo necesario para devolver el resultado deseado; en este aspecto se debió extender las funciones de cálculo sobre grupos de tuplas para realizar dichos cálculos sobre tuplas difusas de manera de poder calcular el grado de membrecía respectivo y almacenarlo en los TargetEntry generados en el planner, lo cual se logro implementando rutinas que se apoyan en las funciones ValidateFuzzyPred y grmembFuzzyPred creadas anteriormente y que permitieron realizar los cálculos necesarios sobre los grupos de tuplas difusas. Operaciones Conjuntistas • Intersección Difusa: La intersección entre dos conjuntos A y B es otro

conjunto difuso C = A 9 B cuya función de pertenencia o grado de

bool hasFuzzyPred; /* identifies if a Fuzzy Predicate is present.

int typefp; /* identifies the Fuzzy predicate type.

case 1: if (fcinfo.arg[0] < fcinfo.arg[2]) return (fcinfo.arg[0] - fcinfo.arg[1]*1.0)/(fcinfo .arg[2] - fcinfo.arg[1]); if (fcinfo.arg[0] >= fcinfo.arg[2] && fcinfo.arg[0] <= fcinfo.arg[3]) return 1; else{ if (fcinfo.arg[0] >= fcinfo.arg[3] && fcinfo.arg[0 ] < fcinfo.arg[4]) return (fcinfo.arg[4]*1.0 - fcinfo.arg[0])/(fcinf o.arg[4] - fcinfo.arg[3]); else return 0; } break;

PostgreSQLf Página 98

membresía se calcula a partir de las funciones de pertenencia de A y B mediante una función T : [0, 1] c [0, 1] d[0, 1] que realiza la agregación de dos grados de pertenencia de la siguiente forma:

�=��� �A9B��� &1%��A���, �B���� : Teoría de Zadeh • Unión Difusa: La unión de dos conjuntos difusos A y B es otro conjunto

difuso C = A : B cuya función de pertenencia se calcula a partir de las funciones de pertenencia de A y B mediante una función S : [0, 1] c [0; 1] d [0, 1] que realiza la agregación de dos grados de pertenencia de la siguiente forma:

�=��� �A:B��� &"���A���, �B���� : Teoría de Zadeh

• Diferencia Difusa: La diferencia entre dos conjuntos A y B es otro conjunto

difuso C = A.B cuya función de pertenencia o grado de membresía se calcula a partir de las funciones de pertenencia de A y B mediante una función T : [0, 1] c [0, 1] d[0, 1] que realiza la agregación de dos grados de pertenencia de la siguiente forma:

�=��� �AeB��� &1%��A���, 1 . �B���� : Teoría de Zadeh

A continuación se muestra en la Tabla 2 la instancia relacional difusa tipo-1 A

Id Nombre � 1 Rodolfo Vegas 0.8 2 Aury Rodríguez 0.8

Tabla 2 Instancia relacional difuso tipo-1 A

Además se muestra en la Tabla 3 la instancia relacional difusa tipo-1 B

Id Nombre � 1 Rodolfo Vegas 0.28345 2 Aury Rodríguez 0.28345 3 Judith Gómez 0.5 4 Lilibeth Gómez 0.4 5 María de Gómez 0.8

Tabla 3 Instancia relacional difuso tipo-1 B

• Intersección de relaciones difusa tipo-1 La intersección de dos relaciones difusas tipo-1 se obtiene de la aplicación directa de las definición de la intersección de dos conjuntos difusos; es decir, la intersección de relaciones difusas tipo-1 n-arias, va a dar como resultado las tuplas que están en una y a la vez en la otra relación difusa tipo-1, y el grado de membresía resultante va a ser el mínimo entre los grados de membresías de las tuplas.

Por lo tanto al aplicar la intersección de las relaciones difusas tipo-1 A y B, A∩B entonces se produce la relación difusa tipo-1 mostrada en la Tabla 4.

PostgreSQLf Página 99

Id nombre � 1 Rodolfo Vegas min(0.8,0.28345)=0.28345 2 Aury Rodríguez min(0.8,0.28345)=0.28345

Tabla 4 Relación resultante al aplicar la operación INTERSECT entre las relaciones A y B

• Diferencia de relaciones difusa tipo-1 La diferencia de dos relaciones difusas tipo-1 se obtiene de la aplicación directa de las definición de la diferencia de dos conjuntos difusos; es decir, la diferencia de relaciones difusas tipo-1 n-arias, va a dar como resultado las tuplas que están en una y a la vez en la otra relación difusa tipo-1, y el grado de membresía resultante va a ser el mínimo entre los grados de membresías de cada una de las tuplas de la relación del lado izquierdo del except y el complemento de los grados de membresías de cada una de las tuplas de la relación del lado derecho del except. Ejemplo: 3 ' )/�fgh�ijkl mnompq 3 ' )/kijirsl Por lo tanto al aplicar la diferencia de las relaciones difusas tipo-1 A y B, A-B entonces se produce la relación difusa tipo-1 mostrada a continuación.

Id nombre � 1 Rodolfo Vegas min(0.8,1-0.28345)=0.71655 2 Aury Rodríguez min(0.8,1-0.28345)=0.71655

Tabla 5 Relación resultante al aplicar la operación EXCEPT entre relaciones A y B

• Unión de relaciones difusa tipo-1 La unión de dos relaciones difusas tipo-1 se obtiene de la aplicación directa de las definición de la unión de dos conjuntos difusos; es decir, la unión de relaciones difusas tipo-1 n-arias, va a dar como resultado las tuplas que están en una ó que están en la otra relación difusa tipo-1, y el grado de membresía resultante va a ser el máximo entre los grados de membresías de cada una de las tuplas que coincidan en las dos relaciones. Por lo tanto al aplicar la intersección de las relaciones difusas tipo-1 A y B, A:B entonces se produce la relación difusa tipo-1 mostrada en la Tabla 6.

Id nombre � 1 Rodolfo Vegas min(0.8,0.28345)=0.8 2 Aury Rodríguez min(0.8,0.28345)=0.8 3 Judith Gómez 0.5 4 Lilibeth Gómez 0.4 5 María de Gómez 0.8

Tabla 6 Relación resultante al aplicar la operación UNION entre relaciones A y B

PostgreSQLf Página 100

Para la implementación de estas operaciones en PostgreSQL, se modificó parte del código del archivo /src/backend/executor/nodeSetop.c, primero hay que proyectar por pantalla el atributo Gr. Memb. (Grado de Membresía), para lograr esto se extrae del plan SetOp (Operación INTERSECT/EXCEPT) en la función SetOpState *ExecInitSetOp() el último nodo TargetEntry del TargetList de dicho plan. Hay que acotar que la estructura de datos TargetEntry representa cada uno de los atributos que se mostrarán por pantalla de la tabla resultante, siempre y cuando un atributo lógico que posee este llamado resjunk es igual a false. El último nodo del TargetList representa el atributo Grado de Membresía, pero el atributo resjunk que posee este esta inicializado en true, por lo cual se cambia este valor a false y así se proyectará por pantalla el atributo Gr.Memb. gdm : Pointer to TargetEntry;

gdm a list_nth(setopstate↑.ps.plan↑.targetlist, list_length(setopstate↑.ps.plan↑.targetlist)-

1); //Extracción del último nodo Targetentry del targetList del Plan SetOp

if (gdm↑.resname = "Gr.Memb.") then

begin

setopstate↑.ps↑.plan↑.targetlist a list_truncate(setopstate↑.ps.plan↑.targetlist,

list_length(setopstate↑.ps.plan↑.targetlist)-1); //Eliminación del último nodo Targetentry del

targetlist

setopstate↑.ps.plan↑.hfp a true;

gdm↑.resjunk a false; //Proyectar el atributo Gr.Memb.

setopstate↑.ps.plan↑.targetlist = lappend(setopstate↑.ps.plan↑.targetlist, gdm);

//Inserción del gdm en el targetlist del plan SetOp

end_if

La función TupleTableSlot * ExecSetOp en el archivo /src/backend/executor/nodeSetop.c es donde se ejecuta las operaciones INTERSECT/EXCEPT, por lo cual es en la rutina ExecSetOp donde se implementarán las operaciones INTERSECT/EXCEPT difusas y realizar los calculo del grado de membresía correspondiente a cada una de estas operaciones. En ExecSetOp tiene dos estructuras de tipo TupleTableSlot llamados inputTupleSlot y resultTupleSlot. El inputTupleSlot es donde esta contenida todas las tuplas que satisfacen cada uno de los Select’s involucrados en las operaciones conjuntistas antes mencionadas. En cambio, el resultTupleSlot contendrá las tuplas que satisfacen las operaciones conjuntistas que se esta ejecutando. Primero se verifica si el plan SetOp es difuso a través de la variable hfp, si esta resulta verdadera se determina que operación conjuntista es la que se esta ejecutando a través de la variable cmd. En el caso del INTERSECT difuso, para el cálculo del grado de membresía se implementó el siguiente algoritmo:

isNull : bool;

left, right : float;

left a

DatumGetFloat4(slot_getattr(inputTupleSlot,inputTupleSlot↑.tts_tupleDescriptor↑.natts,&isN

ull)); //�A��� Grado de Membresía de la relación difusa A

PostgreSQLf Página 101

right a

DatumGetFloat4(slot_getattr(resultTupleSlot,resultTupleSlot↑.tts_tupleDescriptor↑.natts,&is

Null)); //�B��� Grado de Membresía de la relación difusa B

if (plannode↑.cmd = SETOPCMD_INTERSECT) then //INTERSECT

begin

if (left<right) then // &1%��A���, �B����

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1]

a Float4GetDatum(left);

else

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1]

a Float4GetDatum(right);

end_if

Para el caso del EXCEPT difuso hay que tener varias consideraciones, la primera de ella es determinar que tuplas pertenecen a la relación difusa A y que tuplas pertenecen a la relación difusa B, para así calcular el complemento de los grados de membresías de las tuplas de la relación difusa B y determinar el menor del complemento y los grados de membresía de la relación difusa A. En la función ExecSetOp existe una variable llamada node que pertenece a un tipo de datos llamado SetOpState, esta estructura de dato posee dos atributos que se llaman numLeft y numRight, si numLeft > numRight significa que inputTupleSlot contiene las tuplas de la relación difusa B; por el contrario si numLeft <= numRight significa que resultTupleSlot contiene las tuplas de la relación difusa B. Por otra parte, el complemento de los grados de membresías de la relación difusa B puede dar 0, si se cumple este caso no se debe proyectar las tuplas que cumple esta condición, solo con inicializar la variable endOfGroup en false no se proyecta este conjunto de tuplas cuyo grado de membresía es 0. Otra consideración que hay que tomar en cuenta es que el EXCEPT difuso se maneja como un INTERSECT difuso, la única diferencia es el cálculo del grado de membresía, para esto el código de cuantas tuplas el INTERSECT utiliza para emitir por pantalla (ExecSetOp, línea 190-193) será el mismo cuando se ejecuta un EXCEPT difuso. Para la implementación del EXCEPT difuso se implemento el siguiente algoritmo:

if (plannode↑.cmd = SETOPCMD_EXCEPT) then

begin

if (node↑.numLeft > node↑.numRight) then

if (right<1.0-left) then // &1%��A���, 1 . �B����

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1] a

Float4GetDatum(right);

else

begin

if (1.0-left = 0.0) then //1 . �B��� 0

endOfGroup a true;

else

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1] a

Float4GetDatum(1.0-left);

PostgreSQLf Página 102

end_else

else

if (left<1.0-right) then // &1%��A���, 1 . �B����

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1] a

Float4GetDatum(left);

else

begin

if (1.0-right = 0.0) then //1 . �B��� 0

endOfGroup a true;

else

resultTupleSlot↑.tts_values[resultTupleSlot↑.tts_tupleDescriptor↑.natts-1] a

Float4GetDatum(1.0-right);

end_else

end_if

Para determinar cuantos tuplas el EXCEPT difuso emitirá por pantalla, se implementó el siguiente algoritmo:

case SETOPCMD_EXCEPT:

if (node↑.ps.plan↑.hfp) then //ESCEPT difuso

begin

if (node↑.numLeft > 0 and node↑.numRight > 0) then

node↑.numOutput a 1;

else

node↑.numOutput a 0;

end_if

else //EXCEPT booleando

begin

if (node↑.numLeft > 0 and node↑.numRight== 0) then

node↑.numOutput a 1;

else

node↑.numOutput a 0;

end_else

end

La implementación de la UNION formo parte del Trabajo Especial de Grado del Bachiller Armando Bracho (Bracho, 2009) y su explicación se muestra a continuación. La modificación para la ejecución de la UNION difusa se realizo sobre el archivo nodeUnique.c que es el encargado de realizar el proceso de UNION en una consulta y fue aquí donde se implementaron rutinas que permitieran recibir consultas con condiciones difusas, gracias al apoyo de las rutinas creadas por Cadenas (2008); y se extendió la funcionalidad de la UNION para permitir la comparación y cálculo de los grados de membrecía ya que al unir dos relaciones con condiciones difusas si existen tuplas iguales con distintos grados de membrecía la UNION debe mostrar siempre el grado de membrecía mayor. La extensión de la UNION difusa también requirió la definición de varios tipos de estructuras en el archivo fuzzypred.h a fin de poder realizar la comparación requerida de los grados de membrecía de manera rápida y satisfactoria; también se modifico el archivo utilitario equalfuncs.c ubicado en /src/backend/nodes/

PostgreSQLf Página 103

donde se definió la función _equalFuzzyPred cuya función es comparar 2 predicados difusas para identificar si son iguales, esta función se implemento como complemento para el uso de consultas empleando el explain analyze de manera de estudiar los resultados de la consulta difusas extendidas aquí de manera más precisa.

PostgreSQLf Página 104

PRUEBAS DE LA EXTENSION POSTGRESQLf Las pruebas que se llevaron a cabo para verificar el funcionamiento correcto y confiable de la extensión de PostgreSQLf fueron: (1) Pruebas de Funcionalidad y (2) Pruebas de Escalabilidad. El objetivo de las Pruebas de funcionalidad en la extensión de PostgreSQLf es garantizar el cumplimiento de los requisitos funcionales, tales como: la creación y reconocimiento por parte de PostgreSQLf de los comparadores difusos, procesamiento y obtención de resultados generando consultas SQL que involucren operaciones conjuntistas difusas, consultas difusas en el from y comparadores difusos. Por otra parte las pruebas de escalabilidad se utilizaron para demostrar la capacidad de la extensión PostgreSQLf cuando la carga de datos se incrementa o decrementa.

Pruebas de Funcionalidad

Para llevar a cabo dichas pruebas se utilizó la base de datos del Laboratorio de Marcha de Hospital Ortopédico Infantil situada en Caracas – Venezuela, cuyo modelo relacional se muestra en la figura 44:

Figura 44 Modelo Relacional de la Base de Datos lab_marcha

PostgreSQLf Página 105

Para realizar dichas pruebas se definieron los siguientes predicados, modificadores y cuantificadores difusos.

• Predicados Difusos. lab_marcha=# create fuzzy predicate gordo on 1 .. 200 as (60,80,infinite,infinite); CREATE FUZZY PREDICATE lab_marcha=# create fuzzy predicate flaco on 1 .. 200 as (infinite,infinite,10,50); CREATE FUZZY PREDICATE lab_marcha=# create fuzzy predicate atonia ON 0 .. 5 as (infinite, infinite, 1, 4); CREATE FUZZY PREDICATE lab_marcha=# create fuzzy predicate hipertonia ON 0 .. 5 as (1, 4, infinite, infinite); CREATE FUZZY PREDICATE lab_marcha=# Create fuzzy predicate joven on 0 .. 120 as (infinite, infinite, 20, 30); CREATE FUZZY PREDICATE lab_marcha=# Create fuzzy predicate viejo on 0 .. 120 as (20, 27, infinite, infinite); CREATE FUZZY PREDICATE lab_marcha=# Create fuzzy predicate maduro on 0 .. 120 as (18, 20, 24, 30); CREATE FUZZY PREDICATE

• Modificador Difuso.

lab_marcha=# create modifier muy as power 2; CREATE FUZZY MODIFIER

• Cuantificadores Difusos. lab_marcha=# CREATE ABSOLUTE QUANTIFIER al_menos3 AS (1.0, 3.0, infinite, infinite); CREATE FUZZY QUANTIFIER

Para verificar las reglas de negocio y la apropiada aceptación de los datos por parte de la extensión de PostgreSQLf, se tiene que verificar los siguientes aspectos:

1. Creación de comparadores difusos. 2. Reconocimiento y ejecución de consultas difusas en el from que pueden

tener comparadores, predicados, modificadores, cuantificadores difusos y group by con having difuso.

3. Reconocimiento y ejecución de consultas de operaciones conjuntistas difusas (UNION/INTERSECT/EXCEPT), combinando consultas que contenga comparadores difusos, predicados difusos, comparadores difusos, cuantificadores difusos, modificadores difusos, group by con having difuso y consultas en el from.

PostgreSQLf Página 106

1. Creación de Comparadores Difusos.

Se invoca la sentencia CREATE COMPARATOR para poder crear los distintos comparadores definidos para la extensión PostgreSQLf. En la Figura 45 se muestra la creación de comparadores difusos.

Figura 45 Creación de Comparadores Difusos

Después de la creación de los comparadores difusos, se comprueba que han sido almacenados en el Catalogo del Sistemas haciendo consultas sobre la tabla pg_fuzzycomp. En la Figura 46 se visualiza la tabla pg_fuzzycomp donde se almacena los comparadores difusos con cada uno de sus atributos.

Figura 46 Tabla pg_fuzzycomp

2. Reconocimiento y ejecución de consultas difusas en el from que

pueden tener comparadores, predicados, modificadores, cuantificadores difusos y group by con having difuso. En las siguientes figuras se muestra consultas SQL hechas sobre la extensión de PostgreSQLf que tienen presentes subconsultas difusas en el from con condiciones que involucran modificadores, comparadores, predicado, cuantificadores difusos además de group by con having difuso respectivamente.

PostgreSQLf Página 107

Figura 47 Consulta #1 con condición difusa que presenta el cuantificador difuso al_menos3

PostgreSQLf Página 108

Figura 48 Consulta #2 con having difuso

Figura 49 Consulta #3 con cuantificador al_menos3 y modificador difuso muy

PostgreSQLf Página 109

Figura 50 Consulta #4 con cuantificador al_menos3 y comparador difuso >>

3. Reconocimiento y ejecución de consultas de operaciones conjuntistas difusas (UNION/INTERSECT/EXCEPT), combinando consultas que contenga comparadores difusos, predicados difusos, comparadores difusos, cuantificadores difusos, modificadores difusos, group by con having difuso y consultas en el from. Las siguientes figuras muestran una serie de consultas SQL con las tablas resultantes que involucran operaciones conjuntistas difusas con los elementos mencionados anteriormente.

Figura 51 Consulta #1 aplicando UNION difusa con predicados difusos atonía e

hipertonía

PostgreSQLf Página 110

Figura 52 Consulta #2 aplicando INTERSECT con predicados difusos joven, viejo y

cuantificador al_menos3

Figura 53 Consulta #3 aplicando EXCEPT junto al predicado difuso maduro y group by

con having difusos

PostgreSQLf Página 111

Figura 54 Consulta #4 aplicando UNION con predicados difusos tales como joven,

maduro y modificador difuso muy

PostgreSQLf Página 112

Figura 55 Consulta #5 aplicando INTERSECT con condiciones difusas que implican

predicados difusos como joven, viejo y maduro

PostgreSQLf Página 113

Figura 56 Consulta #6 aplicando EXCEPT junto a los predicados difusos maduro y

joven

PostgreSQLf Página 114

Figura 57 Consulta #7 aplicando UNION con predicados difusos joven y viejo

PostgreSQLf Página 115

Figura 58 Consulta #8 aplicando INTERSECT/EXCEPT/UNION con predicados

difusos tales como: joven, viejo y maduro

PostgreSQLf Página 116

Figura 59 Consulta #9 aplicando INTERSECT junto con consultas difusas en el from y

predicados difusos tales como: joven, viejo y maduro

PostgreSQLf Página 117

Figura 60 Consulta #10 aplicando EXCEPT con consultas difusas en el from cuyas

condiciones presentan predicados difusos como: joven y maduro

PostgreSQLf Página 118

Figura 61 Consulta #11 aplicando UNION con consultas difusas en el from y

predicados difusos como: joven, viejo y maduro

PostgreSQLf Página 119

Figura 62 Consulta #12 aplicando INTERSECT/EXCEPT/UNION con consultas

difusas en el from y predicados difusos tales como: joven, viejo y maduro

PostgreSQLf Página 120

Figura 63 Consulta #13 aplicando INTERSECT con comparadores difusos tales como:

<<, >> y ~

PostgreSQLf Página 121

Figura 64 Consulta #14 aplicando EXCEPT junto a los comparadores difusos >> y <<

Figura 65 Consulta #15 aplicando UNION junto con los comparadores difusos << y >>

PostgreSQLf Página 122

Figura 66 Consulta #16 aplicando INTERSECT/EXCEPT/UNION junto a los

comparadores difusos <<, ~ y << y predicados difusos viejo

PostgreSQLf Página 123

Figura 67 Consulta #17 aplicando INTERSECT junto al comparador difuso ~ y los

predicados difusos joven, maduro y viejo

PostgreSQLf Página 124

Figura 68 Consulta #18 aplicando UNION/EXCEPT/INTERSECT junto a los

comparadores difusos << y >> además de los predicados difusos joven, viejo y maduro

Figura 69 Consulta #19 aplicando INTERSECT junto al predicado difuso hipertonía con

el conector not

PostgreSQLf Página 125

Figura 70 Consulta #20 aplicando EXCEPT junto a los predicados difusos atonía e

hipertonía

Figura 71 Consulta #21 aplicando UNION junto a los comparadores difusos << y >>

PostgreSQLf Página 126

Figura 72 Consulta #22 aplicando INTERSECT/EXCEPT/UNION presentando

condiciones con los comparadores difusos: <<, >> y ~

PostgreSQLf Página 127

Figura 73 Consulta #23 aplicando INTERSECT/EXCEPT/UNION con condiciones

difusas en el from, además de los comparadores difusos: <<, >> y ~; predicados difusos tales como: hipertonía y atonía y el conector not

A partir de cada una de las pruebas mostradas anteriormente se ha probado la funcionalidad de la extensión PostgreSQLf ya que se cumplieron con cada uno de los requerimientos funcionales que eran: operaciones conjuntistas difusas, consultas difusas en el from y la utilización de comparadores difusos. Cabe destacar que algunas de las tablas mostradas en las figuras descritas anteriormente no se presentan de forma completa ya que genera muchos registros, por esa razón se decidió mostrar una parte de dichas tablas

PostgreSQLf Página 128

Pruebas de Escalabilidad

Estas pruebas determinaran el rendimiento de la extensión de PostgreSQLf cuando la carga de los datos aumenta o disminuye y verificar si influye en el tiempo de respuesta. Estas pruebas se realizaron sobre la base de datos Benchmark TPCTM (TPC-H). Esta base de datos es una referencia de soporte de decisiones, se compone de una suite of bussines orientada a las consultas ad-hoc y modificaciones de datos simultáneamente. La utilización de esta base de datos se debe a los siguientes puntos:

• Examina grandes volúmenes de datos. • Ejecución de consultas con un alto grado de complejidad. • Da respuestas a interrogantes críticas del negocio.

El esquema de la base de datos TPC-H se muestra en la Figura 74. G

Figura 74 Esquema del TPC-H

Otra de las razones de utilizar el TPC-H es porque se pueden generar base de datos de distintos tamaños y así determinar el comportamiento de la extensión PostgreSQLf con diferentes tamaños de cargas de datos y

PostgreSQLf Página 129

verificando así si el volumen de datos era significativo estadísticamente en el tiempo de consulta. El valor dependiente que tomaremos en cuenta para realizar las pruebas de escalabilidad es el tiempo de procesamiento expresado en milisegundos, resultante de cada una de las consultas generadas para estas pruebas y que se describirán en la Tabla 7. Los factores o grupos de datos (independientes) utilizados para realizar dichas pruebas son los siguientes:

• Volumen de datos clasificados en: o Bajos. Base de datos TPC-H de tamaño 1GB. o Altos. Base de datos TPC-H de tamaño 5GB.

• Tipo de Consulta: o Consulta Clásica o booleana. o Consulta Imprecisa o difusa.

Se tienen un total de 14 consultas para cada uno de los tipos mencionados anteriormente con las operaciones difusas implementadas para esta extensión. Cabe destacar que las consultas clásicas son el equivalente de las consultas difusas, solo transformando la lógica de la misma.

Para realizar las pruebas de escalabilidad se crearon los siguientes predicados, comparadores y cuantificadores difusos: --/Predicados CREATE FUZZY PREDICATE cheap ON 0 .. 10000 AS (infinite, infinite, 100, 200); CREATE FUZZY PREDICATE affordable ON 0 .. 10000 AS (500, 700, 900, 1000); CREATE FUZZY PREDICATE expensive ON 0 .. 10000 AS (1000, 1500, infinite, infinite); CREATE FUZZY PREDICATE small ON 0 .. 100 AS (infinite, infinite, 10, 15); CREATE FUZZY PREDICATE big ON 0 .. 100 AS (40, 100, infinite, infinite); CREATE FUZZY PREDICATE HIGHAVAIL ON 0 .. 10000 AS (2000, 4000, infinite, infinite); CREATE FUZZY PREDICATE LOWAVAIL ON 0 .. 10000 AS (infinite, infinite, 1000, 1500); --/Cuantificadores CREATE RELATIVE QUANTIFIER most_of AS (0.5, 0.75, 1.0, 1.0); CREATE RELATIVE QUANTIFIER few AS (0.0, 0.0, 0.25, 0.5); CREATE ABSOLUTE QUANTIFIER at_least3 AS (1.0, 3.0, infinite, infinite); CREATE ABSOLUTE QUANTIFIER at_most2 AS (infinite, infinite, 2.0, 3.0); CREATE RELATIVE QUANTIFIER aprox_half AS (0.25, 0.5, 0.5, 0.75); --/Comparadores CREATE COMPARATOR '~' ON 1 .. 100 AS ('y-5','y','y','y+5'); CREATE COMPARATOR '<<' ON 1 .. 100 AS ('INFINITE','INFINITE','y/3','y'); CREATE COMPARATOR '>>' ON 1 .. 100 AS ('y','y*3','INFINITE','INFINITE'); CREATE COMPARATOR 'cerca' on 'nation' as ('(ALGERIA,ETHIOPIA)/0.1','(ALGERIA,KENYA)/0.2','(ALGERIA,MOROCCO)/0.3','(ALGERIA,MOZAMBIQUE)/0.4','(ARGENTINA,BRAZIL)/0.9','(ARGENTINA,CANADA)/0.1','(ARGENTINA,PERU)/0.5','(FRANCE,GERMANY)/0.7','(FRANCE,ROMANIA)/0.5','(FRANCE,RUSSIA)/0.1'); --Modificadores CREATE MODIFIER muy AS POWER 2;

En la Tabla 7 se muestra las consultas clásicas y difusas generadas con sus respectivos tiempos de procesamientos para altos y bajos volúmenes de datos.

PostgreSQLf Página 130

Tipo de

Consulta QUERY

Tiempo de Procesamiento

V. Bajo V. alto

Fuzzy

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '<<' LOWAVAIL

INTERSECT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost '~' affordable;

51806.878 312555.03

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost '<<' cheap

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty=LOWAVAIL AND

ps_supplycost=cheap AND p_size=small;

12051.221 134406.008

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '<<' LOWAVAIL AND

ps_supplycost=cheap AND p_size=small

UNION

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '~' affordable AND p_size '>>' big;

3753.707 55348.565

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '<<' LOWAVAIL AND

ps_supplycost=cheap AND p_size=small

UNION

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '~' affordable AND p_size '>>' big

INTERSECT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost '~' affordable

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

43229.067 296780.135

PostgreSQLf Página 131

ps_suppkey=s_suppkey)

AND ps_availqty=LOWAVAIL AND

ps_supplycost=cheap AND p_size=small;

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND most_of(ps_availqty=LOWAVAIL, ps_supplycost=

cheap)

) as FOO;

2114.434 35827.331

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty=LOWAVAIL AND

ps_supplycost=cheap AND p_size=small

) as FOO;

1387.986 17794.705

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty 'muy' LOWAVAIL

) as FOO;

4583.598 46496.797

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND (ps_availqty '<<' LOWAVAIL OR ps_supplycost '~'

affordable OR p_retailprice '>>' expensive)

) as FOO;

12389.558 180652.007

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND at_least3(ps_availqty=LOWAVAIL)

INTERSECT

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND p_size=small AND p_retailprice=expensive

) AS FOO;

25184.416 256377.222

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND at_least3(ps_availqty=LOWAVAIL)

) AS FOO

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty=LOWAVAIL AND

ps_supplycost=cheap AND p_size=small;

6752.073 118769.328

PostgreSQLf Página 132

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND at_most2(ps_availqty=LOWAVAIL,

ps_supplycost=cheap)

) AS FOO

UNION

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '<<' LOWAVAIL AND ps_supplycost

'>>' 1200 AND p_size=big

) AS FOO;

2858.955 61094.788

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND at_least3(ps_availqty=LOWAVAIL)

INTERSECT

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND p_size=small AND p_retailprice=expensive

) AS FOO

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty=LOWAVAIL AND

ps_supplycost=cheap AND p_size=small

UNION

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty '<<' LOWAVAIL AND ps_supplycost

'>>' 1200 AND p_size=big

) AS FOO;

26332.133 505637.799

explain analyze select n_name, n_comment from

(SELECT * FROM nation) AS FOO WHERE n_name

'cerca' 'FRANCE';

0.145 14.732

explain analyze select n_name, n_comment from

(SELECT * FROM nation where n_name 'cerca'

'GERMANY') AS FOO WHERE n_name 'cerca'

'ROMANIA' intersect select n_name, n_comment from

nation;

1.204 20.535

Clasica

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500

INTERSECT

SELECT p_name, s_name

50225.592 292108.485

PostgreSQLf Página 133

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost > 495 AND ps_supplycost < 1005;

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost < 200

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15;

10353.672 117166.283

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15

UNION

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty > 495 AND ps_availqty < 1005 AND

p_size > 40;

3541.553 58155.133

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15

UNION

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty > 495 AND ps_availqty < 1005 AND

p_size > 40

INTERSECT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_supplycost > 495 AND ps_supplycost < 1005

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15;

39510.113 284496.837

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ((ps_availqty < 1500) AND (ps_supplycost < 200))

2042.743 30872.804

PostgreSQLf Página 134

) as FOO;

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15

) as FOO;

1125.745 24928.559

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500

) as FOO;

3201.055 43979.019

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND (ps_availqty < 1500 OR (ps_supplycost > 495 AND

ps_supplycost < 1005) OR p_retailprice > 1000)

) as FOO;

15601.499 180543.901

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500

INTERSECT

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND p_size < 15 AND p_retailprice > 1000

) AS FOO;

23785.724 249366.365

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500

) AS FOO

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15;

3422.995 101096.376

explain analyze SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ((ps_availqty < 1500) AND (ps_supplycost < 200))

) AS FOO

UNION

SELECT p_name, s_name FROM (

SELECT *

2943.224 60033.469

PostgreSQLf Página 135

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost > 1200

AND p_size > 40

) AS FOO;

explain analyze SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500

INTERSECT

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND p_size < 15 AND p_retailprice > 1000

) AS FOO

EXCEPT

SELECT p_name, s_name

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost < 200 AND

p_size < 15

UNION

SELECT p_name, s_name FROM (

SELECT *

FROM part, partsupp, supplier

WHERE (p_partkey=ps_partkey AND

ps_suppkey=s_suppkey)

AND ps_availqty < 1500 AND ps_supplycost > 1200

AND p_size > 40

) AS FOO;

25028.805 451005.291

explain analyze select n_name, n_comment from

(SELECT * FROM nation) AS FOO WHERE n_name =

'GERMANY' OR n_name = 'ROMANIA' OR n_name =

'RUSSIA';

0.18 0.204

explain analyze select n_name, n_comment from

(SELECT * FROM nation where n_name = 'FRANCE') AS

FOO WHERE n_name = 'FRANCE' intersect select

n_name, n_comment from nation;

1.206 1.124

Tabla 7 Consultas clásicas y difusas con sus respectivos tiempos de procesamientos expresados en milisegundos para altos y bajos volúmenes de datos

Análisis Exploratorio de los Datos En primer lugar se va a hacer un análisis exploratorio de los datos mediante estadística descriptiva utilizando la herramienta SPSS. Para ello se realizó un histograma sobre la variable numérica tiempo de acuerdo al volumen de datos (ALTO/BAJO). El histograma generado por la herramienta SPSS para el factor tiempo a partir de un volumen de datos BAJO se muestra en la figura 75.

PostgreSQLf Página 136

Figura 75 Histograma sobre la variable numérica Tiempo

para volúmen de datos bajo Se observa que, de acuerdo al conjunto de datos, se presenta una frecuencia mayoritaria en el intervalo (entre 0 y 60000 milisegundos). La distribución de los datos se asemeja a una función log-normal. Como medida de localización o tendencia tenemos la media, en este caso es de 13329.624321 milisegundos. También existe una alta variabilidad de los datos al mostrar una desviación típica de 16072.0615681 milisegundos. En la tabla 8 se resumen otros estadísticos descriptivos utilizados donde se muestra una gran diferencia entre la media y la mediana; en este caso la mediana es de (4168.6525 milisegundos). También se observa que la moda (valor más frecuente) es 0.1450 segundos, aunque en la tabla se indica que hay más de una moda por la forma del histograma, este valor representa bien a la moda.

BAJO

60.000,000050.000,0000

40.000,000030.000,0000

20.000,000010.000,0000

0,0000

Fre

cuen

cia

20

15

10

5

0

Media =13.329,624321�Desviación típica =16.

072,0615681�N =28

PostgreSQLf Página 137

N Válidos 28 Perdidos 28

Media 13329,624321

Mediana 4168,652500

Moda ,1450(a) Desv. típ. 16072,061

5681 Varianza 25831116

3,048 Mínimo ,1450 Máximo 51806,878

0 Suma 373229,48

10 Percentiles 25 2060,6657

50 50 4168,6525

00 75 24718,034

750 a Existen varias modas. Se mostrará el menor de los valores.

Tabla 8 Estadísticos descriptivos para volúmen de datos bajo En cuanto a la dispersión, dado lo ya acotado de la desviación típica, también se tiene que la diferencia entre el valor mínimo y el máximo es alta (0.1450 y 51806.878 milisegundos), además debido a que los dos primeros cuartiles están relativamente cerca (2060.6657 y 4168.6525 milisegundos) significa que un 25% de la muestra tiene tiempos de respuesta muy parecidos, por lo que existe una concentración en ese intervalo. Esto se puede observar gráficamente en el diagrama de caja presentado en la figura 76.

PostgreSQLf Página 138

Figura 76 Diagrama de Caja, Volumen Bajo

Se observa la mayor concentración de tiempos de respuesta de consultas entre 0.1450 y 4168.6525 milisegundos, donde se ubican el 50% de las consultas, más aún hasta 24718.034750 milisegundos está el 75% de las mismas. Se puede concluir que los tiempos comprendidos entre el 50% y 75% de las consultas procesadas están más dispersas que el 25% y 50%. Ahora, si utilizamos como variable de agrupación el tipo de consulta (BOOLEAN/FUZZY), se despeja un poco mejor el panorama, tal como se visualiza en la Figura 77. Se observa que los mayores tiempos de respuesta se presentan con el tipo de consulta difusa pero por una diferencia minima, además son los que influyen en la variabilidad. Sólo con este análisis podemos concluir que son muy parecidos los tipos de consulta difusa y booleana en cuanto a performance.

BA

JO60.000,0000

50.000,0000

40.000,0000

30.000,0000

20.000,0000

10.000,0000

0,0000

PostgreSQLf Página 139

Figura 77 Diagrama de Caja agrupado por Tipo de Consulta, Volúmen Bajo

Para reafirmar lo anterior obtuvimos el resumen de las medias agrupadas por tipo de consulta que puede observarse en la tabla 9.

N Mínimo Máximo Media Desv. típ. Varianza BOOLEAN 14 ,1800 50225,592

0 12913,150

429 16030,218

3903 25696790

1,640 FUZZY 14 ,1450 51806,878

0 13746,098

214 16707,810

3958 27915092

8,222 N válido (según lista) 14

Tabla 9 Medias por tipo de Consulta (tiempo en milisegundos), Volúmen Bajo

Aquí se observa que para el caso de consultas difusas con un volumen de datos bajo la media y la desviación típica son mayores en comparación a las consultas clásicas o booleanas, pero ahí que mencionar que las diferencias no son significativa entre sí ya que el intervalo entre ellas es bajo. A continuación se mostrara el histograma generado por la herramienta SPSS para el factor tiempo a partir de un volumen de datos ALTO en la figura 79.

CONSULTABOOLEANFUZZY

TIE

MP

O60.000,0000

50.000,0000

40.000,0000

30.000,0000

20.000,0000

10.000,0000

0,0000

PostgreSQLf Página 140

Figura 78 Histograma sobre la variable numérica Tiempo

para volúmen de datos alto Se observa que, de acuerdo al conjunto de datos, se presenta una frecuencia mayoritaria en el intervalo (entre 0 y 600000 milisegundos). La distribución de los datos se asemeja a una función log-normal. Como medida de localización o tendencia tenemos la media, en este caso es de 139840.315429 milisegundos. También existe una alta variabilidad de los datos al mostrar una desviación típica de 140617.4387108 milisegundos. En la tabla 10 se resumen otros estadísticos descriptivos utilizados donde se muestra una gran diferencia entre la media y la mediana; en este caso la mediana es de (81095.582 milisegundos). También se observa que la moda (valor más frecuente) es 0.2040 segundos, aunque en la tabla se indica que hay más de una moda por la forma del histograma, este valor representa bien a la moda.

ALTO

600.000,0000500.000,0000

400.000,0000300.000,0000

200.000,0000100.000,0000

0,0000

Fre

cuen

cia

12,5

10,0

7,5

5,0

2,5

0,0

Media =139.840,315429�Desviación típica =140.

617,4387108�N =28

PostgreSQLf Página 141

N Válidos 28

Perdidos 28 Media 139840,31

5429 Mediana 81095,582

000 Moda ,2040(a) Desv. típ. 140617,43

87109 Varianza 19773264

069,594 Mínimo ,2040 Máximo 505637,79

90 Percentiles 25 32111,435

750 50 81095,582

000 75 254624,50

7750 a Existen varias modas. Se mostrará el menor de los valores.

Tabla 10 Estadísticos descriptivos para volúmen de datos alto En cuanto a la dispersión, dado lo ya acotado de la desviación típica, también se tiene que la diferencia entre el valor mínimo y el máximo es alta (0.2040 y 505637.7990 milisegundos), además debido a que los dos primeros cuartiles están cerca relativamente (32111.435 y 81095.582 milisegundos) significa que un 25% de la muestra tiene tiempos de respuesta muy parecidos, por lo que existe una concentración en ese intervalo. Esto se puede observar gráficamente en el diagrama de caja presentado en la figura 80.

PostgreSQLf Página 142

Figura 79 Diagrama de Caja, Volúmen Alto

Se observa la mayor concentración de tiempos de respuesta de consultas entre 0.2040 y 81095.582 milisegundos, donde se ubican el 50% de las consultas, más aún hasta 254624.50775 milisegundos está el 75% de las mismas. Se puede concluir que los tiempos comprendidos entre el 50% y 75% de las consultas procesadas están más dispersas que el 25% y 50%. Ahora, si utilizamos como variable de agrupación el tipo de consulta (BOOLEAN/FUZZY), se despeja un poco mejor el panorama, tal como se visualiza en la Figura 81. Se observa que los mayores tiempos de respuesta se presentan con el tipo de consulta difusa pero por una diferencia minima, además son los que influyen en la variabilidad. Sólo con este análisis podemos concluir que son muy parecidos los tipos de consulta difusa y booleana en cuanto a performance.

AL

TO

600.000,0000

500.000,0000

400.000,0000

300.000,0000

200.000,0000

100.000,0000

0,0000

PostgreSQLf Página 143

Figura 80 Diagrama de Caja agrupado por Tipo de Consulta, Volúmen Alto

Para reafirmar lo anterior obtuvimos el resumen de las medias agrupadas por tipo de consulta que puede observarse en la tabla 11.

N Mínimo Máximo Media Desv. típ. Varianza BOOLEAN 14 14,7320 505637,79

90 144412,49

8714 149502,48

17552 22350992

050,953 FUZZY 14 ,2040 451005,29

10 135268,13

2143 136643,80

90401 18671530

548,977 N válido (según lista) 14

Tabla 11 Medias por tipo de Consulta (tiempo en milisegundos), Volúmen Alto

Aquí se observa que para el caso de consultas difusas con un volumen de datos alto la media y la desviación típica son mayores en comparación a las consultas clásicas o booleanas, pero ahí que mencionar que las diferencias no son significativa entre sí ya que el intervalo entre ellas es bajo. Test de Hipótesis Como prueba inicial vamos a comprobar a través de un test de Kolmogorov-Smirnov que la muestra no sigue una distribución normal. Para este caso tenemos que,

CONSULTABOOLEANFUZZY

TIE

MP

O600.000,0000

500.000,0000

400.000,0000

300.000,0000

200.000,0000

100.000,0000

0,0000

PostgreSQLf Página 144

H0: La muestra proviene de una distribución Normal. H1: La muestra no proviene de una distribución Normal. Aplicando el test, nos da como resultado la tabla 12.

TIEMPO (mseg)

N 56

Parámetros normales(a,b)

Media 76584,969875

Desviación típica 117930,7886997

Diferencias más extremas Absoluta ,302 Positiva ,302 Negativa -,258

Z de Kolmogorov-Smirnov 2,262 Sig. asintót. (bilateral) ,000

a La distribución de contraste es la Normal. b Se han calculado a partir de los datos.

Tabla 12 Prueba de Kolmogorov-Smirnov para una muestra Dado que la significancia es muy baja, rechazamos la hipótesis nula y aceptamos la alternativa, es decir que la muestra no proviene de una distribución normal. Para realizar dichas pruebas, se tiene que utilizar métodos estadísticos no paramétricos, ésta es una rama de la estadística que estudia las pruebas y modelos estadísticos cuya distribución subyacente no se ajusta a los llamados criterios paramétricos. Su distribución no puede ser definida a priori, pues son los datos observados los que la determinan. La utilización de estos métodos se hace recomendable cuando no se puede asumir que los datos se ajusten a una distribución conocida, cuando el nivel de medida empleado no sea, como mínimo, de intervalo (Canavos, 1994). Las principales pruebas no paramétricas son las siguientes: * Prueba χ² de Pearson * Prueba binomial * Prueba de Anderson-Darling * Prueba de Cochran * Prueba de Cohen kappa * Prueba de Fisher * Prueba de Friedman * Prueba de Kendall * Prueba de Kolmogórov-Smirnov * Prueba de Kruskal-Wallis * Prueba de Kuiper * Prueba de Mann-Whitney o prueba de Wilcoxon * Prueba de McNemar

PostgreSQLf Página 145

* Prueba de la mediana * Prueba de Siegel-Tukey * Coeficiente de correlación de Spearman * Tablas de contingencia * Prueba de Wald-Wolfowitz * Prueba de los signos de Wilcoxon Se utilizó la prueba no paramétrica de Friedman ya que esta K muestras relacionadas entre sí, que es la característica de nuestras muestras. El Friedman sirve para comparar si los valores de un conjunto de datos son significativamente distintos a los valores de otros o más conjuntos de datos, típicamente, el de Friedman se utiliza para asociar una probabilidad a la conclusión de que la media de un grupo de datos es distinta a la media de los otros grupos de datos. Es el equivalente a la prueba paramétrica ANOVA. Para la realización del test de Friedman se utilizó el software estadístico libre R. Antes de realizar el Friedman, se plantea las hipótesis nula H0 y la hipótesis alternativa H1 para que por cada grupo de datos determinar cual hipótesis se cumple. Además se determina el nivel de significancia con valor de _ 0.05. HIPOTESIS H0: ��/�t� ��/�t� vs. H1: ��/�t� u ��/�t� Donde:

• �: promedio. • t: tiempo de procesamiento de consulta expresado en milisegundo. • Índice i: Factor o datos a evaluar del conjunto de datos propuesto. • Índice j: Subfactores correspondientes al factori.

En la figura 81 se muestra los datos que R recibe como entrada para realizar el proceso de Friedman.

PostgreSQLf Página 146

Figura 81 Datos de entrada que recibe R para realizar el test de Friedman

En la Figura 82 se visualiza el resultado generado por el test de Friedman utilizando el programa R.

Figura 82 Resultado del test de Friedman

En conclusión, como el p-valor es menor al nivel de significancia seleccionado (_ 0.05), se rechaza la hipótesis nula, aceptando la alternativa donde afirma que al menos la media del tiempo de procesamiento de cada uno de los factores utilizados para realizar el test de friedman es distinto a los demás.

PostgreSQLf Página 147

A ciencia cierta el test de friedman no proporciona información exacta de cual es la media del tiempo de procesamiento que difiere de los demás, por eso se utilizara el Analisis de Varianza o ANOVA, a pesar de que la prueba de Kolmogorov-Smirnov nos dio como resultado que nuestra muestra no proviene de una distribución normal y esto es una de las condiciones para realizar el ANOVA, debido a la cantidad de datos de la muestra (mayor a 30) y al Teorema del límite central, se van a realizar test estadísticos con la ANOVA (análisis de varianza), la cual sirve para comparar si los valores de un conjunto de datos numéricos son significativamente distintos a los valores de otro o más conjuntos de datos. Ahora vamos a comprobar que existe diferencia significativa entre las medias de las muestras con respecto al tipo de consulta y volumen de dato. Para realizar el análisis de varianza o ANOVA se utilizo también el paquete estadístico R, cuyo datos que recibe como entrada para realizar dicha prueba se muestra en la tabla 13

VOLUMEN TIPO TIEMPO

BAJO FUZZY 51806,878

BAJO FUZZY 12051,221

BAJO FUZZY 3753,707

BAJO FUZZY 43229,067

BAJO BOOLEAN 50225,592

BAJO BOOLEAN 10353,672

BAJO BOOLEAN 3541,553

BAJO BOOLEAN 39510,113

BAJO FUZZY 2114,434

BAJO FUZZY 1387,986

BAJO FUZZY 4583,598

BAJO FUZZY 12389,558

BAJO FUZZY 0,145

BAJO FUZZY 1,204

BAJO FUZZY 25184,416

BAJO FUZZY 6752,073

BAJO FUZZY 2858,955

BAJO FUZZY 26332,133

BAJO BOOLEAN 2042,743

BAJO BOOLEAN 1125,745

BAJO BOOLEAN 3201,055

BAJO BOOLEAN 15601,499

BAJO BOOLEAN 0,18

BAJO BOOLEAN 1,206

BAJO BOOLEAN 23785,724

BAJO BOOLEAN 3422,995

BAJO BOOLEAN 2943,224

BAJO BOOLEAN 25028,805

PostgreSQLf Página 148

ALTO FUZZY 312555,03

ALTO FUZZY 134406,008

ALTO FUZZY 55348,565

ALTO FUZZY 296780,135

ALTO BOOLEAN 292108,485

ALTO BOOLEAN 117166,283

ALTO BOOLEAN 58155,133

ALTO BOOLEAN 284496,837

ALTO FUZZY 35827,331

ALTO FUZZY 17794,705

ALTO FUZZY 46496,797

ALTO FUZZY 180652,007

ALTO FUZZY 14,732

ALTO FUZZY 20,535

ALTO FUZZY 256377,222

ALTO FUZZY 118769,328

ALTO FUZZY 61094,788

ALTO FUZZY 505637,799

ALTO BOOLEAN 30872,804

ALTO BOOLEAN 24928,559

ALTO BOOLEAN 43979,019

ALTO BOOLEAN 180543,901

ALTO BOOLEAN 0,204

ALTO BOOLEAN 1,124

ALTO BOOLEAN 249366,365

ALTO BOOLEAN 101096,376

ALTO BOOLEAN 60033,469

ALTO BOOLEAN 451005,291

Tabla 13 Datos de entrada que recibe R para realizar el ANOVA

En la figura 83 se mostrara el resultado proporcionado por R al realizar el análisis de varianza o ANOVA

Figura 83 Resultado del analisis de varianza o ANOVA

De acuerdo al resultado mostrado en la figura 83 la única variable o factor que resulta significativo estadísticamente en el tiempo de respuesta es el factor VOLUMEN con un 100% de significancia de acurdo al Signif. Codes. correspondiente a dicho factor. Esto se puede visualizar también en la figura

PostgreSQLf Página 149

84, donde se nota la drástica diferencia entre el volumen de datos alto y bajo a través de las consultas difusas o booleanas.

Figura 84 Medias marginales estimadas de Tiempo (milisegundo) Al tener los resultados proporcionados por el ANOVA se puede concluir que la media que difiera de las demás medias en el test de Friedman es del factor VOLUMEN. A continuación se presentarán dos graficas que muestra el factor CONSULTA.

PostgreSQLf

Figura 85 Grafico que muestra la relación del tiempo de procesamiento de acuerdo al factor tipo de consulta (fuzzy/boolean)

La figura 85 muestra una grafica que muestra la relación en cuanto al tiempo de respuesta de las consultas utilizadescalabilidad a partir de los dos tipos de consultas: difuso y boolean. A partir de este grafico se puede decir que los tiempos de respuesta de acuerdo a los dos tipos de consultas son semejantes, la diferencia que pueden presentar es insignificante estadísticamente.

0

100000

200000

300000

400000

500000

600000

1 3 5

Tie

mp

o d

e P

roce

sam

ien

to (

mil

ise

gu

nd

o)

Grafico que muestra la relación del tiempo de procesamiento de acuerdo al factor tipo de consulta (fuzzy/boolean)

La figura 85 muestra una grafica que muestra la relación en cuanto al tiempo de respuesta de las consultas utilizadas para realizar las pruebas de escalabilidad a partir de los dos tipos de consultas: difuso y boolean. A partir de este grafico se puede decir que los tiempos de respuesta de acuerdo a los dos tipos de consultas son semejantes, la diferencia que pueden

esentar es insignificante estadísticamente.

7 9 11 13 15 17 19 21 23 25 27

Consulta sql

Página 150

Grafico que muestra la relación del tiempo de procesamiento

La figura 85 muestra una grafica que muestra la relación en cuanto al as para realizar las pruebas de

escalabilidad a partir de los dos tipos de consultas: difuso y boolean. A partir de este grafico se puede decir que los tiempos de respuesta de acuerdo a los dos tipos de consultas son semejantes, la diferencia que pueden

FUZZY

BOOLEAN

PostgreSQLf Página 151

Figura 86 Relación del tiempo de procesamiento de consultas difusas y booleanas tomando en cuenta el factor VOLUMEN

La figura 86, se puede apreciar como las líneas que representan el tipo de consulta, van casi paralelas y sin mayor variación en el tiempo de ejecución. Así mismo se aprecia como el tiempo tiende a disminuir cuando pasar del VOLUMEN de datos alto al VOLUMEN de datos bajo.

PostgreSQLf Página 152

Anexo A

Extensión del Catálogo del Sistema

PostgreSQLf Página 153

*) Se crea un nuevo archivo: /src/include/catalog/pg_fuzzypred.h que contiene: /*------------------------------------------------- ------------------------ * * pg_fuzzypred.h * definition of the system "relation" Fuzzy Pred icates (pg_fuzzypred) * along with the relation's initial contents. * * * Portions Copyright (c) 1996-2006, PostgreSQL Glo bal Development Group * Portions Copyright (c) 1994, Regents of the Univ ersity of California * Fuzzy Predicate by José Tomás Cadenas, Copyright (c) 2007 Universidad Simón Bolívar * * $PostgreSQL: pgsql/src/include/catalog/pg_fuzzyp red.h,v 1.97 2007/04/06 16:13:00 tgl Exp $ * * NOTES * the genbki.sh script reads this file and gener ates .bki * information from the DATA() statements. * *------------------------------------------------- ------------------------ */ #ifndef PG_FUZZYPRED_H #define PG_FUZZYPRED_H /* ---------------- * postgres.h contains the system type definitions and the * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file * can be read by both genbki.sh and the C compile r. * ---------------- */ /* ---------------- * pg_fuzzypred definition. cpp turns this into * typedef struct FormData_pg_fuzzypred * ---------------- */ #define RelationFuzzyPredId 2859 CATALOG(pg_fuzzypred,2859) BKI_BOOTSTRAP BKI_WITHOU T_OIDS { NameData predname; /* predicate name */ int2 predbegd; /* begin domain */ int2 predendd; /* end domain */ int2 predminfp; /* min trapezoid */ int2 predcore1; /* core1 trapezoid */ int2 predcore2; /* core2 trapezoid */ int2 predmaxfp; /* max trapezoid */ int2 predtypefp; /* type=1 (trapezoid), 2 (at lea st), 3 (at most) */ NameData preddisd; /* Discrete Domain. Rossodivit a */

PostgreSQLf Página 154

text predcompfplist[1]; /* Fuzzy predicates compa re list name. Rossodivita*/ NameData predexprfp; /* expression. Rossidivita*/ } FormData_pg_fuzzypred; /* ---------------- * Form_pg_fuzzypred corresponds to a pointer to a tuple with * the format of pg_fuzzypred relation. * ---------------- */ typedef FormData_pg_fuzzypred *Form_pg_fuzzypred; /* ---------------- * compiler constants for pg_fuzzypred * ---------------- */ #define Natts_pg_fuzzypred 11 #define Anum_pg_fuzzypred_predname 1 #define Anum_pg_fuzzypred_predbegd 2 #define Anum_pg_fuzzypred_predendd 3 #define Anum_pg_fuzzypred_predminfp 4 #define Anum_pg_fuzzypred_predcore1 5 #define Anum_pg_fuzzypred_predcore2 6 #define Anum_pg_fuzzypred_predmaxfp 7 #define Anum_pg_fuzzypred_predtypefp 8 #define Anum_pg_fuzzypred_predexprfp 9 #define Anum_pg_fuzzypred_preddisd 10 #define Anum_pg_fuzzypred_predcompfplist 11 #endif /* PG_FUZZYPRED_H */

*) Se crea un nuevo archivo: /src/include/catalog/pg_fuzzycomp.h que contiene: /*------------------------------------------------- ------------------------ * * pg_fuzzycomp.h * definition of the system "relation" Fuzzy Comp arator (pg_fuzzycomp) * along with the relation's initial contents. * * * Portions Copyright (c) 1996-2006, PostgreSQL Glo bal Development Group * Portions Copyright (c) 1994, Regents of the Univ ersity of California * Fuzzy Comparator by Arturo Rossodivita, Copyrigh t (c) 2009 Universidad Carabobo * * $PostgreSQL: pgsql/src/include/catalog/pg_fuzzyc omp.h,v 1.97 2009/06/18 15:27:00 tgl Exp $ * * NOTES * the genbki.sh script reads this file and gener ates .bki * information from the DATA() statements.

PostgreSQLf Página 155

* *------------------------------------------------- ------------------------ */ #ifndef PG_FUZZYCOMP_H #define PG_FUZZYCOMP_H /* ---------------- * postgres.h contains the system type definitions and the * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file * can be read by both genbki.sh and the C compile r. * ---------------- */ /* ---------------- * pg_fuzzycomp definition. cpp turns this into * typedef struct FormData_pg_fuzzycomp * ---------------- */ #define RelationFuzzyCompId 2857 CATALOG(pg_fuzzycomp,2857) BKI_BOOTSTRAP BKI_WITHOU T_OIDS { NameData compname; int2 compbegd; int2 compendd; NameData compmin; NameData compcore1; NameData compcore2; NameData compmax; int2 comptype; NameData compdisd; text complist[1]; } FormData_pg_fuzzycomp; /* ---------------- * Form_pg_fuzzycomp corresponds to a pointer to a tuple with * the format of pg_fuzzycomp relation. * ---------------- */ typedef FormData_pg_fuzzycomp *Form_pg_fuzzycomp; /* ---------------- * compiler constants for pg_fuzzycomp * ---------------- */ #define Natts_pg_fuzzycomp 10 #define Anum_pg_fuzzycomp_compname 1 #define Anum_pg_fuzzycomp_compbegd 2 #define Anum_pg_fuzzycomp_compendd 3 #define Anum_pg_fuzzycomp_compmin 4 #define Anum_pg_fuzzycomp_compcore1 5 #define Anum_pg_fuzzycomp_compcore2 6 #define Anum_pg_fuzzycomp_compmax 7 #define Anum_pg_fuzzycomp_comptype 8 #define Anum_pg_fuzzycomp_compdisd 9 #define Anum_pg_fuzzycomp_complist 10

PostgreSQLf Página 156

#endif /* PG_FUZZYCOMP_H */

*) Se crea un nuevo archivo: /src/include/catalog/pg_fuzzyconn.h que contiene: /*------------------------------------------------- ------------------------ * * pg_fuzzyconn.h * definition of the system "relation" Fuzzy Conn ector (pg_fuzzyconn) * along with the relation's initial contents. * * * Portions Copyright (c) 1996-2006, PostgreSQL Glo bal Development Group * Portions Copyright (c) 1994, Regents of the Univ ersity of California * Fuzzy Conector by Arturo Rossodivita, Copyright (c) 2009 Universidad Carabobo * * $PostgreSQL: pgsql/src/include/catalog/pg_fuzzyc onn.h,v 1.97 2009/06/18 15:27:00 tgl Exp $ * * NOTES * the genbki.sh script reads this file and gener ates .bki * information from the DATA() statements. * *------------------------------------------------- ------------------------ */ #ifndef PG_FUZZYCONN_H #define PG_FUZZYCONN_H /* ---------------- * postgres.h contains the system type definitions and the * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file * can be read by both genbki.sh and the C compile r. * ---------------- */ /* ---------------- * pg_fuzzyconn definition. cpp turns this into * typedef struct FormData_pg_fuzzyconn * ---------------- */ #define RelationFuzzyConnId 2858 CATALOG(pg_fuzzyconn,2858) BKI_BOOTSTRAP BKI_WITHOU T_OIDS { NameData connname; NameData connexpr; } FormData_pg_fuzzyconn; /* ---------------- * Form_pg_fuzzyconn corresponds to a pointer to a tuple with

PostgreSQLf Página 157

* the format of pg_fuzzyconn relation. * ---------------- */ typedef FormData_pg_fuzzyconn *Form_pg_fuzzyconn; /* ---------------- * compiler constants for pg_fuzzyconn * ---------------- */ #define Natts_pg_fuzzyconn 2 #define Anum_pg_fuzzyconn_connname 1 #define Anum_pg_fuzzyconn_connexpr 2 #endif /* PG_FUZZYCONN_H */

*) Se crea un nuevo archivo: /src/include/catalog/pg_fuzzymod.h que contiene: /*------------------------------------------------- ------------------------ * * pg_fuzzymod.h * definition of the system "relation" Fuzzy Modi fiers (pg_fuzzymod) * along with the relation's initial contents. * * * Portions Copyright (c) 1996-2006, PostgreSQL Glo bal Development Group * Portions Copyright (c) 1994, Regents of the Univ ersity of California * Fuzzy Modifiers by Arturo Rossodivita, Copyright (c) 2009 Universidad de Carabobo * * $PostgreSQL: pgsql/src/include/catalog/pg_fuzzym od.h,v 1.97 2009/04/27 15:16:00 tgl Exp $ * * NOTES * the genbki.sh script reads this file and gener ates .bki * information from the DATA() statements. * *------------------------------------------------- ------------------------ */ #ifndef PG_FUZZYMOD_H #define PG_FUZZYMOD_H /* ---------------- * postgres.h contains the system type definitions and the * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file * can be read by both genbki.sh and the C compile r. * ---------------- */ /* ---------------- * pg_fuzzymod definition. cpp turns this into * typedef struct FormData_pg_fuzzymod

PostgreSQLf Página 158

* ---------------- */ #define RelationFuzzyModId 2879 CATALOG(pg_fuzzymod,2879) BKI_BOOTSTRAP BKI_WITHOUT _OIDS { NameData modname; /* modifier name */ int2 modtype; /* modifier type */ int2 modpower; /* modifier power */ NameData modnorms; /* t-norms and t-conorms name*/ NameData modfirstarg;/* t-norms and t-conorms left arg*/ NameData modsecarg; /* t-norms and t-conorms rigth arg*/ } FormData_pg_fuzzymod; /* ---------------- * Form_pg_fuzzymod corresponds to a pointer to a tuple with * the format of pg_fuzzymod relation. * ---------------- */ typedef FormData_pg_fuzzymod *Form_pg_fuzzymod; /* ---------------- * compiler constants for pg_fuzzymod * ---------------- */ #define Natts_pg_fuzzymod 6 #define Anum_pg_fuzzymod_modname 1 #define Anum_pg_fuzzymod_modtype 2 #define Anum_pg_fuzzymod_modpower 3 #define Anum_pg_fuzzymod_modnorms 4 #define Anum_pg_fuzzymod_modfirstarg 5 #define Anum_pg_fuzzymod_modsecarg 6 #endif /* PG_FUZZYMOD_H */

*) Se crea un nuevo archivo: /src/include/catalog/pg_fuzzyquan.h que contiene: /*------------------------------------------------- ------------------------ * * pg_fuzzyquan.h * add descriptionlater * * * Portions Copyright (c) 1996-2006, PostgreSQL Glo bal Development Group * Portions Copyright (c) 1994, Regents of the Univ ersity of California * Fuzzy Quantifier by Gustavo Bazán, Copyright (c) 2009 Universidad de Carabobo * * $PostgreSQL: pgsql/src/include/catalog/pg_fuzzyp red.h,v 1.97 2007/04/06 16:13:00 tgl Exp $ * * NOTES * the genbki.sh script reads this file and gener ates .bki

PostgreSQLf Página 159

* information from the DATA() statements. * *------------------------------------------------- ------------------------ */ #ifndef PG_FUZZYQUAN_H #define PG_FUZZYQUAN_H /* ---------------- * postgres.h contains the system type definitions and the * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file * can be read by both genbki.sh and the C compile r. * ---------------- */ /* ---------------- * pg_fuzzyquan definition. cpp turns this into * typedef struct FormData_pg_fuzzyquan * ---------------- */ #define RelationFuzzyQuanId 2878 CATALOG(pg_fuzzyquan,2878) BKI_BOOTSTRAP BKI_WITHOU T_OIDS { NameData quanname; /* predicate name */ NameData quanminfp; /* min trapezoid */ NameData quancore1; /* core1 trapezoid */ NameData quancore2; /* core2 trapezoid */ NameData quanmaxfp; /* max trapezoid */ int2 quantypefp; /* type=1 (trapezoid), 2 (at lea st), 3 (at most) */ int2 quantypefq; /* type=1 (absolute), 2 (relativ e)*/ } FormData_pg_fuzzyquan; /* ---------------- * Form_pg_fuzzypred corresponds to a pointer to a tuple with * the format of pg_fuzzypred relation. * ---------------- */ typedef FormData_pg_fuzzyquan *Form_pg_fuzzyquan; /* ---------------- * compiler constants for pg_fuzzyquan * ---------------- */ #define Natts_pg_fuzzyquan 7 #define Anum_pg_fuzzyquan_quanname 1 #define Anum_pg_fuzzyquan_quanminfp 2 #define Anum_pg_fuzzyquan_quancore1 3 #define Anum_pg_fuzzyquan_quancore2 4 #define Anum_pg_fuzzyquan_quanmaxfp 5 #define Anum_pg_fuzzyquan_quantypefp 6 #define Anum_pg_fuzzyquan_quantypefq 7 #endif /* PG_FUZZYQUAN_H */

PostgreSQLf Página 160

*) Modificación del /src/backend/catalog/Makefile.in Línea 39: pg_fuzzypred.h pg_fuzzymod.h pg_fuzzycomp.h pg_fuzz yconn.h pg_fuzzyquan\

*) Modificación del /src/include/catalog/pg_class.h Línea 143: DATA(insert OID = 2859 ( pg_fuzzypred PGNSP 87 PG UID 0 2859 0 0 0 0 0 f f r 11 0 0 0 0 0 f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 2878 ( pg_fuzzyquan PGNSP 87 PG UID 0 2878 0 0 0 0 0 f f r 7 0 0 0 0 0 f f f f 3 _null_ _null_ ) ); DESCR(""); DATA(insert OID = 2879 ( pg_fuzzymod PGNSP 91 PGU ID 0 2879 0 0 0 0 0 f f r 6 0 0 0 0 0 f f f f 3 _null_ _null_ ) ); DESCR(""); DATA(insert OID = 2857 ( pg_fuzzycomp PGNSP 93 PG UID 0 2857 0 0 0 0 0 f f r 10 0 0 0 0 0 f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 2858 ( pg_fuzzyconn PGNSP 95 PG UID 0 2858 0 0 0 0 0 f f r 2 0 0 0 0 0 f f f f 3 _null_ _null_ ) );

*) Modificación del /src/include/catalog/pg_attribute.h /*----------------- * pg_fuzzycomp *----------------- */ #define Schema_pg_fuzzycomp \ { 2857, {"compname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"compbegd"}, 21, -1, 2, 15, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2857, {"compendd"}, 21, -1, 2, 16, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2857, {"compmin"}, 19, -1, NAMEDATALEN, 17, 0, -1 , -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"compcore1"}, 19, -1, NAMEDATALEN, 18, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"compcore2"}, 19, -1, NAMEDATALEN, 19, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"compmax"}, 19, -1, NAMEDATALEN, 19, 0, -1 , -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"comptype"}, 21, -1, 2, 20, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2857, {"compdisd"}, 19, -1, NAMEDATALEN, 21, 0, - 1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2857, {"complist"}, 1009, -1, -1, 22, 1, -1, -1, false, 'x', 'i', true, false, false, true, 0 } DATA(insert ( 2857 compname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2857 compbegd 21 -1 2 2 0 -1 -1 t p s t f f t 0));

PostgreSQLf Página 161

DATA(insert ( 2857 compendd 21 -1 2 3 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2857 compmin 19 -1 NAMEDATALEN 4 0 - 1 -1 f p i t f f t 0)); DATA(insert ( 2857 compcore1 19 -1 NAMEDATALEN 5 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2857 compcore2 19 -1 NAMEDATALEN 6 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2857 compmax 19 -1 NAMEDATALEN 7 0 - 1 -1 f p i t f f t 0)); DATA(insert ( 2857 comptype 21 -1 2 8 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2857 compdisd 19 -1 NAMEDATALEN 9 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2857 complist 1009 -1 -1 10 1 - 1 -1 f x i t f f t 0)); /*----------------- * pg_fuzzyconn *----------------- */ #define Schema_pg_fuzzyconn \ { 2858, {"connname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2858, {"connexpr"}, 19, -1, NAMEDATALEN, 15, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 } DATA(insert ( 2858 connname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2858 connexpr 19 -1 NAMEDATALEN 2 0 -1 -1 f p i t f f t 0)); /*----------------- * pg_fuzzymod *----------------- */ #define Schema_pg_fuzzymod \ { 2879, {"modname"}, 19, -1, NAMEDATALEN, 1, 0, - 1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2879, {"modtype"}, 21, -1, 2, 15, 0, -1, -1, true , 'p', 's', true, false, false, true, 0 }, \ { 2879, {"modpower"}, 21, -1, 2, 16, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2879, {"modnorms"}, 19, -1, NAMEDATALEN, 17, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2879, {"modfirstarg"}, 19, -1, NAMEDATALEN, 18, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2879, {"modsecarg"}, 19, -1, NAMEDATALEN, 19, 0 , -1, -1, false, 'p', 'i', true, false, false, true, 0 } DATA(insert ( 2879 modname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2879 modtype 21 -1 2 2 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2879 modpower 21 -1 2 3 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2879 modnorms 19 -1 NAMEDATALEN 4 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2879 modfirstarg 19 -1 NAMEDATALEN 5 0 -1 -1 f p i t f f t 0));

PostgreSQLf Página 162

DATA(insert ( 2879 modsecarg 19 -1 NAMEDATALEN 6 0 -1 -1 f p i t f f t 0)); /* ---------------- * pg_fuzzypred * ---------------- */ #define Schema_pg_fuzzypred \ { 2859, {"predname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2859, {"predbegd"}, 21, -1, 2, 15, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predendd"}, 21, -1, 2, 16, 0, -1, -1, tru e, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predminfp"}, 21, -1, 2, 17, 0, -1, -1, t rue, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predcore1"}, 21, -1, 2, 18, 0, -1, -1, tr ue, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predcore2"}, 21, -1, 2, 19, 0, -1, -1, tr ue, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predmaxfp"}, 21, -1, 2, 19, 0, -1, -1, tr ue, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"predtypefp"}, 21, -1, 2, 20, 0, -1, -1, t rue, 'p', 's', true, false, false, true, 0 }, \ { 2859, {"compexprfp"}, 19, -1, NAMEDATALEN, 21, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2859, {"preddisd"}, 19, -1, NAMEDATALEN, 22, 0, - 1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2859, {"predcompfplist"}, 1009, -1, -1, 23, 1, -1 , -1, false, 'x', 'i', true, false, false, true, 0 } DATA(insert ( 2859 predname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2859 predbegd 21 -1 2 2 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predendd 21 -1 2 3 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predminfp 21 -1 2 4 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predcore1 21 -1 2 5 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predcore2 21 -1 2 6 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predmaxfp 21 -1 2 7 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predtypefp 21 -1 2 8 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2859 predexprfp 19 -1 NAMEDATALEN 9 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2859 preddisd 19 -1 NAMEDATALEN 10 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2859 predcompfplist 1009 -1 -1 11 1 -1 -1 f x i t f f t 0)); /* ---------------- * pg_fuzzyquan * G.Bazan * ---------------- */

PostgreSQLf Página 163

#define Schema_pg_fuzzyquan \ { 2878, {"quanname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2878, {"quanminfp"}, 19, -1, NAMEDATALEN, 15, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2878, {"quancore1"}, 19, -1, NAMEDATALEN, 16, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2878, {"quancore2"}, 19, -1, NAMEDATALEN, 17, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2878, {"quanmaxfp"}, 19, -1, NAMEDATALEN, 17, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 2878, {"quantypefp"}, 21, -1, 2, 18, 0, -1, -1, t rue, 'p', 's', true, false, false, true, 0 }, \ { 2878, {"predtypefq"}, 21, -1, 2, 19, 0, -1, -1, t rue, 'p', 's', true, false, false, true, 0 } DATA(insert ( 2878 quanname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2878 quanminfp 19 -1 NAMEDATALEN 2 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2878 quancore1 19 -1 NAMEDATALEN 3 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2878 quancore2 19 -1 NAMEDATALEN 4 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2878 quanmaxfp 19 -1 NAMEDATALEN 5 0 -1 -1 f p i t f f t 0)); DATA(insert ( 2878 quantypefp 21 -1 2 6 0 -1 -1 t p s t f f t 0)); DATA(insert ( 2878 quantypefq 21 -1 2 7 0 -1 -1 t p s t f f t 0));

*) Modificación del /src/backend/include/catalog/pg_type.h /* OIDS 800 - 899 */ DATA(insert OID = 801 ( fuzzypred PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - c p f 0 -1 0 _null_ _null_ )); DESCR("Fuzzy Predicate"); #define FUZZYPRED 801 DATA(insert OID = 821 ( fuzzymod PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - c p f 0 -1 0 _null_ _null_ )); DESCR("Fuzzy Modifier"); #define FUZZYMOD 821 DATA(insert OID = 820 ( fuzzyquan PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - c p f 0 -1 0 _null_ _null_ )); DESCR("Fuzzy Quantifier"); #define FUZZYQUAN 820 DATA(insert OID = 822 ( fuzzycomp PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - c p f 0 -1 0 _null_ _null_ )); DESCR("Fuzzy Comparator"); #define FUZZYCOMP 822

PostgreSQLf Página 164

Anexo B

Extensión del Parser

PostgreSQLf Página 165

*) Modificación del /src/backend/parser/keywords.c: Línea 35: {"absolute", ABSOLUTE},

Línea 69: {"calibration", CALIBRATION},

Línea 90: {"comparator", COMPARATOR}, {"connector", CONNECTOR},

Línea 225: {"modifier", MODIFIER},

Línea 272: {"power", POWER},

Línea 283: {"quantifier", QUANTIFIER},

Línea 292: {"relative", RELATIVE},

Línea 351: {"translation", TRANSLATION},

*) Modificación del /src/backend/parser/gram.y: Línea 156: CreateFuzzyCompStmt CreateFuzzyConnStmt CreateFuzzy ModStmt CreateFuzzyQuanStmt CreateFuzzyPredStmt

Línea 200: /*List of compare fuzzy predicates. Rossodivita*/ %type <list> CompFpList %type <defelt> CompFp %type <str> CompFpName

Línea 301, 5998: calibracion

Línea 364: ABSOLUTE

Línea 371: CALIBRATION

Línea 374: COMPARATOR

Línea 387: FUZZY

PostgreSQLf Página 166

Línea 394: INFINITE

Línea 416: PREDICATE

Línea 421: RELATIVE

Línea 546: | CreateFuzzyCompStmt | CreateFuzzyConnStmt | CreateFuzzyModStmt | CreateFuzzyPredStmt | CreateFuzzyQuanStmt

Línea 614: /************************************************** *************************** * * Create a Fuzzy Connector * *************************************************** **************************/ CreateFuzzyConnStmt: CREATE CONNECTOR ColId AS '('SCONST')' { CreateFuzzyConnStmt *n = makeNode(CreateFuzzyConnStmt); n->conn = $3; n->connexpr = $6; $$ = (Node *)n; } ; /************************************************** *************************** * * Create a Fuzzy Predicate :) * *************************************************** **************************/ CreateFuzzyCompStmt: CREATE COMPARATOR SCONST ON Iconst'.''.'Iconst AS '('SCONST','SCONST','SCONST','SCONST')' { CreateFuzzyCompStmt *n = makeNode(CreateFuzzyCompStmt); n->comp=$3; n->begd=$5; n->endd=$8; n->min=$11; n->core1=$13; n->core2=$15;

PostgreSQLf Página 167

n->max=$17; if((strcmp($15,"INFINITE")==0 || strcmp($15,"infinite")==0) && (strcmp($17,"INFINITE ")==0 || strcmp($17,"infinite")==0)) n->typecomp=3; else { if((strcmp($13,"INFINITE")==0 || strcmp($13,"infinite")==0) && (strcmp($11,"INFINITE ")==0 || strcmp($11,"infinite")==0)) n->typecomp=2; else n->typecomp=1; } $$ = (Node *)n; } | CREATE COMPARATOR SCONST ON SCONST AS '('CompFpLi st')' { CreateFuzzyCompStmt *n = makeNode(CreateFuzzyCompStmt); n->comp=$3; n->disd=$5; /***Discrete Domain. Rossodivita***/ n->compfclist=$8; /***Compare fuzzy predicates list. Rossodivita***/ n->typecomp=4; $$ = (Node *)n; } ; CompFpList: CompFp { $$ = list_make1($1);} /***Compare Fuzzy predicates list. Rossodivita***/ | CompFpList ',' CompFp { $$ = lappend($1, $3);} ; CompFp: CompFpName { $$ = makeDefElem("pair", (Node *)makeString($1)); } /***Compare Fuzzy predicates. Rossodivita***/ ; CompFpName: SCONST { $$ = $1; } /***Compare Fuzzy predicates name. Rossodivita***/ /************************************************** *************************** * * Create a Fuzzy Modifier * *************************************************** **************************/ CreateFuzzyModStmt: CREATE MODIFIER ColId AS POWER Iconst

PostgreSQLf Página 168

{ CreateFuzzyModStmt *n = makeNode(CreateFuzzyMod Stmt); n->name = $3; n->modtype = 1; n->power = $6; $$ = (Node *)n; } | CREATE MODIFIER ColId AS ColId '(' ColId ',' Col Id ')' POWER Iconst { CreateFuzzyModStmt *n = makeNode(CreateFuzzyMod Stmt); n->name = $3; n->modtype = 2; n->power = $12; n->norm = $5; n->firstarg = $7; n->secarg = $9; $$ = (Node *)n; } | CREATE MODIFIER ColId AS TRANSLATION SignedIcons t { CreateFuzzyModStmt *n = makeNode(CreateFuzzyMod Stmt); n->name = $3; n->modtype = 3; n->power = $6; $$ = (Node *)n; } ; /************************************************** *************************** * * Create a Fuzzy Predicate :) * *************************************************** **************************/ CreateFuzzyPredStmt: CREATE FUZZY PREDICATE ColId ON Iconst'.''.'Icons t AS '('Iconst','Iconst','Iconst','Iconst')' { CreateFuzzyPredStmt *n = makeNode(CreateFuzzyPredStmt); n->pred=$4; n->begd=$6; n->endd=$9; n->minfp=$12; n->core1=$14; n->core2=$16; n->maxfp=$18; n->typefp=1; $$ = (Node *)n; } | CREATE FUZZY PREDICATE ColId ON Iconst'.''.'Icons t AS '('INFINITE','INFINITE','Iconst','Iconst')' {

PostgreSQLf Página 169

CreateFuzzyPredStmt *n = makeNode(CreateFuzzyPredStmt); n->pred=$4; n->begd=$6; n->endd=$9; n->core2=$16; n->maxfp=$18; n->typefp=2; $$ = (Node *)n; } | CREATE FUZZY PREDICATE ColId ON Iconst'.''.'Icons t AS '('Iconst','Iconst','INFINITE','INFINITE')' { CreateFuzzyPredStmt *n = makeNode(CreateFuzzyPredStmt); n->pred=$4; n->begd=$6; n->endd=$9; n->minfp=$12; n->core1=$14; n->typefp=3; $$ = (Node *)n; } | CREATE FUZZY PREDICATE ColId ON ColId AS '('CompF pList')' { CreateFuzzyPredStmt *n = makeNode(CreateFuzzyPredStmt); n->pred=$4; n->disd=$6; /***Discrete Domain. Rossodivita***/ n->compfplist=$9; /***Compare fuzzy predicates list. Rossodivita***/ n->typefp=4; $$ = (Node *)n; } | CREATE FUZZY PREDICATE ColId ON ColId AS '('SCONS T')' { CreateFuzzyPredStmt *n = makeNode(CreateFuzzyPredStmt); n->pred=$4; n->disd=$6; n->exprfp=$9; n->typefp=5; $$ = (Node *)n; } ; CompFpList: CompFp { $$ = list_make1($1);} /***Compare Fuzzy predicates list. Rossodivita***/ | CompFpList ',' CompFp { $$ = lappend($1, $3);} ; CompFp: CompFpName { $$ = makeDefElem("pair",

PostgreSQLf Página 170

(Node *)makeString($1)); } /***Compare Fuzzy predicates. Rossodivita***/ ; CompFpName: SCONST { $$ = $1; } /***Compare Fuzzy predicates name. Rossodivita***/ /************************************************** *************************** * * Create a Fuzzy Quantifier ;) * *************************************************** **************************/ CreateFuzzyQuanStmt: CREATE ABSOLUTE QUANTIFIER ColId AS '('FCONST','FCONST','FCONST','FCONST')' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->minfp=$7; n->core1=$9; n->core2=$11; n->maxfp=$13; n->typefp=1; n->typefq=1; $$ = (Node *)n; } | CREATE ABSOLUTE QUANTIFIER ColId AS '('INFINITE','INFINITE','FCONST','FCONST')' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->core2=$11; n->maxfp=$13; n->typefp=2; n->typefq=1; $$ = (Node *)n; } | CREATE ABSOLUTE QUANTIFIER ColId AS '('FCONST','FCONST','INFINITE','INFINITE')' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->minfp=$7; n->core1=$9; n->typefp=3; n->typefq=1; $$ = (Node *)n; }

PostgreSQLf Página 171

| CREATE RELATIVE QUANTIFIER ColId AS '('FCONST','FCONST','FCONST','FCONST')' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->minfp=$7; n->core1=$9; n->core2=$11; n->maxfp=$13; n->typefp=1; n->typefq=2; $$ = (Node *)n; } /* | CREATE RELATIVE QUANTIFIER ColId AS '('INFINITE','INFINITE','FCONST','FCONST')' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->core2=$11; n->maxfp=$13; n->typefp=2; n->typefq=2; $$ = (Node *)n; } | CREATE RELATIVE QUANTIFIER ColId AS '('FCONST','F CONST', INFINITE, INFINITE)' { CreateFuzzyQuanStmt *n = makeNode(CreateFuzzyQuanStmt); n->pred=$4; n->minfp=$7; n->core1=$9; n->typefp=3; n->typefq=2; $$ = (Node *)n; }*/ ;

Línea 5999: n->calibracion = $9;

Línea 6567: calibracion: WITH CALIBRATION FCONST { A_Const *n = makeNode(A_Const); n->val.type = T_Float; n->val.val.str = $3; $$ = (Node *)n; } | /*EMPTY*/ {$$ = NULL; } ;

PostgreSQLf Página 172

*) Modificación del /src/backend/parser/parse_expr.c Línea 17: #include "access/genam.h" #include "access/heapam.h" #include "catalog/heap.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_fuzzyquan.h"

Línea 24: #include "commands/fuzzypred.h" #include "commands/fuzzyquan.h"

Línea 29: #include "nodes/print.h"

Línea 42: #include "utils/fmgroids.h"

Línea 53: static Node *derivate_fuzzy_opex (Var *varfa, A_Fuz zyPred *fp); static Node *derivate_fuzzy_quan (ParseState *pstat e, A_FuzzyQuan *fp);

Línea 89: static Node *transformAFuzzyQuan(ParseState *pstate , Node *fuzzyq, bool *isfq);

Línea 211: bool isfq = false; result = transformAFuzzyQuan(pstate, expr, &isfq); if(!isfq){ result = transformFuncCall(pstate, (FuncCall *) ex pr); } break;

Línea 257: case T_A_FuzzyQuan: result=derivate_fuzzy_quan(pstate, (A_FuzzyQuan *) expr); break; /********************************************* * Quietly accept node types that may be presented when we are * called on an already-transformed tree. * * Do any other node types need to be accepted? F or now we are * taking a conservative approach, and only accept ing node * types that are demonstrably necessary to accept . *********************************************/

Línea 269: case T_A_FuzzyPred:

Línea 361: // Variables for Fuzzy predicates Relation pg_fuzzypred_rel; HeapTuple tuple; ScanKeyData key;

PostgreSQLf Página 173

SysScanDesc fpscan; bool isfp; A_FuzzyPred *n = makeNode(A_FuzzyPred); Datum *names; /* Names and membership grade fuzzy pred list. Rossodivita */ int nnames,i; /* Numbers of names and membership g rade. Rossodivita*/ char *cad="";

Línea 435: else { // Is a Fuzzy Predicate? isfp = false; pg_fuzzypred_rel = heap_open(RelationFuzzyPredId,Ro wExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, tr ue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(fp scan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzypre d) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzypred->predname), name) == 0) { n->type=T_A_FuzzyPred; n->pred=name; n->minfp=pg_fuzzypred->predminfp; n->core1=pg_fuzzypred->predcore1; n->core2=pg_fuzzypred->predcore2; n->maxfp=pg_fuzzypred->predmaxfp; n->typefp=pg_fuzzypred->predtypefp; isfp = true; /** If is an extension fuzzy predicate. Rossodivit a **/ if (pg_fuzzypred->predtypefp == 4) { n->disd= DatumGetCString(&(pg_fuzzypred->preddisd )); /** Insert Discrete Domain Name. Rossodivita **/ /** Insert compare fuzzy predicate list. Rossodiv ita **/ deconstruct_array(DatumGetArrayTypeP(pg_fuzzypred ->predcompfplist), TEXTOID, -1, false, 'i', &names, NULL, &nnames); for(i = 0; i < nnames; i++) { cad = DatumGetCString(DirectFunctionCall1(textout,names[i ])); if(i == 0) n->compfplist = list_make1(cad); else lappend(n->compfplist, cad); } } /*if(pg_fuzzypred->predtypefp == 5)

PostgreSQLf Página 174

{ n->disd = DatumGetCString(&(pg_fuzzypred->preddis d)); n->exprfp = DatumGetCString(&(pg_fuzzypred->predd isd)); }*/ break; } } systable_endscan(fpscan); heap_close(pg_fuzzypred_rel, NoLock); if (isfp) { ListCell *x; char *modname; List *modValues; pstate->p_hasFuzzyPred = true; pstate->p_numFuzzyPred++; foreach(x,pstate->p_FuzzyMod) { if(IsA(lfirst(x),String)) { modname = strVal(lfirst(x)); } if(IsA(lfirst(x),Integer)) { int num; num = intVal(lfirst(x)); if(num == pstate->p_numFuzzyPred) { modValues = GetFuzzyMod(pstate,modname); n->hasfm = true; n->fuzzymod = modname; n->Mtype = intVal(linitial(modValues)); n->Mpower = intVal(lsecond(modValues)); if(n->Mtype == 2) { char *normType = strVal(lthird(modValues)); if(strcmp(normType,"min") == 0) { n->normType = 1; } else if(strcmp(normType,"product") == 0) { n->normType = 2; } else if(strcmp(normType,"dproduct") == 0) { n->normType = 3; } else if(strcmp(normType,"bproduct") == 0) { n->normType = 4; } else if(strcmp(normType,"hproduct") == 0)

PostgreSQLf Página 175

{ n->normType = 5; } else if(strcmp(normType,"yfamily") == 0) { n->normType = 6; } else if(strcmp(normType,"dpfamily") == 0) { n->normType = 7; } else if(strcmp(normType,"ffamily") == 0) { n->normType = 8; } else if(strcmp(normType,"eproduct") == 0) { n->normType = 9; } else if(strcmp(normType,"max") == 0) { n->normType = 10; } else if(strcmp(normType,"sproduct") == 0) { n->normType = 11; } else if(strcmp(normType,"dsum") == 0) { n->normType = 12; } else if(strcmp(normType,"bsum") == 0) { n->normType = 13; } else if(strcmp(normType,"esum") == 0) { n->normType = 14; } else if(strcmp(normType,"sfamily") == 0) { n->normType = 15; } else if(strcmp(normType,"cyfamily") == 0) { n->normType = 16; } else if(strcmp(normType,"cdpfamily") == 0) { n->normType = 17; } else if(strcmp(normType,"cffamily") == 0) { n->normType = 18; } pg_fuzzypred_rel = heap_open(RelationFuzzyPredId,RowExclusiveLock);

PostgreSQLf Página 176

ScanKeyInit(&key,Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(modname)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(fpscan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzypred) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzypred->predname), modname) == 0) { if(n->typefp != 4) { n->modminfp = pg_fuzzypred->predminfp; n->modcore1 = pg_fuzzypred->predcore1; n->modcore2 = pg_fuzzypred->predcore2; n->modmaxfp = pg_fuzzypred->predmaxfp; n->modtypefp = pg_fuzzypred->predtypefp; } else { deconstruct_array(DatumGetArrayTypeP(pg_fuzzypred->predcompfplist), TEXTOID, -1, false, 'i', &names, NULL, &nnames); for(i = 0; i < nnames; i++) { cad = DatumGetCString(DirectFunctionCall1(textout,names[i ])); if(i == 0) n->modcompfplist = list_make1(cad); else lappend(n->modcompfplist, cad); } } } } systable_endscan(fpscan); heap_close(pg_fuzzypred_rel, NoLock); } if(n->Mtype == 3) { if(n->typefp != 4) {

PostgreSQLf Página 177

n->minfp = n->minfp + n->Mpower; n->core1 = n->core1 + n->Mpower; n->core2 = n->core2 + n->Mpower; n->maxfp = n->maxfp + n->Mpower; } } } } } node = (Node *) n; } else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", name), parser_errposition(pstate, cref->location))); }

Línea 1776: case T_A_FuzzyPred: type = UNKNOWNOID; break;

Línea 2515: static Node * transformAFuzzyQuan(ParseState *pstate, Node *fuzzy q, bool *isfq) { ColumnRef *cref= (ColumnRef *)fuzzyq; FuncCall *fn = (FuncCall *) fuzzyq; List *targs; ListCell *args; // Variables for Fuzzy quantifiers /*Bazán*/ Relation pg_fuzzyquan_rel; A_FuzzyQuan *nq = makeNode(A_FuzzyQuan); HeapTuple tuple; ScanKeyData key; SysScanDesc fpscan; Node *node; //Node *leftarg = (Node *) lsecond(fn->args) ; char *name = strVal(linitial(cref->fields)); *isfq=false; // Is a Fuzzy Quantifier? pg_fuzzyquan_rel = heap_open(RelationFuzzyQuanId,RowExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzyquan_quanname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzyquan_rel, 0, t rue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzyquan pg_fuzzyquan = (Form_pg_fuzzyq uan) GETSTRUCT(tuple);

PostgreSQLf Página 178

if (namestrcmp(&(pg_fuzzyquan->quanname), name) = = 0) { nq->type=T_A_FuzzyQuan; nq->pred= name; nq->minfp=&(pg_fuzzyquan->quanminfp); nq->core1=&(pg_fuzzyquan->quancore1); nq->core2=&(pg_fuzzyquan->quancore2); nq->maxfp=&(pg_fuzzyquan->quanmaxfp); nq->typefp=pg_fuzzyquan->quantypefp; nq->typefq=pg_fuzzyquan->quantypefq; targs = list_copy(fn->args); foreach(args, targs) { lfirst(args) = transformExpr(pstate,(Node *) lfirst(args)); } nq->args = list_copy(targs); *isfq = true; break; } } systable_endscan(fpscan); heap_close(pg_fuzzyquan_rel, NoLock); if (*isfq) { pstate->p_hasFuzzyQuan = true; pstate->p_numFuzzyQuan++; node=(Node *) nq; node = transformExpr(pstate, (Node *) nq); } return node; } /* * Derivate_fuzzy_opex * * Derivate a fuzzy predicate and generate a boolea n OpExpr or BoolExpr * * Returns the modified version of the given OpExpr node. */ static Node * derivate_fuzzy_opex (Var *varfa, A_FuzzyPred *fp) { Expr *newopclause; Node *newqual = (Node *) makeNode(OpExpr); Node *newqual1 = (Node *) makeNode(OpExpr); Const *newcon = makeNode(Const); Const *newcon1 = makeNode(Const); bool istrap=false; // *** Node Fuzzy Predicate switch (fp->typefp) { case NO_INFINITE: // Trapecio if(varfa->vartype == 21)

PostgreSQLf Página 179

{ newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon1->consttype = 21; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int16GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(520, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int16GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(95, 16, false ,(Expr *) varfa,(Expr *) newcon1); } else if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon1->consttype = 23; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int32GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(521, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(97, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon1->consttype = 20; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int64GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">"

PostgreSQLf Página 180

newopclause = make_opclause(413, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(412, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 700) { newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon1->consttype = 700; newcon1->constlen = 8; newcon1->constbyval = false; newcon1->constisnull = false; newcon->constvalue = Float4GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(623, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Float4GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(622, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon1->consttype = 701; newcon1->constlen = 8; newcon1->constbyval = false; newcon1->constisnull = false; newcon->constvalue = Float8GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(674, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Float8GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(672, 16, false ,(Expr *) varfa,(Expr *) newcon1); }

PostgreSQLf Página 181

fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; istrap = true; break; case INFINITE_BEG: // Decreciente if(varfa->vartype == 21) { newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int16GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(95, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(97, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int64GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(412, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 700) { newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float4GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<"

PostgreSQLf Página 182

newopclause = make_opclause(622, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float8GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(672, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; break; case INFINITE_LAST: // Creciente if(varfa->vartype == 21) { newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int16GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(520, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int32GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(521, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true;

PostgreSQLf Página 183

newcon->constisnull = false; newcon->constvalue = Int64GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(413, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 700) { newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float4GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(623, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float8GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(674, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; break; } if (istrap) return (Node *) make_andclause(list_make2(newqual , newqual1)); return newqual; } /* *Derivate Fuzzy Quantifiers */ static Node * derivate_fuzzy_quan (ParseState *pstate, A_FuzzyQua n *fp) { List *targs; List *dfq=NIL, *tempdfq=NIL; ListCell *args; int i=0; Node *newqual = (Node *) makeNode(OpExpr); Node *newqual1 = (Node *) makeNode(OpExpr);

PostgreSQLf Página 184

Node *newqual2 = (Node *) makeNode(OpExpr); Var *varfa; targs = list_copy(fp->args); foreach(args, targs) { //printf("si\n"); if (IsA(lfirst(args), OpExpr)) { OpExpr *opex = (OpExpr *) lfirst(args); Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); Node *temp; if (IsA(secarg,A_FuzzyPred)) { temp = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); dfq=lappend(dfq, temp); if(list_length(dfq)==1){ varfa=(Var *) firstarg; fp->vno = varfa->varno; } } else elog(ERROR, "fuzzy quantifier arguments must be a fuzzy predicate"); } } if(list_length(dfq)==1){ newqual=list_nth(dfq, 0); } else{ for(i=0; i<list_length(dfq); i++){ int j=0; Node *arg1 = (Node *) makeNode(OpExpr); arg1= list_nth(dfq, i); //tempdfq=list_copy(dfq); for(j=i+1; j<list_length(dfq); j++){ Node *arg2 = (Node *) makeNode(OpExpr); arg2 = list_nth(dfq, j); newqual = make_andclause(list_make2(arg1, arg2)); tempdfq = lappend(tempdfq, newqual); } } if(list_length(tempdfq)==1){ newqual=list_nth(tempdfq, 0); } else{ newqual1= list_nth(tempdfq, 0); newqual2= list_nth(tempdfq, 1); newqual=make_orclause(list_make2(newqual1, newqual2)); i=2; while(i<list_length(tempdfq)){ newqual1= list_nth(tempdfq, i); newqual=make_orclause(list_make2(newqual, newqual1)); i++;

PostgreSQLf Página 185

} } } pstate->p_fuzzyquan = lappend(pstate->p_fuzzyquan, fp); return newqual; }

*) Modificación del /src/include/nodes/nodes.h: Línea 296: T_CreateFuzzyCompStmt, T_CreateFuzzyConnStmt, T_CreateFuzzyModStmt, T_CreateFuzzyPredStmt, T_CreateFuzzyQuanStmt,

Línea 332: T_A_FuzzyPred, T_A_FuzzyQuan, T_A_FuzzyComp,

*) Modificación del /src/include/nodes/parsenodes.h: Línea 102: bool hasFuzzyPred; /* has Fuzzy Predicates */ bool hasFuzzyComp; /* has Fuzzy Comparator */ bool hasFuzzyHavingQual; /*has Fuzzy Qual on Having*/ bool hasFuzzyQual; /*has Fuzzy Qual on Whe re*/ bool hasFuzzy; /*has Fuzzy condition on Fro m*/ int numFuzzyPred; /* How many Fuzzy predicates */ List *FuzzyPredExp; /* Fuzzy predicates expression s*/ List *FuzzyComp; /* Fuzzy Comparators*/ bool hasFuzzyQuan; /* has Fuzzy Quantifiers */ int numFuzzyQuan; /* How many Fuzzy Quantifiers */ List *fuzzyquan; /* Fuzzy Quantifiers*/ Node *calibracion;

Línea 265: /* * A_FuzzPred- a Fuzzy Predicate expression */ typedef struct A_FuzzyPred { NodeTag type; char *pred; int minfp; int modminfp; int core1; int modcore1; int core2; int modcore2; int maxfp; int modmaxfp; int typefp; int modtypefp;

PostgreSQLf Página 186

unsigned int vno; int vattno; Oid rorigtab; Oid rorigcol; List *compfplist; /* Compare fuzzy predicate lis t. Rossodivita */ List *modcompfplist; char *exprfp; char *disd; /* Discrete Domain. Rossodi vita */ bool hasfm; char *fuzzymod; int Mtype; int Mpower; int normType; int vtype; } A_FuzzyPred; /* * A_FuzzQuan- a Fuzzy Quantifier expression */ typedef struct A_FuzzyQuan { NodeTag type; char *pred; char *minfp; char *core1; char *core2; char *maxfp; int typefp; /* type=1 (trapezoid), 2 (at least), 3 (at most) */ int typefq; /* type=1 (Absolute), 2 (Relative) */ List *args; /* the arguments (list of exprs) */ unsigned int vno; int vattno; } A_FuzzyQuan; typedef struct A_FuzzyComp { NodeTag type; char *pred; char *minfp; int modminfp; char *core1; int modcore1; char *core2; int modcore2; char *maxfp; int modmaxfp; int typefp; int modtypefp; unsigned int vno; int vattno; Oid rorigtab; Oid rorigcol; List *compfclist; /* Compare fuzzy predicate lis t. Rossodivita */ char *disd; /* Discrete Domain. Rossodi vita */

PostgreSQLf Página 187

bool hasfm; char *fuzzymod; int Mtype; int Mpower; int normType; A_Const *secarg; int vtype; } A_FuzzyComp;

Línea 839: A_Const *calibracion; /* fuzzy calibration * /

Línea 1363: /* ---------------------- * {Create} FUZZY COMPARATOR Statement * ---------------------- */ typedef struct CreateFuzzyCompStmt { NodeTag type; char *comp; /* Predicate name*/ int begd; /* begin domain */ int endd; /* end domain */ char *min; /* min trapezoid */ char *core1; /* core 1 trapezoid */ char *core2; /* core 2 trapezoid */ char *max; /* max trapezoid */ int typecomp; /* type=1 (trapezoid), 2 (at least), 3 (at most) */ List *compfclist; /* Compare fuzzy predicate li st. Rossodivita */ char *disd; /* Discrete Domain. Ross odivita */ } CreateFuzzyCompStmt; /* ---------------------- * {Create} FUZZY CONNECTOR Statement * ---------------------- */ typedef struct CreateFuzzyConnStmt { NodeTag type; char *conn; /* connector name*/ char *connexpr; } CreateFuzzyConnStmt; /* ---------------------- * {Create} FUZZY MODIFIER Statement * ---------------------- */ typedef struct CreateFuzzyModStmt { NodeTag type; char *name; /* Modifier name*/ int modtype; /* modifier type */ int power; /* modifier power */ char *norm; /* t-norm and t-conorm name*/ char *firstarg; /* t-norm and t-conorm left arg* / char *secarg; /* t-norm and t-conorm rigth arg*/ } CreateFuzzyModStmt;

PostgreSQLf Página 188

/* ---------------------- * {Create} FUZZY PREDICATE Statement * ---------------------- */ typedef struct CreateFuzzyPredStmt { NodeTag type; char *pred; /* Predicate name*/ int begd; /* begin domain */ int endd; /* end domain */ int minfp; /* min trapezoid */ int core1; /* core 1 trapezoid */ int core2; /* core 2 trapezoid */ int maxfp; /* max trapezoid */ int typefp; /* type=1 (trapezoid), 2 (at least), 3 (at most) */ List *compfplist; /* Compare fuzzy predicate li st. Rossodivita */ char *disd; /* Discrete Domain. Ross odivita */ char *exprfp; /* Expression to calculate GrM. Rossodivita*/ } CreateFuzzyPredStmt; /* ---------------------- * {Create} FUZZY QUANTIFIER Statement * ---------------------- */ typedef struct CreateFuzzyQuanStmt { NodeTag type; char *pred; /* Predicate name*/ char *minfp; /* min trapezoid */ char *core1; /* core 1 trapezoid */ char *core2; /* core 2 trapezoid */ char *maxfp; /* max trapezoid */ int typefp; /* type=1 (trapezoid), 2 (at least), 3 (at most) */ int typefq; /* type=1 (Absolute), 2 (Relative) */ } CreateFuzzyQuanStmt;

*) Modificación del /src/backend/include/parser/parse_node.h Línea 83: List *p_FuzzyMod; // fuzzy modifier names List *p_FuzzyPredExp; // Fuzzy predicates express ion names bool p_hasFuzzyHavingQual; /*has Fuzzy Qual on Having. Armando Bracho*/ bool p_hasFuzzyQual; /*has Fuzzy Qual on Where. Armando Bracho*/ bool p_hasFuzzyPred; // Has Fuzzy Predicate int p_numFuzzyPred; // Fuzzy Predicates quantity bool p_hasFuzzyComp; // Has Fuzzy Comparator int p_numFuzzyComp; // Fuzzy Comparator quantity bool p_hasFuzzyQuan; // Has Fuzzy Quantifier int p_numFuzzyQuan; // Fuzzy Quantifiers quanti ty

PostgreSQLf Página 189

List *p_fuzzyquan; // Fuzzy Quantifiers

*) Modificación del /src/backend/parser/parse_coerce.c Línea 362: // A Fuzzy Predicate Node if (inputTypeId == UNKNOWNOID) { return node; }

*) Modificación del /src/backend/parser/parse_clause.c Línea 1070: /*Here we check if there is a fuzzy condition in th e qual and if the qual belongs to the Having or Where clause. Armando B*/ if(pstate->p_hasFuzzyPred) { if(strncmp(constructName, "HAVING", 6) == 0) pstate->p_hasFuzzyHavingQual = true; else pstate->p_hasFuzzyHavingQual = false; if(strncmp(constructName, "WHERE", 5) == 0) pstate->p_hasFuzzyQual = true; else pstate->p_hasFuzzyQual = false; }

*) Modificación del /src/backend/parser/analyze.c Línea 99: int fuzzyIndex, constIndex;

Línea 530, 874, 3570, 3779, 4008, 4317: qry->hasFuzzyPred = pstate->p_hasFuzzyPred; qry->numFuzzyPred = pstate->p_numFuzzyPred; qry->hasFuzzyQual = pstate->p_hasFuzzyQual;/*Armand o Bracho*/ qry->hasFuzzyHavingQual = pstate->p_hasFuzzyHavingQ ual; qry->hasFuzzyQuan = pstate->p_hasFuzzyQuan; qry->numFuzzyQuan = pstate->p_numFuzzyQuan; qry->fuzzyquan = list_copy(pstate->p_fuzzyquan);

Línea 2101: A_FuzzyPred *n; int IsFuzzyPred(ColumnRef *cref) { int numnames; char *name = ""; int result = 0; Relation pg_fuzzypred_rel; HeapTuple tuple; ScanKeyData key; SysScanDesc fpscan;

PostgreSQLf Página 190

numnames = list_length(cref->fields); switch (numnames) { case 1: { name = strVal(linitial(cref->fields)); pg_fuzzypred_rel = heap_open(RelationFuzzyPredId,RowExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(fpscan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzypred) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzypred->predname), name) == 0){ result = pg_fuzzypred->predtypefp; n = makeNode(A_FuzzyPred); n->pred=name; n->minfp=pg_fuzzypred->predminfp; n->core1=pg_fuzzypred->predcore1; n->core2=pg_fuzzypred->predcore2; n->maxfp=pg_fuzzypred->predmaxfp; n->typefp=pg_fuzzypred->predtypefp; } } systable_endscan(fpscan); heap_close(pg_fuzzypred_rel, NoLock); break; } default: result = 0; } return result; } char * GetFuzzyExpr(ParseState *pstate, ColumnRef *cref, i nt kind) { int levels_up, numnames; char *name = ""; Node *node; char *result = NULL; Relation pg_fuzzypred_rel;

PostgreSQLf Página 191

HeapTuple tuple; ScanKeyData key; SysScanDesc fpscan; numnames = list_length(cref->fields); switch (numnames) { case 1: { name = strVal(linitial(cref->fields)); node = colNameToVar(pstate, name, false, cref->location); if (node == NULL) { if (pstate->p_value_substitute != NULL && strcmp(name, "value") == 0) { node = (Node *) copyObject(pstate->p_value_substitute); break; } if (refnameRangeTblEntry(pstate, NULL, name, &levels_up) == NULL) { pg_fuzzypred_rel = heap_open(RelationFuzzyPredId,RowExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(fpscan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzypred) GETSTRUCT(tuple) ; if (namestrcmp(&(pg_fuzzypred->predname), name) == 0) result = DatumGetCString(&(pg_fuzzypred->preddisd)); } systable_endscan(fpscan); heap_close(pg_fuzzypred_rel, NoLock); }

PostgreSQLf Página 192

} break; } default: result = NULL; } if(kind == 0) return result; else return name; } bool isfc; A_FuzzyComp * GetFuzzyComp(ParseState *pstate, char *name) { A_FuzzyComp *n = makeNode(A_FuzzyComp); Relation pg_fuzzycomp_rel; HeapTuple tuple; ScanKeyData key; SysScanDesc fpscan; Datum *names; /* Names and membership grade fuzz y pred list. Rossodivita */ int nnames,i; /* Numbers of names and membership grade. Rossodivita*/ char *cad=""; isfc = false; pg_fuzzycomp_rel = heap_open(RelationFuzzyCompId,RowExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzypred_predname,BTEqual StrategyNumber,F_NAMEEQ,PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzycomp_rel, 0 , true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnex t(fpscan))) { Form_pg_fuzzycomp pg_fuzzycomp = (Form_pg_fuzzyc omp) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzycomp->compname), name) = = 0) { n->type=T_A_FuzzyComp; n->pred=name; n->minfp=pg_fuzzycomp->compmin.data; n->core1=pg_fuzzycomp->compcore1.data; n->core2=pg_fuzzycomp->compcore2.data; n->maxfp=pg_fuzzycomp->compmax.data; n->typefp=pg_fuzzycomp->comptype; isfc = true; if(n->typefp == 4) { n->disd= DatumGetCString(&(pg_fuzzycomp->compdisd)); /** Insert Discrete Domain Name. Ross odivita **/ /** Insert compare fuzzy predicate list. Rossodivita **/ deconstruct_array(DatumGetArrayTypeP(pg_fuzzycomp- >complist),

PostgreSQLf Página 193

TEXTOID, -1, false, 'i', &names, NULL, &nnames); for(i = 0; i < nnames; i++) { cad = DatumGetCString(DirectFunctionCall1(textout,names[i ])); if(i == 0) n->compfclist = list_make1(cad); else lappend(n->compfclist, cad); } } break; } } systable_endscan(fpscan); heap_close(pg_fuzzycomp_rel, NoLock); if (isfc) { pstate->p_hasFuzzyComp = true; pstate->p_numFuzzyComp++; } return n; } List* GetFuzzyMod(ParseState *pstate, char *name) { int levels_up; Node *node = NULL; List *result = NULL; Relation pg_fuzzymod_rel; HeapTuple tuple; ScanKeyData key; SysScanDesc fpscan; if (node == NULL) { if (pstate->p_value_substitute != NULL && strcmp( name, "value") == 0) node = (Node *) copyObject(pstate->p_value_substitute); if (refnameRangeTblEntry(pstate, NULL, name, &lev els_up) == NULL) { pg_fuzzymod_rel = heap_open(RelationFuzzyModId,RowExclusiveLock); ScanKeyInit(&key,Anum_pg_fuzzymod_modname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(name)); fpscan = systable_beginscan(pg_fuzzymod_rel, 0, true, SnapshotNow, 1, &key);

PostgreSQLf Página 194

while (HeapTupleIsValid(tuple = systable_getnext(fpscan))) { Form_pg_fuzzymod pg_fuzzymod = (Form_pg_fuzzymod) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzymod->modname), name) == 0) { result = lappend(result,makeInteger(pg_fuzzymod->modtype)); result = lappend(result,makeInteger(pg_fuzzymod->modpower)); result = lappend(result,makeString(DatumGetCString(&(pg_fuzz ymod->modnorms)))); } else result = NULL; } systable_endscan(fpscan); heap_close(pg_fuzzymod_rel, NoLock); } } return result; } static char * makePosfijo (char *exprfp) { static char infijo[500], posfijo[500], pila[500], x[1], y[1], aux[1], num[20], op1[20], op2[20]; bool fin, exito = true; int i,j; i = 0; aux[0] = ' '; strcpy(posfijo,""); strcpy(pila,""); strcpy(num,""); strcpy(op1,""); strcpy(op2,""); strcpy(infijo,exprfp); while (i < strlen(infijo) && exito) { x[0] = infijo[i]; if (EsOperando(x[0]) || x[0] == 'x' || x[0] == 'y ' || x[0] == '.') { strcat(posfijo,x); if (!EsOperando(infijo[i+1]) && infijo[i+1] != ' .') strcat(posfijo,";"); } else { switch (x[0])

PostgreSQLf Página 195

{ case '(': strcat(pila,x); break; case ')': while (strlen(pila) != 0 && (pila[strlen(pila) - 1] != '(')) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; } if (strlen(pila) != 0) pila[strlen(pila) - 1] = '\0'; break; case '+': case '-': case '*': case '/': fin = false; while (strlen(pila) != 0 && !fin) { y[0] = pila[strlen(pila) - 1]; y[1] = '\0'; if (Prioridad(infijo[i]) <= Prioridad(y[0])) { pila[strlen(pila) - 1] = '\0'; strcat(posfijo,y); } else fin = true; } x[0] = infijo[i]; strcat(pila,x); break; default: exito = false; } } i++; } while (strlen(pila) != 0) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; } i = j = 0;

PostgreSQLf Página 196

x[0] = ' '; x[1] = '\0'; strcpy(pila,""); return (char *)&posfijo; } float evaluacion_Posfijo(char *posfijo, float valor ){ static char infijo[500], pila[500], x[1], aux[1], num[20], op1[20], op2[20]; int i,j,k; float resultado; i = 0; strcpy(pila,""); while (i < strlen(posfijo)) { x[0] = posfijo[i]; strcpy(num,""); strcpy(infijo,""); strcpy(op1,""); strcpy(op2,""); if(x[0] == 'y') { sprintf(num,"%f",(float)valor); strcat(pila,num); strcat(pila,";"); } else { if(EsOperando(x[0])) { k = i; while (posfijo[k] != ';' && posfijo[k] != '\0') { aux[0] = posfijo[k]; aux[1] = '\0'; strcat(num,aux); k++; } strcat(pila,num); strcat(pila,";"); i = k; } else { if(x[0] != ';') { char operador = x[0]; k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--; j = k + 1;

PostgreSQLf Página 197

while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op2,aux); j++; } pila[k+1] = '\0'; k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--; j = k + 1; while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op1,aux); j++; } pila[k+1] = '\0'; resultado = Operacion(operador, atof(op1), atof(op2)); sprintf(num,"%f",resultado); strcat(pila,num); strcat(pila,";"); } } } i++; } return atof(pila); } char posfijo[500]="", pila[500]="", aux[1]="", aux2 [500]="", num[20]="", op1[20] = "", op2[20] = "", ptr[20]="", x[1]=""; static Node * makeExprfpNode (ParseState *pstate, char *exprfp, N ode *cref) { int i=0,j=0,k=0,f=0; List *resultnode = NIL; strcpy(posfijo,exprfp); strcpy(pila,""); while (i < strlen(posfijo)) { x[0] = posfijo[i]; strcpy(num,"");

PostgreSQLf Página 198

strcpy(op1,""); strcpy(op2,""); if(!EsOperando(x[0]) && !EsOperador(x[0]) && x[0] != ';') { f = 0; while(posfijo[i] != ';' && posfijo[i] != '\0') { ptr[f] = posfijo[i]; f++; i++; } ptr[f]='\0'; strcat(pila,ptr); strcat(pila,";"); } else { if(EsOperando(x[0])) { k = i; while (posfijo[k] != ';' && posfijo[k] != '\0') { aux[0] = posfijo[k]; aux[1] = '\0'; strcat(num,aux); k++; } strcat(pila,num); strcat(pila,";"); i = k; } else { if(x[0] != ';') { k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0' && k >= 0) k--; j = k + 1; strcpy(aux2,pila); while (j < strlen(pila) && pila[j] != '\0' && pila[j] != ';') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op2,aux); j++; } pila[k+1] = '\0'; k = strlen(pila) - 2;

PostgreSQLf Página 199

while(pila[k] != ';' && pila[k] != '\0' && k >= 0) k--; j = k + 1; strcpy(aux2,pila); while (j < strlen(pila) && pila[j] != '\0' && pila[j] != ';') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op1,aux); j++; } pila[k+1] = '\0'; resultnode = OperTree(posfijo[i], op1, op2, cref, resultnode); strcat(pila,"><"); strcat(pila,";"); } } } i++; } return (Node *) llast(resultnode); } static Node * transformFuzzyExpr(ParseState *pstate, bool *isexp, Node *whereClause) { A_Expr *a = NULL; Node *l = NULL, *r = NULL, *result = NULL; int fptype; char *posfijo=""; if (whereClause != NULL) { if (IsA(whereClause,A_Expr)) { a = (A_Expr *) whereClause; l=a->lexpr; r=a->rexpr; if (l!=NULL) { if (IsA(l,A_Expr)) l = transformFuzzyExpr(pstate, isexp, l); else if (IsA(l,ColumnRef)) { if (IsA(r,ColumnRef)) {

PostgreSQLf Página 200

fptype = IsFuzzyPred((ColumnRef *) r); if (fptype != 0) { if (fptype==5) { posfijo = makePosfijo(GetFuzzyExpr(pstate,(ColumnRef *) r, 0) ); pstate->p_FuzzyPredExp = lappend(pstate->p_FuzzyPredExp,makeString(GetFuzzyExpr(pstate,(Col umnRef *) r, 0))); result = makeExprfpNode(pstate, posfijo, l); result = (Node *) makeA_Expr(AEXPR_AND, NIL, (Node *) makeSimpleA_Expr(AEXPR_OP, ">", result, (Node *) makeFA_Const(0), -1), (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", result, (Node * ) makeFA_Const(1), -1), -1); *isexp = true; return result; } } } else return whereClause; } } if (r!=NULL) { if (IsA(r,A_Expr)) r = transformFuzzyExpr(pstate, isexp, r); else return whereClause; } } } if(l != NULL) a->lexpr = l; if(r != NULL) a->rexpr = r; return (Node *)a; } static List* GetFuzzyExprNames(ParseState *pstate, Node *whereCl ause, List *fpNames) { Node *l, *r; A_Expr *a; int fptype; if(whereClause != NULL) {

PostgreSQLf Página 201

if(IsA(whereClause,A_Expr)) { a = (A_Expr *) whereClause; l = a->lexpr; r = a->rexpr; if (l != NULL) { if(IsA(l,A_Expr)) fpNames = GetFuzzyExprNames(pstate, l, fpNames); else { if(IsA(l,ColumnRef)) { if(IsA(r,ColumnRef)) { fptype = IsFuzzyPred((ColumnRef *) r); if (fptype == 5) { fpNames = lappend(fpNames,(Node *) makeString(GetFuzzyExpr(ps tate,(ColumnRef *) r, 1))); return fpNames; } } else { if(IsA(r,A_Expr)) { A_Expr *aux; aux = (A_Expr *) r; if(IsA(aux->rexpr,ColumnRef)) { fptype = IsFuzzyPred((ColumnRef *) aux->rexpr); if (fptype == 5) { fpNames = lappend(fpNames,(Node *) makeString(GetFuzzyExpr(ps tate,(ColumnRef *) aux->rexpr, 1))); return fpNames; } } } } } } } if(r != NULL) {

PostgreSQLf Página 202

if(IsA(r,A_Expr)) fpNames = GetFuzzyExprNames(pstate, r, fpNames); } } } return fpNames; } static List* GetFuzzyExprVars(ParseState *pstate, Node *whereCla use, List *vars) { Node *l, *r; A_Expr *a; int fptype; if(whereClause != NULL) { if(IsA(whereClause,A_Expr)) { a = (A_Expr *) whereClause; l = a->lexpr; r = a->rexpr; if (l != NULL) { if(IsA(l,A_Expr)) vars = GetFuzzyExprVars(pstate, l, vars); else { if(IsA(l,ColumnRef)) { if(IsA(r,ColumnRef)) { fptype = IsFuzzyPred((ColumnRef *) r); if (fptype == 5) { Node *node; ColumnRef *prueba = (ColumnRef *) l; char *name = strVal(linitial(prueba->fields)); node = colNameToVar(pstate, name, false, prueba->location) ; vars = lappend(vars, node); return vars; } } else { if(IsA(r,A_Expr)) { A_Expr *aux;

PostgreSQLf Página 203

aux = (A_Expr *) r; if(IsA(aux->rexpr,ColumnRef)) { fptype = IsFuzzyPred((ColumnRef *) aux->rexpr); if (fptype == 5) { Node *node; ColumnRef *prueba = (ColumnRef *) l; char *name = strVal(linitial(prueba->fields)); node = colNameToVar(pstate, name, false, prueba->location) ; vars = lappend(vars, node); return vars; } } } } } } } if(r != NULL) { if(IsA(r,A_Expr)) vars = GetFuzzyExprVars(pstate, r, vars); } } } return vars; } List *compNames; static Node* Transform_compqual(ParseState *pstate, Node *newWhe re, bool *iscomp) { Node *l = NULL, *r = NULL; A_Expr *a = NULL; if(newWhere != NULL) { if(IsA(newWhere,A_Expr)) { a = (A_Expr *) newWhere; l = a->lexpr; r = a->rexpr; if (l != NULL)

PostgreSQLf Página 204

{ if(IsA(l,A_Expr)) l = Transform_compqual(pstate, l, iscomp); else { if(IsA(l,ColumnRef)) { if(IsA(r,A_Expr)) { A_Expr *aux; aux = (A_Expr *) r; if(IsA(aux->rexpr,ColumnRef)) { if (IsFuzzyPred((ColumnRef *) aux->rexpr) != 0) { Node *result = NULL, *result1 = NULL; A_FuzzyComp *nc = makeNode(A_FuzzyComp); fuzzyIndex++; nc = GetFuzzyComp(pstate, strVal(aux->lexpr)); if(isfc) { Node *node; ColumnRef *prueba = (ColumnRef *) l; char *name = strVal(linitial(prueba->fields)); char *posfijo="", *posfijo1="", posfijo_r[100]; char min[20], max[20]; int i, j, k; bool bandera = false; a->rexpr = aux->rexpr; newWhere = (Node *) a; if(n->typefp == 4 || n->typefp == 5) elog(ERROR,"Incompatible types in Fuzzy Comparator "); if(nc->typefp != n->typefp) elog(ERROR,"Fuzzy Predicates and Fuzzy Comparators should be of the same type"); *iscomp = true;

PostgreSQLf Página 205

compNames = lappend(compNames,(Node *) nc); compNames = lappend(compNames,(Node *) n); compNames = lappend(compNames,(Node *) makeInteger(fuzzyIndex)) ; node = colNameToVar(pstate, name, false, prueba->location) ; compNames = lappend(compNames,node); switch(nc->typefp) { case 1: bandera = false; posfijo = makePosfijo(nc->minfp); j = 0; sprintf(min,"%d",(int)n->minfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i]; j++;

PostgreSQLf Página 206

} } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; if(bandera) result = makeExprfpNode(pstate, posfijo_r, l); else result = (Node *) makeFA_Const(evaluacion_Posfijo( posfijo,n->minfp)); bandera = false; posfijo1 = makePosfijo(nc->maxfp); j = 0; sprintf(max,"%d",(int)n->maxfp); for(i=0; i<strlen(posfijo1); i++) { if(posfijo1[i] == 'y') { for(k=0; k<strlen(max); k++) { posfijo_r[j] = max[k]; j++; } } else { if(posfijo1[i] == 'x') bandera = true; posfijo_r[j] = posfijo1[i]; j++; }

PostgreSQLf Página 207

} posfijo_r[strlen(max)+strlen(posfijo1)-1] = '\0'; if(bandera) result1 = makeExprfpNode(pstate, posfijo_r, l); else result1 = (Node *) makeFA_Const(evaluacion_Posfijo (posfijo1,n->maxfp)); result = (Node *) makeA_Expr(AEXPR_AND, NIL, (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, resu lt, -1), (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, resu lt1, -1), -1); //elog_node_display(NOTICE,"result",result,true); break; case 2: bandera = false; posfijo = makePosfijo(nc->maxfp); j = 0; sprintf(max,"%d",(int)n->maxfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0; k<strlen(max); k++) { posfijo_r[j] = max[k]; j++; }

PostgreSQLf Página 208

} else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(max)+strlen(posfijo)-1] = '\0'; if(bandera){ result = makeExprfpNode(pstate, posfijo_r, l); result = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, result, -1); } else result = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, (Node *) makeFA_Const(evaluacion_Posfijo(posfijo,n->maxfp)), -1); //elog_node_display(ERROR,"result",result,true); break; case 3: bandera = false; posfijo = makePosfijo(nc->minfp); j = 0; sprintf(min,"%d",(int)n->minfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') {

PostgreSQLf Página 209

for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; if(bandera){ result = makeExprfpNode(pstate, posfijo_r, l); result = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, result, -1); } else result = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, (Node *) makeFA_Const(evaluacion_Posfijo(posfijo,n->minfp)), -1); //elog_node_display(ERROR,"result",result,true); break; } } else{ if(!IsA(aux->lexpr,ColumnRef) && !IsA(aux->lexpr,A _Expr)) elog(ERROR,"Fuzzy comparator \"%s\" does not exist ", strVal(aux->lexpr)); } return result;

PostgreSQLf Página 210

} else { ColumnRef *msg = (ColumnRef *) aux->rexpr; elog(ERROR,"Fuzzy Predicate \"%s\" does not exist",strVal(linitial(ms g->fields))); } } else { if (IsA(aux->rexpr,A_Const)) { Node *result = NULL, *result1 = NULL; A_FuzzyComp *nc = makeNode(A_FuzzyComp); A_Const *c = (A_Const *) aux->rexpr; constIndex++; nc = GetFuzzyComp(pstate, strVal(aux->lexpr)); if(isfc) { Node *node; ColumnRef *prueba = (ColumnRef *) l; char *name = strVal(linitial(prueba->fields)); char *posfijo="", *posfijo1="", posfijo_r[100]; char min[20], max[20]; int i, j, k; bool bandera = false; float min1; a->rexpr = aux->rexpr; newWhere = (Node *) a; *iscomp = true; compNames = lappend(compNames,nc); compNames = lappend(compNames,aux->rexpr); compNames = lappend(compNames,(Node *) makeInteger(constIndex)) ; node = colNameToVar(pstate, name, false, prueba->location) ; compNames = lappend(compNames,node);

PostgreSQLf Página 211

switch(nc->typefp) { case 1: bandera = false; posfijo = makePosfijo(nc->minfp); j = 0; if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else { if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } sprintf(min,"%f",min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i];

PostgreSQLf Página 212

j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; if(bandera) result = makeExprfpNode(pstate, posfijo_r, l); else result = (Node *) makeFA_Const(evaluacion_Posfijo(posfijo,min1)); bandera = false; posfijo1 = makePosfijo(nc->maxfp); j = 0; sprintf(max,"%f",min1); for(i=0; i<strlen(posfijo1); i++) { if(posfijo1[i] == 'y') { for(k=0; k<strlen(max); k++) { posfijo_r[j] = max[k]; j++; } } else { if(posfijo1[i] == 'x') bandera = true; posfijo_r[j] = posfijo1[i]; j++;

PostgreSQLf Página 213

} } posfijo_r[strlen(max)+strlen(posfijo1)-1] = '\0'; if(bandera) result1 = makeExprfpNode(pstate, posfijo_r, l); else result1 = (Node *) makeFA_Const(evaluacion_Posfijo(posfijo1,min1)); result = (Node *) makeA_Expr(AEXPR_AND, NIL, (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, resu lt, -1), (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, resu lt1, -1), -1); //elog_node_display(NOTICE,"result",result,true); break; case 2: bandera = false; posfijo = makePosfijo(nc->maxfp); j = 0; if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else { if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } sprintf(max,"%f",min1); for(i=0; i<strlen(posfijo); i++)

PostgreSQLf Página 214

{ if(posfijo[i] == 'y') { for(k=0; k<strlen(max); k++) { posfijo_r[j] = max[k]; j++; } } else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(max)+strlen(posfijo)-1] = '\0'; if(bandera){ result = makeExprfpNode(pstate, posfijo_r, l); result = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, result, -1); } else result = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", l, (Node *) makeFA_Const(evaluacion_Posfijo(posfijo,min1)), -1) ; //elog_node_display(ERROR,"result",result,true); break; case 3: bandera = false;

PostgreSQLf Página 215

posfijo = makePosfijo(nc->minfp); j = 0; if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else { if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } sprintf(min,"%f",min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { if(posfijo[i] == 'x') bandera = true; posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0';

PostgreSQLf Página 216

if(bandera){ result = makeExprfpNode(pstate, posfijo_r, l); result = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, result, -1); } else result = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", l, (Node *) makeFA_Const(evaluacion_Posfijo(posfijo,min1)), -1) ; break; case 4: result = newWhere; break; } } else{ if(!IsA(aux->lexpr,ColumnRef) && !IsA(aux->lexpr,A _Expr)) elog(ERROR,"Fuzzy comparator \"%s\" does not exist ", strVal(aux->lexpr)); } return result; } } } } } } if(r != NULL) { if(IsA(r,A_Expr)) r = Transform_compqual(pstate, r, iscomp); else { if(IsA(r, ColumnRef)){ if(IsFuzzyPred((ColumnRef *) r) != 0) fuzzyIndex++; } else { if(IsA(r, A_Const)) constIndex++; }

PostgreSQLf Página 217

} } } } if(l != NULL) a->lexpr = l; if(r != NULL) a->rexpr = r; return (Node *)a; } static List* Transform_modqual(ParseState *pstate, Node *newWher e, bool *ismod, List *modNames) { Node *l, *r; A_Expr *a; if(newWhere != NULL) { if(IsA(newWhere,A_Expr)) { a = (A_Expr *) newWhere; l = a->lexpr; r = a->rexpr; if (l != NULL) { if(IsA(l,A_Expr)) modNames = Transform_modqual(pstate, l, ismod, modNames); else { if(IsA(l,ColumnRef)) { if(IsA(r,A_Expr)) { A_Expr *aux; aux = (A_Expr *) r; if(IsA(aux->rexpr,ColumnRef)) { if (IsFuzzyPred((ColumnRef *) aux->rexpr) != 0) { fuzzyIndex++; if(GetFuzzyMod(pstate, strVal(aux->lexpr))) { *ismod = true; modNames = lappend(modNames,aux->lexpr); modNames = lappend(modNames,(Node *) makeInteger(fuzzyIndex)); a->rexpr = aux->rexpr; newWhere = (Node *) a;

PostgreSQLf Página 218

} else { GetFuzzyComp(pstate, strVal(aux->lexpr)); if(!isfc) elog(ERROR,"Fuzzy modifier \"%s\" does not exist", strVal(aux->lexpr)); } return modNames; } else { ColumnRef *msg = (ColumnRef *) aux->rexpr; elog(ERROR,"Fuzzy Predicate \"%s\" does not exist",strVal(linitial(ms g->fields))); } } } } } } if(r != NULL) { if(IsA(r,A_Expr)) modNames = Transform_modqual(pstate, r, ismod, modNames); else if(IsA(r, ColumnRef)) if(IsFuzzyPred((ColumnRef *) r) != 0) fuzzyIndex++; } } } return modNames; }

Línea 3365: *newWhere = NULL; ListCell *l; bool ismod = false, isexp = false, iscomp = false; List *modNames = NULL, *fpNames = NULL, *vars = N ULL; compNames = NIL; newWhere = stmt->whereClause; fuzzyIndex = 0; modNames = Transform_modqual(pstate, newWhere, &ism od, modNames); fuzzyIndex = 0;

Línea 3393: fuzzyIndex = 0; constIndex = 0; newWhere = Transform_compqual(pstate, newWhere, &is comp); fpNames = GetFuzzyExprNames(pstate, stmt->whereClau se, fpNames);

PostgreSQLf Página 219

vars = GetFuzzyExprVars(pstate, stmt->whereClause, vars); qry->FuzzyComp = NIL; qry->hasFuzzyComp = iscomp; /* transform WHERE */ if (ismod) { pstate->p_FuzzyMod = modNames; newWhere = transformFuzzyExpr(pstate, &isexp, newW here); if (isexp) { ListCell *x; foreach(x, fpNames) { A_FuzzyPred *n = makeNode(A_FuzzyPred); Var *v = makeNode(Var); v = linitial(vars); pstate->p_numFuzzyPred++; n->type=T_A_FuzzyPred; n->pred= strVal(lfirst(x)); n->typefp= 5; n->exprfp = strVal(linitial(pstate->p_FuzzyPredE xp)); n->vno = v->varno; n->vattno = v->varattno; n->vtype = v->vartype; qry->FuzzyPredExp = lappend(qry->FuzzyPredExp, n ); list_delete_first(vars); list_delete_first(pstate->p_FuzzyPredExp); } pstate->p_hasFuzzyPred = true; //qual = transformWhereClause(pstate, newWhere, " WHERE"); } if(iscomp) { ListCell *x; foreach(x,compNames){ A_FuzzyComp *fc = makeNode(A_FuzzyComp); Node *n1=NULL; Node *n2=NULL; Var *v = makeNode(Var); fc = lfirst(x); x = lnext(x); n1 = lfirst(x); x = lnext(x); n2 = lfirst(x); x = lnext(x); v = lfirst(x); fc->vno = v->varno; fc->vattno = v->varattno; fc->vtype = v->vartype; qry->FuzzyComp = lappend(qry->FuzzyComp,fc); qry->FuzzyComp = lappend(qry->FuzzyComp,n1); qry->FuzzyComp = lappend(qry->FuzzyComp,n2);

PostgreSQLf Página 220

} } qual = transformWhereClause(pstate, newWhere, "WHE RE"); } else { newWhere = transformFuzzyExpr(pstate, &isexp, newW here); if (isexp) { ListCell *x; foreach(x, fpNames) { A_FuzzyPred *n = makeNode(A_FuzzyPred); Var *v = makeNode(Var); v = linitial(vars); pstate->p_numFuzzyPred++; n->type=T_A_FuzzyPred; n->pred= strVal(lfirst(x)); n->typefp= 5; n->exprfp = strVal(linitial(pstate->p_FuzzyPredE xp)); n->vno = v->varno; n->vattno = v->varattno; n->vtype = v->vartype; qry->FuzzyPredExp = lappend(qry->FuzzyPredExp, n ); list_delete_first(vars); list_delete_first(pstate->p_FuzzyPredExp); } pstate->p_hasFuzzyPred = true; // qual = transformWhereClause(pstate, newWhere, " WHERE"); } if(iscomp) { ListCell *x; foreach(x,compNames){ A_FuzzyComp *fc = makeNode(A_FuzzyComp); Node *n1=NULL; Node *n2=NULL; Var *v = makeNode(Var); fc = lfirst(x); x = lnext(x); n1 = lfirst(x); x = lnext(x); n2 = lfirst(x); x = lnext(x); v = lfirst(x); fc->vno = v->varno; fc->vattno = v->varattno; fc->vtype = v->vartype; qry->FuzzyComp = lappend(qry->FuzzyComp,fc); qry->FuzzyComp = lappend(qry->FuzzyComp,n1); qry->FuzzyComp = lappend(qry->FuzzyComp,n2); } }

PostgreSQLf Página 221

if(isexp || iscomp) qual = transformWhereClause(pstate, newWhere, "WH ERE"); else qual = transformWhereClause(pstate, stmt->whereCl ause, "WHERE"); }

Línea 3588: compNames = NIL; fuzzyIndex = 0; constIndex = 0;

PostgreSQLf Página 222

Anexo C

Extensión del Traffic Cop

PostgreSQLf Página 223

*) Modificaciones al /src/backend/tcop/utility.c Línea 46: #include "commands/fuzzycomp.h" #include "commands/fuzzyconn.h" #include "commands/fuzzymod.h" #include "commands/fuzzypred.h" #include "commands/fuzzyquan.h"

Línea 326: case T_CreateFuzzyCompStmt: case T_CreateFuzzyConnStmt: case T_CreateFuzzyModStmt: case T_CreateFuzzyPredStmt: case T_CreateFuzzyQuanStmt:

Línea 1030: case T_CreateFuzzyCompStmt: CreateFuzzyComparate((CreateFuzzyCompStmt *) parse tree); break; /* * ******************************** CONNECTOR state ments **** */ case T_CreateFuzzyConnStmt: CreateFuzzyConnector((CreateFuzzyConnStmt *) parse tree); break; /* * ******************************** MODIFIER state ments **** */ case T_CreateFuzzyModStmt: CreateFuzzyModifier((CreateFuzzyModStmt *) parsetr ee); break; /* * ******************************** FUZZY statemen ts **** */ case T_CreateFuzzyPredStmt: CreateFuzzyPredicate((CreateFuzzyPredStmt *) parse tree); break; /* * ****************************** QUANTIFIER state ments **** */ case T_CreateFuzzyQuanStmt: CreateFuzzyQuantifier((CreateFuzzyQuanStmt *) pars etree); break;

Línea 1768: case T_CreateFuzzyCompStmt: tag = "CREATE FUZZY COMPARATOR"; break; case T_CreateFuzzyConnStmt: tag = "CREATE FUZZY CONNECTOR"; break;

PostgreSQLf Página 224

case T_CreateFuzzyModStmt: tag = "CREATE FUZZY MODIFIER"; break; case T_CreateFuzzyPredStmt: tag = "CREATE FUZZY PREDICATE"; break; case T_CreateFuzzyQuanStmt: tag = "CREATE FUZZY QUANTIFIER"; break;

Línea 2158: /* Create Fuzzy Comparator */ case T_CreateFuzzyCompStmt: lev = LOGSTMT_DDL; break; /* Create Fuzzy Connector */ case T_CreateFuzzyConnStmt: lev = LOGSTMT_DDL;

break; /* Create Fuzzy Modifier */ case T_CreateFuzzyModStmt: lev = LOGSTMT_DDL; break; /* Create Fuzzy Predicate */ case T_CreateFuzzyPredStmt: lev = LOGSTMT_DDL; break; /* Create Fuzzy Quantifier */ case T_CreateFuzzyQuanStmt: lev = LOGSTMT_DDL; break;

*) Nuevo archivo en /src/backend/commands/fuzzycomp.c: /*------------------------------------------------- ------------------------ * * fuzzycomp.c * Commands for manipulating fuzzy comparates. * * * $PostgreSQL: pgsql/src/backend/commands/fuzzycom p.c * *------------------------------------------------- ------------------------ */ #include "postgres.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_fuzzycomp.h"

PostgreSQLf Página 225

#include "catalog/pg_type.h" #include "commands/fuzzycomp.h" #include "storage/lock.h" #include "access/heapam.h" #include "access/genam.h" #include "access/xact.h" #include "commands/comment.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" //These are the several kinds of fuzzy predicates t he user can create #define NO_INFINITE 1 #define INFINITE_BEG 2 #define INFINITE_LAST 3 #define EXTENSION 4 static bool EsOperador(char x) { return(x == '+' || x == '-' || x == '*' || x == '/'); } static bool EsOperando(char x) { return(x == '0' || x == '1' || x == '2' || x == '3' || x == '4' || x == '5' || x == '6' || x == '7' || x == '8' || x == '9'); } /** Examine if names and membership degrees list ha ve a value. Rossodivita **/ static void examine_compfplist(List *compfplist, ArrayType **compfpNames) { int listCount = list_length(compfplist); Datum *fpNames; ListCell *x; int i, indice; bool havefp = false; fpNames = (Datum *) palloc0(listCount * sizeof(Dat um)); indice = 0; foreach(x, compfplist) { DefElem *defel = (DefElem *) lfirst(x); if(defel->arg) {

PostgreSQLf Página 226

char cadena[100], *ptr1, *ptr2; int contador = 0, i; strcpy(cadena,strVal(defel->arg)); for(i = 0; i < strlen(cadena); i++) if(cadena[i] == '/') contador++; if(contador != 1 || cadena[0] == '/' || cadena[strlen(cadena)-1] == '/') elog(ERROR,"Syntax error, the correct parameters should be '(x,y)/GR'"); ptr1 = strtok( cadena , "/" ); ptr2 = strtok( NULL, "/" ); if(atof(ptr2) <= 0 || atof(ptr2)>1) elog(ERROR,"Syntax error, the degree of membership should be > 0 and <=1"); contador = 0; for(i = 0; i < strlen(ptr1); i++) if(ptr1[i] == ',') contador++; if(contador != 1 || ptr1[0] == ',' || ptr1[strlen(ptr1)-1] == ',') elog(ERROR,"Syntax error, the correct parameters should be '(x,y)/GR'"); ptr1 = strtok( ptr1 , "," ); ptr2 = strtok( NULL, "," ); if(ptr1[0] != '(' || strlen(ptr1) <= 1 || ptr2[strlen(ptr2)-1] != ')' || strlen(ptr2) <= 1) elog(ERROR,"Syntax error, the correct parameters should be '(x,y)/GR'"); else { fpNames[indice] = DirectFunctionCall1(textin,CStringGetDatum(strVal(d efel->arg))); havefp = true; indice++; } } } if (havefp) { for (i = 0; i < listCount; i++) { if (fpNames[i] == PointerGetDatum(NULL)){ fpNames[i] = DirectFunctionCall1(textin,CStringGetDatum("")); } } *compfpNames = construct_array(fpNames, listCount , TEXTOID,

PostgreSQLf Página 227

-1, false, 'i'); } else { *compfpNames = NULL; } } void eval_expr(char *cad) { int i, cont = 0, cont2 = 0; for(i=0; i < strlen(cad);i++) { if(cad[i] == 'x' || cad[i] == 'y') cont++; if(cad[i] == '(') cont2++; if(cad[i] == ')') cont2--; if(!EsOperando(cad[i])) { if(cad[i] != '.' && (cad[i] != 'x' && cad[i] != 'y') && cad[i] != '(' && cad[i] != ')' && !EsOperador(cad[i])) elog(ERROR,"Sintaxt Error, it only allows the variable X or variable Y"); } if((i == 0 && cad[i] == '.') || (i == 0 && cad[i] == ')')) { elog(ERROR,"Sintaxt Error, wrong expression form at"); } if((i==0 && i+1 < strlen(cad) && !EsOperador(cad[ i+1]) && (cad[i] == 'x' || cad[i] == 'y')) || (i==0 && i+1 < strlen(cad) && !EsOperando(cad[i +1]) && (cad[i+1] != 'x' && cad[i+1] != 'y') && cad[i+1] != '(' && cad[i] == '(')) elog(ERROR,"Sintaxt Error, wrong expression form at"); if(i > 0) { if( (!EsOperando(cad[i-1]) && cad[i] == '.') || (!EsOperando(cad[i-1]) && cad[i-1] != ')' && (cad[i-1] != 'x' && cad[i-1] != 'y') && cad[i] == ' )') || (!EsOperador(cad[i-1]) && cad[i-1] != '(' && cad[i] == '(') || (!EsOperador(cad[i-1]) && cad[i-1] != '(' && (cad[i] == 'x' || cad[i] == 'y') ) ) elog(ERROR,"Sintaxt Error, wrong expression format"); if(i+1 < strlen(cad)) { if( (!EsOperando(cad[i+1]) && cad[i] == '.') || (!EsOperador(cad[i+1]) && cad[i+1] != ')' && cad[i] == ')') || (!EsOperando(cad[i+1]) && (cad[i+1] != 'x' && cad[i+1] != 'y') && cad[i+1] != '(' && cad[i ] == '(') ||

PostgreSQLf Página 228

(!EsOperador(cad[i+1]) && cad[i+1] != ')' && (cad[i] == 'x' || cad[i] == 'y') ) ) elog(ERROR,"Sintaxt Error, wrong expression format"); } if((i == strlen(cad)-1) && !EsOperando(cad[i]) & & (cad[i] != 'x' && cad[i] != 'y') && cad[i] != ')') elog(ERROR,"Sintaxt Error, wrong expression format"); } } if(cont == 0) elog(ERROR,"Sintaxt Error, expression needs the v ariable X or variable Y"); if(cont2 != 0) elog(ERROR,"Sintaxt Error, wrong expression forma t"); } /* * CREATE FUZZY COMPARATE */ void CreateFuzzyComparate(CreateFuzzyCompStmt *stmt) { Relation pg_fuzzycomp_rel; TupleDesc pg_fuzzycomp_dsc; HeapTuple tuple; Datum new_record[Natts_pg_fuzzycomp]; char new_record_nulls[Natts_pg_fuzzycomp]; Oid fuzzycompid; char *namecomp; int2 begd=0; int2 endd=0; char *min; char *core1; char *core2; char *max; int typecomp=0; ArrayType *compfclist; /** Compare fuzzy predicate . Rossodivita **/ char *disd; /** Discrete Domain. Rossodivita **/ ScanKeyData key; SysScanDesc fpscan; disd = min = core1 = core2 = max = "NULL"; compfclist = NULL; namecomp=stmt->comp; switch (stmt->typecomp) { case NO_INFINITE: typecomp=NO_INFINITE; begd=stmt->begd; endd=stmt->endd; min=stmt->min; core1=stmt->core1; core2=stmt->core2;

PostgreSQLf Página 229

max=stmt->max; eval_expr(min); eval_expr(core1); eval_expr(core2); eval_expr(max); break; case INFINITE_BEG: typecomp=INFINITE_BEG; begd=stmt->begd; endd=stmt->endd; core2=stmt->core2; max=stmt->max; eval_expr(core2); eval_expr(max); break; case INFINITE_LAST: typecomp=INFINITE_LAST; begd=stmt->begd; endd=stmt->endd; min=stmt->min; core1=stmt->core1; eval_expr(min); eval_expr(core1); break; /** Fuzzy Predicate by Extension. Rossodivita **/ case EXTENSION: typecomp=EXTENSION; disd=stmt->disd; examine_compfplist(stmt->compfclist, &compfclist); break; } /* * Check the pg_fuzzycomp relation to be certain t he fuzzy comparate doesn't already * exist. */ pg_fuzzycomp_rel = heap_open(RelationFuzzyCompId, RowExclusiveLock); pg_fuzzycomp_dsc = RelationGetDescr(pg_fuzzycomp_r el); ScanKeyInit(&key, Anum_pg_fuzzycomp_compname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(namecomp)); fpscan = systable_beginscan(pg_fuzzycomp_rel, 0, t rue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzycomp pg_fuzzycomp = (Form_pg_fuzzyc omp) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzycomp->compname), namecom p) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Comparate \"%s\" for relation \"%s\" already exists",

PostgreSQLf Página 230

namecomp, RelationGetRelationName(pg_fuzzycomp_rel)))); } systable_endscan(fpscan); MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nu lls)); new_record[Anum_pg_fuzzycomp_compname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt- >comp)); new_record[Anum_pg_fuzzycomp_compbegd - 1] = begd; new_record[Anum_pg_fuzzycomp_compendd - 1] = endd; if(stmt->typecomp != EXTENSION) { new_record[Anum_pg_fuzzycomp_compmin - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->min)); new_record[Anum_pg_fuzzycomp_compcore1 - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->core1)); new_record[Anum_pg_fuzzycomp_compcore2 - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->core2)); new_record[Anum_pg_fuzzycomp_compmax - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->max)); } else { new_record[Anum_pg_fuzzycomp_compmin - 1] = DirectFunctionCall1(namein, CStringGetDatum(min)); new_record[Anum_pg_fuzzycomp_compcore1 - 1] = DirectFunctionCall1(namein, CStringGetDatum(core1)); new_record[Anum_pg_fuzzycomp_compcore2 - 1] = DirectFunctionCall1(namein, CStringGetDatum(core2)); new_record[Anum_pg_fuzzycomp_compmax - 1] = DirectFunctionCall1(namein, CStringGetDatum(max)); } new_record[Anum_pg_fuzzycomp_comptype - 1] = typec omp; /** Insert new Fuzzy Predicate By Extension. Rosso divita **/ if(stmt->typecomp == EXTENSION) { new_record[Anum_pg_fuzzycomp_compdisd - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt ->disd));

PostgreSQLf Página 231

if (PointerGetDatum(compfclist) != PointerGetDatu m(NULL)) { new_record[Anum_pg_fuzzycomp_complist -1] = PointerGetDatum(compfclist); } } else new_record_nulls[Anum_pg_fuzzycomp_complist - 1] = 'n'; if(stmt->typecomp != EXTENSION) new_record_nulls[Anum_pg_fuzzycomp_ compdisd - 1] = 'n'; tuple = heap_formtuple(pg_fuzzycomp_dsc, new_recor d, new_record_nulls); /* * Insert new record in the pg_fuzzycomp table */ fuzzycompid = simple_heap_insert(pg_fuzzycomp_rel, tuple); CatalogUpdateIndexes(pg_fuzzycomp_rel, tuple); /* * Close pg_fuzzycomp, but keep lock till commit ( this is important to * prevent any risk of deadlock failure while upda ting flat file) */ heap_close(pg_fuzzycomp_rel, NoLock); }

*) Nuevo archivo en /src/backend/commands/fuzzyconn.c: /*------------------------------------------------- ------------------------ * * fuzzyconn.c * Commands for manipulating fuzzy connector. * * * $PostgreSQL: pgsql/src/backend/commands/fuzzycon n.c * *------------------------------------------------- ------------------------ */ #include "postgres.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_fuzzyconn.h" #include "catalog/pg_type.h" #include "commands/fuzzyconn.h" #include "storage/lock.h" #include "access/heapam.h" #include "access/genam.h"

PostgreSQLf Página 232

#include "access/xact.h" #include "commands/comment.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" /* * CREATE FUZZY CONNECTOR */ void CreateFuzzyConnector(CreateFuzzyConnStmt *stmt) { Relation pg_fuzzyconn_rel; TupleDesc pg_fuzzyconn_dsc; HeapTuple tuple; Datum new_record[Natts_pg_fuzzyconn]; char new_record_nulls[Natts_pg_fuzzyconn]; Oid fuzzyconnid; char *nameconn, *exprconn; ScanKeyData key; SysScanDesc fpscan; nameconn = stmt->conn; exprconn = stmt->connexpr; /* * Check the pg_fuzzyconn relation to be certain t he fuzzy comparate doesn't already * exist. */ pg_fuzzyconn_rel = heap_open(RelationFuzzyConnId, RowExclusiveLock); pg_fuzzyconn_dsc = RelationGetDescr(pg_fuzzyconn_r el); ScanKeyInit(&key, Anum_pg_fuzzyconn_connname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(nameconn)); fpscan = systable_beginscan(pg_fuzzyconn_rel, 0, t rue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzyconn pg_fuzzyconn = (Form_pg_fuzzyc onn) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzyconn->connname), namecon n) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Connector \"%s\" for relation \"%s\" already exists", nameconn, RelationGetRelationName(pg_fuzzyconn_rel)))); } systable_endscan(fpscan);

PostgreSQLf Página 233

MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nu lls)); new_record[Anum_pg_fuzzyconn_connname - 1] = DirectFunctionCall1(namein, CStringGetDatum(namec onn)); new_record[Anum_pg_fuzzyconn_connexpr - 1] = DirectFunctionCall1(namein, CStringGetDatum(exprc onn)); tuple = heap_formtuple(pg_fuzzyconn_dsc, new_recor d, new_record_nulls); /* * Insert new record in the pg_fuzzyconn table */ fuzzyconnid = simple_heap_insert(pg_fuzzyconn_rel, tuple); CatalogUpdateIndexes(pg_fuzzyconn_rel, tuple); /* * Close pg_fuzzyconn, but keep lock till commit ( this is important to * prevent any risk of deadlock failure while upda ting flat file) */ heap_close(pg_fuzzyconn_rel, NoLock); }

*) Nuevo archivo en /src/backend/commands/fuzzymod.c: /*------------------------------------------------- -------- * * fuzzymod.c * Commands for manipulating fuzzy modifiers. * * * $PostgreSQL:pgsql/src/backend/commands/fuzzymod. c * *------------------------------------------------- -------- */ #include "postgres.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_fuzzymod.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_type.h" #include "commands/fuzzymod.h" #include "commands/fuzzypred.h" #include "storage/lock.h" #include "access/heapam.h" #include "access/genam.h" #include "access/xact.h" #include "commands/comment.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h"

PostgreSQLf Página 234

#include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "nodes/print.h" /* * CREATE FUZZY MODIFIER */ void CreateFuzzyModifier(CreateFuzzyModStmt *stmt) { Relation pg_fuzzymod_rel, pg_fuzzypred_rel; TupleDesc pg_fuzzymod_dsc, pg_fuzzypred_dsc; HeapTuple tuple; Datum new_record[Natts_pg_fuzzymod]; char new_record_nulls[Natts_pg_fuzzymod]; Oid fuzzymodid; char *modname, *norm="", *firstarg="", *secarg="" ; int2 modtype=0; int2 power=0; ScanKeyData key; SysScanDesc fpscan; bool isfuzzypred = false; modname=stmt->name; switch (stmt->modtype) { case 1: modtype = 1; power = stmt->power; break; case 2: modtype = 2; power = stmt->power; if((strcmp(stmt->norm,"min") == 0) || (strcmp(st mt->norm,"product") == 0) || (strcmp(stmt->norm,"dproduct") == 0) || (strcmp(stmt->norm,"bproduct") == 0) || (strcmp(stmt->norm,"hproduct") == 0) || (strcmp(stmt->norm,"yfamily") == 0) || (strcmp(stmt->norm,"dpfamily") == 0) || (strcmp(stmt->norm,"ffamily") == 0) || (strcmp(stmt->norm,"eproduct") == 0) || (strcmp(stmt->norm,"max") == 0) || (strcmp(stmt->norm,"sproduct") == 0) || (strcmp(stmt->norm,"dsum") == 0) || (strcmp(stmt->norm,"bsum") == 0) || (strcmp(s tmt->norm,"esum") == 0) || (strcmp(stmt->norm,"sfamily") == 0) || (strcmp(stmt->norm,"cyfamily") == 0) || (strcmp(stmt->norm,"cdpfamily") == 0) || (strcmp(stmt->norm,"cffamily") == 0)) norm = stmt->norm; else elog(ERROR,"T-norm or T-conorm \"%s\" does not exist", stmt->norm); firstarg = stmt->firstarg; secarg = stmt->secarg; break;

PostgreSQLf Página 235

case 3: modtype = 3; power = stmt->power; break; } /* * Check the pg_fuzzymod relation to be certain th e fuzzy modifier doesn't already * exist. */ pg_fuzzymod_rel = heap_open(RelationFuzzyModId, RowExclusiveLock); pg_fuzzymod_dsc = RelationGetDescr(pg_fuzzymod_rel ); ScanKeyInit(&key, Anum_pg_fuzzymod_modname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(modname)); fpscan = systable_beginscan(pg_fuzzymod_rel, 0, tr ue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzymod pg_fuzzymod = (Form_pg_fuzzymod ) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzymod->modname), modname) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Modifier \"%s\" for relation \"%s\" already exists", modname, RelationGetRelationName(pg_fuzzymod_rel)))); } systable_endscan(fpscan); /* * Check if fuzzy pred of t-norms or t-conorms exi st */ pg_fuzzypred_rel = heap_open(RelationFuzzyPredId, RowExclusiveLock); pg_fuzzypred_dsc = RelationGetDescr(pg_fuzzypred_r el); if(modtype == 2) { ScanKeyInit(&key, Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(modname)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext( fpscan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzy pred) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzypred->predname), modnam e) == 0) isfuzzypred = true; }

PostgreSQLf Página 236

if(!isfuzzypred) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Predicate \"%s\" for relation \"%s\" not exists", modname, RelationGetRelationName(pg_fuzzypred_rel)))); systable_endscan(fpscan); } MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nu lls)); new_record[Anum_pg_fuzzymod_modname - 1] = DirectFunctionCall1(namein, CStringGetDatum(modna me)); new_record[Anum_pg_fuzzymod_modpower - 1] = power; new_record[Anum_pg_fuzzymod_modtype - 1] = modtype ; if (modtype == 2) { new_record[Anum_pg_fuzzymod_modnorms - 1] = DirectFunctionCall1(namein, CStringGetDatum(norm) ); new_record[Anum_pg_fuzzymod_modfirstarg - 1] = DirectFunctionCall1(namein, CStringGetDatum(first arg)); new_record[Anum_pg_fuzzymod_modsecarg - 1] = DirectFunctionCall1(namein, CStringGetDatum(secar g)); } else { new_record_nulls[Anum_pg_fuzzymod_modnorms - 1] = 'n'; new_record_nulls[Anum_pg_fuzzymod_modfirstarg - 1 ] = 'n'; new_record_nulls[Anum_pg_fuzzymod_modsecarg - 1] = 'n'; } tuple = heap_formtuple(pg_fuzzymod_dsc, new_record , new_record_nulls); /* * Insert new record in the pg_fuzzymod table */ fuzzymodid = simple_heap_insert(pg_fuzzymod_rel, t uple); CatalogUpdateIndexes(pg_fuzzymod_rel, tuple); /* * Close pg_fuzzypred, but keep lock till commit ( this is important to * prevent any risk of deadlock failure while upda ting flat file) */ heap_close(pg_fuzzymod_rel, NoLock); heap_close(pg_fuzzypred_rel, NoLock); }

PostgreSQLf Página 237

*) Nuevo archivo en /src/backend/commands/fuzzypred.c: /*------------------------------------------------- ------------------------ * * fuzzypred.c * Commands for manipulating fuzzy predicates. * * * $PostgreSQL: pgsql/src/backend/commands/fuzzypre d.c * *------------------------------------------------- ------------------------ */ #include "postgres.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_type.h" #include "commands/fuzzypred.h" #include "storage/lock.h" #include "access/heapam.h" #include "access/genam.h" #include "access/xact.h" #include "commands/comment.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/print.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/int8.h" /*Armando Bracho*/ #include "executor/executor.h" /*Armando Bracho*/ //These are the several kinds of fuzzy predicates t he user can create #define NO_INFINITE 1 #define INFINITE_BEG 2 #define INFINITE_LAST 3 #define EXTENSION 4 #define EXPRESSION 5 /*Checks a Qual for fuzzy predicates. If one is fou nd it stores the Fuzzy predicate values into an fcinfo structure that is passed on to the Vali dateFuzzyPred function that calculates the Memb Degree*/ float grmembFuzzyPred (List *qual, ExprContext *econtext) { ListCell *l, *arg; float grmemb, maxgrmemb = 0; foreach(l, qual) {

PostgreSQLf Página 238

ExprState *clause = (ExprState *) lfirst(l); FuncExprState *fcache = (FuncExprState *) clause; FunctionCallInfoData fcinfo; int i = 0; InitFunctionCallInfoData(fcinfo, &(fcache->func), 0, NULL, NULL); if(clause->type == T_BoolExprState) { ListCell *bol = list_head(fcache->args); //bol = lnext(bol); ExprState *argstate2 = (ExprState *) lfirst(bol ); fcache = (FuncExprState *) argstate2; InitFunctionCallInfoData(fcinfo, &(fcache->func) , 0, NULL, NULL); } foreach(arg, fcache->args) { ExprState *argstate = (ExprState *) lfirst(arg) ; fcinfo.arg[i] = ExecEvalExpr(argstate, econtext, &fcinfo.argnull[i], NULL); i++; if(argstate->expr->type == T_A_FuzzyPred) { A_FuzzyPred *n = (A_FuzzyPred *) argstate->expr; fcinfo.compfplist = n->compfplist; fcinfo.arg[i] = n->core1; i++; fcinfo.arg[i] = n->core2; i++; fcinfo.arg[i] = n->maxfp; fcinfo.typefp = n->typefp; grmemb = ValidateFuzzyPred(fcinfo); if(grmemb > maxgrmemb) maxgrmemb = grmemb; } } } if(!qual) return 1; return maxgrmemb; } /*Calculates the Memb Degree of a value from a fuzz y predicate*/ float ValidateFuzzyPred (FunctionCallInfoData fcinfo) { ListCell *l; char s1[100], s2[10] = "{/\n\t}", *ptr, GR[20], * varfp; if(fcinfo.flinfo->fn_addr == numeric_eq)

PostgreSQLf Página 239

fcinfo.arg[0] = DatumGetFloat8(DirectFunctionCall1(numeric_float8, fcinfo.arg[0])); if(fcinfo.flinfo->fn_addr == int8eq) fcinfo.arg[0] = DatumGetInt64(DirectFunctionCall1 (int8up, fcinfo.arg[0])); if(fcinfo.flinfo->fn_addr == int4eq) fcinfo.arg[0] = DatumGetInt32(DirectFunctionCall1 (int4up, fcinfo.arg[0])); if(fcinfo.typefp == 4) varfp = DatumGetCString(DirectFunctionCall1(textout,fcinfo. arg[0])); switch (fcinfo.typefp) { case 1: if (fcinfo.arg[0] < fcinfo.arg[2]) return (fcinfo.arg[0] - fcinfo.arg[1]*1.0)/(fcinfo.arg[2] - fcinfo.arg[1]); if (fcinfo.arg[0] >= fcinfo.arg[2] && fcinfo.arg [0] <= fcinfo.arg[3]) return 1; else { if (fcinfo.arg[0] >= fcinfo.arg[3] && fcinfo.arg[0] < fcinfo.arg[4]) return (fcinfo.arg[4]*1.0 - fcinfo.arg[0])/(fcinfo.arg[4] - fcinfo.arg[3]); else return 0; } break; case 2: if ((fcinfo.arg[0] >= fcinfo.arg[3]) && (fcinfo.arg[0] < fcinfo.arg[4])) return (fcinfo.arg[4]*1.0 - fcinfo.arg[0])/(fcinfo.arg[4] - fcinfo.arg[3]); if(fcinfo.arg[0] <= fcinfo.arg[3]) return 1; else return 0; break; case 3: if (fcinfo.arg[0] > fcinfo.arg[1] && fcinfo.arg[ 0] <= fcinfo.arg[2]) return (fcinfo.arg[0] - fcinfo.arg[1]*1.0)/(fcinfo.arg[2] - fcinfo.arg[1]); if(fcinfo.arg[0] > fcinfo.arg[2]) return 1; else return 0; break; case 4: { foreach(l, fcinfo.compfplist) { char *cad = (char *) lfirst(l); strcpy(s1, cad); ptr = strtok( s1, s2 ); cad = ptr; while( (ptr = strtok( NULL, s2 )) != NULL ) {

PostgreSQLf Página 240

if(strcmp(cad,varfp) == 0) strcpy(GR,ptr); } } return atof(GR); } break; } } /** Examine if names and membership degrees list ha ve a value. Rossodivita **/ static void examine_compfplist(List *compfplist, ArrayType **compfpNames) { int listCount = list_length(compfplist); Datum *fpNames; ListCell *x; int i; bool havefp = false; fpNames = (Datum *) palloc0(listCount * sizeof(Dat um)); i = 0; foreach(x, compfplist) { DefElem *defel = (DefElem *) lfirst(x); if(defel->arg) { /**verify that the syntax is correct. Rossodivit a**/ char cad[500]; int j,cont; cont = 0; strcpy(cad,strVal(defel->arg)); for(j=0; j < strlen(cad); j++) { if(cad[j] == '/') cont++; } if (cont == 1) { if(cad[0] == '/' || cad[strlen(cad) - 1] == '/') elog(ERROR,"Syntax error, the correct parameters should be 'name/GR'"); else { char *ptr; /**verify that the degree of membership that between 0 and 1. Rossodivita**/ ptr = strtok( cad, "/" ); while ( (ptr = strtok( NULL, "/" )) != NULL ) {

PostgreSQLf Página 241

if ( (atof(ptr) <= 0) || (atof(ptr) > 1) ) elog(ERROR,"Syntax error, the degree of membership should be > 0 and <=1"); else { fpNames[i] = DirectFunctionCall1(textin, CStringGetDatum(strVal(defel->arg))); havefp = true; } } } } else elog(ERROR,"Syntax error, the correct parameters should be 'name/GR'"); } i++; } if (havefp) { for (i = 0; i < listCount; i++) { if (fpNames[i] == PointerGetDatum(NULL)) fpNames[i] = DirectFunctionCall1(textin, CStringGetDatum("")); } *compfpNames = construct_array(fpNames, listCount , TEXTOID, -1, false, 'i'); } else { *compfpNames = NULL; } } bool EsOperando(char x) { return (x == '0' || x == '1' || x == '2' || x == '3' || x == '4' || x == '5' || x == '6' || x == '7' || x == '8' || x == '9'); } bool EsOperador(char x) { return (x == '+' || x == '-' || x == '*' || x == '/'); } int Prioridad(char x) { switch (x)

PostgreSQLf Página 242

{ case '+': case '-': return 1; break; case '*': case '/': return 2; break; default: return 0; } } float Operacion(char operador, float operando1, float ope rando2) { float res = 0.0; switch (operador) { case '+': res = operando1 + operando2; break; case '-': res = operando1 - operando2; break; case '*': res = operando1 * operando2; break; case '/': res = operando1 / operando2; break; } return res; } A_Const * makeFA_Const(float value) { A_Const *cons = makeNode(A_Const); char *strval; strval = (char*) malloc(20*sizeof(char)); cons->val.val.str = (char*) malloc(20*sizeof(char) ); sprintf(strval,"%f",value); cons->val.type = T_Float; strcpy(cons->val.val.str,strval); return cons; } List * OperTree(char x, char *op1, char *op2, Node *cref, List *stack) { Node *auxnode = NULL, *auxnode2 = NULL; float lexpr,rexpr; lexpr = atof(op1); rexpr = atof(op2);

PostgreSQLf Página 243

if( (atof(op1)!=0) && (atof(op2)!=0) ) { switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+",(Node *) makeFA_Cons t(lexpr), (Node *) makeFA_Const(rexpr), -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-",(Node *) makeFA_Cons t(lexpr), (Node *) makeFA_Const(rexpr), -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*",(Node *) makeFA_Cons t(lexpr), (Node *) makeFA_Const(rexpr), -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/",(Node *) makeFA_Cons t(lexpr), (Node *) makeFA_Const(rexpr), -1)); break; } } else if (atof(op1)!=0) { if (!strcmp(op2,"><")) { auxnode = (Node *) llast(stack); stack = list_delete_ptr(stack,llast(stack)); switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+",(Node *) makeFA_Cons t(lexpr), (Node *) auxnode, -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-",(Node *) makeFA_Cons t(lexpr), (Node *) auxnode, -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*",(Node *) makeFA_Cons t(lexpr), (Node *) auxnode, -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/",(Node *) makeFA_Cons t(lexpr), (Node *) auxnode, -1)); break; } } else {

PostgreSQLf Página 244

switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+",(Node *) makeFA_Cons t(lexpr), (Node *) cref, -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-",(Node *) makeFA_Cons t(lexpr), (Node *) cref, -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*",(Node *) makeFA_Cons t(lexpr), (Node *) cref, -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/",(Node *) makeFA_Cons t(lexpr), (Node *) cref, -1)); break; } } } else if (atof(op2)!=0) { if (!strcmp(op1,"><")) { auxnode = (Node *) llast(stack); stack = list_delete_ptr(stack,llast(stack)); switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+",(Node *) auxnode, (N ode *) makeFA_Const(rexpr), -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-",(Node *) auxnode, (N ode *) makeFA_Const(rexpr), -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*",(Node *) auxnode, (N ode *) makeFA_Const(rexpr), -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/",(Node *) auxnode, (N ode *) makeFA_Const(rexpr), -1)); break; } } else { switch (x) {

PostgreSQLf Página 245

case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *) cref, (Nod e *) makeFA_Const(rexpr), -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-", (Node *) cref, (Nod e *) makeFA_Const(rexpr), -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *) cref, (Nod e *) makeFA_Const(rexpr), -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/", (Node *) cref, (Nod e *) makeFA_Const(rexpr), -1)); break; } } } else if(!(strcmp(op1,"><")) && !(strcmp(op2,"><")) ) { auxnode2 = (Node *) llast(stack); stack = list_delete_ptr(stack,llast(stack)); auxnode = (Node *) llast(stack); stack = list_delete_ptr(stack,llast(stack)); switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+",(Node *) auxnode, (N ode *) auxnode2, -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-",(Node *) auxnode, (N ode *) auxnode2, -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*",(Node *) auxnode, (N ode *) auxnode2, -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/",(Node *) auxnode, (N ode *) auxnode2, -1)); break; } } else if (!(strcmp(op1,"><"))) { if (atof(op2)==0) { auxnode = (Node *) llast(stack);

PostgreSQLf Página 246

stack = list_delete_ptr(stack,llast(stack)); switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *) auxnode, ( Node *) cref, -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-", (Node *) auxnode, ( Node *) cref, -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *) auxnode, ( Node *) cref, -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/", (Node *) auxnode, ( Node *) cref, -1)); break; } } } else if (!(strcmp(op2,"><"))) { if (atof(op1)==0) { auxnode = (Node *) llast(stack); stack = list_delete_ptr(stack,llast(stack)); switch (x) { case '+': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *) cref, (Nod e *) auxnode, -1)); break; case '-': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "-", (Node *) cref, (Nod e *) auxnode, -1)); break; case '*': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *) cref, (Nod e *) auxnode, -1)); break; case '/': stack = lappend(stack,(Node *) makeSimpleA_Expr(AEXPR_OP, "/", (Node *) cref, (Nod e *) auxnode, -1)); break; } } } return stack; } /* * CREATE FUZZY PREDICATE */ void CreateFuzzyPredicate(CreateFuzzyPredStmt *stmt)

PostgreSQLf Página 247

{ Relation pg_fuzzypred_rel; TupleDesc pg_fuzzypred_dsc; HeapTuple tuple; Datum new_record[Natts_pg_fuzzypred]; char new_record_nulls[Natts_pg_fuzzypred]; Oid fuzzypredid; char *namefp; int2 begd=0; int2 endd=0; int2 minfp=0; int2 core1=0; int2 core2=0; int2 maxfp=0; int typefp=0; ArrayType *compfplist; /** Compare fuzzy predicate . Rossodivita **/ char *disd; /** Discrete Domain. Rossodivita **/ char *exprfp; ScanKeyData key; SysScanDesc fpscan; disd = exprfp = "NULL"; compfplist = NULL; namefp=stmt->pred; switch (stmt->typefp) { case NO_INFINITE: typefp=NO_INFINITE; begd=stmt->begd; endd=stmt->endd; minfp=stmt->minfp; core1=stmt->core1; core2=stmt->core2; maxfp=stmt->maxfp; break; case INFINITE_BEG: typefp=INFINITE_BEG; begd=stmt->begd; endd=stmt->endd; core2=stmt->core2; maxfp=stmt->maxfp; break; case INFINITE_LAST: typefp=INFINITE_LAST; begd=stmt->begd; endd=stmt->endd; minfp=stmt->minfp; core1=stmt->core1; break; /** Fuzzy Predicate by Extension. Rossodivita **/ case EXTENSION: typefp=EXTENSION; disd=stmt->disd; examine_compfplist(stmt->compfplist, &compfplist);

PostgreSQLf Página 248

break; case EXPRESSION: { int i, cont = 0, cont2 = 0; char cad[500] ; strcpy(cad,stmt->exprfp); for(i=0; i < strlen(cad);i++) { if(cad[i] == 'x') cont++; if(cad[i] == '(') cont2++; if(cad[i] == ')') cont2--; if(!EsOperando(cad[i])) { if(cad[i] != '.' && cad[i] != 'x' && cad[i] != '(' && cad[i] != ')' && !EsOperador(cad[i])) elog(ERROR,"Sintaxt Error, it onl y allows the variable X"); } if((i == 0 && cad[i] == '.') || (i == 0 && cad[i] == ')')) { elog(ERROR,"Sintaxt Error, wrong expression format"); } if((i==0 && i+1 < strlen(cad) && !EsOperador(cad[i+1]) && cad[i] == 'x') || (i==0 && i+1 < strlen(cad) && !EsOperando(cad[i+1]) && cad[i+1] != 'x' && cad[i+1] != '(' && cad[i] == '(' )) elog(ERROR,"Sintaxt Error, wrong expression format"); if(i > 0) { if( (!EsOperando(cad[i-1]) && cad[ i] == '.') || (!EsOperando(cad[i-1]) && cad[i-1 ] != ')' && cad[i-1] != 'x' && cad[i] == ')') || (!EsOperador(cad[i-1]) && cad[i-1 ] != '(' && cad[i] == '(') || (!EsOperador(cad[i-1]) && cad[i-1 ] != '(' && cad[i] == 'x') ) elog(ERROR,"Sintaxt Error, wrong expression format"); if(i+1 < strlen(cad)) { if( (!EsOperando(cad[i+1]) && cad[i] == '.') || (!EsOperador(cad[i+1]) && cad[i+1] != ')' && cad[i] == ')') ||

PostgreSQLf Página 249

(!EsOperando(cad[i+1]) && cad[i+1] != 'x' && cad[i+1] != '(' && cad[i] == '(' ) || (!EsOperador(cad[i+1]) && cad[i+1] != ')' && cad[i] == 'x') ) elog(ERROR,"Sintaxt Error, wrong expression format"); } if((i == strlen(cad)-1) && !EsOperando(cad[i]) && cad[i] != 'x' && cad[i] != ')') elog(ERROR,"Sintaxt Error, wrong expression format"); } } if(cont == 0) elog(ERROR,"Sintaxt Error, expressi on needs the variable X"); if(cont2 != 0) elog(ERROR,"Sintaxt Error, wrong ex pression format"); else { typefp=EXPRESSION; disd=stmt->disd; exprfp=stmt->exprfp; } } break; } /* * Check the pg_fuzzypred relation to be certain t he fuzzy predicate doesn't already * exist. */ pg_fuzzypred_rel = heap_open(RelationFuzzyPredId, RowExclusiveLock); pg_fuzzypred_dsc = RelationGetDescr(pg_fuzzypred_r el); ScanKeyInit(&key, Anum_pg_fuzzypred_predname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(namefp)); fpscan = systable_beginscan(pg_fuzzypred_rel, 0, t rue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzypred pg_fuzzypred = (Form_pg_fuzzyp red) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzypred->predname), namefp) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Predicate \"%s\" for relation \"%s\" already exists", namefp, RelationGetRelationName(pg_fuzzypred_rel)))); } systable_endscan(fpscan);

PostgreSQLf Página 250

MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nu lls)); new_record[Anum_pg_fuzzypred_predname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt- >pred)); new_record[Anum_pg_fuzzypred_predbegd - 1] = begd; new_record[Anum_pg_fuzzypred_predendd - 1] = endd; new_record[Anum_pg_fuzzypred_predminfp - 1] = minf p; new_record[Anum_pg_fuzzypred_predcore1 - 1] = core 1; new_record[Anum_pg_fuzzypred_predcore2 - 1] = core 2; new_record[Anum_pg_fuzzypred_predmaxfp - 1] = maxf p; new_record[Anum_pg_fuzzypred_predtypefp - 1] = typ efp; /** Insert new Fuzzy Predicate By Extension. Rosso divita **/ if(stmt->typefp == EXTENSION) { new_record[Anum_pg_fuzzypred_preddisd - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt ->disd)); if (PointerGetDatum(compfplist) != PointerGetDatu m(NULL)) { new_record[Anum_pg_fuzzypred_predcompfplist -1] = PointerGetDatum(compfplist); } } else new_record_nulls[Anum_pg_fuzzypred_predcompfplis t - 1] = 'n'; if(stmt->typefp == EXPRESSION) { new_record[Anum_pg_fuzzypred_preddisd - 1] = DirectFunctionCall1(namein, CStringGetDatum(disd )); new_record[Anum_pg_fuzzypred_predexprfp - 1] = DirectFunctionCall1(namein, CStringGetDatum(expr fp)); } else new_record_nulls[Anum_pg_fuzzypred_predexprfp - 1 ] = 'n'; if((stmt->typefp != EXTENSION) && (stmt->typefp != EXPRESSION)) new_record_nulls[Anum_pg_fuzzypred_ preddisd - 1] = 'n'; tuple = heap_formtuple(pg_fuzzypred_dsc, new_recor d, new_record_nulls); /* * Insert new record in the pg_fuzzypred table */ fuzzypredid = simple_heap_insert(pg_fuzzypred_rel, tuple); CatalogUpdateIndexes(pg_fuzzypred_rel, tuple); /* * Close pg_fuzzypred, but keep lock till commit ( this is important to * prevent any risk of deadlock failure while upda ting flat file)

PostgreSQLf Página 251

*/ heap_close(pg_fuzzypred_rel, NoLock); }

*) Nuevo archivo en /src/backend/commands/fuzzyquan.c: /*------------------------------------------------- ------------------------ * * fuzzyquan.c * Commands for manipulating fuzzy quantifiers. * * * $PostgreSQL: pgsql/src/backend/commands/fuzzyqua n.c * *------------------------------------------------- ------------------------ */ #include "postgres.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_fuzzyquan.h" #include "commands/fuzzyquan.h" #include "storage/lock.h" #include "access/heapam.h" #include "access/genam.h" #include "access/xact.h" #include "commands/comment.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" //These are the several kinds of fuzzy predicates t he user can create #define NO_INFINITE 1 #define INFINITE_BEG 2 #define INFINITE_LAST 3 /* * Buscar ayor elemento en un arreglo */ int mayor (float *arreglo, int desde, int TAM) { int i, mayor; mayor = desde++; for (i=desde; i<TAM; i++) if (arreglo[i] > arreglo[mayor]) mayor = i; return mayor;

PostgreSQLf Página 252

} /* * Algoritmo de ordenamiento selectsort decreciente */ void seleccion (float *arreglo, int TAM) { int i,pos_may; float temp; for (i=0; i<TAM - 1; i++) { /* Buscamos el elemento mayor */ pos_may = mayor(arreglo, i, TAM); /* Lo colocamos en el lugar que le corres ponde */ temp = arreglo[i]; arreglo[i] = arreglo [pos_may]; arreglo [pos_may] = temp; } } /* * Select min value */ float min(float Mq, float Pi) { if(Mq<Pi) return Mq; else return Pi; } /* * CREATE FUZZY QUANTIFIER */ void CreateFuzzyQuantifier(CreateFuzzyQuanStmt *stmt) { Relation pg_fuzzyquan_rel; TupleDesc pg_fuzzyquan_dsc; HeapTuple tuple; Datum new_record[Natts_pg_fuzzyquan]; char new_record_nulls[Natts_pg_fuzzyquan]; Oid fuzzyquanid; char *namefp; char *minfp; char *core1; char *core2; char *maxfp; int typefp=0; int typefq=0; ScanKeyData key; SysScanDesc fpscan; namefp=stmt->pred; typefq=stmt->typefq; switch (stmt->typefp) { case NO_INFINITE: minfp=stmt->minfp; core1=stmt->core1; core2=stmt->core2;

PostgreSQLf Página 253

maxfp=stmt->maxfp; if(typefq==2){ if(strcmp(minfp,"0.0")==0 && strcmp(core1,"0.0")==0){ typefp=INFINITE_BEG; } else if(strcmp(maxfp,"1.0")==0 && strcmp(core2,"1.0")==0){ typefp=INFINITE_LAST; } else{ typefp=NO_INFINITE; } } else typefp=NO_INFINITE; break; case INFINITE_BEG: typefp=INFINITE_BEG; minfp=(char *)malloc( 4*sizeof(char) ); strcpy(minfp,"0.0"); core1=(char *)malloc( 4*sizeof(char) ); strcpy(core1,"0.0"); core2=stmt->core2; maxfp=stmt->maxfp; break; case INFINITE_LAST: typefp=INFINITE_LAST; minfp=stmt->minfp; core1=stmt->core1; core2=(char *)malloc( 4*sizeof(char) ); strcpy(core2,"0.0"); maxfp=(char *)malloc( 4*sizeof(char) ); strcpy(maxfp,"0.0"); break; } /* * Check the pg_fuzzyquan relation to be certain t he fuzzy quantifier doesn't already * exist. */ pg_fuzzyquan_rel = heap_open(RelationFuzzyQuanId, RowExclusiveLock); pg_fuzzyquan_dsc = RelationGetDescr(pg_fuzzyquan_r el); ScanKeyInit(&key, Anum_pg_fuzzyquan_quanname, BTEqualStrategyNumber, F_NAMEEQ, PointerGetDatum(namefp)); fpscan = systable_beginscan(pg_fuzzyquan_rel, 0, t rue, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(f pscan))) { Form_pg_fuzzyquan pg_fuzzyquan = (Form_pg_fuzzyq uan) GETSTRUCT(tuple); if (namestrcmp(&(pg_fuzzyquan->quanname), namefp) == 0)

PostgreSQLf Página 254

ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Fuzzy Quantifier \"%s\" for relation \"%s\" already exists", namefp, RelationGetRelationName(pg_fuzzyquan_rel)))); } systable_endscan(fpscan); MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nu lls)); new_record[Anum_pg_fuzzyquan_quanname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt- >pred)); new_record[Anum_pg_fuzzyquan_quanminfp - 1] = DirectFunctionCall1(namein, CStringGetDatum(minfp )); new_record[Anum_pg_fuzzyquan_quancore1 - 1] = DirectFunctionCall1(namein, CStringGetDatum(core1 )); new_record[Anum_pg_fuzzyquan_quancore2 - 1] = DirectFunctionCall1(namein, CStringGetDatum(core2 )); new_record[Anum_pg_fuzzyquan_quanmaxfp - 1] = DirectFunctionCall1(namein, CStringGetDatum(maxfp )); new_record[Anum_pg_fuzzyquan_quantypefp - 1] = typ efp; new_record[Anum_pg_fuzzyquan_quantypefq - 1] = typ efq; tuple = heap_formtuple(pg_fuzzyquan_dsc, new_recor d, new_record_nulls); /* * Insert new record in the pg_fuzzyquan table */ fuzzyquanid = simple_heap_insert(pg_fuzzyquan_rel, tuple); CatalogUpdateIndexes(pg_fuzzyquan_rel, tuple); /* * Close pg_fuzzyquan, but keep lock till commit ( this is important to * prevent any risk of deadlock failure while upda ting flat file) */ heap_close(pg_fuzzyquan_rel, NoLock); }

*) Nuevo archivo en /src/include/commands/fuzzycomp.h: /*------------------------------------------------- ------------------------ * * fuzzycomp.h * Commands for manipulating fuzzy comparates. * * * $PostgreSQL: pgsql/src/include/commands/fuzzycom p.h *

PostgreSQLf Página 255

*------------------------------------------------- ------------------------ */ #ifndef FUZZYCOMP_H #define FUZZYCOMP_H #include "nodes/parsenodes.h" extern void CreateFuzzyComparate(CreateFuzzyCompStm t *stmt); #endif /* FUZZYCOMP_H */

*) Nuevo archivo en /src/include/commands/fuzzyconn.h: /*------------------------------------------------- ------------------------ * * fuzzyconn.h * Commands for manipulating fuzzy connector. * * * $PostgreSQL: pgsql/src/include/commands/fuzzycon n.h * *------------------------------------------------- ------------------------ */ #ifndef FUZZYCONN_H #define FUZZYCONN_H #include "nodes/parsenodes.h" extern void CreateFuzzyConnector(CreateFuzzyConnStm t *stmt); #endif /* FUZZYCONN_H */

*) Nuevo archivo en /src/include/commands/fuzzymod.h: /*------------------------------------------------- ------------------------ * * fuzzymod.h * Commands for manipulating fuzzy modifiers. * * * $PostgreSQL: pgsql/src/include/commands/fuzzymod .h * *------------------------------------------------- ------------------------ */ #ifndef FUZZYMOD_H #define FUZZYMOD_H #include "nodes/parsenodes.h" extern void CreateFuzzyModifier(CreateFuzzyModStmt *stmt); #endif /* FUZZYMOD_H */

PostgreSQLf Página 256

*) Nuevo archivo en /src/include/commands/fuzzypred.h: /*------------------------------------------------- ------------------------ * * fuzzypred.h * Commands for manipulating fuzzy predicates. * * * $PostgreSQL: pgsql/src/include/commands/fuzzypre d.h * *------------------------------------------------- ------------------------ */ #ifndef FUZZYPRED_H #define FUZZYPRED_H #include "nodes/parsenodes.h" #include "executor/executor.h" #include "utils/logtape.h" //Armando #include "utils/pg_rusage.h" //Armando #include "utils/tuplesort.h" //Armando bool EsOperando(char x); bool EsOperador(char x); int Prioridad(char x); float grmembFuzzyPred (List *qual, ExprContext *eco ntext); /*Armando Bracho*/ float ValidateFuzzyPred (FunctionCallInfoData fcinf o); /*Armando Bracho*/ float Operacion(char operador, float operando1, flo at operando2); A_Const * makeFA_Const(float value); List * OperTree(char x, char *op1, char *op2, Node *cref, List *stack); typedef struct { void *tuple; /* the tuple proper */ Datum datum1; /* value of first key column */ bool isnull1; /* is first key column NULL? */ int tupindex; /* see notes above */ } SortTuple; typedef enum { TSS_INITIAL, /* Loading tuples; still within memory limit */ TSS_BUILDRUNS, /* Loading tuples; writing to tape */ TSS_SORTEDINMEM, /* Sort completed entirely in memory */

PostgreSQLf Página 257

TSS_SORTEDONTAPE, /* Sort completed, final run i s on tape */ TSS_FINALMERGE /* Performing final merge on-the-fly */ } TupSortStatus; struct Tuplesortstate { TupSortStatus status; /* enumerated value as show n above */ int nKeys; /* number of columns in sort key */ bool randomAccess; /* did caller request random access? */ long availMem; /* remaining memory available, in bytes */ long allowedMem; /* total memory allowed, in byt es */ int maxTapes; /* number of tapes (Knuth's T) */ int tapeRange; /* maxTapes-1 (Knuth's P) */ MemoryContext sortcontext; /* memory context holdi ng all sort data */ LogicalTapeSet *tapeset; /* logtape.c object for t apes in a temp file */ int (*comparetup) (const SortTuple *a, const SortTuple *b, Tuplesortstate *state); void (*copytup) (Tuplesortstate *state, SortTuple *stup, void *tup); void (*writetup) (Tuplesortstate *state, int tape num, SortTuple *stup); void (*readtup) (Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); SortTuple *memtuples; /* array of SortTuple stru cts */ int memtupcount; /* number of tuples currently present */ int memtupsize; /* allocated length of memtuples array */ int currentRun; bool *mergeactive; /* active input run source? */ int *mergenext; /* first preread tuple for each source */ int *mergelast; /* last preread tuple for each source */ int *mergeavailslots; /* slots left for prerea ding each tape */ long *mergeavailmem; /* availMem for prereading each tape */ int mergefreelist; /* head of freelist of recycled slots */ int mergefirstfree; /* first slot never used in this merge */ int Level; /* Knuth's l */ int destTape; /* current output tape (Knuth's j, less 1) */ int *tp_fib; /* Target Fibonacci run counts (A[]) */

PostgreSQLf Página 258

int *tp_runs; /* # of real runs on each tape */ int *tp_dummy; /* # of dummy runs for each tape (D[]) */ int *tp_tapenum; /* Actual tape numbers (TAPE[]) */ int activeTapes; /* # of active input tapes in merge pass */ int result_tape; /* actual tape number of finished output */ int current; /* array index (only used if SORTEDINMEM) */ bool eof_reached; /* reached EOF (needed for curs ors) */ long markpos_block; /* tape block# (only used if SORTEDONTAPE) */ int markpos_offset; /* saved "current", or offse t in tape block */ bool markpos_eof; /* saved "eof_reached" */ TupleDesc tupDesc; ScanKey scanKeys; /* array of length nKeys */ SortFunctionKind *sortFnKinds; /* array of length nKeys */ Relation indexRel; ScanKey indexScanKey; bool enforceUnique; /* complain if we find duplic ate tuples */ Oid datumType; Oid sortOperator; FmgrInfo sortOpFn; /* cached lookup data for sortOperator */ SortFunctionKind sortFnKind; int datumTypeLen; bool datumTypeByVal; #ifdef TRACE_SORT PGRUsage ru_start; #endif }; extern void CreateFuzzyPredicate(CreateFuzzyPredStm t *stmt); #endif /* FUZZYPRED_H */

*) Nuevo archivo en /src/include/commands/fuzzyquan.h: /*------------------------------------------------- ------------------------ * * fuzzyquan.h * Commands for manipulating fuzzy predicates. * * * $PostgreSQL: pgsql/src/include/commands/fuzzypre d.h * *------------------------------------------------- ------------------------ */

PostgreSQLf Página 259

#ifndef FUZZYQUAN_H #define FUZZYQUAN_H #include "nodes/parsenodes.h" int mayor (float *arreglo, int desde, int TAM); void seleccion (float *arreglo, int TAM); float min(float Mq, float Pi); extern void CreateFuzzyQuantifier(CreateFuzzyQuanSt mt *stmt); #endif /* FUZZYQUAN_H */

*) Modificación del /src/backend/commands/Makefile

Línea 21: fuzzycomp.o fuzzyconn.o fuzzymod.o fuzzypred.o fuzz yquan.o

*) Modificación del /src/backend/utils/adt/ruleutils.c

Línea 3292: case T_A_FuzzyPred: { A_FuzzyPred *n = (A_FuzzyPred *) node; char *attname; attname = n->pred; if (attname) appendStringInfoString(buf, quote_identifier(attname)); else appendStringInfoString(buf, "*"); } break;

*) Modificación del /src/backend/utils/cache/relcache.c

Línea 44: #include "catalog/pg_fuzzycomp.h" #include "catalog/pg_fuzzyconn.h" #include "catalog/pg_fuzzymod.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_fuzzyquan.h"

Línea 87: static FormData_pg_attribute Desc_pg_fuzzycomp[Natt s_pg_fuzzycomp] = {Schema_pg_fuzzycomp}; static FormData_pg_attribute Desc_pg_fuzzyconn[Natt s_pg_fuzzyconn] = {Schema_pg_fuzzyconn}; static FormData_pg_attribute Desc_pg_fuzzymod[Natts _pg_fuzzymod] = {Schema_pg_fuzzymod}; static FormData_pg_attribute Desc_pg_fuzzypred[Natt s_pg_fuzzypred] = {Schema_pg_fuzzypred};

PostgreSQLf Página 260

static FormData_pg_attribute Desc_pg_fuzzyquan[Natt s_pg_fuzzyquan] = {Schema_pg_fuzzyquan};

Línea 678: /*Scan the rules for Fuzzy Predicates*/ foreach(l, rule->actions) /*Armando Bracho*/ { Query *que = (Query *) lfirst(l); if(que->rtable->length > 1) { foreach(r, que->rtable) { RangeTblEntry *rt = (RangeTblEntry *) lfirst(r); if(rt->rtekind == RTE_SUBQUERY) { if(rt->subquery->jointree->quals && IsA(rt->subquery->jointree, FromExpr) && IsA(rt->subquery- >jointree->quals, OpExpr)) { OpExpr *opex = (OpExpr *) rt->subquery->jointree->quals; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)){ rt->subquery->hasFuzzyQual = true; relation->rd_hasFuzzyPred = true; } } } } } if(que->jointree->quals) { if(IsA(que->jointree, FromExpr)) { if(IsA(que->jointree->quals, OpExpr)) { OpExpr *opex = (OpExpr *) que->jointree->quals; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) relation->rd_hasFuzzyPred = true; } } } if(que->havingQual) { if(IsA(que->havingQual, OpExpr)) { OpExpr *opex = (OpExpr *) que->havingQual; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) relation->rd_hasFuzzyPred = true; } else{ BoolExpr *boex = (BoolExpr *) que->havingQual; Node *arg1 = (Node *) linitial(boex->args); Node *arg2 = (Node *) lsecond(boex->args);

PostgreSQLf Página 261

OpExpr *opex = (OpExpr *) arg1; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) relation->rd_hasFuzzyPred = true; opex = (OpExpr *) arg2; secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) relation->rd_hasFuzzyPred = true; } } }

*) Modificación del /src/backend/utils/cache/syscache.c

Línea 42: #include "catalog/pg_fuzzycomp.h" #include "catalog/pg_fuzzyconn.h" #include "catalog/pg_fuzzymod.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_fuzzyquan.h"

*) Modificación del /src/backend/utils/cache/lsyscache.c

Línea 28: #include "catalog/pg_fuzzycomp.h" #include "catalog/pg_fuzzyconn.h" #include "catalog/pg_fuzzymod.h" #include "catalog/pg_fuzzypred.h" #include "catalog/pg_fuzzyquan.h"

PostgreSQLf Página 262

Anexo D

Extensión del Planner/Optimazer

PostgreSQLf Página 263

*) Modificaciones al /src/backend/optimizer/plan/planner.c Línea 56: //These are the several kinds of fuzzy predicates t he user can create #define NO_INFINITE 1 #define INFINITE_BEG 2 #define INFINITE_LAST 3 #define EXTENSION 4

Línea 62: static Node *derivate_fuzzy_opex (Var *varfa, A_Fuz zyPred *fp); static Node *derivate_fuzzy_boex (Node *arg1, Node *arg2, BoolExprType boextype);

Línea 83: static Node * derivate_fuzzy_opex_comp(Var * varfa , A_FuzzyComp *n); int constIndex; List *fc = NIL; List *newfp1 = NIL; bool hfc = FALSE; bool hfs = false; BoolExprType aux_boextype; int qual_aux; List *pred = NIL; List *quan = NIL;

Línea 179: constIndex = 0; fc = NIL; hfc = FALSE; newfp1 = NIL; hfs = false; qual_aux = 0;

Línea 214: List *newfp = NIL; List *tup = NIL; Datum *fpNames = NULL; static void FuzzySubquery(Query *parse, bool *fp, bool *hasFuzz y) { BoolExprType boextype = -1; float calibration1, calibration2; if (parse != NULL) { ListCell *l1; bool bandera1 = FALSE; if (fp[0]) { newfp = NIL; fp[0] = FALSE; } foreach(l1, parse->rtable) { RangeTblEntry *auxiliar = (RangeTblEntry *) lfirst(l1);

PostgreSQLf Página 264

char *token; bool bandera = FALSE; if(auxiliar->alias!=NULL) { token = strtok( auxiliar->alias->aliasname, " " ); if(strcmp(token,"*SELECT*")==0) { bandera = TRUE; bandera1 = TRUE; } } else bandera = FALSE; if(!bandera) FuzzySubquery(auxiliar->subquery, fp, hasFuzzy); if(!bandera && auxiliar->subquery!=NULL && (auxi liar->subquery->hasFuzzyComp || auxiliar->subquery->hasF uzzyQuan || auxiliar->subquery->hasFuzzyPred || auxiliar->subqu ery->hasFuzzyHavingQual)){ if(parse->calibracion==NULL && auxiliar->subquery->calibracion!=NULL) parse->calibracion = auxiliar->subquery->calibracion; if(parse->calibracion!=NULL && auxiliar->subquery->calibracion!=NULL) { calibration1 = atof(((A_Const *)parse->calibracion)->val.val.str); calibration2 = atof(((A_Const *)auxiliar->subquery->calibracion)->val.val.str); if(calibration2>calibration1) parse->calibracion = auxiliar->subquery->calibracion; } } if(!bandera && auxiliar->subquery!=NULL && auxil iar->subquery->hasFuzzyComp){ A_FuzzyComp *aFC; ListCell *x; hfc = auxiliar->subquery->hasFuzzyComp; fc = auxiliar->subquery->FuzzyComp; constIndex = 0; foreach(x,auxiliar->subquery->FuzzyComp){ aFC = makeNode(A_FuzzyComp); aFC = lfirst(x); if(aFC->typefp == 4) { x = lnext(x); x = lnext(x); } else {

PostgreSQLf Página 265

newfp = lappend(newfp,aFC); x = lnext(x); newfp = lappend(newfp,(Node *) lfirst(x)); x = lnext(x); } } } if(!bandera && auxiliar->subquery!=NULL && auxil iar->subquery->hasFuzzyQuan){ ListCell *x; foreach(x,auxiliar->subquery->fuzzyquan){ parse->fuzzyquan = lappend(parse->fuzzyquan,lfirst(x)); } parse->hasFuzzyQuan = true; } if(!bandera && auxiliar->subquery!=NULL && auxil iar->subquery->hasFuzzyPred && auxiliar->subquery->hasF uzzyQual) { Node *nodeq = (Node *) auxiliar->subquery->jointree->quals; float4 val = 1.0; int resno1 = list_length(auxiliar->subquery->targetList)+1; TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); Node *nodeq1 = NULL; Node *nodeq2 = NULL ; ListCell *x; foreach(x,auxiliar->subquery->FuzzyPredExp){ newfp = lappend(newfp,lfirst(x)); } hasFuzzy[0] = TRUE; if (IsA(nodeq, OpExpr)) { OpExpr *opex = (OpExpr *) nodeq; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) auxiliar->subquery->jointree->quals = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPre d *) secarg); } else{ BoolExpr *boex; Node *arg1 = NULL; Node *arg2 = NULL; if (and_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); boextype = AND_EXPR;

PostgreSQLf Página 266

aux_boextype = AND_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } if(or_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); boextype = OR_EXPR; aux_boextype = OR_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } if(not_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) NULL; boextype = NOT_EXPR; aux_boextype = NOT_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } } //Project a membreship degree val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = resno1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList auxiliar->subquery->targetList = lappend(auxiliar->subquery->targetList, tfp); nodeq1 = (Node *) auxiliar->subquery->jointree->quals; nodeq2 = (Node *) parse->jointree->quals; if(qual_aux > 0) hfs = true; else{ qual_aux++; if(nodeq2 == NULL && nodeq1 != NULL){ //parse->jointree->quals = nodeq1; if (and_clause(nodeq1)) aux_boextype = AND_EXPR; else if (or_clause(nodeq1)) aux_boextype = OR_EXPR; else if (not_clause(nodeq1)) aux_boextype = NOT_EXPR; else aux_boextype = -1;

PostgreSQLf Página 267

} } } if(!bandera && auxiliar->subquery!=NULL && auxil iar->subquery->hasFuzzyHavingQual) { float4 val = 1.0; Const *cn = makeNode(Const); TargetEntry *tfp = makeNode(TargetEntry); cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(parse->targetList) +1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; newfp = NIL; //New Target entry in targetList parse->targetList = lappend(parse->targetList, tfp); parse->hasFuzzyPred = true; parse->hasFuzzyHavingQual = true; } else { if(!bandera && auxiliar->subquery!=NULL && auxiliar->subquery->hasFuzzyComp) { hasFuzzy[0] = TRUE; if(auxiliar->subquery->jointree->quals != NULL){ Node *nodeq = (Node *) auxiliar->subquery->jointree->quals; Node *nodeq1 = NULL; Node *nodeq2 = NULL; float4 val = 1.0; int resno1 = list_length(auxiliar->subquery->targetList)+1; TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); if (IsA(nodeq, OpExpr)) { OpExpr *opex = (OpExpr *) nodeq; Node *firstarg = (Node *) linitial(opex->args); List *l = auxiliar->subquery->FuzzyComp; A_FuzzyComp *n = (A_FuzzyComp *) linitial(l); Node *c = lsecond(l); if(IsA(c,A_Const)){ A_Const *ac = (A_Const *)c; switch(n->typefp)

PostgreSQLf Página 268

{ case 4: n->secarg = ac; auxiliar->subquery->jointree->quals = derivate_fuzzy_opex_comp((Var *) firstarg , n); break; } } } else { BoolExpr *boex; Node *arg1 = NULL; Node *arg2 = NULL; if (and_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); boextype = AND_EXPR; aux_boextype = AND_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(ar g1, arg2, boextype); } if(or_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); boextype = OR_EXPR; aux_boextype = OR_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(ar g1, arg2, boextype); } if(not_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args);

PostgreSQLf Página 269

arg2 = (Node *) NULL; boextype = NOT_EXPR; aux_boextype = NOT_EXPR; auxiliar->subquery->jointree->quals = derivate_fuzzy_boex(ar g1, arg2, boextype); } } val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = resno1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList auxiliar->subquery->targetList = lappend(auxiliar->subquery->targetLis t, tfp); //auxiliar->subquery->hasFuzzyPred = true; nodeq1 = (Node *) auxiliar->subquery->jointree->quals; nodeq2 = (Node *) parse->jointree->quals; if(qual_aux > 0) hfs = true; else{ qual_aux++; if(nodeq2 == NULL && nodeq1 != NULL){ //parse->jointree->quals = nodeq1; if (and_clause(nodeq1)) aux_boextype = AND_EXPR; else if (or_clause(nodeq1)) aux_boextype = OR_EXPR; else if (not_clause(nodeq1)) aux_boextype = NOT_EXPR; else aux_boextype = -1; } } } } } hfc = false;

PostgreSQLf Página 270

fc = NIL; } } }

Línea 523: ListCell *l; List *newHaving; bool hasboex = false; BoolExprType boextype = -1; float calibration; constIndex = 0; fc = parse->FuzzyComp; hfc = parse->hasFuzzyComp; aux_boextype = -1; qual_aux = 0; //Check for Fuzzy predicates on a view if(parse->jointree->quals && !parse->hasFuzzyQual) { if(IsA(parse->jointree, FromExpr)) { if(IsA(parse->jointree->quals, OpExpr)) { OpExpr *opex = (OpExpr *) parse->jointree->quals; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) { parse->hasFuzzyQual = true; parse->hasFuzzyPred = true; } } } } if(parse->havingQual && !parse->hasFuzzyHavingQual) { if(IsA(parse->havingQual, OpExpr)) { OpExpr *opex = (OpExpr *) parse->havingQual; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) { parse->hasFuzzyHavingQual = true; parse->hasFuzzyPred = true; } } else{ BoolExpr *boex = (BoolExpr *) parse->havingQual; Node *arg1 = (Node *) linitial(boex->args); Node *arg2 = (Node *) lsecond(boex->args); OpExpr *opex = (OpExpr *) arg1; Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) parse->hasFuzzyPred = true;

PostgreSQLf Página 271

opex = (OpExpr *) arg2; secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) parse->hasFuzzyPred = true; } } /* Look for Fuzzy Predicates and aplicate the deriv ation's principle on quals */ if (parse->hasFuzzyPred && parse->hasFuzzyQual && p arse->commandType != CMD_UPDATE) { Node *nodeq = (Node *) parse->jointree->quals; float4 val = 1.0; int resno1 = list_length(parse->targetList)+1; TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); newfp = NIL; tup = NIL; qual_aux++; if(parse->FuzzyPredExp) newfp = parse->FuzzyPredExp; if(parse->hasFuzzyComp) { A_FuzzyComp *aFC; ListCell *x; foreach(x,parse->FuzzyComp){ aFC = makeNode(A_FuzzyComp); aFC = lfirst(x); if(aFC->typefp == 4) { x = lnext(x); x = lnext(x); } else { newfp = lappend(newfp,aFC); x = lnext(x); newfp = lappend(newfp,(Node *) lfirst(x)); x = lnext(x); } } } if (IsA(nodeq, OpExpr)) { OpExpr *opex = (OpExpr *) nodeq; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) { parse->jointree->quals = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); } } else { BoolExpr *boex;

PostgreSQLf Página 272

Node *arg1 = NULL; Node *arg2 = NULL; if (and_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); hasboex = true; boextype = AND_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg 1, arg2, boextype); } if(or_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); hasboex = true; boextype = OR_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg 1, arg2, boextype); } if(not_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) NULL; hasboex = true; boextype = NOT_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg 1, arg2, boextype); } } //Project a membreship degree val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), fal se, true); tfp->expr = (Expr *) cn; tfp->resno = resno1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList parse->targetList = lappend(parse->targetList, tf p); } if(parse->hasFuzzyHavingQual && parse->commandType != CMD_UPDATE) { float4 val = 1.0; Const *cn = makeNode(Const); TargetEntry *tfp = makeNode(TargetEntry); cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(parse->targetList)+1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; newfp = NIL; //New Target entry in targetList

PostgreSQLf Página 273

parse->targetList = lappend(parse->targetList, tfp ); } if(parse->hasFuzzyPred && !parse->hasFuzzyQual && ! parse->hasFuzzyHavingQual) { float4 val = 1.0; Const *cn = makeNode(Const); TargetEntry *tfp = makeNode(TargetEntry); cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(parse->targetList)+1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; newfp = NIL; //New Target entry in targetList parse->targetList = lappend(parse->targetList, tfp ); } else { if(parse->hasFuzzyComp) { Node *nodeq = (Node *) parse->jointree->quals; A_FuzzyComp *aFC; newfp = NIL; ListCell *x; tup = NIL; parse->hasFuzzyPred = true; qual_aux++; foreach(x,parse->FuzzyComp){ aFC = makeNode(A_FuzzyComp); aFC = lfirst(x); if(aFC->typefp == 4) { x = lnext(x); x = lnext(x); } else { newfp = lappend(newfp,(Node *) lfirst(x)); x = lnext(x); newfp = lappend(newfp,(Node *) lfirst(x)); x = lnext(x); } } if (IsA(nodeq, OpExpr)) { OpExpr *opex = (OpExpr *) nodeq; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); List *l = parse->FuzzyComp; A_FuzzyComp *n = (A_FuzzyComp *) linitial(l); Node *c = lsecond(l); if(IsA(c,A_Const)){ A_Const *ac = (A_Const *)c; switch(n->typefp) {

PostgreSQLf Página 274

case 4: n->secarg = ac; parse->jointree->quals = derivate_fuzzy_opex_comp((Var *) firstarg , n); break; } } } else { BoolExpr *boex; Node *arg1 = NULL; Node *arg2 = NULL; if (and_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); hasboex = true; boextype = AND_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } if(or_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) lsecond(boex->args); hasboex = true; boextype = OR_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } if(not_clause(nodeq)) { boex = (BoolExpr *) nodeq; arg1 = (Node *) linitial(boex->args); arg2 = (Node *) NULL; hasboex = true; boextype = NOT_EXPR; parse->jointree->quals = derivate_fuzzy_boex(arg1, arg2, boextype); } } float4 val = 1.0; int resno1 = list_length(parse->targetList)+1; TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), fal se, true); tfp->expr = (Expr *) cn; tfp->resno = resno1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false;

PostgreSQLf Página 275

//New Target entry in targetList parse->targetList = lappend(parse->targetList, tf p); } } /************************************************** *****************/ bool *fp, *hasFuzzy; fp = (bool *)palloc0(1*sizeof(bool)); hasFuzzy = (bool *)palloc0(1*sizeof(bool)); if(!parse->hasFuzzyPred && !parse->hasFuzzyComp) fp[0] = TRUE; else fp[0] = FALSE; hasFuzzy[0] = FALSE; FuzzySubquery(parse, fp, hasFuzzy); if(hasFuzzy[0]) { if(!parse->hasFuzzyPred){ float4 val = 1.0; int resno1 = list_length(parse->targetList)+1; TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), fal se, true); tfp->expr = (Expr *) cn; tfp->resno = resno1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList parse->targetList = lappend(parse->targetList, tf p); parse->hasFuzzyPred = true; } } parse->hasFuzzy = hasFuzzy[0]; /************************************************** *****************/ if(parse->hasFuzzyPred || parse->hasFuzzyQual || pa rse->hasFuzzyHavingQual || parse->hasFuzzyQuan || parse ->hasFuzzyComp) { if(parse->calibracion != NULL){ calibration = atof(((A_Const *)parse->calibracion )->val.val.str); if(calibration<=0 || calibration>1) elog(ERROR,"The calibration must be greater than zero and less than or equal to one."); } } else if(parse->calibracion != NULL) elog(ERROR,"The calibration must be defined when fuzzy conditions are present");

PostgreSQLf Página 276

Línea 867: if (parse->hasFuzzyQuan){ //New Target entry in targetList root->fuzzyquan = parse->fuzzyquan; //elog(NOTICE,"planner = %d",list_length(root->fuz zyquan)); } else root->fuzzyquan = NIL; if (hasFuzzy[0] || (parse->hasFuzzyPred && parse->c ommandType != CMD_UPDATE)) /*Armando B*/ root->fuzzypred = newfp; else root->fuzzypred = NIL;

Línea 1077: if (parse->hasFuzzyQuan) { ListCell *x; foreach(x,parse->fuzzyquan) { newfp = lappend(newfp,lfirst(x)); } plan->fuzzyquan=parse->fuzzyquan; plan->hfq = true; if(plan->hfq==false){ plan->fq=(Node *) makeNode(A_FuzzyQuan); plan->fq=list_nth(parse->fuzzyquan ,0); } } else plan->hfq = false; if (parse->hasFuzzyPred && parse->commandType != CM D_UPDATE) /*Armando Bracho*/ { plan->fuzzypred = newfp; plan->hfp = true; plan->hasboex = hasboex; plan->boextype = boextype; } else plan->hfp = false; if(hasFuzzy[0]){ plan->fuzzypred = newfp; plan->hfp = true; if(hfs){ plan->boextype = AND_EXPR; plan->hasboex = true; } else{ plan->boextype = aux_boextype; if(aux_boextype != -1) plan->hasboex = true; else plan->hasboex = false; } }

PostgreSQLf Página 277

Línea 1120: /* * Derivate_fuzzy_opex * * Derivate a fuzzy predicate and generate a boolea n OpExpr or BoolExpr * * Returns the modified version of the given OpExpr node. */ static Node * derivate_fuzzy_opex_comp(Var * varfa , A_FuzzyComp *n) { int i=0; int listCount; ListCell *x; char s1[100], *ptr1, *ptr2; A_Const *c = n->secarg; List *aux = NIL; tup = NIL; foreach(x, n->compfclist) { char *cad = (char *) lfirst(x); strcpy(s1, cad); ptr1 = strtok( s1, "/" ); ptr1 = strtok( ptr1, "," ); ptr2 = strtok( NULL, "," ); ptr1 = strtok( ptr1, "{ \n\t( \n\t}"); ptr2 = strtok( ptr2, "{ \n\t) \n\t}" ); if(!IsA(&c->val, String)) elog(ERROR,"Incompatible types"); else { if(strcmp(ptr1,c->val.val.str)==0) aux = lappend(aux,DirectFunctionCall1(textin,CStringGetDa tum(ptr2))); else{ if(strcmp(ptr2,c->val.val.str)==0) aux = lappend(aux,DirectFunctionCall1(textin,CStringGetDa tum(ptr1))); } } } listCount = list_length(aux); fpNames = (Datum *) palloc0(listCount * sizeof(Dat um)); foreach(x,aux){ fpNames[i] = (Datum *)lfirst(x); i++; }

PostgreSQLf Página 278

for(i = 0; i < listCount; i++) tup = lappend(tup, (Node *) make_opclause(98, 25, false, (Expr *) varfa, (Expr *) makeConst(25, -1, fpNames[i],fal se,false))); n->vno =varfa->varno; n->vattno = varfa->varattno; n->vtype = varfa->vartype; newfp = lappend(newfp, n); return (Node *) make_orclause(tup); } static Node * derivate_fuzzy_opex_extendC(Var *firstarg ) { bool bandera = FALSE; ListCell *lc; A_FuzzyComp *n; A_Const *c = makeNode(A_Const); foreach(lc,fc){ int aux; n = makeNode(A_FuzzyComp); n = (A_FuzzyComp *) lfirst(lc); lc = lnext(lc); if(IsA(lfirst(lc),A_Const)){ c = (A_Const *)lfirst(lc); lc = lnext(lc); aux = intVal(lfirst(lc)); if(constIndex == aux) bandera = TRUE; } else lc = lnext(lc); if(bandera) break; } if(bandera){ switch(n->typefp) { case 4: n->secarg = c; return derivate_fuzzy_opex_comp(firstarg , n); break; } } return NULL; } static Node * derivate_fuzzy_opex (Var *varfa, A_FuzzyPred *fp) { Expr *newopclause; Node *newqual = (Node *) makeNode(OpExpr); Node *newqual1 = (Node *) makeNode(OpExpr); Const *newcon = makeNode(Const); Const *newcon1 = makeNode(Const); bool istrap=false, IsExt=false; int listCount = list_length(fp->compfplist), i=0 ; ListCell *x;

PostgreSQLf Página 279

char s1[100], s2[10] = "{/\n\t}", *ptr; fpNames = (Datum *) palloc0(listCount * sizeof(Dat um)); // *** Node Fuzzy Predicate switch (fp->typefp) { case NO_INFINITE: // Trapecio if(varfa->vartype == 21) { newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon1->consttype = 21; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int16GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(520, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int16GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(95, 16, false ,(Expr *) varfa,(Expr *) newcon1); } else if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon1->consttype = 23; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int32GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(521, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(97, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true;

PostgreSQLf Página 280

newcon->constisnull = false; newcon1->consttype = 20; newcon1->constlen = 4; newcon1->constbyval = true; newcon1->constisnull = false; newcon->constvalue = Int64GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(413, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(412, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 700) { newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon1->consttype = 700; newcon1->constlen = 8; newcon1->constbyval = false; newcon1->constisnull = false; newcon->constvalue = Float4GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(623, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; newcon1->constvalue = Float4GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(622, 16, false ,(Expr *) varfa,(Expr *) newcon1); } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon1->consttype = 701; newcon1->constlen = 8; newcon1->constbyval = false; newcon1->constisnull = false; newcon->constvalue = Float8GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(674, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause;

PostgreSQLf Página 281

newcon1->constvalue = Float8GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newqual1 = (Node *) make_opclause(672, 16, false ,(Expr *) varfa,(Expr *) newcon1); } fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; newfp = lappend(newfp , fp); istrap = true; break; case INFINITE_BEG: // Decreciente if(varfa->vartype == 21) { newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int16GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(95, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int32GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(97, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int64GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(412, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 700)

PostgreSQLf Página 282

{ newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float4GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(622, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float8GetDatum(fp->maxfp); // Change Node Opexpr op "=" for "<" newopclause = make_opclause(672, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; newfp = lappend(newfp , fp); break; case INFINITE_LAST: // Creciente if(varfa->vartype == 21) { newcon->consttype = 21; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int16GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(520, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 23) { newcon->consttype = 23; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int32GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">"

PostgreSQLf Página 283

newopclause = make_opclause(521, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 20) { newcon->consttype = 20; newcon->constlen = 4; newcon->constbyval = true; newcon->constisnull = false; newcon->constvalue = Int64GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(413, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 700) { newcon->consttype = 700; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float4GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(623, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } if(varfa->vartype == 701) { newcon->consttype = 701; newcon->constlen = 8; newcon->constbyval = false; newcon->constisnull = false; newcon->constvalue = Float8GetDatum(fp->minfp); // Change Node Opexpr op "=" for ">" newopclause = make_opclause(674, 16, false,(Expr *) varfa,(Expr *) newcon); newqual = (Node *) newopclause; } fp->vno = varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; newfp = lappend(newfp , fp); break; case EXTENSION: // Extension foreach(x, fp->compfplist) { char *cad = (char *) lfirst(x); strcpy(s1, cad);

PostgreSQLf Página 284

ptr = strtok( s1, s2 ); fpNames[i] = DirectFunctionCall1(textin, CStringGetDatum(ptr)); i++; } for(i = 0; i < listCount; i++) tup = lappend(tup, (Node *) make_opclause(98, 25 , false, (Expr *) varfa, (Expr *) makeConst(25, -1, fpNames[i],false,false))); fp->vno =varfa->varno; fp->vattno = varfa->varattno; fp->vtype = varfa->vartype; newfp = lappend(newfp, fp); IsExt = true; listCount = 0; break; } if (IsExt) return (Node *) make_orclause(tup); if (istrap) return (Node *) make_andclause(list_make2(newqual , newqual1)); return newqual; } /* * Derivate_fuzzy_boex * * Look for fuzzy predicate and generate a Boolean Expresion * * Returns the modified version of the given BoolEx pr node. */ static Node * derivate_fuzzy_boex (Node *arg1, Node *arg2, BoolEx prType boextype) { Node *clause = NULL; if (boextype == AND_EXPR) { if (IsA(arg1, OpExpr)) { OpExpr *opex = (OpExpr *) arg1; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) arg1 = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); else { if(IsA(secarg,Const)) { OpExpr *aux; constIndex++; if(hfc){

PostgreSQLf Página 285

aux = derivate_fuzzy_opex_extendC((Var *) firstarg); if(aux != NULL) arg1 = aux; } } } if (IsA(arg2, OpExpr)) { opex = (OpExpr *) arg2; firstarg = (Node *) linitial(opex->args); secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) arg2 = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); else { if(IsA(secarg,Const)) { OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) firstarg); if(aux != NULL) arg2 = aux; } } } } else { BoolExpr *boex1 = (BoolExpr *) arg2; Node *arg11 = (Node *) linitial(boex1->args); Node *arg21; if (!not_clause(arg2)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); } } else { BoolExpr *boex1 = (BoolExpr *) arg1; Node *arg11 = (Node *) linitial(boex1->args );

PostgreSQLf Página 286

Node *arg21; if (!not_clause(arg1)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); if (IsA(arg2, OpExpr)) { OpExpr *opex1 = (OpExpr *) arg2; arg11 = (Node *) linitial(opex1->args); arg21 = (Node *) lsecond(opex1->args); if (IsA(arg21,A_FuzzyPred)) arg2 = derivate_fuzzy_opex((Var *) arg11 ,(A_FuzzyPred *) arg21); else { if(IsA(arg21,Const)) { OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) arg11); if(aux != NULL) arg2 = aux; } } } } else { BoolExpr *boex1 = (BoolExpr *) arg2; Node *arg11 = (Node *) linitial(boex1->args); Node *arg21; if (!not_clause(arg2)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR);

PostgreSQLf Página 287

if (not_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); } } clause = (Node *) make_andclause(list_make2(arg1, arg2)); } if (boextype == OR_EXPR) { if (IsA(arg1, OpExpr)) { OpExpr *opex = (OpExpr *) arg1; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) arg1 = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); else { if(IsA(secarg,Const)) { OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) firstarg); if(aux != NULL) arg1 = aux; } } } if (IsA(arg2, OpExpr)) { opex = (OpExpr *) arg2; firstarg = (Node *) linitial(opex->args); secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) arg2 = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); else { if(IsA(secarg,Const)) { OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) firstarg); if(aux != NULL) arg2 = aux; } } } }

PostgreSQLf Página 288

else { BoolExpr *boex1 = (BoolExpr *) arg2; Node *arg11 = (Node *) linitial(boex1->args); Node *arg21; if (!not_clause(arg2)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); } } else { BoolExpr *boex1 = (BoolExpr *) arg1; Node *arg11 = (Node *) linitial(boex1->args ); Node *arg21; if (!not_clause(arg1)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); if (IsA(arg2, OpExpr)) { OpExpr *opex1 = (OpExpr *) arg2; arg11 = (Node *) linitial(opex1->args); arg21 = (Node *) lsecond(opex1->args); if (IsA(arg21,A_FuzzyPred)) arg2 = derivate_fuzzy_opex((Var *) arg11 ,(A_FuzzyPred *) arg21); else { if(IsA(arg21,Const)) {

PostgreSQLf Página 289

OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) arg11); if(aux != NULL) arg2 = aux; } } } } else { BoolExpr *boex1 = (BoolExpr *) arg2; Node *arg11 = (Node *) linitial(boex1->args); Node *arg21; if (!not_clause(arg2)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg2)) arg2 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); } } clause = (Node *) make_orclause(list_make2(arg1, arg2)); } if(boextype == NOT_EXPR) { if (IsA(arg1, OpExpr)) { OpExpr *opex = (OpExpr *) arg1; Node *firstarg = (Node *) linitial(opex->args); Node *secarg = (Node *) lsecond(opex->args); if (IsA(secarg,A_FuzzyPred)) arg1 = derivate_fuzzy_opex((Var *) firstarg ,(A_FuzzyPred *) secarg); else { if(IsA(secarg,Const)) { OpExpr *aux; constIndex++; if(hfc){ aux = derivate_fuzzy_opex_extendC((Var *) firstarg); if(aux != NULL)

PostgreSQLf Página 290

arg1 = aux; } } } } else { BoolExpr *boex1 = (BoolExpr *) arg1; Node *arg11 = (Node *) linitial(boex1->args ); Node *arg21; if(!not_clause(arg1)) arg21 = (Node *) lsecond(boex1->args); else arg21 = (Node *) NULL; if (and_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, AND_EXPR); if (or_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, OR_EXPR); if (not_clause(arg1)) arg1 = derivate_fuzzy_boex(arg11, arg21, NOT_EXPR); } clause = (Node *) make_notclause((Expr *) arg1); } return clause; }

*) Modificaciones al /src/include/nodes/plannodes.h Línea64: bool hfp; // Has fuzzy predicates? List *fuzzypred; // Fuzzy Predicates bool hfq; // Has fuzzy Quantifiers?//G. Bazan const List *fuzzyquan; // Fuzzy Quantifier bool hasboex;

Línea 179: Node *calibracion;

*) Modificaciones a /src/include/nodes/relation.h Línea 111: List *fuzzypred; /* list of Fuzzes Predicates * / List *fuzzyquan; /* list of Fuzzes Quantifiers *///G. Bazan

Línea 295: List *fp; /* relations's fuzzes predicates */ List *fq; /* relations's fuzzes quantifiers */

PostgreSQLf Página 291

*) Modificaciones a /src/backend/optimizer/util/relnode.c Línea 128: // If this relation has fuzzes predicates, put each one in the list rel->fp if (root->fuzzypred) { ListCell *lfp; foreach(lfp, root->fuzzypred) { if(IsA(lfirst(lfp),A_FuzzyPred)) { A_FuzzyPred *Afp = lfirst(lfp); if (relid == Afp->vno || (root->parse->hasFuzzy && auxiliar == Afp->vno+1)){ rel->fp = lappend(rel->fp, Afp); } } if(IsA(lfirst(lfp),A_FuzzyComp)) { A_FuzzyComp *Afc = lfirst(lfp); if (relid == Afc->vno || (root->parse->hasFuzzy && auxiliar == Afc->vno+1)){ rel->fp = lappend(rel->fp, Afc); if(Afc->typefp!=4){ lfp = lnext(lfp); rel->fp = lappend(rel->fp, lfirst(lfp)); } } else if(Afc->typefp!=4) lfp = lnext(lfp); } } } // If this relation has fuzzes quan, put each one i n the list rel->fq if (root->fuzzyquan) { ListCell *lfq; foreach(lfq, root->fuzzyquan) { A_FuzzyQuan *Afq = lfirst(lfq); if (relid == Afq->vno || (root->parse->hasFuzzy & & auxiliar == Afq->vno+1)) rel->fp = lappend(rel->fp, Afq); } }

Línea 384: joinrel->fp = NIL; joinrel->fq = NIL;

Línea 398: if (outer_rel->fp) joinrel->fp = lappend(joinrel->fp, outer_rel->fp); if (inner_rel->fp) joinrel->fp = lappend(joinrel->fp, inner_rel->fp); if (outer_rel->fq) { joinrel->fq = lappend(joinrel->fq, outer_rel->fq);

PostgreSQLf Página 292

} if (inner_rel->fq) { joinrel->fq = lappend(joinrel->fq, inner_rel->fq); }

*) Modificaciones al /src/backend/optimizer/utils/clause.c Línea 3174, 3637: case T_A_FuzzyPred: case T_A_FuzzyQuan:

*) Modificaciones a /src/backend/optimizer/plan/createplan.c Línea 292: /* * If the relation has fuzzy quantiier put in the p lan and generate Membership degree (fuzzy relation) */ if (rel->fq) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; plan->hfq = true; plan->fuzzyquan = rel->fq; cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); } /* * If the relation has fuzzy predicate put in the p lan and generate Membership degree (fuzzy relation) */ if (rel->fp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; plan->hfp = true; plan->fuzzypred = rel->fp; cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); }

PostgreSQLf Página 293

Línea 425: if (plan->hfq) { TargetEntry *tlast = list_nth(plan->targetlist, list_length(plan->targetlist)-1); if (tlast->resname != "Gr.Memb.") { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), fal se, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp) ; } } if (plan->hfp) { TargetEntry *tlast = list_nth(plan->targetlist, list_length(plan->targetlist)-1); if (tlast->resname != "Gr.Memb.") { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), fal se, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp) ; } } Línea 859: scan_plan->calibracion = root->parse->calibracion;

Línea 1540, 1657, 1755: if ((outer_plan->hfq) || (inner_plan->hfq)) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; join_plan->join.plan.hfq = true; cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(join_plan->join.plan.targ etlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList join_plan->join.plan.targetlist = lappend(join_pla n->join.plan.targetlist, tfp);

PostgreSQLf Página 294

} /* If the inner or the outer has fuzzy predicate th en put in the join */ if ((outer_plan->hfp) || (inner_plan->hfp)) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; join_plan->join.plan.hfp = true; cn = makeConst(700, 4, (Float4GetDatum(val)), fals e, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(join_plan->join.plan.targ etlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList join_plan->join.plan.targetlist = lappend(join_pla n->join.plan.targetlist, tfp); }

Línea 2491: if (lefttree->hfq) plan->hfq =true; if (lefttree->hfp) plan->hfp =true;

*) Modificaciones a /src/backend/optimizer/prep/prepunion.c Línea 83: static void validarFuzzyPredicate(Plan *plan, bool *isfuzzy);

Línea 148: bool *isfuzzy; isfuzzy = (bool *)palloc0(1 * sizeof(bool)); isfuzzy[0] = FALSE; validarFuzzyPredicate(plan,isfuzzy);

Línea 156: static void validarFuzzyPredicate(Plan *plan, bool *isfuzzy) { if(plan != NULL) switch (nodeTag(plan)) { case T_Result: if(plan->hfp) isfuzzy[0] = TRUE; validarFuzzyPredicate(plan->lefttree,isfuzzy); if(isfuzzy[0] && !plan->hfp) { TargetEntry *tlast = makeNode(TargetEntry); TargetEntry *aux = list_nth(plan->lefttree->targetlist, list_length(plan->lefttree-> targetlist)-1); tlast->expr = aux->expr; tlast->resno = list_length(plan->targetlist) + 1; tlast->resname = "Gr.Memb.";

PostgreSQLf Página 295

tlast->ressortgroupref = 0; tlast->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tlast); plan->hfp = true; } break; case T_Append: if(plan->hfp) isfuzzy[0] = TRUE; ListCell *subnode; List *cappendplans = ((Append *) plan)->appendplans; cappendplans = list_truncate(cappendplans,0); foreach(subnode,((Append *) plan)->appendplans) { Plan *subplan = (Plan *) lfirst(subnode); validarFuzzyPredicate(subplan,isfuzzy); cappendplans = lappend(cappendplans,subplan); } ((Append *) plan)->appendplans = list_truncate(((Append *) plan)->appendplans,0); foreach(subnode,cappendplans) { Plan *subplan = (Plan *) lfirst(subnode); validarFuzzyPredicate(subplan,isfuzzy); ((Append *) plan)->appendplans = lappend(((Append *) plan)->appendplans,subplan); } if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); plan->hfp = true; } break;

PostgreSQLf Página 296

case T_SubqueryScan: if(plan->hfp) isfuzzy[0] = TRUE; validarFuzzyPredicate(((SubqueryScan *) plan)->subplan,isfuzzy); if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); plan->hfp = true; plan->fuzzypred = ((SubqueryScan *) plan)->subplan->fuzzypred; } break; case T_Sort: if(plan->hfp) isfuzzy[0] = TRUE; validarFuzzyPredicate(plan->lefttree,isfuzzy); if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); plan->hfp = true; } break; case T_SetOp: if(plan->hfp) isfuzzy[0] = TRUE; validarFuzzyPredicate(plan->lefttree,isfuzzy); if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry);

PostgreSQLf Página 297

Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); plan->hfp = true; } break; case T_Unique: if(plan->hfp) isfuzzy[0] = TRUE; validarFuzzyPredicate(plan->lefttree,isfuzzy); if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = true; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp); plan->hfp = true; } break; default: if(plan->hfp) isfuzzy[0] = TRUE; if(isfuzzy[0] && !plan->hfp) { TargetEntry *tfp = makeNode(TargetEntry); Const *cn = makeNode(Const); float val = 1.0; cn = makeConst(700, 4, (Float4GetDatum(val)), false, true); tfp->expr = (Expr *) cn; tfp->resno = list_length(plan->targetlist) + 1; tfp->resname = "Gr.Memb."; tfp->ressortgroupref = 0; tfp->resjunk = false; //New Target entry in targetList plan->targetlist = lappend(plan->targetlist, tfp);

PostgreSQLf Página 298

plan->hfp = true; } break; } }

PostgreSQLf Página 299

Anexo E

Extensión del Executor

PostgreSQLf Página 300

*) Modificaciones a /src/backend/executor/execScan.c Línea 26: #include "commands/fuzzypred.h" #include "commands/fuzzyquan.h" #include <math.h> List *GrM = NIL; static bool tlist_matches_tupdesc(PlanState *ps, Li st *tlist, Index varno, TupleDesc tupdesc); static float CalculateTnorms(int normType, float x, float y, float p); static float CalculateGrmemb(int typefp, int minfp, int core1, int core2, int maxfp, float varfp, char *varfp2, List * compfplist);

Línea 55: static float CalculateTnorms(int normType, float x, float y, flo at p) { float result = 0; switch (normType) { case 1: if(x < y) result = x; else result = y; break; case 2: result = x * y; break; case 3: if( y == 1) result = x * y; else if ( x == 1) result = y; else result = 0; break; case 4: { float aux; if(p >= -1) { aux = ((1 + p) * (x + y - 1) - (p * x * y)); if(aux > 0) result = aux; else result = 0; } } break; case 5: if(p >= 0) result = (x * y) / (p + (1 - p) * (x + y - (x * y)));

PostgreSQLf Página 301

break; case 6: { float aux, aux2; if (p > 0) { aux = 1 / p; aux2 = pow( pow((1 - x) , p) + pow((1 - y) , p) , aux); if (aux2 < 1) aux = aux2; else aux = 1; result = 1 - aux; } } break; case 7: if((p >= 0) && (p <= 1)) { if((x > y) && (x > p)) result = (x * y) / x; else if ((y > x) && (y > p)) result = (x * y) / y; else if ((p > x) && (p > y)) result = (x * y) / p; } break; case 8: { float aux; if((p > 0) && ( p != 1)) { aux = 1 + (((pow(p , x) - 1) * (pow(p , y) - 1)) / ( p -1)); result = (log(aux) / log(p)); } } break; case 9: result = (x * y) / (1 + ((1 - x) + (1 - y))); break; case 10: if(x > y) result = x; else result = y; break; case 11: result = (x + y) - (x * y); break; case 12: if(y == 0) result = x; else if (x == 0) result = y; else

PostgreSQLf Página 302

result = 1; break; case 13: { float aux; if(p >= 0) { aux = x + y + (p * x * y); if(aux < 1) result = aux; else result = 1; } } break; case 14: result = (x + y) / (1 + (x * y)); break; case 15: { float aux; if(p >= 0) { aux = x + y + p - (x * y); if (aux < 1) result = aux; else result = 1; } } break; case 16: { float aux; if(p > 0) { aux = pow(pow(x , p) + pow(y , p) , (1 / p)); if(aux < 1) result = aux; else result = 1; } } break; case 17: { float aux, aux2; if((p >= 0) && (p <= 1)) { aux = 1 - x; aux2 = 1 - y; if((aux > aux2) && (aux > p))

PostgreSQLf Página 303

result = ((1 - x) * (1 - y)) / aux; else if((aux2 > aux) && (aux2 > p)) result = ((1 - x) * (1 - y)) / aux2; else if ((p > aux) && (p > aux2)) result = ((1 - x) * (1 - y)) / p; } } break; case 18: { float aux; if((p > 0) && (p != 1)) { aux = 1 + (((pow(p , (1 - x)) - 1) * (pow(p , (1 - y)) -1)) / (p - 1)); result = (log(aux) / log(p)); } } break; } return result; } static char * makePosfijo (char *exprfp) { static char infijo[500], posfijo[500], pila[500], x[1], y[1], aux[1], num[20], op1[20], op2[20]; bool fin, exito = true; int i,j; i = 0; aux[0] = ' '; strcpy(posfijo,""); strcpy(pila,""); strcpy(num,""); strcpy(op1,""); strcpy(op2,""); strcpy(infijo,exprfp); while (i < strlen(infijo) && exito) { x[0] = infijo[i]; if (EsOperando(x[0]) || x[0] == 'x' || x[0] == 'y ' || x[0] == '.') { strcat(posfijo,x); if (!EsOperando(infijo[i+1]) && infijo[i+1] != ' .') strcat(posfijo,";"); } else

PostgreSQLf Página 304

{ switch (x[0]) { case '(': strcat(pila,x); break; case ')': while (strlen(pila) != 0 && (pila[strlen(pila) - 1] != '(')) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; } if (strlen(pila) != 0) pila[strlen(pila) - 1] = '\0'; break; case '+': case '-': case '*': case '/': fin = false; while (strlen(pila) != 0 && !fin) { y[0] = pila[strlen(pila) - 1]; y[1] = '\0'; if (Prioridad(infijo[i]) <= Prioridad(y[0])) { pila[strlen(pila) - 1] = '\0'; strcat(posfijo,y); } else fin = true; } x[0] = infijo[i]; strcat(pila,x); break; default: exito = false; } } i++; } while (strlen(pila) != 0) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; }

PostgreSQLf Página 305

i = j = 0; x[0] = ' '; x[1] = '\0'; strcpy(pila,""); return (char *)&posfijo; } static float evaluacion_Posfijo(char *posfijo, floa t valor){ static char infijo[500], pila[500], x[1], aux[1], num[20], op1[20], op2[20]; int i,j,k; float resultado; i = 0; strcpy(pila,""); while (i < strlen(posfijo)) { x[0] = posfijo[i]; strcpy(num,""); strcpy(infijo,""); strcpy(op1,""); strcpy(op2,""); if(x[0] == 'x') { sprintf(num,"%f",(float)valor); strcat(pila,num); strcat(pila,";"); } else { if(EsOperando(x[0])) { k = i; while (posfijo[k] != ';' && posfijo[k] != '\0') { aux[0] = posfijo[k]; aux[1] = '\0'; strcat(num,aux); k++; } strcat(pila,num); strcat(pila,";"); i = k; } else { if(x[0] != ';') { char operador = x[0]; k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--;

PostgreSQLf Página 306

j = k + 1; while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op2,aux); j++; } pila[k+1] = '\0'; k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--; j = k + 1; while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op1,aux); j++; } pila[k+1] = '\0'; resultado = Operacion(operador, atof(op1), atof(op2)); sprintf(num,"%f",resultado); strcat(pila,num); strcat(pila,";"); } } } i++; } return atof(pila); } static float CalculateGrmemb(int typefp, int minfp, int core1, i nt core2, int maxfp, float varfp, char *varfp2, List *compfplist) { //elog(NOTICE,"type=%d, core2=%d, maxfp=%d, varfp=%f",typefp,core2,maxfp,varfp); float result = 1; switch (typefp) { case 1: if (varfp < core1) result = (varfp - minfp*1.0)/(core1 - minfp); else if (varfp >= core2 && varfp < maxfp) result = (maxfp*1.0 - varfp)/(maxfp - core2);

PostgreSQLf Página 307

break; case 2: if ((varfp >= core2) && (varfp < maxfp)) result = (maxfp*1.0 - varfp)/(maxfp - core2); break; case 3: if (varfp > minfp && varfp <= core1) result = (varfp - minfp*1.0)/(core1 - minfp); break; case 4: { ListCell *x; char s1[100]; char s2[10] = "{/\n\t}"; char *ptr, GR[20]; strcpy(GR,""); foreach(x, compfplist) { char *cad = (char *) lfirst(x); strcpy(s1, cad); ptr = strtok( s1, s2 ); cad = ptr; while( (ptr = strtok( NULL, s2 )) != NULL ) { if(strcmp(cad,varfp2) == 0) strcpy(GR,ptr); } } result = atof(GR); } break; } return result; } static float CalculateGrmemb_CompExt(char *varfp2, List *compfclist, A_FuzzyComp *n) { ListCell *x; char s1[100], *ptr1, *ptr2, *GR; A_Const *c = n->secarg; List *aux = NIL; foreach(x, n->compfclist) { char *cad = (char *) lfirst(x); strcpy(s1, cad); ptr1 = strtok( s1, "/" ); GR = strtok( NULL, "/" ); ptr1 = strtok( ptr1, "," ); ptr2 = strtok( NULL, "," ); ptr1 = strtok( ptr1, "{ \n\t( \n\t}");

PostgreSQLf Página 308

ptr2 = strtok( ptr2, "{ \n\t) \n\t}" ); if(!IsA(&c->val, String)) elog(ERROR,"Incompatible types"); else { if(strcmp(ptr1,c->val.val.str)==0){ if(strcmp(ptr2,varfp2)==0) return atof(GR); } else{ if(strcmp(ptr2,c->val.val.str)==0) if(strcmp(ptr1,varfp2)==0) return atof(GR); } } } return 0; }

Línea 521: bool isExt = false; float calibration;

Línea 601: float grmemb = 1.0, grmemb2, mingrmembQuan, mingrme mb=1.0, resultado = 0.0; if(node->ps.plan->hasboex) { if(node->ps.plan->boextype == AND_EXPR) mingrmemb = 1.0; if(node->ps.plan->boextype == OR_EXPR) mingrmemb = 0.0; } /* * Found a satisfactory scan tuple. */ // calculate membreship degree for fuzzes predicate s if (node->ps.plan->fuzzypred) { ListCell *lc; grmemb = grmemb2 = 1.0; foreach(lc, node->ps.plan->fuzzypred) { //List *X = NIL; /*node->ps.plan->X = lappend(node->ps.plan->X ,lfi rst(lc));*/ /*MemoryContext oldContext; oldContext = MemoryContextSwitchTo(node->ps.plan); MemoryContextSwitchTo(oldContext);*/ //MemoryContextSwitchTo(oldContext); if(IsA(lfirst(lc),A_FuzzyQuan)) { float *Mu, *Mu2; mingrmembQuan=0.0; if(!IsA(node->ps.plan,SubqueryScan)){

PostgreSQLf Página 309

A_FuzzyQuan *fq = (A_FuzzyQuan *)lfirst(lc); List *targs; ListCell *args; int i=0; // /*if ((atof(fq->minfp)==0 && fq->typefp==3) || ((atof(fq->maxfp)==0 && fq->typefp==2))){ elog(ERROR, "segmentation fault"); break; }*/ targs = list_copy(fq->args); Mu = malloc(list_length(targs)*sizeof (float)); //printf("Lista: %d\n", list_length(targs)); mingrmembQuan = 0.0; foreach(args, targs) { OpExpr *opex = (OpExpr *) lfirst(args); A_FuzzyPred *lfp = (A_FuzzyPred *) lsecond(opex->args); //*** Calculate membership degree for each tuple *** bool isNull; float varfp = 0.0; grmemb = 0.0; //print_slot(lfp); if(lfp->vtype == 21 || lfp->vtype == 23 || lfp->vtype == 20){ if(lfp->vtype == 21) varfp = DatumGetInt16(slot_getattr(slot, lfp->vattno, &isNu ll)); else if(lfp->vtype == 23) varfp = DatumGetInt32(slot_getattr(slot, lfp->vattno, &isNu ll)); else if(lfp->vtype == 20) varfp = DatumGetInt64(slot_getattr(slot, lfp->vattno, &isNu ll)); } else { if(lfp->vtype == 701) varfp = DatumGetFloat8(slot_getattr(slot, lfp->vattno, &isN ull)); else if(lfp->vtype == 700) varfp = DatumGetFloat4(slot_getattr(slot, lfp->vattno, &isN ull)); else elog(ERROR,"Type mismatch, value must be numeric"); } if (isNull) grmemb = 0.0;//elog(ERROR, "Variable with fuzzy predicate is Null"); else { switch (lfp->typefp) { case 1:

PostgreSQLf Página 310

if (varfp > lfp->core1 && varfp < lfp->core2) grmemb = 1.0; else if (varfp > lfp->minfp && varfp < lfp->core1) grmemb = (varfp - lfp->minfp*1.0)/(lfp->core1 - lfp->minfp); else if (varfp >= lfp->core2 && varfp < lfp->maxfp) grmemb = (lfp->maxfp*1.0 - varfp)/(lfp->maxfp - lfp->core2); break; case 2: if (varfp < lfp->core2) grmemb = 1.0; else if ((varfp >= lfp->core2) && (varfp < lfp->maxfp)) grmemb = (lfp->maxfp*1.0 - varfp)/(lfp->maxfp - lfp->core2); break; case 3: if (varfp > lfp->core1) grmemb = 1.0; else if (varfp > lfp->minfp && varfp <= lfp->core1) grmemb = (varfp - lfp->minfp*1.0)/(lfp->core1 - lfp->minfp); break; } } Mu[i]=grmemb; i++; //printf("*** calculo del grado de membresia mingrmemb: %f\n", grmemb); } seleccion(Mu, i); switch (fq->typefp) { case 1://Unimodal Mu2 = malloc(list_length(targs)*sizeof (float)); for(i=0; i<list_length(targs); i++){ float j=(float)i+1; grmemb = 0.0; if(fq->typefq==2){//Relative j=i/(float)list_length(targs); } if (j > (atof(fq->core1)) && j < (atof(fq->core2))) grmemb = 1.0; else if (j > (atof(fq->minfp)) && j < (atof(fq->core1))) grmemb = (j - atof(fq->minfp))/(atof(fq->core1) - atof(fq->minfp)); else if (j >= (atof(fq->core2)) && j < (atof(fq->maxfp)))

PostgreSQLf Página 311

grmemb = (atof(fq->maxfp) - j/(atof(fq->maxfp) - atof(fq->core2))); Mu[i]=min(grmemb,Mu[i]); Mu2[i]=min(grmemb,1-Mu[i]); } break; case 2: //Decreciente for(i=0; i<list_length(targs)-1; i++){ float j=(float)(i+1); grmemb = 0.0; if(fq->typefq==2){//Relative j=i/(float)list_length(targs); } if (j < (atof(fq->core2))) grmemb = 1.0; else if ((j >= (atof(fq->core2))) && (j < (atof(fq->maxfp)))) grmemb = (atof(fq->maxfp) - j/(atof(fq->maxfp) - atof(fq->core2))); Mu[i]=min(grmemb,1-Mu[i+1]); } break; case 3: //Creciente for(i=0; i<list_length(targs); i++){ float j=(float)(i+1); grmemb = 0.0; if(fq->typefq==2){//Relative j=(float)j/(float)list_length(targs); } if (j > (atof(fq->core1))){ grmemb = 1.0; } else if (j > (atof(fq->minfp)) && j <= (atof(fq->core1))){ grmemb = (j - atof(fq->minfp))/(atof(fq->core1) - atof(fq->minfp)); } Mu[i]=min(grmemb,Mu[i]); } break; } if(fq->typefp==1){ mingrmembQuan=min(Mu[mayor(Mu, 0, list_length(targs))],Mu2[mayor(Mu2, 0, list_length( targs)-1)]); free(Mu2); } else mingrmembQuan=Mu[mayor(Mu, 0, list_length(targs))]; free(Mu); if(node->ps.plan->hasboex) { if(node->ps.plan->boextype == AND_EXPR)

PostgreSQLf Página 312

if (mingrmembQuan < mingrmemb && mingrmembQuan >= 0 && mingrmembQuan <= 1) mingrmemb = mingrmembQuan; if(node->ps.plan->boextype == OR_EXPR) if (mingrmembQuan > mingrmemb && mingrmembQuan >= 0 && mingrmembQuan <= 1) mingrmemb = mingrmembQuan; if(node->ps.plan->boextype == NOT_EXPR) if(mingrmembQuan < 1 && mingrmembQuan > 0) mingrmemb = 1 - mingrmembQuan; } else mingrmemb = mingrmembQuan; } } if(IsA(lfirst(lc),A_FuzzyPred)) { A_FuzzyPred *lfp = lfirst(lc); //*** Calculate membership degree for each tuple ** * bool isNull; float varfp = 0; char *varfp2 = ""; if(!IsA(node->ps.plan,SubqueryScan)){ if(lfp->typefp == 4) { if (lfp->vtype == 25) varfp2 = DatumGetCString(DirectFunctionCall1(textout,slot_ge tattr(slot, lfp->vattno, &isNull))); else elog(ERROR,"Type mismatch, value must be text"); } else { if(lfp->vtype == 21 || lfp->vtype == 23 || lfp->vtype == 20){ if(lfp->vtype == 21) varfp = DatumGetInt16(slot_getattr(slot, lfp->vattno, &isNu ll)); if(lfp->vtype == 23) varfp = DatumGetInt32(slot_getattr(slot, lfp->vattno, &isNu ll)); if(lfp->vtype == 20) varfp = DatumGetInt64(slot_getattr(slot, lfp->vattno, &isNu ll)); } else { if(lfp->vtype == 701) varfp = DatumGetFloat8(slot_getattr(slot, lfp->vattno, &isN ull)); else { if(lfp->vtype == 700) varfp = DatumGetFloat4(slot_getattr(slot, lfp->vattno, &isN ull)); else

PostgreSQLf Página 313

elog(ERROR,"Type mismatch, value must be numeric"); } } } if (isNull) mingrmemb = 0.0; //elog(ERROR, "Variable with fuzzy predicate is Null"); else { switch (lfp->typefp) { case 1: grmemb = CalculateGrmemb(lfp->typefp, lfp->minfp, lfp->core1, lfp->core2, lfp->maxfp, varfp, varfp2, lfp->compfplist); if (lfp->hasfm) { if(lfp->Mtype == 1) grmemb = pow(grmemb,lfp->Mpower); if(lfp->Mtype == 2) { grmemb2 = CalculateGrmemb(lfp->modtypefp, lfp->modminfp, lfp- >modcore1, lfp->modcore2, lfp->modmaxfp, varfp, varfp2, lfp->modcompfplist); grmemb = CalculateTnorms(lfp->normType, grmemb2, grmemb, (float) varfp); grmemb = pow(grmemb,lfp->Mpower); } } break; case 2: grmemb = CalculateGrmemb(lfp->typefp, lfp->minfp, lfp->core1, lfp->core2, lfp->maxfp, varfp, varfp2, lfp->compfplist); if (lfp->hasfm) { if(lfp->Mtype == 1) grmemb = pow(grmemb, lfp->Mpower);

PostgreSQLf Página 314

if(lfp->Mtype == 2) { grmemb2 = CalculateGrmemb(lfp->modtypefp, lfp->modminfp, lfp- >modcore1, lfp->modcore2, lfp->modmaxfp, varfp, varfp2, lfp->modcompfplist); grmemb = CalculateTnorms(lfp->normType, grmemb2, grmemb, (float) varfp); grmemb = pow(grmemb, lfp->Mpower); } } break; case 3: grmemb = CalculateGrmemb(lfp->typefp, lfp->minfp, lfp->core1, lfp->core2, lfp->maxfp, varfp, varfp2, lfp->compfplist); if (lfp->hasfm) { if(lfp->Mtype == 1) grmemb = pow(grmemb, lfp->Mpower); if(lfp->Mtype == 2) { grmemb2 = CalculateGrmemb(lfp->modtypefp, lfp->modminfp, lfp- >modcore1, lfp->modcore2, lfp->modmaxfp, varfp, varfp2, lfp->modcompfplist); grmemb = CalculateTnorms(lfp->normType, grmemb2, grmemb, (float) varfp); grmemb = pow(grmemb, lfp->Mpower); } } break; case 4: grmemb = CalculateGrmemb(lfp->typefp, lfp->minfp, lfp->core1, lfp->core2, lfp->maxfp, varfp,

PostgreSQLf Página 315

varfp2, lfp->compfplist); if (lfp->hasfm) { if(lfp->Mtype == 1) grmemb = pow(grmemb, lfp->Mpower); if(lfp->Mtype == 2) { grmemb2 = CalculateGrmemb(lfp->modtypefp, lfp->modminfp, lfp- >modcore1, lfp->modcore2, lfp->modmaxfp, varfp, varfp2, lfp->modcompfplist); grmemb = CalculateTnorms(lfp->normType, grmemb2, grmemb, 0); grmemb = pow(grmemb, lfp->Mpower); } } break; case 5: { char infijo[500], posfijo[500], pila[500], x[1], y[1], aux[1], num[20], op1[20], op 2[20]; bool fin, exito = true; int i,k,j; i = 0; aux[0] = ' '; strcpy(posfijo,""); strcpy(pila,""); strcpy(num,""); strcpy(op1,""); strcpy(op2,""); strcpy(infijo,lfp->exprfp); while (i < strlen(infijo) && exito) { x[0] = infijo[i]; if (EsOperando(x[0]) || x[0] == 'x' || x[0] == '.') { strcat(posfijo,x); if (!EsOperando(infijo[i+1]) && infijo[i+1] != '.') strcat(posfijo,";"); } else { switch (x[0])

PostgreSQLf Página 316

{ case '(': strcat(pila,x); break; case ')': while (strlen(pila) != 0 && (pila[strlen(pila) - 1] != '( ')) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; } if (strlen(pila) != 0) pila[strlen(pila) - 1] = '\0'; break; case '+': case '-': case '*': case '/': fin = false; while (strlen(pila) != 0 && !fin) { y[0] = pila[strlen(pila) - 1]; y[1] = '\0'; if (Prioridad(infijo[i]) <= Prioridad(y[0])) { pila[strlen(pila) - 1] = '\0'; strcat(posfijo,y); } else fin = true; } x[0] = infijo[i]; strcat(pila,x); break; default: exito = false; } } i++; }

PostgreSQLf Página 317

while (strlen(pila) != 0) { aux[0] = pila[strlen(pila) - 1]; aux[1] = '\0'; strcat(posfijo,aux); pila[strlen(pila) - 1] = '\0'; } i = 0; x[0] = ' '; x[1] = '\0'; strcpy(pila,""); while (i < strlen(posfijo)) { x[0] = posfijo[i]; strcpy(num,""); strcpy(infijo,""); strcpy(op1,""); strcpy(op2,""); if(x[0] == 'x') { sprintf(num,"%f",(float)varfp); strcat(pila,num); strcat(pila,";"); } else { if(EsOperando(x[0])) { k = i; while (posfijo[k] != ';' && posfijo[k] != '\0') { aux[0] = posfijo[k]; aux[1] = '\0'; strcat(num,aux); k++; } strcat(pila,num); strcat(pila,";"); i = k; } else { if(x[0] != ';') { k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--;

PostgreSQLf Página 318

j = k + 1; while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op2,aux); j++; } pila[k+1] = '\0'; k = strlen(pila) - 2; while(pila[k] != ';' && pila[k] != '\0') k--; j = k + 1; while (j < strlen(pila) && pila[j] != '\0') { aux[0] = pila[j]; aux[1] = '\0'; strcat(op1,aux); j++; } pila[k+1] = '\0'; resultado = Operacion(x[0], atof(op1), atof(op2)); sprintf(num,"%f",resultado); strcat(pila,num); strcat(pila,";"); } } } i++; } grmemb = resultado; } break; } if(node->ps.plan->hasboex) { if(node->ps.plan->boextype == AND_EXPR)

PostgreSQLf Página 319

if (grmemb < mingrmemb && grmemb > 0 && grmemb <= 1) mingrmemb = grmemb; if(node->ps.plan->boextype == OR_EXPR) if (grmemb > mingrmemb && grmemb > 0 && grmemb <= 1) mingrmemb = grmemb; if(node->ps.plan->boextype == NOT_EXPR) if(grmemb < 1 && grmemb > 0) mingrmemb = 1 - grmemb; } else mingrmemb = grmemb; } } // } // printf("*** calculo del grado de membresia mingr memb: %f\n", mingrmemb); } if(IsA(lfirst(lc),A_FuzzyComp)) { A_FuzzyComp *lfp = lfirst(lc); A_FuzzyPred *fp = makeNode(A_FuzzyPred); A_Const *c = makeNode(A_Const); //*** Calculate membership degree for each tuple ** * bool isNull; float varfp = 0; char *varfp2 = ""; char *posfijo="", posfijo_r[100]; char min[20]; int i, j, k; float minimo, c1, c2, maximo; if(!IsA(node->ps.plan,SubqueryScan)){ if(lfp->typefp == 4) { if (lfp->vtype == 25) varfp2 = DatumGetCString(DirectFunctionCall1(textout,slot_ge tattr(slot, lfp->vattno, &isNull))); else elog(ERROR,"Type mismatch, value must be text"); } else { if(lfp->vtype == 21 || lfp->vtype == 23 || lfp->vtype == 20){ if(lfp->vtype == 21) varfp = DatumGetInt16(slot_getattr(slot, lfp->vattno, &isNu ll)); if(lfp->vtype == 23) varfp = DatumGetInt32(slot_getattr(slot, lfp->vattno, &isNu ll)); if(lfp->vtype == 20) varfp = DatumGetInt64(slot_getattr(slot, lfp->vattno, &isNu ll)); } else {

PostgreSQLf Página 320

if(lfp->vtype == 701) varfp = DatumGetFloat8(slot_getattr(slot, lfp->vattno, &isN ull)); else { if(lfp->vtype == 700){ varfp = DatumGetFloat4(slot_getattr(slot, lfp->vattno, &isN ull)); } else elog(ERROR,"Type mismatch, value must be numeric"); } } } if (isNull){ mingrmemb = 0.0; //elog(ERROR, "Variable with fuzzy comparator is Null"); if(lfp->typefp != 4) lc = lnext(lc); } else { switch (lfp->typefp) { case 1: lc = lnext(lc); if(IsA(lfirst(lc),A_FuzzyPred)) { fp = lfirst(lc); posfijo = makePosfijo(lfp->minfp); j = 0; sprintf(min,"%d",(int)fp->minfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0';

PostgreSQLf Página 321

minimo = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core1); j = 0; sprintf(min,"%d",(int)fp->core1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c1 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core2); j = 0; sprintf(min,"%d",(int)fp->core2); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else {

PostgreSQLf Página 322

posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c2 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->maxfp); j = 0; sprintf(min,"%d",(int)fp->maxfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; maximo = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(1, minimo, c1, c2, maximo, varfp, varfp2, NULL); } if(IsA(lfirst(lc),A_Const)) { float min1; c = lfirst(lc); if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else {

PostgreSQLf Página 323

if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } posfijo = makePosfijo(lfp->minfp); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; minimo = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core1); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i];

PostgreSQLf Página 324

j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c1 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core2); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c2 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->maxfp); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else

PostgreSQLf Página 325

{ posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; maximo = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(1, minimo, c1, c2, maximo, varfp, varfp2, NULL); } break; case 2: lc = lnext(lc); if(IsA(lfirst(lc),A_FuzzyPred)) { fp = lfirst(lc); posfijo = makePosfijo(lfp->core2); j = 0; sprintf(min,"%d",(int)fp->core2); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c2 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->maxfp);

PostgreSQLf Página 326

j = 0; sprintf(min,"%d",(int)fp->maxfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; maximo = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(2, minimo, c1, c2, maximo, varfp, varfp2, NULL); } if(IsA(lfirst(lc),A_Const)) { float min1; c = lfirst(lc); if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else { if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } posfijo = makePosfijo(lfp->core2); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++)

PostgreSQLf Página 327

{ if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c2 = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->maxfp); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; maximo = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(2, minimo, c1,

PostgreSQLf Página 328

c2, maximo, varfp, varfp2, NULL); } break; case 3: lc = lnext(lc); if(IsA(lfirst(lc),A_FuzzyPred)) { fp = lfirst(lc); posfijo = makePosfijo(lfp->minfp); j = 0; sprintf(min,"%d",(int)fp->minfp); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; minimo = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core1); j = 0; sprintf(min,"%d",(int)fp->core1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) {

PostgreSQLf Página 329

posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c1 = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(3, minimo, c1, c2, maximo, varfp, varfp2, NULL); } if(IsA(lfirst(lc),A_Const)) { float min1; c = lfirst(lc); if (IsA(&c->val, Integer)) min1 = (long) c->val.val.ival; else { if (IsA(&c->val, Float) || IsA(&c->val, String)) min1 = atof(c->val.val.str); } posfijo = makePosfijo(lfp->minfp); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else {

PostgreSQLf Página 330

posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; minimo = evaluacion_Posfijo(posfijo_r,varfp); posfijo = makePosfijo(lfp->core1); j = 0; sprintf(min,"%d",(int)min1); for(i=0; i<strlen(posfijo); i++) { if(posfijo[i] == 'y') { for(k=0;k<strlen(min);k++) { posfijo_r[j] = min[k]; j++; } } else { posfijo_r[j] = posfijo[i]; j++; } } posfijo_r[strlen(min)+strlen(posfijo)-1] = '\0'; c1 = evaluacion_Posfijo(posfijo_r,varfp); grmemb = CalculateGrmemb(3, minimo, c1, c2, maximo, varfp, varfp2, NULL); } break; case 4: grmemb = CalculateGrmemb_CompExt(varfp2, lfp->compfclist, lf p); break; } if(node->ps.plan->hasboex) { if(node->ps.plan->boextype == AND_EXPR)

PostgreSQLf Página 331

if (grmemb < mingrmemb && grmemb > 0 && grmemb <= 1) mingrmemb = grmemb; if(node->ps.plan->boextype == OR_EXPR) if (grmemb > mingrmemb && grmemb > 0 && grmemb <= 1) mingrmemb = grmemb; if(node->ps.plan->boextype == NOT_EXPR) if(grmemb < 1 && grmemb > 0) mingrmemb = 1 - grmemb; } else{ mingrmemb = grmemb; } } } else { if(lfp->typefp != 4) lc = lnext(lc); } } } }

Línea 1667: if(node->ps.plan->hfp && !node->ps.plan->fuzzypred) /*Armando Bracho*/ { if(grmemb == 1 && qual && strncmp(NameStr(resultSl ot->tts_tupleDescriptor->attrs[resultSlot->tts_tupleDe scriptor->natts-1]->attname), "Gr.Memb.", 8) == 0) { mingrmemb = grmembFuzzyPred(qual, econtext); resultSlot->tts_values[resultSlot->tts_tupleDescr iptor->natts-1] = Float4GetDatum(mingrmemb); } else{ if(IsA(node->ps.plan,SubqueryScan)){ if(strncmp(NameStr(slot->tts_tupleDescriptor->attrs[slot->tts_tupleDescriptor->natts-1]->attname ), "Gr.Memb.", 8) == 0 && node->ps.plan->hfp) resultSlot->tts_values[resultSlot->tts_tupleDescriptor->natts-1] = slot->tts_values[s lot->tts_tupleDescriptor->natts-1]; } else{ if(strncmp(NameStr(slot->tts_tupleDescriptor->attrs[slot->tts_tupleDescriptor->natts-1]->attname ), "Gr.Memb.", 8) == 0) resultSlot->tts_values[resultSlot->tts_tupleDescriptor->natts-1] = Float4GetDatum(grm emb); } } } if (node->ps.plan->fuzzypred || node->ps.plan->fuzz yquan){ if(IsA(node->ps.plan,SubqueryScan)){ ListCell *lc; foreach(lc,GrM) {

PostgreSQLf Página 332

resultSlot->tts_values[resultSlot->tts_tupleDescriptor->natts-1] = lfirst(lc); } GrM = NIL; /*Condition for Memb Degree of views as subquerie s*/ if(strncmp(NameStr(slot->tts_tupleDescriptor->att rs[slot->tts_tupleDescriptor->natts-1]->attname), "Gr.Memb. ", 8) == 0 && node->ps.plan->hfp) resultSlot->tts_values[resultSlot->tts_tupleDescriptor->natts-1] = slot->tts_values[s lot->tts_tupleDescriptor->natts-1]; } else{ GrM = lappend(GrM,Float4GetDatum(mingrmemb)); if(strncmp(NameStr(resultSlot->tts_tupleDescripto r->attrs[resultSlot->tts_tupleDescriptor->natts-1]->a ttname), "Gr.Memb.", 8) == 0) resultSlot->tts_values[resultSlot->tts_tupleDescriptor->natts-1] = Float4GetDatum(min grmemb); } } Línea 1708: if(mingrmemb>0 && mingrmemb<=1){ if(((SeqScan *)node->ps.plan)->calibracion != NULL ) { calibration = atof(((A_Const *)((SeqScan *)node-> ps.plan)->calibracion)->val.val.str); if(mingrmemb >= calibration) return resultSlot; } else return resultSlot; }

Línea 1762: GrM = NIL;

*) Modificaciones a /src/backend/executor/execqual.c Línea 43: #include "commands/fuzzypred.h" /*Armando Bracho*/

Línea 71: static Datum ExecEvalFuzzyPred(ExprState *exprstate , ExprContext *econtext,/*Armando Bracho*/ bool *isNull, ExprDoneCond *isDone);

Línea 659: /*Armando Bracho*/ static Datum ExecEvalFuzzyPred(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone) { A_FuzzyPred *n = (A_FuzzyPred *) exprstate->ex pr;

PostgreSQLf Página 333

if(isDone) *isDone = ExprSingleResult; *isNull = false; return n->minfp; }

Línea 919: fcinfo->hasFuzzyPred = false;

Línea 944: if(argstate->expr->type == T_A_FuzzyPred) { A_FuzzyPred *n = (A_FuzzyPred *) argstate->exp r; fcinfo->arg[i] = n->core1; fcinfo->argnull[i] = false; i++; fcinfo->arg[i] = n->core2; fcinfo->argnull[i] = false; i++; fcinfo->arg[i] = n->maxfp; fcinfo->argnull[i] = false; fcinfo->typefp = n->typefp; fcinfo->hasFuzzyPred = true; }

Línea 1181, 1270: if(fcinfo.hasFuzzyPred) { float grmemb; grmemb = ValidateFuzzyPred(fcinfo); if(grmemb > 0) result = 1; else result = 0; } else result = FunctionCallInvoke(&fcinfo);

Línea 1124: fcinfo.hasFuzzyPred = false;

Línea 1234: if(argstate->expr->type == T_A_FuzzyPred) { A_FuzzyPred *n = (A_FuzzyPred *) argstate->exp r; fcinfo.arg[i] = n->core1; fcinfo.argnull[i] = false; i++; fcinfo.arg[i] = n->core2; fcinfo.argnull[i] = false; i++; fcinfo.arg[i] = n->maxfp; fcinfo.argnull[i] = false; fcinfo.typefp = n->typefp; fcinfo.hasFuzzyPred = true;

PostgreSQLf Página 334

}

Línea 3292: case T_A_FuzzyPred: {

state = (ExprState *) makeNode(ExprState); state->evalfunc = ExecEvalFuzzyPred; }

*) Modificaciones a /src/include/fmrg.h Línea 66: bool hasFuzzyPred; /* identifies if a Fuzzy Pred icate is present. Armando Bracho*/ int typefp; /* identifies the Fuzzy predicate type. Armando Bracho*/

*) Modificaciones a /src/backend/executor/nodeAgg.c Línea 90: #include "commands/fuzzypred.h" /*Armando Bracho*/ #include "utils/int8.h" /*Armando Bracho*/

Línea 1060: TupleTableSlot *firstSlot, *resultSlot;

Línea 1132: float4 grmemb = 0, maxgrmemb = 0; /* * Form and return a projection tuple using the agg regate results * and the representative input tuple. Note we do n ot support * aggregates returning sets ... */ resultSlot = ExecProject(projInfo, NULL); if(aggstate->ss.ps.plan->hfp) { bool isNull; if(aggstate->ss.ps.qual) grmemb = grmembFuzzyPred(aggstate->ss.ps.qual, ec ontext); if(!aggstate->ss.ps.qual && aggstate->ss.ps.plan-> fuzzypred) { FunctionCallInfoData *fcinfo; ListCell *l; fcinfo = (FunctionCallInfoData *)palloc0(sizeof(FunctionCallInfoData)); fcinfo->flinfo = (FmgrInfo *)palloc0(sizeof(FmgrI nfo)); foreach(l, aggstate->ss.ps.plan->fuzzypred) { int i = 0, j = 0; A_FuzzyPred *fuzzypred = lfirst(l); if(*aggvalues == 0) {

PostgreSQLf Página 335

fcinfo->arg[i] = slot_getattr(aggstate->ss.ss_ScanTupleSlot, fuzzypred->vattno, &isNull); if(fuzzypred->vattno-1 < aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor->natts) fcinfo->flinfo->fn_oid = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor->attrs[fu zzypred->vattno-1]->atttypid; else{ grmemb = 2; resultSlot = firstSlot; break; } } else { fcinfo->flinfo->fn_oid = peragg->aggref->aggtype; fcinfo->arg[i] = aggvalues[j]; } switch (fcinfo->flinfo->fn_oid) { case 20: fcinfo->flinfo->fn_addr = int8eq; break; case 23: fcinfo->flinfo->fn_addr = int4eq; break; case 1700: fcinfo->flinfo->fn_addr = numeric_eq; break; } i++; fcinfo->arg[i] = fuzzypred->minfp; i++; fcinfo->arg[i] = fuzzypred->core1; i++; fcinfo->arg[i] = fuzzypred->core2; i++; fcinfo->arg[i] = fuzzypred->maxfp; fcinfo->typefp = fuzzypred->typefp; grmemb = ValidateFuzzyPred(*fcinfo); if(aggstate->numaggs > 1) { while(j < aggstate->numaggs-1) { j++; fcinfo->arg[0] = aggvalues[j]; if(grmemb == 0) grmemb = ValidateFuzzyPred(*fcinfo); if(grmemb > maxgrmemb) maxgrmemb = grmemb; } grmemb = maxgrmemb; } } } if(grmemb != 2)

PostgreSQLf Página 336

resultSlot->tts_values[resultSlot->tts_tupleDescr iptor->natts-1] = Float4GetDatum(grmemb); } if(grmemb != 0 || !aggstate->ss.ps.plan->hfp) return resultSlot;

*) Modificaciones a /src/backend/executor/nodeHashJoin.c Línea 277: if (outerNode->plan->hfp && hashNode->ps.plan->hfp ) { Datum memdeg_dt = slot_getattr(inntuple, inntuple ->tts_tupleDescriptor->natts, &isnull); float4 memdeg_in = DatumGetFloat4(memdeg_dt); if (DatumGetFloat4(slot_getattr(outerTupleSlot,outerTu pleSlot->tts_tupleDescriptor->natts,&isnull)) < memdeg_in) result->tts_values[result->tts_tupleDescriptor->natts-1] = slot_getattr(outerTupleSlot, outerTuple Slot->tts_tupleDescriptor->natts,&isnull); else result->tts_values[result->tts_tupleDescriptor->natts-1] = memdeg_dt; } else if (outerNode->plan->hfp) result->tts_values[result->tts_tupleDescriptor->natts-1] = slot_getattr(outerTupleSlot, outerTuple Slot->tts_tupleDescriptor->natts,&isnull); else if (hashNode->ps.plan->hfp) result->tts_values[result->tts_tupleDescriptor->natts-1] = slot_getattr(inntuple, inntuple->tts_tu pleDescriptor->natts,&isnull); } else { if (hashNode->ps.plan->hfp) result->tts_values[result->tts_tupleDescriptor->n atts-1] = slot_getattr(inntuple, inntuple->tts_tupleDescripto r->natts, &isnull); }

*) Modificaciones a /src/backend/executor/nodeNestLoop.c Línea 255: if (outerPlan->plan->hfp && innerPlan->plan->hfp) { if (DatumGetFloat4(outerTupleSlot->tts_values[oute rTupleSlot->tts_tupleDescriptor->natts-1]) < DatumGetFloat4(in nerTupleSlot->tts_values[innerTupleSlot->tts_tupleDescriptor->na tts-1])) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else

PostgreSQLf Página 337

result->tts_values[result->tts_tupleDescriptor->n atts-1] = innerTupleSlot->tts_values[innerTupleSlot->tts_tupl eDescriptor->natts-1]; } else if (outerPlan->plan->hfp) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else if (innerPlan->plan->hfp) result->tts_values[result->tts_tupleDescriptor->natts-1] = innerTupleSlot->tts_values[innerTupleSl ot->tts_tupleDescriptor->natts-1]; /******/ if (outerPlan->plan->hfq && innerPlan->plan->hfq) { if (DatumGetFloat4(outerTupleSlot->tts_values[oute rTupleSlot->tts_tupleDescriptor->natts-1]) < DatumGetFloat4(in nerTupleSlot->tts_values[innerTupleSlot->tts_tupleDescriptor->na tts-1])) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else result->tts_values[result->tts_tupleDescriptor->n atts-1] = innerTupleSlot->tts_values[innerTupleSlot->tts_tupl eDescriptor->natts-1]; } else if (outerPlan->plan->hfq) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else if (innerPlan->plan->hfq) result->tts_values[result->tts_tupleDescriptor->natts-1] = innerTupleSlot->tts_values[innerTupleSl ot->tts_tupleDescriptor->natts-1];

*) Modificaciones a /src/backend/executor/nodeMergejoin.c Línea 911: if (outerPlan->plan->hfp && innerPlan->plan->hfp) { if (DatumGetFloat4(outerTupleSlot->tts_values[oute rTupleSlot->tts_tupleDescriptor->natts-1]) < DatumGetFloat4(in nerTupleSlot->tts_values[innerTupleSlot->tts_tupleDescriptor->na tts-1])) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else

PostgreSQLf Página 338

result->tts_values[result->tts_tupleDescriptor->n atts-1] = innerTupleSlot->tts_values[innerTupleSlot->tts_tupl eDescriptor->natts-1]; } else if (outerPlan->plan->hfp) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else if (innerPlan->plan->hfp) result->tts_values[result->tts_tupleDescriptor->natts-1] = innerTupleSlot->tts_values[innerTupleSl ot->tts_tupleDescriptor->natts-1]; /****/ if (outerPlan->plan->hfq && innerPlan->plan->hfq) { if (DatumGetFloat4(outerTupleSlot->tts_values[oute rTupleSlot->tts_tupleDescriptor->natts-1]) < DatumGetFloat4(in nerTupleSlot->tts_values[innerTupleSlot->tts_tupleDescriptor->na tts-1])) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else result->tts_values[result->tts_tupleDescriptor->n atts-1] = innerTupleSlot->tts_values[innerTupleSlot->tts_tupl eDescriptor->natts-1]; } else if (outerPlan->plan->hfq) result->tts_values[result->tts_tupleDescriptor->n atts-1] = outerTupleSlot->tts_values[outerTupleSlot->tts_tupl eDescriptor->natts-1]; else if (innerPlan->plan->hfq) result->tts_values[result->tts_tupleDescriptor->natts-1] = innerTupleSlot->tts_values[innerTupleSl ot->tts_tupleDescriptor->natts-1];

*) Modificaciones a /src/backend/executor/nodeSetOp.c Línea 131: if (node->ps.plan->hfp) { bool isNull; float left, right; if(plannode->cmd == SETOPCMD_INTERSECT_ALL || plan node->cmd == SETOPCMD_EXCEPT_ALL) elog(ERROR,"The operations INTERSECT ALL, EXCEPT ALL can not be used in the presence of Fuzzy Predicate"); left = DatumGetFloat4(slot_getattr(inputTupleSlot,inputTup leSlot->tts_tupleDescriptor->natts,&isNull)); right = DatumGetFloat4(slot_getattr(resultTupleSlot,resultT upleSlot->tts_tupleDescriptor->natts,&isNull));

PostgreSQLf Página 339

if (plannode->cmd == SETOPCMD_INTERSECT) { if(left<right) resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->natts-1] = Float4GetDatum(lef t); else resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->natts-1] = Float4GetDatum(rig ht); } else { if (plannode->cmd == SETOPCMD_EXCEPT) { if(node->numLeft > node->numRight) if(right<1.0-left) resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->n atts-1] = Float4GetDatum(right); else{ if(1.0-left == 0.0) endOfGroup = true; else resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->n atts-1] = Float4GetDatum(1.0-left); } else if(left<1.0-right) resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->n atts-1] = Float4GetDatum(left); else{ if(1.0-right == 0.0) endOfGroup = true; else resultTupleSlot->tts_values[resultTupleSlot->tts_tupleDescriptor->n atts-1] = Float4GetDatum(1.0-right); } } } }

Línea 199: if (node->ps.plan->hfp) { if (node->numLeft > 0 && node->numRight > 0) node->numOutput = 1; else node->numOutput = 0; }

Línea 287: setopstate->ps.plan = (Plan *) node; gdm = list_nth(setopstate->ps.plan->targetlist, list_length(setopstate->ps.plan->targetlist)-1); if (strcmp(gdm->resname,"Gr.Memb.") == 0) {

PostgreSQLf Página 340

setopstate->ps.plan->targetlist = list_truncate(se topstate->ps.plan->targetlist, list_length(setopstate->ps.pl an->targetlist)-1); setopstate->ps.plan->hfp = true; gdm->resjunk = false; setopstate->ps.plan->targetlist = lappend(setopsta te->ps.plan->targetlist, gdm); }

*) Modificaciones a /src/backend/executor/nodeUnique.c

Línea 102: if(plannode->plan.hfp) { SortState *nodeS = (SortState *) outerPlan; Tuplesortstate *tuplesortstate; int current; bool isNull; float left, right; tuplesortstate = (Tuplesortstate *) nodeS->tuplesor tstate; current = tuplesortstate->current; if (execTuplesMatch(slot, resultTupleSlot, plannode->numCols, plannode->uniqColIdx, node->eqfunctions, node->tempContext)) { left = DatumGetFloat4(slot_getattr(slot,slot->tts_tupleDescriptor->natts,&isNull)); right = DatumGetFloat4(slot_getattr(resultTupleSlot,resultT upleSlot->tts_tupleDescriptor->natts,&isNull)); if (left < right) { tuplesortstate->current = current; return ExecCopySlot(slot ,resultTupleSlot); } } tuplesortstate->current = current; }

Línea 159: TargetEntry *gdm = list_nth(uniquestate->ps.plan->t argetlist, list_length(uniquestate->ps.plan->targetlist)-1); if (strcmp(gdm->resname,"Gr.Memb.") == 0) { uniquestate->ps.plan->targetlist = list_truncate(u niquestate->ps.plan->targetlist, list_length(uniquestate->ps.p lan->targetlist)-1); uniquestate->ps.plan->hfp = true; gdm->resjunk = false; uniquestate->ps.plan->targetlist = lappend(uniques tate->ps.plan->targetlist, gdm); }

PostgreSQLf Página 341

PostgreSQLf Página 342

Anexo F

Extensión de Funciones de Nodo

PostgreSQLf Página 343

*) Modificaciones a /src/backend/nodes/equalfunc.c Línea 1824: static bool _equalFuzzyPred(A_FuzzyPred *a,A_FuzzyPred *b)//Arm ando { COMPARE_STRING_FIELD(pred); COMPARE_SCALAR_FIELD(minfp); COMPARE_SCALAR_FIELD(core1); COMPARE_SCALAR_FIELD(core2); COMPARE_SCALAR_FIELD(maxfp); COMPARE_SCALAR_FIELD(typefp); COMPARE_SCALAR_FIELD(vno); COMPARE_SCALAR_FIELD(vattno); return true; }

*) Nuevo archivo en /src/backend/nodes/redfuncs.c: Línea 929: static A_FuzzyPred * _readFuzzyPredicate(void) { READ_LOCALS(A_FuzzyPred); READ_STRING_FIELD(pred); READ_INT_FIELD(minfp); READ_INT_FIELD(core1); READ_INT_FIELD(core2); READ_INT_FIELD(maxfp); READ_INT_FIELD(typefp); READ_INT_FIELD(vno); READ_INT_FIELD(vattno); READ_DONE(); }

Línea 970: else if (MATCH("A_Fuzzy_Predicate", 17)) return_value = _readFuzzyPredicate();

*) Modificaciones al /src/backend/nodes/outfuncs.c Línea 26: #include "nodes/parsenodes.h"

Línea 255: WRITE_BOOL_FIELD(hfp); WRITE_NODE_FIELD(fuzzypred); WRITE_BOOL_FIELD(hfq); WRITE_NODE_FIELD(fuzzyquan);

Línea 1836: static void _outFuzzyPred(StringInfo str, A_FuzzyPred *node) {

PostgreSQLf Página 344

WRITE_NODE_TYPE("A_Fuzzy_Predicate"); WRITE_STRING_FIELD(pred); WRITE_INT_FIELD(minfp); WRITE_INT_FIELD(core1); WRITE_INT_FIELD(core2); WRITE_INT_FIELD(maxfp); WRITE_INT_FIELD(typefp); WRITE_INT_FIELD(vno); WRITE_INT_FIELD(vattno); } static void _outFuzzyQuan(StringInfo str, A_FuzzyQuan *node) { WRITE_NODE_TYPE("Nodo A_Fuzzy_Quantifier"); WRITE_STRING_FIELD(pred); WRITE_STRING_FIELD(minfp); WRITE_STRING_FIELD(core1); WRITE_STRING_FIELD(core2); WRITE_STRING_FIELD(maxfp); WRITE_INT_FIELD(typefq); WRITE_INT_FIELD(vno); WRITE_INT_FIELD(vattno); } static void _outFuzzyComp(StringInfo str, A_FuzzyComp *node) { WRITE_NODE_TYPE("Nodo A_Fuzzy_Comparator"); WRITE_STRING_FIELD(pred); WRITE_STRING_FIELD(minfp); WRITE_STRING_FIELD(core1); WRITE_STRING_FIELD(core2); WRITE_STRING_FIELD(maxfp); WRITE_INT_FIELD(typefp); WRITE_INT_FIELD(vno); WRITE_INT_FIELD(vattno); }

Línea 2219: case T_A_FuzzyPred: _outFuzzyPred(str, obj); break; case T_A_FuzzyQuan: _outFuzzyQuan(str, obj); break; case T_A_FuzzyComp: _outFuzzyComp(str, obj); break;

*) Modificaciones al /src/backend/nodes/copyfuncs.c Línea 89: COPY_NODE_FIELD(fuzzypred); COPY_NODE_FIELD(fuzzyquan); COPY_SCALAR_FIELD(hfp);

PostgreSQLf Página 345

Línea 1707: COPY_SCALAR_FIELD(hasFuzzyPred); COPY_SCALAR_FIELD(numFuzzyPred); COPY_SCALAR_FIELD(hasFuzzyQuan); COPY_SCALAR_FIELD(numFuzzyQuan);

Línea 2713: static A_FuzzyPred * _copyAFuzzyPred(A_FuzzyPred *from) { A_FuzzyPred *newnode = makeNode(A_FuzzyPred); COPY_STRING_FIELD(pred); COPY_SCALAR_FIELD(minfp); COPY_SCALAR_FIELD(core1); COPY_SCALAR_FIELD(core2); COPY_SCALAR_FIELD(maxfp); COPY_SCALAR_FIELD(typefp); COPY_SCALAR_FIELD(vno); COPY_SCALAR_FIELD(vattno); COPY_SCALAR_FIELD(rorigtab); COPY_SCALAR_FIELD(rorigcol); return newnode; } static A_FuzzyQuan * _copyAFuzzyQuan(A_FuzzyQuan *from) { A_FuzzyQuan *newnode = makeNode(A_FuzzyQuan); COPY_STRING_FIELD(pred); COPY_STRING_FIELD(minfp); COPY_STRING_FIELD(core1); COPY_STRING_FIELD(core2); COPY_STRING_FIELD(maxfp); COPY_SCALAR_FIELD(typefp); COPY_SCALAR_FIELD(typefq); COPY_SCALAR_FIELD(vno); COPY_SCALAR_FIELD(vattno); return newnode; }

Línea 3384: case T_A_FuzzyPred: retval = _copyAFuzzyPred(from); break; case T_A_FuzzyQuan: retval = _copyAFuzzyQuan(from); break;

PostgreSQLf Página 346

Bibliografía

Bazán, G. (9 de Noviembre de 2009). PostgreSQLf: Implementación de Cuantificadores Difusos.

Naguanagua, Carabobo, Venezuela.

Bosc, P., & Pivert, O. (Febrero de 1995). SQLf: A Relational Database Language for Fuzzy

Quering. IEEE Transactions on Fuzzy Systems, Vol. 3, No. 1, .

Bracho, A. (9 de Noviembre de 2009). PostgreSQLf: Implementación de Extensiones Difusas de

manera Fuertemente Acoplada sobre el RDBMS PostgreSQL. Naguanagua, Carabobo,

Venezuela.

Cadenas Lucero, J. T. (Febrero de 2008). Una Contribución a la Interrogación Flexible de Bases

de Datos: Optimización y Evaluación a Nivel Físico. Sartenejas, Miranda, Venezuela.

Canavos, G. (1994). Probabilidad y Estadísticas: Métodos y Aplicaciones. McGraw-Hill

Companies.

Cod, E. (1970). A relational model of data for large shared data banks. Communications of the

ACM , 377-389.

Crespo, V. (Septiembre de 2006). Reingeniería del Sistema de Consultas Difusas a Bases de

Datos SQLfi. Sartenejas, Miranda, Venezuela.

Chen, H., Lim, H., & Xiao, J. (s.f.). PostgreSQL. Recuperado el 15 de Noviembre de 2009, de

University of Waterloo: http://www.cs.uwaterloo.ca/~h8chen/course/798/a1.html

Geschwwinde, E., & Shonig, H.-J. (2001). PostgreSQL Developer's Handbook. Indianapolis:

Sams.

López, J. A. (12 de Mayo de 2001). Lógica Difusa. Recuperado el 18 de Noviembre de 2009, de

Tripod: http://members.tripod.com/jesus_alfonso_lopez/FuzzyIntro.html

Rossodivita, A. (9 de Noviembre de 2009). PostgreSQLf: Sistema de Consultas Flexibles

Fuertemente Acoplado con el SGBD PostgreSQL. Naguanagua, Carabobo, Venezuela.

Stephen, J. (1979). YACC: Yet another compiler-compiler. Unix Programmer's Manual Vol_2b.

PostgreSQLf Página 347

Tineo, L. (Enero de 1998). Interrogaciones Flexibles en Base de Datos Relacionales. Sartenejas,

Miranda, Venezuela.

Tineo, L. (2006). Una contribución a la interrogación flexible de bases de datos: evaluación de

consultas cuantificadas difusas. Sartenejas, Miranda, Venezuela.