Перейти к основному содержимому

Расширяемость

SP-GiST предлагает интерфейс с высоким уровнем абстракции, требуя от разработчика методов доступа реализовывать только методы, специфичные для данного типа данных. Ядро SP-GiST отвечает за эффективное отображение на диск и поиск в древовидной структуре. Оно также заботится о параллелизме и протоколировании.

Листовые кортежи дерева SP-GiST обычно содержат значения того же типа данных, что и индексируемый столбец, хотя возможно, что они также содержат представления индексируемого столбца с потерями. Кортежи, хранящиеся на корневом уровне, будут непосредственно представлять исходное значение индексированных данных, но кортежи на более низких уровнях могут содержать только частичное значение, например суффикс. В этом случае функции поддержки операторного класса должны уметь восстанавливать исходное значение, используя информацию, накопленную из внутренних кортежей, которые передаются для достижения уровня листа.

Когда индекс SP-GiST создается с колонками INCLUDE, значения этих колонок также хранятся в кортежах листа. Столбцы INCLUDE не имеют отношения к классу оператора SP-GiST, поэтому далее они не рассматриваются.

Внутренние кортежи более сложны, поскольку являются точками ветвления в дереве поиска. Каждый внутренний кортеж содержит набор из одного или нескольких узлов, которые представляют собой группы одинаковых значений листьев. Узел содержит ссылку, которая ведет либо к другому внутреннему кортежу более низкого уровня, либо к короткому списку листовых кортежей, которые находятся на одной индексной странице. Каждый узел обычно имеет метку, которая описывает его; например, в радиксном дереве меткой узла может быть следующий символ строкового значения. (В качестве альтернативы класс оператора может опустить метки узлов, если он работает с фиксированным набором узлов для всех внутренних кортежей; см. раздел «SP-GiST без меток узлов».) По желанию, внутренний кортеж может иметь префиксное значение, которое описывает все его члены. В радиксном дереве это может быть общим префиксом представленных строк. Значение префикса не обязательно является префиксом, но может быть любой информацией, необходимой классу оператора; например, в квадродереве оно может хранить центральную точку, относительно которой измеряются четыре квадранта. Тогда внутренний кортеж квадродерева будет также содержать четыре узла, соответствующие квадрантам вокруг этой центральной точки.

Некоторые алгоритмы работы с деревьями требуют знания уровня (или глубины) текущего кортежа, поэтому ядро SP-GiST предоставляет классам операторов возможность управлять подсчетом уровней во время спуска по дереву. Также поддерживается инкрементная реконструкция представленного значения, когда это необходимо, и передача дополнительных данных (называемых значениями обхода) во время спуска по дереву.

Примечание

Ядро SP-GiST заботится о записях NULL. Хотя индексы SP-GiST сохраняют записи для NULL в индексируемых столбцах, это скрыто от кода класса операторов индекса: никакие нулевые записи индекса или условия поиска никогда не будут переданы методам класса операторов. (Предполагается, что операторы SP-GiST являются строгими и поэтому не могут быть успешными для нулевых значений values.), поэтому значения NULL здесь не обсуждаются.

Существует пять пользовательских методов, которые должен предоставлять класс оператора индекса для SP-GiST, и два необязательных. Все пять обязательных методов принимают два внутренних аргумента, первый из которых - указатель на структуру C, содержащий входные значения для метода поддержки, а второй аргумент - указатель на структуру C, куда должны быть помещены выходные значения. Четыре обязательных метода просто возвращают void, поскольку все их результаты появляются в выходной структуре; но leaf_consistent возвращает булевский результат. Методы не должны изменять никаких полей своих входных структур. Во всех случаях выходная структура инициализируется нулями перед вызовом пользовательского метода. Необязательный шестой метод compress принимает в качестве единственного аргумента индексируемый массив данных и возвращает значение, пригодное для физического хранения в кортеже листа. Необязательный седьмой метод options принимает внутренний указатель на C-структуру, в которой должны быть размещены специфические для opclass параметры, и возвращает void.

Пять обязательных пользовательских методов:

config

Возвращает статическую информацию о реализации индекса, включая OID типов данных префикса и метки узла.

Объявление функции в формате SQL должно выглядеть следующим образом:

CREATE FUNCTION my_config(internal, internal) RETURNS void ...

Первый аргумент - указатель на структуру spgConfigIn языка C, содержащую входные данные для функции. Второй аргумент - указатель на структуру spgConfigOut языка C, которую функция должна заполнить результатами.

