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

Правила декларирования системного каталога

примечание

Эта страница переведена при помощи нейросети GigaChat.

Ключевой частью заголовочного файла каталога является описание структуры на C, определяющее вид каждой строки каталога. Оно начинается с макроса CATALOG, который, если говорить о компиляторе C, является просто сокращенной записью typedef struct FormData_имя_каталога. Каждое поле в этой структуре порождает столбец каталога. Поля можно дополнить макросами свойств BKI, объявленными в genbki.h. Например, для поля можно задать значение по умолчанию или указать, допускается ли в нем NULL. Строку CATALOG можно также дополнить некоторыми другими макросами свойств BKI, объявленными в genbki.h и определяющими другие свойства каталога в целом, например, является ли он общим.

Код кеша системного каталога (и практически весь код, работающий с каталогом) основывается на том, что части всех кортежей системных каталогов с постоянным размером реально существуют, так как они отображены на структуры языка C. Поля переменной длины и допускающие значение NULL должны находиться в конце, и доступ к ним через структуру невозможен. Например, если присвоить полю pg_type.typrelid значение NULL, попытка обращения где-либо в коде к typetup->typrelid (или, что еще хуже, к следующему за ним полю typetup->typelem) приведет к ошибке. Это может вызвать непредсказуемые сбои или даже нарушение сегментации.

В качестве частичной защиты от ошибок такого типа поля переменной длины или поля, принимающие NULL, следует скрыть от компилятора C. Это реализуется посредством обертки #ifdef CATALOG_VARLEN ... #endif (где CATALOG_VARLEN — символ, который всегда будет неопределенным). Это не позволяет коду на C беспрепятственно обращаться к полям, которые могут отсутствовать или располагаться по некоторому другому смещению. В качестве дополнительной меры, препятствующей созданию некорректных строк, требуется, чтобы все столбцы, которые не должны принимать NULL, помечались соответствующим образом в pg_attribute. Код начальной загрузки автоматически пометит столбцы каталога как NOT NULL, если они имеют фиксированную длину и перед ними нет столбцов, принимающих NULL, или столбцов переменной длины. Там, где это правило применяется некорректно, можно исправить пометку, добавив дополнительные указания BKI_FORCE_NOT_NULL или BKI_FORCE_NULL.

Код клиентской части не должен включать никакие заголовочные файлы каталогов pg_xxx.h, так как эти файлы могут содержать код на C, который не будет компилироваться вне кода сервера. (Обычно это происходит из-за того, что эти файлы также содержат объявления функций в файлах src/backend/catalog/.) Вместо этого клиентский код может включить соответствующий сгенерированный заголовок pg_xxx_d.h с определениями различных OID и другими данными, которые могут быть полезны на стороне клиента. Если нужно, чтобы макросы или другой код в заголовочных файлах каталогов были видимы в клиентском коде, заключите соответствущую секцию в условие #ifdef EXPOSE_TO_CLIENT_CODE ... #endif, чтобы genbki.pl скопировал эту секцию в заголовок pg_xxx_d.h.

Некоторые каталоги настолько основополагающие, что их нельзя создать даже командой BKI create, которая используется для большинства каталогов, так как эта команда должна записать информацию, описывающую новый каталог, в эти базовые каталоги. Они называются каталогами начальной загрузки и для определения их требуется много дополнительные действий: необходимо вручную подготовить соответствующие записи для них в предварительно загружаемых данных pg_class и pg_type, и эти записи потребуется модифицировать при последующих изменениях в структуре каталога. (Каталогам начальной загрузки также нужны предварительно загруженные записи в pg_attribute, но, к счастью, сейчас с этим управляется скрипт genbki.pl.) По возможности избегайте включения новых каталогов в категорию каталогов начальной загрузки.

Ключевой частью заголовка каталога является определение структуры на C, описывающее компоновку каждой строки каталога. Это начинается с макроса CATALOG, который, насколько известно компилятору на C, является всего лишь сокращением имени структуры Typedef FormData_catalogname. Каждое поле в структуре порождает столбец каталога. Поля могут быть аннотированы с помощью макросов свойств BKI, описанных в genbki.h, например, чтобы определить значение по умолчанию для поля или пометить его как нулевое или ненулевое. Строка CATALOG также может быть аннотирована некоторыми другими макросами свойств BKI, описанными в genbki.h, чтобы определить другие свойства каталога в целом, например, является ли он общим отношением.

Код кеша системного каталога (и большая часть кода, работающего на основе каталога в целом) предполагает, что части всех кортежей системного каталога с фиксированной длиной действительно присутствуют, так как они отображаются на них. Это объявление структуры C. Таким образом, все поля переменной длины и поля, которые могут быть аннулированы, должны быть размещены в конце, и к ним нельзя получить доступ как к полям структуры. Например, если установить pg_type.typrelid как NULL, это потерпит неудачу, если какой-либо фрагмент кода попытается сослаться на typetup\-\>typrelid (или хуже, typetup->typelem, потому что это следует за typrelid). Это приведет к случайным ошибкам или даже нарушениям сегментации