调用存储过程抛出错误时如何使任务失败

Posted

技术标签:

【中文标题】调用存储过程抛出错误时如何使任务失败【英文标题】:How to make the task fail when the calling stored procedure throws an error 【发布时间】:2021-09-07 16:33:16 【问题描述】:

我有一个存储过程从任务调用的阶段插入数据。如果加载失败(由于 on_error=skip_file 选项),它会抛出一个错误并被处理。但任务的状态显示为成功。存储过程出错时如何使任务失败。 这是示例代码

create or replace procedure sample_procedure()
returns varchar not null
language javascript
execute as caller    
as
$$
    try
    
       try
        
            var ct_table_cmd = `create or replace table sample_table_temp like sample_table`;
            var ct_table_stmt = snowflake.createStatement(sqlText: ct_table_cmd);
            var result_set= ct_table_stmt.execute();
             result_set.next();
        
        catch(err)
        
           var queryId = ct_table_stmt.getQueryId();
           var queryText = ct_table_stmt.getSqlText();
           var log_insert_into=snowflake.createStatement(sqlText:`insert into error_table
               (code, message, queryid, querytext) VALUES (?,?,?,?);`
               ,binds : [err.code, err.message,queryId,queryText]
            );
            log_insert_into.execute();
            var ct_task_ret_value = snowflake.createStatement(sqlText: `call system$set_return_value('err.message');`).execute();
            return err.message;
       
        var copy_cmd = `copy into smaple_table_temp from @mystage
                 file_format=(format_name= 'sample_csv_format')
                 files=('/file_name')
                 on_error=skip_file;`;
 

         var copy_cmd_stmt = snowflake.createStatement(sqlText:copy_cmd);
        var result_set =copy_cmd_stmt.execute();
        result_set.next();
       if(result_set.getColumnValue(2)=='LOADED')
       
          var swap_cmd = `alter table sample_table_temp swap with sample_table;`;
          var swap_stmt = snowflake.createStatement(sqlText: swap_cmd);
          swap_stmt.execute();
       
       else if (result_set.getColumnValue(2)== 'LOAD_FAILED')
      
        var err_message= result_set.getColumnValue(7);
        var queryId = copy_cmd_stmt.getQueryId();
        var queryText = copy_cmd_stmt.getSqlText();
        var log_insert_into=snowflake.createStatement(sqlText:`insert into error_table
         (code, message, queryid, querytext) VALUES (?,?,?,?);`
         ,binds : [err.code, err.message,queryId,queryText]
          );
        var task_ret_value = snowflake.createStatement(sqlText: `call system$set_return_value('err_message');`).execute();
        log_insert_into.execute();
        return err_message
  
     
    
$$
;

调用过程的错误日志表和任务是:

create or replace table error_table (ts timestamp_ntz, src varchar(50),code varhcar(100) , 
                                   message varchar, queryid varchar, querytext varhcar);

创建或替换任务示例任务 仓库 = '我的仓库' 时间表='10分钟' 作为 调用 sample_procedure();

当任务调用该位置中没有数据的过程时,它会在任务历史记录中抛出一个错误,如“存储过程示例过程中的执行错误:

SQL 编译错误: 位置 47 的语法错误行意外“远程”。在 statement.execute,第 172 行位置 111”。但实际错误是“远程文件不存在。有几个潜在的原因。该文件可能不存在。所需的凭据可能丢失或无效。"

当表不存在时,信息模式的task_history中显示的错误不同。它没有显示独立调用过程时显示的错误(即调用 sample_procdure())。

任何建议都有帮助。

【问题讨论】:

【参考方案1】:

您在此处设置任务的返回值:

var ct_task_ret_value = snowflake.createStatement(sqlText: `call system$set_return_value('err.message');`).execute();

您在此处设置存储过程的返回值:

return err.message;

问题是err.message 是一个包含错误消息文本的字符串,它不是错误指示。您已经发现了错误,就 Snowflake 而言,它已得到处理。

要在 SP 执行时指示错误,您可以 1) 不捕获错误或 2) 捕获错误、处理它并抛出错误。

选项 2 似乎是您想要做的。像您已经在做的那样捕获错误,但不要返回err.message,而是这样做:

//return err.message;
throw err.message;

Snowflake 将使用自己的错误文本包装错误消息。目前没有办法避免这种情况,因此您可能需要在文本中做一些事情来引起对错误文本的注意,例如 *wrapping in stars* 或类似的东西。 Snowflake Stored Procedure Exception & Failure

【讨论】:

name: @Greg 使用 throw err.message 时,它​​显示为未捕获的错误,但将错误记录到日志表中,但是当使用 return err.message 时,它​​给出了实际错误。如何处理?

以上是关于调用存储过程抛出错误时如何使任务失败的主要内容,如果未能解决你的问题,请参考以下文章

从SQL代理作业调用时,工作存储过程失败

Postgresql 11:存储过程调用错误 - 要调用过程,请使用 CALL、Java

Java存储过程中的getOutputStream抛出错误

带有DateTime列的DataTable抛出“转换日期和/或时间时转换失败”

九、存储过程中异常的处理

IBExpert 中的 Firebird 在访问某些存储过程时抛出错误