typedef struct spgConfigIn
{
Oid attType; /* Data type to be indexed */
} spgConfigIn;

typedef struct spgConfigOut
{
Oid prefixType; /* Data type of inner-tuple prefixes */
Oid labelType; /* Data type of inner-tuple node labels */
Oid leafType; /* Data type of leaf-tuple values */
bool canReturnData; /* Opclass can reconstruct original data */
bool longValuesOK; /* Opclass can cope with values > 1 page */
} spgConfigOut;

attType передается для поддержки классов полиморфных индексных операторов; для обычных классов операторов с фиксированным типом данных он всегда будет иметь одно и то же значение, поэтому его можно игнорировать.

Для классов операторов, не использующих префиксы, prefixType может быть установлен в VOIDOID. Аналогично, для классов операторов, не использующих метки узлов, labelType может быть установлен в VOIDOID. canReturnData должен быть установлен в true, если класс оператора способен восстановить первоначально подставленное значение индекса. longValuesOK должен быть установлен в true, только если attType имеет переменную длину и класс оператора способен сегментировать длинные значения путем повторной суффиксации (см. раздел «SP-GiST без меток узлов»).

leafType должен соответствовать типу хранения индекса, определенному в записи каталога opckeytype класса оператора. (Обратите внимание, что opckeytype может быть нулем, подразумевая, что тип хранения совпадает с типом ввода класса оператора, что является наиболее распространенной ситуацией). По соображениям обратной совместимости метод config может установить leafType в какое-либо другое значение, и оно будет использоваться; но это устарело, так как содержимое индекса в этом случае будет неверно идентифицировано в каталогах. Кроме того, допустимо оставить leafType неинициализированным (нулевым); это интерпретируется как значение типа хранения индекса, полученного из opckeytype.

Если attType и leafType различны, необходимо предоставить необязательный метод compress. Метод compress отвечает за преобразование индексируемых точек отсчета из attType в leafType.

choose

Выбирает метод для вставки нового значения во внутренний кортеж.

SQL-объявление функции должно выглядеть следующим образом:

CREATE FUNCTION my_choose(internal, internal) RETURNS void ...

Первый аргумент - указатель на структуру spgChooseIn языка C, содержащую входные данные для функции. Второй аргумент - указатель на структуру spgChooseOut языка C, которую функция должна заполнить данными о результате.

typedef struct spgChooseIn
{
Datum datum; /* original datum to be indexed */
Datum leafDatum; /* current datum to be stored at leaf */
int level; /* current level (counting from zero) */

/* Data from current inner tuple */
bool allTheSame; /* tuple is marked all-the-same? */
bool hasPrefix; /* tuple has a prefix? */
Datum prefixDatum; /* if so, the prefix value */
int nNodes; /* number of nodes in the inner tuple */
Datum *nodeLabels; /* node label values (NULL if none) */
} spgChooseIn;

typedef enum spgChooseResultType
{
spgMatchNode = 1, /* descend into existing node */
spgAddNode, /* add a node to the inner tuple */
spgSplitTuple /* split inner tuple (change its prefix) */
} spgChooseResultType;

typedef struct spgChooseOut
{
spgChooseResultType resultType; /* action code, see above */
union
{
struct /* results for spgMatchNode */
{
int nodeN; /* descend to this node (index from 0) */
int levelAdd; /* increment level by this much */
Datum restDatum; /* new leaf datum */
} matchNode;
struct /* results for spgAddNode */
{
Datum nodeLabel; /* new node's label */
int nodeN; /* where to insert it (index from 0) */
} addNode;
struct /* results for spgSplitTuple */
{
/* Info to form new upper-level inner tuple with one child tuple */
bool prefixHasPrefix; /* tuple should have a prefix? */
Datum prefixPrefixDatum; /* if so, its value */
int prefixNNodes; /* number of nodes */
Datum *prefixNodeLabels; /* their labels (or NULL for
* no labels) */
int childNodeN; /* which node gets child tuple */

/* Info to form new lower-level inner tuple with all old nodes */
bool postfixHasPrefix; /* tuple should have a prefix? */
Datum postfixPrefixDatum; /* if so, its value */
} splitTuple;
} result;
} spgChooseOut;

