Интерфейс программирования сервера

Интерфейс программирования сервера (SPI, Server Programming Interface) дает разработчикам пользовательских функций на C или RUST возможность запускать команды SQL внутри своих функций или процедур. SPI — это набор функций интерфейса, упрощающих доступ к анализатору, планировщику и исполнителю. Также SPI осуществляет управление памятью.

Примечание
Доступные процедурные языки предоставляют различные средства для выполнения команд SQL из функций. Большинство этих средств основаны на SPI, поэтому эта документация может быть полезна и для пользователей этих языков.

Обратите внимание, что если команда, вызванная через SPI, завершится с ошибкой, управление не вернется в вашу функцию на C/RUST. Скорее всего, транзакция или субтранзакция, в которой выполняется ваша функция C/RUST, откатится. (Это может показаться удивительным, учитывая, что у большинства функций SPI имеются документированные соглашения о возврате ошибок. Однако эти соглашения применяются только к ошибкам, обнаруженным в самих функциях SPI). Можно восстановить управление после ошибки, создав собственную субтранзакцию, окружающую вызовы SPI, в которых может быть ошибка.

В случае успеха функции SPI возвращают неотрицательный результат (либо через возвращаемое целочисленное значение, либо через глобальную переменную SPI_result, как описано ниже). В случае ошибки будет возвращен отрицательный результат или NULL.

Файлы исходного кода, использующие SPI, должны включать заголовочный файл executor/spi.h.

Функции интерфейса

SPI_connect — подключить функцию на C/RUST к менеджеру SPI
SPI_finish — отключить функцию на C/RUST от менеджера SPI
SPI_execute — выполнить команду
SPI_exec — Выполнить команду чтения/записи
SPI_execute_with_args — выполнить команду с внешними параметрами
SPI_prepare — подготовить оператор, но пока не выполнять его
SPI_prepare_cursor — подготовить оператор, но пока не выполнять его
SPI_prepare_params — подготовить оператор, но пока не выполнять его
SPI_getargcount — вернуть количество аргументов, необходимых для оператора, подготовленного функцией SPI_prepare
SPI_getargtypeid — вернуть OID типа данных для аргумента оператора, подготовленного функцией SPI_prepare
SPI_is_cursor_plan — вернуть true, если оператор, подготовленный функцией SPI_prepare, можно использовать с функцией SPI_cursor_open
SPI_execute_plan — выполнить оператор, подготовленный функцией SPI_prepare
SPI_execute_plan_with_paramlist — выполнить оператор, подготовленный функцией SPI_prepare
SPI_execp — выполнить оператор в режиме чтения/записи
SPI_cursor_open — установить курсор, используя оператор, созданный с помощью функции SPI_prepare
SPI_cursor_open_with_args — установить курсор, используя запрос и параметры
SPI_cursor_open_with_paramlist — установить курсор, используя параметры
SPI_cursor_find — найти существующий курсор по имени
SPI_cursor_fetch — извлечь несколько строк через курсор
SPI_cursor_move — переместить курсор
SPI_scroll_cursor_fetch — извлечь несколько строк через курсор
SPI_scroll_cursor_move — переместить курсор
SPI_cursor_close — закрыть курсор
SPI_keepplan — сохранить подготовленный оператор
SPI_saveplan — сохранить подготовленный оператор
SPI_register_relation — сделать эфемерное именованное отношение доступным по имени в запросах SPI
SPI_unregister_relation — удалить эфемерное именованное отношение из реестра
SPI_register_trigger_data — сделать эфемерные данные триггера доступными в запросах SPI

SPI_connect

SPI_connect, SPI_connect_ext — подключить функцию на C/RUST к менеджеру SPI

Синтаксис

int SPI_connect(void)
int SPI_connect_ext(int options)

Описание

SPI_connect устанавливает подключение вызова функции на C/RUST к менеджеру SPI. Эту функцию следует вызывать, если вы хотите выполнять команды через SPI. Некоторые служебные SPI-функции можно вызывать из неподключенных функций на C/RUST.

SPI_connect_ext делает то же самое, но принимает аргумент, позволяющий передавать дополнительные флаги. В настоящее время доступны следующие дополнительные значения:

SPI_OPT_NONATOMIC

Устанавливает подключение SPI в неатомарном режиме, то есть разрешает использование вызовов SPI_commit, SPI_rollback и SPI_start_transaction для управления транзакцией. В противном случае вызов данных функций приведет к немедленной ошибке.

Функция SPI_connect() равнозначна функции SPI_connect_ext(0).

Возвращаемое значение

SPI_OK_CONNECT

при успешном выполнении

SPI_ERROR_CONNECT

при ошибке

SPI_finish

SPI_finish — отключить функцию на C/RUST от менеджера SPI

Синтаксис

int SPI_finish (void)

Описание

SPI_finish закрывает существующее соединение с менеджером SPI. Эту функцию необходимо вызвать после завершения всех операций SPI, требуемых во время текущего вызова функции на C/RUST. Однако при прерывании транзакции с помощью elog(ERROR) о закрытии соединения можно не беспокоиться. В этом случае SPI очистится автоматически.

Возвращаемое значение

SPI_OK_FINISH

при корректном отключении

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

SPI_execute

SPI_execute — выполнить команду

Синтаксис

int SPI_execute(const char * command, bool read_only, long count)

Описание

SPI_execute выполняет указанную команду SQL для получения строк в количестве, ограниченном значением count. Если параметр read_only имеет значение true, команда должна только читать данные, тем самым несколько снижая издержки на ее выполнение.

Эта функция может быть вызвана только из подключеннной функции на C/RUST.

Если count равно нулю, то команда выполняется для всех строк, удовлетворяющих условиями запроса. Если count больше нуля, то будет получено не больше, чем count строк; выполнение остановится при достижении этого числа, почти так же, как при добавлении к запросу предложения LIMIT. Например,

SPI_execute("SELECT * FROM foo", true, 5);

получит из таблицы не более 5 строк. Обратите внимание, что такой предел действует, только когда команда действительно возвращает строки. Например,

SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);

вставляет все строки из bar, игнорируя параметр count. Однако запрос

SPI_execute("INSERT INTO foo SELECT * FROM bar RETURNING *", false, 5);

вставит не более 5 строк, поскольку выполнение будет остановлено после получения пятой строки, извлеченной RETURNING.

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

Когда параметр read_only имеет значение false, SPI_execute увеличивает счетчик команд и вычисляет новый снимок перед выполнением каждой команды в строке. Снимок фактически не изменяется, если текущий уровень изоляции транзакции SERIALIZABLE или REPEATABLE READ, но в режиме READ COMMITTED обновление снимка позволяет каждой команде видеть результаты только что зафиксированных транзакций из других сеансов. Это важно для согласованного поведения, когда команды изменяют базу данных.

Когда параметр read_only имеет значение true, SPI_execute не обновляет ни снимок, ни счетчик команд, и допускает в строке команды только простые команды SELECT. Эти команды выполняются с использованием снимка, предварительно установленного для окружающего запроса. Этот режим выполнения несколько быстрее, чем режим чтения/записи, из-за устранения издержек на каждую команду. Это также позволяет создавать действительно стабильные функции: поскольку все последующие выполнения будут использовать один и тот же снимок, в результатах не будет никаких изменений.

Обычно неразумно смешивать команды только для чтения и чтения/записи в одной функции с использованием SPI; это может привести к очень запутанному поведению, поскольку запросы только для чтения не будут видеть результаты каких-либо обновлений базы данных, выполненных запросами чтения/записи.

Фактическое количество строк, для которых была выполнена (последняя) команда, возвращается в глобальной переменной SPI_processed. Если эта функция возвращает значение SPI_OK_SELECT, SPI_OK_INSERT_RETURNING, SPI_OK_DELETE_RETURNING или SPI_OK_UPDATE_RETURNING, то для доступа к строкам результата можно воспользоваться глобальным указателем SPITupleTable *SPI_tuptable. Некоторые служебные команды (такие как EXPLAIN) также возвращают наборы строк, и SPI_tuptable будет содержать их результат и в этих случаях. Некоторые служебные команды (COPY, CREATE TABLE AS) не возвращают набор строк, поэтому SPI_tuptable имеет значение NULL, но они по-прежнему возвращают количество обработанных строк в SPI_processed.

