L'interface GIN a un haut niveau d'abstraction. De ce fait, la personne qui code la méthode d'accès n'a besoin d'implanter que les sémantiques du type de données accédé. La couche GIN prend en charge la gestion de la concurrence, des traces et des recherches dans la structure de l'arbre.
Pour obtenir une méthode d'accès GIN fonctionnelle, il suffit d'implanter quelques méthodes utilisateur. Celles-ci définissent le comportement des clés dans l'arbre et les relations entre clés, valeurs indexées et requêtes indexables. En résumé, GIN combine extensibilité, généralisation, ré-utilisation du code à une interface claire.
Voici les deux méthodes qu'une classe d'opérateur GIN doit fournir sont :
Datum *extractValue(Datum inputValue, int32 *nkeys,
bool **nullFlags)
Retourne un tableau de clés alloué par palloc en fonction
d'un item à indexer. Le nombre de clés retournées doit
être stocké dans *nkeys
. Si une des clés
peut être nulle, allouez aussi par palloc un tableau de
*nkeys
champs de type bool
,
stockez son adresse dans
*nullFlags
, et positionnez les drapeaux null où
ils doivent l'être. *nullFlags
peut être laissé
à NULL
(sa valeur initiale) si toutes les clés sont non-nulles.
La valeur retournée peut être NULL
si l'élément ne contient aucune clé.
Datum *extractQuery(Datum query, int32 *nkeys,
StrategyNumber n, bool **pmatch, Pointer **extra_data,
bool **nullFlags, int32 *searchMode)
Renvoie un tableau de clés en fonction de la valeur à requêter ; c'est-à-dire
que query
est la valeur du côté droit d'un opérateur
indexable dont le côté gauche est la colonne indexée.
n
est le numéro de stratégie de l'opérateur dans la
classe d'opérateur (voir Section 37.16.2). Souvent,
extractQuery
doit consulter
n
pour déterminer le type de données de
query
et la méthode à utiliser pour extraire les valeurs des clés.
Le nombre de clés renvoyées doit être stocké dans
*nkeys
.
Si une des clés peut être nulle, allouez aussi par palloc un tableau de
*nkeys
champs de type bool
, stockez son address à
*nullFlags
, et positionnez les drapeaux NULL
où_ils doivent l'être.
*nullFlags
peut être laissé à NULL (sa valeur initiale)
si toutes les clés sont non-nulles.
La valeur de retour peut être NULL
si query
ne contient aucune clé.
searchMode
est un argument de sortie qui permet à
extractQuery
de spécifier des détails sur comment la
recherche sera effectuée.
Si *searchMode
est positionné à
GIN_SEARCH_MODE_DEFAULT
(qui est la valeur à laquelle il
est initialisé avant l'appel), seuls les items qui correspondent à au moins une des
clés retournées sont considérées comme des candidats à correspondance.
Si *searchMode
est positionné à
GIN_SEARCH_MODE_INCLUDE_EMPTY
, alors en plus des items qui
contiennent au moins une clé correspondant, les items qui ne contiennent aucune clé
sont aussi considérées comme des candidats à correspondance. (Ce mode est utile pour implémenter
un opérateur «est sous-ensemble de», par exemple.)
Si *searchMode
est positionné à GIN_SEARCH_MODE_ALL
,
alors tous les items non nuls de l'index sont candidats à correspondance, qu'ils aient
une clé qui corresponde à celles retournées ou non. (Ce mode est beaucoup
plus lent que les deux autres, mais il peut être nécessaire pour implémenter des cas exceptionnels
correctement. Un opérateur qui a besoin de ce mode dans la plupart des cas n'est
probablement pas un bon candidat pour une classe d'opérateur GIN.)
Les symboles à utiliser pour positionner ce mode sont définis dans
access/gin.h
.
pmatch
est un paramètre de sortie à utiliser quand une correspondance
partielle est permise. Pour l'utiliser, extractQuery
doit allouer
un tableau de booléens *nkeys
et stocker son adresse dans
*pmatch
. Chaque élément du tableau devrait être positionné
à TRUE si la clé correspondante a besoin d'une correspondance partielle, FALSE sinon.
Si *pmatch
est positionné à NULL
alors GIN suppose qu'une
mise en correspondance partielle n'est pas nécessaire. La variable est
initialisée à NULL
avant l'appel, et peut donc être simplement ignorée
par les classes d'opérateurs qui ne supportent pas les correspondances
partielles.
extra_data
est un paramètre de sortie qui autorise
extractQuery
à passer des données supplémentaires aux
méthodes consistent
et comparePartial
.
Pour l'utiliser, extractQuery
doit allouer un tableau
de pointeurs *nkeys
et stocker son adresse à
*extra_data
, puis stocker ce qu'il souhaite dans les
pointeurs individuels. La variable est initialisée à NULL
avant l'appel,
afin que ce paramètre soit simplement ignoré par une classe d'opérateurs
qui n'a pas besoin de données supplémentaires. Si *extra_data
est positionné, le tableau dans son ensemble est passé à la méthode
consistent
, et l'élément approprié à la méthode
comparePartial
.
Une classe d'opérateur doit aussi fournir une fonction pour vérifier si un
élément indexé correspond à la requête. Elle vient en deux versions, une
fonction booléenne consistent
et une fonction ternaire
triConsistent
. Cette dernière couvre les fonctionnalités
des deux, donc fournir uniquement triConsistent
est suffisant. Cependant, si
la variante booléenne est bien moins coûteuse à calculer, il peut être
avantageux de fournir les deux. Si seule la variante booléenne est fournie,
certaines optimisations dépendant de la réfutation d'éléments d'index avant
de récupérer toutes les clés sont désactivées.
bool consistent(bool check[], StrategyNumber n, Datum query,
int32 nkeys, Pointer extra_data[], bool *recheck,
Datum queryKeys[], bool nullFlags[])
Retourne TRUE si un item indexé répond à l'opérateur de requête possédant
le numéro de stratégie n
(ou pourrait le satisfaire, si
l'indication recheck est retournée). Cette fonction n'a pas d'accès direct aux valeurs
des items indexés. Au lieu de cela, ce qui est disponible, c'est la connaissance
de quelles valeurs de clés extraites de la requête apparaissent dans un item indexé donné.
Le tableau check
a une longueur de nkeys
, qui
est la même que le nombre de clés retourné précédemment par extractQuery
pour ce datum query
.
Chaque élément du tableau check
est TRUE si l'item indexé contient
la clé de requête correspondante, c'est à dire, si (check[i] == TRUE) la i-ème clé du
tableau résultat de extractQuery
est présente dans l'item indexé.
Le datum query
original est passé au cas où la méthode contains
aurait besoin de le consulter, de même que les tableaux queryKeys[]
et
nullFlags[]
retournée précédemment par extractQuery
, ou
NULL
si aucun.
Quand extractQuery
retourne une clé nulle dans
queryKeys[]
, l'élément correspondant de check[]
est TRUE si l'item indexé contient une clé nulle; c'est à dire que la sémantique de
check[]
est comme celle de IS NOT DISTINCT FROM
.
La fonction consistent
peut examiner l'élément correspondant de
nullFlags[]
si elle a besoin de faire la différence entre une
correspondance de valeur «normale» et une correspondance nulle.
En cas de réussite, *recheck
devrait être positionné à TRUE
si les enregistrements de la table doivent être revérifiées par rapport à l'opérateur de
la requête, ou FALSE si le test d'index est exact. Autrement dit, une valeur de retour à FALSE
garantit que l'enregistrement de la table ne correspond pas; une valeur de retour à TRUE avec
*recheck
à FALSE garantit que l'enregistrement de la table correspond à
la requête; et une valeur de retour à TRUE avec *recheck
à TRUE signifie
que l'enregistrement de la table pourrait correspondre à la requête, et qu'il doit être récupéré
et re-vérifié en évaluant l'opérateur de la requête directement sur l'item initialement indexé.
GinTernaryValue triConsistent(GinTernaryValue check[], StrategyNumber n, Datum query,
int32 nkeys, Pointer extra_data[],
Datum queryKeys[], bool nullFlags[])
triConsistent
est similaire à
consistent
, mais en lieu dde booléens dans le vecteur
check[]
, il existe trois valeurs possibles à chaque
clé : GIN_TRUE
, GIN_FALSE
et
GIN_MAYBE
. GIN_FALSE
et
GIN_TRUE
ont la même signification que des valeurs
booléennes standards alors que GIN_MAYBE
signifie que la
présence de cette clé est inconnue. Quand des valeurs
GIN_MAYBE
sont présentes, la fonction devrait seulement
renvoyer GIN_TRUE
si l'élément correspond que l'élément de l'index
contient ou non les clés de la requête correspondante. De la même façon,
la fonction doit renvoyer GIN_FALSE
seulement si l'élément ne correspond
pas, qu'il contienne ou non des clés GIN_MAYBE
. Si le résultat dépend des
entrées GIN_MAYBE
, autrement dit si la correspondance ne peut pas être
confirmée ou réfutée d'après les clés connues de requête, la fonction doit
renvoyer GIN_MAYBE
.
Quand il n'y a pas de valeurs GIN_MAYBE
dans le vecteur
check
, la valeur de retour GIN_MAYBE
est équivalent à configurer le drapeau recheck
dans
la fonction booléenne consistent
.
De plus, GIN doit avoir un moyen de trier les valeurs des clés stockées dans l'index. La classe d'opérateur peut définir l'ordre de tri en spécifiant une méthode de comparaison :
int compare(Datum a, Datum b)
Compare deux clés (pas des items indexés !) et retourne un entier inférieur à zéro, zéro ou supérieur à zéro, indiquant si la première clé est inférieure à, égale à ou supérieure à la seconde. Les clés NULL ne sont jamais fournit en argument à cette fonction.
Sinon, si la classe d'opérateur ne fournit pas de méthode
compare
, GIN cherchera la classe d'opérateur par défaut
pour le type de donnée de la clé d'index, et utilisera sa fonction de
comparaison. Il est recommandé de spécifier la fonction de comparaison dans
une classe d'opérateur GIN destinée à un seul type de donnée, car rechercher
la classe d'opérateur btree coûte quelques cycles. Cependant, les classes
d'opérateur GIN polymorphiques (telle que array_ops
) ne
peuvent typiquement pas spécifier une seule fonction de comparaison.
Une classe d'opérateurs pour GIN peut fournir en option les méthodes suivantes :
int comparePartial(Datum partial_key, Datum key, StrategyNumber n,
Pointer extra_data)
Compare une requête de correspondance partielle à une clé d'index. Renvoie
un entier dont le signe indique le résultat : inférieur à zéro
signifie que la clé d'index ne correspond pas à la requête mais que le
parcours d'index va continuer ; zéro signifie que la clé d'index
ne correspond pas à la requête ; supérieur à zéro indique que le
parcours d'index doit s'arrêter car il n'existe pas d'autres
correspondances. Le numéro de stratégie n
de l'opérateur
qui a généré la requête de correspondance partielle est fourni au cas où
sa sémantique est nécessaire pour déterminer la fin du parcours. De plus,
extra_data
est l'élément correspondant du tableau
extra-data fait par extractQuery
, ou NULL
sinon.
Les clés NULL ne sont jamais passées à cette fonction.
void options(local_relopts *relopts)
Définit un ensemble de paramètres visibles aux utilisateurs qui contrôlent le comportement d'une classe d'opérateur.
La fonction options
se voit donné un pointeur
vers une structure local_relopts
qui doit
être remplie avec un ensemble d'options spécifiques à la classe
d'opérateur. Les options peuvent être accédées à partir des autres
fonctions de support en utilisant les macros
PG_HAS_OPCLASS_OPTIONS()
et
PG_GET_OPCLASS_OPTIONS()
.
Étant donné que l'extraction des clés des valeurs indexées et la représentation de la clé dans GIN sont flexibles, elles peuvent dépendre de paramètres spécifiés par l'utilisateur.
Pour supporter des requêtes à « correspondance partielle »,
une classe d'opérateur doit fournir la méthode comparePartial
,
et sa méthode extractQuery
doit positionner le
paramètre pmatch
quand une requête à correspondance
partielle est rencontrée. Voir Section 66.4.2 pour les détails.
Le type de données réel des différentes valeurs Datum
mentionnées ci-dessus varient en fonction de la classe d'opérateurs. Les
valeurs d'élément passée à extractValue
sont toujours
du type d'entrée de la classe d'opérateur, et toutes les valeurs clé doivent
être du type de STORAGE
de la classe. Le type de
l'argument query
passé à extractQuery
,
consistent
et triConsistent
est le
type de l'argument côté droit de l'opérateur du membre de la classe identifié
par le numéro de stratégie. Ce n'est pas nécessairement le même que l'élément
indexé, tant que des valeurs de clés d'un type correct peuvent en être
extraites. Néanmoins, il est recommandé que les déclarations SQL de ces trois
fonctions de support utilisent le type de données indexé de la classe
d'opérateur pour l'argument query
, même si le type réel
pourrait être différent suivant l'opérateur.