datum - исходное значение типа spgConfigIn.attType, которое должно быть вставлено в индекс. leafDatum - значение типа spgConfigOut.leafType, которое изначально является результатом значение метода compress, примененное к datum, если предоставлен метод compress, или то же значение, что и datum, в противном случае. leafDatum может изменяться на более низких уровнях дерева, если его изменяют методы choose или picksplit. Когда поиск вставки достигает листовой страницы, текущее значение leafDatum - это то, что будет храниться во вновь созданном листовом кортеже. level - уровень текущего внутреннего кортежа, начиная с нуля для корневого уровня. allTheSame - true, если текущий внутренний кортеж помечен как содержащий несколько эквивалентных узлов (см. раздел «Внутренние кортежи "все-равны"»). hasPrefix - истина, если текущий внутренний кортеж содержит префикс; если да, то prefixDatum - его значение. nNodes - количество дочерних узлов, содержащихся во внутреннем кортеже, а nodeLabels - массив значений их меток, или NULL, если меток нет.

Функция choose может определить, что новое значение совпадает с одним из существующих дочерних узлов, или что необходимо добавить новый дочерний узел, или что новое значение не соответствует префиксу кортежа, и поэтому внутренний кортеж должен быть разделен, чтобы создать менее строгий префикс.

Если новое значение совпадает с одним из существующих дочерних узлов, установите resultType в spgMatchNode. Установите nodeN в индекс (от нуля) этого узла в массиве узлов. Установите levelAdd в приращение уровня, вызванное спуском через этот узел, или оставьте его равным нулю, если класс оператора не использует уровни. Установите restDatum равным leafDatum, если класс оператора не модифицирует точки отсчета от одного уровня к другому, или иначе установите его в модифицированное значение, которое будет использоваться как leafDatum на следующем уровне.

Если необходимо добавить новый дочерний узел, установите resultType в spgAddNode. Установите nodeLabel в метку, которая будет использоваться для нового узла, и установите nodeN в индекс (от нуля), по которому нужно вставить узел в массив узлов. После добавления узла функция choose будет вызвана снова с измененным внутренним кортежем; этот вызов должен привести к результату spgMatchNode.

Если новое значение несовместимо с префиксом кортежа, установите resultType в spgSplitTuple. Это действие перемещает все существующие узлы в новый внутренний кортеж нижнего уровня и заменяет существующий внутренний кортеж кортежем с единственной нисходящей ссылкой, указывающей на новый внутренний кортеж нижнего уровня. Установите prefixHasPrefix, чтобы указать, должен ли новый верхний кортеж иметь префикс, и если да, то установите prefixPrefixDatum в значение префикса. Это новое значение префикса должно быть достаточно менее ограничительным, чем исходное, чтобы новое значение могло быть проиндексировано. Установите prefixNNodes в число узлов, необходимых в новом кортеже, и установите prefixNodeLabels в массив palloc, содержащий их метки, или в NULL, если метки узлов не требуются. Обратите внимание, что общий размер нового верхнего кортежа должен быть не больше общего размера кортежа, который он заменяет; это ограничивает длину нового префикса и новых меток. Установите childNodeN в индекс (от нуля) узла, который будет ссылаться на новый внутренний кортеж нижнего уровня. Установите postfixHasPrefix, чтобы определить, должен ли новый внутренний кортеж нижнего уровня иметь префикс, и если да, то установите postfixPrefixDatum в значение префикса. Комбинация этих двух префиксов и метки нисходящего узла (если таковая имеется) должна иметь то же значение, что и исходный префикс, поскольку нет возможности изменить метки узлов, которые перемещаются в новый кортеж нижнего уровня, а также изменить какие-либо записи дочерних индексов. После того как узел будет разделен, функция choose будет вызвана снова с заменяющим внутренним кортежем. Этот вызов может вернуть результат spgAddNode, если действием spgSplitTuple не был создан подходящий узел. В конечном итоге choose должна вернуть spgMatchNode, чтобы вставка могла спуститься на следующий уровень.

picksplit

Решает, как создать новый внутренний кортеж над набором листовых кортежей.

SQL-объявление функции должно выглядеть следующим образом:

CREATE FUNCTION my_picksplit(internal, internal) RETURNS void ...

Первый аргумент - указатель на структуру spgPickSplitIn языка C, содержащую входные данные для функции. Второй аргумент - указатель на структуру spgPickSplitOut языка C, которую функция должна заполнить данными о результате.

