55.3. Выполнение нестандартного сканирования

Когда выполняется узел CustomScan, его состояние представляется структурой CustomScanState, объявленной следующим образом:

typedef struct CustomScanState
{
    ScanState ss;
    uint32    flags;
    const CustomExecMethods *methods;
} CustomScanState;

Поле ss инициализируется как и для состояния любого другого сканирования, за исключением того, что когда это сканирование для соединения, а не для базового отношения, в ss.ss_currentRelation остаётся NULL. Поле flags содержит битовую маску с тем же значением, что и в CustomPath и CustomScan. Поле methods должно указывать на объект (обычно статически размещённый), реализующий требуемые методы состояния нестандартного сканирования, подробнее описанные ниже. Обычно структура CustomScanState, которой не нужно поддерживать copyObject, фактически включается в расширенную структуру в качестве её первого члена.

55.3.1. Обработчики выполнения нестандартного сканирования

void (*BeginCustomScan) (CustomScanState *node,
                         EState *estate,
                         int eflags);

Завершает инициализацию переданного объекта CustomScanState. Стандартные поля инициализируются в ExecInitCustomScan, но все внутренние поля должны инициализироваться здесь.

TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);

Считывает следующий кортеж. В случае наличия кортежей эта функция должна записать в ps_ResultTupleSlot следующий кортеж в текущем направлении сканирования и вернуть слот с кортежем. Если же кортежей больше нет, она должна вернуть NULL или пустой слот.

void (*EndCustomScan) (CustomScanState *node);

Очищает все внутренние данные, связанные с CustomScanState. Этот метод является обязательным, но он может ничего не делать, если такие данные отсутствуют или они будут очищены автоматически.

void (*ReScanCustomScan) (CustomScanState *node);

Возвращает позицию текущего сканирования в начало и подготавливает повторное сканирование отношения.

void (*MarkPosCustomScan) (CustomScanState *node);

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

void (*RestrPosCustomScan) (CustomScanState *node);

Восстанавливает предыдущую позицию сканирования, сохранённую обработчиком MarkPosCustomScan. Данный обработчик является необязательным и должен присутствовать, только если установлен флаг CUSTOMPATH_SUPPORT_MARK_RESTORE.

Size (*EstimateDSMCustomScan) (CustomScanState *node,
                               ParallelContext *pcxt);

Оценивает объём динамической разделяемой памяти, которая потребуется для параллельной операции. Это значение может превышать объём, который будет занят фактически, но не должно быть меньше. Возвращаемое значение задаётся в байтах. Этот обработчик не является обязательным и должен устанавливаться, только если провайдер нестандартного сканирования поддерживает параллельное выполнение.

void (*InitializeDSMCustomScan) (CustomScanState *node,
                                 ParallelContext *pcxt,
                                 void *coordinate);

Инициализирует динамическую разделяемую память, которая потребуется для параллельной операции; coordinate указывает на область разделяемой памяти размера, равного возвращаемому значению EstimateDSMCustomScan. Этот обработчик является необязательным и должен устанавливаться, только если провайдер нестандартного сканирования поддерживает параллельное выполнение.

void (*ReInitializeDSMCustomScan) (CustomScanState *node,
                                   ParallelContext *pcxt,
                                   void *coordinate);

Заново инициализирует динамическую разделяемую память, требуемую для параллельной операции, перед тем как будет повторно просканирован узел нестандартного сканирования. Этот обработчик является необязательным и должен устанавливаться, только если провайдер нестандартного сканирования поддерживает параллельное выполнение. В этом обработчике рекомендуется сбрасывать только общее состояние, а в обработчике ReScanCustomScan сбрасывать только локальное. В настоящее время этот обработчик будет вызываться перед ReScanCustomScan, но лучше на этот порядок не рассчитывать.

void (*InitializeWorkerCustomScan) (CustomScanState *node,
                                    shm_toc *toc,
                                    void *coordinate);

Инициализирует локальное состояние параллельного исполнителя на основе общего состояния, заданного ведущим исполнителем во время InitializeDSMCustomScan. Этот обработчик является необязательным и должен устанавливаться, только если провайдер нестандартного сканирования поддерживает параллельное выполнение.

void (*ShutdownCustomScan) (CustomScanState *node);

Освобождает ресурсы, когда становится понятно, что этот узел больше не будет выполняться. Этот обработчик вызывается не во всех случаях; иногда может вызываться только EndCustomScan. Так как сегмент DSM, используемый параллельным запросом, освобождается сразу после вызова этого обработчика, провайдеры нестандартного сканирования, которым нужно выполнять некоторые действия до ликвидации сегмента DSM, должны реализовывать этот метод.

void (*ExplainCustomScan) (CustomScanState *node,
                           List *ancestors,
                           ExplainState *es);

Выводит дополнительную информацию для EXPLAIN об узле нестандартного сканирования. Этот обработчик является необязательным. Общие данные, сохранённые в ScanState, такие как целевой список и сканируемое отношение, будут выводиться и без этого обработчика, но с помощью этого обработчика можно выдать дополнительные, внутренние сведения.