All'atto dell'acquisizione della query, il parser accerta la corretezza della clausola where e produce la corrispondente struttura dati Oql_Query che ne rappresenta il contenuto. Una generica clausola where prevede un insieme di espressioni che possono essere composte ricorsivamente per mezzo delle classi di specializzazione di Oql_Query. I casi finora gestiti del Query Manager sono:
- espressioni booleane
Sono tre le classi java che rappresentano le corrispondenti espressioni booleane: Oql_AndExpr, Oql_OrExpr,Oql_NotExpr.Gli operandi di queste classi sono altre strutture Oql_Query.- espressioni di confronto
La classe java che le rappresenta e' Oql_Comparison i cui operatori possono essere attributi, espressi in forma semplice o attraverso una PathExpression,tipi base e operazioni aritmetiche.Normalizzazione della clausola where
Il Query Manager, prima di iniziare la fase di definizione del piano di accesso, trasforma questa generica struttura booleana in forma normale congiuntiva, cioe' and di or di predicati semplici. In questo modo si ottimizza la fase di esecuzione della query, in quanto vengono valutati il maggior numero di predicati in and e quindi viene minimizzata la quantita' di risultati restituiti dalle sorgenti locali, con una conseguente velocizzazione della fase di integrazione. Per ottenere la forma normale, la clausola where viene analizzata ricorsivamente e trasformata utilizzando i teoremi dell'algebra di commutazione:
- Valutazione di una clausola NOT:
(T1) not(x or y) = not(x) and not(y) (De Morgan)
(T1') not(x and y) = not(x) or not(y)
(T2) not(not(x)) = x (Involuzione)
Per quanto riguarda le espressioni not, utilizzando i teoremi elencati, queste possono essere considerate and o or e valutate come i due casi descritti in seguito.
- Valutazione di una clausola AND:
(T3) x and 1 = x (identita')
(T4) x and 0 = 0 (elemento nullo)
(T5) x and x = x (idempotenza)
(T6) x and not(x) = 0 (complemento)
(T7) x and (x or y) = x (assorbimento)
I teoremi precedenti vengono valutati nell'ordine descritto e, se nessuno e' applicabile, i due fattori in and vengono trasformati in modo indipendente.
- Valutazione di una clausola OR:
(T3') x or 0 = x (identita')
(T4') x or 1 = 1 (elemento nullo)
(T5') x or x = x (idempotenza)
(T6') x or not(x) = 1 (complemento)
(T7') x or (x and y) = x (assorbimento)
Nel caso in cui questi teoremi non siano applicabili viene utilizzata, quando e' possibile, la proprieta' distributiva che consente la scomposizione della clausola in due fattori in and analizzabili separatamente:
(T8) (x and y) or z = (x or z) and (y or z) (proprieta' distributiva)
(T8') x or (y and z) = (x or y) and (x or z)
Se (T8) e (T8') non sono applicabili,i due operandi vengono tradotti ricorsivamente prima di applicare nuovamente la proprieta' distributiva alla nuova clausola or cosi' ottenuta.
La forma normale congiuntiva, prevede l'eliminazione completa della negazione, la negazione di una condizione composta viene trasformata utilizzando i teoremi (T1), (T1') e (T2) visti in precedenza, se invece l'operatore not precede una condizione semplice si sostituisce la condizione con la sua complementare. Per fare cio' devono essere valutati sia l'operatore che il quantificatore presenti all'interno dell'espressione di confronto.
Un esempio di normalizzazione di una clausola WHERE e' il seguente:
Q: select name
from University_Person
where not((faculty = 'CS') or (pay > 10000))
and (title = 'full professor')
La clausola where della query Q viene posta in forma normale congiuntiva, generando Q':
Q': select name
from University_Person
where (faculty != 'CS')
and (pay <= 10000)
and (title = 'full professor')
Generazione della Query Assembler e modifica della Basic Query
Ad ogni BasicQuery viene associata una struttura Oql_SelectExpr che rappresenta la query assemblatrice. La clausola where di questa query deve contenere tutti quei predicati di selezione che non sono tradotti in nessuna delle classi locali generate.Il query Manager dopo aver svolto la fase di "Esecuzione della Query" ed aver quindi integrato i risultati provenienti dalle sorgenti locali, dovra' eseguire la Query Assemblatrice per ottenere il risultato voluto. Per fare questo pero' la Basic Query di partenza dovra' essere aggiornata,aggiungendo agli attributi di selezione quelli presenti nella clausola where della query assemblatrice,infatti questi attributi devono essere selezionati dalle sorgenti locali per poter poi eseguire correttamente la query finale.
E' stato implementato un algoritmo che analizza ricorsivamente i predicati in and della forma normale congiuntiva: se il predicato e' interamente mappato dagli attributi di almeno una delle classi locali viene inserito nel vettore di predicati da tradurre, in caso contario viene aggiunto in and alla clausola where della Query Assembler.Traduzione della clausola where
Nella fase di trasformazione della Basic Query, che e' posta sullo schema globale, in Local Query eseguibili dalle singole sorgenti, deve essere trasformata anche la clausola where. Per ogni query locale da generare viene chiamato il metodo translateWhereElement() che analizza una ad una le clausole contenute nei predicati da tradurre, controlla che la clausola sia interamente mappata dagli attributi della classe locale e se questo e' verificato richiama il metodo di traduzione che restituisce la clausola,espressa in termini locali, da aggiungere in AND ai predicati di selezione della query locale.
Esempi di traduzione della clausola where.
Possibili sviluppi futuri
In fase di "Definizione del Query-Plan", si potrebbero annalizzare i predicati di selezione contenenti valori di default , in questo modo sarebbere possibile fare una selezione delle Base Extension da valutare. Ad esempio per una query col predicato: faculty = "biology" sarebbe possibile eliminare dal piano tutte le Base Extension che coinvolgono le classi in cui e' predefinito il valore di default faculty = "cs".