Структура SPITupleTable определяется таким образом:

typedef struct
{
    MemoryContext tuptabcxt;    /* контекст таблицы результатов в памяти */
    uint64      alloced;        /* количество зарезервированных в памяти значений */
    uint64      free;           /* количество свободных значений */
    TupleDesc   tupdesc;        /* дескриптор строки */
    HeapTuple  *vals;           /* строки */
} SPITupleTable;

vals — это массив указателей на строки. (Количество допустимых записей задается SPI_processed.) tupdesc — это дескриптор строки, который можно передать функциям SPI, работающим со строками. tuptabcxt, alloced и free являются внутренними полями, не предназначенными для использования процедурами, вызывающими SPI.

SPI_finish освобождает все SPITupleTable, выделенные для текущей функции на C/RUST. Вы можете досрочно освободить конкретную результирующую таблицу, если закончили с ней работать, вызвав SPI_freetuptable.

Аргументы

const char * command

строка, содержащая команду для выполнения

bool read_only

true для режима выполнения «только чтение»

long count

максимальное количество строк, которые нужно вернуть, или 0, если ограничений нет

Возвращаемое значение

Если выполнение команды было успешным, то будет возвращено одно из следующих (неотрицательных) значений:

SPI_OK_SELECT

если была выполнена команда SELECT (но не SELECT INTO)

SPI_OK_SELINTO

если была выполнена команда SELECT INTO

SPI_OK_INSERT

если была выполнена команда INSERT

SPI_OK_DELETE

если была выполнена команда DELETE

SPI_OK_UPDATE

если была выполнена команда UPDATE

SPI_OK_INSERT_RETURNING

если была выполнена команда INSERT RETURNING

SPI_OK_DELETE_RETURNING

если была выполнена команда DELETE RETURNING

SPI_OK_UPDATE_RETURNING

если была выполнена команда UPDATE RETURNING

SPI_OK_UTILITY

если была выполнена служебная команда (например, CREATE TABLE)

SPI_OK_REWRITTEN

если команда была преобразована правилом в команду другого вида (например, UPDATE стала INSERT).

При ошибке возвращается одно из следующих отрицательных значений:

SPI_ERROR_ARGUMENT

если command равен NULL или count меньше 0

SPI_ERROR_COPY

при попытке выполнить COPY TO stdout или COPY FROM stdin

SPI_ERROR_TRANSACTION

при попытке выполнить команду управления транзакцией ( BEGIN, COMMIT, ROLLBACK, SAVEPOINT, PREPARE TRANSACTION, COMMIT PREPARED, ROLLBACK PREPARED или любой их вариант)

SPI_ERROR_OPUNKNOWN

если тип команды неизвестен (такого происходить не должно)

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

Примечания

Все функции SPI, выполняющие запросы, устанавливают значения как SPI_processed, так и SPI_tuptable (только указатель, а не содержимое структуры). Сохраните значения этих двух глобальных переменных в локальные переменные функции на C/RUST, если вам нужно получить доступ к таблице результатов выполнения SPI_execute или другой функции, выполняющие запросы, при последующих вызовах.

SPI_exec

SPI_exec — выполнить команду чтения/записи

Синтаксис

int SPI_exec(const char * command, long count)

Описание

SPI_exec работает так же, как SPI_execute, но параметр read_only всегда принимается как false.

Аргументы

const char * command

строка, содержащая запрос для выполнения

long count

максимальное количество строк, которые нужно вернуть, или 0, если нет ограничений

Возвращаемое значение

См. описание функции SPI_execute.

SPI_execute_with_args

SPI_execute_with_args — выполнить команду с внешними параметрами

Синтаксис

int SPI_execute_with_args(const char *command,
                          int nargs, Oid *argtypes,
                          Datum *values, const char *nulls,
                          bool read_only, long count)

Описание

SPI_execute_with_args выполняет команду, которая может включать ссылки на параметры, передаваемые извне. В тексте команды параметры обозначаются символами $n, а в вызове указываются типы данных и значения для каждого такого символа. Параметры read_only и count имеют ту же интерпретацию, что и в SPI_execute.

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

Аналогичных результатов можно достичь, вызвав SPI_prepare, а затем SPI_execute_plan; однако при использовании этой функции план запроса всегда настраивается на предоставленные конкретные значения параметров. Для одноразового выполнения запроса SPI_execute_with_args предпочтительней. Если ту же команду нужно выполнить со многими различными параметрами, любой из этих методов может оказаться быстрее, в зависимости от стоимости перепланирования по сравнению с преимуществами специализированных планов.

Аргументы

const char * command

строка с командой

int nargs

количество входных параметров ($1, $2 и т. д.)

Oid * argtypes

массив длиной nargs, содержащий OID типов данных этих параметров

Datum * values

массив длиной nargs, содержащий фактические значения параметров

const char * nulls

массив длиной nargs, описывающий, какие параметры равны NULL

