41.5. Доступ к базе данных из PL/Tcl#

41.5. Доступ к базе данных из PL/Tcl

41.5. Доступ к базе данных из PL/Tcl #

В этом разделе мы следуем обычной традиции Tcl и используем вопросительные знаки, а не скобки, для обозначения необязательного элемента в синтаксическом обзоре. Следующие команды доступны для доступа к базе данных из тела функции PL/Tcl:

spi_exec ?-count n? ?-array name? command ?loop-body?

Выполняет SQL-команду, заданную в виде строки. Ошибка в команде вызывает ошибку. В противном случае, возвращаемое значение функции spi_exec - это количество обработанных строк (выбранных, вставленных, обновленных или удаленных) командой, или ноль, если команда является утилитарным оператором. Кроме того, если команда является оператором SELECT, значения выбранных столбцов помещаются в переменные Tcl, как описано ниже.

Опциональное значение -count указывает spi_exec остановиться после того, как будут получены n строк, как если бы в запросе было указано предложение LIMIT. Если n равно нулю, запрос выполняется до завершения, так же, как когда -count прне указан.

Если команда является оператором SELECT, значения столбцов результата помещаются в переменные Tcl с именами, соответствующими именам столбцов. Если указана опция -array, значения столбцов вместо этого сохраняются в элементах именованного ассоциативного массива, где имена столбцов используются в качестве индексов массива. Кроме того, текущий номер строки в результате (считая с нуля) сохраняется в элементе массива с именем .tupno, если это имя не используется в качестве имени столбца в результате.

Если команда является оператором SELECT и не задан скрипт loop-body, тогда только первая строка результатов сохраняется в переменные Tcl или элементы массива; остальные строки, если они есть, игнорируются. Если запрос не возвращает ни одной строки, то сохранение не происходит. (Этот случай можно обнаружить, проверив результат spi_exec). Например:

spi_exec "SELECT count(*) AS cnt FROM pg_proc"

установит переменную Tcl $cnt в количество строк в системном каталоге pg_proc.

Если задан необязательный аргумент loop-body, то это фрагмент скрипта Tcl, который выполняется один раз для каждой строки в результате запроса. (loop-body игнорируется, если заданная команда не является SELECT). Значения столбцов текущей строки сохраняются в переменных или элементах массива Tcl перед каждой итерацией. Например:

spi_exec -array C "SELECT * FROM pg_class" {
    elog DEBUG "have table $C(relname)"
}

будет выводить сообщение журнала для каждой строки pg_class. Эта функция работает аналогично другим циклическим конструкциям Tcl; в частности, continue и break работают обычным образом внутри тела цикла.

Если столбец результата запроса является пустым, целевая переменная для него будет неустановленной, а не установленной.

spi_prepare query typelist

Подготавливает и сохраняет план запроса для последующего выполнения. Сохраненный план будет сохранен на протяжении всей текущей сессии.

Запрос может использовать параметры, то есть заполнители для значений, которые будут предоставлены при выполнении плана. В строке запроса обращайтесь к параметрам по символам $1 ... $n. Если запрос использует параметры, необходимо указать имена типов параметров в виде Tcl-списка. (Если параметры не используются, напишите пустой список для typelist).

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

spi_execp ?-count n? ?-array name? ?-nulls string? queryid ?value-list? ?loop-body?

Выполняет запрос, ранее подготовленный с помощью функции spi_prepare. queryid - это идентификатор, возвращаемый функцией spi_prepare. Если запрос ссылается на параметры, необходимо предоставить value-list. Это список фактических значений для параметров в формате Tcl. Список должен иметь такую же длину, как и список типов параметров, предоставленный ранее функции spi_prepare. Оставьте value-list пустым, если запрос не содержит параметров.

Опциональное значение для -nulls представляет собой строку из пробелов и символов 'n', которая сообщает функции spi_execp, какие из параметров являются пустыми значениями. Если значение задано, оно должно иметь точно такую же длину, как и value-list. Если значение не задано, все значения параметров являются ненулевыми.

За исключением способа указания запроса и его параметров, функция spi_execp работает так же, как функция spi_exec. Опции -count, -array и loop-body аналогичны, а также значение результата.

Вот пример функции PL/Tcl, использующей подготовленный план:

CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
    if {![ info exists GD(plan) ]} {
        # prepare the saved plan on the first call
        set GD(plan) [ spi_prepare \
                "SELECT count(*) AS cnt FROM t1 WHERE num >= \$1 AND num <= \$2" \
                [ list int4 int4 ] ]
    }
    spi_execp -count 1 $GD(plan) [ list $1 $2 ]
    return $cnt
$$ LANGUAGE pltcl;

Нам нужны обратные косые черты внутри строки запроса, передаваемой в функцию spi_prepare, чтобы гарантировать, что маркеры $n будут переданы в spi_prepare без изменений и не будут заменены подстановкой переменных Tcl.

subtransaction command

Tcl-скрипт, содержащийся в command, выполняется в пределах SQL-подтранзакции. Если скрипт возвращает ошибку, вся подтранзакция откатывается перед возвратом ошибки в окружающий Tcl-код. См. Раздел 41.9 для получения дополнительной информации и примера.

quote string

Удваивает все апострофы и обратные косые черты в данной строке. Это может быть использовано для безопасного экранирования строк, которые будут вставлены в SQL-команды, передаваемые функциям spi_exec или spi_prepare. Например, подумайте о строке SQL-команды вида:

"SELECT '$val' AS ret"

где переменная Tcl val фактически содержит doesn't. Это приведет к окончательной строке команды:

SELECT 'doesn't' AS ret

что приведет к ошибке разбора во время spi_exec или spi_prepare. Чтобы работать правильно, отправленная команда должна содержать:

SELECT 'doesn''t' AS ret

которые могут быть созданы в PL/Tcl с использованием:

"SELECT '[ quote $val ]' AS ret"

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

elog level msg

Выдает сообщение журнала или ошибки. Возможные уровни: DEBUG, LOG, INFO, NOTICE, WARNING, ERROR и FATAL. Уровень ERROR вызывает ошибочное состояние; если это не обрабатывается окружающим Tcl-кодом, ошибка передается вызывающему запросу, что приводит к прерыванию текущей транзакции или подтранзакции. Это фактически то же самое, что и команда Tcl error. Уровень FATAL прерывает транзакцию и приводит к завершению текущей сессии. (Вероятно, нет хорошей причины использовать этот уровень ошибки в функциях PL/Tcl, но он предоставляется для полноты). Другие уровни только генерируют сообщения разных приоритетов. Что касается сообщений определенного приоритета, то их отображение клиенту, запись в журнал сервера или оба действия контролируются переменными конфигурации log_min_messages и client_min_messages. Дополнительную информацию см. в разделах Глава 18 и Раздел 41.8.