59.2. Создание нестандартных планов сканирования
Нестандартное сканирование представляется в окончательном дереве плана в виде следующей структуры:
typedef struct CustomScan { Scan scan; uint32 flags; List *custom_plans; List *custom_exprs; List *custom_private; List *custom_scan_tlist; Bitmapset *custom_relids; const CustomScanMethods *methods; } CustomScan;
Объект в поле scan
должен быть инициализирован, как и для любого другого сканирования, и включать оценки стоимости, целевые списки, условия и т. д. Поле flags
содержит битовую маску с тем же значением, что и в CustomPath
. В поле custom_plans
могут быть сохранены дочерние узлы Plan
. В custom_exprs
могут быть сохранены деревья выражений, которые будут исправляться кодом в setrefs.c
и subselect.c
, а в custom_private
следует сохранить другие внутренние данные, которые будут использоваться только самим провайдером нестандартного сканирования. Поле custom_scan_tlist
может содержать NIL при сканировании базового отношения, что будет показывать, что нестандартное сканирование возвращает кортежи, соответствующие типу строк базового отношения. В противном случае оно должно указывать на целевой список, описывающий фактические кортежи. Список custom_scan_tlist
должен устанавливаться при соединениях и может задаваться при сканировании, если провайдер сканирования может вычислять какие-либо выражения без переменных. Поле custom_relids
заполняется ядром и задаёт набор отношений (индексов в списке отношений), которые обрабатывает данный узел сканирования; когда имеет место сканирование, а не соединение, в этом списке будет всего один элемент. Поле methods
должно указывать на объект (обычно статически размещённый), реализующий требуемые методы нестандартного сканирования, которые подробнее описываются ниже.
Когда CustomScan
сканирует одно отношение, в scan.scanrelid
должен задаваться индекс сканируемой таблицы в списке отношений. Когда он заменяет соединение, поле scan.scanrelid
должно быть нулевым.
Деревья планов должны поддерживать возможность копирования функцией copyObject
, так что все данные, сохранённые в «дополнительных» полях, должны быть узлами, которые может обработать эта функция. Более того, провайдеры нестандартного сканирования не могут заменять структуру CustomScan
расширенной структурой, её содержащей, что возможно с CustomPath
или CustomScanState
.
59.2.1. Обработчики плана нестандартного сканирования
Node *(*CreateCustomScanState) (CustomScan *cscan);
Выделяет структуру CustomScanState
для заданного объекта CustomScan
. Фактически выделенная область будет обычно больше, чем требуется для самой структуры CustomScanState
, так как многие провайдеры могут включать её в расширенную структуру в качестве первого поля. В возвращаемом значении должны быть подходящим образом заполнены тег узла и поле methods
, но другие поля на данном этапе должны быть обнулены; после того как ExecInitCustomScan
произведёт базовую инициализацию, будет вызван обработчик BeginCustomScan
, в котором провайдер нестандартного сканирования может выполнить все остальные требуемые действия.