typedef struct spgPickSplitIn
{
int nTuples; /* number of leaf tuples */
Datum *datums; /* their datums (array of length nTuples) */
int level; /* current level (counting from zero) */
} spgPickSplitIn;

typedef struct spgPickSplitOut
{
bool hasPrefix; /* new inner tuple should have a prefix? */
Datum prefixDatum; /* if so, its value */

int nNodes; /* number of nodes for new inner tuple */
Datum *nodeLabels; /* their labels (or NULL for no labels) */

int *mapTuplesToNodes; /* node index for each leaf tuple */
Datum *leafTupleDatums; /* datum to store in each new leaf tuple */
} spgPickSplitOut;

nTuples – количество предоставленных кортежей листьев. datums – массив их значений datum типа spgConfigOut.leafType. level - текущий уровень, который разделяют все кортежи листьев и который станет уровнем нового внутреннего кортежа.

Установите hasPrefix, чтобы указать, должен ли новый внутренний кортеж иметь префикс, и если да, установите prefixDatum в значение префикса. Установите nNodes, чтобы указать количество узлов, которые будет содержать новый внутренний кортеж, и установите nodeLabels в массив значений их меток, или в NULL, если метки узлов не требуются. Установите mapTuplesToNodes в массив, задающий индекс (от нуля) узла, которому должен быть присвоен каждый кортеж листа. Установите leafTupleDatums в массив значений, которые будут храниться в новых кортежах листьев (они будут такими же, как и входные значения, если класс оператора не изменяет значения от одного уровня к другому). Обратите внимание, что функция picksplit отвечает за распределение массивов nodeLabels, mapTuplesToNodes и leafTupleDatums.

Если предоставлено более одного кортежа листьев, ожидается, что функция picksplit отнесет их к нескольким узлам; иначе невозможно разделить кортежи листьев по нескольким страницам, что является конечной целью этой операции. Поэтому, если функция picksplit в итоге поместит все кортежи листьев в один узел, основной код SP-GiST отменит это решение и сгенерирует внутренний кортеж, в котором кортежи листьев будут случайным образом распределены по нескольким одинаково помеченным узлам. Такой кортеж помечается как allTheSame, чтобы показать, что это произошло. Функции choose и inner_consistent должны проявлять соответствующую осторожность при работе с такими внутренними кортежами. Более подробную информацию см. в разделе «Внутренние кортежи "все-равны"»

Операция picksplit может быть применена к кортежу с одним листом только в том случае, если функция config установила значение longValuesOK в true и было предоставлено входное значение, превышающее размер страницы. В этом случае смысл операции заключается в удалении префикса и создании нового, более короткого значения данных листа. Вызов будет повторяться до тех пор, пока не будет получено достаточно короткое значение leaf datum, чтобы поместиться на странице. Дополнительные сведения см. в разделе «Лимиты SP-GiST»

inner_consistent

Возвращает набор узлов (ветвей), по которым следует двигаться при поиске дерева.

SQL-объявление функции должно выглядеть следующим образом:

CREATE FUNCTION my_inner_consistent(internal, internal) RETURNS void ...

Первый аргумент – указатель на структуру spgInnerConsistentIn языка C, содержащую входные данные для функции. Второй аргумент - указатель на структуру spgInnerConsistentOut языка C, которую функция должна заполнить данными о результате.

typedef struct spgInnerConsistentIn
{
ScanKey scankeys; /* array of operators and comparison values */
ScanKey orderbys; /* array of ordering operators and comparison
* values */
int nkeys; /* length of scankeys array */
int norderbys; /* length of orderbys array */

Datum reconstructedValue; /* value reconstructed at parent */
void *traversalValue; /* opclass-specific traverse value */
MemoryContext traversalMemoryContext; /* put new traverse values here */
int level; /* current level (counting from zero) */
bool returnData; /* original data must be returned? */

/* Data from current inner tuple */
bool allTheSame; /* tuple is marked all-the-same? */
bool hasPrefix; /* tuple has a prefix? */
Datum prefixDatum; /* if so, the prefix value */
int nNodes; /* number of nodes in the inner tuple */
Datum *nodeLabels; /* node label values (NULL if none) */
} spgInnerConsistentIn;

typedef struct spgInnerConsistentOut
{
int nNodes; /* number of child nodes to be visited */
int *nodeNumbers; /* their indexes in the node array */
int *levelAdds; /* increment level by this much for each */
Datum *reconstructedValues; /* associated reconstructed values */
void **traversalValues; /* opclass-specific traverse values */
double **distances; /* associated distances */
} spgInnerConsistentOut;

