【问题标题】:How to Commit/Rollback stored procedure based on return value in Snowflake?如何根据雪花中的返回值提交/回滚存储过程?
【发布时间】:2020-09-19 18:17:49
【问题描述】:

我有一个返回布尔值的 javascript 存储过程。我希望能够在事务中调用此存储过程并在提交事务之前测试返回值。

BEGIN;
SET result = CALL my_stored_proc();

IF $result = true 
COMMIT;
ELSE
ROLLBACK;

如果出现异常或者基于业务逻辑存在一些缺失值,存储过程将返回false。

如何在 Snowflake 中实现这一点?


编辑: 我尝试了以下方法,但没有奏效。事务保持打开状态,并且在存储过程中执行的语句不会回滚,直到发出显式 ROLLBACK 语句。

USE COMMON;


CREATE TABLE LOG
(
LOG_ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_LOG_ID PRIMARY KEY,
LOG_LEVEL VARCHAR (50) NOT NULL,
LOGGER VARCHAR (500) NOT NULL,
MESSAGE VARCHAR NOT NULL,
EXCEPTION VARCHAR NULL,
APPLICATION_NAME VARCHAR(500) NOT NULL,
LOGGED_ON DATETIME DEFAULT TO_TIMESTAMP_NTZ(CURRENT_TIMESTAMP()) NOT NULL,
LOGGED_BY VARCHAR(200) DEFAULT CURRENT_USER() NOT NULL
);

CREATE OR REPLACE PROCEDURE TEST_TRANSACTION() 
RETURNS VARCHAR 
LANGUAGE javascript 
EXECUTE AS CALLER
AS 
$$
snowflake.execute({sqlText:`
INSERT
            INTO
                COMMON.LOG (LOG_LEVEL, LOGGER, MESSAGE, EXCEPTION, APPLICATION_NAME)
            VALUES ('DEBUG', 'TEST_TRANSACTION', 'This is a test transaction.', '', 'DATA LOADER'); 
`});
snowflake.execute({sqlText:`
INSERT
            INTO
                COMMON.LOG (LOG_LEVEL, LOGGER, MESSAGE, EXCEPTION, APPLICATION_NAME)
            VALUES ('DEBUG', 'TEST_TRANSACTION', 'This message should not be in the logs.', '', 'DATA LOADER'); 
`});

throw 'Test error'
$$
;
-- Run the next 3 lines as a batch
BEGIN;
CALL COMMON.TEST_TRANSACTION(); -- This Fails
COMMIT; -- Commit is NOT executed

SELECT * FROM COMMON.LOG WHERE LOGGER = 'TEST_TRANSACTION'; -- The insert is successful & the transaction is still OPEN

如何回滚存储过程中执行的语句?

【问题讨论】:

    标签: snowflake-cloud-data-platform


    【解决方案1】:

    我建议通读本文档,因为它提供了几个示例和方法来满足您的要求。

    https://docs.snowflake.com/en/sql-reference/stored-procedures-usage.html#transaction-management

    【讨论】:

    • @user:12178980 我已经阅读了整个页面,没有提到测试返回值以提交或回滚。我的问题非常具体。如果存储过程返回 FALSE,我如何回滚事务。我知道我可以得到这样的返回值 - SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) 但在那之后我该怎么办,如果值为 FALSE,我如何告诉雪花回滚。
    • 我知道这篇文章并没有回答您提出的具体问题,但它确实告诉您如何处理失败的事务和存储过程。它只是不像你要求的那样做。为什么不将您的 SP 更改为本文建议的方式并以这种方式处理回滚,而不是返回布尔值“FALSE”并尝试以不推荐的方式处理它?
    • 能否请您指出它显示如何处理事务和失败的存储过程的位置。我真的很难在你分享的页面上找到它。我不能在存储过程中发出回滚语句,可以吗?或者我是否必须从存储的过程中抛出一个错误,让 Snowflake 停止执行并使事务处于不稳定状态?
    • 开始; W;调用我的程序(); -- 执行 X 和 Y Z;犯罪;在这个例子中,如果 SP 失败,SP 内部的 DML 会因为语句失败而回滚。如果成功,则提交,因为允许脚本继续提交。
    • 如果您在 SP 中执行任何 DDL,请注意文章中的 cmets,然后需要使用 TRY/CATCH 撤消您所做的操作。文章中也对此进行了概述。
    【解决方案2】:

    事实证明,您可以在存储过程中发出事务控制命令(BEGIN、COMMIT、ROLLBACK)。我可以作为事务,检查存储过程中的返回值并决定 COMMIT 或 ROLLBACK。

    有人应该更新雪花文档。

    CREATE OR REPLACE PROCEDURE TEST_TRANSACTION(result BOOLEAN) 
    RETURNS BOOLEAN NOT NULL 
    LANGUAGE javascript 
    EXECUTE AS CALLER
    AS 
    $$
    snowflake.execute({sqlText:`BEGIN;`});
    
    snowflake.execute({sqlText:`
    INSERT
                INTO
                    COMMON.LOG (LOG_LEVEL, LOGGER, MESSAGE, EXCEPTION, APPLICATION_NAME)
                VALUES ('DEBUG', 'TEST_TRANSACTION', 'This is a test transaction.', '', 'DATA LOADER'); 
    `});
    snowflake.execute({sqlText:`
    INSERT
                INTO
                    COMMON.LOG (LOG_LEVEL, LOGGER, MESSAGE, EXCEPTION, APPLICATION_NAME)
                VALUES ('DEBUG', 'TEST_TRANSACTION', 'This message should not be in the logs.', '', 'DATA LOADER'); 
    `});
    
    if ( RESULT ) { snowflake.execute( {sqlText: "COMMIT" }) } 
        else {
            snowflake.execute( {sqlText: "ROLLBACK" }) };
    
    return true;
    $$
    ;
    

    【讨论】:

      猜你喜欢
      • 2022-11-11
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 2021-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多