Интерфейс программирования сервера
Интерфейс программирования сервера (Server Programming Interface, SPI) дает разработчикам пользовательских функций на 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_extended — выполнить команду с внешними параметрами
SPI_execute_with_args — выполнить команду с внешними параметрами
SPI_prepare — подготовить оператор, но пока не выполнять его
SPI_prepare_cursor — подготовить оператор, но пока не выполнять его
SPI_prepare_extended — подготовить оператор, но пока не выполнять его
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_extended — выполнить оператор, подготовленный функцией 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_parse_open — установить курсор, используя строку запроса и параметры
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_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 SPITupleTable
{
/* Открытые члены */
TupleDesc tupdesc; /* дескриптор кортежа */
HeapTuple *vals; /* массив кортежей */
uint64 numvals; /* количество допустимых кортежей */
/* Закрытые члены, не предназначенные для внешних вызывающиъ функций */
uint64 alloced; /* зарезервированная в памяти длина массива vals */
MemoryContext tuptabcxt; /* контекст таблицы результатов в памяти */
slist_node next; /* ссылка для внутреннего учета системных ресурсов */
SubTransactionId subid; /* субтранзакция, в которой была создана структура tuptable */
} SPITupleTable;
Поля tupdesc, vals и numvals могут использоваться кодом, вызывающим SPI; остальные поля являются внутренними. vals представляет собой массив указателей на строки. Количество строк задается numvals (по некоторым историческим причинам это число тоже возвращается в SPI_processed). tupdesc является дескриптором строки, который можно передать 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_MERGE — если была выполнена команда MERGE
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_extended
SPI_execute_extended — выполнить команду с внешними параметрами
Синтаксис
int SPI_execute_extended(const char *command,
const SPIExecuteOptions * options)
Описание
Функция SPI_execute_extended выполняет команду, которая может включать ссылки на параметры, передаваемые извне. В тексте команды параметры обозначаются символами $n, а объект options->params (если передается) предоставляет информацию о значениях и типе для каждого такого символа. Также в структуре options можно задавать различные параметры выполнения.
Как правило, в объекте options->params все параметры должны помечаться флагом PARAM_FLAG_CONST, поскольку для запроса всегда используется одноразовый план.
Если options->dest отличен от NULL, то результирующие кортежи не накапливаются в SPI_tuptable, а передаются в этот объект по мере их генерирования исполнителем. Переданный вызывающей функцией объект DestReceiver бывает особенно полезно использовать для запросов, которые могут сгенерировать много кортежей, поскольку данные можно обрабатывать на ходу, а не накапливать в памяти.
Аргументы
const char * command
командная строка
const SPIExecuteOptions * options
структура, содержащая необязательные аргументы
Вызывающая функция всегда должна сначала полностью заполнять структуру options нулями, а потом уже заполнять поля, которые хочет установить. Это гарантирует восходящую совместимость кода, так как если все поля, добавляемые в эту структуру в будущем, содержат ноль, они будут определены как обратно совместимые. В настоящее время в options имеются следующие поля:
ParamListInfo params
структура данных, содержащая типы и значения параметров запроса; NULL, если
таковых нет
bool read_only
true для выполнения запросов в режиме «только чтение»
bool allow_nonatomic
true разрешает неатомарное выполнение операторов CALL
и DO
bool must_return_tuples
если равно true, то вызывает ошибку для типов запросов, не возвращающих кортежи
(не реагирует на случаи, когда возвращаются нулевые кортежи)
uint64 tcount
максимальное количество возвращаемых строк или 0, если ограничения нет
DestReceiver * dest
Объект DestReceiver, который будет получать все кортежи, выданные запросом; если
равен NULL, то результирующие кортежи накапливаются в структуре SPI_tuptable,
как в SPI_execute
ResourceOwner owner
Это поле присутствует для согласованности с SPI_execute_plan_extended, но
игнорируется, так как используемый SPI_execute_extended план никогда не
сохраняется.
Возвращаемое значение
Возвращаемое значение то же, что и для функции SPI_execute.
Когда options->dest равен NULL, SPI_processed и SPI_tuptable устанавливаются как в SPI_execute. Когда options->dest отличен от NULL, SPI_processed устанавливается в ноль, а SPI_tuptable — в NULL. Если требуется число кортежей, его должен вычислять объект DestReceiver вызывающей функции.
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', если равно. (В последнем случае фактическое значение
соответствующей записи в параметре 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 возвращает отличный от NULL указатель на 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 построит общий план, и, если тот ненамного дороже специализированных планов, начнет использовать его, вместо того чтобы каждый раз создавать новый. Если это поведение по умолчанию не подходит, его можно изменить, передав в SPI_prepare_cursor флаг CURSOR_OPT_GENERIC_PLAN или CURSOR_OPT_CUSTOM_PLAN, чтобы принудительно использовать общие или специализированные планы соответственно.
Хотя основной смысл подготовленного оператора заключается в том, чтобы избежать
повторного анализа и планирования оператора, 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 всегда принимает параметры курсора равными нулю.
Сейчас эта функция устарела и вместо нее рекомендуется использовать функцию SPI_prepare_extended.
Аргументы
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_extended
SPI_prepare_extended — подготовить оператор, пока не выполняя его
Синтаксис
SPIPlanPtr SPI_prepare_extended(const char * command,
const SPIPrepareOptions * options)
Описание
Функция SPI_prepare_extended создает и возвращает подготовленный оператор для указанной команды, но не выполняет ее. Эта функция равнозначна SPI_prepare, но дополнительно позволяет вызывающей функции задавать параметры для управления синтаксическим анализом ссылок на внешние параметры, а также другими аспектами анализа и планирования запросов.
Аргументы
const char * command
командная строка
const SPIPrepareOptions * options
структура, содержащая необязательные аргументы
Вызывающая функция всегда должна сначала полностью заполнять структуру options нулями, а потом уже заполнять поля, которые хочет установить. Это гарантирует восходящую совместимость кода, так как если все поля, добавляемые в эту структуру в будущем, содержат ноль, они будут определены как обратно совместимые. В настоящее время в options имеются следующие поля:
ParserSetupHook parserSetup
Функция настройки обработчиков синтаксического анализа
void * parserSetupArg
аргумент для сквозной передачи в parserSetup
RawParseMode parseMode
режим для простого синтаксического анализа; RAW_PARSE_DEFAULT (ноль) выбирает
поведение по умолчанию
int cursorOptions
целочисленная битовая маска для параметров курсора; ноль выбирает поведение по
умолчанию
Возвращаемое значение
SPI_prepare_extended имеет те же соглашения о возвращаемом результате, что и SPI_prepare.
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, но дополнительно позволяет вызывающей функции задавать функции обработки синтаксического анализа для управления анализом ссылок на внешние параметры.
Сейчас эта функция устарела и вместо нее рекомендуется использовать функцию SPI_prepare_extended.
Аргументы
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', если равно. (В последнем случае фактическое значение
в соответствующей записи 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_extended
SPI_execute_plan_extended — выполнить оператор, подготовленный функцией SPI_prepare
Синтаксис
int SPI_execute_plan_extended(SPIPlanPtr plan,
const SPIExecuteOptions * options)
Описание
Функция SPI_execute_plan_extended выполняет оператор, подготовленный функцией SPI_prepare или родственными ей. Эта функция равнозначна SPI_execute_plan, но информация о значениях параметров, передаваемых в запрос, представляется по-другому, а кроме того ей могут передаваться дополнительные параметры, управляющие выполнением запроса.
Значения параметров запроса представляются через структуру ParamListInfo, что удобно для передачи значений, уже доступных в этом формате. Также посредством функций обработки, заданных в ParamListInfo, можно использовать динамические наборы параметров.
Также вместо того чтобы постоянно накапливать результирующие кортежи в структуре SPI_tuptable, эти кортежи можно передавать в предоставляемый вызывающим кодом объект DestReceiver по мере их генерирования исполнителем. Это особенно полезно для запросов, которые могут генерировать много кортежей, поскольку данные можно обрабатывать на ходу, а не копить в памяти.
Аргументы
SPIPlanPtr plan
подготовленный оператор (возвращаемый функцией SPI_prepare)
const SPIExecuteOptions * options
структура, содержащая необязательные аргументы
Вызывающая функция всегда должна сначала полностью заполнять структуру options нулями, а потом уже заполнять поля, которые хочет установить. Это гарантирует восходящую совместимость кода, так как если все поля, добавляемые в эту структуру в будущем, содержат ноль, они будут определены как обратно совместимые. В настоящее время в options имеются следующие поля:
ParamListInfo params
структура данных, содержащая типы и значения параметров запроса; NULL, если
таковых нет
bool read_only
true для выполнения запроса в режиме «только чтение»
bool allow_nonatomic
true разрешает неатомарное выполнение операторов CALL
и DO
bool must_return_tuples
если равно true, то вызывает ошибку для типов запросов, не возвращающих кортежи
(не реагирует на случаи, когда возвращаются нулевые кортежи)
uint64 tcount
максимальное количество возвращаемых строк или 0, если ограничения нет
DestReceiver * dest
Объект DestReceiver, который будет получать все кортежи, выданные запросом; если
равен NULL, то результирующие кортежи накапливаются в структуре SPI_tuptable,
как в SPI_execute_plan
ResourceOwner owner
Владелец источника, который будет содержать счетчик ссылок на план во время его
выполнения. Если равно NULL, используется текущий владелец ресурса
(CurrentResourceOwner). Игнорируется для несохраненных планов, поскольку SPI не
получает на них счетчики ссылок.
Возвращаемое значение
Возвращаемое значение такое же, как у SPI_execute_plan.
Когда options->dest равен NULL, SPI_processed и SPI_tuptable устанавливаются как в SPI_execute_plan. Когда options->dest отличен от NULL, SPI_processed устанавливается в ноль, а SPI_tuptable — в NULL. Если требуется число кортежей, его должен вычислять объект DestReceiver вызывающей функции.
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.
Сейчас эта функция устарела и вместо нее рекомендуется использовать функцию SPI_execute_plan_extended.
Аргументы
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', если равно. (В последнем случае фактическое значение в
соответствующем элементе values неважно.) Обратите внимание, что nulls
— это не текстовая строка, а просто массив; завершающий символ '\0' не нужен.
long count
максимальное количество возвращаемых строк или 0, если ограничения нет
Возвращаемое значение
См. SPI_execute_plan.
В случае успешного вызова переменные SPI_processed и SPI_tuptable устанавливаются так же, как в SPI_execute.
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', если равно. (В последнем случае фактическое значение
в соответствующей записи 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. Если одну и ту же команду нужно выполнять со множеством различных параметров, любой из этих методов может оказаться быстрее, в зависимости от того, что перевесит: стоимость повторного планирования или преимущества специализированных планов.
Данные переданных параметров будут скопированы в портал курсора, поэтому их можно освободить даже во время существования курсора.
В настоящее время эта функция устарела и вместо нее рекомендуется использовать функцию SPI_cursor_parse_open, предоставляющую равнозначную функциональность, но применяющую более современный API для обработки параметров запроса.
Аргументы
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', если равно. (В последнем случае фактическое
значение в соответствующей записи 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_parse_open
SPI_cursor_parse_open — установить курсор, используя строку запроса и параметры
Синтаксис
Portal SPI_cursor_parse_open(const char *name,
const char *command,
const SPIParseOpenOptions * options)
Описание
Функция SPI_cursor_parse_open устанавливает курсор (называемый внутренне порталом), который выполнит заданную строку запроса. Это сравнимо с последовательным вызовом функций SPI_prepare_cursor и SPI_cursor_open_with_paramlist, но все ссылки на параметры в строке запроса обрабатываются путем предоставления объекта ParamListInfo.
Для одноразового выполнения запроса эту функцию следует предпочесть последовательным вызовам SPI_prepare_cursor и SPI_cursor_open_with_paramlist. Если одну и ту же команду нужно выполнять со множеством различных параметров, любой из этих методов может оказаться быстрее, в зависимости от того, что перевесит: стоимость повторного планирования или преимущества специализированных планов.
Как правило, объект options->params должен пометить каждый параметр флагом PARAM_FLAG_CONST, поскольку для этого запроса всегда используется одноразовый план.
Данные переданных параметров будут скопированы в портал курсора, поэтому их можно освободить даже во время существования курсора.
Аргументы
const char * name
имя для портала или NULL, чтобы система сама выбрала имя
const char * command
командная строка
const SPIParseOpenOptions * options
структура, содержащая необязательные аргументы
Вызывающая функция всегда должна сначала полностью заполнять структуру options нулями, а потом уже заполнять поля, которые хочет установить. Это гарантирует восходящую совместимость кода, так как если все поля, добавляемые в эту структуру в будущем, содержат ноль, они будут определены как обратно совместимые. В настоящее время в options имеются следующие поля:
ParamListInfo params
структура данных, содержащая типы и значения параметров запроса; NULL, если
таковых нет
int cursorOptions
целочисленная битовая маска параметров курсора; ноль выбирает поведение по умолчанию
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. Если во время фиксации происходит ошибка,
текущая транзакция откатывается и начинается новая, после чего ошибка выдается
обычным способом.
Функция 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.
Функция 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 ничего не делает и существует только для совместимости кода с более ранними версиями QHB. Ранее она требовалась после вызова SPI_commit или SPI_rollback, но теперь эти функции начинают новую транзакцию автоматически.
Видимость изменений данных
Следующие правила регулируют видимость изменений данных в функциях, использующих SPI (или любых других функциях на C/RUST):
-
Во время выполнения команды SQL любые изменения данных, сделанные этой командой, невидимы для самой команды. Например, в:
INSERT INTO a SELECT * FROM a;
вставленные строки невидимы для части
SELECT
. -
Изменения, произведенные командой К, видны всем командам, которые запускаются после нее, независимо от того, были ли эти команды запущены внутри К (во время ее выполнения) или после ее завершения.
-
Команды, выполняемые через SPI внутри функции, вызванной командой SQL (обычной функцией или триггером), следуют одному или другому из приведенных выше правил в зависимости от флага чтения/записи, передаваемого в SPI. Команды, выполняемые в режиме «только чтение», следуют первому правилу: они не могут видеть изменения, произведенные вызывающей командой. Команды, выполняемые в режиме «чтение-запись», следуют второму правилу: они могут видеть все произведенные к этому моменту изменения.
-
Все стандартные процедурные языки устанавливают режим SPI «чтение-запись» в зависимости от атрибута изменчивости функции. Команды функций STABLE и IMMUTABLE выполняются в режиме «только чтение», тогда как команды функций VOLATILE выполняются в режиме «чтение-запись». Хотя авторы функций на C/RUST могут нарушить это соглашение, вряд ли это будет хорошей идеей.
Следующий раздел содержит пример, иллюстрирующий применение этих правил.
Примеры
Этот раздел содержит очень простой пример использования SPI. Функция на C execq принимает команду SQL в качестве первого аргумента и число строк в качестве второго, выполняет команду с помощью функции SPI_exec и возвращает количество строк, обработанных командой. Более сложные примеры для SPI можно найти в модуле spi.
#include "qhb.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 RETURNING *', 1);
INFO: EXECQ: 2 -- 0 + 2, затем выполнение было остановлено при достижении предела count
execq
-------
1
(1 row)
=> SELECT execq('SELECT * FROM a', 10);
INFO: EXECQ: 0
INFO: EXECQ: 1
INFO: EXECQ: 2
execq
-------
3 -- 10 — всего лишь максимальное значение, 3 — реальное число строк
(1 row)
=> SELECT execq('INSERT INTO a SELECT x + 10 FROM a', 1);
execq
-------
3 -- обработаны все строки; обработки не останавливается по достижении count, поскольку ничего не возвращается
(1 row)
=> SELECT * FROM a;
x
----
0
1
2
10
11
12
(6 rows)
=> DELETE FROM a;
DELETE 3
=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INSERT 0 1
=> SELECT * FROM a;
x
---
1 -- 0 (нет строк в a) + 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 -- 1 (в a была только одна строка) + 1
(2 rows)
-- Этот пример демонстрирует правило видимости изменений данных.
-- execq вызывается дважды и каждый раз видит разное количество строк:
=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
INFO: EXECQ: 1 -- результаты из первой execq
INFO: EXECQ: 2
INFO: EXECQ: 1 -- результаты из второй execq
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)