Массив scankeys длины nkeys описывает условие(я) поиска по индексу. Эти условия объединяются с помощью AND - интересны только те записи индекса, которые удовлетворяют всем этим условиям. (Примечание что nkeys = 0 означает, что все записи индекса удовлетворяют запросу). Обычно последовательная функция интересуется только полями sk_strategy и sk_argument каждого элемента массива, которые повторно указывают индексируемый оператор и значение сравнения. В частности, нет необходимости проверять sk_flags на предмет того, не является ли значение сравнения NULL, поскольку код ядра SP-GiST отфильтрует такие условия. Массив orderbys длины norderbys описывает операторы упорядочивания (если таковые имеются) аналогичным образом. reconstructedValue - значение, реконструированное для родительского кортежа; оно равно (Datum) 0 на корневом уровне или если функция inner_consistent не предоставила значения на родительском уровне. traversalValue - указатель на любые данные траверса, переданные из предыдущего вызова inner_consistent для родительского кортежа индексов, или NULL на корневом уровне. traversalMemoryContext - контекст памяти, в котором будут храниться выходные значения траверса (см. ниже). level - текущий уровень внутреннего кортежа, начиная с нуля для корневого уровня. returnData - истина, если для этого запроса требуются реконструированные данные; это будет так, только если функция config утверждает canReturnData. allTheSame - истина, если текущий внутренний кортеж помечен как «all-the-same» (все равны); в этом случае все узлы имеют одну и ту же метку (если она есть) и поэтому либо все, либо ни один из них не соответствует запросу (см. раздел «Внутренние кортежи "все-равны"»). hasPrefix - истина, если текущий внутренний кортеж содержит префикс; если да, то prefixDatum - его значение. nNodes - количество дочерних узлов, содержащихся во внутреннем кортеже, а nodeLabels - массив значений их меток, или NULL, если узлы не имеют меток.

nNodes должно быть задано количество дочерних узлов, которые должны быть посещены при поиске, а nodeNumbers - массив их индексов. Если класс оператора отслеживает уровни, установите levelAdds в массив приращений уровней, необходимых при спуске к каждому узлу, который необходимо посетить. (Часто эти приращения будут одинаковыми для всех узлов, но это не обязательно, поэтому используется массив). Если требуется реконструкция значений, установите reconstructedValues в массив значений, реконструированных для каждого посещаемого дочернего узла; в противном случае оставьте reconstructedValues как NULL. Предполагается, что реконструированные значения имеют тип spgConfigOut.leafType. (Однако, поскольку система ядра не будет ничего с ними делать, кроме возможного копирования, достаточно, чтобы они имели те же свойства typlen и typbyval, что и leafType). Если выполняется упорядоченный поиск, установите distances в массив значений расстояний в соответствии с массивом orderbys (узлы с наименьшим расстоянием будут обработаны первыми). В противном случае оставьте значение NULL. Если необходимо передать дополнительную внеполосную информацию («значения обхода») на более низкие уровни поиска по дереву, установите traversalValues в массив соответствующих значений обхода, по одному для каждого дочернего узла, который будет посещен; в противном случае оставьте traversalValues как NULL. Обратите внимание, что функция inner_consistent отвечает за размещение массивов nodeNumbers, levelAdds, distances, reconstructedValues и traversalValues в текущем контексте памяти. Однако все выходные значения траверса, на которые указывает массив traversalValues, должны быть выделены в traversalMemoryContext. Каждое значение траверса должно быть одним выделенным чанком.

leaf_consistent

Возвращает true, если кортеж листьев удовлетворяет запросу.

Объявление функции в формате SQL должно выглядеть следующим образом:

CREATE FUNCTION my_leaf_consistent(internal, internal) RETURNS bool ...

Первый аргумент - указатель на структуру spgLeafConsistentIn языка C, содержащую входные данные для функции. Второй аргумент - указатель на структуру spgLeafConsistentOut языка C, которую функция должна заполнить данными о результате.

typedef struct spgLeafConsistentIn
{
ScanKey scankeys; /* array of operators and comparison values */
ScanKey orderbys; /* array of ordering operators and comparison
* values */
int nkeys; /* length of scankeys array */
int norderbys; /* length of orderbys array */

Datum reconstructedValue; /* value reconstructed at parent */
void *traversalValue; /* opclass-specific traverse value */
int level; /* current level (counting from zero) */
bool returnData; /* original data must be returned? */

Datum leafDatum; /* datum in leaf tuple */
} spgLeafConsistentIn;