Если параметр nulls равен NULL, то SPI_execute_with_args предполагает, что ни один из параметров не содержит NULL. В противном случае каждая запись массива nulls должна содержать ' ', если значение соответствующего параметра не NULL, или 'n', если оно равно NULL. (В последнем случае фактическое значение соответствующей записи в параметре values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

bool read_only

true для выполнения запросов в режиме «только чтение»

long count

максимальное количество строк, которое должно быть возвращено, или 0, если нет ограничений

Возвращаемое значение

Возвращаемое значение такое же, как и для SPI_execute.

При успешном вызове переменные SPI_processed и SPI_tuptable устанавливаются так же, как в SPI_execute.

SPI_prepare

SPI_prepare — подготовить оператор, пока не выполняя его

Синтаксис

SPIPlanPtr SPI_prepare(const char * command, int nargs, Oid * argtypes)

Описание

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

Когда одна и та же или схожая команда должна выполняться многократно, обычно выгодно провести синтаксический анализ только один раз и еще более выгодным может быть повторное использование плана выполнения команды. SPI_prepare преобразует строку команды в подготовленный оператор, который инкапсулирует результаты синтаксического анализа. Подготовленный оператор также предоставляет место для кэширования плана выполнения, если выясняется, что создание специализированного плана для каждого выполнения бесполезно.

Подготовленную команду можно обобщить, записав параметры ($1, $2 и т. д.) вместо значений, задаваемых константами в обычной команде. Тогда фактические значения параметров будут указываться при вызове SPI_execute_plan. Это позволяет использовать подготовленную команду в более широком диапазоне ситуаций, чем это было бы возможно без параметров.

Оператор, возвращаемый SPI_prepare, может использоваться только в текущем вызове функции на C/RUST, поскольку SPI_finish освобождает память, выделенную для такого оператора. Но этот оператор можно сохранить на потом, используя функции SPI_keepplan или SPI_saveplan.

Аргументы

const char * command

строка команды

int nargs

количество входных параметров ($1, $2 и т. д.)

Oid * argtypes

указатель на массив, содержащий OID типов данных параметров

Возвращаемое значение

SPI_prepare возвращает ненулевой указатель на SPIPlan, который является скрытой структурой, представляющей подготовленный оператор. В случае ошибки будет возвращен NULL, а переменная SPI_result будет содержать один из тех же кодов ошибок, которые используются SPI_execute, за исключением того, что код SPI_ERROR_ARGUMENT устанавливается, если command равен NULL, или nargs меньше 0, или nargs больше 0, а argtypes равен NULL.

Примечания

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

Хотя основной смысл подготовленного оператора заключается в том, чтобы избежать повторного анализа и планирования оператора, QHB будет принудительно повторять анализ и планирование оператора перед его использованием в случаях, если с момента предыдущего использования подготовленного оператора изменяются определения (DDL) объектов базы данных, используемых в этом операторе. Кроме того, если значение параметра search_path изменяется от одного использования к следующему, оператор будет повторно проанализирован с использованием нового значения search_path. Дополнительную информацию о поведении подготовленных операторов см. в описании команды PREPARE.

Эта функция должна вызываться только из подключенной функции на C/RUST.

SPIPlanPtr объявлен как указатель на скрытый тип структуры в spi.h. Неразумно пытаться получить доступ к его содержимому напрямую, так как это повышает вероятность того, что ваш код сломается в будущих версиях QHB.

Имя SPIPlanPtr в некотором смысле сохранено по историческим причинам, поскольку теперь структуре данных не обязательно содержать план выполнения.

SPI_prepare_cursor

SPI_prepare_cursor — подготовить оператор, пока не выполняя его

Синтаксис

SPIPlanPtr SPI_prepare_cursor(const char * command, int nargs,
                              Oid * argtypes, int cursorOptions)

Описание

Функция SPI_prepare_cursor идентична SPI_prepare, но позволяет дополнительно передать планировщику «параметры курсора». Это битовая маска, имеющая значения, перечисленные в nodes/parsenodes.h для поля options структуры DeclareCursorStmt. SPI_prepare всегда принимает параметры курсора равными нулю.

Аргументы

const char * command

строка команды

int nargs

количество входных параметров ($1, $2 и т. д.)

Oid * argtypes

указатель на массив, содержащий OID типов данных параметров

int cursorOptions

целочисленная битовая маска параметров курсора; ноль — поведение по умолчанию

Возвращаемое значение

SPI_prepare_cursor имеет те же соглашения о возврате, что и SPI_prepare.

Примечания

Полезные биты для установки в cursorOptions включают:

  • CURSOR_OPT_SCROLL;
  • CURSOR_OPT_NO_SCROLL;
  • CURSOR_OPT_FAST_PLAN;
  • CURSOR_OPT_GENERIC_PLAN;
  • CURSOR_OPT_CUSTOM_PLAN.

В частности, следует отметить, что CURSOR_OPT_HOLD игнорируется.

SPI_prepare_params

SPI_prepare_params — подготовить оператор, пока не выполняя его

Синтаксис

SPIPlanPtr SPI_prepare_params(const char * command,
                              ParserSetupHook parserSetup,
                              void * parserSetupArg,
                              int cursorOptions)

Описание

SPI_prepare_params создает и возвращает подготовленный оператор для указанной команды, но не выполняет его. Эта функция равнозначна SPI_prepare_cursor, но дополнительно позволяет вызывающему ее задать функции обработки синтаксического анализа для управления разбором ссылок на внешние параметры.

Аргументы

const char * command

строка команды

ParserSetupHook parserSetup

функция настройки обработчиков синтаксического анализа

void * parserSetupArg

сквозной аргумент для parserSetup

int cursorOptions

целочисленная битовая маска параметров курсора; ноль — поведение по умолчанию

Возвращаемое значение

SPI_prepare_params имеет те же соглашения о возврате, что и SPI_prepare.

SPI_getargcount

SPI_getargcount — вернуть количество аргументов, необходимых оператору, подготовленному функцией SPI_prepare

Синтаксис

int SPI_getargcount(SPIPlanPtr plan)

Описание

SPI_getargcount возвращает количество аргументов, необходимых для выполнения оператора, подготовленного функцией SPI_prepare.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

Возвращаемое значение

Количество ожидаемых аргументов для параметра plan. Если plan равен NULL или недействителен, в SPI_result устанавливается код SPI_ERROR_ARGUMENT, и функция возвращает -1.

SPI_getargtypeid

SPI_getargtypeid — вернуть OID типа данных для аргумента оператора, подготовленного функцией SPI_prepare

Синтаксис

Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex)

Описание

SPI_getargtypeid возвращает OID, представляющий типа аргумента с индексом argIndex для оператора, подготовленного функцией SPI_prepare. Нумерация аргументов начинается с нуля.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

int argIndex

индекс аргумента, начиная с нуля

Возвращаемое значение

OID типа аргумента с заданным индексом. Если значение параметра plan неверное или равно NULL, либо значение argIndex меньше 0 или больше или равно количеству аргументов, объявленных для параметра plan, в SPI_result устанавливается код SPI_ERROR_ARGUMENT и возвращается InvalidOid.

SPI_is_cursor_plan

SPI_is_cursor_plan — вернуть true, если оператор, подготовленный функцией SPI_prepare, можно использовать с функцией SPI_cursor_open

Синтаксис

bool SPI_is_cursor_plan(SPIPlanPtr plan)

Описание

SPI_is_cursor_plan возвращает true, если оператор, подготовленный функцией SPI_prepare, можно передать в качестве аргумента функции SPI_cursor_open, либо false, если это не так. Для true в параметре plan должна быть представлена только одна команда, и эта команда должна возвращать кортежи вызывающей стороне. Например, команда SELECT подходит, если не содержит предложение INTO, а команда UPDATE — только если содержит предложение RETURNING.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

Возвращаемое значение

Значение true или false, указывающее, может ли plan создать курсор, при SPI_result равном нулю. Если определить ответ невозможно (например, если значение plan неверное или NULL, или при вызове без подключения к SPI), тогда в SPI_result устанавливается подходящий код ошибки и возвращается значение false.

SPI_execute_plan

SPI_execute_plan — выполнить оператор, подготовленный SPI_prepare

Синтаксис

int SPI_execute_plan(SPIPlanPtr plan, Datum * values, const char * nulls,
                     bool read_only, long count)

Описание

SPI_execute_plan выполняет оператор, подготовленный функцией SPI_prepare или родственными ей. Параметры read_only и count имеют то же назначение, что и в SPI_execute.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

Datum * values

Массив фактических значений параметров. Должен иметь ту же длину, что и количество аргументов оператора.

const char * nulls

Массив, описывающий, какие параметры содержат NULL. Должен иметь ту же длину, что и количество аргументов оператора.

