2025, Oct 20 01:16

Как присвоить результат Python‑процедуры в Snowflake без EXECUTE IMMEDIATE

Разбираем ошибки с EXECUTE IMMEDIATE в Snowflake Scripting и показываем, как получить значение Python‑процедуры через CALL INTO или прямой вызов без ошибок.

Присвоение результата Python‑процедуры переменной в Snowflake Scripting выглядит обманчиво простым, однако одна неуместная конструкция быстро приводит к запутанным ошибкам парсера. Если вы пытались провести возвращаемое значение процедуры через EXECUTE IMMEDIATE, скорее всего, видели сообщения о неожиданном INTO или RETURN. Причина проста: EXECUTE IMMEDIATE предназначен для динамического SQL и здесь вовсе не нужен.

Постановка задачи

Рассмотрим Python‑процедуру, которая возвращает строку об успешном выполнении, и блок, пытающийся сохранить это значение в переменную с помощью EXECUTE IMMEDIATE, а затем вернуть его.

CREATE OR REPLACE TEMPORARY PROCEDURE py_task_proc()
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = 3.11
HANDLER = 'entry'
AS
$$
def entry():
    return "Procedure executed successfully"
$$
;
DECLARE out_msg STRING;
BEGIN
  EXECUTE IMMEDIATE 'CALL py_task_proc()' INTO :out_msg;
  RETURN out_msg;
END;
SHOW VARIABLES;

В результате возникают ошибки вроде «Syntax error: unexpected 'INTO'» и «syntax error ... unexpected 'RETURN'».

Что именно идет не так

EXECUTE IMMEDIATE предназначен для динамического SQL. В нашей ситуации оператор статичен и не требует динамического выполнения. Использование EXECUTE IMMEDIATE запускает лишний путь выполнения, и парсер отклоняет размещение INTO в таком контексте. Есть более простой и корректный способ получить возвращаемое значение процедуры. Также стоит помнить, что SHOW VARIABLES относится к переменным сессии, которые отличаются от переменных Snowflake Scripting, объявленных внутри блока.

Рабочий подход

Результат вызова можно напрямую присвоить скриптовой переменной или поручить Snowflake поместить его в переменную через синтаксис CALL ... INTO. Оба варианта полностью обходятся без динамического SQL.

CREATE OR REPLACE TEMPORARY PROCEDURE py_task_proc()
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = 3.11
PACKAGES = ('snowflake-snowpark-python')
HANDLER = 'entry'
AS
$$
def entry():
    return "Procedure executed successfully :)"
$$
;

Основной блок:

DECLARE 
  out_msg STRING;
BEGIN
  out_msg := (CALL py_task_proc());
  CALL py_task_proc() INTO :out_msg;
  RETURN :out_msg;
END;

Почему это важно

Выбор нативных конструкций Snowflake Scripting вместо динамического SQL делает код компактнее и избавляет от лишних синтаксических ошибок. Управление потоком и передача данных становятся прозрачными: процедура вызывается, возвращаемое значение фиксируется, а результат возвращается из блока. Понимание того, что SHOW VARIABLES показывает переменные уровня сессии, а не переменные, объявленные внутри блока, помогает избежать неверных проверок при отладке.

Итоги

Если нужно получить возвращаемое значение Python‑процедуры в Snowflake Scripting, вызывайте ее напрямую и присваивайте результат либо используйте CALL ... INTO. Оставьте EXECUTE IMMEDIATE для случаев, когда действительно необходим динамический SQL, и помните: SHOW VARIABLES не отображает переменные, созданные с помощью DECLARE внутри скриптового блока.

Материал основан на вопросе на StackOverflow от James Gorman и ответе от Lukasz Szozda.