typedef struct spgLeafConsistentOut
{
Datum leafValue; /* reconstructed original data, if any */
bool recheck; /* set true if operator must be rechecked */
bool recheckDistances; /* set true if distances must be rechecked */
double *distances; /* associated distances */
} spgLeafConsistentOut;

Массив scankeys длины nkeys описывает условие(я) поиска по индексу. Эти условия объединяются оператором AND – только те записи индекса, которые удовлетворяют всем из них, удовлетворяют запросу. (Заметим, что nkeys = 0 подразумевает, что все записи индекса удовлетворяют запросу). Обычно последовательную функцию интересуют только поля sk_strategy и sk_argument каждой записи массива, которые повторно указывают индексируемый оператор и значение сравнения. В частности, нет необходимости проверять sk_flags на предмет того, не является ли значение сравнения NULL, поскольку код ядра SP-GiST отфильтрует такие условия. Массив orderbys длины norderbys описывает операторы упорядочивания аналогичным образом. reconstructedValue - значение, реконструированное для родительского кортежа; оно равно (Datum) 0 на корневом уровне или если функция inner_consistent не предоставила значения на родительском уровне. traversalValue - указатель на любые данные траверса, переданные из предыдущего вызова inner_consistent на родительском индексном кортеже, или NULL на корневом уровне. level - уровень текущего кортежа листьев, начиная с нуля для корневого уровня. returnData - true, если для этого запроса требуются реконструированные данные; это будет так, только если функция config утверждает canReturnData. leafDatum - ключевое значение spgConfigOut.leafType, хранящееся в текущем кортеже листьев.

Функция должна возвращать true, если кортеж листа соответствует запросу, или false, если нет. В истинном случае, если returnData равен true, то leafValue должно быть установлено в значение (типа spgConfigIn.attType), первоначально предоставленное для индексирования этого кортежа листьев. Кроме того, перепроверка может быть установлена в true, если совпадение неопределено, и поэтому оператор(ы) должен(ы) быть повторно применен(ы) к фактическому кортежу кучи, чтобы проверить совпадение. Если выполняется упорядоченный поиск, установите distances в массив значений расстояний в соответствии с массивом orderbys. В противном случае оставьте значение NULL. Если хотя бы одно из возвращаемых значений расстояний не является точным, установите для параметра recheckDistances значение true. В этом случае исполнитель вычислит точные расстояния после извлечения кортежа из кучи и при необходимости переупорядочит кортежи.

Дополнительными пользовательскими методами являются:

Datum compress (Datum in)

Преобразует элемент данных в формат, подходящий для физического хранения в листовом кортеже индекса. Принимает значение типа spgConfigIn.attType и возвращает значение типа spgConfigOut.leafType. Возвращаемое значение не должно содержать указатель на внешние TOAST-данные.

Обратите внимание, метод сжатия применяется только к значениям, подлежащим хранению. Консистентные методы получают scankeys запросов в неизменном виде, без преобразования с помощью сжатия.

options

Определяет набор видимых пользователю параметров, которые управляют поведением класса оператора.

SQL-объявление функции должно выглядеть следующим образом:

CREATE OR REPLACE FUNCTION my_options(internal)
RETURNS void
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;

Функции передается указатель на структуру local_relopts, которая должна быть заполнена набором опций, специфичных для класса оператора. Доступ к опциям можно получить из других функций поддержки с помощью макросов PG_HAS_OPCLASS_OPTIONS() и PG_GET_OPCLASS_OPTIONS().

Поскольку представление ключа в SP-GiST является гибким, оно может зависеть от заданных пользователем параметров.

Все методы поддержки SP-GiST обычно вызываются в кратковременных контекстах памяти; то есть CurrentMemoryContext будет сброшен после обработки каждого кортежа. Таким образом, можно не заботиться об освобождении любых блоков памяти, выделенных функцией palloc. (Метод config является исключением: он должен стараться избегать утечек памяти. Но обычно метод config не должен делать ничего, кроме как присваивать константы в переданную структуру параметров).

Если индексируемый столбец имеет сортируемый тип данных, правило сортировки индекса будет передаваться всем опорным методам, используя стандартный механизм PG_GET_COLLATION().