Если параметр nulls равен NULL, то SPI_execute_plan предполагает, что ни один из параметров не равен NULL. В противном случае каждая запись массива nulls должна содержать ' ', если значение соответствующего параметра не NULL, или 'n', если оно равно NULL. (В последнем случае фактическое значение в соответствующем элементе values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

bool read_only

true для выполнения запроса в режиме «только чтение»

long count

максимальное количество строк, которые нужно вернуть, или 0, если нет ограничений

Возвращаемое значение

Возвращаемое значение такое же, как и для SPI_execute, со следующими дополнительными вариантами ошибочных (отрицательных) результатов:

SPI_ERROR_ARGUMENT

если параметр plan неверен или равен NULL, либо если параметр count меньше 0

SPI_ERROR_PARAM

если параметр values равен NULL, и plan подготовлен с другими параметрами

В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются как в SPI_execute.

SPI_execute_plan_with_paramlist

SPI_execute_plan_with_paramlist - выполнить оператор, подготовленный функцией SPI_prepare

Синтаксис

int SPI_execute_plan_with_paramlist(SPIPlanPtr plan,
                                    ParamListInfo params,
                                    bool read_only,
                                    long count)

Описание

SPI_execute_plan_with_paramlist выполняет оператор, подготовленный функцией SPI_prepare. Эта функция равнозначна SPI_execute_plan за исключением того, что информация о значениях параметров, передаваемых в запрос, представляется по-другому. Представление ParamListInfo может быть удобно для передачи значений, которые уже доступны в этом формате. Функция также поддерживает использование динамических наборов параметров посредством функций-обработчиков, указанных в ParamListInfo.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

ParamListInfo params

структура данных, содержащая типы и значения параметров; NULL, если параметров нет

bool read_only

true для выполнения запроса в режиме «только чтение»

long count

максимальное количество строк, которые нужно вернуть, или 0, если нет ограничений

Возвращаемое значение

Возвращаемое значение такое же, как у функции SPI_execute_plan.

В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются как при вызове функции SPI_execute_plan.

SPI_execp

SPI_execp — выполнить оператор в режиме чтения/записи

Синтаксис

int SPI_execp(SPIPlanPtr plan, Datum * values, const char * nulls, long count)

Описание

SPI_execp сходна с SPI_execute_plan, но параметр read_only всегда имеет значение false.

Аргументы

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

Datum * values

Массив фактических значений параметров. Должен иметь ту же длину, что и число аргументов оператора.

const char * nulls

Массив, описывающий, какие параметры равны NULL. Должен иметь ту же длину, что и число аргументов оператора.

Если параметр nulls равен NULL, то SPI_execp предполагает, что ни один из параметров не содержит NULL. В противном случае каждая запись массива nulls должна содержать ' ', если значение соответствующего параметра не NULL, или 'n', если оно равно NULL. (В последнем случае фактическое значение в соответствующем элементе values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

long count

максимальное количество строк, которые нужно вернуть, или 0, если нет ограничений

Возвращаемое значение

Возвращаемое значение такое же, как у функции SPI_execute_plan.

В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются как при вызове функции SPI_execute_plan.

SPI_cursor_open

SPI_cursor_open — открыть курсор для оператора, созданного функцией SPI_prepare

Синтаксис

Portal SPI_cursor_open(const char * name, SPIPlanPtr plan,
                       Datum * values, const char * nulls,
                       bool read_only)

Описание

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

Использование курсора вместо непосредственного выполнения оператора имеет два преимущества. Во-первых, результирующие строки могут быть небольшими порциями, что позволяет избежать переполнения памяти при выполнении запросов, которые возвращают много строк. Во-вторых, портал может пережить текущую функцию C/RUST (фактически он может дожить до конца текущей транзакции). Возврат имени портала в код, вызывающий функцию на C/RUST, дает возможность выдавать результат в виде набора строк.

Данные переданных параметров будут скопированы в портал курсора, поэтому их можно освободить даже во время существования курсора.

Аргументы

const char * name

имя для портала или NULL, чтобы система сама выбрала имя

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

Datum * values

Массив фактических значений параметров. Должен иметь ту же длину, что и число аргументов оператора.

const char * nulls

Массив, описывающий, какие параметры равны NULL. Должен иметь ту же длину, что и число аргументов оператора.

Если параметр nulls равен NULL, то SPI_cursor_open предполагает, что ни один из параметров не содержит NULL. В противном случае каждый элемент массива nulls должен содержать ' ', если значение соответствующего параметра не NULL, или 'n', если оно равно NULL. (В последнем случае фактическое значение в соответствующем элементе values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

bool read_only

true для выполнения запроса в режиме «только чтение»

Возвращаемое значение

Указатель на портал, содержащий курсор. Обратите внимание, что нет соглашения о возврате ошибок; все ошибки будут выдаваться через elog.

SPI_cursor_open_with_args

SPI_cursor_open_with_args — открыть курсор, используя запрос и параметры

Синтаксис

Portal SPI_cursor_open_with_args(const char *name,
                                 const char *command,
                                 int nargs, Oid *argtypes,
                                 Datum *values, const char *nulls,
                                 bool read_only, int cursorOptions)

Описание

SPI_cursor_open_with_args открывает курсор (называемый внутри базы данных порталом), который будет выполнять указанный запрос. Большинство параметров имеют те же значения, что и соответствующие параметры для SPI_prepare_cursor и SPI_cursor_open.

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

Данные переданных параметров будут скопированы в портал курсора, поэтому их можно освободить даже во время существования курсора.

Аргументы

const char * name

имя для портала или NULL, чтобы система сама выбрала имя

const char * command

строка команды

int nargs

количество входных параметров ($1, $2 и т. д.)

Oid * argtypes

массив длиной nargs, содержащий OID типов данных параметров

Datum * values

массив длиной nargs, содержащий фактические значения параметров

const char * nulls

Массив длиной nargs, описывающий, какие параметры равны NULL.

Если параметр nulls равен NULL, то SPI_cursor_open_with_args предполагает, что ни один из параметров не содержит NULL. В противном случае каждый элемент массива nulls должен содержать ' ', если значение соответствующего параметра не NULL, или 'n', если оно равно NULL. (В последнем случае фактическое значение в соответствующем элементе values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

bool read_only

true для выполнения запроса в режиме «только чтение»

int cursorOptions

целочисленная битовая маска параметров курсора; ноль — поведение по умолчанию

Возвращаемое значение

Указатель на портал, содержащий курсор. Обратите внимание, что нет соглашения о возврате ошибок; все ошибки будут выдаваться через elog.

SPI_cursor_open_with_paramlist

SPI_cursor_open_with_paramlist — открыть курсор, используя параметры

Синтаксис

Portal SPI_cursor_open_with_paramlist(const char *name,
                                      SPIPlanPtr plan,
                                      ParamListInfo params,
                                      bool read_only)

Описание

SPI_cursor_open_with_paramlist открывает курсор (называемый внутри базы данных порталом), который будет выполнять оператор, подготовленный функцией SPI_prepare. Эта функция равнозначна SPI_cursor_open за исключением того, что информация о значениях параметров, передаваемых в запрос, представлена по-другому. Представление ParamListInfo может быть удобным для передачи значений, которые уже доступны в этом формате. Функция также поддерживает динамическую подстановку параметров через функции-обработчики, указанные в ParamListInfo.

Содержимое переданных параметров будет скопировано в портал курсора, поэтому они могут быть освобождены еще во время существования курсора.

Аргументы

const char * name

имя для портала или NULL, чтобы система сама выбрала имя

SPIPlanPtr plan

подготовленный оператор (возвращаемый функцией SPI_prepare)

ParamListInfo params

структура данных, содержащая типы и значения параметров; NULL, если параметров нет

bool read_only

true для выполнения запроса в режиме «только чтение»

Возвращаемое значение

Указатель на портал, содержащий курсор. Обратите внимание, что нет соглашения о возврате ошибок; все ошибки будут выдаваться через elog.

SPI_cursor_find

SPI_cursor_find — найти существующий курсор по имени

Синтаксис

Portal SPI_cursor_find(const char * name)

Описание

SPI_cursor_find находит существующий портал по имени. Это в первую очередь полезно для разрешения имени курсора, возвращенного в виде текста какой-то другой функцией.

Аргументы

const char * name

имя портала

Возвращаемое значение

Указатель на портал с заданным именем или NULL, если такой портал не найден.

SPI_cursor_fetch

SPI_cursor_fetch — извлечь несколько строк через курсор

Синтаксис

void SPI_cursor_fetch(Portal portal, bool forward, long count)

Описание

SPI_cursor_fetch извлекает несколько строк через курсор. Эта функция по действию аналогична подмножеству возможностей SQL-команды FETCH (расширенную функциональность предоставляет функция SPI_scroll_cursor_fetch).

Аргументы

Portal portal

портал, содержащий курсор

bool forward

true для извлечения с перемещением вперед, false — в обратном направлении

long count

максимальное количество строк для извлечения

Возвращаемое значение

В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются как в SPI_execute.

Примечания

Извлечение в обратном направлении может завершиться ошибкой, если план курсора был создан без параметра CURSOR_OPT_SCROLL.

SPI_cursor_move

SPI_cursor_move — переместить курсор

Синтаксис

void SPI_cursor_move(Portal portal, bool forward, long count)

Описание

SPI_cursor_move пропускает некоторое количество строк в курсоре. Эта функция по действию аналогична подмножеству возможностей SQL-команды MOVE (расширенную функциональность предоставляет функция SPI_scroll_cursor_move).

Аргументы

Portal portal

портал, содержащий курсор

bool forward

true для перемещения вперед, false — в обратном направлении

long count

максимальное количество строк для перемещения

Примечания

Перемещение в обратном направлении может завершиться ошибкой, если план курсора был создан без параметра CURSOR_OPT_SCROLL.

SPI_scroll_cursor_fetch

SPI_scroll_cursor_fetch — извлечь несколько строк через курсор

Синтаксис

void SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction,
                             long count)

Описание

SPI_scroll_cursor_fetch извлекает несколько строк через курсора. Эта функция действует аналогично SQL-команде FETCH.

Аргументы

Portal portal

портал, содержащий курсор

FetchDirection direction

один из вариантов: FETCH_FORWARD, FETCH_BACKWARD, FETCH_ABSOLUTE или FETCH_RELATIVE

long count

количество строк для извлечения в направлении FETCH_FORWARD или FETCH_BACKWARD; абсолютный номер строки для извлечения с вариантом FETCH_ABSOLUTE; относительный номер строки для извлечения с вариантом FETCH_RELATIVE

Возвращаемое значение

В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются как в SPI_execute.

Примечания

Подробную интерпретацию параметров direction и count см. в описании SQL-команды FETCH.

При значении параметра direction (направление извлечения), отличном от FETCH_FORWARD, функция может завершиться ошибкой, если план курсора был создан без параметра CURSOR_OPT_SCROLL.

SPI_scroll_cursor_move

SPI_scroll_cursor_move — переместить курсор

Синтаксис

void SPI_scroll_cursor_move(Portal portal, FetchDirection direction,
                            long count)

Описание

SPI_scroll_cursor_move перемещает курсор на некоторое количество строк. Эта функция действует аналогично SQL-команде MOVE.

Аргументы

Portal portal

портал, содержащий курсор

FetchDirection direction

один из вариантов: FETCH_FORWARD, FETCH_BACKWARD, FETCH_ABSOLUTE или FETCH_RELATIVE

long count

количество строк, на которое перемещения курсор в направлении FETCH_FORWARD или FETCH_BACKWARD; абсолютный номер строки, к которой перемещается курсор, с вариантом FETCH_ABSOLUTE; относительный номер строки, к которой перемещается курсор, с вариантом FETCH_RELATIVE

Возвращаемое значение

В случае успешного вызова переменная SPI_processed устанавливается как в SPI_execute. Переменная SPI_tuptable всегда равна NULL, поскольку эта функция не возвращает строк.

Примечания

Подробную интерпретацию параметров direction и count см. в описании SQL-команды FETCH.

При значении параметра direction (направление перемещения курсора), отличном от FETCH_FORWARD, функция может завершиться ошибкой, если план курсора был создан без параметра CURSOR_OPT_SCROLL.

SPI_cursor_close

SPI_cursor_close — закрыть курсор

Синтаксис

void SPI_cursor_close(Portal portal)

Описание

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

Все открытые курсоры автоматически закрываются в конце транзакции. SPI_cursor_close нужно вызывать только в случае, если есть желание освободить ресурсы раньше.

Аргументы

Portal portal

портал, содержащий курсор

SPI_keepplan

SPI_keepplan — сохранить подготовленный оператор

Синтаксис

int SPI_keepplan(SPIPlanPtr plan)

Описание

SPI_keepplan сохраняет переданный оператор (подготовленный функцией SPI_prepare), чтобы его не ликвидировали ни функция SPI_finish, ни менеджер транзакций. Это дает возможность повторно использовать подготовленные операторы в последующих вызовах функции на C/RUST в текущем сеансе.

Аргументы

SPIPlanPtr plan

подготовленные оператор, подлежащий сохранению

Возвращаемое значение

0 в случае успеха; SPI_ERROR_ARGUMENT, если значение параметра plan неверное или равно NULL.

Примечания

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

SPI_saveplan

SPI_saveplan — сохранить подготовленный оператор

Синтаксис

SPIPlanPtr SPI_saveplan(SPIPlanPtr plan)

Описание

SPI_saveplan копирует переданный оператор (подготовленный функцией SPI_prepare) в память, которая не будет освобождена ни SPI_finish, ни менеджером транзакций, и возвращает указатель на скопированный оператор. Это дает возможность повторно использовать подготовленные операторы при последующих вызовах функции на C/RUST в текущем сеансе.

Аргументы

SPIPlanPtr plan

подготовленный оператор, подлежащий сохранению

Возвращаемое значение

Указатель на скопированный оператор или NULL в случае ошибки. При ошибке SPI_result принимает одно из следующих значений:

SPI_ERROR_ARGUMENT

если значение параметра plan неверное или равно NULL

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

Примечания

Первоначально переданный оператор не освобождается, поэтому при желании его можно освободить вызовом функции SPI_freeplan, чтобы избежать утечки памяти до выполнения SPI_finish.

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

SPI_register_relation

SPI_register_relation — сделать эфемерное именованное отношение доступным по имени в запросах SPI

Синтаксис

int SPI_register_relation(EphemeralNamedRelation enr)

Описание

SPI_register_relation делает эфемерное именованное отношение, вместе со связанной информацией, доступным для запросов, планируемых и выполняемых через текущее подключение SPI.

Аргументы

EphemeralNamedRelation enr

запись эфемерного именованного отношения в реестре

Возвращаемое значение

Если выполнение команды было успешным, то будет возвращено следующее (неотрицательное) значение:

SPI_OK_REL_REGISTER

если отношение было успешно зарегистрировано по имени

При ошибке возвращается одно из следующих отрицательных значений:

SPI_ERROR_ARGUMENT

если значение параметра enr или его поля name равно NULL

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

SPI_ERROR_REL_DUPLICATE

если имя, указанное в поле name параметра enr, уже зарегистрировано для этого подключения

SPI_unregister_relation

SPI_unregister_relation — удалить эфемерное именованное отношение из реестра

Синтаксис

int SPI_unregister_relation(const char * name)

Описание

SPI_unregister_relation удаляет эфемерное именованное отношение из реестра для текущего подключения.

Аргументы

const char * name

имя записи отношения в реестре

Возвращаемое значение

Если выполнение команды было успешным, то будет возвращено следующее (неотрицательное) значение:

SPI_OK_REL_UNREGISTER

если блок кортежей был успешно удален из реестра

При ошибке возвращается одно из следующих отрицательных значений:

SPI_ERROR_ARGUMENT

если значение параметра name равно NULL

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

SPI_ERROR_REL_NOT_FOUND

если name не обнаруживается в реестре для текущего подключения

SPI_register_trigger_data

SPI_register_trigger_data — сделать эфемерные данные триггера доступными в запросах SPI

Синтаксис

int SPI_register_trigger_data(TriggerData *tdata)

Описание

SPI_register_trigger_data делает любые эфемерный отношения, захваченные триггером, доступными для запросов, планируемых и выполняемых через текущее подключение SPI. В настоящее время это подразумевает таблицы переходов, захваченные триггером AFTER, определенным с помощью предложения REFERENCING OLD/NEW TABLE AS. Эта функция должна вызываться после подключения функцией-обработчиком триггера на языке программирования.

Аргументы

TriggerData * tdata

объект TriggerData, передаваемый функции-обработчику триггера через fcinfo->context

Возвращаемое значение

Если выполнение команды было успешным, то будет возвращено следующее (неотрицательное) значение:

SPI_OK_TD_REGISTER

если захваченные данные триггера (если таковые имеются) были успешно зарегистрированы

При ошибке возвращается одно из следующих отрицательных значений:

SPI_ERROR_ARGUMENT

если значение параметра tdata равно NULL

SPI_ERROR_UNCONNECTED

при вызове из неподключенной функции на C/RUST

SPI_ERROR_REL_DUPLICATE

если имя любого переходного отношения в данных триггера уже зарегистрировано для этого подключения


Вспомогательные функции интерфейса

SPI_fname — определить имя столбца для указанного номера столбца
SPI_fnumber — определить номер столбца для указанного имени столбца
SPI_getvalue — вернуть строковое значение указанного столбца
SPI_getbinval — вернуть двоичное значение указанного столбца
SPI_gettype — вернуть имя типа данных указанного столбца
SPI_gettypeid — вернуть OID типа данных указанного столбца
SPI_getrelname — вернуть имя указанного отношения
SPI_getnspname — вернуть пространство имен указанного отношения
SPI_result_code_string — вернуть код ошибки в виде строки

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

Все функции, описанные в этом разделе, могут использоваться и в подключенных, и в неподключенных функциях на C/RUST.

SPI_fname

SPI_fname — определить имя столбца для указанного номера столбца

Синтаксис

char * SPI_fname(TupleDesc rowdesc, int colnumber)

Описание

SPI_fname возвращает копию имени столбца с указанным номером. (Когда эта копия имени будет не нужна, ее можно освободить с помощью pfree.)

Аргументы

TupleDesc rowdesc

описание входной строки

int colnumber

номер столбца (отсчет начинается с 1)

Возвращаемое значение

Название столбца или NULL, если значение параметра colnumber выходит за пределы допустимого диапазона. В случае ошибки в SPI_result устанавливается SPI_ERROR_NOATTRIBUTE.

SPI_fnumber

SPI_fnumber — определить номер столбца для указанного имени столбца

Синтаксис

int SPI_fnumber(TupleDesc rowdesc, const char * colname)

Описание

SPI_fnumber возвращает номер столбца для столбца с указанным именем.

Если параметр colname ссылается на системный столбец (например, ctid), будет возвращен соответствующий отрицательный номер столбца. Вызывающий должен провести тщательную проверку на наличие ошибки, досконально сравнивая возвращаемое значение с SPI_ERROR_NOATTRIBUTE; проверка результата по условию «меньше или равно 0» не будет корректной, если только не нужно исключить системные столбцы.

Аргументы

TupleDesc rowdesc

описание входной строки

const char * colname

имя столбца

Возвращаемое значение

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

SPI_getvalue

SPI_getvalue — вернуть строковое значение указанного столбца

Синтаксис

char * SPI_getvalue(HeapTuple row, TupleDesc rowdesc, int colnumber)

Описание

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

Результат возвращается в памяти, выделенной с помощью palloc. (Когда он станет не нужен, можно будет освободить память с помощью pfree.)

Аргументы

HeapTuple row

входная строка, подлежащая проверке

TupleDesc rowdesc

описание входной строки

int colnumber

номер столбца (отсчет начинается с 1)

Возвращаемое значение

Значение столбца или NULL, если столбец содержит NULL, значение colnumber выходит за пределы допустимого диапазона (в SPI_result устанавливается SPI_ERROR_NOATTRIBUTE) или нет доступной функции выхода (в SPI_result устанавливается SPI_ERROR_NOOUTFUNC).

SPI_getbinval

SPI_getbinval — вернуть двоичное значение указанного столбца

Синтаксис

Datum SPI_getbinval(HeapTuple row, TupleDesc rowdesc, int colnumber,
                    bool * isnull)

Описание

SPI_getbinval возвращает значение указанного столбца во внутренней форме (как тип Datum).

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

Аргументы

HeapTuple row

входная строка, подлежащая изучению

TupleDesc rowdesc

описание входной строки

int colnumber

номер столбца (отсчет начинается с 1)

bool * isnull

флаг для значения NULL в столбце

Возвращаемое значение

Возвращается двоичное значение столбца. Если этот столбец содержит NULL, переменной, на которую указывает параметр isnull, присваивается значение true, иначе — false.

При ошибке в SPI_result устанавливается SPI_ERROR_NOATTRIBUTE.

SPI_gettype

SPI_gettype — вернуть имя типа данных указанного столбца

Синтаксис

char * SPI_gettype(TupleDesc rowdesc, int colnumber)

Описание

SPI_gettype возвращает копию имени типа данных указанного столбца. (Когда копия имени станет не нужна, можно будет освободить ее с помощью pfree.)

Аргументы

TupleDesc rowdesc

описание входной строки

int colnumber

номер столбца (отсчет начинается с 1)

Возвращаемое значение

Имя типа данных указанного столбца или NULL при ошибке. При ошибке в SPI_result устанавливается SPI_ERROR_NOATTRIBUTE.

SPI_gettypeid

SPI_gettypeid — вернуть OID типа данных указанного столбца

Синтаксис

Oid SPI_gettypeid(TupleDesc rowdesc, int colnumber)

Описание

SPI_gettypeid возвращает OID типа данных указанного столбца.

Аргументы

TupleDesc rowdesc

описание входной строки

int colnumber

номер столбца (отсчет начинается с 1)

Возвращаемое значение

OID типа данных указанного столбца или InvalidOid при ошибке. При ошибке в SPI_result устанавливается SPI_ERROR_NOATTRIBUTE.

SPI_getrelname

SPI_getrelname — вернуть имя указанного отношения

Синтаксис

char * SPI_getrelname(Relation rel)

Описание

SPI_getrelname возвращает копию имени указанного отношения. (Когда копия имени станет не нужна, можно будет освободить ее с помощью pfree.)

Аргументы

Relation rel

входное отношение

Возвращаемое значение

Имя указанного отношения.

SPI_getnspname

SPI_getnspname — вернуть пространство имен указанного отношения

Синтаксис

char * SPI_getnspname(Relation rel)

Описание

SPI_getnspname возвращает копию имени пространства имен, которому принадлежит указанное отношение (Relation). Другое название пространства имен — схема. По окончании работы со значением, возвращенным этой функцией, следует освободить его с помощью pfree.

Аргументы

Relation rel

входное отношение

Возвращаемое значение

Имя пространства имен указанного отношения.

SPI_result_code_string

SPI_result_code_string — вернуть код ошибки в виде строки

Синтаксис

const char * SPI_result_code_string(int code);

Описание

SPI_result_code_string выдает строковое представление кода результата, возвращенного различными функциями SPI или сохраненного в SPI_result.

Аргументы

int code

код результата

Возвращаемое значение

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


Управление памятью

SPI_palloc — выделить память в верхнем контексте исполнителя
SPI_repalloc — перераспределить память в верхнем контексте исполнителя
SPI_pfree — освободить память в верхнем контексте исполнителя
SPI_copytuple — сделать копию строки в верхнем контексте исполнителя
SPI_returntuple — подготовить кортеж к возврату в виде Datum
SPI_modifytuple — создать новую запись, заменив выбранные поля данной записи
SPI_freetuple — освободить строку, выделенную в верхнем контексте исполнителя
SPI_freetuptable — освободить набор строк, созданных SPI_execute или подобной функцией
SPI_freeplan — освободить ранее сохраненный подготовленный оператор

QHB выделяет память в контекстах памяти, предоставляющих удобный метод управления распределением памяти по многим различным местам и с различным требуемым сроком жизни этой памяти. Уничтожение контекста освобождает всю выделенную в нем память. Таким образом, нет необходимости отслеживать отдельные объекты, чтобы избежать утечек памяти; вместо этого достаточно управлять только относительно небольшим количеством контекстов. palloc и связанные функции выделяют память из «текущего» контекста.

Функция SPI_connect создает новый контекст памяти и делает его текущим. Функция SPI_finish восстанавливает контекст, который был текущим ранее, и уничтожает контекст, созданный SPI_connect. Эти действия гарантируют, что временные выделения памяти, сделанные внутри вашей функции на C/RUST, будут освобождены при выходе из этой функции, предотвращая утечки памяти.

Однако если вашей функции на C/RUST нужно вернуть объект в выделенной памяти (например, значение типа данных с передачей по ссылке), вы не можете выделить эту память, используя palloc, по крайней мере, пока вы подключены к SPI. Если вы попытаетесь, объект будет освобожден посредством SPI_finish, и ваша функция на C/RUST не будет работать надежно. Для решения этой проблемы используйте SPI_palloc, чтобы выделить память для вашего возвращаемого объекта. SPI_palloc выделяет память в «верхнем контексте исполнителя», то есть в контексте памяти, который был текущим при вызове SPI_connect и является абсолютно верным контекстом для значения, возвращаемого вашей функцией на C/RUST. Некоторые другие служебные функции, описанные в этом разделе, также возвращают объекты, созданные в верхнем контексте исполнителя.

Когда вызывается SPI_connect, создаваемый ей частный контекст функции на C/RUST становится текущим контекстом. Все выделения, сделанные функциями palloc, repalloc или служебными функциями SPI (за исключением случаев, описанных в этом разделе), выполняются в этом контексте. Когда функция на C/RUST отключается от менеджера SPI (через SPI_finish), текущим контекстом снова становится верхний контекст исполнителя, а вся память, выделенная в контексте памяти функции на C/RUST, освобождается и больше не может быть использована.

SPI_palloc

SPI_palloc — выделить память в верхнем контексте исполнителя

Синтаксис

void * SPI_palloc(Size size)

Описание

SPI_palloc выделяет память в верхнем контексте исполнителя

Эту функцию можно использовать только при подключении к SPI. В противном случае она выдает ошибку.

Аргументы

Size size

размер выделяемой памяти (в байтах)

Возвращаемое значение

указатель на новый выделенный блок памяти заданного размера

SPI_repalloc

SPI_repalloc — перераспределить память в верхнем контексте исполнителя

Синтаксис

void * SPI_repalloc(void * pointer, Size size)

Описание

SPI_repalloc изменяет размер сегмента памяти, ранее выделенного с помощью функции SPI_palloc.

Эта функция больше не отличается от обычного repalloc. Она сохранена только для обратной совместимости существующего кода.

Аргументы

void * pointer

указатель на существующее хранилище, подлежащее изменению

Size size

размер выделяемой памяти (в байтах)

Возвращаемое значение

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

SPI_pfree

SPI_pfree — освободить память в верхнем контексте исполнителя

Синтаксис

void SPI_pfree(void * pointer)

Описание

SPI_pfree освобождает память, ранее выделенную с помощью функции SPI_palloc или SPI_repalloc.

Эта функция больше не отличается от обычного pfree. Она сохранена только для обратной совместимости существующего кода.

Аргументы

void * pointer

указатель на существующий блок памяти, подлежащий освобождению

SPI_copytuple

SPI_copytuple — сделать копию строки в верхнем контексте исполнителя

Синтаксис

HeapTuple SPI_copytuple(HeapTuple row)

Описание

SPI_copytuple создает копию строки в верхнем контексте исполнителя. Обычно это используется для возврата измененной строки из триггера. В функции, объявленной для возврата составного типа, используйте вместо этого SPI_returntuple.

Эту функцию можно использовать только при подключении к SPI. В противном случае она возвращает NULL и устанавливает в SPI_result значение SPI_ERROR_UNCONNECTED.

Аргументы

HeapTuple row

строка, подлежащая копированию

Возвращаемое значение

скопированная строка или NULL в случае ошибки (код ошибки см. в SPI_result)

SPI_returntuple

SPI_returntuple — подготовить кортеж к возврату в виде Datum

Синтаксис

HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc rowdesc)

Описание

SPI_returntuple создает копию строки в верхнем контексте исполнителя, возвращая ее в виде типа Datum. Перед возвратом полученный указатель нужно лишь преобразовать в Datum посредством функции PointerGetDatum.

Эту функцию можно использовать только при подключении к SPI. В противном случае она возвращает NULL и устанавливает в SPI_result значение SPI_ERROR_UNCONNECTED.

Обратите внимание, что данный метод следует использовать для функций, которые объявлены для возврата составных типов. Для триггеров он не применяется; чтобы вернуть измененную строку в триггере, используйте функцию SPI_copytuple.

Аргументы

HeapTuple row

строка, подлежащая копированию

TupleDesc rowdesc

дескриптор для строки (передавайте каждый раз один и тот же дескриптор для наиболее эффективного кэширования)

Возвращаемое значение

HeapTupleHeader, указывающий на скопированную строку, или NULL при ошибке (код ошибки см. в SPI_result)

SPI_modifytuple

SPI_modifytuple — создать строку, заменив выбранные поля исходной строки

Синтаксис

HeapTuple SPI_modifytuple(Relation rel, HeapTuple row, int ncols,
                          int * colnum, Datum * values, const char * nulls)

Описание

SPI_modifytuple создает новую строку, подставляя новые значения для выбранных столбцов и копируя остальные столбцы исходной строки. Входная строка не изменяется. Новая строка возвращается в верхнем контексте исполнителя.

Эту функцию можно использовать только при подключении к SPI. В противном случае она возвращает NULL и устанавливает в SPI_result значение SPI_ERROR_UNCONNECTED.

Аргументы

Relation rel

Используется только как источник дескриптора строки. (Передача отношения вместо дескриптора строки является ошибкой.)

HeapTuple row

строка, подлежащая изменению

int ncols

количество столбцов, подлежащих изменению

int * colnum

массив длиной ncols, содержащий номера столбцов, подлежащих изменению (номера столбцов начинаются с 1)

Datum * values

массив длиной ncols, содержащий новые значения для указанных столбцов

const char * nulls

массив длиной ncols, описывающий, какие из новых значений равны NULL

Если параметр nulls равен NULL, то SPI_modifytuple предполагает, что ни одно новое значение не равно NULL. В противном случае каждый элемент массива nulls должен содержать ' ', если соответствующее новое значение не равно NULL, или 'n', если равно. (В последнем случае фактическое значение в соответствующем элементе values не имеет значения.) Обратите внимание, что nulls — это не текстовая строка, а массив, поэтому завершающий символ '\0' не нужен.

Возвращаемое значение

новая строка с изменениями, размещенная в верхнем контексте исполнителя или NULL при ошибке (код ошибки см. в SPI_result)

В случае ошибки в SPI_result устанавливаются следующие значения:

SPI_ERROR_ARGUMENT

если rel равен NULL, или row равен NULL, или ncols меньше или равен 0, или colnum равен NULL, или values равен NULL.

SPI_ERROR_NOATTRIBUTE

если параметр colnum содержит недопустимый номер столбца (меньше или равен 0 или больше, чем количество столбцов в параметре row)

SPI_ERROR_UNCONNECTED

если SPI неактивен

SPI_freetuple

SPI_freetuple — освободить строку, выделенную в верхнем контексте исполнителя

Синтаксис

void SPI_freetuple(HeapTuple row)

Описание

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

Эта функция больше не отличается от обычной heap_freetuple. Она сохранена только для обратной совместимости существующего кода.

Аргументы

HeapTuple row

строка, подлежащая освобождению

SPI_freetuptable

SPI_freetuptable — освободить набор строк, созданный SPI_execute или подобной функцией

Синтаксис

void SPI_freetuptable(SPITupleTable * tuptable)

Описание

SPI_freetuptable освобождает набор строк, созданный предыдущим вызовом функции SPI, выполняющей команды, например SPI_execute. Поэтому данная функция часто вызывается с глобальной переменной SPI_tuptable в качестве аргумента.

Эта функция полезна, если функция на C/RUST, использующая SPI, должна выполнять несколько команд и не хочет сохранять результаты предыдущих команд до завершения. Обратите внимание, что все наборы строк будут в любом случае освобождены при вызове SPI_finish. Кроме того, если субтранзакция запускается, а затем прерывается в ходе выполнения использующей SPI функции на C/RUST, то SPI автоматически освобождает все наборы строк, созданные в рамках субтранзакции.

Аргументы

SPITupleTable * tuptable

указатель на набор строк, подлежащий освобождению, или NULL, если ничего не делать не нужно

SPI_freeplan

SPI_freeplan — освободить ранее сохраненный подготовленный оператор

Синтаксис

int SPI_freeplan(SPIPlanPtr plan)

Описание

SPI_freeplan освобождает подготовленный оператор, ранее возвращенный функцией SPI_prepare или сохраненный функцией SPI_keepplan или SPI_saveplan.

Аргументы

SPIPlanPtr plan

указатель на оператор, подлежащий освобождению

Возвращаемое значение

0 в случае успеха; SPI_ERROR_ARGUMENT, если значение параметра plan неверно или равно NULL.


Управление транзакциями

SPI_commit — зафиксировать текущую транзакцию
SPI_rollback — прервать текущую транзакцию
SPI_start_transaction — начать новую транзакцию

Невозможно выполнить команды управления транзакциями, например COMMIT и ROLLBACK через функции SPI, такие как SPI_execute. Однако существуют отдельные функции интерфейса, позволяющие управлять транзакциями через SPI.

Обычно небезопасно и нецелесообразно запускать и завершать транзакции в произвольных пользовательских функциях, вызываемых из SQL, без учета контекста, в котором они вызываются. Например, граница транзакции в середине функции, которая является частью сложного SQL-выражения, являющегося частью какой-либо другой команды SQL, скорее всего приведет к непонятным внутренним ошибкам или сбоям. Представленные здесь функции интерфейса предназначены, в первую очередь, для использования реализациями процедурных языков в целях поддержки управления транзакциями в процедурах уровня SQL, которые вызываются командой CALL (с учетом контекста ее вызова). Процедуры, реализованные на C/RUST и использующие SPI, могут реализовывать ту же логику, но подробное освещение этой темы этого выходит за рамки данной документации.

SPI_commit

SPI_commit, SPI_commit_and_chain — зафиксировать текущую транзакцию

Синтаксис

void SPI_commit(void)
void SPI_commit_and_chain(void)

Описание

SPI_commit фиксирует текущую транзакцию. Это примерно равнозначно выполнению SQL-команды COMMIT. После фиксации транзакции и перед выполнением дальнейший действий с базой данных нужно запустить новую транзакцию с помощью функции SPI_start_transaction.

SPI_commit_and_chain делает то же самое, но новая транзакция немедленно запускается с теми же характеристиками, что и только что завершенная, как при выполнении SQL-команды COMMIT AND CHAIN.

Эти функции можно выполнить, только если SPI-подключение было установлено в неатомарном режиме путем вызова функции SPI_connect_ext.

SPI_rollback

SPI\rollback, SPI_rollback_and_chain — отменить текущую транзакцию

Синтаксис

void SPI_rollback(void)
void SPI_rollback_and_chain(void)

Описание

SPI_rollback откатывает текущую транзакцию. Это примерно равнозначно выполнению SQL-команды ROLLBACK. После отката транзакции и перед выполнением дальнейший действий с базой данных нужно запустить новую транзакцию с помощью функции SPI_start_transaction.

SPI_rollback_and_chain делает то же самое, но новая транзакция немедленно запускается с теми же характеристиками, что и только что завершенная, как при выполнении SQL-команды ROLLBACK AND CHAIN.

Эти функции можно выполнить, только если SPI-подключение было установлено в неатомарном режиме путем вызова функции SPI_connect_ext.

SPI_start_transaction

SPI_start_transaction — начать новую транзакцию

Синтаксис

void SPI_start_transaction(void)

Описание

SPI_start_transaction начинает новую транзакцию. Эту функцию можно вызвать только после SPI_commit или SPI_rollback, поскольку в этот момент транзакция не активна. Обычно, когда вызывается процедура, использующая SPI, уже существует активная транзакция, поэтому попытка начать еще одну до закрытия текущей приведет к ошибке.

Эту функцию можно выполнить, только если SPI-подключение было установлено в неатомарном режиме путем вызова функции SPI_connect_ext.


Видимость изменений данных

Следующие правила регулируют видимость изменений данных в функциях, использующих SPI (или любых других функциях на C/RUST):

  • Во время выполнения команды SQL любые изменения данных, сделанные этой командой, невидимы для самой команды. Например, в:
INSERT INTO a SELECT * FROM a;

вставленные строки невидимы для части SELECT.

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

  • Команды, выполняемые через SPI внутри функции, вызванной командой SQL (обычной функцией или триггером), следуют одному или другому из приведенных выше правил в зависимости от флага чтения/записи, передаваемого в SPI. Команды, выполняемые в режиме «только чтение», следуют первому правилу: они не могут видеть изменения, произведенные вызывающей командой. Команды, выполняемые в режиме «чтение-запись», следуют второму правилу: они могут видеть все произведенные к этому моменту изменения.

  • Все стандартные процедурные языки устанавливают режим SPI «чтение-запись» в зависимости от атрибута изменчивости функции. Команды функций STABLE и IMMUTABLE выполняются в режиме «только чтение», тогда как команды функций VOLATILE выполняются в режиме «чтение-запись». Хотя авторы функций на C/RUST могут нарушить это соглашение, вряд ли это будет хорошей идеей.

Следующий раздел содержит пример, который иллюстрирует применение этих правил.


Примеры

Этот раздел содержит очень простой пример использования SPI. Функция на C/RUST execq принимает команду SQL в качестве первого аргумента и число строк в качестве второго, выполняет команду с помощью функции SPI_exec и возвращает количество строк, обработанных командой. Вы можете найти более сложные примеры для SPI в дереве исходного кода в src/test/regress/regress.c.

#include "postgres.h"

#include "executor/spi.h"
#include "utils/builtins.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(execq);

Datum
execq(PG_FUNCTION_ARGS)
{
    char *command;
    int cnt;
    int ret;
    uint64 proc;

    /* Преобразовать данный текстовый объект в строку C */
    command = text_to_cstring(PG_GETARG_TEXT_PP(0));
    cnt = PG_GETARG_INT32(1);

    SPI_connect();

    ret = SPI_exec(command, cnt);

    proc = SPI_processed;

    /*
     * Если были извлечены какие-то строки, вывести их через elog(INFO).
     */
    if (ret > 0 && SPI_tuptable != NULL)
    {
        TupleDesc tupdesc = SPI_tuptable->tupdesc;
        SPITupleTable *tuptable = SPI_tuptable;
        char buf[8192];
        uint64 j;

        for (j = 0; j < proc; j++)
        {
            HeapTuple tuple = tuptable->vals[j];
            int i;

            for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %s%s",
                        SPI_getvalue(tuple, tupdesc, i),
                        (i == tupdesc->natts) ? " " : " |");
            elog(INFO, "EXECQ: %s", buf);
        }
    }

    SPI_finish();
    pfree(command);

    PG_RETURN_INT64(proc);
}

Так эта функция будет объявлена после ее компиляции в разделяемую библиотеку (подробности в разделе Компиляция и связывание динамически загружаемых функций):

CREATE FUNCTION execq(text, integer) RETURNS int8
    AS 'имя_файла'
    LANGUAGE C STRICT;

Пример сеанса:

=> SELECT execq('CREATE TABLE a (x integer)', 0);
 execq
-------
     0
(1 row)

=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)', 0));
INSERT 0 1
=> SELECT execq('SELECT * FROM a', 0);
INFO:  EXECQ:  0    -- вставлено функцией execq
INFO:  EXECQ:  1    -- возвращено функцией execq и вставлено верхней командой INSERT

 execq
