问题
I have a javascript stored procedure that return boolean. I want to be able to call this stored procedure inside a transaction and test the return value before committing the transaction.
BEGIN;
SET result = CALL my_stored_proc();
IF $result = true
COMMIT;
ELSE
ROLLBACK;
The stored procedure will return false if there is an exception or if there is some missing values based on business logic.
How do I achieve this in Snowflake?
EDIT: I tried the following and it did not work. The transaction remains open and the statements executed inside the stored proc are not rolled back until an explicit ROLLBACK statement is issued.
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
How do I rollback the statements executed inside the stored procedure?
回答1:
I recommend reading through this document as it offers several examples and methods to do what you are asking.
https://docs.snowflake.com/en/sql-reference/stored-procedures-usage.html#transaction-management
回答2:
So it turns out that you CAN issue transaction control commands (BEGIN, COMMIT, ROLLBACK) inside a stored procedure. I can being the transaction, check the return value inside the stored procedure and decide to COMMIT or ROLLBACK.
Someone should update the snowflake documentation.
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;
$$
;
来源:https://stackoverflow.com/questions/62132365/how-to-commit-rollback-stored-procedure-based-on-return-value-in-snowflake