我正在使用Snowflake云数据库,请帮我调试程序或函数。
下面的Snowflake Javascript存储过程是我用来开始新存储过程的模板。它包含大量的调试技巧,例如:
- 它有一个"我在哪里?"变量,可以让您了解代码中的位置
- 它在进程进行过程中收集数组中的信息
- 它将该数组返回到调用命令的标准输出
- 它有一个异常块的"良好开端",如果失败,在调用存储过程时,异常块的内容也会被推送到标准输出
我一直想添加的内容是在代码中设置一个查询标记,这在查看查询历史记录时很有帮助,可以轻松地识别存储过程执行中使用的SQL命令。
这"与"最后的"调试技巧"有关——在开发或测试环境中开发存储过程时,尤其是在构建动态SQL语句时,应该始终查看查询历史记录(代码执行的实际查询(。查看查询历史记录是必须的,它将准确地显示运行的命令及其运行的操作顺序。
这是它使用的示例表的代码,我希望它能有所帮助。。。富
CREATE OR REPLACE TABLE test_scripts (
load_seq number,
script varchar(2000)
);
INSERT INTO test_scripts values
(1, 'SELECT current_timestamp();'),
(2, 'SELECT current_warehouse();'),
(3, 'SELECT COUNT(*) FROM snowflake.account_usage.tables;'),
(4, 'SELECT current_date();'),
(5, 'SELECT current_account();'),
(6, 'SELECT COUNT(*) FROM snowflake.account_usage.tables;'),
(7, 'SELECT ''RICH'';');
select * from test_scripts;
CREATE OR REPLACE PROCEDURE sp_test(p1 varchar, p2 varchar)
RETURNS ARRAY
LANGUAGE javascript
EXECUTE AS caller
AS
$$
//note: you can change the RETURN to VARCHAR if needed
// but the array "looks nice"
try {
var whereAmI = 1;
var return_array = [];
var counter = 0;
var p1_str = "p1: " + P1
var p2_str = "p2: " + P2
var load_seq = P1;
var continue_flag = P2;
whereAmI = 2;
return_array.push(p1_str)
return_array.push(p2_str)
whereAmI = 3;
//which SQL do I want to run?
if (continue_flag=="YES") {
return_array.push("query 1")
var sqlquery = "SELECT * FROM test_scripts WHERE load_seq >= " + load_seq + " order by 1, 2;";
}
else {
return_array.push("query 2")
var sqlquery = "SELECT * FROM test_scripts WHERE load_seq = " + load_seq + " order by 1, 2;";
}
whereAmI = 4;
//begin the run of grabbing the commands
var stmt = snowflake.createStatement( {sqlText: sqlquery} );
var rs = stmt.execute();
whereAmI = 5;
// Loop through the results, processing one row at a time...
while (rs.next()) {
counter = counter + 1;
var tmp_load_seq = rs.getColumnValue(1);
var tmp_script = rs.getColumnValue(2);
var tmp_rs = snowflake.execute({sqlText: tmp_script});
tmp_rs.next();
var tmp_col1 = tmp_rs.getColumnValue(1);
return_array.push("tmp_col1: " + tmp_col1)
}
whereAmI = 6;
return_array.push("end process - counter: " + counter)
return return_array;
}
catch (err) {
return_array.push("error found")
return_array.push(whereAmI)
return_array.push(err)
return return_array;
}
$$;
CALL sp_test(3, 'NO');
我认为Snowflake的存储过程没有任何编辑器/调试器。少数选项:
- 您可以将代码分解为较小的部分并尝试进行故障排除
- 使用日志表并经常插入到日志表中,这样您就可以查看日志表来找出问题所在
不幸的是,没有一个环境可以统治它们1.在工作表或编辑器中编写SQL2.在启用JS的编辑器中编写SPROC代码3.将它们合并到工作表或编辑器中4.如@Rich Murmane 所示,在SPROCS中进行单元测试
我通常只是在工作表中写SPROC,但这不是最佳
Logging是您的朋友,因为这里没有调试器。一般来说,很难找到并使用数据库存储过程的调试器。并非不可能,只是可能性不大。
这是一个不错的选择:
CREATE or replace PROCEDURE do_log(MSG STRING)
RETURNS STRING
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS $$
//see if we should log - checks for do_log = true session variable
try{
var foo = snowflake.createStatement( { sqlText: `select $do_log` } ).execute();
} catch (ERROR){
return; //swallow the error, variable not set so don't log
}
foo.next();
if (foo.getColumnValue(1)==true){ //if the value is anything other than true, don't log
try{
snowflake.createStatement( { sqlText: `create temp table identifier ($log_table) if not exists (ts number, msg string)`} ).execute();
snowflake.createStatement( { sqlText: `insert into identifier ($log_table) values (:1, :2)`, binds:[Date.now(), MSG] } ).execute();
} catch (ERROR){
throw ERROR;
}
}
$$
;
然后在存储过程中,您希望调试在顶部添加一个log
函数:
function log(msg){
snowflake.createStatement( { sqlText: `call do_log(:1)`, binds:[msg] } ).execute();
}
然后调用上面的存储过程:
set do_log = true; --true to enable logging, false (or undefined) to disable
set log_table = 'my_log_table'; --The name of the temp table where log messages go
然后在实际的存储过程中,您需要添加一些日志行:
log('this is another log message');
然后像往常一样调用存储过程。然后从CCD_ 3中选择CCD_。
重要提示:这使用了一个临时表,因此您将无法在不同的Snowflake连接中读取该日志记录表。这意味着,如果您使用工作表编辑器,则需要将所有这些内容放在同一张工作表上。
"借用的";发件人:https://community.snowflake.com/s/article/Snowflake-Stored-Procedure-Logging