Les fonctions de construction et de maintenance que doit fournir
une méthode d'accès aux index dans IndexAmRoutine
sont :
IndexBuildResult * ambuild (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo);
Construit un nouvel index. La relation de l'index a été créée physiquement
mais elle est vide. Elle doit être remplie avec toute donnée figée nécessaire
à la méthode d'accès, ainsi que les entrées pour toutes les lignes existant
déjà dans la table. Habituellement, la fonction ambuild
appelle table_index_build_scan()
pour parcourir la table
à la recherche des lignes existantes et calculer les clés à insérer
dans l'index. La fonction doit renvoyer une structure allouée par palloc
contenant les statistiques du nouvel index.
Le drapeau amcanbuildparallel
indique si la
méthode d'accès accepte les constructions parallélisées d'index. Quand
il est configuré à true
, le système tentera d'allouer
des workers parallélisés pour la construction. Les méthodes d'accès
supportant uniquement des contructions d'index non parallélisées devraient
laisser ce drapeau à false
.
bool void ambuildempty (Relation indexRelation);
Construit un index vide et l'écrit dans le fichier d'initialisation
(INIT_FORKNUM
) de la relation. Cette méthode n'est appelée
que pour les index non journalisés ; l'index vide écrit dans ce fichier
écrasera le fichier de la relation à chaque redémarrage du serveur.
bool aminsert (Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_tid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo);
Insère une nouvelle ligne dans un index existant. Les tableaux
values
et isnull
donnent les valeurs
de clés à indexer et heap_tid
est le TID à indexer.
Si la méthode d'accès supporte les
index uniques (son drapeau amcanunique
vaut true), alors checkUnique
indique le type de
vérification d'unicité nécessaire. Elle varie si la contrainte unique est
déferrable ou non ; voir Section 62.5 pour
les détails. Normalement, la méthode d'accès a seulement besoin du
paramètre heapRelation
lors de la vérification
d'unicité (car elle doit vérifier la visibilité de la ligne dans la table).
La valeur booléenne indexUnchanged
donne une idée sur la
nature de la ligne à indexer. Quand elle vaut true, la ligne est un
duplicat d'une ligne existant dans l'index. La nouvelle ligne est une
version ultérieure de ligne MVCC logiquement non modifiée. Ceci survient
quand un UPDATE
a lieu et qu'il ne modifie par les
colonnes couvertes par l'index, mais qu'une nouvelle version est malgré
tout nécessaire. La méthode d'accès de l'index peut utiliser cette
information pour décider d'application la suppression du bas vers le haut
dans certaines parties de l'index où de nombreuses versions de la même
ligne logique s'accumulent. Notez que la mise à jour d'une colonne non clé
ou d'une colonne qui apparaît seulement dans un prédicat d'index partiel
n'affecte pas la valeur de indexUnchanged
. Le code
détermine la valeur de indexUnchanged
de chaque ligne
utilisant une approche avec une surcharge faible qui permet à la fois les
faux positifs et les faux négatifs. Les méthodes d'accès des index ne
doivent pas traiter indexUnchanged
comme une source
d'informations faisant autorité sur la visibilité ou le versionnement des
lignes.
La valeur booléenne résultante n'a de sens
que si checkUnique
vaut
UNIQUE_CHECK_PARTIAL
. Dans ce cas, un résultat true
signifie que la nouvelle entrée est reconnue comme unique alors que false
indique qu'elle pourrait ne pas être unique (et une vérification d'unicité
déferrée doit être planifiée). Dans les autres cas, renvoyer une constante
false est recommandé.
Certains index peuvent ne pas indexer toutes les lignes. Si la ligne
ne doit pas être indexée, aminsert
devrait s'achever
sans rien faire.
Si l'AM de l'index souhaite mettre en cache des données entre plusieurs
insertions successives dans l'index au sein d'un même ordre SQL, il peut
allouer de l'espace dans indexInfo->ii_Context
et
stocker un pointeur vers les données dans
indexInfo->ii_AmCache
(qui sera initialement NULL).
Si des ressources autres que la mémoire doivent être rendues après des
insertions dans l'index, aminsertcleanup
peut être
fourni, elle sera appelée quand la mémoire est rendue.
void aminsertcleanup (Relation indexRelation, IndexInfo *indexInfo);
Nettoie l'état qui a été maintenu au travers de plusieurs insertions
successives dans
indexInfo->ii_AmCache
. C'est utile si les données
nécessitent des étapes supplémentaires de nettoyage (par exemple relacher
des buffers verrouillés), et si rendre la mémoire n'est pas suffisant.
IndexBulkDeleteResult * ambulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state);
Supprime un ou des tuple(s) de l'index. Il s'agit d'une opération de
« suppression en masse » à implémenter par un parcours complet de
l'index et la vérification de chaque entrée pour voir si elle
doit être supprimée. La fonction callback
en argument
doit être appelée, sous la forme
callback(
, pour déterminer si une entrée d'index particulière,
identifiée par son TID, doit être supprimée. Elle doit retourner NULL
ou une structure issue d'un palloc contenant des statistiques sur les
effets de la suppression.
La fonction peut renvoyer NULL si aucune information n'a besoin d'être
envoyée à TID
, callback_state)
returns boolamvacuumcleanup
.
À cause d'un maintenance_work_mem
limité, la
suppression de nombreux tuples peut nécessiter d'appeler
ambulkdelete
à plusieurs reprises.
L'argument stats
est le résultat du dernier appel pour
cet index (il est NULL au premier appel dans une opération
VACUUM
). Ceci permet à la méthode d'accumuler des
statistiques sur toute l'opération. Typiquement,
ambulkdelete
modifie et renvoie la même structure
si le stats
fourni n'est pas NULL.
IndexBulkDeleteResult * amvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats);
Nettoyer après une opération VACUUM
(zéro à plusieurs
appels à ambulkdelete
). La fonction n'a pas d'autre but
que de retourner des statistiques sur les index, mais elle peut réaliser
un nettoyage en masse (réclamer les pages d'index vides, par exemple).
stats
est le retour de l'appel à
ambulkdelete
, ou NULL si
ambulkdelete
n'a pas été appelée car aucune ligne
n'avait besoin d'être supprimée. Si le résultat n'est pas NULL, il s'agit
d'une structure allouée par palloc. Les statistiques qu'elle contient
seront utilisées pour mettre à jour pg_class
,
et sont rapportées par VACUUM
si
VERBOSE
est indiqué. La fonction peut retourner NULL
si l'index n'a pas été modifié lors de l'opération
de VACUUM
mais, dans le cas contraire, il faut retourner
des statistiques correctes.
amvacuumcleanup
sera aussi appelé à la fin d'une
opération ANALYZE
. Dans ce cas,
stats
vaut toujours NULL et toute valeur de retour sera
ignorée. Ce cas peut être repéré en vérifiant
info->analyze_only
. Il est recommandé que la méthode
d'accès ne fasse rien en dehors du nettoyage après insertion pour ce type
d'appel, et cela seulement au sein d'un processus autovacuum.
bool amcanreturn (Relation indexRelation, int attno);
Vérifie si l'index supporte les parcours d'index
seul sur la colonne indiquée, en renvoyant la valeur
originale indexée de la colonne. Le numéro d'attribut est indexé à partir
de 1, c'est-à-dire que le champ attno de la première colonne est 1. Renvoie
true si supporté, false sinon. Cette fonction renvoit toujours true pour
les colonnes inclues (si elles sont supportées) car il y a peu d'intérêt à
une colonne inclue qui ne peut pas être récupérée. Si la méthode d'accès ne
supporte pas du tout les parcours d'index seul, le champ
amcanreturn
de la structure
IndexAmRoutine
peut être mis à NULL.
void amcostestimate (PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages);
Estime les coûts d'un parcours d'index. Cette fonction est décrite complètement dans Section 62.6 ci-dessous.
bytea * amoptions (ArrayType *reloptions, bool validate);
Analyse et valide le tableau reloptions d'un index. Cette fonction
n'est appelée que lorsqu'il existe un tableau reloptions non NULL pour l'index.
reloptions
est un tableau
avec des entrées de type text
et de la forme
nom
=
valeur
.
La fonction doit construire une valeur de type bytea
à
copier dans le rd_options
de l'entrée relcache
de l'index. Les données contenues dans le bytea
sont
définies par la méthode d'accès. La plupart des méthodes d'accès standard utilisent
la structure StdRdOptions
.
Lorsque validate
est true, la fonction doit remonter
un message d'erreur clair si une des options n'est pas reconnue ou a des
valeurs invalides ; quand validate
est false, les
entrées invalides sont ignorées silencieusement.
(validate
est faux lors du chargement d'options déjà
stockées dans pg_catalog
; une entrée invalide
ne peut se trouver que si la méthode d'accès a modifié ses règles pour
les options et, dans ce cas, il faut ignorer les entrées obsolètes.)
Pour obtenir le comportement par défaut, il suffit de retourner NULL.
bool amproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull);
Permet aux méthodes d'accès de surcharger le comportement par défaut de
pg_index_column_has_property
et des fonctions
liées. Si la méthode d'accès n'a pas de comportement spécial lors des
demandes de propriétés d'index, le champ
amproperty
dans sa structure
IndexAmRoutine
peut être NULL. Dans le
cas contraire, la méthode amproperty
sera appelée avec
index_oid
et attno
tous les
deux à zéro pour les appels à pg_indexam_has_property
,
ou avec un index_oid
valide et
attno
à zéro pour les appels à
pg_index_has_property
, ou avec un
index_oid
valide et un attno
supérieur à zéro pour les appels à
pg_index_column_has_property
.
prop
est une valeur enum identifiant la propriété
testée, alors que propname
est le nom de la
propriété originale. Si le code principal ne reconnaît pas le nom de la
propriété, alors prop
vaut
AMPROP_UNKNOWN
. Les méthodes d'accès peuvent définir les
noms de propriétés personnalisées en cherchant une correspondance avec
propname
(utilisez
pg_strcasecmp
pour être cohérent
avec le code principal) ; pour les noms connus du code principal,
il est préférable d'inspecter prop
. Si
la méthode amproperty
renvoit
true
, alors elle a passé le test de
propriété : elle doit renvoyer le booléen *res
ou mettre *isnull
à
true
pour renvoyer un NULL. (Les deux variables
référencées sont initialisées à false
avant l'appel.) Si
la méthode amproperty
renvoit
false
, alors le code principal continuera avec sa
logique habituelle pour tester la propriété.
Les méthodes d'accès supportant les opérateurs de tri devraient implémenter
le test de AMPROP_DISTANCE_ORDERABLE
car le
code principal ne sait pas le faire et renverra NULL. Il pourrait aussi
être avantageux d'implémenter un test sur
AMPROP_RETURNABLE
si cela peut être fait de façon plus
simple que d'ouvrir l'index et d'appeler
amcanreturn
, comme le fait
le code principal. Le comportement par défaut devrait être
satisfaisant pour toutes les autres propriétés standard.
char * ambuildphasename (int64 phasenum);
Retourne le nom textuel du numéro de phase de construction donnée. Les
numéros de phase sont ceux reportés durant une construction d'index via
l'interface pgstat_progress_update_param
. Les noms de
phase sont ensuite exposés dans la vue
pg_stat_progress_create_index
.
bool amvalidate (Oid opclassoid);
Valide les entrées du catalogue pour la classe d'opérateur indiquée, à
condition que la méthode d'accès puisse le faire raisonnablement. Par
exemple, ceci pourrait inclure le test de la présence de toutes les
fonctions de support. La fonction
amvalidate
doit renvoyer false si la classe d'opérateur
est invalide. Les problèmes devraient être rapportés avec les messages
ereport
, typiquement au niveau INFO
.
void amadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions);
Valide l'opérateur new proposé et les membres fonctions d'une famille
d'opérateur, si la méthode d'accès peut raisonnablement le faire, et
configure leur types de dépendance si le défaut n'est pas satisfaisant.
C'est appelée lors du CREATE OPERATOR CLASS
et lors du
ALTER OPERATOR FAMILY ADD
; dans ce dernier cas,
opclassoid
vaut InvalidOid
. Les
arguments List
sont des listes de structures
OpFamilyMember
, comme définies dans
amapi.h
. Les tests réalisés par cette fonction seront
typiquement un sous-ensemble de ceux réalisés par
amvalidate
, parce que
amadjustmembers
ne peut pas assumer qu'elle voit un
ensemble complet de membres. Par exemple, il serait raisonnable de
vérifier la signature d'une fonction d'appui, mais pas de vérifier si
toutes les fonctions d'appui requises sont fournies. Tout problème peut
être rapporté en renvoyant une erreur. Les champs relatifs aux dépendances
des structures OpFamilyMember
sont initialisés
par le cœur de PostgreSQL pour créer les dépendances dures sur la classe
d'opérateur si c'est CREATE OPERATOR CLASS
, ou des
dépendances douces sur la famille d'opérateur si c'est ALTER
OPERATOR FAMILY ADD
. amadjustmembers
peut
ajuster ces champs si d'autres comportements sont plus appropriés. Par
exemple, GIN, GiST et SP-GiST configurent toujours les membres opérateurs
pour avoir des dépendances douces sur la famille d'opérateur car la
connexion entre un opérateur et une classe d'opérateur est relativement
faible dans ces types d'index ; donc il est raisonnable de permettre
l'ajout et la suppression libres de membres d'opérateurs. Les fonctions
d'appui optionnelles ont typiquement des dépendances douces, pour être
supprimées si nécessaire.
Le but d'un index est bien sûr de supporter les parcours de lignes
qui correspondent à une condition WHERE
indexable,
souvent appelée qualificateur
(qualifier) ou clé de
parcours (scan key). La sémantique
du parcours d'index est décrite plus complètement dans Section 62.3,
ci-dessous. Une méthode d'accès à l'index peut supporter les parcours d'accès
standards (« plain index scan »),
les parcours d'index « bitmap »
ou les deux. Les fonctions liées au parcours qu'une méthode d'accès à
l'index doit ou devrait fournir sont :
IndexScanDesc ambeginscan (Relation indexRelation, int nkeys, int norderbys);
Prépare un parcours d'index. Les paramètres nkeys
et
norderbys
indiquent le nombre de qualificateurs et
d'opérateurs de tri qui seront utilisés dans le parcours. Ils peuvent
servir pour l'allocation d'espace. Notez que les valeurs réelles
des clés de parcours ne sont pas encore fournies. Le résultat doit être
une structure palloc. Pour des raisons
d'implémentation, la méthode d'accès à l'index doit
créer cette structure en appelant
RelationGetIndexScan()
. Dans la plupart des cas,
ambeginscan
ne fait pas grand-chose d'autre que cet appel et
parfois l'acquisition de verrous ; les parties intéressantes du début
du parcours sont dans amrescan
.
void amrescan (IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys);
Démarre ou relance un parcours d'index, possiblement avec de nouvelles
clés d'index. (Pour relancer en utilisant des clés déjà passées,
passer NULL à keys
et/ou orderbys
.) Notez
que le nombre de clés ou d'opérateurs de tri
ne doit pas être plus grand que ce qui a été passé à la fonction
ambeginscan
. En pratique, le
relancement est utilisé quand une nouvelle ligne externe est sélectionnée
par une jointure de boucle imbriquée, donc avec une nouvelle valeur de
comparaison, mais la structure de clé de parcours reste
la même.
bool amgettuple (IndexScanDesc scan, ScanDirection direction);
Récupérer la prochaine ligne d'un parcours donné, dans la direction donnée
(vers l'avant ou l'arrière de l'index). Renvoie true si une ligne a
été obtenue, false s'il ne reste aucune ligne. Dans le cas
true, le TID de la ligne est stocké dans la structure
scan
. « success » signifie juste que
l'index contient une entrée qui correspond aux clés de parcours, pas que
la ligne existe toujours dans la table ou qu'elle sera visible
dans l'instantané (snapshot)
de l'appelant. En cas de succès, amgettuple
doit passer scan->xs_recheck
à true ou false.
True signifie que ce n'est pas certain et que les conditions
représentées par les clés de parcours doivent être de nouveau vérifiées sur
la ligne dans la table après récupération. Cette différence permet de
supporter les opérateurs d'index « à perte ». Notez que cela
ne s'appliquera qu'aux conditions de parcours ; un prédicat
partiel d'index n'est jamais revérifié par les appelants à
amgettuple
.
Si l'index supporte les parcours
d'index seul (c'est-à-dire que amcanreturn
renvoit true pour chacune de ces colonnes), alors, en cas de succès, la
méthode d'accès doit aussi vérifier
scan->xs_want_itup
, et si ce dernier est true, elle
doit renvoyer les données indexées originales de cette entrée d'index. Les
colonnes pour lesquelles amcanreturn
renvoit false
peuvent êre renvoyées comme NULL. Les données peuvent être retournées sous
la forme d'un pointeur d'IndexTuple
stocké dans
scan->xs_itup
, avec un descripteur de lignes dans
scan->xs_itupdesc
; ou sous la forme d'un pointeur
HeapTuple
stocké dans
scan->xs_hitup
, avec le descripteur de ligne
scan->xs_hitupdesc
. (Le second format devrait être
utilisé lors de la reconstruction des données qui pourraient ne pas tenir
dans un IndexTuple
.) Dans tous les cas, la
gestion de la donnée référencée par le pointeur est de la responsabilité de
la méthode d'accès. Les données doivent rester bonnes au moins jusqu'au
prochain appel à amgettuple
,
amrescan
ou amendscan
pour le
parcours.
La fonction amgettuple
a seulement besoin d'exister
si la méthode d'accès supporte les parcours d'index standards. Si ce n'est
pas le cas, le champ amgettuple
de la structure
IndexAmRoutine
doit être NULL.
int64 amgetbitmap (IndexScanDesc scan, TIDBitmap *tbm);
Récupère toutes les lignes du parcours sélectionné et les ajoute au
TIDBitmap
fourni par l'appelant (c'est-à-dire un OU de l'ensemble des
identifiants de ligne dans l'ensemble où se trouve déjà le bitmap). Le
nombre de lignes récupérées est renvoyé (cela peut n'être qu'une estimation
car certaines méthodes d'accès ne détectent pas les duplicats). Lors de
l'insertion d'identifiants de ligne dans le bitmap, amgetbitmap
peut indiquer que la vérification des conditions du parcours est requis pour
des identifiants précis de transactions. C'est identique au paramètre de sortie
xs_recheck
de amgettuple
. Note :
dans l'implémentation actuelle, le support de cette fonctionnalité
est fusionné avec le support du stockage à perte du bitmap lui-même, et du coup
les appelants revérifient à la fois les conditions du parcours et le prédicat de l'index
partiel (si c'en est un) pour les lignes à revérifier. Cela ne
sera pas forcément toujours vrai. amgetbitmap
et
amgettuple
ne peuvent pas être utilisés dans le même
parcours d'index ; il existe d'autres restrictions lors de l'utilisation
de amgetbitmap
, comme expliqué dans Section 62.3.
En plus de supporter des parcours d'index ordinaires, certains types d'index peuvent souhaiter supporter des parcours d'index parallèle, qui permettent à de multiples processus clients de coopérer afin de réaliser un parcours d'index. La méthode d'accès à l'index devrait s'arranger pour que chaque processus participant au parcours retourne un sous-ensemble des lignes qui devraient être traitées par un parcours d'index ordinaire, non parallèle, mais de telle façon que l'union de tous ces sous ensembles soit identique aux ensemble de lignes qui seraient retournés par un parcours d'index ordinaire, non parallèle. En outre, bien qu'il n'y ait pas besoin d'un ordre de tri global des lignes retournée par un parcours parallèle, l'ordre du sous ensemble de lignes retourné par chaque processus participant au parcours d'index doit correspondre à l'ordre demandé. Les fonctions suivantes peuvent être implémentée pour supporter les parcours d'index parallèles :
Size amestimateparallelscan (int nkeys, int norderbys);
Estime et retourne le nombre d'octets de mémoire partagée dynamique dont la
méthode d'accès aura besoin pour effectuer le parcours d'index. (Ce chiffre
est en plus, et non à la place, de la quantité d'espace nécessaire pour les
données indépendantes de l'AM dans
ParallelIndexScanDescData
.)
Les paramètres nkeys
et norderbys
indiquent le nombre de qualificatifs et d'opérateurs de tri qui seront
utilisés dans le parcours ; les mêmes valeurs seront passées à
amrescan
. Notez que les valeurs réels des clés du
parcours ne sont pas encore fournies.
Il n'est pas nécessaire d'implémenter cette fonction pour les méthodes d'accès qui ne supportent pas les parcours d'index parallèles, où pour lesquelles le nombre d'octets de stockage additionnels vaut zéro.
void aminitparallelscan (void *target);
Cette fonction sera appelée pour initialiser la mémoire partagée dynamique
au début du parcours parallèle. target
pointera vers
au moins le nombre d'octets précédemment retourné par
amestimateparallelscan
, et cette fonction pourra
utiliser cette quantité d'espace pour stocker n'importe quelle donnée dont
elle a besoin.
Il n'est pas nécessaire d'implémenter cette fonction pour les méthodes d'accès qui ne spportent pas les parcours d'index parallèles ou dans le cas où l'espace de mémoire partagé requis ne nécessite pas d'initialisation.
void amparallelrescan (IndexScanDesc scan);
Si implémentée, cette fonction sera appelée lorsqu'un parcours d'index
parallèle doit recommencer. Elle devrait réinitialiser tout état partagé
mis en place par aminitparallelscan
de telle manière à
ce que le parcours sera recommencé depuis le début.
La fonction amgetbitmap
ne doit exister que si la
méthode d'accès supporte les parcours d'index « bitmap ». Dans le
cas contraire, le champ amgetbitmap
de la structure
IndexAmRoutine
doit être NULL.
void amendscan (IndexScanDesc scan);
Terminer un parcours et libérer les ressources. La structure scan
elle-même ne doit pas être libérée, mais tout verrou posé en interne par
la méthode d'accès doit être libéré, ainsi qu'à tout autre mémoire allouée
par ambeginscan
et les autres fonctions relatives aux
parcours.
void ammarkpos (IndexScanDesc scan);
Marquer la position courante du parcours. La méthode d'accès n'a besoin de mémoriser qu'une seule position par parcours.
La fonction ammarkpos
n'a besoin d'être fournie que
si la méthode supporte les parcours ordonnés. Dans le cas contraire, le champ
ammarkpos
dans sa structure
IndexAmRoutine
peut être NULL.
void amrestrpos (IndexScanDesc scan);
Restaurer le parcours à sa plus récente position marquée.