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

Создание пользовательских планов сканирования

Пользовательское сканирование представлено в дереве готовых планов со следующей структурой:

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 должен быть инициализирован, как и любой другой 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.

Пользовательские обратные вызовы плана сканирования

Node *(*CreateCustomScanState) (CustomScan *cscan);

Выделяет CustomScanState для данного CustomScan. Фактическое распределение часто будет больше, чем требуется для обычного CustomScanState, потому что многие провайдеры захотят встроить его в качестве первого поля более крупной структуры. Возвращаемое значение должно иметь тег узла и методы, установленные соответствующим образом, но другие поля на этом этапе следует оставить нулевыми; после того как ExecInitCustomScan выполнит базовую инициализацию, будет вызван обратный вызов BeginCustomScan, чтобы дать провайдеру пользовательского сканирования возможность сделать все остальное, что необходимо.