-------
     2
(1 row)

=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a', 1);
 execq
-------
     1
(1 row)

=> SELECT execq('SELECT * FROM a', 10);
INFO:  EXECQ:  0
INFO:  EXECQ:  1
INFO:  EXECQ:  2    -- 0 + 2, вставлена только одна строка — как указано

 execq
-------
     3              -- 10 — только максимальное значение, 3 — реальное число строк
(1 row)

=> DELETE FROM a;
DELETE 3
=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INSERT 0 1
=> SELECT * FROM a;
 x
---
 1                  -- нет строк в a (0) + 1
(1 row)

=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INFO:  EXECQ:  1
INSERT 0 1
=> SELECT * FROM a;
 x
---
 1
 2                  -- была только одна строка в a + 1
(2 rows)

-- Этот пример демонстрирует правило видимости изменений данных:

=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
INFO:  EXECQ:  1
INFO:  EXECQ:  2
INFO:  EXECQ:  1
INFO:  EXECQ:  2
INFO:  EXECQ:  2
INSERT 0 2
=> SELECT * FROM a;
 x
---
 1
 2
 2                  -- 2 строки * 1 (x в первой строке)
 6                  -- 3 строки (2 + 1 только что вставленная) * 2 (x во второй строке)
(4 rows)               ^^^^^^
                       строки, видимые в execq() при разных вызовах